##// END OF EJS Templates
copy-tracing: add a --compute flag to debugchangedfiles...
marmoute -
r47208:c2435280 default
parent child Browse files
Show More
@@ -1,4732 +1,4749 b''
1 # debugcommands.py - command processing for debug* commands
1 # debugcommands.py - command processing for debug* commands
2 #
2 #
3 # Copyright 2005-2016 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2016 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 codecs
10 import codecs
11 import collections
11 import collections
12 import difflib
12 import difflib
13 import errno
13 import errno
14 import glob
14 import glob
15 import operator
15 import operator
16 import os
16 import os
17 import platform
17 import platform
18 import random
18 import random
19 import re
19 import re
20 import socket
20 import socket
21 import ssl
21 import ssl
22 import stat
22 import stat
23 import string
23 import string
24 import subprocess
24 import subprocess
25 import sys
25 import sys
26 import time
26 import time
27
27
28 from .i18n import _
28 from .i18n import _
29 from .node import (
29 from .node import (
30 bin,
30 bin,
31 hex,
31 hex,
32 nullid,
32 nullid,
33 nullrev,
33 nullrev,
34 short,
34 short,
35 )
35 )
36 from .pycompat import (
36 from .pycompat import (
37 getattr,
37 getattr,
38 open,
38 open,
39 )
39 )
40 from . import (
40 from . import (
41 bundle2,
41 bundle2,
42 bundlerepo,
42 bundlerepo,
43 changegroup,
43 changegroup,
44 cmdutil,
44 cmdutil,
45 color,
45 color,
46 context,
46 context,
47 copies,
47 copies,
48 dagparser,
48 dagparser,
49 encoding,
49 encoding,
50 error,
50 error,
51 exchange,
51 exchange,
52 extensions,
52 extensions,
53 filemerge,
53 filemerge,
54 filesetlang,
54 filesetlang,
55 formatter,
55 formatter,
56 hg,
56 hg,
57 httppeer,
57 httppeer,
58 localrepo,
58 localrepo,
59 lock as lockmod,
59 lock as lockmod,
60 logcmdutil,
60 logcmdutil,
61 mergestate as mergestatemod,
61 mergestate as mergestatemod,
62 metadata,
62 metadata,
63 obsolete,
63 obsolete,
64 obsutil,
64 obsutil,
65 pathutil,
65 pathutil,
66 phases,
66 phases,
67 policy,
67 policy,
68 pvec,
68 pvec,
69 pycompat,
69 pycompat,
70 registrar,
70 registrar,
71 repair,
71 repair,
72 repoview,
72 repoview,
73 revlog,
73 revlog,
74 revset,
74 revset,
75 revsetlang,
75 revsetlang,
76 scmutil,
76 scmutil,
77 setdiscovery,
77 setdiscovery,
78 simplemerge,
78 simplemerge,
79 sshpeer,
79 sshpeer,
80 sslutil,
80 sslutil,
81 streamclone,
81 streamclone,
82 strip,
82 strip,
83 tags as tagsmod,
83 tags as tagsmod,
84 templater,
84 templater,
85 treediscovery,
85 treediscovery,
86 upgrade,
86 upgrade,
87 url as urlmod,
87 url as urlmod,
88 util,
88 util,
89 vfs as vfsmod,
89 vfs as vfsmod,
90 wireprotoframing,
90 wireprotoframing,
91 wireprotoserver,
91 wireprotoserver,
92 wireprotov2peer,
92 wireprotov2peer,
93 )
93 )
94 from .utils import (
94 from .utils import (
95 cborutil,
95 cborutil,
96 compression,
96 compression,
97 dateutil,
97 dateutil,
98 procutil,
98 procutil,
99 stringutil,
99 stringutil,
100 )
100 )
101
101
102 from .revlogutils import (
102 from .revlogutils import (
103 deltas as deltautil,
103 deltas as deltautil,
104 nodemap,
104 nodemap,
105 sidedata,
105 sidedata,
106 )
106 )
107
107
108 release = lockmod.release
108 release = lockmod.release
109
109
110 table = {}
110 table = {}
111 table.update(strip.command._table)
111 table.update(strip.command._table)
112 command = registrar.command(table)
112 command = registrar.command(table)
113
113
114
114
115 @command(b'debugancestor', [], _(b'[INDEX] REV1 REV2'), optionalrepo=True)
115 @command(b'debugancestor', [], _(b'[INDEX] REV1 REV2'), optionalrepo=True)
116 def debugancestor(ui, repo, *args):
116 def debugancestor(ui, repo, *args):
117 """find the ancestor revision of two revisions in a given index"""
117 """find the ancestor revision of two revisions in a given index"""
118 if len(args) == 3:
118 if len(args) == 3:
119 index, rev1, rev2 = args
119 index, rev1, rev2 = args
120 r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), index)
120 r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), index)
121 lookup = r.lookup
121 lookup = r.lookup
122 elif len(args) == 2:
122 elif len(args) == 2:
123 if not repo:
123 if not repo:
124 raise error.Abort(
124 raise error.Abort(
125 _(b'there is no Mercurial repository here (.hg not found)')
125 _(b'there is no Mercurial repository here (.hg not found)')
126 )
126 )
127 rev1, rev2 = args
127 rev1, rev2 = args
128 r = repo.changelog
128 r = repo.changelog
129 lookup = repo.lookup
129 lookup = repo.lookup
130 else:
130 else:
131 raise error.Abort(_(b'either two or three arguments required'))
131 raise error.Abort(_(b'either two or three arguments required'))
132 a = r.ancestor(lookup(rev1), lookup(rev2))
132 a = r.ancestor(lookup(rev1), lookup(rev2))
133 ui.write(b'%d:%s\n' % (r.rev(a), hex(a)))
133 ui.write(b'%d:%s\n' % (r.rev(a), hex(a)))
134
134
135
135
136 @command(b'debugantivirusrunning', [])
136 @command(b'debugantivirusrunning', [])
137 def debugantivirusrunning(ui, repo):
137 def debugantivirusrunning(ui, repo):
138 """attempt to trigger an antivirus scanner to see if one is active"""
138 """attempt to trigger an antivirus scanner to see if one is active"""
139 with repo.cachevfs.open('eicar-test-file.com', b'wb') as f:
139 with repo.cachevfs.open('eicar-test-file.com', b'wb') as f:
140 f.write(
140 f.write(
141 util.b85decode(
141 util.b85decode(
142 # This is a base85-armored version of the EICAR test file. See
142 # This is a base85-armored version of the EICAR test file. See
143 # https://en.wikipedia.org/wiki/EICAR_test_file for details.
143 # https://en.wikipedia.org/wiki/EICAR_test_file for details.
144 b'ST#=}P$fV?P+K%yP+C|uG$>GBDK|qyDK~v2MM*<JQY}+dK~6+LQba95P'
144 b'ST#=}P$fV?P+K%yP+C|uG$>GBDK|qyDK~v2MM*<JQY}+dK~6+LQba95P'
145 b'E<)&Nm5l)EmTEQR4qnHOhq9iNGnJx'
145 b'E<)&Nm5l)EmTEQR4qnHOhq9iNGnJx'
146 )
146 )
147 )
147 )
148 # Give an AV engine time to scan the file.
148 # Give an AV engine time to scan the file.
149 time.sleep(2)
149 time.sleep(2)
150 util.unlink(repo.cachevfs.join('eicar-test-file.com'))
150 util.unlink(repo.cachevfs.join('eicar-test-file.com'))
151
151
152
152
153 @command(b'debugapplystreamclonebundle', [], b'FILE')
153 @command(b'debugapplystreamclonebundle', [], b'FILE')
154 def debugapplystreamclonebundle(ui, repo, fname):
154 def debugapplystreamclonebundle(ui, repo, fname):
155 """apply a stream clone bundle file"""
155 """apply a stream clone bundle file"""
156 f = hg.openpath(ui, fname)
156 f = hg.openpath(ui, fname)
157 gen = exchange.readbundle(ui, f, fname)
157 gen = exchange.readbundle(ui, f, fname)
158 gen.apply(repo)
158 gen.apply(repo)
159
159
160
160
161 @command(
161 @command(
162 b'debugbuilddag',
162 b'debugbuilddag',
163 [
163 [
164 (
164 (
165 b'm',
165 b'm',
166 b'mergeable-file',
166 b'mergeable-file',
167 None,
167 None,
168 _(b'add single file mergeable changes'),
168 _(b'add single file mergeable changes'),
169 ),
169 ),
170 (
170 (
171 b'o',
171 b'o',
172 b'overwritten-file',
172 b'overwritten-file',
173 None,
173 None,
174 _(b'add single file all revs overwrite'),
174 _(b'add single file all revs overwrite'),
175 ),
175 ),
176 (b'n', b'new-file', None, _(b'add new file at each rev')),
176 (b'n', b'new-file', None, _(b'add new file at each rev')),
177 ],
177 ],
178 _(b'[OPTION]... [TEXT]'),
178 _(b'[OPTION]... [TEXT]'),
179 )
179 )
180 def debugbuilddag(
180 def debugbuilddag(
181 ui,
181 ui,
182 repo,
182 repo,
183 text=None,
183 text=None,
184 mergeable_file=False,
184 mergeable_file=False,
185 overwritten_file=False,
185 overwritten_file=False,
186 new_file=False,
186 new_file=False,
187 ):
187 ):
188 """builds a repo with a given DAG from scratch in the current empty repo
188 """builds a repo with a given DAG from scratch in the current empty repo
189
189
190 The description of the DAG is read from stdin if not given on the
190 The description of the DAG is read from stdin if not given on the
191 command line.
191 command line.
192
192
193 Elements:
193 Elements:
194
194
195 - "+n" is a linear run of n nodes based on the current default parent
195 - "+n" is a linear run of n nodes based on the current default parent
196 - "." is a single node based on the current default parent
196 - "." is a single node based on the current default parent
197 - "$" resets the default parent to null (implied at the start);
197 - "$" resets the default parent to null (implied at the start);
198 otherwise the default parent is always the last node created
198 otherwise the default parent is always the last node created
199 - "<p" sets the default parent to the backref p
199 - "<p" sets the default parent to the backref p
200 - "*p" is a fork at parent p, which is a backref
200 - "*p" is a fork at parent p, which is a backref
201 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
201 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
202 - "/p2" is a merge of the preceding node and p2
202 - "/p2" is a merge of the preceding node and p2
203 - ":tag" defines a local tag for the preceding node
203 - ":tag" defines a local tag for the preceding node
204 - "@branch" sets the named branch for subsequent nodes
204 - "@branch" sets the named branch for subsequent nodes
205 - "#...\\n" is a comment up to the end of the line
205 - "#...\\n" is a comment up to the end of the line
206
206
207 Whitespace between the above elements is ignored.
207 Whitespace between the above elements is ignored.
208
208
209 A backref is either
209 A backref is either
210
210
211 - a number n, which references the node curr-n, where curr is the current
211 - a number n, which references the node curr-n, where curr is the current
212 node, or
212 node, or
213 - the name of a local tag you placed earlier using ":tag", or
213 - the name of a local tag you placed earlier using ":tag", or
214 - empty to denote the default parent.
214 - empty to denote the default parent.
215
215
216 All string valued-elements are either strictly alphanumeric, or must
216 All string valued-elements are either strictly alphanumeric, or must
217 be enclosed in double quotes ("..."), with "\\" as escape character.
217 be enclosed in double quotes ("..."), with "\\" as escape character.
218 """
218 """
219
219
220 if text is None:
220 if text is None:
221 ui.status(_(b"reading DAG from stdin\n"))
221 ui.status(_(b"reading DAG from stdin\n"))
222 text = ui.fin.read()
222 text = ui.fin.read()
223
223
224 cl = repo.changelog
224 cl = repo.changelog
225 if len(cl) > 0:
225 if len(cl) > 0:
226 raise error.Abort(_(b'repository is not empty'))
226 raise error.Abort(_(b'repository is not empty'))
227
227
228 # determine number of revs in DAG
228 # determine number of revs in DAG
229 total = 0
229 total = 0
230 for type, data in dagparser.parsedag(text):
230 for type, data in dagparser.parsedag(text):
231 if type == b'n':
231 if type == b'n':
232 total += 1
232 total += 1
233
233
234 if mergeable_file:
234 if mergeable_file:
235 linesperrev = 2
235 linesperrev = 2
236 # make a file with k lines per rev
236 # make a file with k lines per rev
237 initialmergedlines = [
237 initialmergedlines = [
238 b'%d' % i for i in pycompat.xrange(0, total * linesperrev)
238 b'%d' % i for i in pycompat.xrange(0, total * linesperrev)
239 ]
239 ]
240 initialmergedlines.append(b"")
240 initialmergedlines.append(b"")
241
241
242 tags = []
242 tags = []
243 progress = ui.makeprogress(
243 progress = ui.makeprogress(
244 _(b'building'), unit=_(b'revisions'), total=total
244 _(b'building'), unit=_(b'revisions'), total=total
245 )
245 )
246 with progress, repo.wlock(), repo.lock(), repo.transaction(b"builddag"):
246 with progress, repo.wlock(), repo.lock(), repo.transaction(b"builddag"):
247 at = -1
247 at = -1
248 atbranch = b'default'
248 atbranch = b'default'
249 nodeids = []
249 nodeids = []
250 id = 0
250 id = 0
251 progress.update(id)
251 progress.update(id)
252 for type, data in dagparser.parsedag(text):
252 for type, data in dagparser.parsedag(text):
253 if type == b'n':
253 if type == b'n':
254 ui.note((b'node %s\n' % pycompat.bytestr(data)))
254 ui.note((b'node %s\n' % pycompat.bytestr(data)))
255 id, ps = data
255 id, ps = data
256
256
257 files = []
257 files = []
258 filecontent = {}
258 filecontent = {}
259
259
260 p2 = None
260 p2 = None
261 if mergeable_file:
261 if mergeable_file:
262 fn = b"mf"
262 fn = b"mf"
263 p1 = repo[ps[0]]
263 p1 = repo[ps[0]]
264 if len(ps) > 1:
264 if len(ps) > 1:
265 p2 = repo[ps[1]]
265 p2 = repo[ps[1]]
266 pa = p1.ancestor(p2)
266 pa = p1.ancestor(p2)
267 base, local, other = [
267 base, local, other = [
268 x[fn].data() for x in (pa, p1, p2)
268 x[fn].data() for x in (pa, p1, p2)
269 ]
269 ]
270 m3 = simplemerge.Merge3Text(base, local, other)
270 m3 = simplemerge.Merge3Text(base, local, other)
271 ml = [l.strip() for l in m3.merge_lines()]
271 ml = [l.strip() for l in m3.merge_lines()]
272 ml.append(b"")
272 ml.append(b"")
273 elif at > 0:
273 elif at > 0:
274 ml = p1[fn].data().split(b"\n")
274 ml = p1[fn].data().split(b"\n")
275 else:
275 else:
276 ml = initialmergedlines
276 ml = initialmergedlines
277 ml[id * linesperrev] += b" r%i" % id
277 ml[id * linesperrev] += b" r%i" % id
278 mergedtext = b"\n".join(ml)
278 mergedtext = b"\n".join(ml)
279 files.append(fn)
279 files.append(fn)
280 filecontent[fn] = mergedtext
280 filecontent[fn] = mergedtext
281
281
282 if overwritten_file:
282 if overwritten_file:
283 fn = b"of"
283 fn = b"of"
284 files.append(fn)
284 files.append(fn)
285 filecontent[fn] = b"r%i\n" % id
285 filecontent[fn] = b"r%i\n" % id
286
286
287 if new_file:
287 if new_file:
288 fn = b"nf%i" % id
288 fn = b"nf%i" % id
289 files.append(fn)
289 files.append(fn)
290 filecontent[fn] = b"r%i\n" % id
290 filecontent[fn] = b"r%i\n" % id
291 if len(ps) > 1:
291 if len(ps) > 1:
292 if not p2:
292 if not p2:
293 p2 = repo[ps[1]]
293 p2 = repo[ps[1]]
294 for fn in p2:
294 for fn in p2:
295 if fn.startswith(b"nf"):
295 if fn.startswith(b"nf"):
296 files.append(fn)
296 files.append(fn)
297 filecontent[fn] = p2[fn].data()
297 filecontent[fn] = p2[fn].data()
298
298
299 def fctxfn(repo, cx, path):
299 def fctxfn(repo, cx, path):
300 if path in filecontent:
300 if path in filecontent:
301 return context.memfilectx(
301 return context.memfilectx(
302 repo, cx, path, filecontent[path]
302 repo, cx, path, filecontent[path]
303 )
303 )
304 return None
304 return None
305
305
306 if len(ps) == 0 or ps[0] < 0:
306 if len(ps) == 0 or ps[0] < 0:
307 pars = [None, None]
307 pars = [None, None]
308 elif len(ps) == 1:
308 elif len(ps) == 1:
309 pars = [nodeids[ps[0]], None]
309 pars = [nodeids[ps[0]], None]
310 else:
310 else:
311 pars = [nodeids[p] for p in ps]
311 pars = [nodeids[p] for p in ps]
312 cx = context.memctx(
312 cx = context.memctx(
313 repo,
313 repo,
314 pars,
314 pars,
315 b"r%i" % id,
315 b"r%i" % id,
316 files,
316 files,
317 fctxfn,
317 fctxfn,
318 date=(id, 0),
318 date=(id, 0),
319 user=b"debugbuilddag",
319 user=b"debugbuilddag",
320 extra={b'branch': atbranch},
320 extra={b'branch': atbranch},
321 )
321 )
322 nodeid = repo.commitctx(cx)
322 nodeid = repo.commitctx(cx)
323 nodeids.append(nodeid)
323 nodeids.append(nodeid)
324 at = id
324 at = id
325 elif type == b'l':
325 elif type == b'l':
326 id, name = data
326 id, name = data
327 ui.note((b'tag %s\n' % name))
327 ui.note((b'tag %s\n' % name))
328 tags.append(b"%s %s\n" % (hex(repo.changelog.node(id)), name))
328 tags.append(b"%s %s\n" % (hex(repo.changelog.node(id)), name))
329 elif type == b'a':
329 elif type == b'a':
330 ui.note((b'branch %s\n' % data))
330 ui.note((b'branch %s\n' % data))
331 atbranch = data
331 atbranch = data
332 progress.update(id)
332 progress.update(id)
333
333
334 if tags:
334 if tags:
335 repo.vfs.write(b"localtags", b"".join(tags))
335 repo.vfs.write(b"localtags", b"".join(tags))
336
336
337
337
338 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
338 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
339 indent_string = b' ' * indent
339 indent_string = b' ' * indent
340 if all:
340 if all:
341 ui.writenoi18n(
341 ui.writenoi18n(
342 b"%sformat: id, p1, p2, cset, delta base, len(delta)\n"
342 b"%sformat: id, p1, p2, cset, delta base, len(delta)\n"
343 % indent_string
343 % indent_string
344 )
344 )
345
345
346 def showchunks(named):
346 def showchunks(named):
347 ui.write(b"\n%s%s\n" % (indent_string, named))
347 ui.write(b"\n%s%s\n" % (indent_string, named))
348 for deltadata in gen.deltaiter():
348 for deltadata in gen.deltaiter():
349 node, p1, p2, cs, deltabase, delta, flags = deltadata
349 node, p1, p2, cs, deltabase, delta, flags = deltadata
350 ui.write(
350 ui.write(
351 b"%s%s %s %s %s %s %d\n"
351 b"%s%s %s %s %s %s %d\n"
352 % (
352 % (
353 indent_string,
353 indent_string,
354 hex(node),
354 hex(node),
355 hex(p1),
355 hex(p1),
356 hex(p2),
356 hex(p2),
357 hex(cs),
357 hex(cs),
358 hex(deltabase),
358 hex(deltabase),
359 len(delta),
359 len(delta),
360 )
360 )
361 )
361 )
362
362
363 gen.changelogheader()
363 gen.changelogheader()
364 showchunks(b"changelog")
364 showchunks(b"changelog")
365 gen.manifestheader()
365 gen.manifestheader()
366 showchunks(b"manifest")
366 showchunks(b"manifest")
367 for chunkdata in iter(gen.filelogheader, {}):
367 for chunkdata in iter(gen.filelogheader, {}):
368 fname = chunkdata[b'filename']
368 fname = chunkdata[b'filename']
369 showchunks(fname)
369 showchunks(fname)
370 else:
370 else:
371 if isinstance(gen, bundle2.unbundle20):
371 if isinstance(gen, bundle2.unbundle20):
372 raise error.Abort(_(b'use debugbundle2 for this file'))
372 raise error.Abort(_(b'use debugbundle2 for this file'))
373 gen.changelogheader()
373 gen.changelogheader()
374 for deltadata in gen.deltaiter():
374 for deltadata in gen.deltaiter():
375 node, p1, p2, cs, deltabase, delta, flags = deltadata
375 node, p1, p2, cs, deltabase, delta, flags = deltadata
376 ui.write(b"%s%s\n" % (indent_string, hex(node)))
376 ui.write(b"%s%s\n" % (indent_string, hex(node)))
377
377
378
378
379 def _debugobsmarkers(ui, part, indent=0, **opts):
379 def _debugobsmarkers(ui, part, indent=0, **opts):
380 """display version and markers contained in 'data'"""
380 """display version and markers contained in 'data'"""
381 opts = pycompat.byteskwargs(opts)
381 opts = pycompat.byteskwargs(opts)
382 data = part.read()
382 data = part.read()
383 indent_string = b' ' * indent
383 indent_string = b' ' * indent
384 try:
384 try:
385 version, markers = obsolete._readmarkers(data)
385 version, markers = obsolete._readmarkers(data)
386 except error.UnknownVersion as exc:
386 except error.UnknownVersion as exc:
387 msg = b"%sunsupported version: %s (%d bytes)\n"
387 msg = b"%sunsupported version: %s (%d bytes)\n"
388 msg %= indent_string, exc.version, len(data)
388 msg %= indent_string, exc.version, len(data)
389 ui.write(msg)
389 ui.write(msg)
390 else:
390 else:
391 msg = b"%sversion: %d (%d bytes)\n"
391 msg = b"%sversion: %d (%d bytes)\n"
392 msg %= indent_string, version, len(data)
392 msg %= indent_string, version, len(data)
393 ui.write(msg)
393 ui.write(msg)
394 fm = ui.formatter(b'debugobsolete', opts)
394 fm = ui.formatter(b'debugobsolete', opts)
395 for rawmarker in sorted(markers):
395 for rawmarker in sorted(markers):
396 m = obsutil.marker(None, rawmarker)
396 m = obsutil.marker(None, rawmarker)
397 fm.startitem()
397 fm.startitem()
398 fm.plain(indent_string)
398 fm.plain(indent_string)
399 cmdutil.showmarker(fm, m)
399 cmdutil.showmarker(fm, m)
400 fm.end()
400 fm.end()
401
401
402
402
403 def _debugphaseheads(ui, data, indent=0):
403 def _debugphaseheads(ui, data, indent=0):
404 """display version and markers contained in 'data'"""
404 """display version and markers contained in 'data'"""
405 indent_string = b' ' * indent
405 indent_string = b' ' * indent
406 headsbyphase = phases.binarydecode(data)
406 headsbyphase = phases.binarydecode(data)
407 for phase in phases.allphases:
407 for phase in phases.allphases:
408 for head in headsbyphase[phase]:
408 for head in headsbyphase[phase]:
409 ui.write(indent_string)
409 ui.write(indent_string)
410 ui.write(b'%s %s\n' % (hex(head), phases.phasenames[phase]))
410 ui.write(b'%s %s\n' % (hex(head), phases.phasenames[phase]))
411
411
412
412
413 def _quasirepr(thing):
413 def _quasirepr(thing):
414 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
414 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
415 return b'{%s}' % (
415 return b'{%s}' % (
416 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing))
416 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing))
417 )
417 )
418 return pycompat.bytestr(repr(thing))
418 return pycompat.bytestr(repr(thing))
419
419
420
420
421 def _debugbundle2(ui, gen, all=None, **opts):
421 def _debugbundle2(ui, gen, all=None, **opts):
422 """lists the contents of a bundle2"""
422 """lists the contents of a bundle2"""
423 if not isinstance(gen, bundle2.unbundle20):
423 if not isinstance(gen, bundle2.unbundle20):
424 raise error.Abort(_(b'not a bundle2 file'))
424 raise error.Abort(_(b'not a bundle2 file'))
425 ui.write((b'Stream params: %s\n' % _quasirepr(gen.params)))
425 ui.write((b'Stream params: %s\n' % _quasirepr(gen.params)))
426 parttypes = opts.get('part_type', [])
426 parttypes = opts.get('part_type', [])
427 for part in gen.iterparts():
427 for part in gen.iterparts():
428 if parttypes and part.type not in parttypes:
428 if parttypes and part.type not in parttypes:
429 continue
429 continue
430 msg = b'%s -- %s (mandatory: %r)\n'
430 msg = b'%s -- %s (mandatory: %r)\n'
431 ui.write((msg % (part.type, _quasirepr(part.params), part.mandatory)))
431 ui.write((msg % (part.type, _quasirepr(part.params), part.mandatory)))
432 if part.type == b'changegroup':
432 if part.type == b'changegroup':
433 version = part.params.get(b'version', b'01')
433 version = part.params.get(b'version', b'01')
434 cg = changegroup.getunbundler(version, part, b'UN')
434 cg = changegroup.getunbundler(version, part, b'UN')
435 if not ui.quiet:
435 if not ui.quiet:
436 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
436 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
437 if part.type == b'obsmarkers':
437 if part.type == b'obsmarkers':
438 if not ui.quiet:
438 if not ui.quiet:
439 _debugobsmarkers(ui, part, indent=4, **opts)
439 _debugobsmarkers(ui, part, indent=4, **opts)
440 if part.type == b'phase-heads':
440 if part.type == b'phase-heads':
441 if not ui.quiet:
441 if not ui.quiet:
442 _debugphaseheads(ui, part, indent=4)
442 _debugphaseheads(ui, part, indent=4)
443
443
444
444
445 @command(
445 @command(
446 b'debugbundle',
446 b'debugbundle',
447 [
447 [
448 (b'a', b'all', None, _(b'show all details')),
448 (b'a', b'all', None, _(b'show all details')),
449 (b'', b'part-type', [], _(b'show only the named part type')),
449 (b'', b'part-type', [], _(b'show only the named part type')),
450 (b'', b'spec', None, _(b'print the bundlespec of the bundle')),
450 (b'', b'spec', None, _(b'print the bundlespec of the bundle')),
451 ],
451 ],
452 _(b'FILE'),
452 _(b'FILE'),
453 norepo=True,
453 norepo=True,
454 )
454 )
455 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
455 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
456 """lists the contents of a bundle"""
456 """lists the contents of a bundle"""
457 with hg.openpath(ui, bundlepath) as f:
457 with hg.openpath(ui, bundlepath) as f:
458 if spec:
458 if spec:
459 spec = exchange.getbundlespec(ui, f)
459 spec = exchange.getbundlespec(ui, f)
460 ui.write(b'%s\n' % spec)
460 ui.write(b'%s\n' % spec)
461 return
461 return
462
462
463 gen = exchange.readbundle(ui, f, bundlepath)
463 gen = exchange.readbundle(ui, f, bundlepath)
464 if isinstance(gen, bundle2.unbundle20):
464 if isinstance(gen, bundle2.unbundle20):
465 return _debugbundle2(ui, gen, all=all, **opts)
465 return _debugbundle2(ui, gen, all=all, **opts)
466 _debugchangegroup(ui, gen, all=all, **opts)
466 _debugchangegroup(ui, gen, all=all, **opts)
467
467
468
468
469 @command(b'debugcapabilities', [], _(b'PATH'), norepo=True)
469 @command(b'debugcapabilities', [], _(b'PATH'), norepo=True)
470 def debugcapabilities(ui, path, **opts):
470 def debugcapabilities(ui, path, **opts):
471 """lists the capabilities of a remote peer"""
471 """lists the capabilities of a remote peer"""
472 opts = pycompat.byteskwargs(opts)
472 opts = pycompat.byteskwargs(opts)
473 peer = hg.peer(ui, opts, path)
473 peer = hg.peer(ui, opts, path)
474 caps = peer.capabilities()
474 caps = peer.capabilities()
475 ui.writenoi18n(b'Main capabilities:\n')
475 ui.writenoi18n(b'Main capabilities:\n')
476 for c in sorted(caps):
476 for c in sorted(caps):
477 ui.write(b' %s\n' % c)
477 ui.write(b' %s\n' % c)
478 b2caps = bundle2.bundle2caps(peer)
478 b2caps = bundle2.bundle2caps(peer)
479 if b2caps:
479 if b2caps:
480 ui.writenoi18n(b'Bundle2 capabilities:\n')
480 ui.writenoi18n(b'Bundle2 capabilities:\n')
481 for key, values in sorted(pycompat.iteritems(b2caps)):
481 for key, values in sorted(pycompat.iteritems(b2caps)):
482 ui.write(b' %s\n' % key)
482 ui.write(b' %s\n' % key)
483 for v in values:
483 for v in values:
484 ui.write(b' %s\n' % v)
484 ui.write(b' %s\n' % v)
485
485
486
486
487 @command(b'debugchangedfiles', [], b'REV')
487 @command(
488 def debugchangedfiles(ui, repo, rev):
488 b'debugchangedfiles',
489 [
490 (
491 b'',
492 b'compute',
493 False,
494 b"compute information instead of reading it from storage",
495 ),
496 ],
497 b'REV',
498 )
499 def debugchangedfiles(ui, repo, rev, **opts):
489 """list the stored files changes for a revision"""
500 """list the stored files changes for a revision"""
490 ctx = scmutil.revsingle(repo, rev, None)
501 ctx = scmutil.revsingle(repo, rev, None)
491 sd = repo.changelog.sidedata(ctx.rev())
502 files = None
492 files_block = sd.get(sidedata.SD_FILES)
503
493 if files_block is not None:
504 if opts['compute']:
494 files = metadata.decode_files_sidedata(sd)
505 files = metadata.compute_all_files_changes(ctx)
506 else:
507 sd = repo.changelog.sidedata(ctx.rev())
508 files_block = sd.get(sidedata.SD_FILES)
509 if files_block is not None:
510 files = metadata.decode_files_sidedata(sd)
511 if files is not None:
495 for f in sorted(files.touched):
512 for f in sorted(files.touched):
496 if f in files.added:
513 if f in files.added:
497 action = b"added"
514 action = b"added"
498 elif f in files.removed:
515 elif f in files.removed:
499 action = b"removed"
516 action = b"removed"
500 elif f in files.merged:
517 elif f in files.merged:
501 action = b"merged"
518 action = b"merged"
502 elif f in files.salvaged:
519 elif f in files.salvaged:
503 action = b"salvaged"
520 action = b"salvaged"
504 else:
521 else:
505 action = b"touched"
522 action = b"touched"
506
523
507 copy_parent = b""
524 copy_parent = b""
508 copy_source = b""
525 copy_source = b""
509 if f in files.copied_from_p1:
526 if f in files.copied_from_p1:
510 copy_parent = b"p1"
527 copy_parent = b"p1"
511 copy_source = files.copied_from_p1[f]
528 copy_source = files.copied_from_p1[f]
512 elif f in files.copied_from_p2:
529 elif f in files.copied_from_p2:
513 copy_parent = b"p2"
530 copy_parent = b"p2"
514 copy_source = files.copied_from_p2[f]
531 copy_source = files.copied_from_p2[f]
515
532
516 data = (action, copy_parent, f, copy_source)
533 data = (action, copy_parent, f, copy_source)
517 template = b"%-8s %2s: %s, %s;\n"
534 template = b"%-8s %2s: %s, %s;\n"
518 ui.write(template % data)
535 ui.write(template % data)
519
536
520
537
521 @command(b'debugcheckstate', [], b'')
538 @command(b'debugcheckstate', [], b'')
522 def debugcheckstate(ui, repo):
539 def debugcheckstate(ui, repo):
523 """validate the correctness of the current dirstate"""
540 """validate the correctness of the current dirstate"""
524 parent1, parent2 = repo.dirstate.parents()
541 parent1, parent2 = repo.dirstate.parents()
525 m1 = repo[parent1].manifest()
542 m1 = repo[parent1].manifest()
526 m2 = repo[parent2].manifest()
543 m2 = repo[parent2].manifest()
527 errors = 0
544 errors = 0
528 for f in repo.dirstate:
545 for f in repo.dirstate:
529 state = repo.dirstate[f]
546 state = repo.dirstate[f]
530 if state in b"nr" and f not in m1:
547 if state in b"nr" and f not in m1:
531 ui.warn(_(b"%s in state %s, but not in manifest1\n") % (f, state))
548 ui.warn(_(b"%s in state %s, but not in manifest1\n") % (f, state))
532 errors += 1
549 errors += 1
533 if state in b"a" and f in m1:
550 if state in b"a" and f in m1:
534 ui.warn(_(b"%s in state %s, but also in manifest1\n") % (f, state))
551 ui.warn(_(b"%s in state %s, but also in manifest1\n") % (f, state))
535 errors += 1
552 errors += 1
536 if state in b"m" and f not in m1 and f not in m2:
553 if state in b"m" and f not in m1 and f not in m2:
537 ui.warn(
554 ui.warn(
538 _(b"%s in state %s, but not in either manifest\n") % (f, state)
555 _(b"%s in state %s, but not in either manifest\n") % (f, state)
539 )
556 )
540 errors += 1
557 errors += 1
541 for f in m1:
558 for f in m1:
542 state = repo.dirstate[f]
559 state = repo.dirstate[f]
543 if state not in b"nrm":
560 if state not in b"nrm":
544 ui.warn(_(b"%s in manifest1, but listed as state %s") % (f, state))
561 ui.warn(_(b"%s in manifest1, but listed as state %s") % (f, state))
545 errors += 1
562 errors += 1
546 if errors:
563 if errors:
547 errstr = _(b".hg/dirstate inconsistent with current parent's manifest")
564 errstr = _(b".hg/dirstate inconsistent with current parent's manifest")
548 raise error.Abort(errstr)
565 raise error.Abort(errstr)
549
566
550
567
551 @command(
568 @command(
552 b'debugcolor',
569 b'debugcolor',
553 [(b'', b'style', None, _(b'show all configured styles'))],
570 [(b'', b'style', None, _(b'show all configured styles'))],
554 b'hg debugcolor',
571 b'hg debugcolor',
555 )
572 )
556 def debugcolor(ui, repo, **opts):
573 def debugcolor(ui, repo, **opts):
557 """show available color, effects or style"""
574 """show available color, effects or style"""
558 ui.writenoi18n(b'color mode: %s\n' % stringutil.pprint(ui._colormode))
575 ui.writenoi18n(b'color mode: %s\n' % stringutil.pprint(ui._colormode))
559 if opts.get('style'):
576 if opts.get('style'):
560 return _debugdisplaystyle(ui)
577 return _debugdisplaystyle(ui)
561 else:
578 else:
562 return _debugdisplaycolor(ui)
579 return _debugdisplaycolor(ui)
563
580
564
581
565 def _debugdisplaycolor(ui):
582 def _debugdisplaycolor(ui):
566 ui = ui.copy()
583 ui = ui.copy()
567 ui._styles.clear()
584 ui._styles.clear()
568 for effect in color._activeeffects(ui).keys():
585 for effect in color._activeeffects(ui).keys():
569 ui._styles[effect] = effect
586 ui._styles[effect] = effect
570 if ui._terminfoparams:
587 if ui._terminfoparams:
571 for k, v in ui.configitems(b'color'):
588 for k, v in ui.configitems(b'color'):
572 if k.startswith(b'color.'):
589 if k.startswith(b'color.'):
573 ui._styles[k] = k[6:]
590 ui._styles[k] = k[6:]
574 elif k.startswith(b'terminfo.'):
591 elif k.startswith(b'terminfo.'):
575 ui._styles[k] = k[9:]
592 ui._styles[k] = k[9:]
576 ui.write(_(b'available colors:\n'))
593 ui.write(_(b'available colors:\n'))
577 # sort label with a '_' after the other to group '_background' entry.
594 # sort label with a '_' after the other to group '_background' entry.
578 items = sorted(ui._styles.items(), key=lambda i: (b'_' in i[0], i[0], i[1]))
595 items = sorted(ui._styles.items(), key=lambda i: (b'_' in i[0], i[0], i[1]))
579 for colorname, label in items:
596 for colorname, label in items:
580 ui.write(b'%s\n' % colorname, label=label)
597 ui.write(b'%s\n' % colorname, label=label)
581
598
582
599
583 def _debugdisplaystyle(ui):
600 def _debugdisplaystyle(ui):
584 ui.write(_(b'available style:\n'))
601 ui.write(_(b'available style:\n'))
585 if not ui._styles:
602 if not ui._styles:
586 return
603 return
587 width = max(len(s) for s in ui._styles)
604 width = max(len(s) for s in ui._styles)
588 for label, effects in sorted(ui._styles.items()):
605 for label, effects in sorted(ui._styles.items()):
589 ui.write(b'%s' % label, label=label)
606 ui.write(b'%s' % label, label=label)
590 if effects:
607 if effects:
591 # 50
608 # 50
592 ui.write(b': ')
609 ui.write(b': ')
593 ui.write(b' ' * (max(0, width - len(label))))
610 ui.write(b' ' * (max(0, width - len(label))))
594 ui.write(b', '.join(ui.label(e, e) for e in effects.split()))
611 ui.write(b', '.join(ui.label(e, e) for e in effects.split()))
595 ui.write(b'\n')
612 ui.write(b'\n')
596
613
597
614
598 @command(b'debugcreatestreamclonebundle', [], b'FILE')
615 @command(b'debugcreatestreamclonebundle', [], b'FILE')
599 def debugcreatestreamclonebundle(ui, repo, fname):
616 def debugcreatestreamclonebundle(ui, repo, fname):
600 """create a stream clone bundle file
617 """create a stream clone bundle file
601
618
602 Stream bundles are special bundles that are essentially archives of
619 Stream bundles are special bundles that are essentially archives of
603 revlog files. They are commonly used for cloning very quickly.
620 revlog files. They are commonly used for cloning very quickly.
604 """
621 """
605 # TODO we may want to turn this into an abort when this functionality
622 # TODO we may want to turn this into an abort when this functionality
606 # is moved into `hg bundle`.
623 # is moved into `hg bundle`.
607 if phases.hassecret(repo):
624 if phases.hassecret(repo):
608 ui.warn(
625 ui.warn(
609 _(
626 _(
610 b'(warning: stream clone bundle will contain secret '
627 b'(warning: stream clone bundle will contain secret '
611 b'revisions)\n'
628 b'revisions)\n'
612 )
629 )
613 )
630 )
614
631
615 requirements, gen = streamclone.generatebundlev1(repo)
632 requirements, gen = streamclone.generatebundlev1(repo)
616 changegroup.writechunks(ui, gen, fname)
633 changegroup.writechunks(ui, gen, fname)
617
634
618 ui.write(_(b'bundle requirements: %s\n') % b', '.join(sorted(requirements)))
635 ui.write(_(b'bundle requirements: %s\n') % b', '.join(sorted(requirements)))
619
636
620
637
621 @command(
638 @command(
622 b'debugdag',
639 b'debugdag',
623 [
640 [
624 (b't', b'tags', None, _(b'use tags as labels')),
641 (b't', b'tags', None, _(b'use tags as labels')),
625 (b'b', b'branches', None, _(b'annotate with branch names')),
642 (b'b', b'branches', None, _(b'annotate with branch names')),
626 (b'', b'dots', None, _(b'use dots for runs')),
643 (b'', b'dots', None, _(b'use dots for runs')),
627 (b's', b'spaces', None, _(b'separate elements by spaces')),
644 (b's', b'spaces', None, _(b'separate elements by spaces')),
628 ],
645 ],
629 _(b'[OPTION]... [FILE [REV]...]'),
646 _(b'[OPTION]... [FILE [REV]...]'),
630 optionalrepo=True,
647 optionalrepo=True,
631 )
648 )
632 def debugdag(ui, repo, file_=None, *revs, **opts):
649 def debugdag(ui, repo, file_=None, *revs, **opts):
633 """format the changelog or an index DAG as a concise textual description
650 """format the changelog or an index DAG as a concise textual description
634
651
635 If you pass a revlog index, the revlog's DAG is emitted. If you list
652 If you pass a revlog index, the revlog's DAG is emitted. If you list
636 revision numbers, they get labeled in the output as rN.
653 revision numbers, they get labeled in the output as rN.
637
654
638 Otherwise, the changelog DAG of the current repo is emitted.
655 Otherwise, the changelog DAG of the current repo is emitted.
639 """
656 """
640 spaces = opts.get('spaces')
657 spaces = opts.get('spaces')
641 dots = opts.get('dots')
658 dots = opts.get('dots')
642 if file_:
659 if file_:
643 rlog = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), file_)
660 rlog = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), file_)
644 revs = {int(r) for r in revs}
661 revs = {int(r) for r in revs}
645
662
646 def events():
663 def events():
647 for r in rlog:
664 for r in rlog:
648 yield b'n', (r, list(p for p in rlog.parentrevs(r) if p != -1))
665 yield b'n', (r, list(p for p in rlog.parentrevs(r) if p != -1))
649 if r in revs:
666 if r in revs:
650 yield b'l', (r, b"r%i" % r)
667 yield b'l', (r, b"r%i" % r)
651
668
652 elif repo:
669 elif repo:
653 cl = repo.changelog
670 cl = repo.changelog
654 tags = opts.get('tags')
671 tags = opts.get('tags')
655 branches = opts.get('branches')
672 branches = opts.get('branches')
656 if tags:
673 if tags:
657 labels = {}
674 labels = {}
658 for l, n in repo.tags().items():
675 for l, n in repo.tags().items():
659 labels.setdefault(cl.rev(n), []).append(l)
676 labels.setdefault(cl.rev(n), []).append(l)
660
677
661 def events():
678 def events():
662 b = b"default"
679 b = b"default"
663 for r in cl:
680 for r in cl:
664 if branches:
681 if branches:
665 newb = cl.read(cl.node(r))[5][b'branch']
682 newb = cl.read(cl.node(r))[5][b'branch']
666 if newb != b:
683 if newb != b:
667 yield b'a', newb
684 yield b'a', newb
668 b = newb
685 b = newb
669 yield b'n', (r, list(p for p in cl.parentrevs(r) if p != -1))
686 yield b'n', (r, list(p for p in cl.parentrevs(r) if p != -1))
670 if tags:
687 if tags:
671 ls = labels.get(r)
688 ls = labels.get(r)
672 if ls:
689 if ls:
673 for l in ls:
690 for l in ls:
674 yield b'l', (r, l)
691 yield b'l', (r, l)
675
692
676 else:
693 else:
677 raise error.Abort(_(b'need repo for changelog dag'))
694 raise error.Abort(_(b'need repo for changelog dag'))
678
695
679 for line in dagparser.dagtextlines(
696 for line in dagparser.dagtextlines(
680 events(),
697 events(),
681 addspaces=spaces,
698 addspaces=spaces,
682 wraplabels=True,
699 wraplabels=True,
683 wrapannotations=True,
700 wrapannotations=True,
684 wrapnonlinear=dots,
701 wrapnonlinear=dots,
685 usedots=dots,
702 usedots=dots,
686 maxlinewidth=70,
703 maxlinewidth=70,
687 ):
704 ):
688 ui.write(line)
705 ui.write(line)
689 ui.write(b"\n")
706 ui.write(b"\n")
690
707
691
708
692 @command(b'debugdata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
709 @command(b'debugdata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
693 def debugdata(ui, repo, file_, rev=None, **opts):
710 def debugdata(ui, repo, file_, rev=None, **opts):
694 """dump the contents of a data file revision"""
711 """dump the contents of a data file revision"""
695 opts = pycompat.byteskwargs(opts)
712 opts = pycompat.byteskwargs(opts)
696 if opts.get(b'changelog') or opts.get(b'manifest') or opts.get(b'dir'):
713 if opts.get(b'changelog') or opts.get(b'manifest') or opts.get(b'dir'):
697 if rev is not None:
714 if rev is not None:
698 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
715 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
699 file_, rev = None, file_
716 file_, rev = None, file_
700 elif rev is None:
717 elif rev is None:
701 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
718 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
702 r = cmdutil.openstorage(repo, b'debugdata', file_, opts)
719 r = cmdutil.openstorage(repo, b'debugdata', file_, opts)
703 try:
720 try:
704 ui.write(r.rawdata(r.lookup(rev)))
721 ui.write(r.rawdata(r.lookup(rev)))
705 except KeyError:
722 except KeyError:
706 raise error.Abort(_(b'invalid revision identifier %s') % rev)
723 raise error.Abort(_(b'invalid revision identifier %s') % rev)
707
724
708
725
709 @command(
726 @command(
710 b'debugdate',
727 b'debugdate',
711 [(b'e', b'extended', None, _(b'try extended date formats'))],
728 [(b'e', b'extended', None, _(b'try extended date formats'))],
712 _(b'[-e] DATE [RANGE]'),
729 _(b'[-e] DATE [RANGE]'),
713 norepo=True,
730 norepo=True,
714 optionalrepo=True,
731 optionalrepo=True,
715 )
732 )
716 def debugdate(ui, date, range=None, **opts):
733 def debugdate(ui, date, range=None, **opts):
717 """parse and display a date"""
734 """parse and display a date"""
718 if opts["extended"]:
735 if opts["extended"]:
719 d = dateutil.parsedate(date, dateutil.extendeddateformats)
736 d = dateutil.parsedate(date, dateutil.extendeddateformats)
720 else:
737 else:
721 d = dateutil.parsedate(date)
738 d = dateutil.parsedate(date)
722 ui.writenoi18n(b"internal: %d %d\n" % d)
739 ui.writenoi18n(b"internal: %d %d\n" % d)
723 ui.writenoi18n(b"standard: %s\n" % dateutil.datestr(d))
740 ui.writenoi18n(b"standard: %s\n" % dateutil.datestr(d))
724 if range:
741 if range:
725 m = dateutil.matchdate(range)
742 m = dateutil.matchdate(range)
726 ui.writenoi18n(b"match: %s\n" % m(d[0]))
743 ui.writenoi18n(b"match: %s\n" % m(d[0]))
727
744
728
745
729 @command(
746 @command(
730 b'debugdeltachain',
747 b'debugdeltachain',
731 cmdutil.debugrevlogopts + cmdutil.formatteropts,
748 cmdutil.debugrevlogopts + cmdutil.formatteropts,
732 _(b'-c|-m|FILE'),
749 _(b'-c|-m|FILE'),
733 optionalrepo=True,
750 optionalrepo=True,
734 )
751 )
735 def debugdeltachain(ui, repo, file_=None, **opts):
752 def debugdeltachain(ui, repo, file_=None, **opts):
736 """dump information about delta chains in a revlog
753 """dump information about delta chains in a revlog
737
754
738 Output can be templatized. Available template keywords are:
755 Output can be templatized. Available template keywords are:
739
756
740 :``rev``: revision number
757 :``rev``: revision number
741 :``chainid``: delta chain identifier (numbered by unique base)
758 :``chainid``: delta chain identifier (numbered by unique base)
742 :``chainlen``: delta chain length to this revision
759 :``chainlen``: delta chain length to this revision
743 :``prevrev``: previous revision in delta chain
760 :``prevrev``: previous revision in delta chain
744 :``deltatype``: role of delta / how it was computed
761 :``deltatype``: role of delta / how it was computed
745 :``compsize``: compressed size of revision
762 :``compsize``: compressed size of revision
746 :``uncompsize``: uncompressed size of revision
763 :``uncompsize``: uncompressed size of revision
747 :``chainsize``: total size of compressed revisions in chain
764 :``chainsize``: total size of compressed revisions in chain
748 :``chainratio``: total chain size divided by uncompressed revision size
765 :``chainratio``: total chain size divided by uncompressed revision size
749 (new delta chains typically start at ratio 2.00)
766 (new delta chains typically start at ratio 2.00)
750 :``lindist``: linear distance from base revision in delta chain to end
767 :``lindist``: linear distance from base revision in delta chain to end
751 of this revision
768 of this revision
752 :``extradist``: total size of revisions not part of this delta chain from
769 :``extradist``: total size of revisions not part of this delta chain from
753 base of delta chain to end of this revision; a measurement
770 base of delta chain to end of this revision; a measurement
754 of how much extra data we need to read/seek across to read
771 of how much extra data we need to read/seek across to read
755 the delta chain for this revision
772 the delta chain for this revision
756 :``extraratio``: extradist divided by chainsize; another representation of
773 :``extraratio``: extradist divided by chainsize; another representation of
757 how much unrelated data is needed to load this delta chain
774 how much unrelated data is needed to load this delta chain
758
775
759 If the repository is configured to use the sparse read, additional keywords
776 If the repository is configured to use the sparse read, additional keywords
760 are available:
777 are available:
761
778
762 :``readsize``: total size of data read from the disk for a revision
779 :``readsize``: total size of data read from the disk for a revision
763 (sum of the sizes of all the blocks)
780 (sum of the sizes of all the blocks)
764 :``largestblock``: size of the largest block of data read from the disk
781 :``largestblock``: size of the largest block of data read from the disk
765 :``readdensity``: density of useful bytes in the data read from the disk
782 :``readdensity``: density of useful bytes in the data read from the disk
766 :``srchunks``: in how many data hunks the whole revision would be read
783 :``srchunks``: in how many data hunks the whole revision would be read
767
784
768 The sparse read can be enabled with experimental.sparse-read = True
785 The sparse read can be enabled with experimental.sparse-read = True
769 """
786 """
770 opts = pycompat.byteskwargs(opts)
787 opts = pycompat.byteskwargs(opts)
771 r = cmdutil.openrevlog(repo, b'debugdeltachain', file_, opts)
788 r = cmdutil.openrevlog(repo, b'debugdeltachain', file_, opts)
772 index = r.index
789 index = r.index
773 start = r.start
790 start = r.start
774 length = r.length
791 length = r.length
775 generaldelta = r.version & revlog.FLAG_GENERALDELTA
792 generaldelta = r.version & revlog.FLAG_GENERALDELTA
776 withsparseread = getattr(r, '_withsparseread', False)
793 withsparseread = getattr(r, '_withsparseread', False)
777
794
778 def revinfo(rev):
795 def revinfo(rev):
779 e = index[rev]
796 e = index[rev]
780 compsize = e[1]
797 compsize = e[1]
781 uncompsize = e[2]
798 uncompsize = e[2]
782 chainsize = 0
799 chainsize = 0
783
800
784 if generaldelta:
801 if generaldelta:
785 if e[3] == e[5]:
802 if e[3] == e[5]:
786 deltatype = b'p1'
803 deltatype = b'p1'
787 elif e[3] == e[6]:
804 elif e[3] == e[6]:
788 deltatype = b'p2'
805 deltatype = b'p2'
789 elif e[3] == rev - 1:
806 elif e[3] == rev - 1:
790 deltatype = b'prev'
807 deltatype = b'prev'
791 elif e[3] == rev:
808 elif e[3] == rev:
792 deltatype = b'base'
809 deltatype = b'base'
793 else:
810 else:
794 deltatype = b'other'
811 deltatype = b'other'
795 else:
812 else:
796 if e[3] == rev:
813 if e[3] == rev:
797 deltatype = b'base'
814 deltatype = b'base'
798 else:
815 else:
799 deltatype = b'prev'
816 deltatype = b'prev'
800
817
801 chain = r._deltachain(rev)[0]
818 chain = r._deltachain(rev)[0]
802 for iterrev in chain:
819 for iterrev in chain:
803 e = index[iterrev]
820 e = index[iterrev]
804 chainsize += e[1]
821 chainsize += e[1]
805
822
806 return compsize, uncompsize, deltatype, chain, chainsize
823 return compsize, uncompsize, deltatype, chain, chainsize
807
824
808 fm = ui.formatter(b'debugdeltachain', opts)
825 fm = ui.formatter(b'debugdeltachain', opts)
809
826
810 fm.plain(
827 fm.plain(
811 b' rev chain# chainlen prev delta '
828 b' rev chain# chainlen prev delta '
812 b'size rawsize chainsize ratio lindist extradist '
829 b'size rawsize chainsize ratio lindist extradist '
813 b'extraratio'
830 b'extraratio'
814 )
831 )
815 if withsparseread:
832 if withsparseread:
816 fm.plain(b' readsize largestblk rddensity srchunks')
833 fm.plain(b' readsize largestblk rddensity srchunks')
817 fm.plain(b'\n')
834 fm.plain(b'\n')
818
835
819 chainbases = {}
836 chainbases = {}
820 for rev in r:
837 for rev in r:
821 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
838 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
822 chainbase = chain[0]
839 chainbase = chain[0]
823 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
840 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
824 basestart = start(chainbase)
841 basestart = start(chainbase)
825 revstart = start(rev)
842 revstart = start(rev)
826 lineardist = revstart + comp - basestart
843 lineardist = revstart + comp - basestart
827 extradist = lineardist - chainsize
844 extradist = lineardist - chainsize
828 try:
845 try:
829 prevrev = chain[-2]
846 prevrev = chain[-2]
830 except IndexError:
847 except IndexError:
831 prevrev = -1
848 prevrev = -1
832
849
833 if uncomp != 0:
850 if uncomp != 0:
834 chainratio = float(chainsize) / float(uncomp)
851 chainratio = float(chainsize) / float(uncomp)
835 else:
852 else:
836 chainratio = chainsize
853 chainratio = chainsize
837
854
838 if chainsize != 0:
855 if chainsize != 0:
839 extraratio = float(extradist) / float(chainsize)
856 extraratio = float(extradist) / float(chainsize)
840 else:
857 else:
841 extraratio = extradist
858 extraratio = extradist
842
859
843 fm.startitem()
860 fm.startitem()
844 fm.write(
861 fm.write(
845 b'rev chainid chainlen prevrev deltatype compsize '
862 b'rev chainid chainlen prevrev deltatype compsize '
846 b'uncompsize chainsize chainratio lindist extradist '
863 b'uncompsize chainsize chainratio lindist extradist '
847 b'extraratio',
864 b'extraratio',
848 b'%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f',
865 b'%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f',
849 rev,
866 rev,
850 chainid,
867 chainid,
851 len(chain),
868 len(chain),
852 prevrev,
869 prevrev,
853 deltatype,
870 deltatype,
854 comp,
871 comp,
855 uncomp,
872 uncomp,
856 chainsize,
873 chainsize,
857 chainratio,
874 chainratio,
858 lineardist,
875 lineardist,
859 extradist,
876 extradist,
860 extraratio,
877 extraratio,
861 rev=rev,
878 rev=rev,
862 chainid=chainid,
879 chainid=chainid,
863 chainlen=len(chain),
880 chainlen=len(chain),
864 prevrev=prevrev,
881 prevrev=prevrev,
865 deltatype=deltatype,
882 deltatype=deltatype,
866 compsize=comp,
883 compsize=comp,
867 uncompsize=uncomp,
884 uncompsize=uncomp,
868 chainsize=chainsize,
885 chainsize=chainsize,
869 chainratio=chainratio,
886 chainratio=chainratio,
870 lindist=lineardist,
887 lindist=lineardist,
871 extradist=extradist,
888 extradist=extradist,
872 extraratio=extraratio,
889 extraratio=extraratio,
873 )
890 )
874 if withsparseread:
891 if withsparseread:
875 readsize = 0
892 readsize = 0
876 largestblock = 0
893 largestblock = 0
877 srchunks = 0
894 srchunks = 0
878
895
879 for revschunk in deltautil.slicechunk(r, chain):
896 for revschunk in deltautil.slicechunk(r, chain):
880 srchunks += 1
897 srchunks += 1
881 blkend = start(revschunk[-1]) + length(revschunk[-1])
898 blkend = start(revschunk[-1]) + length(revschunk[-1])
882 blksize = blkend - start(revschunk[0])
899 blksize = blkend - start(revschunk[0])
883
900
884 readsize += blksize
901 readsize += blksize
885 if largestblock < blksize:
902 if largestblock < blksize:
886 largestblock = blksize
903 largestblock = blksize
887
904
888 if readsize:
905 if readsize:
889 readdensity = float(chainsize) / float(readsize)
906 readdensity = float(chainsize) / float(readsize)
890 else:
907 else:
891 readdensity = 1
908 readdensity = 1
892
909
893 fm.write(
910 fm.write(
894 b'readsize largestblock readdensity srchunks',
911 b'readsize largestblock readdensity srchunks',
895 b' %10d %10d %9.5f %8d',
912 b' %10d %10d %9.5f %8d',
896 readsize,
913 readsize,
897 largestblock,
914 largestblock,
898 readdensity,
915 readdensity,
899 srchunks,
916 srchunks,
900 readsize=readsize,
917 readsize=readsize,
901 largestblock=largestblock,
918 largestblock=largestblock,
902 readdensity=readdensity,
919 readdensity=readdensity,
903 srchunks=srchunks,
920 srchunks=srchunks,
904 )
921 )
905
922
906 fm.plain(b'\n')
923 fm.plain(b'\n')
907
924
908 fm.end()
925 fm.end()
909
926
910
927
911 @command(
928 @command(
912 b'debugdirstate|debugstate',
929 b'debugdirstate|debugstate',
913 [
930 [
914 (
931 (
915 b'',
932 b'',
916 b'nodates',
933 b'nodates',
917 None,
934 None,
918 _(b'do not display the saved mtime (DEPRECATED)'),
935 _(b'do not display the saved mtime (DEPRECATED)'),
919 ),
936 ),
920 (b'', b'dates', True, _(b'display the saved mtime')),
937 (b'', b'dates', True, _(b'display the saved mtime')),
921 (b'', b'datesort', None, _(b'sort by saved mtime')),
938 (b'', b'datesort', None, _(b'sort by saved mtime')),
922 ],
939 ],
923 _(b'[OPTION]...'),
940 _(b'[OPTION]...'),
924 )
941 )
925 def debugstate(ui, repo, **opts):
942 def debugstate(ui, repo, **opts):
926 """show the contents of the current dirstate"""
943 """show the contents of the current dirstate"""
927
944
928 nodates = not opts['dates']
945 nodates = not opts['dates']
929 if opts.get('nodates') is not None:
946 if opts.get('nodates') is not None:
930 nodates = True
947 nodates = True
931 datesort = opts.get('datesort')
948 datesort = opts.get('datesort')
932
949
933 if datesort:
950 if datesort:
934 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
951 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
935 else:
952 else:
936 keyfunc = None # sort by filename
953 keyfunc = None # sort by filename
937 for file_, ent in sorted(pycompat.iteritems(repo.dirstate), key=keyfunc):
954 for file_, ent in sorted(pycompat.iteritems(repo.dirstate), key=keyfunc):
938 if ent[3] == -1:
955 if ent[3] == -1:
939 timestr = b'unset '
956 timestr = b'unset '
940 elif nodates:
957 elif nodates:
941 timestr = b'set '
958 timestr = b'set '
942 else:
959 else:
943 timestr = time.strftime(
960 timestr = time.strftime(
944 "%Y-%m-%d %H:%M:%S ", time.localtime(ent[3])
961 "%Y-%m-%d %H:%M:%S ", time.localtime(ent[3])
945 )
962 )
946 timestr = encoding.strtolocal(timestr)
963 timestr = encoding.strtolocal(timestr)
947 if ent[1] & 0o20000:
964 if ent[1] & 0o20000:
948 mode = b'lnk'
965 mode = b'lnk'
949 else:
966 else:
950 mode = b'%3o' % (ent[1] & 0o777 & ~util.umask)
967 mode = b'%3o' % (ent[1] & 0o777 & ~util.umask)
951 ui.write(b"%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
968 ui.write(b"%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
952 for f in repo.dirstate.copies():
969 for f in repo.dirstate.copies():
953 ui.write(_(b"copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
970 ui.write(_(b"copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
954
971
955
972
956 @command(
973 @command(
957 b'debugdiscovery',
974 b'debugdiscovery',
958 [
975 [
959 (b'', b'old', None, _(b'use old-style discovery')),
976 (b'', b'old', None, _(b'use old-style discovery')),
960 (
977 (
961 b'',
978 b'',
962 b'nonheads',
979 b'nonheads',
963 None,
980 None,
964 _(b'use old-style discovery with non-heads included'),
981 _(b'use old-style discovery with non-heads included'),
965 ),
982 ),
966 (b'', b'rev', [], b'restrict discovery to this set of revs'),
983 (b'', b'rev', [], b'restrict discovery to this set of revs'),
967 (b'', b'seed', b'12323', b'specify the random seed use for discovery'),
984 (b'', b'seed', b'12323', b'specify the random seed use for discovery'),
968 (
985 (
969 b'',
986 b'',
970 b'local-as-revs',
987 b'local-as-revs',
971 "",
988 "",
972 'treat local has having these revisions only',
989 'treat local has having these revisions only',
973 ),
990 ),
974 (
991 (
975 b'',
992 b'',
976 b'remote-as-revs',
993 b'remote-as-revs',
977 "",
994 "",
978 'use local as remote, with only these these revisions',
995 'use local as remote, with only these these revisions',
979 ),
996 ),
980 ]
997 ]
981 + cmdutil.remoteopts,
998 + cmdutil.remoteopts,
982 _(b'[--rev REV] [OTHER]'),
999 _(b'[--rev REV] [OTHER]'),
983 )
1000 )
984 def debugdiscovery(ui, repo, remoteurl=b"default", **opts):
1001 def debugdiscovery(ui, repo, remoteurl=b"default", **opts):
985 """runs the changeset discovery protocol in isolation
1002 """runs the changeset discovery protocol in isolation
986
1003
987 The local peer can be "replaced" by a subset of the local repository by
1004 The local peer can be "replaced" by a subset of the local repository by
988 using the `--local-as-revs` flag. Int he same way, usual `remote` peer can
1005 using the `--local-as-revs` flag. Int he same way, usual `remote` peer can
989 be "replaced" by a subset of the local repository using the
1006 be "replaced" by a subset of the local repository using the
990 `--local-as-revs` flag. This is useful to efficiently debug pathological
1007 `--local-as-revs` flag. This is useful to efficiently debug pathological
991 discovery situation.
1008 discovery situation.
992 """
1009 """
993 opts = pycompat.byteskwargs(opts)
1010 opts = pycompat.byteskwargs(opts)
994 unfi = repo.unfiltered()
1011 unfi = repo.unfiltered()
995
1012
996 # setup potential extra filtering
1013 # setup potential extra filtering
997 local_revs = opts[b"local_as_revs"]
1014 local_revs = opts[b"local_as_revs"]
998 remote_revs = opts[b"remote_as_revs"]
1015 remote_revs = opts[b"remote_as_revs"]
999
1016
1000 # make sure tests are repeatable
1017 # make sure tests are repeatable
1001 random.seed(int(opts[b'seed']))
1018 random.seed(int(opts[b'seed']))
1002
1019
1003 if not remote_revs:
1020 if not remote_revs:
1004
1021
1005 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl))
1022 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl))
1006 remote = hg.peer(repo, opts, remoteurl)
1023 remote = hg.peer(repo, opts, remoteurl)
1007 ui.status(_(b'comparing with %s\n') % util.hidepassword(remoteurl))
1024 ui.status(_(b'comparing with %s\n') % util.hidepassword(remoteurl))
1008 else:
1025 else:
1009 branches = (None, [])
1026 branches = (None, [])
1010 remote_filtered_revs = scmutil.revrange(
1027 remote_filtered_revs = scmutil.revrange(
1011 unfi, [b"not (::(%s))" % remote_revs]
1028 unfi, [b"not (::(%s))" % remote_revs]
1012 )
1029 )
1013 remote_filtered_revs = frozenset(remote_filtered_revs)
1030 remote_filtered_revs = frozenset(remote_filtered_revs)
1014
1031
1015 def remote_func(x):
1032 def remote_func(x):
1016 return remote_filtered_revs
1033 return remote_filtered_revs
1017
1034
1018 repoview.filtertable[b'debug-discovery-remote-filter'] = remote_func
1035 repoview.filtertable[b'debug-discovery-remote-filter'] = remote_func
1019
1036
1020 remote = repo.peer()
1037 remote = repo.peer()
1021 remote._repo = remote._repo.filtered(b'debug-discovery-remote-filter')
1038 remote._repo = remote._repo.filtered(b'debug-discovery-remote-filter')
1022
1039
1023 if local_revs:
1040 if local_revs:
1024 local_filtered_revs = scmutil.revrange(
1041 local_filtered_revs = scmutil.revrange(
1025 unfi, [b"not (::(%s))" % local_revs]
1042 unfi, [b"not (::(%s))" % local_revs]
1026 )
1043 )
1027 local_filtered_revs = frozenset(local_filtered_revs)
1044 local_filtered_revs = frozenset(local_filtered_revs)
1028
1045
1029 def local_func(x):
1046 def local_func(x):
1030 return local_filtered_revs
1047 return local_filtered_revs
1031
1048
1032 repoview.filtertable[b'debug-discovery-local-filter'] = local_func
1049 repoview.filtertable[b'debug-discovery-local-filter'] = local_func
1033 repo = repo.filtered(b'debug-discovery-local-filter')
1050 repo = repo.filtered(b'debug-discovery-local-filter')
1034
1051
1035 data = {}
1052 data = {}
1036 if opts.get(b'old'):
1053 if opts.get(b'old'):
1037
1054
1038 def doit(pushedrevs, remoteheads, remote=remote):
1055 def doit(pushedrevs, remoteheads, remote=remote):
1039 if not util.safehasattr(remote, b'branches'):
1056 if not util.safehasattr(remote, b'branches'):
1040 # enable in-client legacy support
1057 # enable in-client legacy support
1041 remote = localrepo.locallegacypeer(remote.local())
1058 remote = localrepo.locallegacypeer(remote.local())
1042 common, _in, hds = treediscovery.findcommonincoming(
1059 common, _in, hds = treediscovery.findcommonincoming(
1043 repo, remote, force=True, audit=data
1060 repo, remote, force=True, audit=data
1044 )
1061 )
1045 common = set(common)
1062 common = set(common)
1046 if not opts.get(b'nonheads'):
1063 if not opts.get(b'nonheads'):
1047 ui.writenoi18n(
1064 ui.writenoi18n(
1048 b"unpruned common: %s\n"
1065 b"unpruned common: %s\n"
1049 % b" ".join(sorted(short(n) for n in common))
1066 % b" ".join(sorted(short(n) for n in common))
1050 )
1067 )
1051
1068
1052 clnode = repo.changelog.node
1069 clnode = repo.changelog.node
1053 common = repo.revs(b'heads(::%ln)', common)
1070 common = repo.revs(b'heads(::%ln)', common)
1054 common = {clnode(r) for r in common}
1071 common = {clnode(r) for r in common}
1055 return common, hds
1072 return common, hds
1056
1073
1057 else:
1074 else:
1058
1075
1059 def doit(pushedrevs, remoteheads, remote=remote):
1076 def doit(pushedrevs, remoteheads, remote=remote):
1060 nodes = None
1077 nodes = None
1061 if pushedrevs:
1078 if pushedrevs:
1062 revs = scmutil.revrange(repo, pushedrevs)
1079 revs = scmutil.revrange(repo, pushedrevs)
1063 nodes = [repo[r].node() for r in revs]
1080 nodes = [repo[r].node() for r in revs]
1064 common, any, hds = setdiscovery.findcommonheads(
1081 common, any, hds = setdiscovery.findcommonheads(
1065 ui, repo, remote, ancestorsof=nodes, audit=data
1082 ui, repo, remote, ancestorsof=nodes, audit=data
1066 )
1083 )
1067 return common, hds
1084 return common, hds
1068
1085
1069 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
1086 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
1070 localrevs = opts[b'rev']
1087 localrevs = opts[b'rev']
1071 with util.timedcm('debug-discovery') as t:
1088 with util.timedcm('debug-discovery') as t:
1072 common, hds = doit(localrevs, remoterevs)
1089 common, hds = doit(localrevs, remoterevs)
1073
1090
1074 # compute all statistics
1091 # compute all statistics
1075 heads_common = set(common)
1092 heads_common = set(common)
1076 heads_remote = set(hds)
1093 heads_remote = set(hds)
1077 heads_local = set(repo.heads())
1094 heads_local = set(repo.heads())
1078 # note: they cannot be a local or remote head that is in common and not
1095 # note: they cannot be a local or remote head that is in common and not
1079 # itself a head of common.
1096 # itself a head of common.
1080 heads_common_local = heads_common & heads_local
1097 heads_common_local = heads_common & heads_local
1081 heads_common_remote = heads_common & heads_remote
1098 heads_common_remote = heads_common & heads_remote
1082 heads_common_both = heads_common & heads_remote & heads_local
1099 heads_common_both = heads_common & heads_remote & heads_local
1083
1100
1084 all = repo.revs(b'all()')
1101 all = repo.revs(b'all()')
1085 common = repo.revs(b'::%ln', common)
1102 common = repo.revs(b'::%ln', common)
1086 roots_common = repo.revs(b'roots(::%ld)', common)
1103 roots_common = repo.revs(b'roots(::%ld)', common)
1087 missing = repo.revs(b'not ::%ld', common)
1104 missing = repo.revs(b'not ::%ld', common)
1088 heads_missing = repo.revs(b'heads(%ld)', missing)
1105 heads_missing = repo.revs(b'heads(%ld)', missing)
1089 roots_missing = repo.revs(b'roots(%ld)', missing)
1106 roots_missing = repo.revs(b'roots(%ld)', missing)
1090 assert len(common) + len(missing) == len(all)
1107 assert len(common) + len(missing) == len(all)
1091
1108
1092 initial_undecided = repo.revs(
1109 initial_undecided = repo.revs(
1093 b'not (::%ln or %ln::)', heads_common_remote, heads_common_local
1110 b'not (::%ln or %ln::)', heads_common_remote, heads_common_local
1094 )
1111 )
1095 heads_initial_undecided = repo.revs(b'heads(%ld)', initial_undecided)
1112 heads_initial_undecided = repo.revs(b'heads(%ld)', initial_undecided)
1096 roots_initial_undecided = repo.revs(b'roots(%ld)', initial_undecided)
1113 roots_initial_undecided = repo.revs(b'roots(%ld)', initial_undecided)
1097 common_initial_undecided = initial_undecided & common
1114 common_initial_undecided = initial_undecided & common
1098 missing_initial_undecided = initial_undecided & missing
1115 missing_initial_undecided = initial_undecided & missing
1099
1116
1100 data[b'elapsed'] = t.elapsed
1117 data[b'elapsed'] = t.elapsed
1101 data[b'nb-common-heads'] = len(heads_common)
1118 data[b'nb-common-heads'] = len(heads_common)
1102 data[b'nb-common-heads-local'] = len(heads_common_local)
1119 data[b'nb-common-heads-local'] = len(heads_common_local)
1103 data[b'nb-common-heads-remote'] = len(heads_common_remote)
1120 data[b'nb-common-heads-remote'] = len(heads_common_remote)
1104 data[b'nb-common-heads-both'] = len(heads_common_both)
1121 data[b'nb-common-heads-both'] = len(heads_common_both)
1105 data[b'nb-common-roots'] = len(roots_common)
1122 data[b'nb-common-roots'] = len(roots_common)
1106 data[b'nb-head-local'] = len(heads_local)
1123 data[b'nb-head-local'] = len(heads_local)
1107 data[b'nb-head-local-missing'] = len(heads_local) - len(heads_common_local)
1124 data[b'nb-head-local-missing'] = len(heads_local) - len(heads_common_local)
1108 data[b'nb-head-remote'] = len(heads_remote)
1125 data[b'nb-head-remote'] = len(heads_remote)
1109 data[b'nb-head-remote-unknown'] = len(heads_remote) - len(
1126 data[b'nb-head-remote-unknown'] = len(heads_remote) - len(
1110 heads_common_remote
1127 heads_common_remote
1111 )
1128 )
1112 data[b'nb-revs'] = len(all)
1129 data[b'nb-revs'] = len(all)
1113 data[b'nb-revs-common'] = len(common)
1130 data[b'nb-revs-common'] = len(common)
1114 data[b'nb-revs-missing'] = len(missing)
1131 data[b'nb-revs-missing'] = len(missing)
1115 data[b'nb-missing-heads'] = len(heads_missing)
1132 data[b'nb-missing-heads'] = len(heads_missing)
1116 data[b'nb-missing-roots'] = len(roots_missing)
1133 data[b'nb-missing-roots'] = len(roots_missing)
1117 data[b'nb-ini_und'] = len(initial_undecided)
1134 data[b'nb-ini_und'] = len(initial_undecided)
1118 data[b'nb-ini_und-heads'] = len(heads_initial_undecided)
1135 data[b'nb-ini_und-heads'] = len(heads_initial_undecided)
1119 data[b'nb-ini_und-roots'] = len(roots_initial_undecided)
1136 data[b'nb-ini_und-roots'] = len(roots_initial_undecided)
1120 data[b'nb-ini_und-common'] = len(common_initial_undecided)
1137 data[b'nb-ini_und-common'] = len(common_initial_undecided)
1121 data[b'nb-ini_und-missing'] = len(missing_initial_undecided)
1138 data[b'nb-ini_und-missing'] = len(missing_initial_undecided)
1122
1139
1123 # display discovery summary
1140 # display discovery summary
1124 ui.writenoi18n(b"elapsed time: %(elapsed)f seconds\n" % data)
1141 ui.writenoi18n(b"elapsed time: %(elapsed)f seconds\n" % data)
1125 ui.writenoi18n(b"round-trips: %(total-roundtrips)9d\n" % data)
1142 ui.writenoi18n(b"round-trips: %(total-roundtrips)9d\n" % data)
1126 ui.writenoi18n(b"heads summary:\n")
1143 ui.writenoi18n(b"heads summary:\n")
1127 ui.writenoi18n(b" total common heads: %(nb-common-heads)9d\n" % data)
1144 ui.writenoi18n(b" total common heads: %(nb-common-heads)9d\n" % data)
1128 ui.writenoi18n(
1145 ui.writenoi18n(
1129 b" also local heads: %(nb-common-heads-local)9d\n" % data
1146 b" also local heads: %(nb-common-heads-local)9d\n" % data
1130 )
1147 )
1131 ui.writenoi18n(
1148 ui.writenoi18n(
1132 b" also remote heads: %(nb-common-heads-remote)9d\n" % data
1149 b" also remote heads: %(nb-common-heads-remote)9d\n" % data
1133 )
1150 )
1134 ui.writenoi18n(b" both: %(nb-common-heads-both)9d\n" % data)
1151 ui.writenoi18n(b" both: %(nb-common-heads-both)9d\n" % data)
1135 ui.writenoi18n(b" local heads: %(nb-head-local)9d\n" % data)
1152 ui.writenoi18n(b" local heads: %(nb-head-local)9d\n" % data)
1136 ui.writenoi18n(
1153 ui.writenoi18n(
1137 b" common: %(nb-common-heads-local)9d\n" % data
1154 b" common: %(nb-common-heads-local)9d\n" % data
1138 )
1155 )
1139 ui.writenoi18n(
1156 ui.writenoi18n(
1140 b" missing: %(nb-head-local-missing)9d\n" % data
1157 b" missing: %(nb-head-local-missing)9d\n" % data
1141 )
1158 )
1142 ui.writenoi18n(b" remote heads: %(nb-head-remote)9d\n" % data)
1159 ui.writenoi18n(b" remote heads: %(nb-head-remote)9d\n" % data)
1143 ui.writenoi18n(
1160 ui.writenoi18n(
1144 b" common: %(nb-common-heads-remote)9d\n" % data
1161 b" common: %(nb-common-heads-remote)9d\n" % data
1145 )
1162 )
1146 ui.writenoi18n(
1163 ui.writenoi18n(
1147 b" unknown: %(nb-head-remote-unknown)9d\n" % data
1164 b" unknown: %(nb-head-remote-unknown)9d\n" % data
1148 )
1165 )
1149 ui.writenoi18n(b"local changesets: %(nb-revs)9d\n" % data)
1166 ui.writenoi18n(b"local changesets: %(nb-revs)9d\n" % data)
1150 ui.writenoi18n(b" common: %(nb-revs-common)9d\n" % data)
1167 ui.writenoi18n(b" common: %(nb-revs-common)9d\n" % data)
1151 ui.writenoi18n(b" heads: %(nb-common-heads)9d\n" % data)
1168 ui.writenoi18n(b" heads: %(nb-common-heads)9d\n" % data)
1152 ui.writenoi18n(b" roots: %(nb-common-roots)9d\n" % data)
1169 ui.writenoi18n(b" roots: %(nb-common-roots)9d\n" % data)
1153 ui.writenoi18n(b" missing: %(nb-revs-missing)9d\n" % data)
1170 ui.writenoi18n(b" missing: %(nb-revs-missing)9d\n" % data)
1154 ui.writenoi18n(b" heads: %(nb-missing-heads)9d\n" % data)
1171 ui.writenoi18n(b" heads: %(nb-missing-heads)9d\n" % data)
1155 ui.writenoi18n(b" roots: %(nb-missing-roots)9d\n" % data)
1172 ui.writenoi18n(b" roots: %(nb-missing-roots)9d\n" % data)
1156 ui.writenoi18n(b" first undecided set: %(nb-ini_und)9d\n" % data)
1173 ui.writenoi18n(b" first undecided set: %(nb-ini_und)9d\n" % data)
1157 ui.writenoi18n(b" heads: %(nb-ini_und-heads)9d\n" % data)
1174 ui.writenoi18n(b" heads: %(nb-ini_und-heads)9d\n" % data)
1158 ui.writenoi18n(b" roots: %(nb-ini_und-roots)9d\n" % data)
1175 ui.writenoi18n(b" roots: %(nb-ini_und-roots)9d\n" % data)
1159 ui.writenoi18n(b" common: %(nb-ini_und-common)9d\n" % data)
1176 ui.writenoi18n(b" common: %(nb-ini_und-common)9d\n" % data)
1160 ui.writenoi18n(b" missing: %(nb-ini_und-missing)9d\n" % data)
1177 ui.writenoi18n(b" missing: %(nb-ini_und-missing)9d\n" % data)
1161
1178
1162 if ui.verbose:
1179 if ui.verbose:
1163 ui.writenoi18n(
1180 ui.writenoi18n(
1164 b"common heads: %s\n"
1181 b"common heads: %s\n"
1165 % b" ".join(sorted(short(n) for n in heads_common))
1182 % b" ".join(sorted(short(n) for n in heads_common))
1166 )
1183 )
1167
1184
1168
1185
1169 _chunksize = 4 << 10
1186 _chunksize = 4 << 10
1170
1187
1171
1188
1172 @command(
1189 @command(
1173 b'debugdownload',
1190 b'debugdownload',
1174 [
1191 [
1175 (b'o', b'output', b'', _(b'path')),
1192 (b'o', b'output', b'', _(b'path')),
1176 ],
1193 ],
1177 optionalrepo=True,
1194 optionalrepo=True,
1178 )
1195 )
1179 def debugdownload(ui, repo, url, output=None, **opts):
1196 def debugdownload(ui, repo, url, output=None, **opts):
1180 """download a resource using Mercurial logic and config"""
1197 """download a resource using Mercurial logic and config"""
1181 fh = urlmod.open(ui, url, output)
1198 fh = urlmod.open(ui, url, output)
1182
1199
1183 dest = ui
1200 dest = ui
1184 if output:
1201 if output:
1185 dest = open(output, b"wb", _chunksize)
1202 dest = open(output, b"wb", _chunksize)
1186 try:
1203 try:
1187 data = fh.read(_chunksize)
1204 data = fh.read(_chunksize)
1188 while data:
1205 while data:
1189 dest.write(data)
1206 dest.write(data)
1190 data = fh.read(_chunksize)
1207 data = fh.read(_chunksize)
1191 finally:
1208 finally:
1192 if output:
1209 if output:
1193 dest.close()
1210 dest.close()
1194
1211
1195
1212
1196 @command(b'debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
1213 @command(b'debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
1197 def debugextensions(ui, repo, **opts):
1214 def debugextensions(ui, repo, **opts):
1198 '''show information about active extensions'''
1215 '''show information about active extensions'''
1199 opts = pycompat.byteskwargs(opts)
1216 opts = pycompat.byteskwargs(opts)
1200 exts = extensions.extensions(ui)
1217 exts = extensions.extensions(ui)
1201 hgver = util.version()
1218 hgver = util.version()
1202 fm = ui.formatter(b'debugextensions', opts)
1219 fm = ui.formatter(b'debugextensions', opts)
1203 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
1220 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
1204 isinternal = extensions.ismoduleinternal(extmod)
1221 isinternal = extensions.ismoduleinternal(extmod)
1205 extsource = None
1222 extsource = None
1206
1223
1207 if util.safehasattr(extmod, '__file__'):
1224 if util.safehasattr(extmod, '__file__'):
1208 extsource = pycompat.fsencode(extmod.__file__)
1225 extsource = pycompat.fsencode(extmod.__file__)
1209 elif getattr(sys, 'oxidized', False):
1226 elif getattr(sys, 'oxidized', False):
1210 extsource = pycompat.sysexecutable
1227 extsource = pycompat.sysexecutable
1211 if isinternal:
1228 if isinternal:
1212 exttestedwith = [] # never expose magic string to users
1229 exttestedwith = [] # never expose magic string to users
1213 else:
1230 else:
1214 exttestedwith = getattr(extmod, 'testedwith', b'').split()
1231 exttestedwith = getattr(extmod, 'testedwith', b'').split()
1215 extbuglink = getattr(extmod, 'buglink', None)
1232 extbuglink = getattr(extmod, 'buglink', None)
1216
1233
1217 fm.startitem()
1234 fm.startitem()
1218
1235
1219 if ui.quiet or ui.verbose:
1236 if ui.quiet or ui.verbose:
1220 fm.write(b'name', b'%s\n', extname)
1237 fm.write(b'name', b'%s\n', extname)
1221 else:
1238 else:
1222 fm.write(b'name', b'%s', extname)
1239 fm.write(b'name', b'%s', extname)
1223 if isinternal or hgver in exttestedwith:
1240 if isinternal or hgver in exttestedwith:
1224 fm.plain(b'\n')
1241 fm.plain(b'\n')
1225 elif not exttestedwith:
1242 elif not exttestedwith:
1226 fm.plain(_(b' (untested!)\n'))
1243 fm.plain(_(b' (untested!)\n'))
1227 else:
1244 else:
1228 lasttestedversion = exttestedwith[-1]
1245 lasttestedversion = exttestedwith[-1]
1229 fm.plain(b' (%s!)\n' % lasttestedversion)
1246 fm.plain(b' (%s!)\n' % lasttestedversion)
1230
1247
1231 fm.condwrite(
1248 fm.condwrite(
1232 ui.verbose and extsource,
1249 ui.verbose and extsource,
1233 b'source',
1250 b'source',
1234 _(b' location: %s\n'),
1251 _(b' location: %s\n'),
1235 extsource or b"",
1252 extsource or b"",
1236 )
1253 )
1237
1254
1238 if ui.verbose:
1255 if ui.verbose:
1239 fm.plain(_(b' bundled: %s\n') % [b'no', b'yes'][isinternal])
1256 fm.plain(_(b' bundled: %s\n') % [b'no', b'yes'][isinternal])
1240 fm.data(bundled=isinternal)
1257 fm.data(bundled=isinternal)
1241
1258
1242 fm.condwrite(
1259 fm.condwrite(
1243 ui.verbose and exttestedwith,
1260 ui.verbose and exttestedwith,
1244 b'testedwith',
1261 b'testedwith',
1245 _(b' tested with: %s\n'),
1262 _(b' tested with: %s\n'),
1246 fm.formatlist(exttestedwith, name=b'ver'),
1263 fm.formatlist(exttestedwith, name=b'ver'),
1247 )
1264 )
1248
1265
1249 fm.condwrite(
1266 fm.condwrite(
1250 ui.verbose and extbuglink,
1267 ui.verbose and extbuglink,
1251 b'buglink',
1268 b'buglink',
1252 _(b' bug reporting: %s\n'),
1269 _(b' bug reporting: %s\n'),
1253 extbuglink or b"",
1270 extbuglink or b"",
1254 )
1271 )
1255
1272
1256 fm.end()
1273 fm.end()
1257
1274
1258
1275
1259 @command(
1276 @command(
1260 b'debugfileset',
1277 b'debugfileset',
1261 [
1278 [
1262 (
1279 (
1263 b'r',
1280 b'r',
1264 b'rev',
1281 b'rev',
1265 b'',
1282 b'',
1266 _(b'apply the filespec on this revision'),
1283 _(b'apply the filespec on this revision'),
1267 _(b'REV'),
1284 _(b'REV'),
1268 ),
1285 ),
1269 (
1286 (
1270 b'',
1287 b'',
1271 b'all-files',
1288 b'all-files',
1272 False,
1289 False,
1273 _(b'test files from all revisions and working directory'),
1290 _(b'test files from all revisions and working directory'),
1274 ),
1291 ),
1275 (
1292 (
1276 b's',
1293 b's',
1277 b'show-matcher',
1294 b'show-matcher',
1278 None,
1295 None,
1279 _(b'print internal representation of matcher'),
1296 _(b'print internal representation of matcher'),
1280 ),
1297 ),
1281 (
1298 (
1282 b'p',
1299 b'p',
1283 b'show-stage',
1300 b'show-stage',
1284 [],
1301 [],
1285 _(b'print parsed tree at the given stage'),
1302 _(b'print parsed tree at the given stage'),
1286 _(b'NAME'),
1303 _(b'NAME'),
1287 ),
1304 ),
1288 ],
1305 ],
1289 _(b'[-r REV] [--all-files] [OPTION]... FILESPEC'),
1306 _(b'[-r REV] [--all-files] [OPTION]... FILESPEC'),
1290 )
1307 )
1291 def debugfileset(ui, repo, expr, **opts):
1308 def debugfileset(ui, repo, expr, **opts):
1292 '''parse and apply a fileset specification'''
1309 '''parse and apply a fileset specification'''
1293 from . import fileset
1310 from . import fileset
1294
1311
1295 fileset.symbols # force import of fileset so we have predicates to optimize
1312 fileset.symbols # force import of fileset so we have predicates to optimize
1296 opts = pycompat.byteskwargs(opts)
1313 opts = pycompat.byteskwargs(opts)
1297 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
1314 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
1298
1315
1299 stages = [
1316 stages = [
1300 (b'parsed', pycompat.identity),
1317 (b'parsed', pycompat.identity),
1301 (b'analyzed', filesetlang.analyze),
1318 (b'analyzed', filesetlang.analyze),
1302 (b'optimized', filesetlang.optimize),
1319 (b'optimized', filesetlang.optimize),
1303 ]
1320 ]
1304 stagenames = {n for n, f in stages}
1321 stagenames = {n for n, f in stages}
1305
1322
1306 showalways = set()
1323 showalways = set()
1307 if ui.verbose and not opts[b'show_stage']:
1324 if ui.verbose and not opts[b'show_stage']:
1308 # show parsed tree by --verbose (deprecated)
1325 # show parsed tree by --verbose (deprecated)
1309 showalways.add(b'parsed')
1326 showalways.add(b'parsed')
1310 if opts[b'show_stage'] == [b'all']:
1327 if opts[b'show_stage'] == [b'all']:
1311 showalways.update(stagenames)
1328 showalways.update(stagenames)
1312 else:
1329 else:
1313 for n in opts[b'show_stage']:
1330 for n in opts[b'show_stage']:
1314 if n not in stagenames:
1331 if n not in stagenames:
1315 raise error.Abort(_(b'invalid stage name: %s') % n)
1332 raise error.Abort(_(b'invalid stage name: %s') % n)
1316 showalways.update(opts[b'show_stage'])
1333 showalways.update(opts[b'show_stage'])
1317
1334
1318 tree = filesetlang.parse(expr)
1335 tree = filesetlang.parse(expr)
1319 for n, f in stages:
1336 for n, f in stages:
1320 tree = f(tree)
1337 tree = f(tree)
1321 if n in showalways:
1338 if n in showalways:
1322 if opts[b'show_stage'] or n != b'parsed':
1339 if opts[b'show_stage'] or n != b'parsed':
1323 ui.write(b"* %s:\n" % n)
1340 ui.write(b"* %s:\n" % n)
1324 ui.write(filesetlang.prettyformat(tree), b"\n")
1341 ui.write(filesetlang.prettyformat(tree), b"\n")
1325
1342
1326 files = set()
1343 files = set()
1327 if opts[b'all_files']:
1344 if opts[b'all_files']:
1328 for r in repo:
1345 for r in repo:
1329 c = repo[r]
1346 c = repo[r]
1330 files.update(c.files())
1347 files.update(c.files())
1331 files.update(c.substate)
1348 files.update(c.substate)
1332 if opts[b'all_files'] or ctx.rev() is None:
1349 if opts[b'all_files'] or ctx.rev() is None:
1333 wctx = repo[None]
1350 wctx = repo[None]
1334 files.update(
1351 files.update(
1335 repo.dirstate.walk(
1352 repo.dirstate.walk(
1336 scmutil.matchall(repo),
1353 scmutil.matchall(repo),
1337 subrepos=list(wctx.substate),
1354 subrepos=list(wctx.substate),
1338 unknown=True,
1355 unknown=True,
1339 ignored=True,
1356 ignored=True,
1340 )
1357 )
1341 )
1358 )
1342 files.update(wctx.substate)
1359 files.update(wctx.substate)
1343 else:
1360 else:
1344 files.update(ctx.files())
1361 files.update(ctx.files())
1345 files.update(ctx.substate)
1362 files.update(ctx.substate)
1346
1363
1347 m = ctx.matchfileset(repo.getcwd(), expr)
1364 m = ctx.matchfileset(repo.getcwd(), expr)
1348 if opts[b'show_matcher'] or (opts[b'show_matcher'] is None and ui.verbose):
1365 if opts[b'show_matcher'] or (opts[b'show_matcher'] is None and ui.verbose):
1349 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
1366 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
1350 for f in sorted(files):
1367 for f in sorted(files):
1351 if not m(f):
1368 if not m(f):
1352 continue
1369 continue
1353 ui.write(b"%s\n" % f)
1370 ui.write(b"%s\n" % f)
1354
1371
1355
1372
1356 @command(b'debugformat', [] + cmdutil.formatteropts)
1373 @command(b'debugformat', [] + cmdutil.formatteropts)
1357 def debugformat(ui, repo, **opts):
1374 def debugformat(ui, repo, **opts):
1358 """display format information about the current repository
1375 """display format information about the current repository
1359
1376
1360 Use --verbose to get extra information about current config value and
1377 Use --verbose to get extra information about current config value and
1361 Mercurial default."""
1378 Mercurial default."""
1362 opts = pycompat.byteskwargs(opts)
1379 opts = pycompat.byteskwargs(opts)
1363 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
1380 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
1364 maxvariantlength = max(len(b'format-variant'), maxvariantlength)
1381 maxvariantlength = max(len(b'format-variant'), maxvariantlength)
1365
1382
1366 def makeformatname(name):
1383 def makeformatname(name):
1367 return b'%s:' + (b' ' * (maxvariantlength - len(name)))
1384 return b'%s:' + (b' ' * (maxvariantlength - len(name)))
1368
1385
1369 fm = ui.formatter(b'debugformat', opts)
1386 fm = ui.formatter(b'debugformat', opts)
1370 if fm.isplain():
1387 if fm.isplain():
1371
1388
1372 def formatvalue(value):
1389 def formatvalue(value):
1373 if util.safehasattr(value, b'startswith'):
1390 if util.safehasattr(value, b'startswith'):
1374 return value
1391 return value
1375 if value:
1392 if value:
1376 return b'yes'
1393 return b'yes'
1377 else:
1394 else:
1378 return b'no'
1395 return b'no'
1379
1396
1380 else:
1397 else:
1381 formatvalue = pycompat.identity
1398 formatvalue = pycompat.identity
1382
1399
1383 fm.plain(b'format-variant')
1400 fm.plain(b'format-variant')
1384 fm.plain(b' ' * (maxvariantlength - len(b'format-variant')))
1401 fm.plain(b' ' * (maxvariantlength - len(b'format-variant')))
1385 fm.plain(b' repo')
1402 fm.plain(b' repo')
1386 if ui.verbose:
1403 if ui.verbose:
1387 fm.plain(b' config default')
1404 fm.plain(b' config default')
1388 fm.plain(b'\n')
1405 fm.plain(b'\n')
1389 for fv in upgrade.allformatvariant:
1406 for fv in upgrade.allformatvariant:
1390 fm.startitem()
1407 fm.startitem()
1391 repovalue = fv.fromrepo(repo)
1408 repovalue = fv.fromrepo(repo)
1392 configvalue = fv.fromconfig(repo)
1409 configvalue = fv.fromconfig(repo)
1393
1410
1394 if repovalue != configvalue:
1411 if repovalue != configvalue:
1395 namelabel = b'formatvariant.name.mismatchconfig'
1412 namelabel = b'formatvariant.name.mismatchconfig'
1396 repolabel = b'formatvariant.repo.mismatchconfig'
1413 repolabel = b'formatvariant.repo.mismatchconfig'
1397 elif repovalue != fv.default:
1414 elif repovalue != fv.default:
1398 namelabel = b'formatvariant.name.mismatchdefault'
1415 namelabel = b'formatvariant.name.mismatchdefault'
1399 repolabel = b'formatvariant.repo.mismatchdefault'
1416 repolabel = b'formatvariant.repo.mismatchdefault'
1400 else:
1417 else:
1401 namelabel = b'formatvariant.name.uptodate'
1418 namelabel = b'formatvariant.name.uptodate'
1402 repolabel = b'formatvariant.repo.uptodate'
1419 repolabel = b'formatvariant.repo.uptodate'
1403
1420
1404 fm.write(b'name', makeformatname(fv.name), fv.name, label=namelabel)
1421 fm.write(b'name', makeformatname(fv.name), fv.name, label=namelabel)
1405 fm.write(b'repo', b' %3s', formatvalue(repovalue), label=repolabel)
1422 fm.write(b'repo', b' %3s', formatvalue(repovalue), label=repolabel)
1406 if fv.default != configvalue:
1423 if fv.default != configvalue:
1407 configlabel = b'formatvariant.config.special'
1424 configlabel = b'formatvariant.config.special'
1408 else:
1425 else:
1409 configlabel = b'formatvariant.config.default'
1426 configlabel = b'formatvariant.config.default'
1410 fm.condwrite(
1427 fm.condwrite(
1411 ui.verbose,
1428 ui.verbose,
1412 b'config',
1429 b'config',
1413 b' %6s',
1430 b' %6s',
1414 formatvalue(configvalue),
1431 formatvalue(configvalue),
1415 label=configlabel,
1432 label=configlabel,
1416 )
1433 )
1417 fm.condwrite(
1434 fm.condwrite(
1418 ui.verbose,
1435 ui.verbose,
1419 b'default',
1436 b'default',
1420 b' %7s',
1437 b' %7s',
1421 formatvalue(fv.default),
1438 formatvalue(fv.default),
1422 label=b'formatvariant.default',
1439 label=b'formatvariant.default',
1423 )
1440 )
1424 fm.plain(b'\n')
1441 fm.plain(b'\n')
1425 fm.end()
1442 fm.end()
1426
1443
1427
1444
1428 @command(b'debugfsinfo', [], _(b'[PATH]'), norepo=True)
1445 @command(b'debugfsinfo', [], _(b'[PATH]'), norepo=True)
1429 def debugfsinfo(ui, path=b"."):
1446 def debugfsinfo(ui, path=b"."):
1430 """show information detected about current filesystem"""
1447 """show information detected about current filesystem"""
1431 ui.writenoi18n(b'path: %s\n' % path)
1448 ui.writenoi18n(b'path: %s\n' % path)
1432 ui.writenoi18n(
1449 ui.writenoi18n(
1433 b'mounted on: %s\n' % (util.getfsmountpoint(path) or b'(unknown)')
1450 b'mounted on: %s\n' % (util.getfsmountpoint(path) or b'(unknown)')
1434 )
1451 )
1435 ui.writenoi18n(b'exec: %s\n' % (util.checkexec(path) and b'yes' or b'no'))
1452 ui.writenoi18n(b'exec: %s\n' % (util.checkexec(path) and b'yes' or b'no'))
1436 ui.writenoi18n(b'fstype: %s\n' % (util.getfstype(path) or b'(unknown)'))
1453 ui.writenoi18n(b'fstype: %s\n' % (util.getfstype(path) or b'(unknown)'))
1437 ui.writenoi18n(
1454 ui.writenoi18n(
1438 b'symlink: %s\n' % (util.checklink(path) and b'yes' or b'no')
1455 b'symlink: %s\n' % (util.checklink(path) and b'yes' or b'no')
1439 )
1456 )
1440 ui.writenoi18n(
1457 ui.writenoi18n(
1441 b'hardlink: %s\n' % (util.checknlink(path) and b'yes' or b'no')
1458 b'hardlink: %s\n' % (util.checknlink(path) and b'yes' or b'no')
1442 )
1459 )
1443 casesensitive = b'(unknown)'
1460 casesensitive = b'(unknown)'
1444 try:
1461 try:
1445 with pycompat.namedtempfile(prefix=b'.debugfsinfo', dir=path) as f:
1462 with pycompat.namedtempfile(prefix=b'.debugfsinfo', dir=path) as f:
1446 casesensitive = util.fscasesensitive(f.name) and b'yes' or b'no'
1463 casesensitive = util.fscasesensitive(f.name) and b'yes' or b'no'
1447 except OSError:
1464 except OSError:
1448 pass
1465 pass
1449 ui.writenoi18n(b'case-sensitive: %s\n' % casesensitive)
1466 ui.writenoi18n(b'case-sensitive: %s\n' % casesensitive)
1450
1467
1451
1468
1452 @command(
1469 @command(
1453 b'debuggetbundle',
1470 b'debuggetbundle',
1454 [
1471 [
1455 (b'H', b'head', [], _(b'id of head node'), _(b'ID')),
1472 (b'H', b'head', [], _(b'id of head node'), _(b'ID')),
1456 (b'C', b'common', [], _(b'id of common node'), _(b'ID')),
1473 (b'C', b'common', [], _(b'id of common node'), _(b'ID')),
1457 (
1474 (
1458 b't',
1475 b't',
1459 b'type',
1476 b'type',
1460 b'bzip2',
1477 b'bzip2',
1461 _(b'bundle compression type to use'),
1478 _(b'bundle compression type to use'),
1462 _(b'TYPE'),
1479 _(b'TYPE'),
1463 ),
1480 ),
1464 ],
1481 ],
1465 _(b'REPO FILE [-H|-C ID]...'),
1482 _(b'REPO FILE [-H|-C ID]...'),
1466 norepo=True,
1483 norepo=True,
1467 )
1484 )
1468 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1485 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1469 """retrieves a bundle from a repo
1486 """retrieves a bundle from a repo
1470
1487
1471 Every ID must be a full-length hex node id string. Saves the bundle to the
1488 Every ID must be a full-length hex node id string. Saves the bundle to the
1472 given file.
1489 given file.
1473 """
1490 """
1474 opts = pycompat.byteskwargs(opts)
1491 opts = pycompat.byteskwargs(opts)
1475 repo = hg.peer(ui, opts, repopath)
1492 repo = hg.peer(ui, opts, repopath)
1476 if not repo.capable(b'getbundle'):
1493 if not repo.capable(b'getbundle'):
1477 raise error.Abort(b"getbundle() not supported by target repository")
1494 raise error.Abort(b"getbundle() not supported by target repository")
1478 args = {}
1495 args = {}
1479 if common:
1496 if common:
1480 args['common'] = [bin(s) for s in common]
1497 args['common'] = [bin(s) for s in common]
1481 if head:
1498 if head:
1482 args['heads'] = [bin(s) for s in head]
1499 args['heads'] = [bin(s) for s in head]
1483 # TODO: get desired bundlecaps from command line.
1500 # TODO: get desired bundlecaps from command line.
1484 args['bundlecaps'] = None
1501 args['bundlecaps'] = None
1485 bundle = repo.getbundle(b'debug', **args)
1502 bundle = repo.getbundle(b'debug', **args)
1486
1503
1487 bundletype = opts.get(b'type', b'bzip2').lower()
1504 bundletype = opts.get(b'type', b'bzip2').lower()
1488 btypes = {
1505 btypes = {
1489 b'none': b'HG10UN',
1506 b'none': b'HG10UN',
1490 b'bzip2': b'HG10BZ',
1507 b'bzip2': b'HG10BZ',
1491 b'gzip': b'HG10GZ',
1508 b'gzip': b'HG10GZ',
1492 b'bundle2': b'HG20',
1509 b'bundle2': b'HG20',
1493 }
1510 }
1494 bundletype = btypes.get(bundletype)
1511 bundletype = btypes.get(bundletype)
1495 if bundletype not in bundle2.bundletypes:
1512 if bundletype not in bundle2.bundletypes:
1496 raise error.Abort(_(b'unknown bundle type specified with --type'))
1513 raise error.Abort(_(b'unknown bundle type specified with --type'))
1497 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
1514 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
1498
1515
1499
1516
1500 @command(b'debugignore', [], b'[FILE]')
1517 @command(b'debugignore', [], b'[FILE]')
1501 def debugignore(ui, repo, *files, **opts):
1518 def debugignore(ui, repo, *files, **opts):
1502 """display the combined ignore pattern and information about ignored files
1519 """display the combined ignore pattern and information about ignored files
1503
1520
1504 With no argument display the combined ignore pattern.
1521 With no argument display the combined ignore pattern.
1505
1522
1506 Given space separated file names, shows if the given file is ignored and
1523 Given space separated file names, shows if the given file is ignored and
1507 if so, show the ignore rule (file and line number) that matched it.
1524 if so, show the ignore rule (file and line number) that matched it.
1508 """
1525 """
1509 ignore = repo.dirstate._ignore
1526 ignore = repo.dirstate._ignore
1510 if not files:
1527 if not files:
1511 # Show all the patterns
1528 # Show all the patterns
1512 ui.write(b"%s\n" % pycompat.byterepr(ignore))
1529 ui.write(b"%s\n" % pycompat.byterepr(ignore))
1513 else:
1530 else:
1514 m = scmutil.match(repo[None], pats=files)
1531 m = scmutil.match(repo[None], pats=files)
1515 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
1532 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
1516 for f in m.files():
1533 for f in m.files():
1517 nf = util.normpath(f)
1534 nf = util.normpath(f)
1518 ignored = None
1535 ignored = None
1519 ignoredata = None
1536 ignoredata = None
1520 if nf != b'.':
1537 if nf != b'.':
1521 if ignore(nf):
1538 if ignore(nf):
1522 ignored = nf
1539 ignored = nf
1523 ignoredata = repo.dirstate._ignorefileandline(nf)
1540 ignoredata = repo.dirstate._ignorefileandline(nf)
1524 else:
1541 else:
1525 for p in pathutil.finddirs(nf):
1542 for p in pathutil.finddirs(nf):
1526 if ignore(p):
1543 if ignore(p):
1527 ignored = p
1544 ignored = p
1528 ignoredata = repo.dirstate._ignorefileandline(p)
1545 ignoredata = repo.dirstate._ignorefileandline(p)
1529 break
1546 break
1530 if ignored:
1547 if ignored:
1531 if ignored == nf:
1548 if ignored == nf:
1532 ui.write(_(b"%s is ignored\n") % uipathfn(f))
1549 ui.write(_(b"%s is ignored\n") % uipathfn(f))
1533 else:
1550 else:
1534 ui.write(
1551 ui.write(
1535 _(
1552 _(
1536 b"%s is ignored because of "
1553 b"%s is ignored because of "
1537 b"containing directory %s\n"
1554 b"containing directory %s\n"
1538 )
1555 )
1539 % (uipathfn(f), ignored)
1556 % (uipathfn(f), ignored)
1540 )
1557 )
1541 ignorefile, lineno, line = ignoredata
1558 ignorefile, lineno, line = ignoredata
1542 ui.write(
1559 ui.write(
1543 _(b"(ignore rule in %s, line %d: '%s')\n")
1560 _(b"(ignore rule in %s, line %d: '%s')\n")
1544 % (ignorefile, lineno, line)
1561 % (ignorefile, lineno, line)
1545 )
1562 )
1546 else:
1563 else:
1547 ui.write(_(b"%s is not ignored\n") % uipathfn(f))
1564 ui.write(_(b"%s is not ignored\n") % uipathfn(f))
1548
1565
1549
1566
1550 @command(
1567 @command(
1551 b'debugindex',
1568 b'debugindex',
1552 cmdutil.debugrevlogopts + cmdutil.formatteropts,
1569 cmdutil.debugrevlogopts + cmdutil.formatteropts,
1553 _(b'-c|-m|FILE'),
1570 _(b'-c|-m|FILE'),
1554 )
1571 )
1555 def debugindex(ui, repo, file_=None, **opts):
1572 def debugindex(ui, repo, file_=None, **opts):
1556 """dump index data for a storage primitive"""
1573 """dump index data for a storage primitive"""
1557 opts = pycompat.byteskwargs(opts)
1574 opts = pycompat.byteskwargs(opts)
1558 store = cmdutil.openstorage(repo, b'debugindex', file_, opts)
1575 store = cmdutil.openstorage(repo, b'debugindex', file_, opts)
1559
1576
1560 if ui.debugflag:
1577 if ui.debugflag:
1561 shortfn = hex
1578 shortfn = hex
1562 else:
1579 else:
1563 shortfn = short
1580 shortfn = short
1564
1581
1565 idlen = 12
1582 idlen = 12
1566 for i in store:
1583 for i in store:
1567 idlen = len(shortfn(store.node(i)))
1584 idlen = len(shortfn(store.node(i)))
1568 break
1585 break
1569
1586
1570 fm = ui.formatter(b'debugindex', opts)
1587 fm = ui.formatter(b'debugindex', opts)
1571 fm.plain(
1588 fm.plain(
1572 b' rev linkrev %s %s p2\n'
1589 b' rev linkrev %s %s p2\n'
1573 % (b'nodeid'.ljust(idlen), b'p1'.ljust(idlen))
1590 % (b'nodeid'.ljust(idlen), b'p1'.ljust(idlen))
1574 )
1591 )
1575
1592
1576 for rev in store:
1593 for rev in store:
1577 node = store.node(rev)
1594 node = store.node(rev)
1578 parents = store.parents(node)
1595 parents = store.parents(node)
1579
1596
1580 fm.startitem()
1597 fm.startitem()
1581 fm.write(b'rev', b'%6d ', rev)
1598 fm.write(b'rev', b'%6d ', rev)
1582 fm.write(b'linkrev', b'%7d ', store.linkrev(rev))
1599 fm.write(b'linkrev', b'%7d ', store.linkrev(rev))
1583 fm.write(b'node', b'%s ', shortfn(node))
1600 fm.write(b'node', b'%s ', shortfn(node))
1584 fm.write(b'p1', b'%s ', shortfn(parents[0]))
1601 fm.write(b'p1', b'%s ', shortfn(parents[0]))
1585 fm.write(b'p2', b'%s', shortfn(parents[1]))
1602 fm.write(b'p2', b'%s', shortfn(parents[1]))
1586 fm.plain(b'\n')
1603 fm.plain(b'\n')
1587
1604
1588 fm.end()
1605 fm.end()
1589
1606
1590
1607
1591 @command(
1608 @command(
1592 b'debugindexdot',
1609 b'debugindexdot',
1593 cmdutil.debugrevlogopts,
1610 cmdutil.debugrevlogopts,
1594 _(b'-c|-m|FILE'),
1611 _(b'-c|-m|FILE'),
1595 optionalrepo=True,
1612 optionalrepo=True,
1596 )
1613 )
1597 def debugindexdot(ui, repo, file_=None, **opts):
1614 def debugindexdot(ui, repo, file_=None, **opts):
1598 """dump an index DAG as a graphviz dot file"""
1615 """dump an index DAG as a graphviz dot file"""
1599 opts = pycompat.byteskwargs(opts)
1616 opts = pycompat.byteskwargs(opts)
1600 r = cmdutil.openstorage(repo, b'debugindexdot', file_, opts)
1617 r = cmdutil.openstorage(repo, b'debugindexdot', file_, opts)
1601 ui.writenoi18n(b"digraph G {\n")
1618 ui.writenoi18n(b"digraph G {\n")
1602 for i in r:
1619 for i in r:
1603 node = r.node(i)
1620 node = r.node(i)
1604 pp = r.parents(node)
1621 pp = r.parents(node)
1605 ui.write(b"\t%d -> %d\n" % (r.rev(pp[0]), i))
1622 ui.write(b"\t%d -> %d\n" % (r.rev(pp[0]), i))
1606 if pp[1] != nullid:
1623 if pp[1] != nullid:
1607 ui.write(b"\t%d -> %d\n" % (r.rev(pp[1]), i))
1624 ui.write(b"\t%d -> %d\n" % (r.rev(pp[1]), i))
1608 ui.write(b"}\n")
1625 ui.write(b"}\n")
1609
1626
1610
1627
1611 @command(b'debugindexstats', [])
1628 @command(b'debugindexstats', [])
1612 def debugindexstats(ui, repo):
1629 def debugindexstats(ui, repo):
1613 """show stats related to the changelog index"""
1630 """show stats related to the changelog index"""
1614 repo.changelog.shortest(nullid, 1)
1631 repo.changelog.shortest(nullid, 1)
1615 index = repo.changelog.index
1632 index = repo.changelog.index
1616 if not util.safehasattr(index, b'stats'):
1633 if not util.safehasattr(index, b'stats'):
1617 raise error.Abort(_(b'debugindexstats only works with native code'))
1634 raise error.Abort(_(b'debugindexstats only works with native code'))
1618 for k, v in sorted(index.stats().items()):
1635 for k, v in sorted(index.stats().items()):
1619 ui.write(b'%s: %d\n' % (k, v))
1636 ui.write(b'%s: %d\n' % (k, v))
1620
1637
1621
1638
1622 @command(b'debuginstall', [] + cmdutil.formatteropts, b'', norepo=True)
1639 @command(b'debuginstall', [] + cmdutil.formatteropts, b'', norepo=True)
1623 def debuginstall(ui, **opts):
1640 def debuginstall(ui, **opts):
1624 """test Mercurial installation
1641 """test Mercurial installation
1625
1642
1626 Returns 0 on success.
1643 Returns 0 on success.
1627 """
1644 """
1628 opts = pycompat.byteskwargs(opts)
1645 opts = pycompat.byteskwargs(opts)
1629
1646
1630 problems = 0
1647 problems = 0
1631
1648
1632 fm = ui.formatter(b'debuginstall', opts)
1649 fm = ui.formatter(b'debuginstall', opts)
1633 fm.startitem()
1650 fm.startitem()
1634
1651
1635 # encoding might be unknown or wrong. don't translate these messages.
1652 # encoding might be unknown or wrong. don't translate these messages.
1636 fm.write(b'encoding', b"checking encoding (%s)...\n", encoding.encoding)
1653 fm.write(b'encoding', b"checking encoding (%s)...\n", encoding.encoding)
1637 err = None
1654 err = None
1638 try:
1655 try:
1639 codecs.lookup(pycompat.sysstr(encoding.encoding))
1656 codecs.lookup(pycompat.sysstr(encoding.encoding))
1640 except LookupError as inst:
1657 except LookupError as inst:
1641 err = stringutil.forcebytestr(inst)
1658 err = stringutil.forcebytestr(inst)
1642 problems += 1
1659 problems += 1
1643 fm.condwrite(
1660 fm.condwrite(
1644 err,
1661 err,
1645 b'encodingerror',
1662 b'encodingerror',
1646 b" %s\n (check that your locale is properly set)\n",
1663 b" %s\n (check that your locale is properly set)\n",
1647 err,
1664 err,
1648 )
1665 )
1649
1666
1650 # Python
1667 # Python
1651 pythonlib = None
1668 pythonlib = None
1652 if util.safehasattr(os, '__file__'):
1669 if util.safehasattr(os, '__file__'):
1653 pythonlib = os.path.dirname(pycompat.fsencode(os.__file__))
1670 pythonlib = os.path.dirname(pycompat.fsencode(os.__file__))
1654 elif getattr(sys, 'oxidized', False):
1671 elif getattr(sys, 'oxidized', False):
1655 pythonlib = pycompat.sysexecutable
1672 pythonlib = pycompat.sysexecutable
1656
1673
1657 fm.write(
1674 fm.write(
1658 b'pythonexe',
1675 b'pythonexe',
1659 _(b"checking Python executable (%s)\n"),
1676 _(b"checking Python executable (%s)\n"),
1660 pycompat.sysexecutable or _(b"unknown"),
1677 pycompat.sysexecutable or _(b"unknown"),
1661 )
1678 )
1662 fm.write(
1679 fm.write(
1663 b'pythonimplementation',
1680 b'pythonimplementation',
1664 _(b"checking Python implementation (%s)\n"),
1681 _(b"checking Python implementation (%s)\n"),
1665 pycompat.sysbytes(platform.python_implementation()),
1682 pycompat.sysbytes(platform.python_implementation()),
1666 )
1683 )
1667 fm.write(
1684 fm.write(
1668 b'pythonver',
1685 b'pythonver',
1669 _(b"checking Python version (%s)\n"),
1686 _(b"checking Python version (%s)\n"),
1670 (b"%d.%d.%d" % sys.version_info[:3]),
1687 (b"%d.%d.%d" % sys.version_info[:3]),
1671 )
1688 )
1672 fm.write(
1689 fm.write(
1673 b'pythonlib',
1690 b'pythonlib',
1674 _(b"checking Python lib (%s)...\n"),
1691 _(b"checking Python lib (%s)...\n"),
1675 pythonlib or _(b"unknown"),
1692 pythonlib or _(b"unknown"),
1676 )
1693 )
1677
1694
1678 try:
1695 try:
1679 from . import rustext
1696 from . import rustext
1680
1697
1681 rustext.__doc__ # trigger lazy import
1698 rustext.__doc__ # trigger lazy import
1682 except ImportError:
1699 except ImportError:
1683 rustext = None
1700 rustext = None
1684
1701
1685 security = set(sslutil.supportedprotocols)
1702 security = set(sslutil.supportedprotocols)
1686 if sslutil.hassni:
1703 if sslutil.hassni:
1687 security.add(b'sni')
1704 security.add(b'sni')
1688
1705
1689 fm.write(
1706 fm.write(
1690 b'pythonsecurity',
1707 b'pythonsecurity',
1691 _(b"checking Python security support (%s)\n"),
1708 _(b"checking Python security support (%s)\n"),
1692 fm.formatlist(sorted(security), name=b'protocol', fmt=b'%s', sep=b','),
1709 fm.formatlist(sorted(security), name=b'protocol', fmt=b'%s', sep=b','),
1693 )
1710 )
1694
1711
1695 # These are warnings, not errors. So don't increment problem count. This
1712 # These are warnings, not errors. So don't increment problem count. This
1696 # may change in the future.
1713 # may change in the future.
1697 if b'tls1.2' not in security:
1714 if b'tls1.2' not in security:
1698 fm.plain(
1715 fm.plain(
1699 _(
1716 _(
1700 b' TLS 1.2 not supported by Python install; '
1717 b' TLS 1.2 not supported by Python install; '
1701 b'network connections lack modern security\n'
1718 b'network connections lack modern security\n'
1702 )
1719 )
1703 )
1720 )
1704 if b'sni' not in security:
1721 if b'sni' not in security:
1705 fm.plain(
1722 fm.plain(
1706 _(
1723 _(
1707 b' SNI not supported by Python install; may have '
1724 b' SNI not supported by Python install; may have '
1708 b'connectivity issues with some servers\n'
1725 b'connectivity issues with some servers\n'
1709 )
1726 )
1710 )
1727 )
1711
1728
1712 fm.plain(
1729 fm.plain(
1713 _(
1730 _(
1714 b"checking Rust extensions (%s)\n"
1731 b"checking Rust extensions (%s)\n"
1715 % (b'missing' if rustext is None else b'installed')
1732 % (b'missing' if rustext is None else b'installed')
1716 ),
1733 ),
1717 )
1734 )
1718
1735
1719 # TODO print CA cert info
1736 # TODO print CA cert info
1720
1737
1721 # hg version
1738 # hg version
1722 hgver = util.version()
1739 hgver = util.version()
1723 fm.write(
1740 fm.write(
1724 b'hgver', _(b"checking Mercurial version (%s)\n"), hgver.split(b'+')[0]
1741 b'hgver', _(b"checking Mercurial version (%s)\n"), hgver.split(b'+')[0]
1725 )
1742 )
1726 fm.write(
1743 fm.write(
1727 b'hgverextra',
1744 b'hgverextra',
1728 _(b"checking Mercurial custom build (%s)\n"),
1745 _(b"checking Mercurial custom build (%s)\n"),
1729 b'+'.join(hgver.split(b'+')[1:]),
1746 b'+'.join(hgver.split(b'+')[1:]),
1730 )
1747 )
1731
1748
1732 # compiled modules
1749 # compiled modules
1733 hgmodules = None
1750 hgmodules = None
1734 if util.safehasattr(sys.modules[__name__], '__file__'):
1751 if util.safehasattr(sys.modules[__name__], '__file__'):
1735 hgmodules = os.path.dirname(pycompat.fsencode(__file__))
1752 hgmodules = os.path.dirname(pycompat.fsencode(__file__))
1736 elif getattr(sys, 'oxidized', False):
1753 elif getattr(sys, 'oxidized', False):
1737 hgmodules = pycompat.sysexecutable
1754 hgmodules = pycompat.sysexecutable
1738
1755
1739 fm.write(
1756 fm.write(
1740 b'hgmodulepolicy', _(b"checking module policy (%s)\n"), policy.policy
1757 b'hgmodulepolicy', _(b"checking module policy (%s)\n"), policy.policy
1741 )
1758 )
1742 fm.write(
1759 fm.write(
1743 b'hgmodules',
1760 b'hgmodules',
1744 _(b"checking installed modules (%s)...\n"),
1761 _(b"checking installed modules (%s)...\n"),
1745 hgmodules or _(b"unknown"),
1762 hgmodules or _(b"unknown"),
1746 )
1763 )
1747
1764
1748 rustandc = policy.policy in (b'rust+c', b'rust+c-allow')
1765 rustandc = policy.policy in (b'rust+c', b'rust+c-allow')
1749 rustext = rustandc # for now, that's the only case
1766 rustext = rustandc # for now, that's the only case
1750 cext = policy.policy in (b'c', b'allow') or rustandc
1767 cext = policy.policy in (b'c', b'allow') or rustandc
1751 nopure = cext or rustext
1768 nopure = cext or rustext
1752 if nopure:
1769 if nopure:
1753 err = None
1770 err = None
1754 try:
1771 try:
1755 if cext:
1772 if cext:
1756 from .cext import ( # pytype: disable=import-error
1773 from .cext import ( # pytype: disable=import-error
1757 base85,
1774 base85,
1758 bdiff,
1775 bdiff,
1759 mpatch,
1776 mpatch,
1760 osutil,
1777 osutil,
1761 )
1778 )
1762
1779
1763 # quiet pyflakes
1780 # quiet pyflakes
1764 dir(bdiff), dir(mpatch), dir(base85), dir(osutil)
1781 dir(bdiff), dir(mpatch), dir(base85), dir(osutil)
1765 if rustext:
1782 if rustext:
1766 from .rustext import ( # pytype: disable=import-error
1783 from .rustext import ( # pytype: disable=import-error
1767 ancestor,
1784 ancestor,
1768 dirstate,
1785 dirstate,
1769 )
1786 )
1770
1787
1771 dir(ancestor), dir(dirstate) # quiet pyflakes
1788 dir(ancestor), dir(dirstate) # quiet pyflakes
1772 except Exception as inst:
1789 except Exception as inst:
1773 err = stringutil.forcebytestr(inst)
1790 err = stringutil.forcebytestr(inst)
1774 problems += 1
1791 problems += 1
1775 fm.condwrite(err, b'extensionserror', b" %s\n", err)
1792 fm.condwrite(err, b'extensionserror', b" %s\n", err)
1776
1793
1777 compengines = util.compengines._engines.values()
1794 compengines = util.compengines._engines.values()
1778 fm.write(
1795 fm.write(
1779 b'compengines',
1796 b'compengines',
1780 _(b'checking registered compression engines (%s)\n'),
1797 _(b'checking registered compression engines (%s)\n'),
1781 fm.formatlist(
1798 fm.formatlist(
1782 sorted(e.name() for e in compengines),
1799 sorted(e.name() for e in compengines),
1783 name=b'compengine',
1800 name=b'compengine',
1784 fmt=b'%s',
1801 fmt=b'%s',
1785 sep=b', ',
1802 sep=b', ',
1786 ),
1803 ),
1787 )
1804 )
1788 fm.write(
1805 fm.write(
1789 b'compenginesavail',
1806 b'compenginesavail',
1790 _(b'checking available compression engines (%s)\n'),
1807 _(b'checking available compression engines (%s)\n'),
1791 fm.formatlist(
1808 fm.formatlist(
1792 sorted(e.name() for e in compengines if e.available()),
1809 sorted(e.name() for e in compengines if e.available()),
1793 name=b'compengine',
1810 name=b'compengine',
1794 fmt=b'%s',
1811 fmt=b'%s',
1795 sep=b', ',
1812 sep=b', ',
1796 ),
1813 ),
1797 )
1814 )
1798 wirecompengines = compression.compengines.supportedwireengines(
1815 wirecompengines = compression.compengines.supportedwireengines(
1799 compression.SERVERROLE
1816 compression.SERVERROLE
1800 )
1817 )
1801 fm.write(
1818 fm.write(
1802 b'compenginesserver',
1819 b'compenginesserver',
1803 _(
1820 _(
1804 b'checking available compression engines '
1821 b'checking available compression engines '
1805 b'for wire protocol (%s)\n'
1822 b'for wire protocol (%s)\n'
1806 ),
1823 ),
1807 fm.formatlist(
1824 fm.formatlist(
1808 [e.name() for e in wirecompengines if e.wireprotosupport()],
1825 [e.name() for e in wirecompengines if e.wireprotosupport()],
1809 name=b'compengine',
1826 name=b'compengine',
1810 fmt=b'%s',
1827 fmt=b'%s',
1811 sep=b', ',
1828 sep=b', ',
1812 ),
1829 ),
1813 )
1830 )
1814 re2 = b'missing'
1831 re2 = b'missing'
1815 if util._re2:
1832 if util._re2:
1816 re2 = b'available'
1833 re2 = b'available'
1817 fm.plain(_(b'checking "re2" regexp engine (%s)\n') % re2)
1834 fm.plain(_(b'checking "re2" regexp engine (%s)\n') % re2)
1818 fm.data(re2=bool(util._re2))
1835 fm.data(re2=bool(util._re2))
1819
1836
1820 # templates
1837 # templates
1821 p = templater.templatedir()
1838 p = templater.templatedir()
1822 fm.write(b'templatedirs', b'checking templates (%s)...\n', p or b'')
1839 fm.write(b'templatedirs', b'checking templates (%s)...\n', p or b'')
1823 fm.condwrite(not p, b'', _(b" no template directories found\n"))
1840 fm.condwrite(not p, b'', _(b" no template directories found\n"))
1824 if p:
1841 if p:
1825 (m, fp) = templater.try_open_template(b"map-cmdline.default")
1842 (m, fp) = templater.try_open_template(b"map-cmdline.default")
1826 if m:
1843 if m:
1827 # template found, check if it is working
1844 # template found, check if it is working
1828 err = None
1845 err = None
1829 try:
1846 try:
1830 templater.templater.frommapfile(m)
1847 templater.templater.frommapfile(m)
1831 except Exception as inst:
1848 except Exception as inst:
1832 err = stringutil.forcebytestr(inst)
1849 err = stringutil.forcebytestr(inst)
1833 p = None
1850 p = None
1834 fm.condwrite(err, b'defaulttemplateerror', b" %s\n", err)
1851 fm.condwrite(err, b'defaulttemplateerror', b" %s\n", err)
1835 else:
1852 else:
1836 p = None
1853 p = None
1837 fm.condwrite(
1854 fm.condwrite(
1838 p, b'defaulttemplate', _(b"checking default template (%s)\n"), m
1855 p, b'defaulttemplate', _(b"checking default template (%s)\n"), m
1839 )
1856 )
1840 fm.condwrite(
1857 fm.condwrite(
1841 not m,
1858 not m,
1842 b'defaulttemplatenotfound',
1859 b'defaulttemplatenotfound',
1843 _(b" template '%s' not found\n"),
1860 _(b" template '%s' not found\n"),
1844 b"default",
1861 b"default",
1845 )
1862 )
1846 if not p:
1863 if not p:
1847 problems += 1
1864 problems += 1
1848 fm.condwrite(
1865 fm.condwrite(
1849 not p, b'', _(b" (templates seem to have been installed incorrectly)\n")
1866 not p, b'', _(b" (templates seem to have been installed incorrectly)\n")
1850 )
1867 )
1851
1868
1852 # editor
1869 # editor
1853 editor = ui.geteditor()
1870 editor = ui.geteditor()
1854 editor = util.expandpath(editor)
1871 editor = util.expandpath(editor)
1855 editorbin = procutil.shellsplit(editor)[0]
1872 editorbin = procutil.shellsplit(editor)[0]
1856 fm.write(b'editor', _(b"checking commit editor... (%s)\n"), editorbin)
1873 fm.write(b'editor', _(b"checking commit editor... (%s)\n"), editorbin)
1857 cmdpath = procutil.findexe(editorbin)
1874 cmdpath = procutil.findexe(editorbin)
1858 fm.condwrite(
1875 fm.condwrite(
1859 not cmdpath and editor == b'vi',
1876 not cmdpath and editor == b'vi',
1860 b'vinotfound',
1877 b'vinotfound',
1861 _(
1878 _(
1862 b" No commit editor set and can't find %s in PATH\n"
1879 b" No commit editor set and can't find %s in PATH\n"
1863 b" (specify a commit editor in your configuration"
1880 b" (specify a commit editor in your configuration"
1864 b" file)\n"
1881 b" file)\n"
1865 ),
1882 ),
1866 not cmdpath and editor == b'vi' and editorbin,
1883 not cmdpath and editor == b'vi' and editorbin,
1867 )
1884 )
1868 fm.condwrite(
1885 fm.condwrite(
1869 not cmdpath and editor != b'vi',
1886 not cmdpath and editor != b'vi',
1870 b'editornotfound',
1887 b'editornotfound',
1871 _(
1888 _(
1872 b" Can't find editor '%s' in PATH\n"
1889 b" Can't find editor '%s' in PATH\n"
1873 b" (specify a commit editor in your configuration"
1890 b" (specify a commit editor in your configuration"
1874 b" file)\n"
1891 b" file)\n"
1875 ),
1892 ),
1876 not cmdpath and editorbin,
1893 not cmdpath and editorbin,
1877 )
1894 )
1878 if not cmdpath and editor != b'vi':
1895 if not cmdpath and editor != b'vi':
1879 problems += 1
1896 problems += 1
1880
1897
1881 # check username
1898 # check username
1882 username = None
1899 username = None
1883 err = None
1900 err = None
1884 try:
1901 try:
1885 username = ui.username()
1902 username = ui.username()
1886 except error.Abort as e:
1903 except error.Abort as e:
1887 err = e.message
1904 err = e.message
1888 problems += 1
1905 problems += 1
1889
1906
1890 fm.condwrite(
1907 fm.condwrite(
1891 username, b'username', _(b"checking username (%s)\n"), username
1908 username, b'username', _(b"checking username (%s)\n"), username
1892 )
1909 )
1893 fm.condwrite(
1910 fm.condwrite(
1894 err,
1911 err,
1895 b'usernameerror',
1912 b'usernameerror',
1896 _(
1913 _(
1897 b"checking username...\n %s\n"
1914 b"checking username...\n %s\n"
1898 b" (specify a username in your configuration file)\n"
1915 b" (specify a username in your configuration file)\n"
1899 ),
1916 ),
1900 err,
1917 err,
1901 )
1918 )
1902
1919
1903 for name, mod in extensions.extensions():
1920 for name, mod in extensions.extensions():
1904 handler = getattr(mod, 'debuginstall', None)
1921 handler = getattr(mod, 'debuginstall', None)
1905 if handler is not None:
1922 if handler is not None:
1906 problems += handler(ui, fm)
1923 problems += handler(ui, fm)
1907
1924
1908 fm.condwrite(not problems, b'', _(b"no problems detected\n"))
1925 fm.condwrite(not problems, b'', _(b"no problems detected\n"))
1909 if not problems:
1926 if not problems:
1910 fm.data(problems=problems)
1927 fm.data(problems=problems)
1911 fm.condwrite(
1928 fm.condwrite(
1912 problems,
1929 problems,
1913 b'problems',
1930 b'problems',
1914 _(b"%d problems detected, please check your install!\n"),
1931 _(b"%d problems detected, please check your install!\n"),
1915 problems,
1932 problems,
1916 )
1933 )
1917 fm.end()
1934 fm.end()
1918
1935
1919 return problems
1936 return problems
1920
1937
1921
1938
1922 @command(b'debugknown', [], _(b'REPO ID...'), norepo=True)
1939 @command(b'debugknown', [], _(b'REPO ID...'), norepo=True)
1923 def debugknown(ui, repopath, *ids, **opts):
1940 def debugknown(ui, repopath, *ids, **opts):
1924 """test whether node ids are known to a repo
1941 """test whether node ids are known to a repo
1925
1942
1926 Every ID must be a full-length hex node id string. Returns a list of 0s
1943 Every ID must be a full-length hex node id string. Returns a list of 0s
1927 and 1s indicating unknown/known.
1944 and 1s indicating unknown/known.
1928 """
1945 """
1929 opts = pycompat.byteskwargs(opts)
1946 opts = pycompat.byteskwargs(opts)
1930 repo = hg.peer(ui, opts, repopath)
1947 repo = hg.peer(ui, opts, repopath)
1931 if not repo.capable(b'known'):
1948 if not repo.capable(b'known'):
1932 raise error.Abort(b"known() not supported by target repository")
1949 raise error.Abort(b"known() not supported by target repository")
1933 flags = repo.known([bin(s) for s in ids])
1950 flags = repo.known([bin(s) for s in ids])
1934 ui.write(b"%s\n" % (b"".join([f and b"1" or b"0" for f in flags])))
1951 ui.write(b"%s\n" % (b"".join([f and b"1" or b"0" for f in flags])))
1935
1952
1936
1953
1937 @command(b'debuglabelcomplete', [], _(b'LABEL...'))
1954 @command(b'debuglabelcomplete', [], _(b'LABEL...'))
1938 def debuglabelcomplete(ui, repo, *args):
1955 def debuglabelcomplete(ui, repo, *args):
1939 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1956 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1940 debugnamecomplete(ui, repo, *args)
1957 debugnamecomplete(ui, repo, *args)
1941
1958
1942
1959
1943 @command(
1960 @command(
1944 b'debuglocks',
1961 b'debuglocks',
1945 [
1962 [
1946 (b'L', b'force-free-lock', None, _(b'free the store lock (DANGEROUS)')),
1963 (b'L', b'force-free-lock', None, _(b'free the store lock (DANGEROUS)')),
1947 (
1964 (
1948 b'W',
1965 b'W',
1949 b'force-free-wlock',
1966 b'force-free-wlock',
1950 None,
1967 None,
1951 _(b'free the working state lock (DANGEROUS)'),
1968 _(b'free the working state lock (DANGEROUS)'),
1952 ),
1969 ),
1953 (b's', b'set-lock', None, _(b'set the store lock until stopped')),
1970 (b's', b'set-lock', None, _(b'set the store lock until stopped')),
1954 (
1971 (
1955 b'S',
1972 b'S',
1956 b'set-wlock',
1973 b'set-wlock',
1957 None,
1974 None,
1958 _(b'set the working state lock until stopped'),
1975 _(b'set the working state lock until stopped'),
1959 ),
1976 ),
1960 ],
1977 ],
1961 _(b'[OPTION]...'),
1978 _(b'[OPTION]...'),
1962 )
1979 )
1963 def debuglocks(ui, repo, **opts):
1980 def debuglocks(ui, repo, **opts):
1964 """show or modify state of locks
1981 """show or modify state of locks
1965
1982
1966 By default, this command will show which locks are held. This
1983 By default, this command will show which locks are held. This
1967 includes the user and process holding the lock, the amount of time
1984 includes the user and process holding the lock, the amount of time
1968 the lock has been held, and the machine name where the process is
1985 the lock has been held, and the machine name where the process is
1969 running if it's not local.
1986 running if it's not local.
1970
1987
1971 Locks protect the integrity of Mercurial's data, so should be
1988 Locks protect the integrity of Mercurial's data, so should be
1972 treated with care. System crashes or other interruptions may cause
1989 treated with care. System crashes or other interruptions may cause
1973 locks to not be properly released, though Mercurial will usually
1990 locks to not be properly released, though Mercurial will usually
1974 detect and remove such stale locks automatically.
1991 detect and remove such stale locks automatically.
1975
1992
1976 However, detecting stale locks may not always be possible (for
1993 However, detecting stale locks may not always be possible (for
1977 instance, on a shared filesystem). Removing locks may also be
1994 instance, on a shared filesystem). Removing locks may also be
1978 blocked by filesystem permissions.
1995 blocked by filesystem permissions.
1979
1996
1980 Setting a lock will prevent other commands from changing the data.
1997 Setting a lock will prevent other commands from changing the data.
1981 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
1998 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
1982 The set locks are removed when the command exits.
1999 The set locks are removed when the command exits.
1983
2000
1984 Returns 0 if no locks are held.
2001 Returns 0 if no locks are held.
1985
2002
1986 """
2003 """
1987
2004
1988 if opts.get('force_free_lock'):
2005 if opts.get('force_free_lock'):
1989 repo.svfs.unlink(b'lock')
2006 repo.svfs.unlink(b'lock')
1990 if opts.get('force_free_wlock'):
2007 if opts.get('force_free_wlock'):
1991 repo.vfs.unlink(b'wlock')
2008 repo.vfs.unlink(b'wlock')
1992 if opts.get('force_free_lock') or opts.get('force_free_wlock'):
2009 if opts.get('force_free_lock') or opts.get('force_free_wlock'):
1993 return 0
2010 return 0
1994
2011
1995 locks = []
2012 locks = []
1996 try:
2013 try:
1997 if opts.get('set_wlock'):
2014 if opts.get('set_wlock'):
1998 try:
2015 try:
1999 locks.append(repo.wlock(False))
2016 locks.append(repo.wlock(False))
2000 except error.LockHeld:
2017 except error.LockHeld:
2001 raise error.Abort(_(b'wlock is already held'))
2018 raise error.Abort(_(b'wlock is already held'))
2002 if opts.get('set_lock'):
2019 if opts.get('set_lock'):
2003 try:
2020 try:
2004 locks.append(repo.lock(False))
2021 locks.append(repo.lock(False))
2005 except error.LockHeld:
2022 except error.LockHeld:
2006 raise error.Abort(_(b'lock is already held'))
2023 raise error.Abort(_(b'lock is already held'))
2007 if len(locks):
2024 if len(locks):
2008 ui.promptchoice(_(b"ready to release the lock (y)? $$ &Yes"))
2025 ui.promptchoice(_(b"ready to release the lock (y)? $$ &Yes"))
2009 return 0
2026 return 0
2010 finally:
2027 finally:
2011 release(*locks)
2028 release(*locks)
2012
2029
2013 now = time.time()
2030 now = time.time()
2014 held = 0
2031 held = 0
2015
2032
2016 def report(vfs, name, method):
2033 def report(vfs, name, method):
2017 # this causes stale locks to get reaped for more accurate reporting
2034 # this causes stale locks to get reaped for more accurate reporting
2018 try:
2035 try:
2019 l = method(False)
2036 l = method(False)
2020 except error.LockHeld:
2037 except error.LockHeld:
2021 l = None
2038 l = None
2022
2039
2023 if l:
2040 if l:
2024 l.release()
2041 l.release()
2025 else:
2042 else:
2026 try:
2043 try:
2027 st = vfs.lstat(name)
2044 st = vfs.lstat(name)
2028 age = now - st[stat.ST_MTIME]
2045 age = now - st[stat.ST_MTIME]
2029 user = util.username(st.st_uid)
2046 user = util.username(st.st_uid)
2030 locker = vfs.readlock(name)
2047 locker = vfs.readlock(name)
2031 if b":" in locker:
2048 if b":" in locker:
2032 host, pid = locker.split(b':')
2049 host, pid = locker.split(b':')
2033 if host == socket.gethostname():
2050 if host == socket.gethostname():
2034 locker = b'user %s, process %s' % (user or b'None', pid)
2051 locker = b'user %s, process %s' % (user or b'None', pid)
2035 else:
2052 else:
2036 locker = b'user %s, process %s, host %s' % (
2053 locker = b'user %s, process %s, host %s' % (
2037 user or b'None',
2054 user or b'None',
2038 pid,
2055 pid,
2039 host,
2056 host,
2040 )
2057 )
2041 ui.writenoi18n(b"%-6s %s (%ds)\n" % (name + b":", locker, age))
2058 ui.writenoi18n(b"%-6s %s (%ds)\n" % (name + b":", locker, age))
2042 return 1
2059 return 1
2043 except OSError as e:
2060 except OSError as e:
2044 if e.errno != errno.ENOENT:
2061 if e.errno != errno.ENOENT:
2045 raise
2062 raise
2046
2063
2047 ui.writenoi18n(b"%-6s free\n" % (name + b":"))
2064 ui.writenoi18n(b"%-6s free\n" % (name + b":"))
2048 return 0
2065 return 0
2049
2066
2050 held += report(repo.svfs, b"lock", repo.lock)
2067 held += report(repo.svfs, b"lock", repo.lock)
2051 held += report(repo.vfs, b"wlock", repo.wlock)
2068 held += report(repo.vfs, b"wlock", repo.wlock)
2052
2069
2053 return held
2070 return held
2054
2071
2055
2072
2056 @command(
2073 @command(
2057 b'debugmanifestfulltextcache',
2074 b'debugmanifestfulltextcache',
2058 [
2075 [
2059 (b'', b'clear', False, _(b'clear the cache')),
2076 (b'', b'clear', False, _(b'clear the cache')),
2060 (
2077 (
2061 b'a',
2078 b'a',
2062 b'add',
2079 b'add',
2063 [],
2080 [],
2064 _(b'add the given manifest nodes to the cache'),
2081 _(b'add the given manifest nodes to the cache'),
2065 _(b'NODE'),
2082 _(b'NODE'),
2066 ),
2083 ),
2067 ],
2084 ],
2068 b'',
2085 b'',
2069 )
2086 )
2070 def debugmanifestfulltextcache(ui, repo, add=(), **opts):
2087 def debugmanifestfulltextcache(ui, repo, add=(), **opts):
2071 """show, clear or amend the contents of the manifest fulltext cache"""
2088 """show, clear or amend the contents of the manifest fulltext cache"""
2072
2089
2073 def getcache():
2090 def getcache():
2074 r = repo.manifestlog.getstorage(b'')
2091 r = repo.manifestlog.getstorage(b'')
2075 try:
2092 try:
2076 return r._fulltextcache
2093 return r._fulltextcache
2077 except AttributeError:
2094 except AttributeError:
2078 msg = _(
2095 msg = _(
2079 b"Current revlog implementation doesn't appear to have a "
2096 b"Current revlog implementation doesn't appear to have a "
2080 b"manifest fulltext cache\n"
2097 b"manifest fulltext cache\n"
2081 )
2098 )
2082 raise error.Abort(msg)
2099 raise error.Abort(msg)
2083
2100
2084 if opts.get('clear'):
2101 if opts.get('clear'):
2085 with repo.wlock():
2102 with repo.wlock():
2086 cache = getcache()
2103 cache = getcache()
2087 cache.clear(clear_persisted_data=True)
2104 cache.clear(clear_persisted_data=True)
2088 return
2105 return
2089
2106
2090 if add:
2107 if add:
2091 with repo.wlock():
2108 with repo.wlock():
2092 m = repo.manifestlog
2109 m = repo.manifestlog
2093 store = m.getstorage(b'')
2110 store = m.getstorage(b'')
2094 for n in add:
2111 for n in add:
2095 try:
2112 try:
2096 manifest = m[store.lookup(n)]
2113 manifest = m[store.lookup(n)]
2097 except error.LookupError as e:
2114 except error.LookupError as e:
2098 raise error.Abort(e, hint=b"Check your manifest node id")
2115 raise error.Abort(e, hint=b"Check your manifest node id")
2099 manifest.read() # stores revisision in cache too
2116 manifest.read() # stores revisision in cache too
2100 return
2117 return
2101
2118
2102 cache = getcache()
2119 cache = getcache()
2103 if not len(cache):
2120 if not len(cache):
2104 ui.write(_(b'cache empty\n'))
2121 ui.write(_(b'cache empty\n'))
2105 else:
2122 else:
2106 ui.write(
2123 ui.write(
2107 _(
2124 _(
2108 b'cache contains %d manifest entries, in order of most to '
2125 b'cache contains %d manifest entries, in order of most to '
2109 b'least recent:\n'
2126 b'least recent:\n'
2110 )
2127 )
2111 % (len(cache),)
2128 % (len(cache),)
2112 )
2129 )
2113 totalsize = 0
2130 totalsize = 0
2114 for nodeid in cache:
2131 for nodeid in cache:
2115 # Use cache.get to not update the LRU order
2132 # Use cache.get to not update the LRU order
2116 data = cache.peek(nodeid)
2133 data = cache.peek(nodeid)
2117 size = len(data)
2134 size = len(data)
2118 totalsize += size + 24 # 20 bytes nodeid, 4 bytes size
2135 totalsize += size + 24 # 20 bytes nodeid, 4 bytes size
2119 ui.write(
2136 ui.write(
2120 _(b'id: %s, size %s\n') % (hex(nodeid), util.bytecount(size))
2137 _(b'id: %s, size %s\n') % (hex(nodeid), util.bytecount(size))
2121 )
2138 )
2122 ondisk = cache._opener.stat(b'manifestfulltextcache').st_size
2139 ondisk = cache._opener.stat(b'manifestfulltextcache').st_size
2123 ui.write(
2140 ui.write(
2124 _(b'total cache data size %s, on-disk %s\n')
2141 _(b'total cache data size %s, on-disk %s\n')
2125 % (util.bytecount(totalsize), util.bytecount(ondisk))
2142 % (util.bytecount(totalsize), util.bytecount(ondisk))
2126 )
2143 )
2127
2144
2128
2145
2129 @command(b'debugmergestate', [] + cmdutil.templateopts, b'')
2146 @command(b'debugmergestate', [] + cmdutil.templateopts, b'')
2130 def debugmergestate(ui, repo, *args, **opts):
2147 def debugmergestate(ui, repo, *args, **opts):
2131 """print merge state
2148 """print merge state
2132
2149
2133 Use --verbose to print out information about whether v1 or v2 merge state
2150 Use --verbose to print out information about whether v1 or v2 merge state
2134 was chosen."""
2151 was chosen."""
2135
2152
2136 if ui.verbose:
2153 if ui.verbose:
2137 ms = mergestatemod.mergestate(repo)
2154 ms = mergestatemod.mergestate(repo)
2138
2155
2139 # sort so that reasonable information is on top
2156 # sort so that reasonable information is on top
2140 v1records = ms._readrecordsv1()
2157 v1records = ms._readrecordsv1()
2141 v2records = ms._readrecordsv2()
2158 v2records = ms._readrecordsv2()
2142
2159
2143 if not v1records and not v2records:
2160 if not v1records and not v2records:
2144 pass
2161 pass
2145 elif not v2records:
2162 elif not v2records:
2146 ui.writenoi18n(b'no version 2 merge state\n')
2163 ui.writenoi18n(b'no version 2 merge state\n')
2147 elif ms._v1v2match(v1records, v2records):
2164 elif ms._v1v2match(v1records, v2records):
2148 ui.writenoi18n(b'v1 and v2 states match: using v2\n')
2165 ui.writenoi18n(b'v1 and v2 states match: using v2\n')
2149 else:
2166 else:
2150 ui.writenoi18n(b'v1 and v2 states mismatch: using v1\n')
2167 ui.writenoi18n(b'v1 and v2 states mismatch: using v1\n')
2151
2168
2152 opts = pycompat.byteskwargs(opts)
2169 opts = pycompat.byteskwargs(opts)
2153 if not opts[b'template']:
2170 if not opts[b'template']:
2154 opts[b'template'] = (
2171 opts[b'template'] = (
2155 b'{if(commits, "", "no merge state found\n")}'
2172 b'{if(commits, "", "no merge state found\n")}'
2156 b'{commits % "{name}{if(label, " ({label})")}: {node}\n"}'
2173 b'{commits % "{name}{if(label, " ({label})")}: {node}\n"}'
2157 b'{files % "file: {path} (state \\"{state}\\")\n'
2174 b'{files % "file: {path} (state \\"{state}\\")\n'
2158 b'{if(local_path, "'
2175 b'{if(local_path, "'
2159 b' local path: {local_path} (hash {local_key}, flags \\"{local_flags}\\")\n'
2176 b' local path: {local_path} (hash {local_key}, flags \\"{local_flags}\\")\n'
2160 b' ancestor path: {ancestor_path} (node {ancestor_node})\n'
2177 b' ancestor path: {ancestor_path} (node {ancestor_node})\n'
2161 b' other path: {other_path} (node {other_node})\n'
2178 b' other path: {other_path} (node {other_node})\n'
2162 b'")}'
2179 b'")}'
2163 b'{if(rename_side, "'
2180 b'{if(rename_side, "'
2164 b' rename side: {rename_side}\n'
2181 b' rename side: {rename_side}\n'
2165 b' renamed path: {renamed_path}\n'
2182 b' renamed path: {renamed_path}\n'
2166 b'")}'
2183 b'")}'
2167 b'{extras % " extra: {key} = {value}\n"}'
2184 b'{extras % " extra: {key} = {value}\n"}'
2168 b'"}'
2185 b'"}'
2169 b'{extras % "extra: {file} ({key} = {value})\n"}'
2186 b'{extras % "extra: {file} ({key} = {value})\n"}'
2170 )
2187 )
2171
2188
2172 ms = mergestatemod.mergestate.read(repo)
2189 ms = mergestatemod.mergestate.read(repo)
2173
2190
2174 fm = ui.formatter(b'debugmergestate', opts)
2191 fm = ui.formatter(b'debugmergestate', opts)
2175 fm.startitem()
2192 fm.startitem()
2176
2193
2177 fm_commits = fm.nested(b'commits')
2194 fm_commits = fm.nested(b'commits')
2178 if ms.active():
2195 if ms.active():
2179 for name, node, label_index in (
2196 for name, node, label_index in (
2180 (b'local', ms.local, 0),
2197 (b'local', ms.local, 0),
2181 (b'other', ms.other, 1),
2198 (b'other', ms.other, 1),
2182 ):
2199 ):
2183 fm_commits.startitem()
2200 fm_commits.startitem()
2184 fm_commits.data(name=name)
2201 fm_commits.data(name=name)
2185 fm_commits.data(node=hex(node))
2202 fm_commits.data(node=hex(node))
2186 if ms._labels and len(ms._labels) > label_index:
2203 if ms._labels and len(ms._labels) > label_index:
2187 fm_commits.data(label=ms._labels[label_index])
2204 fm_commits.data(label=ms._labels[label_index])
2188 fm_commits.end()
2205 fm_commits.end()
2189
2206
2190 fm_files = fm.nested(b'files')
2207 fm_files = fm.nested(b'files')
2191 if ms.active():
2208 if ms.active():
2192 for f in ms:
2209 for f in ms:
2193 fm_files.startitem()
2210 fm_files.startitem()
2194 fm_files.data(path=f)
2211 fm_files.data(path=f)
2195 state = ms._state[f]
2212 state = ms._state[f]
2196 fm_files.data(state=state[0])
2213 fm_files.data(state=state[0])
2197 if state[0] in (
2214 if state[0] in (
2198 mergestatemod.MERGE_RECORD_UNRESOLVED,
2215 mergestatemod.MERGE_RECORD_UNRESOLVED,
2199 mergestatemod.MERGE_RECORD_RESOLVED,
2216 mergestatemod.MERGE_RECORD_RESOLVED,
2200 ):
2217 ):
2201 fm_files.data(local_key=state[1])
2218 fm_files.data(local_key=state[1])
2202 fm_files.data(local_path=state[2])
2219 fm_files.data(local_path=state[2])
2203 fm_files.data(ancestor_path=state[3])
2220 fm_files.data(ancestor_path=state[3])
2204 fm_files.data(ancestor_node=state[4])
2221 fm_files.data(ancestor_node=state[4])
2205 fm_files.data(other_path=state[5])
2222 fm_files.data(other_path=state[5])
2206 fm_files.data(other_node=state[6])
2223 fm_files.data(other_node=state[6])
2207 fm_files.data(local_flags=state[7])
2224 fm_files.data(local_flags=state[7])
2208 elif state[0] in (
2225 elif state[0] in (
2209 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
2226 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
2210 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
2227 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
2211 ):
2228 ):
2212 fm_files.data(renamed_path=state[1])
2229 fm_files.data(renamed_path=state[1])
2213 fm_files.data(rename_side=state[2])
2230 fm_files.data(rename_side=state[2])
2214 fm_extras = fm_files.nested(b'extras')
2231 fm_extras = fm_files.nested(b'extras')
2215 for k, v in sorted(ms.extras(f).items()):
2232 for k, v in sorted(ms.extras(f).items()):
2216 fm_extras.startitem()
2233 fm_extras.startitem()
2217 fm_extras.data(key=k)
2234 fm_extras.data(key=k)
2218 fm_extras.data(value=v)
2235 fm_extras.data(value=v)
2219 fm_extras.end()
2236 fm_extras.end()
2220
2237
2221 fm_files.end()
2238 fm_files.end()
2222
2239
2223 fm_extras = fm.nested(b'extras')
2240 fm_extras = fm.nested(b'extras')
2224 for f, d in sorted(pycompat.iteritems(ms.allextras())):
2241 for f, d in sorted(pycompat.iteritems(ms.allextras())):
2225 if f in ms:
2242 if f in ms:
2226 # If file is in mergestate, we have already processed it's extras
2243 # If file is in mergestate, we have already processed it's extras
2227 continue
2244 continue
2228 for k, v in pycompat.iteritems(d):
2245 for k, v in pycompat.iteritems(d):
2229 fm_extras.startitem()
2246 fm_extras.startitem()
2230 fm_extras.data(file=f)
2247 fm_extras.data(file=f)
2231 fm_extras.data(key=k)
2248 fm_extras.data(key=k)
2232 fm_extras.data(value=v)
2249 fm_extras.data(value=v)
2233 fm_extras.end()
2250 fm_extras.end()
2234
2251
2235 fm.end()
2252 fm.end()
2236
2253
2237
2254
2238 @command(b'debugnamecomplete', [], _(b'NAME...'))
2255 @command(b'debugnamecomplete', [], _(b'NAME...'))
2239 def debugnamecomplete(ui, repo, *args):
2256 def debugnamecomplete(ui, repo, *args):
2240 '''complete "names" - tags, open branch names, bookmark names'''
2257 '''complete "names" - tags, open branch names, bookmark names'''
2241
2258
2242 names = set()
2259 names = set()
2243 # since we previously only listed open branches, we will handle that
2260 # since we previously only listed open branches, we will handle that
2244 # specially (after this for loop)
2261 # specially (after this for loop)
2245 for name, ns in pycompat.iteritems(repo.names):
2262 for name, ns in pycompat.iteritems(repo.names):
2246 if name != b'branches':
2263 if name != b'branches':
2247 names.update(ns.listnames(repo))
2264 names.update(ns.listnames(repo))
2248 names.update(
2265 names.update(
2249 tag
2266 tag
2250 for (tag, heads, tip, closed) in repo.branchmap().iterbranches()
2267 for (tag, heads, tip, closed) in repo.branchmap().iterbranches()
2251 if not closed
2268 if not closed
2252 )
2269 )
2253 completions = set()
2270 completions = set()
2254 if not args:
2271 if not args:
2255 args = [b'']
2272 args = [b'']
2256 for a in args:
2273 for a in args:
2257 completions.update(n for n in names if n.startswith(a))
2274 completions.update(n for n in names if n.startswith(a))
2258 ui.write(b'\n'.join(sorted(completions)))
2275 ui.write(b'\n'.join(sorted(completions)))
2259 ui.write(b'\n')
2276 ui.write(b'\n')
2260
2277
2261
2278
2262 @command(
2279 @command(
2263 b'debugnodemap',
2280 b'debugnodemap',
2264 [
2281 [
2265 (
2282 (
2266 b'',
2283 b'',
2267 b'dump-new',
2284 b'dump-new',
2268 False,
2285 False,
2269 _(b'write a (new) persistent binary nodemap on stdout'),
2286 _(b'write a (new) persistent binary nodemap on stdout'),
2270 ),
2287 ),
2271 (b'', b'dump-disk', False, _(b'dump on-disk data on stdout')),
2288 (b'', b'dump-disk', False, _(b'dump on-disk data on stdout')),
2272 (
2289 (
2273 b'',
2290 b'',
2274 b'check',
2291 b'check',
2275 False,
2292 False,
2276 _(b'check that the data on disk data are correct.'),
2293 _(b'check that the data on disk data are correct.'),
2277 ),
2294 ),
2278 (
2295 (
2279 b'',
2296 b'',
2280 b'metadata',
2297 b'metadata',
2281 False,
2298 False,
2282 _(b'display the on disk meta data for the nodemap'),
2299 _(b'display the on disk meta data for the nodemap'),
2283 ),
2300 ),
2284 ],
2301 ],
2285 )
2302 )
2286 def debugnodemap(ui, repo, **opts):
2303 def debugnodemap(ui, repo, **opts):
2287 """write and inspect on disk nodemap"""
2304 """write and inspect on disk nodemap"""
2288 if opts['dump_new']:
2305 if opts['dump_new']:
2289 unfi = repo.unfiltered()
2306 unfi = repo.unfiltered()
2290 cl = unfi.changelog
2307 cl = unfi.changelog
2291 if util.safehasattr(cl.index, "nodemap_data_all"):
2308 if util.safehasattr(cl.index, "nodemap_data_all"):
2292 data = cl.index.nodemap_data_all()
2309 data = cl.index.nodemap_data_all()
2293 else:
2310 else:
2294 data = nodemap.persistent_data(cl.index)
2311 data = nodemap.persistent_data(cl.index)
2295 ui.write(data)
2312 ui.write(data)
2296 elif opts['dump_disk']:
2313 elif opts['dump_disk']:
2297 unfi = repo.unfiltered()
2314 unfi = repo.unfiltered()
2298 cl = unfi.changelog
2315 cl = unfi.changelog
2299 nm_data = nodemap.persisted_data(cl)
2316 nm_data = nodemap.persisted_data(cl)
2300 if nm_data is not None:
2317 if nm_data is not None:
2301 docket, data = nm_data
2318 docket, data = nm_data
2302 ui.write(data[:])
2319 ui.write(data[:])
2303 elif opts['check']:
2320 elif opts['check']:
2304 unfi = repo.unfiltered()
2321 unfi = repo.unfiltered()
2305 cl = unfi.changelog
2322 cl = unfi.changelog
2306 nm_data = nodemap.persisted_data(cl)
2323 nm_data = nodemap.persisted_data(cl)
2307 if nm_data is not None:
2324 if nm_data is not None:
2308 docket, data = nm_data
2325 docket, data = nm_data
2309 return nodemap.check_data(ui, cl.index, data)
2326 return nodemap.check_data(ui, cl.index, data)
2310 elif opts['metadata']:
2327 elif opts['metadata']:
2311 unfi = repo.unfiltered()
2328 unfi = repo.unfiltered()
2312 cl = unfi.changelog
2329 cl = unfi.changelog
2313 nm_data = nodemap.persisted_data(cl)
2330 nm_data = nodemap.persisted_data(cl)
2314 if nm_data is not None:
2331 if nm_data is not None:
2315 docket, data = nm_data
2332 docket, data = nm_data
2316 ui.write((b"uid: %s\n") % docket.uid)
2333 ui.write((b"uid: %s\n") % docket.uid)
2317 ui.write((b"tip-rev: %d\n") % docket.tip_rev)
2334 ui.write((b"tip-rev: %d\n") % docket.tip_rev)
2318 ui.write((b"tip-node: %s\n") % hex(docket.tip_node))
2335 ui.write((b"tip-node: %s\n") % hex(docket.tip_node))
2319 ui.write((b"data-length: %d\n") % docket.data_length)
2336 ui.write((b"data-length: %d\n") % docket.data_length)
2320 ui.write((b"data-unused: %d\n") % docket.data_unused)
2337 ui.write((b"data-unused: %d\n") % docket.data_unused)
2321 unused_perc = docket.data_unused * 100.0 / docket.data_length
2338 unused_perc = docket.data_unused * 100.0 / docket.data_length
2322 ui.write((b"data-unused: %2.3f%%\n") % unused_perc)
2339 ui.write((b"data-unused: %2.3f%%\n") % unused_perc)
2323
2340
2324
2341
2325 @command(
2342 @command(
2326 b'debugobsolete',
2343 b'debugobsolete',
2327 [
2344 [
2328 (b'', b'flags', 0, _(b'markers flag')),
2345 (b'', b'flags', 0, _(b'markers flag')),
2329 (
2346 (
2330 b'',
2347 b'',
2331 b'record-parents',
2348 b'record-parents',
2332 False,
2349 False,
2333 _(b'record parent information for the precursor'),
2350 _(b'record parent information for the precursor'),
2334 ),
2351 ),
2335 (b'r', b'rev', [], _(b'display markers relevant to REV')),
2352 (b'r', b'rev', [], _(b'display markers relevant to REV')),
2336 (
2353 (
2337 b'',
2354 b'',
2338 b'exclusive',
2355 b'exclusive',
2339 False,
2356 False,
2340 _(b'restrict display to markers only relevant to REV'),
2357 _(b'restrict display to markers only relevant to REV'),
2341 ),
2358 ),
2342 (b'', b'index', False, _(b'display index of the marker')),
2359 (b'', b'index', False, _(b'display index of the marker')),
2343 (b'', b'delete', [], _(b'delete markers specified by indices')),
2360 (b'', b'delete', [], _(b'delete markers specified by indices')),
2344 ]
2361 ]
2345 + cmdutil.commitopts2
2362 + cmdutil.commitopts2
2346 + cmdutil.formatteropts,
2363 + cmdutil.formatteropts,
2347 _(b'[OBSOLETED [REPLACEMENT ...]]'),
2364 _(b'[OBSOLETED [REPLACEMENT ...]]'),
2348 )
2365 )
2349 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2366 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2350 """create arbitrary obsolete marker
2367 """create arbitrary obsolete marker
2351
2368
2352 With no arguments, displays the list of obsolescence markers."""
2369 With no arguments, displays the list of obsolescence markers."""
2353
2370
2354 opts = pycompat.byteskwargs(opts)
2371 opts = pycompat.byteskwargs(opts)
2355
2372
2356 def parsenodeid(s):
2373 def parsenodeid(s):
2357 try:
2374 try:
2358 # We do not use revsingle/revrange functions here to accept
2375 # We do not use revsingle/revrange functions here to accept
2359 # arbitrary node identifiers, possibly not present in the
2376 # arbitrary node identifiers, possibly not present in the
2360 # local repository.
2377 # local repository.
2361 n = bin(s)
2378 n = bin(s)
2362 if len(n) != len(nullid):
2379 if len(n) != len(nullid):
2363 raise TypeError()
2380 raise TypeError()
2364 return n
2381 return n
2365 except TypeError:
2382 except TypeError:
2366 raise error.InputError(
2383 raise error.InputError(
2367 b'changeset references must be full hexadecimal '
2384 b'changeset references must be full hexadecimal '
2368 b'node identifiers'
2385 b'node identifiers'
2369 )
2386 )
2370
2387
2371 if opts.get(b'delete'):
2388 if opts.get(b'delete'):
2372 indices = []
2389 indices = []
2373 for v in opts.get(b'delete'):
2390 for v in opts.get(b'delete'):
2374 try:
2391 try:
2375 indices.append(int(v))
2392 indices.append(int(v))
2376 except ValueError:
2393 except ValueError:
2377 raise error.InputError(
2394 raise error.InputError(
2378 _(b'invalid index value: %r') % v,
2395 _(b'invalid index value: %r') % v,
2379 hint=_(b'use integers for indices'),
2396 hint=_(b'use integers for indices'),
2380 )
2397 )
2381
2398
2382 if repo.currenttransaction():
2399 if repo.currenttransaction():
2383 raise error.Abort(
2400 raise error.Abort(
2384 _(b'cannot delete obsmarkers in the middle of transaction.')
2401 _(b'cannot delete obsmarkers in the middle of transaction.')
2385 )
2402 )
2386
2403
2387 with repo.lock():
2404 with repo.lock():
2388 n = repair.deleteobsmarkers(repo.obsstore, indices)
2405 n = repair.deleteobsmarkers(repo.obsstore, indices)
2389 ui.write(_(b'deleted %i obsolescence markers\n') % n)
2406 ui.write(_(b'deleted %i obsolescence markers\n') % n)
2390
2407
2391 return
2408 return
2392
2409
2393 if precursor is not None:
2410 if precursor is not None:
2394 if opts[b'rev']:
2411 if opts[b'rev']:
2395 raise error.InputError(
2412 raise error.InputError(
2396 b'cannot select revision when creating marker'
2413 b'cannot select revision when creating marker'
2397 )
2414 )
2398 metadata = {}
2415 metadata = {}
2399 metadata[b'user'] = encoding.fromlocal(opts[b'user'] or ui.username())
2416 metadata[b'user'] = encoding.fromlocal(opts[b'user'] or ui.username())
2400 succs = tuple(parsenodeid(succ) for succ in successors)
2417 succs = tuple(parsenodeid(succ) for succ in successors)
2401 l = repo.lock()
2418 l = repo.lock()
2402 try:
2419 try:
2403 tr = repo.transaction(b'debugobsolete')
2420 tr = repo.transaction(b'debugobsolete')
2404 try:
2421 try:
2405 date = opts.get(b'date')
2422 date = opts.get(b'date')
2406 if date:
2423 if date:
2407 date = dateutil.parsedate(date)
2424 date = dateutil.parsedate(date)
2408 else:
2425 else:
2409 date = None
2426 date = None
2410 prec = parsenodeid(precursor)
2427 prec = parsenodeid(precursor)
2411 parents = None
2428 parents = None
2412 if opts[b'record_parents']:
2429 if opts[b'record_parents']:
2413 if prec not in repo.unfiltered():
2430 if prec not in repo.unfiltered():
2414 raise error.Abort(
2431 raise error.Abort(
2415 b'cannot used --record-parents on '
2432 b'cannot used --record-parents on '
2416 b'unknown changesets'
2433 b'unknown changesets'
2417 )
2434 )
2418 parents = repo.unfiltered()[prec].parents()
2435 parents = repo.unfiltered()[prec].parents()
2419 parents = tuple(p.node() for p in parents)
2436 parents = tuple(p.node() for p in parents)
2420 repo.obsstore.create(
2437 repo.obsstore.create(
2421 tr,
2438 tr,
2422 prec,
2439 prec,
2423 succs,
2440 succs,
2424 opts[b'flags'],
2441 opts[b'flags'],
2425 parents=parents,
2442 parents=parents,
2426 date=date,
2443 date=date,
2427 metadata=metadata,
2444 metadata=metadata,
2428 ui=ui,
2445 ui=ui,
2429 )
2446 )
2430 tr.close()
2447 tr.close()
2431 except ValueError as exc:
2448 except ValueError as exc:
2432 raise error.Abort(
2449 raise error.Abort(
2433 _(b'bad obsmarker input: %s') % pycompat.bytestr(exc)
2450 _(b'bad obsmarker input: %s') % pycompat.bytestr(exc)
2434 )
2451 )
2435 finally:
2452 finally:
2436 tr.release()
2453 tr.release()
2437 finally:
2454 finally:
2438 l.release()
2455 l.release()
2439 else:
2456 else:
2440 if opts[b'rev']:
2457 if opts[b'rev']:
2441 revs = scmutil.revrange(repo, opts[b'rev'])
2458 revs = scmutil.revrange(repo, opts[b'rev'])
2442 nodes = [repo[r].node() for r in revs]
2459 nodes = [repo[r].node() for r in revs]
2443 markers = list(
2460 markers = list(
2444 obsutil.getmarkers(
2461 obsutil.getmarkers(
2445 repo, nodes=nodes, exclusive=opts[b'exclusive']
2462 repo, nodes=nodes, exclusive=opts[b'exclusive']
2446 )
2463 )
2447 )
2464 )
2448 markers.sort(key=lambda x: x._data)
2465 markers.sort(key=lambda x: x._data)
2449 else:
2466 else:
2450 markers = obsutil.getmarkers(repo)
2467 markers = obsutil.getmarkers(repo)
2451
2468
2452 markerstoiter = markers
2469 markerstoiter = markers
2453 isrelevant = lambda m: True
2470 isrelevant = lambda m: True
2454 if opts.get(b'rev') and opts.get(b'index'):
2471 if opts.get(b'rev') and opts.get(b'index'):
2455 markerstoiter = obsutil.getmarkers(repo)
2472 markerstoiter = obsutil.getmarkers(repo)
2456 markerset = set(markers)
2473 markerset = set(markers)
2457 isrelevant = lambda m: m in markerset
2474 isrelevant = lambda m: m in markerset
2458
2475
2459 fm = ui.formatter(b'debugobsolete', opts)
2476 fm = ui.formatter(b'debugobsolete', opts)
2460 for i, m in enumerate(markerstoiter):
2477 for i, m in enumerate(markerstoiter):
2461 if not isrelevant(m):
2478 if not isrelevant(m):
2462 # marker can be irrelevant when we're iterating over a set
2479 # marker can be irrelevant when we're iterating over a set
2463 # of markers (markerstoiter) which is bigger than the set
2480 # of markers (markerstoiter) which is bigger than the set
2464 # of markers we want to display (markers)
2481 # of markers we want to display (markers)
2465 # this can happen if both --index and --rev options are
2482 # this can happen if both --index and --rev options are
2466 # provided and thus we need to iterate over all of the markers
2483 # provided and thus we need to iterate over all of the markers
2467 # to get the correct indices, but only display the ones that
2484 # to get the correct indices, but only display the ones that
2468 # are relevant to --rev value
2485 # are relevant to --rev value
2469 continue
2486 continue
2470 fm.startitem()
2487 fm.startitem()
2471 ind = i if opts.get(b'index') else None
2488 ind = i if opts.get(b'index') else None
2472 cmdutil.showmarker(fm, m, index=ind)
2489 cmdutil.showmarker(fm, m, index=ind)
2473 fm.end()
2490 fm.end()
2474
2491
2475
2492
2476 @command(
2493 @command(
2477 b'debugp1copies',
2494 b'debugp1copies',
2478 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2495 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2479 _(b'[-r REV]'),
2496 _(b'[-r REV]'),
2480 )
2497 )
2481 def debugp1copies(ui, repo, **opts):
2498 def debugp1copies(ui, repo, **opts):
2482 """dump copy information compared to p1"""
2499 """dump copy information compared to p1"""
2483
2500
2484 opts = pycompat.byteskwargs(opts)
2501 opts = pycompat.byteskwargs(opts)
2485 ctx = scmutil.revsingle(repo, opts.get(b'rev'), default=None)
2502 ctx = scmutil.revsingle(repo, opts.get(b'rev'), default=None)
2486 for dst, src in ctx.p1copies().items():
2503 for dst, src in ctx.p1copies().items():
2487 ui.write(b'%s -> %s\n' % (src, dst))
2504 ui.write(b'%s -> %s\n' % (src, dst))
2488
2505
2489
2506
2490 @command(
2507 @command(
2491 b'debugp2copies',
2508 b'debugp2copies',
2492 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2509 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2493 _(b'[-r REV]'),
2510 _(b'[-r REV]'),
2494 )
2511 )
2495 def debugp1copies(ui, repo, **opts):
2512 def debugp1copies(ui, repo, **opts):
2496 """dump copy information compared to p2"""
2513 """dump copy information compared to p2"""
2497
2514
2498 opts = pycompat.byteskwargs(opts)
2515 opts = pycompat.byteskwargs(opts)
2499 ctx = scmutil.revsingle(repo, opts.get(b'rev'), default=None)
2516 ctx = scmutil.revsingle(repo, opts.get(b'rev'), default=None)
2500 for dst, src in ctx.p2copies().items():
2517 for dst, src in ctx.p2copies().items():
2501 ui.write(b'%s -> %s\n' % (src, dst))
2518 ui.write(b'%s -> %s\n' % (src, dst))
2502
2519
2503
2520
2504 @command(
2521 @command(
2505 b'debugpathcomplete',
2522 b'debugpathcomplete',
2506 [
2523 [
2507 (b'f', b'full', None, _(b'complete an entire path')),
2524 (b'f', b'full', None, _(b'complete an entire path')),
2508 (b'n', b'normal', None, _(b'show only normal files')),
2525 (b'n', b'normal', None, _(b'show only normal files')),
2509 (b'a', b'added', None, _(b'show only added files')),
2526 (b'a', b'added', None, _(b'show only added files')),
2510 (b'r', b'removed', None, _(b'show only removed files')),
2527 (b'r', b'removed', None, _(b'show only removed files')),
2511 ],
2528 ],
2512 _(b'FILESPEC...'),
2529 _(b'FILESPEC...'),
2513 )
2530 )
2514 def debugpathcomplete(ui, repo, *specs, **opts):
2531 def debugpathcomplete(ui, repo, *specs, **opts):
2515 """complete part or all of a tracked path
2532 """complete part or all of a tracked path
2516
2533
2517 This command supports shells that offer path name completion. It
2534 This command supports shells that offer path name completion. It
2518 currently completes only files already known to the dirstate.
2535 currently completes only files already known to the dirstate.
2519
2536
2520 Completion extends only to the next path segment unless
2537 Completion extends only to the next path segment unless
2521 --full is specified, in which case entire paths are used."""
2538 --full is specified, in which case entire paths are used."""
2522
2539
2523 def complete(path, acceptable):
2540 def complete(path, acceptable):
2524 dirstate = repo.dirstate
2541 dirstate = repo.dirstate
2525 spec = os.path.normpath(os.path.join(encoding.getcwd(), path))
2542 spec = os.path.normpath(os.path.join(encoding.getcwd(), path))
2526 rootdir = repo.root + pycompat.ossep
2543 rootdir = repo.root + pycompat.ossep
2527 if spec != repo.root and not spec.startswith(rootdir):
2544 if spec != repo.root and not spec.startswith(rootdir):
2528 return [], []
2545 return [], []
2529 if os.path.isdir(spec):
2546 if os.path.isdir(spec):
2530 spec += b'/'
2547 spec += b'/'
2531 spec = spec[len(rootdir) :]
2548 spec = spec[len(rootdir) :]
2532 fixpaths = pycompat.ossep != b'/'
2549 fixpaths = pycompat.ossep != b'/'
2533 if fixpaths:
2550 if fixpaths:
2534 spec = spec.replace(pycompat.ossep, b'/')
2551 spec = spec.replace(pycompat.ossep, b'/')
2535 speclen = len(spec)
2552 speclen = len(spec)
2536 fullpaths = opts['full']
2553 fullpaths = opts['full']
2537 files, dirs = set(), set()
2554 files, dirs = set(), set()
2538 adddir, addfile = dirs.add, files.add
2555 adddir, addfile = dirs.add, files.add
2539 for f, st in pycompat.iteritems(dirstate):
2556 for f, st in pycompat.iteritems(dirstate):
2540 if f.startswith(spec) and st[0] in acceptable:
2557 if f.startswith(spec) and st[0] in acceptable:
2541 if fixpaths:
2558 if fixpaths:
2542 f = f.replace(b'/', pycompat.ossep)
2559 f = f.replace(b'/', pycompat.ossep)
2543 if fullpaths:
2560 if fullpaths:
2544 addfile(f)
2561 addfile(f)
2545 continue
2562 continue
2546 s = f.find(pycompat.ossep, speclen)
2563 s = f.find(pycompat.ossep, speclen)
2547 if s >= 0:
2564 if s >= 0:
2548 adddir(f[:s])
2565 adddir(f[:s])
2549 else:
2566 else:
2550 addfile(f)
2567 addfile(f)
2551 return files, dirs
2568 return files, dirs
2552
2569
2553 acceptable = b''
2570 acceptable = b''
2554 if opts['normal']:
2571 if opts['normal']:
2555 acceptable += b'nm'
2572 acceptable += b'nm'
2556 if opts['added']:
2573 if opts['added']:
2557 acceptable += b'a'
2574 acceptable += b'a'
2558 if opts['removed']:
2575 if opts['removed']:
2559 acceptable += b'r'
2576 acceptable += b'r'
2560 cwd = repo.getcwd()
2577 cwd = repo.getcwd()
2561 if not specs:
2578 if not specs:
2562 specs = [b'.']
2579 specs = [b'.']
2563
2580
2564 files, dirs = set(), set()
2581 files, dirs = set(), set()
2565 for spec in specs:
2582 for spec in specs:
2566 f, d = complete(spec, acceptable or b'nmar')
2583 f, d = complete(spec, acceptable or b'nmar')
2567 files.update(f)
2584 files.update(f)
2568 dirs.update(d)
2585 dirs.update(d)
2569 files.update(dirs)
2586 files.update(dirs)
2570 ui.write(b'\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2587 ui.write(b'\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2571 ui.write(b'\n')
2588 ui.write(b'\n')
2572
2589
2573
2590
2574 @command(
2591 @command(
2575 b'debugpathcopies',
2592 b'debugpathcopies',
2576 cmdutil.walkopts,
2593 cmdutil.walkopts,
2577 b'hg debugpathcopies REV1 REV2 [FILE]',
2594 b'hg debugpathcopies REV1 REV2 [FILE]',
2578 inferrepo=True,
2595 inferrepo=True,
2579 )
2596 )
2580 def debugpathcopies(ui, repo, rev1, rev2, *pats, **opts):
2597 def debugpathcopies(ui, repo, rev1, rev2, *pats, **opts):
2581 """show copies between two revisions"""
2598 """show copies between two revisions"""
2582 ctx1 = scmutil.revsingle(repo, rev1)
2599 ctx1 = scmutil.revsingle(repo, rev1)
2583 ctx2 = scmutil.revsingle(repo, rev2)
2600 ctx2 = scmutil.revsingle(repo, rev2)
2584 m = scmutil.match(ctx1, pats, opts)
2601 m = scmutil.match(ctx1, pats, opts)
2585 for dst, src in sorted(copies.pathcopies(ctx1, ctx2, m).items()):
2602 for dst, src in sorted(copies.pathcopies(ctx1, ctx2, m).items()):
2586 ui.write(b'%s -> %s\n' % (src, dst))
2603 ui.write(b'%s -> %s\n' % (src, dst))
2587
2604
2588
2605
2589 @command(b'debugpeer', [], _(b'PATH'), norepo=True)
2606 @command(b'debugpeer', [], _(b'PATH'), norepo=True)
2590 def debugpeer(ui, path):
2607 def debugpeer(ui, path):
2591 """establish a connection to a peer repository"""
2608 """establish a connection to a peer repository"""
2592 # Always enable peer request logging. Requires --debug to display
2609 # Always enable peer request logging. Requires --debug to display
2593 # though.
2610 # though.
2594 overrides = {
2611 overrides = {
2595 (b'devel', b'debug.peer-request'): True,
2612 (b'devel', b'debug.peer-request'): True,
2596 }
2613 }
2597
2614
2598 with ui.configoverride(overrides):
2615 with ui.configoverride(overrides):
2599 peer = hg.peer(ui, {}, path)
2616 peer = hg.peer(ui, {}, path)
2600
2617
2601 local = peer.local() is not None
2618 local = peer.local() is not None
2602 canpush = peer.canpush()
2619 canpush = peer.canpush()
2603
2620
2604 ui.write(_(b'url: %s\n') % peer.url())
2621 ui.write(_(b'url: %s\n') % peer.url())
2605 ui.write(_(b'local: %s\n') % (_(b'yes') if local else _(b'no')))
2622 ui.write(_(b'local: %s\n') % (_(b'yes') if local else _(b'no')))
2606 ui.write(_(b'pushable: %s\n') % (_(b'yes') if canpush else _(b'no')))
2623 ui.write(_(b'pushable: %s\n') % (_(b'yes') if canpush else _(b'no')))
2607
2624
2608
2625
2609 @command(
2626 @command(
2610 b'debugpickmergetool',
2627 b'debugpickmergetool',
2611 [
2628 [
2612 (b'r', b'rev', b'', _(b'check for files in this revision'), _(b'REV')),
2629 (b'r', b'rev', b'', _(b'check for files in this revision'), _(b'REV')),
2613 (b'', b'changedelete', None, _(b'emulate merging change and delete')),
2630 (b'', b'changedelete', None, _(b'emulate merging change and delete')),
2614 ]
2631 ]
2615 + cmdutil.walkopts
2632 + cmdutil.walkopts
2616 + cmdutil.mergetoolopts,
2633 + cmdutil.mergetoolopts,
2617 _(b'[PATTERN]...'),
2634 _(b'[PATTERN]...'),
2618 inferrepo=True,
2635 inferrepo=True,
2619 )
2636 )
2620 def debugpickmergetool(ui, repo, *pats, **opts):
2637 def debugpickmergetool(ui, repo, *pats, **opts):
2621 """examine which merge tool is chosen for specified file
2638 """examine which merge tool is chosen for specified file
2622
2639
2623 As described in :hg:`help merge-tools`, Mercurial examines
2640 As described in :hg:`help merge-tools`, Mercurial examines
2624 configurations below in this order to decide which merge tool is
2641 configurations below in this order to decide which merge tool is
2625 chosen for specified file.
2642 chosen for specified file.
2626
2643
2627 1. ``--tool`` option
2644 1. ``--tool`` option
2628 2. ``HGMERGE`` environment variable
2645 2. ``HGMERGE`` environment variable
2629 3. configurations in ``merge-patterns`` section
2646 3. configurations in ``merge-patterns`` section
2630 4. configuration of ``ui.merge``
2647 4. configuration of ``ui.merge``
2631 5. configurations in ``merge-tools`` section
2648 5. configurations in ``merge-tools`` section
2632 6. ``hgmerge`` tool (for historical reason only)
2649 6. ``hgmerge`` tool (for historical reason only)
2633 7. default tool for fallback (``:merge`` or ``:prompt``)
2650 7. default tool for fallback (``:merge`` or ``:prompt``)
2634
2651
2635 This command writes out examination result in the style below::
2652 This command writes out examination result in the style below::
2636
2653
2637 FILE = MERGETOOL
2654 FILE = MERGETOOL
2638
2655
2639 By default, all files known in the first parent context of the
2656 By default, all files known in the first parent context of the
2640 working directory are examined. Use file patterns and/or -I/-X
2657 working directory are examined. Use file patterns and/or -I/-X
2641 options to limit target files. -r/--rev is also useful to examine
2658 options to limit target files. -r/--rev is also useful to examine
2642 files in another context without actual updating to it.
2659 files in another context without actual updating to it.
2643
2660
2644 With --debug, this command shows warning messages while matching
2661 With --debug, this command shows warning messages while matching
2645 against ``merge-patterns`` and so on, too. It is recommended to
2662 against ``merge-patterns`` and so on, too. It is recommended to
2646 use this option with explicit file patterns and/or -I/-X options,
2663 use this option with explicit file patterns and/or -I/-X options,
2647 because this option increases amount of output per file according
2664 because this option increases amount of output per file according
2648 to configurations in hgrc.
2665 to configurations in hgrc.
2649
2666
2650 With -v/--verbose, this command shows configurations below at
2667 With -v/--verbose, this command shows configurations below at
2651 first (only if specified).
2668 first (only if specified).
2652
2669
2653 - ``--tool`` option
2670 - ``--tool`` option
2654 - ``HGMERGE`` environment variable
2671 - ``HGMERGE`` environment variable
2655 - configuration of ``ui.merge``
2672 - configuration of ``ui.merge``
2656
2673
2657 If merge tool is chosen before matching against
2674 If merge tool is chosen before matching against
2658 ``merge-patterns``, this command can't show any helpful
2675 ``merge-patterns``, this command can't show any helpful
2659 information, even with --debug. In such case, information above is
2676 information, even with --debug. In such case, information above is
2660 useful to know why a merge tool is chosen.
2677 useful to know why a merge tool is chosen.
2661 """
2678 """
2662 opts = pycompat.byteskwargs(opts)
2679 opts = pycompat.byteskwargs(opts)
2663 overrides = {}
2680 overrides = {}
2664 if opts[b'tool']:
2681 if opts[b'tool']:
2665 overrides[(b'ui', b'forcemerge')] = opts[b'tool']
2682 overrides[(b'ui', b'forcemerge')] = opts[b'tool']
2666 ui.notenoi18n(b'with --tool %r\n' % (pycompat.bytestr(opts[b'tool'])))
2683 ui.notenoi18n(b'with --tool %r\n' % (pycompat.bytestr(opts[b'tool'])))
2667
2684
2668 with ui.configoverride(overrides, b'debugmergepatterns'):
2685 with ui.configoverride(overrides, b'debugmergepatterns'):
2669 hgmerge = encoding.environ.get(b"HGMERGE")
2686 hgmerge = encoding.environ.get(b"HGMERGE")
2670 if hgmerge is not None:
2687 if hgmerge is not None:
2671 ui.notenoi18n(b'with HGMERGE=%r\n' % (pycompat.bytestr(hgmerge)))
2688 ui.notenoi18n(b'with HGMERGE=%r\n' % (pycompat.bytestr(hgmerge)))
2672 uimerge = ui.config(b"ui", b"merge")
2689 uimerge = ui.config(b"ui", b"merge")
2673 if uimerge:
2690 if uimerge:
2674 ui.notenoi18n(b'with ui.merge=%r\n' % (pycompat.bytestr(uimerge)))
2691 ui.notenoi18n(b'with ui.merge=%r\n' % (pycompat.bytestr(uimerge)))
2675
2692
2676 ctx = scmutil.revsingle(repo, opts.get(b'rev'))
2693 ctx = scmutil.revsingle(repo, opts.get(b'rev'))
2677 m = scmutil.match(ctx, pats, opts)
2694 m = scmutil.match(ctx, pats, opts)
2678 changedelete = opts[b'changedelete']
2695 changedelete = opts[b'changedelete']
2679 for path in ctx.walk(m):
2696 for path in ctx.walk(m):
2680 fctx = ctx[path]
2697 fctx = ctx[path]
2681 try:
2698 try:
2682 if not ui.debugflag:
2699 if not ui.debugflag:
2683 ui.pushbuffer(error=True)
2700 ui.pushbuffer(error=True)
2684 tool, toolpath = filemerge._picktool(
2701 tool, toolpath = filemerge._picktool(
2685 repo,
2702 repo,
2686 ui,
2703 ui,
2687 path,
2704 path,
2688 fctx.isbinary(),
2705 fctx.isbinary(),
2689 b'l' in fctx.flags(),
2706 b'l' in fctx.flags(),
2690 changedelete,
2707 changedelete,
2691 )
2708 )
2692 finally:
2709 finally:
2693 if not ui.debugflag:
2710 if not ui.debugflag:
2694 ui.popbuffer()
2711 ui.popbuffer()
2695 ui.write(b'%s = %s\n' % (path, tool))
2712 ui.write(b'%s = %s\n' % (path, tool))
2696
2713
2697
2714
2698 @command(b'debugpushkey', [], _(b'REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2715 @command(b'debugpushkey', [], _(b'REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2699 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2716 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2700 """access the pushkey key/value protocol
2717 """access the pushkey key/value protocol
2701
2718
2702 With two args, list the keys in the given namespace.
2719 With two args, list the keys in the given namespace.
2703
2720
2704 With five args, set a key to new if it currently is set to old.
2721 With five args, set a key to new if it currently is set to old.
2705 Reports success or failure.
2722 Reports success or failure.
2706 """
2723 """
2707
2724
2708 target = hg.peer(ui, {}, repopath)
2725 target = hg.peer(ui, {}, repopath)
2709 if keyinfo:
2726 if keyinfo:
2710 key, old, new = keyinfo
2727 key, old, new = keyinfo
2711 with target.commandexecutor() as e:
2728 with target.commandexecutor() as e:
2712 r = e.callcommand(
2729 r = e.callcommand(
2713 b'pushkey',
2730 b'pushkey',
2714 {
2731 {
2715 b'namespace': namespace,
2732 b'namespace': namespace,
2716 b'key': key,
2733 b'key': key,
2717 b'old': old,
2734 b'old': old,
2718 b'new': new,
2735 b'new': new,
2719 },
2736 },
2720 ).result()
2737 ).result()
2721
2738
2722 ui.status(pycompat.bytestr(r) + b'\n')
2739 ui.status(pycompat.bytestr(r) + b'\n')
2723 return not r
2740 return not r
2724 else:
2741 else:
2725 for k, v in sorted(pycompat.iteritems(target.listkeys(namespace))):
2742 for k, v in sorted(pycompat.iteritems(target.listkeys(namespace))):
2726 ui.write(
2743 ui.write(
2727 b"%s\t%s\n" % (stringutil.escapestr(k), stringutil.escapestr(v))
2744 b"%s\t%s\n" % (stringutil.escapestr(k), stringutil.escapestr(v))
2728 )
2745 )
2729
2746
2730
2747
2731 @command(b'debugpvec', [], _(b'A B'))
2748 @command(b'debugpvec', [], _(b'A B'))
2732 def debugpvec(ui, repo, a, b=None):
2749 def debugpvec(ui, repo, a, b=None):
2733 ca = scmutil.revsingle(repo, a)
2750 ca = scmutil.revsingle(repo, a)
2734 cb = scmutil.revsingle(repo, b)
2751 cb = scmutil.revsingle(repo, b)
2735 pa = pvec.ctxpvec(ca)
2752 pa = pvec.ctxpvec(ca)
2736 pb = pvec.ctxpvec(cb)
2753 pb = pvec.ctxpvec(cb)
2737 if pa == pb:
2754 if pa == pb:
2738 rel = b"="
2755 rel = b"="
2739 elif pa > pb:
2756 elif pa > pb:
2740 rel = b">"
2757 rel = b">"
2741 elif pa < pb:
2758 elif pa < pb:
2742 rel = b"<"
2759 rel = b"<"
2743 elif pa | pb:
2760 elif pa | pb:
2744 rel = b"|"
2761 rel = b"|"
2745 ui.write(_(b"a: %s\n") % pa)
2762 ui.write(_(b"a: %s\n") % pa)
2746 ui.write(_(b"b: %s\n") % pb)
2763 ui.write(_(b"b: %s\n") % pb)
2747 ui.write(_(b"depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2764 ui.write(_(b"depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2748 ui.write(
2765 ui.write(
2749 _(b"delta: %d hdist: %d distance: %d relation: %s\n")
2766 _(b"delta: %d hdist: %d distance: %d relation: %s\n")
2750 % (
2767 % (
2751 abs(pa._depth - pb._depth),
2768 abs(pa._depth - pb._depth),
2752 pvec._hamming(pa._vec, pb._vec),
2769 pvec._hamming(pa._vec, pb._vec),
2753 pa.distance(pb),
2770 pa.distance(pb),
2754 rel,
2771 rel,
2755 )
2772 )
2756 )
2773 )
2757
2774
2758
2775
2759 @command(
2776 @command(
2760 b'debugrebuilddirstate|debugrebuildstate',
2777 b'debugrebuilddirstate|debugrebuildstate',
2761 [
2778 [
2762 (b'r', b'rev', b'', _(b'revision to rebuild to'), _(b'REV')),
2779 (b'r', b'rev', b'', _(b'revision to rebuild to'), _(b'REV')),
2763 (
2780 (
2764 b'',
2781 b'',
2765 b'minimal',
2782 b'minimal',
2766 None,
2783 None,
2767 _(
2784 _(
2768 b'only rebuild files that are inconsistent with '
2785 b'only rebuild files that are inconsistent with '
2769 b'the working copy parent'
2786 b'the working copy parent'
2770 ),
2787 ),
2771 ),
2788 ),
2772 ],
2789 ],
2773 _(b'[-r REV]'),
2790 _(b'[-r REV]'),
2774 )
2791 )
2775 def debugrebuilddirstate(ui, repo, rev, **opts):
2792 def debugrebuilddirstate(ui, repo, rev, **opts):
2776 """rebuild the dirstate as it would look like for the given revision
2793 """rebuild the dirstate as it would look like for the given revision
2777
2794
2778 If no revision is specified the first current parent will be used.
2795 If no revision is specified the first current parent will be used.
2779
2796
2780 The dirstate will be set to the files of the given revision.
2797 The dirstate will be set to the files of the given revision.
2781 The actual working directory content or existing dirstate
2798 The actual working directory content or existing dirstate
2782 information such as adds or removes is not considered.
2799 information such as adds or removes is not considered.
2783
2800
2784 ``minimal`` will only rebuild the dirstate status for files that claim to be
2801 ``minimal`` will only rebuild the dirstate status for files that claim to be
2785 tracked but are not in the parent manifest, or that exist in the parent
2802 tracked but are not in the parent manifest, or that exist in the parent
2786 manifest but are not in the dirstate. It will not change adds, removes, or
2803 manifest but are not in the dirstate. It will not change adds, removes, or
2787 modified files that are in the working copy parent.
2804 modified files that are in the working copy parent.
2788
2805
2789 One use of this command is to make the next :hg:`status` invocation
2806 One use of this command is to make the next :hg:`status` invocation
2790 check the actual file content.
2807 check the actual file content.
2791 """
2808 """
2792 ctx = scmutil.revsingle(repo, rev)
2809 ctx = scmutil.revsingle(repo, rev)
2793 with repo.wlock():
2810 with repo.wlock():
2794 dirstate = repo.dirstate
2811 dirstate = repo.dirstate
2795 changedfiles = None
2812 changedfiles = None
2796 # See command doc for what minimal does.
2813 # See command doc for what minimal does.
2797 if opts.get('minimal'):
2814 if opts.get('minimal'):
2798 manifestfiles = set(ctx.manifest().keys())
2815 manifestfiles = set(ctx.manifest().keys())
2799 dirstatefiles = set(dirstate)
2816 dirstatefiles = set(dirstate)
2800 manifestonly = manifestfiles - dirstatefiles
2817 manifestonly = manifestfiles - dirstatefiles
2801 dsonly = dirstatefiles - manifestfiles
2818 dsonly = dirstatefiles - manifestfiles
2802 dsnotadded = {f for f in dsonly if dirstate[f] != b'a'}
2819 dsnotadded = {f for f in dsonly if dirstate[f] != b'a'}
2803 changedfiles = manifestonly | dsnotadded
2820 changedfiles = manifestonly | dsnotadded
2804
2821
2805 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2822 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2806
2823
2807
2824
2808 @command(b'debugrebuildfncache', [], b'')
2825 @command(b'debugrebuildfncache', [], b'')
2809 def debugrebuildfncache(ui, repo):
2826 def debugrebuildfncache(ui, repo):
2810 """rebuild the fncache file"""
2827 """rebuild the fncache file"""
2811 repair.rebuildfncache(ui, repo)
2828 repair.rebuildfncache(ui, repo)
2812
2829
2813
2830
2814 @command(
2831 @command(
2815 b'debugrename',
2832 b'debugrename',
2816 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2833 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2817 _(b'[-r REV] [FILE]...'),
2834 _(b'[-r REV] [FILE]...'),
2818 )
2835 )
2819 def debugrename(ui, repo, *pats, **opts):
2836 def debugrename(ui, repo, *pats, **opts):
2820 """dump rename information"""
2837 """dump rename information"""
2821
2838
2822 opts = pycompat.byteskwargs(opts)
2839 opts = pycompat.byteskwargs(opts)
2823 ctx = scmutil.revsingle(repo, opts.get(b'rev'))
2840 ctx = scmutil.revsingle(repo, opts.get(b'rev'))
2824 m = scmutil.match(ctx, pats, opts)
2841 m = scmutil.match(ctx, pats, opts)
2825 for abs in ctx.walk(m):
2842 for abs in ctx.walk(m):
2826 fctx = ctx[abs]
2843 fctx = ctx[abs]
2827 o = fctx.filelog().renamed(fctx.filenode())
2844 o = fctx.filelog().renamed(fctx.filenode())
2828 rel = repo.pathto(abs)
2845 rel = repo.pathto(abs)
2829 if o:
2846 if o:
2830 ui.write(_(b"%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2847 ui.write(_(b"%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2831 else:
2848 else:
2832 ui.write(_(b"%s not renamed\n") % rel)
2849 ui.write(_(b"%s not renamed\n") % rel)
2833
2850
2834
2851
2835 @command(b'debugrequires|debugrequirements', [], b'')
2852 @command(b'debugrequires|debugrequirements', [], b'')
2836 def debugrequirements(ui, repo):
2853 def debugrequirements(ui, repo):
2837 """ print the current repo requirements """
2854 """ print the current repo requirements """
2838 for r in sorted(repo.requirements):
2855 for r in sorted(repo.requirements):
2839 ui.write(b"%s\n" % r)
2856 ui.write(b"%s\n" % r)
2840
2857
2841
2858
2842 @command(
2859 @command(
2843 b'debugrevlog',
2860 b'debugrevlog',
2844 cmdutil.debugrevlogopts + [(b'd', b'dump', False, _(b'dump index data'))],
2861 cmdutil.debugrevlogopts + [(b'd', b'dump', False, _(b'dump index data'))],
2845 _(b'-c|-m|FILE'),
2862 _(b'-c|-m|FILE'),
2846 optionalrepo=True,
2863 optionalrepo=True,
2847 )
2864 )
2848 def debugrevlog(ui, repo, file_=None, **opts):
2865 def debugrevlog(ui, repo, file_=None, **opts):
2849 """show data and statistics about a revlog"""
2866 """show data and statistics about a revlog"""
2850 opts = pycompat.byteskwargs(opts)
2867 opts = pycompat.byteskwargs(opts)
2851 r = cmdutil.openrevlog(repo, b'debugrevlog', file_, opts)
2868 r = cmdutil.openrevlog(repo, b'debugrevlog', file_, opts)
2852
2869
2853 if opts.get(b"dump"):
2870 if opts.get(b"dump"):
2854 numrevs = len(r)
2871 numrevs = len(r)
2855 ui.write(
2872 ui.write(
2856 (
2873 (
2857 b"# rev p1rev p2rev start end deltastart base p1 p2"
2874 b"# rev p1rev p2rev start end deltastart base p1 p2"
2858 b" rawsize totalsize compression heads chainlen\n"
2875 b" rawsize totalsize compression heads chainlen\n"
2859 )
2876 )
2860 )
2877 )
2861 ts = 0
2878 ts = 0
2862 heads = set()
2879 heads = set()
2863
2880
2864 for rev in pycompat.xrange(numrevs):
2881 for rev in pycompat.xrange(numrevs):
2865 dbase = r.deltaparent(rev)
2882 dbase = r.deltaparent(rev)
2866 if dbase == -1:
2883 if dbase == -1:
2867 dbase = rev
2884 dbase = rev
2868 cbase = r.chainbase(rev)
2885 cbase = r.chainbase(rev)
2869 clen = r.chainlen(rev)
2886 clen = r.chainlen(rev)
2870 p1, p2 = r.parentrevs(rev)
2887 p1, p2 = r.parentrevs(rev)
2871 rs = r.rawsize(rev)
2888 rs = r.rawsize(rev)
2872 ts = ts + rs
2889 ts = ts + rs
2873 heads -= set(r.parentrevs(rev))
2890 heads -= set(r.parentrevs(rev))
2874 heads.add(rev)
2891 heads.add(rev)
2875 try:
2892 try:
2876 compression = ts / r.end(rev)
2893 compression = ts / r.end(rev)
2877 except ZeroDivisionError:
2894 except ZeroDivisionError:
2878 compression = 0
2895 compression = 0
2879 ui.write(
2896 ui.write(
2880 b"%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2897 b"%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2881 b"%11d %5d %8d\n"
2898 b"%11d %5d %8d\n"
2882 % (
2899 % (
2883 rev,
2900 rev,
2884 p1,
2901 p1,
2885 p2,
2902 p2,
2886 r.start(rev),
2903 r.start(rev),
2887 r.end(rev),
2904 r.end(rev),
2888 r.start(dbase),
2905 r.start(dbase),
2889 r.start(cbase),
2906 r.start(cbase),
2890 r.start(p1),
2907 r.start(p1),
2891 r.start(p2),
2908 r.start(p2),
2892 rs,
2909 rs,
2893 ts,
2910 ts,
2894 compression,
2911 compression,
2895 len(heads),
2912 len(heads),
2896 clen,
2913 clen,
2897 )
2914 )
2898 )
2915 )
2899 return 0
2916 return 0
2900
2917
2901 v = r.version
2918 v = r.version
2902 format = v & 0xFFFF
2919 format = v & 0xFFFF
2903 flags = []
2920 flags = []
2904 gdelta = False
2921 gdelta = False
2905 if v & revlog.FLAG_INLINE_DATA:
2922 if v & revlog.FLAG_INLINE_DATA:
2906 flags.append(b'inline')
2923 flags.append(b'inline')
2907 if v & revlog.FLAG_GENERALDELTA:
2924 if v & revlog.FLAG_GENERALDELTA:
2908 gdelta = True
2925 gdelta = True
2909 flags.append(b'generaldelta')
2926 flags.append(b'generaldelta')
2910 if not flags:
2927 if not flags:
2911 flags = [b'(none)']
2928 flags = [b'(none)']
2912
2929
2913 ### tracks merge vs single parent
2930 ### tracks merge vs single parent
2914 nummerges = 0
2931 nummerges = 0
2915
2932
2916 ### tracks ways the "delta" are build
2933 ### tracks ways the "delta" are build
2917 # nodelta
2934 # nodelta
2918 numempty = 0
2935 numempty = 0
2919 numemptytext = 0
2936 numemptytext = 0
2920 numemptydelta = 0
2937 numemptydelta = 0
2921 # full file content
2938 # full file content
2922 numfull = 0
2939 numfull = 0
2923 # intermediate snapshot against a prior snapshot
2940 # intermediate snapshot against a prior snapshot
2924 numsemi = 0
2941 numsemi = 0
2925 # snapshot count per depth
2942 # snapshot count per depth
2926 numsnapdepth = collections.defaultdict(lambda: 0)
2943 numsnapdepth = collections.defaultdict(lambda: 0)
2927 # delta against previous revision
2944 # delta against previous revision
2928 numprev = 0
2945 numprev = 0
2929 # delta against first or second parent (not prev)
2946 # delta against first or second parent (not prev)
2930 nump1 = 0
2947 nump1 = 0
2931 nump2 = 0
2948 nump2 = 0
2932 # delta against neither prev nor parents
2949 # delta against neither prev nor parents
2933 numother = 0
2950 numother = 0
2934 # delta against prev that are also first or second parent
2951 # delta against prev that are also first or second parent
2935 # (details of `numprev`)
2952 # (details of `numprev`)
2936 nump1prev = 0
2953 nump1prev = 0
2937 nump2prev = 0
2954 nump2prev = 0
2938
2955
2939 # data about delta chain of each revs
2956 # data about delta chain of each revs
2940 chainlengths = []
2957 chainlengths = []
2941 chainbases = []
2958 chainbases = []
2942 chainspans = []
2959 chainspans = []
2943
2960
2944 # data about each revision
2961 # data about each revision
2945 datasize = [None, 0, 0]
2962 datasize = [None, 0, 0]
2946 fullsize = [None, 0, 0]
2963 fullsize = [None, 0, 0]
2947 semisize = [None, 0, 0]
2964 semisize = [None, 0, 0]
2948 # snapshot count per depth
2965 # snapshot count per depth
2949 snapsizedepth = collections.defaultdict(lambda: [None, 0, 0])
2966 snapsizedepth = collections.defaultdict(lambda: [None, 0, 0])
2950 deltasize = [None, 0, 0]
2967 deltasize = [None, 0, 0]
2951 chunktypecounts = {}
2968 chunktypecounts = {}
2952 chunktypesizes = {}
2969 chunktypesizes = {}
2953
2970
2954 def addsize(size, l):
2971 def addsize(size, l):
2955 if l[0] is None or size < l[0]:
2972 if l[0] is None or size < l[0]:
2956 l[0] = size
2973 l[0] = size
2957 if size > l[1]:
2974 if size > l[1]:
2958 l[1] = size
2975 l[1] = size
2959 l[2] += size
2976 l[2] += size
2960
2977
2961 numrevs = len(r)
2978 numrevs = len(r)
2962 for rev in pycompat.xrange(numrevs):
2979 for rev in pycompat.xrange(numrevs):
2963 p1, p2 = r.parentrevs(rev)
2980 p1, p2 = r.parentrevs(rev)
2964 delta = r.deltaparent(rev)
2981 delta = r.deltaparent(rev)
2965 if format > 0:
2982 if format > 0:
2966 addsize(r.rawsize(rev), datasize)
2983 addsize(r.rawsize(rev), datasize)
2967 if p2 != nullrev:
2984 if p2 != nullrev:
2968 nummerges += 1
2985 nummerges += 1
2969 size = r.length(rev)
2986 size = r.length(rev)
2970 if delta == nullrev:
2987 if delta == nullrev:
2971 chainlengths.append(0)
2988 chainlengths.append(0)
2972 chainbases.append(r.start(rev))
2989 chainbases.append(r.start(rev))
2973 chainspans.append(size)
2990 chainspans.append(size)
2974 if size == 0:
2991 if size == 0:
2975 numempty += 1
2992 numempty += 1
2976 numemptytext += 1
2993 numemptytext += 1
2977 else:
2994 else:
2978 numfull += 1
2995 numfull += 1
2979 numsnapdepth[0] += 1
2996 numsnapdepth[0] += 1
2980 addsize(size, fullsize)
2997 addsize(size, fullsize)
2981 addsize(size, snapsizedepth[0])
2998 addsize(size, snapsizedepth[0])
2982 else:
2999 else:
2983 chainlengths.append(chainlengths[delta] + 1)
3000 chainlengths.append(chainlengths[delta] + 1)
2984 baseaddr = chainbases[delta]
3001 baseaddr = chainbases[delta]
2985 revaddr = r.start(rev)
3002 revaddr = r.start(rev)
2986 chainbases.append(baseaddr)
3003 chainbases.append(baseaddr)
2987 chainspans.append((revaddr - baseaddr) + size)
3004 chainspans.append((revaddr - baseaddr) + size)
2988 if size == 0:
3005 if size == 0:
2989 numempty += 1
3006 numempty += 1
2990 numemptydelta += 1
3007 numemptydelta += 1
2991 elif r.issnapshot(rev):
3008 elif r.issnapshot(rev):
2992 addsize(size, semisize)
3009 addsize(size, semisize)
2993 numsemi += 1
3010 numsemi += 1
2994 depth = r.snapshotdepth(rev)
3011 depth = r.snapshotdepth(rev)
2995 numsnapdepth[depth] += 1
3012 numsnapdepth[depth] += 1
2996 addsize(size, snapsizedepth[depth])
3013 addsize(size, snapsizedepth[depth])
2997 else:
3014 else:
2998 addsize(size, deltasize)
3015 addsize(size, deltasize)
2999 if delta == rev - 1:
3016 if delta == rev - 1:
3000 numprev += 1
3017 numprev += 1
3001 if delta == p1:
3018 if delta == p1:
3002 nump1prev += 1
3019 nump1prev += 1
3003 elif delta == p2:
3020 elif delta == p2:
3004 nump2prev += 1
3021 nump2prev += 1
3005 elif delta == p1:
3022 elif delta == p1:
3006 nump1 += 1
3023 nump1 += 1
3007 elif delta == p2:
3024 elif delta == p2:
3008 nump2 += 1
3025 nump2 += 1
3009 elif delta != nullrev:
3026 elif delta != nullrev:
3010 numother += 1
3027 numother += 1
3011
3028
3012 # Obtain data on the raw chunks in the revlog.
3029 # Obtain data on the raw chunks in the revlog.
3013 if util.safehasattr(r, b'_getsegmentforrevs'):
3030 if util.safehasattr(r, b'_getsegmentforrevs'):
3014 segment = r._getsegmentforrevs(rev, rev)[1]
3031 segment = r._getsegmentforrevs(rev, rev)[1]
3015 else:
3032 else:
3016 segment = r._revlog._getsegmentforrevs(rev, rev)[1]
3033 segment = r._revlog._getsegmentforrevs(rev, rev)[1]
3017 if segment:
3034 if segment:
3018 chunktype = bytes(segment[0:1])
3035 chunktype = bytes(segment[0:1])
3019 else:
3036 else:
3020 chunktype = b'empty'
3037 chunktype = b'empty'
3021
3038
3022 if chunktype not in chunktypecounts:
3039 if chunktype not in chunktypecounts:
3023 chunktypecounts[chunktype] = 0
3040 chunktypecounts[chunktype] = 0
3024 chunktypesizes[chunktype] = 0
3041 chunktypesizes[chunktype] = 0
3025
3042
3026 chunktypecounts[chunktype] += 1
3043 chunktypecounts[chunktype] += 1
3027 chunktypesizes[chunktype] += size
3044 chunktypesizes[chunktype] += size
3028
3045
3029 # Adjust size min value for empty cases
3046 # Adjust size min value for empty cases
3030 for size in (datasize, fullsize, semisize, deltasize):
3047 for size in (datasize, fullsize, semisize, deltasize):
3031 if size[0] is None:
3048 if size[0] is None:
3032 size[0] = 0
3049 size[0] = 0
3033
3050
3034 numdeltas = numrevs - numfull - numempty - numsemi
3051 numdeltas = numrevs - numfull - numempty - numsemi
3035 numoprev = numprev - nump1prev - nump2prev
3052 numoprev = numprev - nump1prev - nump2prev
3036 totalrawsize = datasize[2]
3053 totalrawsize = datasize[2]
3037 datasize[2] /= numrevs
3054 datasize[2] /= numrevs
3038 fulltotal = fullsize[2]
3055 fulltotal = fullsize[2]
3039 if numfull == 0:
3056 if numfull == 0:
3040 fullsize[2] = 0
3057 fullsize[2] = 0
3041 else:
3058 else:
3042 fullsize[2] /= numfull
3059 fullsize[2] /= numfull
3043 semitotal = semisize[2]
3060 semitotal = semisize[2]
3044 snaptotal = {}
3061 snaptotal = {}
3045 if numsemi > 0:
3062 if numsemi > 0:
3046 semisize[2] /= numsemi
3063 semisize[2] /= numsemi
3047 for depth in snapsizedepth:
3064 for depth in snapsizedepth:
3048 snaptotal[depth] = snapsizedepth[depth][2]
3065 snaptotal[depth] = snapsizedepth[depth][2]
3049 snapsizedepth[depth][2] /= numsnapdepth[depth]
3066 snapsizedepth[depth][2] /= numsnapdepth[depth]
3050
3067
3051 deltatotal = deltasize[2]
3068 deltatotal = deltasize[2]
3052 if numdeltas > 0:
3069 if numdeltas > 0:
3053 deltasize[2] /= numdeltas
3070 deltasize[2] /= numdeltas
3054 totalsize = fulltotal + semitotal + deltatotal
3071 totalsize = fulltotal + semitotal + deltatotal
3055 avgchainlen = sum(chainlengths) / numrevs
3072 avgchainlen = sum(chainlengths) / numrevs
3056 maxchainlen = max(chainlengths)
3073 maxchainlen = max(chainlengths)
3057 maxchainspan = max(chainspans)
3074 maxchainspan = max(chainspans)
3058 compratio = 1
3075 compratio = 1
3059 if totalsize:
3076 if totalsize:
3060 compratio = totalrawsize / totalsize
3077 compratio = totalrawsize / totalsize
3061
3078
3062 basedfmtstr = b'%%%dd\n'
3079 basedfmtstr = b'%%%dd\n'
3063 basepcfmtstr = b'%%%dd %s(%%5.2f%%%%)\n'
3080 basepcfmtstr = b'%%%dd %s(%%5.2f%%%%)\n'
3064
3081
3065 def dfmtstr(max):
3082 def dfmtstr(max):
3066 return basedfmtstr % len(str(max))
3083 return basedfmtstr % len(str(max))
3067
3084
3068 def pcfmtstr(max, padding=0):
3085 def pcfmtstr(max, padding=0):
3069 return basepcfmtstr % (len(str(max)), b' ' * padding)
3086 return basepcfmtstr % (len(str(max)), b' ' * padding)
3070
3087
3071 def pcfmt(value, total):
3088 def pcfmt(value, total):
3072 if total:
3089 if total:
3073 return (value, 100 * float(value) / total)
3090 return (value, 100 * float(value) / total)
3074 else:
3091 else:
3075 return value, 100.0
3092 return value, 100.0
3076
3093
3077 ui.writenoi18n(b'format : %d\n' % format)
3094 ui.writenoi18n(b'format : %d\n' % format)
3078 ui.writenoi18n(b'flags : %s\n' % b', '.join(flags))
3095 ui.writenoi18n(b'flags : %s\n' % b', '.join(flags))
3079
3096
3080 ui.write(b'\n')
3097 ui.write(b'\n')
3081 fmt = pcfmtstr(totalsize)
3098 fmt = pcfmtstr(totalsize)
3082 fmt2 = dfmtstr(totalsize)
3099 fmt2 = dfmtstr(totalsize)
3083 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
3100 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
3084 ui.writenoi18n(b' merges : ' + fmt % pcfmt(nummerges, numrevs))
3101 ui.writenoi18n(b' merges : ' + fmt % pcfmt(nummerges, numrevs))
3085 ui.writenoi18n(
3102 ui.writenoi18n(
3086 b' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs)
3103 b' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs)
3087 )
3104 )
3088 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
3105 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
3089 ui.writenoi18n(b' empty : ' + fmt % pcfmt(numempty, numrevs))
3106 ui.writenoi18n(b' empty : ' + fmt % pcfmt(numempty, numrevs))
3090 ui.writenoi18n(
3107 ui.writenoi18n(
3091 b' text : '
3108 b' text : '
3092 + fmt % pcfmt(numemptytext, numemptytext + numemptydelta)
3109 + fmt % pcfmt(numemptytext, numemptytext + numemptydelta)
3093 )
3110 )
3094 ui.writenoi18n(
3111 ui.writenoi18n(
3095 b' delta : '
3112 b' delta : '
3096 + fmt % pcfmt(numemptydelta, numemptytext + numemptydelta)
3113 + fmt % pcfmt(numemptydelta, numemptytext + numemptydelta)
3097 )
3114 )
3098 ui.writenoi18n(
3115 ui.writenoi18n(
3099 b' snapshot : ' + fmt % pcfmt(numfull + numsemi, numrevs)
3116 b' snapshot : ' + fmt % pcfmt(numfull + numsemi, numrevs)
3100 )
3117 )
3101 for depth in sorted(numsnapdepth):
3118 for depth in sorted(numsnapdepth):
3102 ui.write(
3119 ui.write(
3103 (b' lvl-%-3d : ' % depth)
3120 (b' lvl-%-3d : ' % depth)
3104 + fmt % pcfmt(numsnapdepth[depth], numrevs)
3121 + fmt % pcfmt(numsnapdepth[depth], numrevs)
3105 )
3122 )
3106 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
3123 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
3107 ui.writenoi18n(b'revision size : ' + fmt2 % totalsize)
3124 ui.writenoi18n(b'revision size : ' + fmt2 % totalsize)
3108 ui.writenoi18n(
3125 ui.writenoi18n(
3109 b' snapshot : ' + fmt % pcfmt(fulltotal + semitotal, totalsize)
3126 b' snapshot : ' + fmt % pcfmt(fulltotal + semitotal, totalsize)
3110 )
3127 )
3111 for depth in sorted(numsnapdepth):
3128 for depth in sorted(numsnapdepth):
3112 ui.write(
3129 ui.write(
3113 (b' lvl-%-3d : ' % depth)
3130 (b' lvl-%-3d : ' % depth)
3114 + fmt % pcfmt(snaptotal[depth], totalsize)
3131 + fmt % pcfmt(snaptotal[depth], totalsize)
3115 )
3132 )
3116 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
3133 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
3117
3134
3118 def fmtchunktype(chunktype):
3135 def fmtchunktype(chunktype):
3119 if chunktype == b'empty':
3136 if chunktype == b'empty':
3120 return b' %s : ' % chunktype
3137 return b' %s : ' % chunktype
3121 elif chunktype in pycompat.bytestr(string.ascii_letters):
3138 elif chunktype in pycompat.bytestr(string.ascii_letters):
3122 return b' 0x%s (%s) : ' % (hex(chunktype), chunktype)
3139 return b' 0x%s (%s) : ' % (hex(chunktype), chunktype)
3123 else:
3140 else:
3124 return b' 0x%s : ' % hex(chunktype)
3141 return b' 0x%s : ' % hex(chunktype)
3125
3142
3126 ui.write(b'\n')
3143 ui.write(b'\n')
3127 ui.writenoi18n(b'chunks : ' + fmt2 % numrevs)
3144 ui.writenoi18n(b'chunks : ' + fmt2 % numrevs)
3128 for chunktype in sorted(chunktypecounts):
3145 for chunktype in sorted(chunktypecounts):
3129 ui.write(fmtchunktype(chunktype))
3146 ui.write(fmtchunktype(chunktype))
3130 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
3147 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
3131 ui.writenoi18n(b'chunks size : ' + fmt2 % totalsize)
3148 ui.writenoi18n(b'chunks size : ' + fmt2 % totalsize)
3132 for chunktype in sorted(chunktypecounts):
3149 for chunktype in sorted(chunktypecounts):
3133 ui.write(fmtchunktype(chunktype))
3150 ui.write(fmtchunktype(chunktype))
3134 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
3151 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
3135
3152
3136 ui.write(b'\n')
3153 ui.write(b'\n')
3137 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
3154 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
3138 ui.writenoi18n(b'avg chain length : ' + fmt % avgchainlen)
3155 ui.writenoi18n(b'avg chain length : ' + fmt % avgchainlen)
3139 ui.writenoi18n(b'max chain length : ' + fmt % maxchainlen)
3156 ui.writenoi18n(b'max chain length : ' + fmt % maxchainlen)
3140 ui.writenoi18n(b'max chain reach : ' + fmt % maxchainspan)
3157 ui.writenoi18n(b'max chain reach : ' + fmt % maxchainspan)
3141 ui.writenoi18n(b'compression ratio : ' + fmt % compratio)
3158 ui.writenoi18n(b'compression ratio : ' + fmt % compratio)
3142
3159
3143 if format > 0:
3160 if format > 0:
3144 ui.write(b'\n')
3161 ui.write(b'\n')
3145 ui.writenoi18n(
3162 ui.writenoi18n(
3146 b'uncompressed data size (min/max/avg) : %d / %d / %d\n'
3163 b'uncompressed data size (min/max/avg) : %d / %d / %d\n'
3147 % tuple(datasize)
3164 % tuple(datasize)
3148 )
3165 )
3149 ui.writenoi18n(
3166 ui.writenoi18n(
3150 b'full revision size (min/max/avg) : %d / %d / %d\n'
3167 b'full revision size (min/max/avg) : %d / %d / %d\n'
3151 % tuple(fullsize)
3168 % tuple(fullsize)
3152 )
3169 )
3153 ui.writenoi18n(
3170 ui.writenoi18n(
3154 b'inter-snapshot size (min/max/avg) : %d / %d / %d\n'
3171 b'inter-snapshot size (min/max/avg) : %d / %d / %d\n'
3155 % tuple(semisize)
3172 % tuple(semisize)
3156 )
3173 )
3157 for depth in sorted(snapsizedepth):
3174 for depth in sorted(snapsizedepth):
3158 if depth == 0:
3175 if depth == 0:
3159 continue
3176 continue
3160 ui.writenoi18n(
3177 ui.writenoi18n(
3161 b' level-%-3d (min/max/avg) : %d / %d / %d\n'
3178 b' level-%-3d (min/max/avg) : %d / %d / %d\n'
3162 % ((depth,) + tuple(snapsizedepth[depth]))
3179 % ((depth,) + tuple(snapsizedepth[depth]))
3163 )
3180 )
3164 ui.writenoi18n(
3181 ui.writenoi18n(
3165 b'delta size (min/max/avg) : %d / %d / %d\n'
3182 b'delta size (min/max/avg) : %d / %d / %d\n'
3166 % tuple(deltasize)
3183 % tuple(deltasize)
3167 )
3184 )
3168
3185
3169 if numdeltas > 0:
3186 if numdeltas > 0:
3170 ui.write(b'\n')
3187 ui.write(b'\n')
3171 fmt = pcfmtstr(numdeltas)
3188 fmt = pcfmtstr(numdeltas)
3172 fmt2 = pcfmtstr(numdeltas, 4)
3189 fmt2 = pcfmtstr(numdeltas, 4)
3173 ui.writenoi18n(
3190 ui.writenoi18n(
3174 b'deltas against prev : ' + fmt % pcfmt(numprev, numdeltas)
3191 b'deltas against prev : ' + fmt % pcfmt(numprev, numdeltas)
3175 )
3192 )
3176 if numprev > 0:
3193 if numprev > 0:
3177 ui.writenoi18n(
3194 ui.writenoi18n(
3178 b' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev)
3195 b' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev)
3179 )
3196 )
3180 ui.writenoi18n(
3197 ui.writenoi18n(
3181 b' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev)
3198 b' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev)
3182 )
3199 )
3183 ui.writenoi18n(
3200 ui.writenoi18n(
3184 b' other : ' + fmt2 % pcfmt(numoprev, numprev)
3201 b' other : ' + fmt2 % pcfmt(numoprev, numprev)
3185 )
3202 )
3186 if gdelta:
3203 if gdelta:
3187 ui.writenoi18n(
3204 ui.writenoi18n(
3188 b'deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas)
3205 b'deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas)
3189 )
3206 )
3190 ui.writenoi18n(
3207 ui.writenoi18n(
3191 b'deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas)
3208 b'deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas)
3192 )
3209 )
3193 ui.writenoi18n(
3210 ui.writenoi18n(
3194 b'deltas against other : ' + fmt % pcfmt(numother, numdeltas)
3211 b'deltas against other : ' + fmt % pcfmt(numother, numdeltas)
3195 )
3212 )
3196
3213
3197
3214
3198 @command(
3215 @command(
3199 b'debugrevlogindex',
3216 b'debugrevlogindex',
3200 cmdutil.debugrevlogopts
3217 cmdutil.debugrevlogopts
3201 + [(b'f', b'format', 0, _(b'revlog format'), _(b'FORMAT'))],
3218 + [(b'f', b'format', 0, _(b'revlog format'), _(b'FORMAT'))],
3202 _(b'[-f FORMAT] -c|-m|FILE'),
3219 _(b'[-f FORMAT] -c|-m|FILE'),
3203 optionalrepo=True,
3220 optionalrepo=True,
3204 )
3221 )
3205 def debugrevlogindex(ui, repo, file_=None, **opts):
3222 def debugrevlogindex(ui, repo, file_=None, **opts):
3206 """dump the contents of a revlog index"""
3223 """dump the contents of a revlog index"""
3207 opts = pycompat.byteskwargs(opts)
3224 opts = pycompat.byteskwargs(opts)
3208 r = cmdutil.openrevlog(repo, b'debugrevlogindex', file_, opts)
3225 r = cmdutil.openrevlog(repo, b'debugrevlogindex', file_, opts)
3209 format = opts.get(b'format', 0)
3226 format = opts.get(b'format', 0)
3210 if format not in (0, 1):
3227 if format not in (0, 1):
3211 raise error.Abort(_(b"unknown format %d") % format)
3228 raise error.Abort(_(b"unknown format %d") % format)
3212
3229
3213 if ui.debugflag:
3230 if ui.debugflag:
3214 shortfn = hex
3231 shortfn = hex
3215 else:
3232 else:
3216 shortfn = short
3233 shortfn = short
3217
3234
3218 # There might not be anything in r, so have a sane default
3235 # There might not be anything in r, so have a sane default
3219 idlen = 12
3236 idlen = 12
3220 for i in r:
3237 for i in r:
3221 idlen = len(shortfn(r.node(i)))
3238 idlen = len(shortfn(r.node(i)))
3222 break
3239 break
3223
3240
3224 if format == 0:
3241 if format == 0:
3225 if ui.verbose:
3242 if ui.verbose:
3226 ui.writenoi18n(
3243 ui.writenoi18n(
3227 b" rev offset length linkrev %s %s p2\n"
3244 b" rev offset length linkrev %s %s p2\n"
3228 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3245 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3229 )
3246 )
3230 else:
3247 else:
3231 ui.writenoi18n(
3248 ui.writenoi18n(
3232 b" rev linkrev %s %s p2\n"
3249 b" rev linkrev %s %s p2\n"
3233 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3250 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3234 )
3251 )
3235 elif format == 1:
3252 elif format == 1:
3236 if ui.verbose:
3253 if ui.verbose:
3237 ui.writenoi18n(
3254 ui.writenoi18n(
3238 (
3255 (
3239 b" rev flag offset length size link p1"
3256 b" rev flag offset length size link p1"
3240 b" p2 %s\n"
3257 b" p2 %s\n"
3241 )
3258 )
3242 % b"nodeid".rjust(idlen)
3259 % b"nodeid".rjust(idlen)
3243 )
3260 )
3244 else:
3261 else:
3245 ui.writenoi18n(
3262 ui.writenoi18n(
3246 b" rev flag size link p1 p2 %s\n"
3263 b" rev flag size link p1 p2 %s\n"
3247 % b"nodeid".rjust(idlen)
3264 % b"nodeid".rjust(idlen)
3248 )
3265 )
3249
3266
3250 for i in r:
3267 for i in r:
3251 node = r.node(i)
3268 node = r.node(i)
3252 if format == 0:
3269 if format == 0:
3253 try:
3270 try:
3254 pp = r.parents(node)
3271 pp = r.parents(node)
3255 except Exception:
3272 except Exception:
3256 pp = [nullid, nullid]
3273 pp = [nullid, nullid]
3257 if ui.verbose:
3274 if ui.verbose:
3258 ui.write(
3275 ui.write(
3259 b"% 6d % 9d % 7d % 7d %s %s %s\n"
3276 b"% 6d % 9d % 7d % 7d %s %s %s\n"
3260 % (
3277 % (
3261 i,
3278 i,
3262 r.start(i),
3279 r.start(i),
3263 r.length(i),
3280 r.length(i),
3264 r.linkrev(i),
3281 r.linkrev(i),
3265 shortfn(node),
3282 shortfn(node),
3266 shortfn(pp[0]),
3283 shortfn(pp[0]),
3267 shortfn(pp[1]),
3284 shortfn(pp[1]),
3268 )
3285 )
3269 )
3286 )
3270 else:
3287 else:
3271 ui.write(
3288 ui.write(
3272 b"% 6d % 7d %s %s %s\n"
3289 b"% 6d % 7d %s %s %s\n"
3273 % (
3290 % (
3274 i,
3291 i,
3275 r.linkrev(i),
3292 r.linkrev(i),
3276 shortfn(node),
3293 shortfn(node),
3277 shortfn(pp[0]),
3294 shortfn(pp[0]),
3278 shortfn(pp[1]),
3295 shortfn(pp[1]),
3279 )
3296 )
3280 )
3297 )
3281 elif format == 1:
3298 elif format == 1:
3282 pr = r.parentrevs(i)
3299 pr = r.parentrevs(i)
3283 if ui.verbose:
3300 if ui.verbose:
3284 ui.write(
3301 ui.write(
3285 b"% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n"
3302 b"% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n"
3286 % (
3303 % (
3287 i,
3304 i,
3288 r.flags(i),
3305 r.flags(i),
3289 r.start(i),
3306 r.start(i),
3290 r.length(i),
3307 r.length(i),
3291 r.rawsize(i),
3308 r.rawsize(i),
3292 r.linkrev(i),
3309 r.linkrev(i),
3293 pr[0],
3310 pr[0],
3294 pr[1],
3311 pr[1],
3295 shortfn(node),
3312 shortfn(node),
3296 )
3313 )
3297 )
3314 )
3298 else:
3315 else:
3299 ui.write(
3316 ui.write(
3300 b"% 6d %04x % 8d % 6d % 6d % 6d %s\n"
3317 b"% 6d %04x % 8d % 6d % 6d % 6d %s\n"
3301 % (
3318 % (
3302 i,
3319 i,
3303 r.flags(i),
3320 r.flags(i),
3304 r.rawsize(i),
3321 r.rawsize(i),
3305 r.linkrev(i),
3322 r.linkrev(i),
3306 pr[0],
3323 pr[0],
3307 pr[1],
3324 pr[1],
3308 shortfn(node),
3325 shortfn(node),
3309 )
3326 )
3310 )
3327 )
3311
3328
3312
3329
3313 @command(
3330 @command(
3314 b'debugrevspec',
3331 b'debugrevspec',
3315 [
3332 [
3316 (
3333 (
3317 b'',
3334 b'',
3318 b'optimize',
3335 b'optimize',
3319 None,
3336 None,
3320 _(b'print parsed tree after optimizing (DEPRECATED)'),
3337 _(b'print parsed tree after optimizing (DEPRECATED)'),
3321 ),
3338 ),
3322 (
3339 (
3323 b'',
3340 b'',
3324 b'show-revs',
3341 b'show-revs',
3325 True,
3342 True,
3326 _(b'print list of result revisions (default)'),
3343 _(b'print list of result revisions (default)'),
3327 ),
3344 ),
3328 (
3345 (
3329 b's',
3346 b's',
3330 b'show-set',
3347 b'show-set',
3331 None,
3348 None,
3332 _(b'print internal representation of result set'),
3349 _(b'print internal representation of result set'),
3333 ),
3350 ),
3334 (
3351 (
3335 b'p',
3352 b'p',
3336 b'show-stage',
3353 b'show-stage',
3337 [],
3354 [],
3338 _(b'print parsed tree at the given stage'),
3355 _(b'print parsed tree at the given stage'),
3339 _(b'NAME'),
3356 _(b'NAME'),
3340 ),
3357 ),
3341 (b'', b'no-optimized', False, _(b'evaluate tree without optimization')),
3358 (b'', b'no-optimized', False, _(b'evaluate tree without optimization')),
3342 (b'', b'verify-optimized', False, _(b'verify optimized result')),
3359 (b'', b'verify-optimized', False, _(b'verify optimized result')),
3343 ],
3360 ],
3344 b'REVSPEC',
3361 b'REVSPEC',
3345 )
3362 )
3346 def debugrevspec(ui, repo, expr, **opts):
3363 def debugrevspec(ui, repo, expr, **opts):
3347 """parse and apply a revision specification
3364 """parse and apply a revision specification
3348
3365
3349 Use -p/--show-stage option to print the parsed tree at the given stages.
3366 Use -p/--show-stage option to print the parsed tree at the given stages.
3350 Use -p all to print tree at every stage.
3367 Use -p all to print tree at every stage.
3351
3368
3352 Use --no-show-revs option with -s or -p to print only the set
3369 Use --no-show-revs option with -s or -p to print only the set
3353 representation or the parsed tree respectively.
3370 representation or the parsed tree respectively.
3354
3371
3355 Use --verify-optimized to compare the optimized result with the unoptimized
3372 Use --verify-optimized to compare the optimized result with the unoptimized
3356 one. Returns 1 if the optimized result differs.
3373 one. Returns 1 if the optimized result differs.
3357 """
3374 """
3358 opts = pycompat.byteskwargs(opts)
3375 opts = pycompat.byteskwargs(opts)
3359 aliases = ui.configitems(b'revsetalias')
3376 aliases = ui.configitems(b'revsetalias')
3360 stages = [
3377 stages = [
3361 (b'parsed', lambda tree: tree),
3378 (b'parsed', lambda tree: tree),
3362 (
3379 (
3363 b'expanded',
3380 b'expanded',
3364 lambda tree: revsetlang.expandaliases(tree, aliases, ui.warn),
3381 lambda tree: revsetlang.expandaliases(tree, aliases, ui.warn),
3365 ),
3382 ),
3366 (b'concatenated', revsetlang.foldconcat),
3383 (b'concatenated', revsetlang.foldconcat),
3367 (b'analyzed', revsetlang.analyze),
3384 (b'analyzed', revsetlang.analyze),
3368 (b'optimized', revsetlang.optimize),
3385 (b'optimized', revsetlang.optimize),
3369 ]
3386 ]
3370 if opts[b'no_optimized']:
3387 if opts[b'no_optimized']:
3371 stages = stages[:-1]
3388 stages = stages[:-1]
3372 if opts[b'verify_optimized'] and opts[b'no_optimized']:
3389 if opts[b'verify_optimized'] and opts[b'no_optimized']:
3373 raise error.Abort(
3390 raise error.Abort(
3374 _(b'cannot use --verify-optimized with --no-optimized')
3391 _(b'cannot use --verify-optimized with --no-optimized')
3375 )
3392 )
3376 stagenames = {n for n, f in stages}
3393 stagenames = {n for n, f in stages}
3377
3394
3378 showalways = set()
3395 showalways = set()
3379 showchanged = set()
3396 showchanged = set()
3380 if ui.verbose and not opts[b'show_stage']:
3397 if ui.verbose and not opts[b'show_stage']:
3381 # show parsed tree by --verbose (deprecated)
3398 # show parsed tree by --verbose (deprecated)
3382 showalways.add(b'parsed')
3399 showalways.add(b'parsed')
3383 showchanged.update([b'expanded', b'concatenated'])
3400 showchanged.update([b'expanded', b'concatenated'])
3384 if opts[b'optimize']:
3401 if opts[b'optimize']:
3385 showalways.add(b'optimized')
3402 showalways.add(b'optimized')
3386 if opts[b'show_stage'] and opts[b'optimize']:
3403 if opts[b'show_stage'] and opts[b'optimize']:
3387 raise error.Abort(_(b'cannot use --optimize with --show-stage'))
3404 raise error.Abort(_(b'cannot use --optimize with --show-stage'))
3388 if opts[b'show_stage'] == [b'all']:
3405 if opts[b'show_stage'] == [b'all']:
3389 showalways.update(stagenames)
3406 showalways.update(stagenames)
3390 else:
3407 else:
3391 for n in opts[b'show_stage']:
3408 for n in opts[b'show_stage']:
3392 if n not in stagenames:
3409 if n not in stagenames:
3393 raise error.Abort(_(b'invalid stage name: %s') % n)
3410 raise error.Abort(_(b'invalid stage name: %s') % n)
3394 showalways.update(opts[b'show_stage'])
3411 showalways.update(opts[b'show_stage'])
3395
3412
3396 treebystage = {}
3413 treebystage = {}
3397 printedtree = None
3414 printedtree = None
3398 tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
3415 tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
3399 for n, f in stages:
3416 for n, f in stages:
3400 treebystage[n] = tree = f(tree)
3417 treebystage[n] = tree = f(tree)
3401 if n in showalways or (n in showchanged and tree != printedtree):
3418 if n in showalways or (n in showchanged and tree != printedtree):
3402 if opts[b'show_stage'] or n != b'parsed':
3419 if opts[b'show_stage'] or n != b'parsed':
3403 ui.write(b"* %s:\n" % n)
3420 ui.write(b"* %s:\n" % n)
3404 ui.write(revsetlang.prettyformat(tree), b"\n")
3421 ui.write(revsetlang.prettyformat(tree), b"\n")
3405 printedtree = tree
3422 printedtree = tree
3406
3423
3407 if opts[b'verify_optimized']:
3424 if opts[b'verify_optimized']:
3408 arevs = revset.makematcher(treebystage[b'analyzed'])(repo)
3425 arevs = revset.makematcher(treebystage[b'analyzed'])(repo)
3409 brevs = revset.makematcher(treebystage[b'optimized'])(repo)
3426 brevs = revset.makematcher(treebystage[b'optimized'])(repo)
3410 if opts[b'show_set'] or (opts[b'show_set'] is None and ui.verbose):
3427 if opts[b'show_set'] or (opts[b'show_set'] is None and ui.verbose):
3411 ui.writenoi18n(
3428 ui.writenoi18n(
3412 b"* analyzed set:\n", stringutil.prettyrepr(arevs), b"\n"
3429 b"* analyzed set:\n", stringutil.prettyrepr(arevs), b"\n"
3413 )
3430 )
3414 ui.writenoi18n(
3431 ui.writenoi18n(
3415 b"* optimized set:\n", stringutil.prettyrepr(brevs), b"\n"
3432 b"* optimized set:\n", stringutil.prettyrepr(brevs), b"\n"
3416 )
3433 )
3417 arevs = list(arevs)
3434 arevs = list(arevs)
3418 brevs = list(brevs)
3435 brevs = list(brevs)
3419 if arevs == brevs:
3436 if arevs == brevs:
3420 return 0
3437 return 0
3421 ui.writenoi18n(b'--- analyzed\n', label=b'diff.file_a')
3438 ui.writenoi18n(b'--- analyzed\n', label=b'diff.file_a')
3422 ui.writenoi18n(b'+++ optimized\n', label=b'diff.file_b')
3439 ui.writenoi18n(b'+++ optimized\n', label=b'diff.file_b')
3423 sm = difflib.SequenceMatcher(None, arevs, brevs)
3440 sm = difflib.SequenceMatcher(None, arevs, brevs)
3424 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3441 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3425 if tag in ('delete', 'replace'):
3442 if tag in ('delete', 'replace'):
3426 for c in arevs[alo:ahi]:
3443 for c in arevs[alo:ahi]:
3427 ui.write(b'-%d\n' % c, label=b'diff.deleted')
3444 ui.write(b'-%d\n' % c, label=b'diff.deleted')
3428 if tag in ('insert', 'replace'):
3445 if tag in ('insert', 'replace'):
3429 for c in brevs[blo:bhi]:
3446 for c in brevs[blo:bhi]:
3430 ui.write(b'+%d\n' % c, label=b'diff.inserted')
3447 ui.write(b'+%d\n' % c, label=b'diff.inserted')
3431 if tag == 'equal':
3448 if tag == 'equal':
3432 for c in arevs[alo:ahi]:
3449 for c in arevs[alo:ahi]:
3433 ui.write(b' %d\n' % c)
3450 ui.write(b' %d\n' % c)
3434 return 1
3451 return 1
3435
3452
3436 func = revset.makematcher(tree)
3453 func = revset.makematcher(tree)
3437 revs = func(repo)
3454 revs = func(repo)
3438 if opts[b'show_set'] or (opts[b'show_set'] is None and ui.verbose):
3455 if opts[b'show_set'] or (opts[b'show_set'] is None and ui.verbose):
3439 ui.writenoi18n(b"* set:\n", stringutil.prettyrepr(revs), b"\n")
3456 ui.writenoi18n(b"* set:\n", stringutil.prettyrepr(revs), b"\n")
3440 if not opts[b'show_revs']:
3457 if not opts[b'show_revs']:
3441 return
3458 return
3442 for c in revs:
3459 for c in revs:
3443 ui.write(b"%d\n" % c)
3460 ui.write(b"%d\n" % c)
3444
3461
3445
3462
3446 @command(
3463 @command(
3447 b'debugserve',
3464 b'debugserve',
3448 [
3465 [
3449 (
3466 (
3450 b'',
3467 b'',
3451 b'sshstdio',
3468 b'sshstdio',
3452 False,
3469 False,
3453 _(b'run an SSH server bound to process handles'),
3470 _(b'run an SSH server bound to process handles'),
3454 ),
3471 ),
3455 (b'', b'logiofd', b'', _(b'file descriptor to log server I/O to')),
3472 (b'', b'logiofd', b'', _(b'file descriptor to log server I/O to')),
3456 (b'', b'logiofile', b'', _(b'file to log server I/O to')),
3473 (b'', b'logiofile', b'', _(b'file to log server I/O to')),
3457 ],
3474 ],
3458 b'',
3475 b'',
3459 )
3476 )
3460 def debugserve(ui, repo, **opts):
3477 def debugserve(ui, repo, **opts):
3461 """run a server with advanced settings
3478 """run a server with advanced settings
3462
3479
3463 This command is similar to :hg:`serve`. It exists partially as a
3480 This command is similar to :hg:`serve`. It exists partially as a
3464 workaround to the fact that ``hg serve --stdio`` must have specific
3481 workaround to the fact that ``hg serve --stdio`` must have specific
3465 arguments for security reasons.
3482 arguments for security reasons.
3466 """
3483 """
3467 opts = pycompat.byteskwargs(opts)
3484 opts = pycompat.byteskwargs(opts)
3468
3485
3469 if not opts[b'sshstdio']:
3486 if not opts[b'sshstdio']:
3470 raise error.Abort(_(b'only --sshstdio is currently supported'))
3487 raise error.Abort(_(b'only --sshstdio is currently supported'))
3471
3488
3472 logfh = None
3489 logfh = None
3473
3490
3474 if opts[b'logiofd'] and opts[b'logiofile']:
3491 if opts[b'logiofd'] and opts[b'logiofile']:
3475 raise error.Abort(_(b'cannot use both --logiofd and --logiofile'))
3492 raise error.Abort(_(b'cannot use both --logiofd and --logiofile'))
3476
3493
3477 if opts[b'logiofd']:
3494 if opts[b'logiofd']:
3478 # Ideally we would be line buffered. But line buffering in binary
3495 # Ideally we would be line buffered. But line buffering in binary
3479 # mode isn't supported and emits a warning in Python 3.8+. Disabling
3496 # mode isn't supported and emits a warning in Python 3.8+. Disabling
3480 # buffering could have performance impacts. But since this isn't
3497 # buffering could have performance impacts. But since this isn't
3481 # performance critical code, it should be fine.
3498 # performance critical code, it should be fine.
3482 try:
3499 try:
3483 logfh = os.fdopen(int(opts[b'logiofd']), 'ab', 0)
3500 logfh = os.fdopen(int(opts[b'logiofd']), 'ab', 0)
3484 except OSError as e:
3501 except OSError as e:
3485 if e.errno != errno.ESPIPE:
3502 if e.errno != errno.ESPIPE:
3486 raise
3503 raise
3487 # can't seek a pipe, so `ab` mode fails on py3
3504 # can't seek a pipe, so `ab` mode fails on py3
3488 logfh = os.fdopen(int(opts[b'logiofd']), 'wb', 0)
3505 logfh = os.fdopen(int(opts[b'logiofd']), 'wb', 0)
3489 elif opts[b'logiofile']:
3506 elif opts[b'logiofile']:
3490 logfh = open(opts[b'logiofile'], b'ab', 0)
3507 logfh = open(opts[b'logiofile'], b'ab', 0)
3491
3508
3492 s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
3509 s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
3493 s.serve_forever()
3510 s.serve_forever()
3494
3511
3495
3512
3496 @command(b'debugsetparents', [], _(b'REV1 [REV2]'))
3513 @command(b'debugsetparents', [], _(b'REV1 [REV2]'))
3497 def debugsetparents(ui, repo, rev1, rev2=None):
3514 def debugsetparents(ui, repo, rev1, rev2=None):
3498 """manually set the parents of the current working directory (DANGEROUS)
3515 """manually set the parents of the current working directory (DANGEROUS)
3499
3516
3500 This command is not what you are looking for and should not be used. Using
3517 This command is not what you are looking for and should not be used. Using
3501 this command will most certainly results in slight corruption of the file
3518 this command will most certainly results in slight corruption of the file
3502 level histories withing your repository. DO NOT USE THIS COMMAND.
3519 level histories withing your repository. DO NOT USE THIS COMMAND.
3503
3520
3504 The command update the p1 and p2 field in the dirstate, and not touching
3521 The command update the p1 and p2 field in the dirstate, and not touching
3505 anything else. This useful for writing repository conversion tools, but
3522 anything else. This useful for writing repository conversion tools, but
3506 should be used with extreme care. For example, neither the working
3523 should be used with extreme care. For example, neither the working
3507 directory nor the dirstate is updated, so file status may be incorrect
3524 directory nor the dirstate is updated, so file status may be incorrect
3508 after running this command. Only used if you are one of the few people that
3525 after running this command. Only used if you are one of the few people that
3509 deeply unstand both conversion tools and file level histories. If you are
3526 deeply unstand both conversion tools and file level histories. If you are
3510 reading this help, you are not one of this people (most of them sailed west
3527 reading this help, you are not one of this people (most of them sailed west
3511 from Mithlond anyway.
3528 from Mithlond anyway.
3512
3529
3513 So one last time DO NOT USE THIS COMMAND.
3530 So one last time DO NOT USE THIS COMMAND.
3514
3531
3515 Returns 0 on success.
3532 Returns 0 on success.
3516 """
3533 """
3517
3534
3518 node1 = scmutil.revsingle(repo, rev1).node()
3535 node1 = scmutil.revsingle(repo, rev1).node()
3519 node2 = scmutil.revsingle(repo, rev2, b'null').node()
3536 node2 = scmutil.revsingle(repo, rev2, b'null').node()
3520
3537
3521 with repo.wlock():
3538 with repo.wlock():
3522 repo.setparents(node1, node2)
3539 repo.setparents(node1, node2)
3523
3540
3524
3541
3525 @command(b'debugsidedata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
3542 @command(b'debugsidedata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
3526 def debugsidedata(ui, repo, file_, rev=None, **opts):
3543 def debugsidedata(ui, repo, file_, rev=None, **opts):
3527 """dump the side data for a cl/manifest/file revision
3544 """dump the side data for a cl/manifest/file revision
3528
3545
3529 Use --verbose to dump the sidedata content."""
3546 Use --verbose to dump the sidedata content."""
3530 opts = pycompat.byteskwargs(opts)
3547 opts = pycompat.byteskwargs(opts)
3531 if opts.get(b'changelog') or opts.get(b'manifest') or opts.get(b'dir'):
3548 if opts.get(b'changelog') or opts.get(b'manifest') or opts.get(b'dir'):
3532 if rev is not None:
3549 if rev is not None:
3533 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
3550 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
3534 file_, rev = None, file_
3551 file_, rev = None, file_
3535 elif rev is None:
3552 elif rev is None:
3536 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
3553 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
3537 r = cmdutil.openstorage(repo, b'debugdata', file_, opts)
3554 r = cmdutil.openstorage(repo, b'debugdata', file_, opts)
3538 r = getattr(r, '_revlog', r)
3555 r = getattr(r, '_revlog', r)
3539 try:
3556 try:
3540 sidedata = r.sidedata(r.lookup(rev))
3557 sidedata = r.sidedata(r.lookup(rev))
3541 except KeyError:
3558 except KeyError:
3542 raise error.Abort(_(b'invalid revision identifier %s') % rev)
3559 raise error.Abort(_(b'invalid revision identifier %s') % rev)
3543 if sidedata:
3560 if sidedata:
3544 sidedata = list(sidedata.items())
3561 sidedata = list(sidedata.items())
3545 sidedata.sort()
3562 sidedata.sort()
3546 ui.writenoi18n(b'%d sidedata entries\n' % len(sidedata))
3563 ui.writenoi18n(b'%d sidedata entries\n' % len(sidedata))
3547 for key, value in sidedata:
3564 for key, value in sidedata:
3548 ui.writenoi18n(b' entry-%04o size %d\n' % (key, len(value)))
3565 ui.writenoi18n(b' entry-%04o size %d\n' % (key, len(value)))
3549 if ui.verbose:
3566 if ui.verbose:
3550 ui.writenoi18n(b' %s\n' % stringutil.pprint(value))
3567 ui.writenoi18n(b' %s\n' % stringutil.pprint(value))
3551
3568
3552
3569
3553 @command(b'debugssl', [], b'[SOURCE]', optionalrepo=True)
3570 @command(b'debugssl', [], b'[SOURCE]', optionalrepo=True)
3554 def debugssl(ui, repo, source=None, **opts):
3571 def debugssl(ui, repo, source=None, **opts):
3555 """test a secure connection to a server
3572 """test a secure connection to a server
3556
3573
3557 This builds the certificate chain for the server on Windows, installing the
3574 This builds the certificate chain for the server on Windows, installing the
3558 missing intermediates and trusted root via Windows Update if necessary. It
3575 missing intermediates and trusted root via Windows Update if necessary. It
3559 does nothing on other platforms.
3576 does nothing on other platforms.
3560
3577
3561 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
3578 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
3562 that server is used. See :hg:`help urls` for more information.
3579 that server is used. See :hg:`help urls` for more information.
3563
3580
3564 If the update succeeds, retry the original operation. Otherwise, the cause
3581 If the update succeeds, retry the original operation. Otherwise, the cause
3565 of the SSL error is likely another issue.
3582 of the SSL error is likely another issue.
3566 """
3583 """
3567 if not pycompat.iswindows:
3584 if not pycompat.iswindows:
3568 raise error.Abort(
3585 raise error.Abort(
3569 _(b'certificate chain building is only possible on Windows')
3586 _(b'certificate chain building is only possible on Windows')
3570 )
3587 )
3571
3588
3572 if not source:
3589 if not source:
3573 if not repo:
3590 if not repo:
3574 raise error.Abort(
3591 raise error.Abort(
3575 _(
3592 _(
3576 b"there is no Mercurial repository here, and no "
3593 b"there is no Mercurial repository here, and no "
3577 b"server specified"
3594 b"server specified"
3578 )
3595 )
3579 )
3596 )
3580 source = b"default"
3597 source = b"default"
3581
3598
3582 source, branches = hg.parseurl(ui.expandpath(source))
3599 source, branches = hg.parseurl(ui.expandpath(source))
3583 url = util.url(source)
3600 url = util.url(source)
3584
3601
3585 defaultport = {b'https': 443, b'ssh': 22}
3602 defaultport = {b'https': 443, b'ssh': 22}
3586 if url.scheme in defaultport:
3603 if url.scheme in defaultport:
3587 try:
3604 try:
3588 addr = (url.host, int(url.port or defaultport[url.scheme]))
3605 addr = (url.host, int(url.port or defaultport[url.scheme]))
3589 except ValueError:
3606 except ValueError:
3590 raise error.Abort(_(b"malformed port number in URL"))
3607 raise error.Abort(_(b"malformed port number in URL"))
3591 else:
3608 else:
3592 raise error.Abort(_(b"only https and ssh connections are supported"))
3609 raise error.Abort(_(b"only https and ssh connections are supported"))
3593
3610
3594 from . import win32
3611 from . import win32
3595
3612
3596 s = ssl.wrap_socket(
3613 s = ssl.wrap_socket(
3597 socket.socket(),
3614 socket.socket(),
3598 ssl_version=ssl.PROTOCOL_TLS,
3615 ssl_version=ssl.PROTOCOL_TLS,
3599 cert_reqs=ssl.CERT_NONE,
3616 cert_reqs=ssl.CERT_NONE,
3600 ca_certs=None,
3617 ca_certs=None,
3601 )
3618 )
3602
3619
3603 try:
3620 try:
3604 s.connect(addr)
3621 s.connect(addr)
3605 cert = s.getpeercert(True)
3622 cert = s.getpeercert(True)
3606
3623
3607 ui.status(_(b'checking the certificate chain for %s\n') % url.host)
3624 ui.status(_(b'checking the certificate chain for %s\n') % url.host)
3608
3625
3609 complete = win32.checkcertificatechain(cert, build=False)
3626 complete = win32.checkcertificatechain(cert, build=False)
3610
3627
3611 if not complete:
3628 if not complete:
3612 ui.status(_(b'certificate chain is incomplete, updating... '))
3629 ui.status(_(b'certificate chain is incomplete, updating... '))
3613
3630
3614 if not win32.checkcertificatechain(cert):
3631 if not win32.checkcertificatechain(cert):
3615 ui.status(_(b'failed.\n'))
3632 ui.status(_(b'failed.\n'))
3616 else:
3633 else:
3617 ui.status(_(b'done.\n'))
3634 ui.status(_(b'done.\n'))
3618 else:
3635 else:
3619 ui.status(_(b'full certificate chain is available\n'))
3636 ui.status(_(b'full certificate chain is available\n'))
3620 finally:
3637 finally:
3621 s.close()
3638 s.close()
3622
3639
3623
3640
3624 @command(
3641 @command(
3625 b"debugbackupbundle",
3642 b"debugbackupbundle",
3626 [
3643 [
3627 (
3644 (
3628 b"",
3645 b"",
3629 b"recover",
3646 b"recover",
3630 b"",
3647 b"",
3631 b"brings the specified changeset back into the repository",
3648 b"brings the specified changeset back into the repository",
3632 )
3649 )
3633 ]
3650 ]
3634 + cmdutil.logopts,
3651 + cmdutil.logopts,
3635 _(b"hg debugbackupbundle [--recover HASH]"),
3652 _(b"hg debugbackupbundle [--recover HASH]"),
3636 )
3653 )
3637 def debugbackupbundle(ui, repo, *pats, **opts):
3654 def debugbackupbundle(ui, repo, *pats, **opts):
3638 """lists the changesets available in backup bundles
3655 """lists the changesets available in backup bundles
3639
3656
3640 Without any arguments, this command prints a list of the changesets in each
3657 Without any arguments, this command prints a list of the changesets in each
3641 backup bundle.
3658 backup bundle.
3642
3659
3643 --recover takes a changeset hash and unbundles the first bundle that
3660 --recover takes a changeset hash and unbundles the first bundle that
3644 contains that hash, which puts that changeset back in your repository.
3661 contains that hash, which puts that changeset back in your repository.
3645
3662
3646 --verbose will print the entire commit message and the bundle path for that
3663 --verbose will print the entire commit message and the bundle path for that
3647 backup.
3664 backup.
3648 """
3665 """
3649 backups = list(
3666 backups = list(
3650 filter(
3667 filter(
3651 os.path.isfile, glob.glob(repo.vfs.join(b"strip-backup") + b"/*.hg")
3668 os.path.isfile, glob.glob(repo.vfs.join(b"strip-backup") + b"/*.hg")
3652 )
3669 )
3653 )
3670 )
3654 backups.sort(key=lambda x: os.path.getmtime(x), reverse=True)
3671 backups.sort(key=lambda x: os.path.getmtime(x), reverse=True)
3655
3672
3656 opts = pycompat.byteskwargs(opts)
3673 opts = pycompat.byteskwargs(opts)
3657 opts[b"bundle"] = b""
3674 opts[b"bundle"] = b""
3658 opts[b"force"] = None
3675 opts[b"force"] = None
3659 limit = logcmdutil.getlimit(opts)
3676 limit = logcmdutil.getlimit(opts)
3660
3677
3661 def display(other, chlist, displayer):
3678 def display(other, chlist, displayer):
3662 if opts.get(b"newest_first"):
3679 if opts.get(b"newest_first"):
3663 chlist.reverse()
3680 chlist.reverse()
3664 count = 0
3681 count = 0
3665 for n in chlist:
3682 for n in chlist:
3666 if limit is not None and count >= limit:
3683 if limit is not None and count >= limit:
3667 break
3684 break
3668 parents = [True for p in other.changelog.parents(n) if p != nullid]
3685 parents = [True for p in other.changelog.parents(n) if p != nullid]
3669 if opts.get(b"no_merges") and len(parents) == 2:
3686 if opts.get(b"no_merges") and len(parents) == 2:
3670 continue
3687 continue
3671 count += 1
3688 count += 1
3672 displayer.show(other[n])
3689 displayer.show(other[n])
3673
3690
3674 recovernode = opts.get(b"recover")
3691 recovernode = opts.get(b"recover")
3675 if recovernode:
3692 if recovernode:
3676 if scmutil.isrevsymbol(repo, recovernode):
3693 if scmutil.isrevsymbol(repo, recovernode):
3677 ui.warn(_(b"%s already exists in the repo\n") % recovernode)
3694 ui.warn(_(b"%s already exists in the repo\n") % recovernode)
3678 return
3695 return
3679 elif backups:
3696 elif backups:
3680 msg = _(
3697 msg = _(
3681 b"Recover changesets using: hg debugbackupbundle --recover "
3698 b"Recover changesets using: hg debugbackupbundle --recover "
3682 b"<changeset hash>\n\nAvailable backup changesets:"
3699 b"<changeset hash>\n\nAvailable backup changesets:"
3683 )
3700 )
3684 ui.status(msg, label=b"status.removed")
3701 ui.status(msg, label=b"status.removed")
3685 else:
3702 else:
3686 ui.status(_(b"no backup changesets found\n"))
3703 ui.status(_(b"no backup changesets found\n"))
3687 return
3704 return
3688
3705
3689 for backup in backups:
3706 for backup in backups:
3690 # Much of this is copied from the hg incoming logic
3707 # Much of this is copied from the hg incoming logic
3691 source = ui.expandpath(os.path.relpath(backup, encoding.getcwd()))
3708 source = ui.expandpath(os.path.relpath(backup, encoding.getcwd()))
3692 source, branches = hg.parseurl(source, opts.get(b"branch"))
3709 source, branches = hg.parseurl(source, opts.get(b"branch"))
3693 try:
3710 try:
3694 other = hg.peer(repo, opts, source)
3711 other = hg.peer(repo, opts, source)
3695 except error.LookupError as ex:
3712 except error.LookupError as ex:
3696 msg = _(b"\nwarning: unable to open bundle %s") % source
3713 msg = _(b"\nwarning: unable to open bundle %s") % source
3697 hint = _(b"\n(missing parent rev %s)\n") % short(ex.name)
3714 hint = _(b"\n(missing parent rev %s)\n") % short(ex.name)
3698 ui.warn(msg, hint=hint)
3715 ui.warn(msg, hint=hint)
3699 continue
3716 continue
3700 revs, checkout = hg.addbranchrevs(
3717 revs, checkout = hg.addbranchrevs(
3701 repo, other, branches, opts.get(b"rev")
3718 repo, other, branches, opts.get(b"rev")
3702 )
3719 )
3703
3720
3704 if revs:
3721 if revs:
3705 revs = [other.lookup(rev) for rev in revs]
3722 revs = [other.lookup(rev) for rev in revs]
3706
3723
3707 quiet = ui.quiet
3724 quiet = ui.quiet
3708 try:
3725 try:
3709 ui.quiet = True
3726 ui.quiet = True
3710 other, chlist, cleanupfn = bundlerepo.getremotechanges(
3727 other, chlist, cleanupfn = bundlerepo.getremotechanges(
3711 ui, repo, other, revs, opts[b"bundle"], opts[b"force"]
3728 ui, repo, other, revs, opts[b"bundle"], opts[b"force"]
3712 )
3729 )
3713 except error.LookupError:
3730 except error.LookupError:
3714 continue
3731 continue
3715 finally:
3732 finally:
3716 ui.quiet = quiet
3733 ui.quiet = quiet
3717
3734
3718 try:
3735 try:
3719 if not chlist:
3736 if not chlist:
3720 continue
3737 continue
3721 if recovernode:
3738 if recovernode:
3722 with repo.lock(), repo.transaction(b"unbundle") as tr:
3739 with repo.lock(), repo.transaction(b"unbundle") as tr:
3723 if scmutil.isrevsymbol(other, recovernode):
3740 if scmutil.isrevsymbol(other, recovernode):
3724 ui.status(_(b"Unbundling %s\n") % (recovernode))
3741 ui.status(_(b"Unbundling %s\n") % (recovernode))
3725 f = hg.openpath(ui, source)
3742 f = hg.openpath(ui, source)
3726 gen = exchange.readbundle(ui, f, source)
3743 gen = exchange.readbundle(ui, f, source)
3727 if isinstance(gen, bundle2.unbundle20):
3744 if isinstance(gen, bundle2.unbundle20):
3728 bundle2.applybundle(
3745 bundle2.applybundle(
3729 repo,
3746 repo,
3730 gen,
3747 gen,
3731 tr,
3748 tr,
3732 source=b"unbundle",
3749 source=b"unbundle",
3733 url=b"bundle:" + source,
3750 url=b"bundle:" + source,
3734 )
3751 )
3735 else:
3752 else:
3736 gen.apply(repo, b"unbundle", b"bundle:" + source)
3753 gen.apply(repo, b"unbundle", b"bundle:" + source)
3737 break
3754 break
3738 else:
3755 else:
3739 backupdate = encoding.strtolocal(
3756 backupdate = encoding.strtolocal(
3740 time.strftime(
3757 time.strftime(
3741 "%a %H:%M, %Y-%m-%d",
3758 "%a %H:%M, %Y-%m-%d",
3742 time.localtime(os.path.getmtime(source)),
3759 time.localtime(os.path.getmtime(source)),
3743 )
3760 )
3744 )
3761 )
3745 ui.status(b"\n%s\n" % (backupdate.ljust(50)))
3762 ui.status(b"\n%s\n" % (backupdate.ljust(50)))
3746 if ui.verbose:
3763 if ui.verbose:
3747 ui.status(b"%s%s\n" % (b"bundle:".ljust(13), source))
3764 ui.status(b"%s%s\n" % (b"bundle:".ljust(13), source))
3748 else:
3765 else:
3749 opts[
3766 opts[
3750 b"template"
3767 b"template"
3751 ] = b"{label('status.modified', node|short)} {desc|firstline}\n"
3768 ] = b"{label('status.modified', node|short)} {desc|firstline}\n"
3752 displayer = logcmdutil.changesetdisplayer(
3769 displayer = logcmdutil.changesetdisplayer(
3753 ui, other, opts, False
3770 ui, other, opts, False
3754 )
3771 )
3755 display(other, chlist, displayer)
3772 display(other, chlist, displayer)
3756 displayer.close()
3773 displayer.close()
3757 finally:
3774 finally:
3758 cleanupfn()
3775 cleanupfn()
3759
3776
3760
3777
3761 @command(
3778 @command(
3762 b'debugsub',
3779 b'debugsub',
3763 [(b'r', b'rev', b'', _(b'revision to check'), _(b'REV'))],
3780 [(b'r', b'rev', b'', _(b'revision to check'), _(b'REV'))],
3764 _(b'[-r REV] [REV]'),
3781 _(b'[-r REV] [REV]'),
3765 )
3782 )
3766 def debugsub(ui, repo, rev=None):
3783 def debugsub(ui, repo, rev=None):
3767 ctx = scmutil.revsingle(repo, rev, None)
3784 ctx = scmutil.revsingle(repo, rev, None)
3768 for k, v in sorted(ctx.substate.items()):
3785 for k, v in sorted(ctx.substate.items()):
3769 ui.writenoi18n(b'path %s\n' % k)
3786 ui.writenoi18n(b'path %s\n' % k)
3770 ui.writenoi18n(b' source %s\n' % v[0])
3787 ui.writenoi18n(b' source %s\n' % v[0])
3771 ui.writenoi18n(b' revision %s\n' % v[1])
3788 ui.writenoi18n(b' revision %s\n' % v[1])
3772
3789
3773
3790
3774 @command(b'debugshell', optionalrepo=True)
3791 @command(b'debugshell', optionalrepo=True)
3775 def debugshell(ui, repo):
3792 def debugshell(ui, repo):
3776 """run an interactive Python interpreter
3793 """run an interactive Python interpreter
3777
3794
3778 The local namespace is provided with a reference to the ui and
3795 The local namespace is provided with a reference to the ui and
3779 the repo instance (if available).
3796 the repo instance (if available).
3780 """
3797 """
3781 import code
3798 import code
3782
3799
3783 imported_objects = {
3800 imported_objects = {
3784 'ui': ui,
3801 'ui': ui,
3785 'repo': repo,
3802 'repo': repo,
3786 }
3803 }
3787
3804
3788 code.interact(local=imported_objects)
3805 code.interact(local=imported_objects)
3789
3806
3790
3807
3791 @command(
3808 @command(
3792 b'debugsuccessorssets',
3809 b'debugsuccessorssets',
3793 [(b'', b'closest', False, _(b'return closest successors sets only'))],
3810 [(b'', b'closest', False, _(b'return closest successors sets only'))],
3794 _(b'[REV]'),
3811 _(b'[REV]'),
3795 )
3812 )
3796 def debugsuccessorssets(ui, repo, *revs, **opts):
3813 def debugsuccessorssets(ui, repo, *revs, **opts):
3797 """show set of successors for revision
3814 """show set of successors for revision
3798
3815
3799 A successors set of changeset A is a consistent group of revisions that
3816 A successors set of changeset A is a consistent group of revisions that
3800 succeed A. It contains non-obsolete changesets only unless closests
3817 succeed A. It contains non-obsolete changesets only unless closests
3801 successors set is set.
3818 successors set is set.
3802
3819
3803 In most cases a changeset A has a single successors set containing a single
3820 In most cases a changeset A has a single successors set containing a single
3804 successor (changeset A replaced by A').
3821 successor (changeset A replaced by A').
3805
3822
3806 A changeset that is made obsolete with no successors are called "pruned".
3823 A changeset that is made obsolete with no successors are called "pruned".
3807 Such changesets have no successors sets at all.
3824 Such changesets have no successors sets at all.
3808
3825
3809 A changeset that has been "split" will have a successors set containing
3826 A changeset that has been "split" will have a successors set containing
3810 more than one successor.
3827 more than one successor.
3811
3828
3812 A changeset that has been rewritten in multiple different ways is called
3829 A changeset that has been rewritten in multiple different ways is called
3813 "divergent". Such changesets have multiple successor sets (each of which
3830 "divergent". Such changesets have multiple successor sets (each of which
3814 may also be split, i.e. have multiple successors).
3831 may also be split, i.e. have multiple successors).
3815
3832
3816 Results are displayed as follows::
3833 Results are displayed as follows::
3817
3834
3818 <rev1>
3835 <rev1>
3819 <successors-1A>
3836 <successors-1A>
3820 <rev2>
3837 <rev2>
3821 <successors-2A>
3838 <successors-2A>
3822 <successors-2B1> <successors-2B2> <successors-2B3>
3839 <successors-2B1> <successors-2B2> <successors-2B3>
3823
3840
3824 Here rev2 has two possible (i.e. divergent) successors sets. The first
3841 Here rev2 has two possible (i.e. divergent) successors sets. The first
3825 holds one element, whereas the second holds three (i.e. the changeset has
3842 holds one element, whereas the second holds three (i.e. the changeset has
3826 been split).
3843 been split).
3827 """
3844 """
3828 # passed to successorssets caching computation from one call to another
3845 # passed to successorssets caching computation from one call to another
3829 cache = {}
3846 cache = {}
3830 ctx2str = bytes
3847 ctx2str = bytes
3831 node2str = short
3848 node2str = short
3832 for rev in scmutil.revrange(repo, revs):
3849 for rev in scmutil.revrange(repo, revs):
3833 ctx = repo[rev]
3850 ctx = repo[rev]
3834 ui.write(b'%s\n' % ctx2str(ctx))
3851 ui.write(b'%s\n' % ctx2str(ctx))
3835 for succsset in obsutil.successorssets(
3852 for succsset in obsutil.successorssets(
3836 repo, ctx.node(), closest=opts['closest'], cache=cache
3853 repo, ctx.node(), closest=opts['closest'], cache=cache
3837 ):
3854 ):
3838 if succsset:
3855 if succsset:
3839 ui.write(b' ')
3856 ui.write(b' ')
3840 ui.write(node2str(succsset[0]))
3857 ui.write(node2str(succsset[0]))
3841 for node in succsset[1:]:
3858 for node in succsset[1:]:
3842 ui.write(b' ')
3859 ui.write(b' ')
3843 ui.write(node2str(node))
3860 ui.write(node2str(node))
3844 ui.write(b'\n')
3861 ui.write(b'\n')
3845
3862
3846
3863
3847 @command(b'debugtagscache', [])
3864 @command(b'debugtagscache', [])
3848 def debugtagscache(ui, repo):
3865 def debugtagscache(ui, repo):
3849 """display the contents of .hg/cache/hgtagsfnodes1"""
3866 """display the contents of .hg/cache/hgtagsfnodes1"""
3850 cache = tagsmod.hgtagsfnodescache(repo.unfiltered())
3867 cache = tagsmod.hgtagsfnodescache(repo.unfiltered())
3851 for r in repo:
3868 for r in repo:
3852 node = repo[r].node()
3869 node = repo[r].node()
3853 tagsnode = cache.getfnode(node, computemissing=False)
3870 tagsnode = cache.getfnode(node, computemissing=False)
3854 tagsnodedisplay = hex(tagsnode) if tagsnode else b'missing/invalid'
3871 tagsnodedisplay = hex(tagsnode) if tagsnode else b'missing/invalid'
3855 ui.write(b'%d %s %s\n' % (r, hex(node), tagsnodedisplay))
3872 ui.write(b'%d %s %s\n' % (r, hex(node), tagsnodedisplay))
3856
3873
3857
3874
3858 @command(
3875 @command(
3859 b'debugtemplate',
3876 b'debugtemplate',
3860 [
3877 [
3861 (b'r', b'rev', [], _(b'apply template on changesets'), _(b'REV')),
3878 (b'r', b'rev', [], _(b'apply template on changesets'), _(b'REV')),
3862 (b'D', b'define', [], _(b'define template keyword'), _(b'KEY=VALUE')),
3879 (b'D', b'define', [], _(b'define template keyword'), _(b'KEY=VALUE')),
3863 ],
3880 ],
3864 _(b'[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3881 _(b'[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3865 optionalrepo=True,
3882 optionalrepo=True,
3866 )
3883 )
3867 def debugtemplate(ui, repo, tmpl, **opts):
3884 def debugtemplate(ui, repo, tmpl, **opts):
3868 """parse and apply a template
3885 """parse and apply a template
3869
3886
3870 If -r/--rev is given, the template is processed as a log template and
3887 If -r/--rev is given, the template is processed as a log template and
3871 applied to the given changesets. Otherwise, it is processed as a generic
3888 applied to the given changesets. Otherwise, it is processed as a generic
3872 template.
3889 template.
3873
3890
3874 Use --verbose to print the parsed tree.
3891 Use --verbose to print the parsed tree.
3875 """
3892 """
3876 revs = None
3893 revs = None
3877 if opts['rev']:
3894 if opts['rev']:
3878 if repo is None:
3895 if repo is None:
3879 raise error.RepoError(
3896 raise error.RepoError(
3880 _(b'there is no Mercurial repository here (.hg not found)')
3897 _(b'there is no Mercurial repository here (.hg not found)')
3881 )
3898 )
3882 revs = scmutil.revrange(repo, opts['rev'])
3899 revs = scmutil.revrange(repo, opts['rev'])
3883
3900
3884 props = {}
3901 props = {}
3885 for d in opts['define']:
3902 for d in opts['define']:
3886 try:
3903 try:
3887 k, v = (e.strip() for e in d.split(b'=', 1))
3904 k, v = (e.strip() for e in d.split(b'=', 1))
3888 if not k or k == b'ui':
3905 if not k or k == b'ui':
3889 raise ValueError
3906 raise ValueError
3890 props[k] = v
3907 props[k] = v
3891 except ValueError:
3908 except ValueError:
3892 raise error.Abort(_(b'malformed keyword definition: %s') % d)
3909 raise error.Abort(_(b'malformed keyword definition: %s') % d)
3893
3910
3894 if ui.verbose:
3911 if ui.verbose:
3895 aliases = ui.configitems(b'templatealias')
3912 aliases = ui.configitems(b'templatealias')
3896 tree = templater.parse(tmpl)
3913 tree = templater.parse(tmpl)
3897 ui.note(templater.prettyformat(tree), b'\n')
3914 ui.note(templater.prettyformat(tree), b'\n')
3898 newtree = templater.expandaliases(tree, aliases)
3915 newtree = templater.expandaliases(tree, aliases)
3899 if newtree != tree:
3916 if newtree != tree:
3900 ui.notenoi18n(
3917 ui.notenoi18n(
3901 b"* expanded:\n", templater.prettyformat(newtree), b'\n'
3918 b"* expanded:\n", templater.prettyformat(newtree), b'\n'
3902 )
3919 )
3903
3920
3904 if revs is None:
3921 if revs is None:
3905 tres = formatter.templateresources(ui, repo)
3922 tres = formatter.templateresources(ui, repo)
3906 t = formatter.maketemplater(ui, tmpl, resources=tres)
3923 t = formatter.maketemplater(ui, tmpl, resources=tres)
3907 if ui.verbose:
3924 if ui.verbose:
3908 kwds, funcs = t.symbolsuseddefault()
3925 kwds, funcs = t.symbolsuseddefault()
3909 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
3926 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
3910 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
3927 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
3911 ui.write(t.renderdefault(props))
3928 ui.write(t.renderdefault(props))
3912 else:
3929 else:
3913 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
3930 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
3914 if ui.verbose:
3931 if ui.verbose:
3915 kwds, funcs = displayer.t.symbolsuseddefault()
3932 kwds, funcs = displayer.t.symbolsuseddefault()
3916 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
3933 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
3917 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
3934 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
3918 for r in revs:
3935 for r in revs:
3919 displayer.show(repo[r], **pycompat.strkwargs(props))
3936 displayer.show(repo[r], **pycompat.strkwargs(props))
3920 displayer.close()
3937 displayer.close()
3921
3938
3922
3939
3923 @command(
3940 @command(
3924 b'debuguigetpass',
3941 b'debuguigetpass',
3925 [
3942 [
3926 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
3943 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
3927 ],
3944 ],
3928 _(b'[-p TEXT]'),
3945 _(b'[-p TEXT]'),
3929 norepo=True,
3946 norepo=True,
3930 )
3947 )
3931 def debuguigetpass(ui, prompt=b''):
3948 def debuguigetpass(ui, prompt=b''):
3932 """show prompt to type password"""
3949 """show prompt to type password"""
3933 r = ui.getpass(prompt)
3950 r = ui.getpass(prompt)
3934 if r is None:
3951 if r is None:
3935 r = b"<default response>"
3952 r = b"<default response>"
3936 ui.writenoi18n(b'response: %s\n' % r)
3953 ui.writenoi18n(b'response: %s\n' % r)
3937
3954
3938
3955
3939 @command(
3956 @command(
3940 b'debuguiprompt',
3957 b'debuguiprompt',
3941 [
3958 [
3942 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
3959 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
3943 ],
3960 ],
3944 _(b'[-p TEXT]'),
3961 _(b'[-p TEXT]'),
3945 norepo=True,
3962 norepo=True,
3946 )
3963 )
3947 def debuguiprompt(ui, prompt=b''):
3964 def debuguiprompt(ui, prompt=b''):
3948 """show plain prompt"""
3965 """show plain prompt"""
3949 r = ui.prompt(prompt)
3966 r = ui.prompt(prompt)
3950 ui.writenoi18n(b'response: %s\n' % r)
3967 ui.writenoi18n(b'response: %s\n' % r)
3951
3968
3952
3969
3953 @command(b'debugupdatecaches', [])
3970 @command(b'debugupdatecaches', [])
3954 def debugupdatecaches(ui, repo, *pats, **opts):
3971 def debugupdatecaches(ui, repo, *pats, **opts):
3955 """warm all known caches in the repository"""
3972 """warm all known caches in the repository"""
3956 with repo.wlock(), repo.lock():
3973 with repo.wlock(), repo.lock():
3957 repo.updatecaches(full=True)
3974 repo.updatecaches(full=True)
3958
3975
3959
3976
3960 @command(
3977 @command(
3961 b'debugupgraderepo',
3978 b'debugupgraderepo',
3962 [
3979 [
3963 (
3980 (
3964 b'o',
3981 b'o',
3965 b'optimize',
3982 b'optimize',
3966 [],
3983 [],
3967 _(b'extra optimization to perform'),
3984 _(b'extra optimization to perform'),
3968 _(b'NAME'),
3985 _(b'NAME'),
3969 ),
3986 ),
3970 (b'', b'run', False, _(b'performs an upgrade')),
3987 (b'', b'run', False, _(b'performs an upgrade')),
3971 (b'', b'backup', True, _(b'keep the old repository content around')),
3988 (b'', b'backup', True, _(b'keep the old repository content around')),
3972 (b'', b'changelog', None, _(b'select the changelog for upgrade')),
3989 (b'', b'changelog', None, _(b'select the changelog for upgrade')),
3973 (b'', b'manifest', None, _(b'select the manifest for upgrade')),
3990 (b'', b'manifest', None, _(b'select the manifest for upgrade')),
3974 (b'', b'filelogs', None, _(b'select all filelogs for upgrade')),
3991 (b'', b'filelogs', None, _(b'select all filelogs for upgrade')),
3975 ],
3992 ],
3976 )
3993 )
3977 def debugupgraderepo(ui, repo, run=False, optimize=None, backup=True, **opts):
3994 def debugupgraderepo(ui, repo, run=False, optimize=None, backup=True, **opts):
3978 """upgrade a repository to use different features
3995 """upgrade a repository to use different features
3979
3996
3980 If no arguments are specified, the repository is evaluated for upgrade
3997 If no arguments are specified, the repository is evaluated for upgrade
3981 and a list of problems and potential optimizations is printed.
3998 and a list of problems and potential optimizations is printed.
3982
3999
3983 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
4000 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
3984 can be influenced via additional arguments. More details will be provided
4001 can be influenced via additional arguments. More details will be provided
3985 by the command output when run without ``--run``.
4002 by the command output when run without ``--run``.
3986
4003
3987 During the upgrade, the repository will be locked and no writes will be
4004 During the upgrade, the repository will be locked and no writes will be
3988 allowed.
4005 allowed.
3989
4006
3990 At the end of the upgrade, the repository may not be readable while new
4007 At the end of the upgrade, the repository may not be readable while new
3991 repository data is swapped in. This window will be as long as it takes to
4008 repository data is swapped in. This window will be as long as it takes to
3992 rename some directories inside the ``.hg`` directory. On most machines, this
4009 rename some directories inside the ``.hg`` directory. On most machines, this
3993 should complete almost instantaneously and the chances of a consumer being
4010 should complete almost instantaneously and the chances of a consumer being
3994 unable to access the repository should be low.
4011 unable to access the repository should be low.
3995
4012
3996 By default, all revlog will be upgraded. You can restrict this using flag
4013 By default, all revlog will be upgraded. You can restrict this using flag
3997 such as `--manifest`:
4014 such as `--manifest`:
3998
4015
3999 * `--manifest`: only optimize the manifest
4016 * `--manifest`: only optimize the manifest
4000 * `--no-manifest`: optimize all revlog but the manifest
4017 * `--no-manifest`: optimize all revlog but the manifest
4001 * `--changelog`: optimize the changelog only
4018 * `--changelog`: optimize the changelog only
4002 * `--no-changelog --no-manifest`: optimize filelogs only
4019 * `--no-changelog --no-manifest`: optimize filelogs only
4003 * `--filelogs`: optimize the filelogs only
4020 * `--filelogs`: optimize the filelogs only
4004 * `--no-changelog --no-manifest --no-filelogs`: skip all revlog optimizations
4021 * `--no-changelog --no-manifest --no-filelogs`: skip all revlog optimizations
4005 """
4022 """
4006 return upgrade.upgraderepo(
4023 return upgrade.upgraderepo(
4007 ui, repo, run=run, optimize=set(optimize), backup=backup, **opts
4024 ui, repo, run=run, optimize=set(optimize), backup=backup, **opts
4008 )
4025 )
4009
4026
4010
4027
4011 @command(
4028 @command(
4012 b'debugwalk', cmdutil.walkopts, _(b'[OPTION]... [FILE]...'), inferrepo=True
4029 b'debugwalk', cmdutil.walkopts, _(b'[OPTION]... [FILE]...'), inferrepo=True
4013 )
4030 )
4014 def debugwalk(ui, repo, *pats, **opts):
4031 def debugwalk(ui, repo, *pats, **opts):
4015 """show how files match on given patterns"""
4032 """show how files match on given patterns"""
4016 opts = pycompat.byteskwargs(opts)
4033 opts = pycompat.byteskwargs(opts)
4017 m = scmutil.match(repo[None], pats, opts)
4034 m = scmutil.match(repo[None], pats, opts)
4018 if ui.verbose:
4035 if ui.verbose:
4019 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
4036 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
4020 items = list(repo[None].walk(m))
4037 items = list(repo[None].walk(m))
4021 if not items:
4038 if not items:
4022 return
4039 return
4023 f = lambda fn: fn
4040 f = lambda fn: fn
4024 if ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/':
4041 if ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/':
4025 f = lambda fn: util.normpath(fn)
4042 f = lambda fn: util.normpath(fn)
4026 fmt = b'f %%-%ds %%-%ds %%s' % (
4043 fmt = b'f %%-%ds %%-%ds %%s' % (
4027 max([len(abs) for abs in items]),
4044 max([len(abs) for abs in items]),
4028 max([len(repo.pathto(abs)) for abs in items]),
4045 max([len(repo.pathto(abs)) for abs in items]),
4029 )
4046 )
4030 for abs in items:
4047 for abs in items:
4031 line = fmt % (
4048 line = fmt % (
4032 abs,
4049 abs,
4033 f(repo.pathto(abs)),
4050 f(repo.pathto(abs)),
4034 m.exact(abs) and b'exact' or b'',
4051 m.exact(abs) and b'exact' or b'',
4035 )
4052 )
4036 ui.write(b"%s\n" % line.rstrip())
4053 ui.write(b"%s\n" % line.rstrip())
4037
4054
4038
4055
4039 @command(b'debugwhyunstable', [], _(b'REV'))
4056 @command(b'debugwhyunstable', [], _(b'REV'))
4040 def debugwhyunstable(ui, repo, rev):
4057 def debugwhyunstable(ui, repo, rev):
4041 """explain instabilities of a changeset"""
4058 """explain instabilities of a changeset"""
4042 for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
4059 for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
4043 dnodes = b''
4060 dnodes = b''
4044 if entry.get(b'divergentnodes'):
4061 if entry.get(b'divergentnodes'):
4045 dnodes = (
4062 dnodes = (
4046 b' '.join(
4063 b' '.join(
4047 b'%s (%s)' % (ctx.hex(), ctx.phasestr())
4064 b'%s (%s)' % (ctx.hex(), ctx.phasestr())
4048 for ctx in entry[b'divergentnodes']
4065 for ctx in entry[b'divergentnodes']
4049 )
4066 )
4050 + b' '
4067 + b' '
4051 )
4068 )
4052 ui.write(
4069 ui.write(
4053 b'%s: %s%s %s\n'
4070 b'%s: %s%s %s\n'
4054 % (entry[b'instability'], dnodes, entry[b'reason'], entry[b'node'])
4071 % (entry[b'instability'], dnodes, entry[b'reason'], entry[b'node'])
4055 )
4072 )
4056
4073
4057
4074
4058 @command(
4075 @command(
4059 b'debugwireargs',
4076 b'debugwireargs',
4060 [
4077 [
4061 (b'', b'three', b'', b'three'),
4078 (b'', b'three', b'', b'three'),
4062 (b'', b'four', b'', b'four'),
4079 (b'', b'four', b'', b'four'),
4063 (b'', b'five', b'', b'five'),
4080 (b'', b'five', b'', b'five'),
4064 ]
4081 ]
4065 + cmdutil.remoteopts,
4082 + cmdutil.remoteopts,
4066 _(b'REPO [OPTIONS]... [ONE [TWO]]'),
4083 _(b'REPO [OPTIONS]... [ONE [TWO]]'),
4067 norepo=True,
4084 norepo=True,
4068 )
4085 )
4069 def debugwireargs(ui, repopath, *vals, **opts):
4086 def debugwireargs(ui, repopath, *vals, **opts):
4070 opts = pycompat.byteskwargs(opts)
4087 opts = pycompat.byteskwargs(opts)
4071 repo = hg.peer(ui, opts, repopath)
4088 repo = hg.peer(ui, opts, repopath)
4072 for opt in cmdutil.remoteopts:
4089 for opt in cmdutil.remoteopts:
4073 del opts[opt[1]]
4090 del opts[opt[1]]
4074 args = {}
4091 args = {}
4075 for k, v in pycompat.iteritems(opts):
4092 for k, v in pycompat.iteritems(opts):
4076 if v:
4093 if v:
4077 args[k] = v
4094 args[k] = v
4078 args = pycompat.strkwargs(args)
4095 args = pycompat.strkwargs(args)
4079 # run twice to check that we don't mess up the stream for the next command
4096 # run twice to check that we don't mess up the stream for the next command
4080 res1 = repo.debugwireargs(*vals, **args)
4097 res1 = repo.debugwireargs(*vals, **args)
4081 res2 = repo.debugwireargs(*vals, **args)
4098 res2 = repo.debugwireargs(*vals, **args)
4082 ui.write(b"%s\n" % res1)
4099 ui.write(b"%s\n" % res1)
4083 if res1 != res2:
4100 if res1 != res2:
4084 ui.warn(b"%s\n" % res2)
4101 ui.warn(b"%s\n" % res2)
4085
4102
4086
4103
4087 def _parsewirelangblocks(fh):
4104 def _parsewirelangblocks(fh):
4088 activeaction = None
4105 activeaction = None
4089 blocklines = []
4106 blocklines = []
4090 lastindent = 0
4107 lastindent = 0
4091
4108
4092 for line in fh:
4109 for line in fh:
4093 line = line.rstrip()
4110 line = line.rstrip()
4094 if not line:
4111 if not line:
4095 continue
4112 continue
4096
4113
4097 if line.startswith(b'#'):
4114 if line.startswith(b'#'):
4098 continue
4115 continue
4099
4116
4100 if not line.startswith(b' '):
4117 if not line.startswith(b' '):
4101 # New block. Flush previous one.
4118 # New block. Flush previous one.
4102 if activeaction:
4119 if activeaction:
4103 yield activeaction, blocklines
4120 yield activeaction, blocklines
4104
4121
4105 activeaction = line
4122 activeaction = line
4106 blocklines = []
4123 blocklines = []
4107 lastindent = 0
4124 lastindent = 0
4108 continue
4125 continue
4109
4126
4110 # Else we start with an indent.
4127 # Else we start with an indent.
4111
4128
4112 if not activeaction:
4129 if not activeaction:
4113 raise error.Abort(_(b'indented line outside of block'))
4130 raise error.Abort(_(b'indented line outside of block'))
4114
4131
4115 indent = len(line) - len(line.lstrip())
4132 indent = len(line) - len(line.lstrip())
4116
4133
4117 # If this line is indented more than the last line, concatenate it.
4134 # If this line is indented more than the last line, concatenate it.
4118 if indent > lastindent and blocklines:
4135 if indent > lastindent and blocklines:
4119 blocklines[-1] += line.lstrip()
4136 blocklines[-1] += line.lstrip()
4120 else:
4137 else:
4121 blocklines.append(line)
4138 blocklines.append(line)
4122 lastindent = indent
4139 lastindent = indent
4123
4140
4124 # Flush last block.
4141 # Flush last block.
4125 if activeaction:
4142 if activeaction:
4126 yield activeaction, blocklines
4143 yield activeaction, blocklines
4127
4144
4128
4145
4129 @command(
4146 @command(
4130 b'debugwireproto',
4147 b'debugwireproto',
4131 [
4148 [
4132 (b'', b'localssh', False, _(b'start an SSH server for this repo')),
4149 (b'', b'localssh', False, _(b'start an SSH server for this repo')),
4133 (b'', b'peer', b'', _(b'construct a specific version of the peer')),
4150 (b'', b'peer', b'', _(b'construct a specific version of the peer')),
4134 (
4151 (
4135 b'',
4152 b'',
4136 b'noreadstderr',
4153 b'noreadstderr',
4137 False,
4154 False,
4138 _(b'do not read from stderr of the remote'),
4155 _(b'do not read from stderr of the remote'),
4139 ),
4156 ),
4140 (
4157 (
4141 b'',
4158 b'',
4142 b'nologhandshake',
4159 b'nologhandshake',
4143 False,
4160 False,
4144 _(b'do not log I/O related to the peer handshake'),
4161 _(b'do not log I/O related to the peer handshake'),
4145 ),
4162 ),
4146 ]
4163 ]
4147 + cmdutil.remoteopts,
4164 + cmdutil.remoteopts,
4148 _(b'[PATH]'),
4165 _(b'[PATH]'),
4149 optionalrepo=True,
4166 optionalrepo=True,
4150 )
4167 )
4151 def debugwireproto(ui, repo, path=None, **opts):
4168 def debugwireproto(ui, repo, path=None, **opts):
4152 """send wire protocol commands to a server
4169 """send wire protocol commands to a server
4153
4170
4154 This command can be used to issue wire protocol commands to remote
4171 This command can be used to issue wire protocol commands to remote
4155 peers and to debug the raw data being exchanged.
4172 peers and to debug the raw data being exchanged.
4156
4173
4157 ``--localssh`` will start an SSH server against the current repository
4174 ``--localssh`` will start an SSH server against the current repository
4158 and connect to that. By default, the connection will perform a handshake
4175 and connect to that. By default, the connection will perform a handshake
4159 and establish an appropriate peer instance.
4176 and establish an appropriate peer instance.
4160
4177
4161 ``--peer`` can be used to bypass the handshake protocol and construct a
4178 ``--peer`` can be used to bypass the handshake protocol and construct a
4162 peer instance using the specified class type. Valid values are ``raw``,
4179 peer instance using the specified class type. Valid values are ``raw``,
4163 ``http2``, ``ssh1``, and ``ssh2``. ``raw`` instances only allow sending
4180 ``http2``, ``ssh1``, and ``ssh2``. ``raw`` instances only allow sending
4164 raw data payloads and don't support higher-level command actions.
4181 raw data payloads and don't support higher-level command actions.
4165
4182
4166 ``--noreadstderr`` can be used to disable automatic reading from stderr
4183 ``--noreadstderr`` can be used to disable automatic reading from stderr
4167 of the peer (for SSH connections only). Disabling automatic reading of
4184 of the peer (for SSH connections only). Disabling automatic reading of
4168 stderr is useful for making output more deterministic.
4185 stderr is useful for making output more deterministic.
4169
4186
4170 Commands are issued via a mini language which is specified via stdin.
4187 Commands are issued via a mini language which is specified via stdin.
4171 The language consists of individual actions to perform. An action is
4188 The language consists of individual actions to perform. An action is
4172 defined by a block. A block is defined as a line with no leading
4189 defined by a block. A block is defined as a line with no leading
4173 space followed by 0 or more lines with leading space. Blocks are
4190 space followed by 0 or more lines with leading space. Blocks are
4174 effectively a high-level command with additional metadata.
4191 effectively a high-level command with additional metadata.
4175
4192
4176 Lines beginning with ``#`` are ignored.
4193 Lines beginning with ``#`` are ignored.
4177
4194
4178 The following sections denote available actions.
4195 The following sections denote available actions.
4179
4196
4180 raw
4197 raw
4181 ---
4198 ---
4182
4199
4183 Send raw data to the server.
4200 Send raw data to the server.
4184
4201
4185 The block payload contains the raw data to send as one atomic send
4202 The block payload contains the raw data to send as one atomic send
4186 operation. The data may not actually be delivered in a single system
4203 operation. The data may not actually be delivered in a single system
4187 call: it depends on the abilities of the transport being used.
4204 call: it depends on the abilities of the transport being used.
4188
4205
4189 Each line in the block is de-indented and concatenated. Then, that
4206 Each line in the block is de-indented and concatenated. Then, that
4190 value is evaluated as a Python b'' literal. This allows the use of
4207 value is evaluated as a Python b'' literal. This allows the use of
4191 backslash escaping, etc.
4208 backslash escaping, etc.
4192
4209
4193 raw+
4210 raw+
4194 ----
4211 ----
4195
4212
4196 Behaves like ``raw`` except flushes output afterwards.
4213 Behaves like ``raw`` except flushes output afterwards.
4197
4214
4198 command <X>
4215 command <X>
4199 -----------
4216 -----------
4200
4217
4201 Send a request to run a named command, whose name follows the ``command``
4218 Send a request to run a named command, whose name follows the ``command``
4202 string.
4219 string.
4203
4220
4204 Arguments to the command are defined as lines in this block. The format of
4221 Arguments to the command are defined as lines in this block. The format of
4205 each line is ``<key> <value>``. e.g.::
4222 each line is ``<key> <value>``. e.g.::
4206
4223
4207 command listkeys
4224 command listkeys
4208 namespace bookmarks
4225 namespace bookmarks
4209
4226
4210 If the value begins with ``eval:``, it will be interpreted as a Python
4227 If the value begins with ``eval:``, it will be interpreted as a Python
4211 literal expression. Otherwise values are interpreted as Python b'' literals.
4228 literal expression. Otherwise values are interpreted as Python b'' literals.
4212 This allows sending complex types and encoding special byte sequences via
4229 This allows sending complex types and encoding special byte sequences via
4213 backslash escaping.
4230 backslash escaping.
4214
4231
4215 The following arguments have special meaning:
4232 The following arguments have special meaning:
4216
4233
4217 ``PUSHFILE``
4234 ``PUSHFILE``
4218 When defined, the *push* mechanism of the peer will be used instead
4235 When defined, the *push* mechanism of the peer will be used instead
4219 of the static request-response mechanism and the content of the
4236 of the static request-response mechanism and the content of the
4220 file specified in the value of this argument will be sent as the
4237 file specified in the value of this argument will be sent as the
4221 command payload.
4238 command payload.
4222
4239
4223 This can be used to submit a local bundle file to the remote.
4240 This can be used to submit a local bundle file to the remote.
4224
4241
4225 batchbegin
4242 batchbegin
4226 ----------
4243 ----------
4227
4244
4228 Instruct the peer to begin a batched send.
4245 Instruct the peer to begin a batched send.
4229
4246
4230 All ``command`` blocks are queued for execution until the next
4247 All ``command`` blocks are queued for execution until the next
4231 ``batchsubmit`` block.
4248 ``batchsubmit`` block.
4232
4249
4233 batchsubmit
4250 batchsubmit
4234 -----------
4251 -----------
4235
4252
4236 Submit previously queued ``command`` blocks as a batch request.
4253 Submit previously queued ``command`` blocks as a batch request.
4237
4254
4238 This action MUST be paired with a ``batchbegin`` action.
4255 This action MUST be paired with a ``batchbegin`` action.
4239
4256
4240 httprequest <method> <path>
4257 httprequest <method> <path>
4241 ---------------------------
4258 ---------------------------
4242
4259
4243 (HTTP peer only)
4260 (HTTP peer only)
4244
4261
4245 Send an HTTP request to the peer.
4262 Send an HTTP request to the peer.
4246
4263
4247 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
4264 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
4248
4265
4249 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
4266 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
4250 headers to add to the request. e.g. ``Accept: foo``.
4267 headers to add to the request. e.g. ``Accept: foo``.
4251
4268
4252 The following arguments are special:
4269 The following arguments are special:
4253
4270
4254 ``BODYFILE``
4271 ``BODYFILE``
4255 The content of the file defined as the value to this argument will be
4272 The content of the file defined as the value to this argument will be
4256 transferred verbatim as the HTTP request body.
4273 transferred verbatim as the HTTP request body.
4257
4274
4258 ``frame <type> <flags> <payload>``
4275 ``frame <type> <flags> <payload>``
4259 Send a unified protocol frame as part of the request body.
4276 Send a unified protocol frame as part of the request body.
4260
4277
4261 All frames will be collected and sent as the body to the HTTP
4278 All frames will be collected and sent as the body to the HTTP
4262 request.
4279 request.
4263
4280
4264 close
4281 close
4265 -----
4282 -----
4266
4283
4267 Close the connection to the server.
4284 Close the connection to the server.
4268
4285
4269 flush
4286 flush
4270 -----
4287 -----
4271
4288
4272 Flush data written to the server.
4289 Flush data written to the server.
4273
4290
4274 readavailable
4291 readavailable
4275 -------------
4292 -------------
4276
4293
4277 Close the write end of the connection and read all available data from
4294 Close the write end of the connection and read all available data from
4278 the server.
4295 the server.
4279
4296
4280 If the connection to the server encompasses multiple pipes, we poll both
4297 If the connection to the server encompasses multiple pipes, we poll both
4281 pipes and read available data.
4298 pipes and read available data.
4282
4299
4283 readline
4300 readline
4284 --------
4301 --------
4285
4302
4286 Read a line of output from the server. If there are multiple output
4303 Read a line of output from the server. If there are multiple output
4287 pipes, reads only the main pipe.
4304 pipes, reads only the main pipe.
4288
4305
4289 ereadline
4306 ereadline
4290 ---------
4307 ---------
4291
4308
4292 Like ``readline``, but read from the stderr pipe, if available.
4309 Like ``readline``, but read from the stderr pipe, if available.
4293
4310
4294 read <X>
4311 read <X>
4295 --------
4312 --------
4296
4313
4297 ``read()`` N bytes from the server's main output pipe.
4314 ``read()`` N bytes from the server's main output pipe.
4298
4315
4299 eread <X>
4316 eread <X>
4300 ---------
4317 ---------
4301
4318
4302 ``read()`` N bytes from the server's stderr pipe, if available.
4319 ``read()`` N bytes from the server's stderr pipe, if available.
4303
4320
4304 Specifying Unified Frame-Based Protocol Frames
4321 Specifying Unified Frame-Based Protocol Frames
4305 ----------------------------------------------
4322 ----------------------------------------------
4306
4323
4307 It is possible to emit a *Unified Frame-Based Protocol* by using special
4324 It is possible to emit a *Unified Frame-Based Protocol* by using special
4308 syntax.
4325 syntax.
4309
4326
4310 A frame is composed as a type, flags, and payload. These can be parsed
4327 A frame is composed as a type, flags, and payload. These can be parsed
4311 from a string of the form:
4328 from a string of the form:
4312
4329
4313 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
4330 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
4314
4331
4315 ``request-id`` and ``stream-id`` are integers defining the request and
4332 ``request-id`` and ``stream-id`` are integers defining the request and
4316 stream identifiers.
4333 stream identifiers.
4317
4334
4318 ``type`` can be an integer value for the frame type or the string name
4335 ``type`` can be an integer value for the frame type or the string name
4319 of the type. The strings are defined in ``wireprotoframing.py``. e.g.
4336 of the type. The strings are defined in ``wireprotoframing.py``. e.g.
4320 ``command-name``.
4337 ``command-name``.
4321
4338
4322 ``stream-flags`` and ``flags`` are a ``|`` delimited list of flag
4339 ``stream-flags`` and ``flags`` are a ``|`` delimited list of flag
4323 components. Each component (and there can be just one) can be an integer
4340 components. Each component (and there can be just one) can be an integer
4324 or a flag name for stream flags or frame flags, respectively. Values are
4341 or a flag name for stream flags or frame flags, respectively. Values are
4325 resolved to integers and then bitwise OR'd together.
4342 resolved to integers and then bitwise OR'd together.
4326
4343
4327 ``payload`` represents the raw frame payload. If it begins with
4344 ``payload`` represents the raw frame payload. If it begins with
4328 ``cbor:``, the following string is evaluated as Python code and the
4345 ``cbor:``, the following string is evaluated as Python code and the
4329 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
4346 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
4330 as a Python byte string literal.
4347 as a Python byte string literal.
4331 """
4348 """
4332 opts = pycompat.byteskwargs(opts)
4349 opts = pycompat.byteskwargs(opts)
4333
4350
4334 if opts[b'localssh'] and not repo:
4351 if opts[b'localssh'] and not repo:
4335 raise error.Abort(_(b'--localssh requires a repository'))
4352 raise error.Abort(_(b'--localssh requires a repository'))
4336
4353
4337 if opts[b'peer'] and opts[b'peer'] not in (
4354 if opts[b'peer'] and opts[b'peer'] not in (
4338 b'raw',
4355 b'raw',
4339 b'http2',
4356 b'http2',
4340 b'ssh1',
4357 b'ssh1',
4341 b'ssh2',
4358 b'ssh2',
4342 ):
4359 ):
4343 raise error.Abort(
4360 raise error.Abort(
4344 _(b'invalid value for --peer'),
4361 _(b'invalid value for --peer'),
4345 hint=_(b'valid values are "raw", "ssh1", and "ssh2"'),
4362 hint=_(b'valid values are "raw", "ssh1", and "ssh2"'),
4346 )
4363 )
4347
4364
4348 if path and opts[b'localssh']:
4365 if path and opts[b'localssh']:
4349 raise error.Abort(_(b'cannot specify --localssh with an explicit path'))
4366 raise error.Abort(_(b'cannot specify --localssh with an explicit path'))
4350
4367
4351 if ui.interactive():
4368 if ui.interactive():
4352 ui.write(_(b'(waiting for commands on stdin)\n'))
4369 ui.write(_(b'(waiting for commands on stdin)\n'))
4353
4370
4354 blocks = list(_parsewirelangblocks(ui.fin))
4371 blocks = list(_parsewirelangblocks(ui.fin))
4355
4372
4356 proc = None
4373 proc = None
4357 stdin = None
4374 stdin = None
4358 stdout = None
4375 stdout = None
4359 stderr = None
4376 stderr = None
4360 opener = None
4377 opener = None
4361
4378
4362 if opts[b'localssh']:
4379 if opts[b'localssh']:
4363 # We start the SSH server in its own process so there is process
4380 # We start the SSH server in its own process so there is process
4364 # separation. This prevents a whole class of potential bugs around
4381 # separation. This prevents a whole class of potential bugs around
4365 # shared state from interfering with server operation.
4382 # shared state from interfering with server operation.
4366 args = procutil.hgcmd() + [
4383 args = procutil.hgcmd() + [
4367 b'-R',
4384 b'-R',
4368 repo.root,
4385 repo.root,
4369 b'debugserve',
4386 b'debugserve',
4370 b'--sshstdio',
4387 b'--sshstdio',
4371 ]
4388 ]
4372 proc = subprocess.Popen(
4389 proc = subprocess.Popen(
4373 pycompat.rapply(procutil.tonativestr, args),
4390 pycompat.rapply(procutil.tonativestr, args),
4374 stdin=subprocess.PIPE,
4391 stdin=subprocess.PIPE,
4375 stdout=subprocess.PIPE,
4392 stdout=subprocess.PIPE,
4376 stderr=subprocess.PIPE,
4393 stderr=subprocess.PIPE,
4377 bufsize=0,
4394 bufsize=0,
4378 )
4395 )
4379
4396
4380 stdin = proc.stdin
4397 stdin = proc.stdin
4381 stdout = proc.stdout
4398 stdout = proc.stdout
4382 stderr = proc.stderr
4399 stderr = proc.stderr
4383
4400
4384 # We turn the pipes into observers so we can log I/O.
4401 # We turn the pipes into observers so we can log I/O.
4385 if ui.verbose or opts[b'peer'] == b'raw':
4402 if ui.verbose or opts[b'peer'] == b'raw':
4386 stdin = util.makeloggingfileobject(
4403 stdin = util.makeloggingfileobject(
4387 ui, proc.stdin, b'i', logdata=True
4404 ui, proc.stdin, b'i', logdata=True
4388 )
4405 )
4389 stdout = util.makeloggingfileobject(
4406 stdout = util.makeloggingfileobject(
4390 ui, proc.stdout, b'o', logdata=True
4407 ui, proc.stdout, b'o', logdata=True
4391 )
4408 )
4392 stderr = util.makeloggingfileobject(
4409 stderr = util.makeloggingfileobject(
4393 ui, proc.stderr, b'e', logdata=True
4410 ui, proc.stderr, b'e', logdata=True
4394 )
4411 )
4395
4412
4396 # --localssh also implies the peer connection settings.
4413 # --localssh also implies the peer connection settings.
4397
4414
4398 url = b'ssh://localserver'
4415 url = b'ssh://localserver'
4399 autoreadstderr = not opts[b'noreadstderr']
4416 autoreadstderr = not opts[b'noreadstderr']
4400
4417
4401 if opts[b'peer'] == b'ssh1':
4418 if opts[b'peer'] == b'ssh1':
4402 ui.write(_(b'creating ssh peer for wire protocol version 1\n'))
4419 ui.write(_(b'creating ssh peer for wire protocol version 1\n'))
4403 peer = sshpeer.sshv1peer(
4420 peer = sshpeer.sshv1peer(
4404 ui,
4421 ui,
4405 url,
4422 url,
4406 proc,
4423 proc,
4407 stdin,
4424 stdin,
4408 stdout,
4425 stdout,
4409 stderr,
4426 stderr,
4410 None,
4427 None,
4411 autoreadstderr=autoreadstderr,
4428 autoreadstderr=autoreadstderr,
4412 )
4429 )
4413 elif opts[b'peer'] == b'ssh2':
4430 elif opts[b'peer'] == b'ssh2':
4414 ui.write(_(b'creating ssh peer for wire protocol version 2\n'))
4431 ui.write(_(b'creating ssh peer for wire protocol version 2\n'))
4415 peer = sshpeer.sshv2peer(
4432 peer = sshpeer.sshv2peer(
4416 ui,
4433 ui,
4417 url,
4434 url,
4418 proc,
4435 proc,
4419 stdin,
4436 stdin,
4420 stdout,
4437 stdout,
4421 stderr,
4438 stderr,
4422 None,
4439 None,
4423 autoreadstderr=autoreadstderr,
4440 autoreadstderr=autoreadstderr,
4424 )
4441 )
4425 elif opts[b'peer'] == b'raw':
4442 elif opts[b'peer'] == b'raw':
4426 ui.write(_(b'using raw connection to peer\n'))
4443 ui.write(_(b'using raw connection to peer\n'))
4427 peer = None
4444 peer = None
4428 else:
4445 else:
4429 ui.write(_(b'creating ssh peer from handshake results\n'))
4446 ui.write(_(b'creating ssh peer from handshake results\n'))
4430 peer = sshpeer.makepeer(
4447 peer = sshpeer.makepeer(
4431 ui,
4448 ui,
4432 url,
4449 url,
4433 proc,
4450 proc,
4434 stdin,
4451 stdin,
4435 stdout,
4452 stdout,
4436 stderr,
4453 stderr,
4437 autoreadstderr=autoreadstderr,
4454 autoreadstderr=autoreadstderr,
4438 )
4455 )
4439
4456
4440 elif path:
4457 elif path:
4441 # We bypass hg.peer() so we can proxy the sockets.
4458 # We bypass hg.peer() so we can proxy the sockets.
4442 # TODO consider not doing this because we skip
4459 # TODO consider not doing this because we skip
4443 # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
4460 # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
4444 u = util.url(path)
4461 u = util.url(path)
4445 if u.scheme != b'http':
4462 if u.scheme != b'http':
4446 raise error.Abort(_(b'only http:// paths are currently supported'))
4463 raise error.Abort(_(b'only http:// paths are currently supported'))
4447
4464
4448 url, authinfo = u.authinfo()
4465 url, authinfo = u.authinfo()
4449 openerargs = {
4466 openerargs = {
4450 'useragent': b'Mercurial debugwireproto',
4467 'useragent': b'Mercurial debugwireproto',
4451 }
4468 }
4452
4469
4453 # Turn pipes/sockets into observers so we can log I/O.
4470 # Turn pipes/sockets into observers so we can log I/O.
4454 if ui.verbose:
4471 if ui.verbose:
4455 openerargs.update(
4472 openerargs.update(
4456 {
4473 {
4457 'loggingfh': ui,
4474 'loggingfh': ui,
4458 'loggingname': b's',
4475 'loggingname': b's',
4459 'loggingopts': {
4476 'loggingopts': {
4460 'logdata': True,
4477 'logdata': True,
4461 'logdataapis': False,
4478 'logdataapis': False,
4462 },
4479 },
4463 }
4480 }
4464 )
4481 )
4465
4482
4466 if ui.debugflag:
4483 if ui.debugflag:
4467 openerargs['loggingopts']['logdataapis'] = True
4484 openerargs['loggingopts']['logdataapis'] = True
4468
4485
4469 # Don't send default headers when in raw mode. This allows us to
4486 # Don't send default headers when in raw mode. This allows us to
4470 # bypass most of the behavior of our URL handling code so we can
4487 # bypass most of the behavior of our URL handling code so we can
4471 # have near complete control over what's sent on the wire.
4488 # have near complete control over what's sent on the wire.
4472 if opts[b'peer'] == b'raw':
4489 if opts[b'peer'] == b'raw':
4473 openerargs['sendaccept'] = False
4490 openerargs['sendaccept'] = False
4474
4491
4475 opener = urlmod.opener(ui, authinfo, **openerargs)
4492 opener = urlmod.opener(ui, authinfo, **openerargs)
4476
4493
4477 if opts[b'peer'] == b'http2':
4494 if opts[b'peer'] == b'http2':
4478 ui.write(_(b'creating http peer for wire protocol version 2\n'))
4495 ui.write(_(b'creating http peer for wire protocol version 2\n'))
4479 # We go through makepeer() because we need an API descriptor for
4496 # We go through makepeer() because we need an API descriptor for
4480 # the peer instance to be useful.
4497 # the peer instance to be useful.
4481 with ui.configoverride(
4498 with ui.configoverride(
4482 {(b'experimental', b'httppeer.advertise-v2'): True}
4499 {(b'experimental', b'httppeer.advertise-v2'): True}
4483 ):
4500 ):
4484 if opts[b'nologhandshake']:
4501 if opts[b'nologhandshake']:
4485 ui.pushbuffer()
4502 ui.pushbuffer()
4486
4503
4487 peer = httppeer.makepeer(ui, path, opener=opener)
4504 peer = httppeer.makepeer(ui, path, opener=opener)
4488
4505
4489 if opts[b'nologhandshake']:
4506 if opts[b'nologhandshake']:
4490 ui.popbuffer()
4507 ui.popbuffer()
4491
4508
4492 if not isinstance(peer, httppeer.httpv2peer):
4509 if not isinstance(peer, httppeer.httpv2peer):
4493 raise error.Abort(
4510 raise error.Abort(
4494 _(
4511 _(
4495 b'could not instantiate HTTP peer for '
4512 b'could not instantiate HTTP peer for '
4496 b'wire protocol version 2'
4513 b'wire protocol version 2'
4497 ),
4514 ),
4498 hint=_(
4515 hint=_(
4499 b'the server may not have the feature '
4516 b'the server may not have the feature '
4500 b'enabled or is not allowing this '
4517 b'enabled or is not allowing this '
4501 b'client version'
4518 b'client version'
4502 ),
4519 ),
4503 )
4520 )
4504
4521
4505 elif opts[b'peer'] == b'raw':
4522 elif opts[b'peer'] == b'raw':
4506 ui.write(_(b'using raw connection to peer\n'))
4523 ui.write(_(b'using raw connection to peer\n'))
4507 peer = None
4524 peer = None
4508 elif opts[b'peer']:
4525 elif opts[b'peer']:
4509 raise error.Abort(
4526 raise error.Abort(
4510 _(b'--peer %s not supported with HTTP peers') % opts[b'peer']
4527 _(b'--peer %s not supported with HTTP peers') % opts[b'peer']
4511 )
4528 )
4512 else:
4529 else:
4513 peer = httppeer.makepeer(ui, path, opener=opener)
4530 peer = httppeer.makepeer(ui, path, opener=opener)
4514
4531
4515 # We /could/ populate stdin/stdout with sock.makefile()...
4532 # We /could/ populate stdin/stdout with sock.makefile()...
4516 else:
4533 else:
4517 raise error.Abort(_(b'unsupported connection configuration'))
4534 raise error.Abort(_(b'unsupported connection configuration'))
4518
4535
4519 batchedcommands = None
4536 batchedcommands = None
4520
4537
4521 # Now perform actions based on the parsed wire language instructions.
4538 # Now perform actions based on the parsed wire language instructions.
4522 for action, lines in blocks:
4539 for action, lines in blocks:
4523 if action in (b'raw', b'raw+'):
4540 if action in (b'raw', b'raw+'):
4524 if not stdin:
4541 if not stdin:
4525 raise error.Abort(_(b'cannot call raw/raw+ on this peer'))
4542 raise error.Abort(_(b'cannot call raw/raw+ on this peer'))
4526
4543
4527 # Concatenate the data together.
4544 # Concatenate the data together.
4528 data = b''.join(l.lstrip() for l in lines)
4545 data = b''.join(l.lstrip() for l in lines)
4529 data = stringutil.unescapestr(data)
4546 data = stringutil.unescapestr(data)
4530 stdin.write(data)
4547 stdin.write(data)
4531
4548
4532 if action == b'raw+':
4549 if action == b'raw+':
4533 stdin.flush()
4550 stdin.flush()
4534 elif action == b'flush':
4551 elif action == b'flush':
4535 if not stdin:
4552 if not stdin:
4536 raise error.Abort(_(b'cannot call flush on this peer'))
4553 raise error.Abort(_(b'cannot call flush on this peer'))
4537 stdin.flush()
4554 stdin.flush()
4538 elif action.startswith(b'command'):
4555 elif action.startswith(b'command'):
4539 if not peer:
4556 if not peer:
4540 raise error.Abort(
4557 raise error.Abort(
4541 _(
4558 _(
4542 b'cannot send commands unless peer instance '
4559 b'cannot send commands unless peer instance '
4543 b'is available'
4560 b'is available'
4544 )
4561 )
4545 )
4562 )
4546
4563
4547 command = action.split(b' ', 1)[1]
4564 command = action.split(b' ', 1)[1]
4548
4565
4549 args = {}
4566 args = {}
4550 for line in lines:
4567 for line in lines:
4551 # We need to allow empty values.
4568 # We need to allow empty values.
4552 fields = line.lstrip().split(b' ', 1)
4569 fields = line.lstrip().split(b' ', 1)
4553 if len(fields) == 1:
4570 if len(fields) == 1:
4554 key = fields[0]
4571 key = fields[0]
4555 value = b''
4572 value = b''
4556 else:
4573 else:
4557 key, value = fields
4574 key, value = fields
4558
4575
4559 if value.startswith(b'eval:'):
4576 if value.startswith(b'eval:'):
4560 value = stringutil.evalpythonliteral(value[5:])
4577 value = stringutil.evalpythonliteral(value[5:])
4561 else:
4578 else:
4562 value = stringutil.unescapestr(value)
4579 value = stringutil.unescapestr(value)
4563
4580
4564 args[key] = value
4581 args[key] = value
4565
4582
4566 if batchedcommands is not None:
4583 if batchedcommands is not None:
4567 batchedcommands.append((command, args))
4584 batchedcommands.append((command, args))
4568 continue
4585 continue
4569
4586
4570 ui.status(_(b'sending %s command\n') % command)
4587 ui.status(_(b'sending %s command\n') % command)
4571
4588
4572 if b'PUSHFILE' in args:
4589 if b'PUSHFILE' in args:
4573 with open(args[b'PUSHFILE'], 'rb') as fh:
4590 with open(args[b'PUSHFILE'], 'rb') as fh:
4574 del args[b'PUSHFILE']
4591 del args[b'PUSHFILE']
4575 res, output = peer._callpush(
4592 res, output = peer._callpush(
4576 command, fh, **pycompat.strkwargs(args)
4593 command, fh, **pycompat.strkwargs(args)
4577 )
4594 )
4578 ui.status(_(b'result: %s\n') % stringutil.escapestr(res))
4595 ui.status(_(b'result: %s\n') % stringutil.escapestr(res))
4579 ui.status(
4596 ui.status(
4580 _(b'remote output: %s\n') % stringutil.escapestr(output)
4597 _(b'remote output: %s\n') % stringutil.escapestr(output)
4581 )
4598 )
4582 else:
4599 else:
4583 with peer.commandexecutor() as e:
4600 with peer.commandexecutor() as e:
4584 res = e.callcommand(command, args).result()
4601 res = e.callcommand(command, args).result()
4585
4602
4586 if isinstance(res, wireprotov2peer.commandresponse):
4603 if isinstance(res, wireprotov2peer.commandresponse):
4587 val = res.objects()
4604 val = res.objects()
4588 ui.status(
4605 ui.status(
4589 _(b'response: %s\n')
4606 _(b'response: %s\n')
4590 % stringutil.pprint(val, bprefix=True, indent=2)
4607 % stringutil.pprint(val, bprefix=True, indent=2)
4591 )
4608 )
4592 else:
4609 else:
4593 ui.status(
4610 ui.status(
4594 _(b'response: %s\n')
4611 _(b'response: %s\n')
4595 % stringutil.pprint(res, bprefix=True, indent=2)
4612 % stringutil.pprint(res, bprefix=True, indent=2)
4596 )
4613 )
4597
4614
4598 elif action == b'batchbegin':
4615 elif action == b'batchbegin':
4599 if batchedcommands is not None:
4616 if batchedcommands is not None:
4600 raise error.Abort(_(b'nested batchbegin not allowed'))
4617 raise error.Abort(_(b'nested batchbegin not allowed'))
4601
4618
4602 batchedcommands = []
4619 batchedcommands = []
4603 elif action == b'batchsubmit':
4620 elif action == b'batchsubmit':
4604 # There is a batching API we could go through. But it would be
4621 # There is a batching API we could go through. But it would be
4605 # difficult to normalize requests into function calls. It is easier
4622 # difficult to normalize requests into function calls. It is easier
4606 # to bypass this layer and normalize to commands + args.
4623 # to bypass this layer and normalize to commands + args.
4607 ui.status(
4624 ui.status(
4608 _(b'sending batch with %d sub-commands\n')
4625 _(b'sending batch with %d sub-commands\n')
4609 % len(batchedcommands)
4626 % len(batchedcommands)
4610 )
4627 )
4611 assert peer is not None
4628 assert peer is not None
4612 for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
4629 for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
4613 ui.status(
4630 ui.status(
4614 _(b'response #%d: %s\n') % (i, stringutil.escapestr(chunk))
4631 _(b'response #%d: %s\n') % (i, stringutil.escapestr(chunk))
4615 )
4632 )
4616
4633
4617 batchedcommands = None
4634 batchedcommands = None
4618
4635
4619 elif action.startswith(b'httprequest '):
4636 elif action.startswith(b'httprequest '):
4620 if not opener:
4637 if not opener:
4621 raise error.Abort(
4638 raise error.Abort(
4622 _(b'cannot use httprequest without an HTTP peer')
4639 _(b'cannot use httprequest without an HTTP peer')
4623 )
4640 )
4624
4641
4625 request = action.split(b' ', 2)
4642 request = action.split(b' ', 2)
4626 if len(request) != 3:
4643 if len(request) != 3:
4627 raise error.Abort(
4644 raise error.Abort(
4628 _(
4645 _(
4629 b'invalid httprequest: expected format is '
4646 b'invalid httprequest: expected format is '
4630 b'"httprequest <method> <path>'
4647 b'"httprequest <method> <path>'
4631 )
4648 )
4632 )
4649 )
4633
4650
4634 method, httppath = request[1:]
4651 method, httppath = request[1:]
4635 headers = {}
4652 headers = {}
4636 body = None
4653 body = None
4637 frames = []
4654 frames = []
4638 for line in lines:
4655 for line in lines:
4639 line = line.lstrip()
4656 line = line.lstrip()
4640 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
4657 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
4641 if m:
4658 if m:
4642 # Headers need to use native strings.
4659 # Headers need to use native strings.
4643 key = pycompat.strurl(m.group(1))
4660 key = pycompat.strurl(m.group(1))
4644 value = pycompat.strurl(m.group(2))
4661 value = pycompat.strurl(m.group(2))
4645 headers[key] = value
4662 headers[key] = value
4646 continue
4663 continue
4647
4664
4648 if line.startswith(b'BODYFILE '):
4665 if line.startswith(b'BODYFILE '):
4649 with open(line.split(b' ', 1), b'rb') as fh:
4666 with open(line.split(b' ', 1), b'rb') as fh:
4650 body = fh.read()
4667 body = fh.read()
4651 elif line.startswith(b'frame '):
4668 elif line.startswith(b'frame '):
4652 frame = wireprotoframing.makeframefromhumanstring(
4669 frame = wireprotoframing.makeframefromhumanstring(
4653 line[len(b'frame ') :]
4670 line[len(b'frame ') :]
4654 )
4671 )
4655
4672
4656 frames.append(frame)
4673 frames.append(frame)
4657 else:
4674 else:
4658 raise error.Abort(
4675 raise error.Abort(
4659 _(b'unknown argument to httprequest: %s') % line
4676 _(b'unknown argument to httprequest: %s') % line
4660 )
4677 )
4661
4678
4662 url = path + httppath
4679 url = path + httppath
4663
4680
4664 if frames:
4681 if frames:
4665 body = b''.join(bytes(f) for f in frames)
4682 body = b''.join(bytes(f) for f in frames)
4666
4683
4667 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
4684 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
4668
4685
4669 # urllib.Request insists on using has_data() as a proxy for
4686 # urllib.Request insists on using has_data() as a proxy for
4670 # determining the request method. Override that to use our
4687 # determining the request method. Override that to use our
4671 # explicitly requested method.
4688 # explicitly requested method.
4672 req.get_method = lambda: pycompat.sysstr(method)
4689 req.get_method = lambda: pycompat.sysstr(method)
4673
4690
4674 try:
4691 try:
4675 res = opener.open(req)
4692 res = opener.open(req)
4676 body = res.read()
4693 body = res.read()
4677 except util.urlerr.urlerror as e:
4694 except util.urlerr.urlerror as e:
4678 # read() method must be called, but only exists in Python 2
4695 # read() method must be called, but only exists in Python 2
4679 getattr(e, 'read', lambda: None)()
4696 getattr(e, 'read', lambda: None)()
4680 continue
4697 continue
4681
4698
4682 ct = res.headers.get('Content-Type')
4699 ct = res.headers.get('Content-Type')
4683 if ct == 'application/mercurial-cbor':
4700 if ct == 'application/mercurial-cbor':
4684 ui.write(
4701 ui.write(
4685 _(b'cbor> %s\n')
4702 _(b'cbor> %s\n')
4686 % stringutil.pprint(
4703 % stringutil.pprint(
4687 cborutil.decodeall(body), bprefix=True, indent=2
4704 cborutil.decodeall(body), bprefix=True, indent=2
4688 )
4705 )
4689 )
4706 )
4690
4707
4691 elif action == b'close':
4708 elif action == b'close':
4692 assert peer is not None
4709 assert peer is not None
4693 peer.close()
4710 peer.close()
4694 elif action == b'readavailable':
4711 elif action == b'readavailable':
4695 if not stdout or not stderr:
4712 if not stdout or not stderr:
4696 raise error.Abort(
4713 raise error.Abort(
4697 _(b'readavailable not available on this peer')
4714 _(b'readavailable not available on this peer')
4698 )
4715 )
4699
4716
4700 stdin.close()
4717 stdin.close()
4701 stdout.read()
4718 stdout.read()
4702 stderr.read()
4719 stderr.read()
4703
4720
4704 elif action == b'readline':
4721 elif action == b'readline':
4705 if not stdout:
4722 if not stdout:
4706 raise error.Abort(_(b'readline not available on this peer'))
4723 raise error.Abort(_(b'readline not available on this peer'))
4707 stdout.readline()
4724 stdout.readline()
4708 elif action == b'ereadline':
4725 elif action == b'ereadline':
4709 if not stderr:
4726 if not stderr:
4710 raise error.Abort(_(b'ereadline not available on this peer'))
4727 raise error.Abort(_(b'ereadline not available on this peer'))
4711 stderr.readline()
4728 stderr.readline()
4712 elif action.startswith(b'read '):
4729 elif action.startswith(b'read '):
4713 count = int(action.split(b' ', 1)[1])
4730 count = int(action.split(b' ', 1)[1])
4714 if not stdout:
4731 if not stdout:
4715 raise error.Abort(_(b'read not available on this peer'))
4732 raise error.Abort(_(b'read not available on this peer'))
4716 stdout.read(count)
4733 stdout.read(count)
4717 elif action.startswith(b'eread '):
4734 elif action.startswith(b'eread '):
4718 count = int(action.split(b' ', 1)[1])
4735 count = int(action.split(b' ', 1)[1])
4719 if not stderr:
4736 if not stderr:
4720 raise error.Abort(_(b'eread not available on this peer'))
4737 raise error.Abort(_(b'eread not available on this peer'))
4721 stderr.read(count)
4738 stderr.read(count)
4722 else:
4739 else:
4723 raise error.Abort(_(b'unknown action: %s') % action)
4740 raise error.Abort(_(b'unknown action: %s') % action)
4724
4741
4725 if batchedcommands is not None:
4742 if batchedcommands is not None:
4726 raise error.Abort(_(b'unclosed "batchbegin" request'))
4743 raise error.Abort(_(b'unclosed "batchbegin" request'))
4727
4744
4728 if peer:
4745 if peer:
4729 peer.close()
4746 peer.close()
4730
4747
4731 if proc:
4748 if proc:
4732 proc.kill()
4749 proc.kill()
@@ -1,443 +1,443 b''
1 Show all commands except debug commands
1 Show all commands except debug commands
2 $ hg debugcomplete
2 $ hg debugcomplete
3 abort
3 abort
4 add
4 add
5 addremove
5 addremove
6 annotate
6 annotate
7 archive
7 archive
8 backout
8 backout
9 bisect
9 bisect
10 bookmarks
10 bookmarks
11 branch
11 branch
12 branches
12 branches
13 bundle
13 bundle
14 cat
14 cat
15 clone
15 clone
16 commit
16 commit
17 config
17 config
18 continue
18 continue
19 copy
19 copy
20 diff
20 diff
21 export
21 export
22 files
22 files
23 forget
23 forget
24 graft
24 graft
25 grep
25 grep
26 heads
26 heads
27 help
27 help
28 identify
28 identify
29 import
29 import
30 incoming
30 incoming
31 init
31 init
32 locate
32 locate
33 log
33 log
34 manifest
34 manifest
35 merge
35 merge
36 outgoing
36 outgoing
37 parents
37 parents
38 paths
38 paths
39 phase
39 phase
40 pull
40 pull
41 purge
41 purge
42 push
42 push
43 recover
43 recover
44 remove
44 remove
45 rename
45 rename
46 resolve
46 resolve
47 revert
47 revert
48 rollback
48 rollback
49 root
49 root
50 serve
50 serve
51 shelve
51 shelve
52 status
52 status
53 summary
53 summary
54 tag
54 tag
55 tags
55 tags
56 tip
56 tip
57 unbundle
57 unbundle
58 unshelve
58 unshelve
59 update
59 update
60 verify
60 verify
61 version
61 version
62
62
63 Show all commands that start with "a"
63 Show all commands that start with "a"
64 $ hg debugcomplete a
64 $ hg debugcomplete a
65 abort
65 abort
66 add
66 add
67 addremove
67 addremove
68 annotate
68 annotate
69 archive
69 archive
70
70
71 Do not show debug commands if there are other candidates
71 Do not show debug commands if there are other candidates
72 $ hg debugcomplete d
72 $ hg debugcomplete d
73 diff
73 diff
74
74
75 Show debug commands if there are no other candidates
75 Show debug commands if there are no other candidates
76 $ hg debugcomplete debug
76 $ hg debugcomplete debug
77 debugancestor
77 debugancestor
78 debugantivirusrunning
78 debugantivirusrunning
79 debugapplystreamclonebundle
79 debugapplystreamclonebundle
80 debugbackupbundle
80 debugbackupbundle
81 debugbuilddag
81 debugbuilddag
82 debugbundle
82 debugbundle
83 debugcapabilities
83 debugcapabilities
84 debugchangedfiles
84 debugchangedfiles
85 debugcheckstate
85 debugcheckstate
86 debugcolor
86 debugcolor
87 debugcommands
87 debugcommands
88 debugcomplete
88 debugcomplete
89 debugconfig
89 debugconfig
90 debugcreatestreamclonebundle
90 debugcreatestreamclonebundle
91 debugdag
91 debugdag
92 debugdata
92 debugdata
93 debugdate
93 debugdate
94 debugdeltachain
94 debugdeltachain
95 debugdirstate
95 debugdirstate
96 debugdiscovery
96 debugdiscovery
97 debugdownload
97 debugdownload
98 debugextensions
98 debugextensions
99 debugfileset
99 debugfileset
100 debugformat
100 debugformat
101 debugfsinfo
101 debugfsinfo
102 debuggetbundle
102 debuggetbundle
103 debugignore
103 debugignore
104 debugindex
104 debugindex
105 debugindexdot
105 debugindexdot
106 debugindexstats
106 debugindexstats
107 debuginstall
107 debuginstall
108 debugknown
108 debugknown
109 debuglabelcomplete
109 debuglabelcomplete
110 debuglocks
110 debuglocks
111 debugmanifestfulltextcache
111 debugmanifestfulltextcache
112 debugmergestate
112 debugmergestate
113 debugnamecomplete
113 debugnamecomplete
114 debugnodemap
114 debugnodemap
115 debugobsolete
115 debugobsolete
116 debugp1copies
116 debugp1copies
117 debugp2copies
117 debugp2copies
118 debugpathcomplete
118 debugpathcomplete
119 debugpathcopies
119 debugpathcopies
120 debugpeer
120 debugpeer
121 debugpickmergetool
121 debugpickmergetool
122 debugpushkey
122 debugpushkey
123 debugpvec
123 debugpvec
124 debugrebuilddirstate
124 debugrebuilddirstate
125 debugrebuildfncache
125 debugrebuildfncache
126 debugrename
126 debugrename
127 debugrequires
127 debugrequires
128 debugrevlog
128 debugrevlog
129 debugrevlogindex
129 debugrevlogindex
130 debugrevspec
130 debugrevspec
131 debugserve
131 debugserve
132 debugsetparents
132 debugsetparents
133 debugshell
133 debugshell
134 debugsidedata
134 debugsidedata
135 debugssl
135 debugssl
136 debugstrip
136 debugstrip
137 debugsub
137 debugsub
138 debugsuccessorssets
138 debugsuccessorssets
139 debugtagscache
139 debugtagscache
140 debugtemplate
140 debugtemplate
141 debuguigetpass
141 debuguigetpass
142 debuguiprompt
142 debuguiprompt
143 debugupdatecaches
143 debugupdatecaches
144 debugupgraderepo
144 debugupgraderepo
145 debugwalk
145 debugwalk
146 debugwhyunstable
146 debugwhyunstable
147 debugwireargs
147 debugwireargs
148 debugwireproto
148 debugwireproto
149
149
150 Do not show the alias of a debug command if there are other candidates
150 Do not show the alias of a debug command if there are other candidates
151 (this should hide rawcommit)
151 (this should hide rawcommit)
152 $ hg debugcomplete r
152 $ hg debugcomplete r
153 recover
153 recover
154 remove
154 remove
155 rename
155 rename
156 resolve
156 resolve
157 revert
157 revert
158 rollback
158 rollback
159 root
159 root
160 Show the alias of a debug command if there are no other candidates
160 Show the alias of a debug command if there are no other candidates
161 $ hg debugcomplete rawc
161 $ hg debugcomplete rawc
162
162
163
163
164 Show the global options
164 Show the global options
165 $ hg debugcomplete --options | sort
165 $ hg debugcomplete --options | sort
166 --color
166 --color
167 --config
167 --config
168 --cwd
168 --cwd
169 --debug
169 --debug
170 --debugger
170 --debugger
171 --encoding
171 --encoding
172 --encodingmode
172 --encodingmode
173 --help
173 --help
174 --hidden
174 --hidden
175 --noninteractive
175 --noninteractive
176 --pager
176 --pager
177 --profile
177 --profile
178 --quiet
178 --quiet
179 --repository
179 --repository
180 --time
180 --time
181 --traceback
181 --traceback
182 --verbose
182 --verbose
183 --version
183 --version
184 -R
184 -R
185 -h
185 -h
186 -q
186 -q
187 -v
187 -v
188 -y
188 -y
189
189
190 Show the options for the "serve" command
190 Show the options for the "serve" command
191 $ hg debugcomplete --options serve | sort
191 $ hg debugcomplete --options serve | sort
192 --accesslog
192 --accesslog
193 --address
193 --address
194 --certificate
194 --certificate
195 --cmdserver
195 --cmdserver
196 --color
196 --color
197 --config
197 --config
198 --cwd
198 --cwd
199 --daemon
199 --daemon
200 --daemon-postexec
200 --daemon-postexec
201 --debug
201 --debug
202 --debugger
202 --debugger
203 --encoding
203 --encoding
204 --encodingmode
204 --encodingmode
205 --errorlog
205 --errorlog
206 --help
206 --help
207 --hidden
207 --hidden
208 --ipv6
208 --ipv6
209 --name
209 --name
210 --noninteractive
210 --noninteractive
211 --pager
211 --pager
212 --pid-file
212 --pid-file
213 --port
213 --port
214 --prefix
214 --prefix
215 --print-url
215 --print-url
216 --profile
216 --profile
217 --quiet
217 --quiet
218 --repository
218 --repository
219 --stdio
219 --stdio
220 --style
220 --style
221 --subrepos
221 --subrepos
222 --templates
222 --templates
223 --time
223 --time
224 --traceback
224 --traceback
225 --verbose
225 --verbose
226 --version
226 --version
227 --web-conf
227 --web-conf
228 -6
228 -6
229 -A
229 -A
230 -E
230 -E
231 -R
231 -R
232 -S
232 -S
233 -a
233 -a
234 -d
234 -d
235 -h
235 -h
236 -n
236 -n
237 -p
237 -p
238 -q
238 -q
239 -t
239 -t
240 -v
240 -v
241 -y
241 -y
242
242
243 Show an error if we use --options with an ambiguous abbreviation
243 Show an error if we use --options with an ambiguous abbreviation
244 $ hg debugcomplete --options s
244 $ hg debugcomplete --options s
245 hg: command 's' is ambiguous:
245 hg: command 's' is ambiguous:
246 serve shelve showconfig status summary
246 serve shelve showconfig status summary
247 [10]
247 [10]
248
248
249 Show all commands + options
249 Show all commands + options
250 $ hg debugcommands
250 $ hg debugcommands
251 abort: dry-run
251 abort: dry-run
252 add: include, exclude, subrepos, dry-run
252 add: include, exclude, subrepos, dry-run
253 addremove: similarity, subrepos, include, exclude, dry-run
253 addremove: similarity, subrepos, include, exclude, dry-run
254 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template
254 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template
255 archive: no-decode, prefix, rev, type, subrepos, include, exclude
255 archive: no-decode, prefix, rev, type, subrepos, include, exclude
256 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
256 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
257 bisect: reset, good, bad, skip, extend, command, noupdate
257 bisect: reset, good, bad, skip, extend, command, noupdate
258 bookmarks: force, rev, delete, rename, inactive, list, template
258 bookmarks: force, rev, delete, rename, inactive, list, template
259 branch: force, clean, rev
259 branch: force, clean, rev
260 branches: active, closed, rev, template
260 branches: active, closed, rev, template
261 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
261 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
262 cat: output, rev, decode, include, exclude, template
262 cat: output, rev, decode, include, exclude, template
263 clone: noupdate, updaterev, rev, branch, pull, uncompressed, stream, ssh, remotecmd, insecure
263 clone: noupdate, updaterev, rev, branch, pull, uncompressed, stream, ssh, remotecmd, insecure
264 commit: addremove, close-branch, amend, secret, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos
264 commit: addremove, close-branch, amend, secret, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos
265 config: untrusted, edit, local, shared, non-shared, global, template
265 config: untrusted, edit, local, shared, non-shared, global, template
266 continue: dry-run
266 continue: dry-run
267 copy: forget, after, at-rev, force, include, exclude, dry-run
267 copy: forget, after, at-rev, force, include, exclude, dry-run
268 debugancestor:
268 debugancestor:
269 debugantivirusrunning:
269 debugantivirusrunning:
270 debugapplystreamclonebundle:
270 debugapplystreamclonebundle:
271 debugbackupbundle: recover, patch, git, limit, no-merges, stat, graph, style, template
271 debugbackupbundle: recover, patch, git, limit, no-merges, stat, graph, style, template
272 debugbuilddag: mergeable-file, overwritten-file, new-file
272 debugbuilddag: mergeable-file, overwritten-file, new-file
273 debugbundle: all, part-type, spec
273 debugbundle: all, part-type, spec
274 debugcapabilities:
274 debugcapabilities:
275 debugchangedfiles:
275 debugchangedfiles: compute
276 debugcheckstate:
276 debugcheckstate:
277 debugcolor: style
277 debugcolor: style
278 debugcommands:
278 debugcommands:
279 debugcomplete: options
279 debugcomplete: options
280 debugcreatestreamclonebundle:
280 debugcreatestreamclonebundle:
281 debugdag: tags, branches, dots, spaces
281 debugdag: tags, branches, dots, spaces
282 debugdata: changelog, manifest, dir
282 debugdata: changelog, manifest, dir
283 debugdate: extended
283 debugdate: extended
284 debugdeltachain: changelog, manifest, dir, template
284 debugdeltachain: changelog, manifest, dir, template
285 debugdirstate: nodates, dates, datesort
285 debugdirstate: nodates, dates, datesort
286 debugdiscovery: old, nonheads, rev, seed, local-as-revs, remote-as-revs, ssh, remotecmd, insecure
286 debugdiscovery: old, nonheads, rev, seed, local-as-revs, remote-as-revs, ssh, remotecmd, insecure
287 debugdownload: output
287 debugdownload: output
288 debugextensions: template
288 debugextensions: template
289 debugfileset: rev, all-files, show-matcher, show-stage
289 debugfileset: rev, all-files, show-matcher, show-stage
290 debugformat: template
290 debugformat: template
291 debugfsinfo:
291 debugfsinfo:
292 debuggetbundle: head, common, type
292 debuggetbundle: head, common, type
293 debugignore:
293 debugignore:
294 debugindex: changelog, manifest, dir, template
294 debugindex: changelog, manifest, dir, template
295 debugindexdot: changelog, manifest, dir
295 debugindexdot: changelog, manifest, dir
296 debugindexstats:
296 debugindexstats:
297 debuginstall: template
297 debuginstall: template
298 debugknown:
298 debugknown:
299 debuglabelcomplete:
299 debuglabelcomplete:
300 debuglocks: force-free-lock, force-free-wlock, set-lock, set-wlock
300 debuglocks: force-free-lock, force-free-wlock, set-lock, set-wlock
301 debugmanifestfulltextcache: clear, add
301 debugmanifestfulltextcache: clear, add
302 debugmergestate: style, template
302 debugmergestate: style, template
303 debugnamecomplete:
303 debugnamecomplete:
304 debugnodemap: dump-new, dump-disk, check, metadata
304 debugnodemap: dump-new, dump-disk, check, metadata
305 debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, user, template
305 debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, user, template
306 debugp1copies: rev
306 debugp1copies: rev
307 debugp2copies: rev
307 debugp2copies: rev
308 debugpathcomplete: full, normal, added, removed
308 debugpathcomplete: full, normal, added, removed
309 debugpathcopies: include, exclude
309 debugpathcopies: include, exclude
310 debugpeer:
310 debugpeer:
311 debugpickmergetool: rev, changedelete, include, exclude, tool
311 debugpickmergetool: rev, changedelete, include, exclude, tool
312 debugpushkey:
312 debugpushkey:
313 debugpvec:
313 debugpvec:
314 debugrebuilddirstate: rev, minimal
314 debugrebuilddirstate: rev, minimal
315 debugrebuildfncache:
315 debugrebuildfncache:
316 debugrename: rev
316 debugrename: rev
317 debugrequires:
317 debugrequires:
318 debugrevlog: changelog, manifest, dir, dump
318 debugrevlog: changelog, manifest, dir, dump
319 debugrevlogindex: changelog, manifest, dir, format
319 debugrevlogindex: changelog, manifest, dir, format
320 debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
320 debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
321 debugserve: sshstdio, logiofd, logiofile
321 debugserve: sshstdio, logiofd, logiofile
322 debugsetparents:
322 debugsetparents:
323 debugshell:
323 debugshell:
324 debugsidedata: changelog, manifest, dir
324 debugsidedata: changelog, manifest, dir
325 debugssl:
325 debugssl:
326 debugstrip: rev, force, no-backup, nobackup, , keep, bookmark, soft
326 debugstrip: rev, force, no-backup, nobackup, , keep, bookmark, soft
327 debugsub: rev
327 debugsub: rev
328 debugsuccessorssets: closest
328 debugsuccessorssets: closest
329 debugtagscache:
329 debugtagscache:
330 debugtemplate: rev, define
330 debugtemplate: rev, define
331 debuguigetpass: prompt
331 debuguigetpass: prompt
332 debuguiprompt: prompt
332 debuguiprompt: prompt
333 debugupdatecaches:
333 debugupdatecaches:
334 debugupgraderepo: optimize, run, backup, changelog, manifest, filelogs
334 debugupgraderepo: optimize, run, backup, changelog, manifest, filelogs
335 debugwalk: include, exclude
335 debugwalk: include, exclude
336 debugwhyunstable:
336 debugwhyunstable:
337 debugwireargs: three, four, five, ssh, remotecmd, insecure
337 debugwireargs: three, four, five, ssh, remotecmd, insecure
338 debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
338 debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
339 diff: rev, from, to, change, merge, text, git, binary, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, unified, stat, root, include, exclude, subrepos
339 diff: rev, from, to, change, merge, text, git, binary, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, unified, stat, root, include, exclude, subrepos
340 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
340 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
341 files: rev, print0, include, exclude, template, subrepos
341 files: rev, print0, include, exclude, template, subrepos
342 forget: interactive, include, exclude, dry-run
342 forget: interactive, include, exclude, dry-run
343 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
343 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
344 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
344 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
345 heads: rev, topo, active, closed, style, template
345 heads: rev, topo, active, closed, style, template
346 help: extension, command, keyword, system
346 help: extension, command, keyword, system
347 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure, template
347 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure, template
348 import: strip, base, secret, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
348 import: strip, base, secret, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
349 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
349 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
350 init: ssh, remotecmd, insecure
350 init: ssh, remotecmd, insecure
351 locate: rev, print0, fullpath, include, exclude
351 locate: rev, print0, fullpath, include, exclude
352 log: follow, follow-first, date, copies, keyword, rev, line-range, removed, only-merges, user, only-branch, branch, bookmark, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
352 log: follow, follow-first, date, copies, keyword, rev, line-range, removed, only-merges, user, only-branch, branch, bookmark, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
353 manifest: rev, all, template
353 manifest: rev, all, template
354 merge: force, rev, preview, abort, tool
354 merge: force, rev, preview, abort, tool
355 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
355 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
356 parents: rev, style, template
356 parents: rev, style, template
357 paths: template
357 paths: template
358 phase: public, draft, secret, force, rev
358 phase: public, draft, secret, force, rev
359 pull: update, force, confirm, rev, bookmark, branch, ssh, remotecmd, insecure
359 pull: update, force, confirm, rev, bookmark, branch, ssh, remotecmd, insecure
360 purge: abort-on-err, all, ignored, dirs, files, print, print0, confirm, include, exclude
360 purge: abort-on-err, all, ignored, dirs, files, print, print0, confirm, include, exclude
361 push: force, rev, bookmark, all-bookmarks, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
361 push: force, rev, bookmark, all-bookmarks, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
362 recover: verify
362 recover: verify
363 remove: after, force, subrepos, include, exclude, dry-run
363 remove: after, force, subrepos, include, exclude, dry-run
364 rename: after, at-rev, force, include, exclude, dry-run
364 rename: after, at-rev, force, include, exclude, dry-run
365 resolve: all, list, mark, unmark, no-status, re-merge, tool, include, exclude, template
365 resolve: all, list, mark, unmark, no-status, re-merge, tool, include, exclude, template
366 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
366 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
367 rollback: dry-run, force
367 rollback: dry-run, force
368 root: template
368 root: template
369 serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, print-url, subrepos
369 serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, print-url, subrepos
370 shelve: addremove, unknown, cleanup, date, delete, edit, keep, list, message, name, patch, interactive, stat, include, exclude
370 shelve: addremove, unknown, cleanup, date, delete, edit, keep, list, message, name, patch, interactive, stat, include, exclude
371 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
371 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
372 summary: remote
372 summary: remote
373 tag: force, local, rev, remove, edit, message, date, user
373 tag: force, local, rev, remove, edit, message, date, user
374 tags: template
374 tags: template
375 tip: patch, git, style, template
375 tip: patch, git, style, template
376 unbundle: update
376 unbundle: update
377 unshelve: abort, continue, interactive, keep, name, tool, date
377 unshelve: abort, continue, interactive, keep, name, tool, date
378 update: clean, check, merge, date, rev, tool
378 update: clean, check, merge, date, rev, tool
379 verify: full
379 verify: full
380 version: template
380 version: template
381
381
382 $ hg init a
382 $ hg init a
383 $ cd a
383 $ cd a
384 $ echo fee > fee
384 $ echo fee > fee
385 $ hg ci -q -Amfee
385 $ hg ci -q -Amfee
386 $ hg tag fee
386 $ hg tag fee
387 $ mkdir fie
387 $ mkdir fie
388 $ echo dead > fie/dead
388 $ echo dead > fie/dead
389 $ echo live > fie/live
389 $ echo live > fie/live
390 $ hg bookmark fo
390 $ hg bookmark fo
391 $ hg branch -q fie
391 $ hg branch -q fie
392 $ hg ci -q -Amfie
392 $ hg ci -q -Amfie
393 $ echo fo > fo
393 $ echo fo > fo
394 $ hg branch -qf default
394 $ hg branch -qf default
395 $ hg ci -q -Amfo
395 $ hg ci -q -Amfo
396 $ echo Fum > Fum
396 $ echo Fum > Fum
397 $ hg ci -q -AmFum
397 $ hg ci -q -AmFum
398 $ hg bookmark Fum
398 $ hg bookmark Fum
399
399
400 Test debugpathcomplete
400 Test debugpathcomplete
401
401
402 $ hg debugpathcomplete f
402 $ hg debugpathcomplete f
403 fee
403 fee
404 fie
404 fie
405 fo
405 fo
406 $ hg debugpathcomplete -f f
406 $ hg debugpathcomplete -f f
407 fee
407 fee
408 fie/dead
408 fie/dead
409 fie/live
409 fie/live
410 fo
410 fo
411
411
412 $ hg rm Fum
412 $ hg rm Fum
413 $ hg debugpathcomplete -r F
413 $ hg debugpathcomplete -r F
414 Fum
414 Fum
415
415
416 Test debugnamecomplete
416 Test debugnamecomplete
417
417
418 $ hg debugnamecomplete
418 $ hg debugnamecomplete
419 Fum
419 Fum
420 default
420 default
421 fee
421 fee
422 fie
422 fie
423 fo
423 fo
424 tip
424 tip
425 $ hg debugnamecomplete f
425 $ hg debugnamecomplete f
426 fee
426 fee
427 fie
427 fie
428 fo
428 fo
429
429
430 Test debuglabelcomplete, a deprecated name for debugnamecomplete that is still
430 Test debuglabelcomplete, a deprecated name for debugnamecomplete that is still
431 used for completions in some shells.
431 used for completions in some shells.
432
432
433 $ hg debuglabelcomplete
433 $ hg debuglabelcomplete
434 Fum
434 Fum
435 default
435 default
436 fee
436 fee
437 fie
437 fie
438 fo
438 fo
439 tip
439 tip
440 $ hg debuglabelcomplete f
440 $ hg debuglabelcomplete f
441 fee
441 fee
442 fie
442 fie
443 fo
443 fo
@@ -1,1754 +1,1759 b''
1 #testcases filelog compatibility changeset sidedata upgraded
1 #testcases filelog compatibility changeset sidedata upgraded
2
2
3 =====================================================
3 =====================================================
4 Test Copy tracing for chain of copies involving merge
4 Test Copy tracing for chain of copies involving merge
5 =====================================================
5 =====================================================
6
6
7 This test files covers copies/rename case for a chains of commit where merges
7 This test files covers copies/rename case for a chains of commit where merges
8 are involved. It cheks we do not have unwanted update of behavior and that the
8 are involved. It cheks we do not have unwanted update of behavior and that the
9 different options to retrieve copies behave correctly.
9 different options to retrieve copies behave correctly.
10
10
11
11
12 Setup
12 Setup
13 =====
13 =====
14
14
15 use git diff to see rename
15 use git diff to see rename
16
16
17 $ cat << EOF >> $HGRCPATH
17 $ cat << EOF >> $HGRCPATH
18 > [diff]
18 > [diff]
19 > git=yes
19 > git=yes
20 > [command-templates]
20 > [command-templates]
21 > log={rev} {desc}\n
21 > log={rev} {desc}\n
22 > EOF
22 > EOF
23
23
24 #if compatibility
24 #if compatibility
25 $ cat >> $HGRCPATH << EOF
25 $ cat >> $HGRCPATH << EOF
26 > [experimental]
26 > [experimental]
27 > copies.read-from = compatibility
27 > copies.read-from = compatibility
28 > EOF
28 > EOF
29 #endif
29 #endif
30
30
31 #if changeset
31 #if changeset
32 $ cat >> $HGRCPATH << EOF
32 $ cat >> $HGRCPATH << EOF
33 > [experimental]
33 > [experimental]
34 > copies.read-from = changeset-only
34 > copies.read-from = changeset-only
35 > copies.write-to = changeset-only
35 > copies.write-to = changeset-only
36 > EOF
36 > EOF
37 #endif
37 #endif
38
38
39 #if sidedata
39 #if sidedata
40 $ cat >> $HGRCPATH << EOF
40 $ cat >> $HGRCPATH << EOF
41 > [format]
41 > [format]
42 > exp-use-side-data = yes
42 > exp-use-side-data = yes
43 > exp-use-copies-side-data-changeset = yes
43 > exp-use-copies-side-data-changeset = yes
44 > EOF
44 > EOF
45 #endif
45 #endif
46
46
47
47
48 $ hg init repo-chain
48 $ hg init repo-chain
49 $ cd repo-chain
49 $ cd repo-chain
50
50
51 Add some linear rename initialy
51 Add some linear rename initialy
52
52
53 $ echo a > a
53 $ echo a > a
54 $ echo b > b
54 $ echo b > b
55 $ echo h > h
55 $ echo h > h
56 $ hg ci -Am 'i-0 initial commit: a b h'
56 $ hg ci -Am 'i-0 initial commit: a b h'
57 adding a
57 adding a
58 adding b
58 adding b
59 adding h
59 adding h
60 $ hg mv a c
60 $ hg mv a c
61 $ hg ci -Am 'i-1: a -move-> c'
61 $ hg ci -Am 'i-1: a -move-> c'
62 $ hg mv c d
62 $ hg mv c d
63 $ hg ci -Am 'i-2: c -move-> d'
63 $ hg ci -Am 'i-2: c -move-> d'
64 $ hg log -G
64 $ hg log -G
65 @ 2 i-2: c -move-> d
65 @ 2 i-2: c -move-> d
66 |
66 |
67 o 1 i-1: a -move-> c
67 o 1 i-1: a -move-> c
68 |
68 |
69 o 0 i-0 initial commit: a b h
69 o 0 i-0 initial commit: a b h
70
70
71
71
72 And having another branch with renames on the other side
72 And having another branch with renames on the other side
73
73
74 $ hg mv d e
74 $ hg mv d e
75 $ hg ci -Am 'a-1: d -move-> e'
75 $ hg ci -Am 'a-1: d -move-> e'
76 $ hg mv e f
76 $ hg mv e f
77 $ hg ci -Am 'a-2: e -move-> f'
77 $ hg ci -Am 'a-2: e -move-> f'
78 $ hg log -G --rev '::.'
78 $ hg log -G --rev '::.'
79 @ 4 a-2: e -move-> f
79 @ 4 a-2: e -move-> f
80 |
80 |
81 o 3 a-1: d -move-> e
81 o 3 a-1: d -move-> e
82 |
82 |
83 o 2 i-2: c -move-> d
83 o 2 i-2: c -move-> d
84 |
84 |
85 o 1 i-1: a -move-> c
85 o 1 i-1: a -move-> c
86 |
86 |
87 o 0 i-0 initial commit: a b h
87 o 0 i-0 initial commit: a b h
88
88
89
89
90 Have a branching with nothing on one side
90 Have a branching with nothing on one side
91
91
92 $ hg up 'desc("i-2")'
92 $ hg up 'desc("i-2")'
93 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
93 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
94 $ echo foo > b
94 $ echo foo > b
95 $ hg ci -m 'b-1: b update'
95 $ hg ci -m 'b-1: b update'
96 created new head
96 created new head
97 $ hg log -G --rev '::.'
97 $ hg log -G --rev '::.'
98 @ 5 b-1: b update
98 @ 5 b-1: b update
99 |
99 |
100 o 2 i-2: c -move-> d
100 o 2 i-2: c -move-> d
101 |
101 |
102 o 1 i-1: a -move-> c
102 o 1 i-1: a -move-> c
103 |
103 |
104 o 0 i-0 initial commit: a b h
104 o 0 i-0 initial commit: a b h
105
105
106
106
107 Create a branch that delete a file previous renamed
107 Create a branch that delete a file previous renamed
108
108
109 $ hg up 'desc("i-2")'
109 $ hg up 'desc("i-2")'
110 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
110 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
111 $ hg rm d
111 $ hg rm d
112 $ hg ci -m 'c-1 delete d'
112 $ hg ci -m 'c-1 delete d'
113 created new head
113 created new head
114 $ hg log -G --rev '::.'
114 $ hg log -G --rev '::.'
115 @ 6 c-1 delete d
115 @ 6 c-1 delete d
116 |
116 |
117 o 2 i-2: c -move-> d
117 o 2 i-2: c -move-> d
118 |
118 |
119 o 1 i-1: a -move-> c
119 o 1 i-1: a -move-> c
120 |
120 |
121 o 0 i-0 initial commit: a b h
121 o 0 i-0 initial commit: a b h
122
122
123
123
124 Create a branch that delete a file previous renamed and recreate it
124 Create a branch that delete a file previous renamed and recreate it
125
125
126 $ hg up 'desc("i-2")'
126 $ hg up 'desc("i-2")'
127 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
128 $ hg rm d
128 $ hg rm d
129 $ hg ci -m 'd-1 delete d'
129 $ hg ci -m 'd-1 delete d'
130 created new head
130 created new head
131 $ echo bar > d
131 $ echo bar > d
132 $ hg add d
132 $ hg add d
133 $ hg ci -m 'd-2 re-add d'
133 $ hg ci -m 'd-2 re-add d'
134 $ hg log -G --rev '::.'
134 $ hg log -G --rev '::.'
135 @ 8 d-2 re-add d
135 @ 8 d-2 re-add d
136 |
136 |
137 o 7 d-1 delete d
137 o 7 d-1 delete d
138 |
138 |
139 o 2 i-2: c -move-> d
139 o 2 i-2: c -move-> d
140 |
140 |
141 o 1 i-1: a -move-> c
141 o 1 i-1: a -move-> c
142 |
142 |
143 o 0 i-0 initial commit: a b h
143 o 0 i-0 initial commit: a b h
144
144
145
145
146 Having another branch renaming a different file to the same filename as another
146 Having another branch renaming a different file to the same filename as another
147
147
148 $ hg up 'desc("i-2")'
148 $ hg up 'desc("i-2")'
149 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
149 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
150 $ hg mv b g
150 $ hg mv b g
151 $ hg ci -m 'e-1 b -move-> g'
151 $ hg ci -m 'e-1 b -move-> g'
152 created new head
152 created new head
153 $ hg mv g f
153 $ hg mv g f
154 $ hg ci -m 'e-2 g -move-> f'
154 $ hg ci -m 'e-2 g -move-> f'
155 $ hg log -G --rev '::.'
155 $ hg log -G --rev '::.'
156 @ 10 e-2 g -move-> f
156 @ 10 e-2 g -move-> f
157 |
157 |
158 o 9 e-1 b -move-> g
158 o 9 e-1 b -move-> g
159 |
159 |
160 o 2 i-2: c -move-> d
160 o 2 i-2: c -move-> d
161 |
161 |
162 o 1 i-1: a -move-> c
162 o 1 i-1: a -move-> c
163 |
163 |
164 o 0 i-0 initial commit: a b h
164 o 0 i-0 initial commit: a b h
165
165
166
166
167 Setup all merge
167 Setup all merge
168 ===============
168 ===============
169
169
170 This is done beforehand to validate that the upgrade process creates valid copy
170 This is done beforehand to validate that the upgrade process creates valid copy
171 information.
171 information.
172
172
173 merging with unrelated change does not interfere with the renames
173 merging with unrelated change does not interfere with the renames
174 ---------------------------------------------------------------
174 ---------------------------------------------------------------
175
175
176 - rename on one side
176 - rename on one side
177 - unrelated change on the other side
177 - unrelated change on the other side
178
178
179 $ hg up 'desc("b-1")'
179 $ hg up 'desc("b-1")'
180 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
180 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
181 $ hg merge 'desc("a-2")'
181 $ hg merge 'desc("a-2")'
182 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
182 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
183 (branch merge, don't forget to commit)
183 (branch merge, don't forget to commit)
184 $ hg ci -m 'mBAm-0 simple merge - one way'
184 $ hg ci -m 'mBAm-0 simple merge - one way'
185 $ hg up 'desc("a-2")'
185 $ hg up 'desc("a-2")'
186 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
187 $ hg merge 'desc("b-1")'
187 $ hg merge 'desc("b-1")'
188 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
188 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 (branch merge, don't forget to commit)
189 (branch merge, don't forget to commit)
190 $ hg ci -m 'mABm-0 simple merge - the other way'
190 $ hg ci -m 'mABm-0 simple merge - the other way'
191 created new head
191 created new head
192 $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))'
192 $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))'
193 @ 12 mABm-0 simple merge - the other way
193 @ 12 mABm-0 simple merge - the other way
194 |\
194 |\
195 +---o 11 mBAm-0 simple merge - one way
195 +---o 11 mBAm-0 simple merge - one way
196 | |/
196 | |/
197 | o 5 b-1: b update
197 | o 5 b-1: b update
198 | |
198 | |
199 o | 4 a-2: e -move-> f
199 o | 4 a-2: e -move-> f
200 | |
200 | |
201 o | 3 a-1: d -move-> e
201 o | 3 a-1: d -move-> e
202 |/
202 |/
203 o 2 i-2: c -move-> d
203 o 2 i-2: c -move-> d
204 |
204 |
205 o 1 i-1: a -move-> c
205 o 1 i-1: a -move-> c
206 |
206 |
207 o 0 i-0 initial commit: a b h
207 o 0 i-0 initial commit: a b h
208
208
209
209
210
210
211 merging with the side having a delete
211 merging with the side having a delete
212 -------------------------------------
212 -------------------------------------
213
213
214 case summary:
214 case summary:
215 - one with change to an unrelated file
215 - one with change to an unrelated file
216 - one deleting the change
216 - one deleting the change
217 and recreate an unrelated file after the merge
217 and recreate an unrelated file after the merge
218
218
219 $ hg up 'desc("b-1")'
219 $ hg up 'desc("b-1")'
220 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
220 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
221 $ hg merge 'desc("c-1")'
221 $ hg merge 'desc("c-1")'
222 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
222 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
223 (branch merge, don't forget to commit)
223 (branch merge, don't forget to commit)
224 $ hg ci -m 'mBCm-0 simple merge - one way'
224 $ hg ci -m 'mBCm-0 simple merge - one way'
225 $ echo bar > d
225 $ echo bar > d
226 $ hg add d
226 $ hg add d
227 $ hg ci -m 'mBCm-1 re-add d'
227 $ hg ci -m 'mBCm-1 re-add d'
228 $ hg up 'desc("c-1")'
228 $ hg up 'desc("c-1")'
229 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
229 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
230 $ hg merge 'desc("b-1")'
230 $ hg merge 'desc("b-1")'
231 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
231 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
232 (branch merge, don't forget to commit)
232 (branch merge, don't forget to commit)
233 $ hg ci -m 'mCBm-0 simple merge - the other way'
233 $ hg ci -m 'mCBm-0 simple merge - the other way'
234 created new head
234 created new head
235 $ echo bar > d
235 $ echo bar > d
236 $ hg add d
236 $ hg add d
237 $ hg ci -m 'mCBm-1 re-add d'
237 $ hg ci -m 'mCBm-1 re-add d'
238 $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))'
238 $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))'
239 @ 16 mCBm-1 re-add d
239 @ 16 mCBm-1 re-add d
240 |
240 |
241 o 15 mCBm-0 simple merge - the other way
241 o 15 mCBm-0 simple merge - the other way
242 |\
242 |\
243 | | o 14 mBCm-1 re-add d
243 | | o 14 mBCm-1 re-add d
244 | | |
244 | | |
245 +---o 13 mBCm-0 simple merge - one way
245 +---o 13 mBCm-0 simple merge - one way
246 | |/
246 | |/
247 | o 6 c-1 delete d
247 | o 6 c-1 delete d
248 | |
248 | |
249 o | 5 b-1: b update
249 o | 5 b-1: b update
250 |/
250 |/
251 o 2 i-2: c -move-> d
251 o 2 i-2: c -move-> d
252 |
252 |
253 o 1 i-1: a -move-> c
253 o 1 i-1: a -move-> c
254 |
254 |
255 o 0 i-0 initial commit: a b h
255 o 0 i-0 initial commit: a b h
256
256
257
257
258 Comparing with a merge re-adding the file afterward
258 Comparing with a merge re-adding the file afterward
259 ---------------------------------------------------
259 ---------------------------------------------------
260
260
261 Merge:
261 Merge:
262 - one with change to an unrelated file
262 - one with change to an unrelated file
263 - one deleting and recreating the change
263 - one deleting and recreating the change
264
264
265 $ hg up 'desc("b-1")'
265 $ hg up 'desc("b-1")'
266 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
266 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
267 $ hg merge 'desc("d-2")'
267 $ hg merge 'desc("d-2")'
268 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
268 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
269 (branch merge, don't forget to commit)
269 (branch merge, don't forget to commit)
270 $ hg ci -m 'mBDm-0 simple merge - one way'
270 $ hg ci -m 'mBDm-0 simple merge - one way'
271 $ hg up 'desc("d-2")'
271 $ hg up 'desc("d-2")'
272 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
272 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
273 $ hg merge 'desc("b-1")'
273 $ hg merge 'desc("b-1")'
274 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
274 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
275 (branch merge, don't forget to commit)
275 (branch merge, don't forget to commit)
276 $ hg ci -m 'mDBm-0 simple merge - the other way'
276 $ hg ci -m 'mDBm-0 simple merge - the other way'
277 created new head
277 created new head
278 $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))'
278 $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))'
279 @ 18 mDBm-0 simple merge - the other way
279 @ 18 mDBm-0 simple merge - the other way
280 |\
280 |\
281 +---o 17 mBDm-0 simple merge - one way
281 +---o 17 mBDm-0 simple merge - one way
282 | |/
282 | |/
283 | o 8 d-2 re-add d
283 | o 8 d-2 re-add d
284 | |
284 | |
285 | o 7 d-1 delete d
285 | o 7 d-1 delete d
286 | |
286 | |
287 o | 5 b-1: b update
287 o | 5 b-1: b update
288 |/
288 |/
289 o 2 i-2: c -move-> d
289 o 2 i-2: c -move-> d
290 |
290 |
291 o 1 i-1: a -move-> c
291 o 1 i-1: a -move-> c
292 |
292 |
293 o 0 i-0 initial commit: a b h
293 o 0 i-0 initial commit: a b h
294
294
295
295
296
296
297 Comparing with a merge with colliding rename
297 Comparing with a merge with colliding rename
298 --------------------------------------------
298 --------------------------------------------
299
299
300 - the "e-" branch renaming b to f (through 'g')
300 - the "e-" branch renaming b to f (through 'g')
301 - the "a-" branch renaming d to f (through e)
301 - the "a-" branch renaming d to f (through e)
302
302
303 $ hg up 'desc("a-2")'
303 $ hg up 'desc("a-2")'
304 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
304 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
305 $ hg merge 'desc("e-2")' --tool :union
305 $ hg merge 'desc("e-2")' --tool :union
306 merging f
306 merging f
307 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
307 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
308 (branch merge, don't forget to commit)
308 (branch merge, don't forget to commit)
309 $ hg ci -m 'mAEm-0 simple merge - one way'
309 $ hg ci -m 'mAEm-0 simple merge - one way'
310 $ hg up 'desc("e-2")'
310 $ hg up 'desc("e-2")'
311 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
311 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
312 $ hg merge 'desc("a-2")' --tool :union
312 $ hg merge 'desc("a-2")' --tool :union
313 merging f
313 merging f
314 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
314 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
315 (branch merge, don't forget to commit)
315 (branch merge, don't forget to commit)
316 $ hg ci -m 'mEAm-0 simple merge - the other way'
316 $ hg ci -m 'mEAm-0 simple merge - the other way'
317 created new head
317 created new head
318 $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))'
318 $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))'
319 @ 20 mEAm-0 simple merge - the other way
319 @ 20 mEAm-0 simple merge - the other way
320 |\
320 |\
321 +---o 19 mAEm-0 simple merge - one way
321 +---o 19 mAEm-0 simple merge - one way
322 | |/
322 | |/
323 | o 10 e-2 g -move-> f
323 | o 10 e-2 g -move-> f
324 | |
324 | |
325 | o 9 e-1 b -move-> g
325 | o 9 e-1 b -move-> g
326 | |
326 | |
327 o | 4 a-2: e -move-> f
327 o | 4 a-2: e -move-> f
328 | |
328 | |
329 o | 3 a-1: d -move-> e
329 o | 3 a-1: d -move-> e
330 |/
330 |/
331 o 2 i-2: c -move-> d
331 o 2 i-2: c -move-> d
332 |
332 |
333 o 1 i-1: a -move-> c
333 o 1 i-1: a -move-> c
334 |
334 |
335 o 0 i-0 initial commit: a b h
335 o 0 i-0 initial commit: a b h
336
336
337
337
338
338
339 Merge:
339 Merge:
340 - one with change to an unrelated file (b)
340 - one with change to an unrelated file (b)
341 - one overwriting a file (d) with a rename (from h to i to d)
341 - one overwriting a file (d) with a rename (from h to i to d)
342
342
343 $ hg up 'desc("i-2")'
343 $ hg up 'desc("i-2")'
344 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
344 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
345 $ hg mv h i
345 $ hg mv h i
346 $ hg commit -m "f-1: rename h -> i"
346 $ hg commit -m "f-1: rename h -> i"
347 created new head
347 created new head
348 $ hg mv --force i d
348 $ hg mv --force i d
349 $ hg commit -m "f-2: rename i -> d"
349 $ hg commit -m "f-2: rename i -> d"
350 $ hg debugindex d
350 $ hg debugindex d
351 rev linkrev nodeid p1 p2
351 rev linkrev nodeid p1 p2
352 0 2 169be882533b 000000000000 000000000000 (no-changeset !)
352 0 2 169be882533b 000000000000 000000000000 (no-changeset !)
353 0 2 b789fdd96dc2 000000000000 000000000000 (changeset !)
353 0 2 b789fdd96dc2 000000000000 000000000000 (changeset !)
354 1 8 b004912a8510 000000000000 000000000000
354 1 8 b004912a8510 000000000000 000000000000
355 2 22 4a067cf8965d 000000000000 000000000000 (no-changeset !)
355 2 22 4a067cf8965d 000000000000 000000000000 (no-changeset !)
356 2 22 fe6f8b4f507f 000000000000 000000000000 (changeset !)
356 2 22 fe6f8b4f507f 000000000000 000000000000 (changeset !)
357 $ hg up 'desc("b-1")'
357 $ hg up 'desc("b-1")'
358 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
358 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
359 $ hg merge 'desc("f-2")'
359 $ hg merge 'desc("f-2")'
360 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
360 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
361 (branch merge, don't forget to commit)
361 (branch merge, don't forget to commit)
362 $ hg ci -m 'mBFm-0 simple merge - one way'
362 $ hg ci -m 'mBFm-0 simple merge - one way'
363 $ hg up 'desc("f-2")'
363 $ hg up 'desc("f-2")'
364 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
364 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
365 $ hg merge 'desc("b-1")'
365 $ hg merge 'desc("b-1")'
366 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
366 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
367 (branch merge, don't forget to commit)
367 (branch merge, don't forget to commit)
368 $ hg ci -m 'mFBm-0 simple merge - the other way'
368 $ hg ci -m 'mFBm-0 simple merge - the other way'
369 created new head
369 created new head
370 $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))'
370 $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))'
371 @ 24 mFBm-0 simple merge - the other way
371 @ 24 mFBm-0 simple merge - the other way
372 |\
372 |\
373 +---o 23 mBFm-0 simple merge - one way
373 +---o 23 mBFm-0 simple merge - one way
374 | |/
374 | |/
375 | o 22 f-2: rename i -> d
375 | o 22 f-2: rename i -> d
376 | |
376 | |
377 | o 21 f-1: rename h -> i
377 | o 21 f-1: rename h -> i
378 | |
378 | |
379 o | 5 b-1: b update
379 o | 5 b-1: b update
380 |/
380 |/
381 o 2 i-2: c -move-> d
381 o 2 i-2: c -move-> d
382 |
382 |
383 o 1 i-1: a -move-> c
383 o 1 i-1: a -move-> c
384 |
384 |
385 o 0 i-0 initial commit: a b h
385 o 0 i-0 initial commit: a b h
386
386
387
387
388
388
389 Merge:
389 Merge:
390 - one with change to a file
390 - one with change to a file
391 - one deleting and recreating the file
391 - one deleting and recreating the file
392
392
393 Unlike in the 'BD/DB' cases, an actual merge happened here. So we should
393 Unlike in the 'BD/DB' cases, an actual merge happened here. So we should
394 consider history and rename on both branch of the merge.
394 consider history and rename on both branch of the merge.
395
395
396 $ hg up 'desc("i-2")'
396 $ hg up 'desc("i-2")'
397 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
397 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
398 $ echo "some update" >> d
398 $ echo "some update" >> d
399 $ hg commit -m "g-1: update d"
399 $ hg commit -m "g-1: update d"
400 created new head
400 created new head
401 $ hg up 'desc("d-2")'
401 $ hg up 'desc("d-2")'
402 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
402 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
403 $ hg merge 'desc("g-1")' --tool :union
403 $ hg merge 'desc("g-1")' --tool :union
404 merging d
404 merging d
405 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
405 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
406 (branch merge, don't forget to commit)
406 (branch merge, don't forget to commit)
407 $ hg ci -m 'mDGm-0 simple merge - one way'
407 $ hg ci -m 'mDGm-0 simple merge - one way'
408 $ hg up 'desc("g-1")'
408 $ hg up 'desc("g-1")'
409 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
409 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
410 $ hg merge 'desc("d-2")' --tool :union
410 $ hg merge 'desc("d-2")' --tool :union
411 merging d
411 merging d
412 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
412 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
413 (branch merge, don't forget to commit)
413 (branch merge, don't forget to commit)
414 $ hg ci -m 'mGDm-0 simple merge - the other way'
414 $ hg ci -m 'mGDm-0 simple merge - the other way'
415 created new head
415 created new head
416 $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))'
416 $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))'
417 @ 27 mGDm-0 simple merge - the other way
417 @ 27 mGDm-0 simple merge - the other way
418 |\
418 |\
419 +---o 26 mDGm-0 simple merge - one way
419 +---o 26 mDGm-0 simple merge - one way
420 | |/
420 | |/
421 | o 25 g-1: update d
421 | o 25 g-1: update d
422 | |
422 | |
423 o | 8 d-2 re-add d
423 o | 8 d-2 re-add d
424 | |
424 | |
425 o | 7 d-1 delete d
425 o | 7 d-1 delete d
426 |/
426 |/
427 o 2 i-2: c -move-> d
427 o 2 i-2: c -move-> d
428 |
428 |
429 o 1 i-1: a -move-> c
429 o 1 i-1: a -move-> c
430 |
430 |
431 o 0 i-0 initial commit: a b h
431 o 0 i-0 initial commit: a b h
432
432
433
433
434
434
435 Merge:
435 Merge:
436 - one with change to a file (d)
436 - one with change to a file (d)
437 - one overwriting that file with a rename (from h to i, to d)
437 - one overwriting that file with a rename (from h to i, to d)
438
438
439 This case is similar to BF/FB, but an actual merge happens, so both side of the
439 This case is similar to BF/FB, but an actual merge happens, so both side of the
440 history are relevant.
440 history are relevant.
441
441
442 Note:
442 Note:
443 | In this case, the merge get conflicting information since on one side we have
443 | In this case, the merge get conflicting information since on one side we have
444 | "a -> c -> d". and one the other one we have "h -> i -> d".
444 | "a -> c -> d". and one the other one we have "h -> i -> d".
445 |
445 |
446 | The current code arbitrarily pick one side
446 | The current code arbitrarily pick one side
447
447
448 $ hg up 'desc("f-2")'
448 $ hg up 'desc("f-2")'
449 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
449 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
450 $ hg merge 'desc("g-1")' --tool :union
450 $ hg merge 'desc("g-1")' --tool :union
451 merging d
451 merging d
452 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
452 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
453 (branch merge, don't forget to commit)
453 (branch merge, don't forget to commit)
454 $ hg ci -m 'mFGm-0 simple merge - one way'
454 $ hg ci -m 'mFGm-0 simple merge - one way'
455 created new head
455 created new head
456 $ hg up 'desc("g-1")'
456 $ hg up 'desc("g-1")'
457 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
457 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
458 $ hg merge 'desc("f-2")' --tool :union
458 $ hg merge 'desc("f-2")' --tool :union
459 merging d
459 merging d
460 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
460 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
461 (branch merge, don't forget to commit)
461 (branch merge, don't forget to commit)
462 $ hg ci -m 'mGFm-0 simple merge - the other way'
462 $ hg ci -m 'mGFm-0 simple merge - the other way'
463 created new head
463 created new head
464 $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))'
464 $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))'
465 @ 29 mGFm-0 simple merge - the other way
465 @ 29 mGFm-0 simple merge - the other way
466 |\
466 |\
467 +---o 28 mFGm-0 simple merge - one way
467 +---o 28 mFGm-0 simple merge - one way
468 | |/
468 | |/
469 | o 25 g-1: update d
469 | o 25 g-1: update d
470 | |
470 | |
471 o | 22 f-2: rename i -> d
471 o | 22 f-2: rename i -> d
472 | |
472 | |
473 o | 21 f-1: rename h -> i
473 o | 21 f-1: rename h -> i
474 |/
474 |/
475 o 2 i-2: c -move-> d
475 o 2 i-2: c -move-> d
476 |
476 |
477 o 1 i-1: a -move-> c
477 o 1 i-1: a -move-> c
478 |
478 |
479 o 0 i-0 initial commit: a b h
479 o 0 i-0 initial commit: a b h
480
480
481
481
482
482
483 Comparing with merging with a deletion (and keeping the file)
483 Comparing with merging with a deletion (and keeping the file)
484 -------------------------------------------------------------
484 -------------------------------------------------------------
485
485
486 Merge:
486 Merge:
487 - one removing a file (d)
487 - one removing a file (d)
488 - one updating that file
488 - one updating that file
489 - the merge keep the modified version of the file (canceling the delete)
489 - the merge keep the modified version of the file (canceling the delete)
490
490
491 In this case, the file keep on living after the merge. So we should not drop its
491 In this case, the file keep on living after the merge. So we should not drop its
492 copy tracing chain.
492 copy tracing chain.
493
493
494 $ hg up 'desc("c-1")'
494 $ hg up 'desc("c-1")'
495 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
495 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
496 $ hg merge 'desc("g-1")'
496 $ hg merge 'desc("g-1")'
497 file 'd' was deleted in local [working copy] but was modified in other [merge rev].
497 file 'd' was deleted in local [working copy] but was modified in other [merge rev].
498 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
498 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
499 What do you want to do? u
499 What do you want to do? u
500 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
500 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
501 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
501 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
502 [1]
502 [1]
503 $ hg resolve -t :other d
503 $ hg resolve -t :other d
504 (no more unresolved files)
504 (no more unresolved files)
505 $ hg ci -m "mCGm-0"
505 $ hg ci -m "mCGm-0"
506 created new head
506 created new head
507
507
508 $ hg up 'desc("g-1")'
508 $ hg up 'desc("g-1")'
509 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
509 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
510 $ hg merge 'desc("c-1")'
510 $ hg merge 'desc("c-1")'
511 file 'd' was deleted in other [merge rev] but was modified in local [working copy].
511 file 'd' was deleted in other [merge rev] but was modified in local [working copy].
512 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
512 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
513 What do you want to do? u
513 What do you want to do? u
514 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
514 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
515 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
515 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
516 [1]
516 [1]
517 $ hg resolve -t :local d
517 $ hg resolve -t :local d
518 (no more unresolved files)
518 (no more unresolved files)
519 $ hg ci -m "mGCm-0"
519 $ hg ci -m "mGCm-0"
520 created new head
520 created new head
521
521
522 $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))'
522 $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))'
523 @ 31 mGCm-0
523 @ 31 mGCm-0
524 |\
524 |\
525 +---o 30 mCGm-0
525 +---o 30 mCGm-0
526 | |/
526 | |/
527 | o 25 g-1: update d
527 | o 25 g-1: update d
528 | |
528 | |
529 o | 6 c-1 delete d
529 o | 6 c-1 delete d
530 |/
530 |/
531 o 2 i-2: c -move-> d
531 o 2 i-2: c -move-> d
532 |
532 |
533 o 1 i-1: a -move-> c
533 o 1 i-1: a -move-> c
534 |
534 |
535 o 0 i-0 initial commit: a b h
535 o 0 i-0 initial commit: a b h
536
536
537
537
538
538
539
539
540 Comparing with merge restoring an untouched deleted file
540 Comparing with merge restoring an untouched deleted file
541 --------------------------------------------------------
541 --------------------------------------------------------
542
542
543 Merge:
543 Merge:
544 - one removing a file (d)
544 - one removing a file (d)
545 - one leaving the file untouched
545 - one leaving the file untouched
546 - the merge actively restore the file to the same content.
546 - the merge actively restore the file to the same content.
547
547
548 In this case, the file keep on living after the merge. So we should not drop its
548 In this case, the file keep on living after the merge. So we should not drop its
549 copy tracing chain.
549 copy tracing chain.
550
550
551 $ hg up 'desc("c-1")'
551 $ hg up 'desc("c-1")'
552 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
552 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
553 $ hg merge 'desc("b-1")'
553 $ hg merge 'desc("b-1")'
554 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
554 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
555 (branch merge, don't forget to commit)
555 (branch merge, don't forget to commit)
556 $ hg revert --rev 'desc("b-1")' d
556 $ hg revert --rev 'desc("b-1")' d
557 $ hg ci -m "mCB-revert-m-0"
557 $ hg ci -m "mCB-revert-m-0"
558 created new head
558 created new head
559
559
560 $ hg up 'desc("b-1")'
560 $ hg up 'desc("b-1")'
561 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
561 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
562 $ hg merge 'desc("c-1")'
562 $ hg merge 'desc("c-1")'
563 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
563 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
564 (branch merge, don't forget to commit)
564 (branch merge, don't forget to commit)
565 $ hg revert --rev 'desc("b-1")' d
565 $ hg revert --rev 'desc("b-1")' d
566 $ hg ci -m "mBC-revert-m-0"
566 $ hg ci -m "mBC-revert-m-0"
567 created new head
567 created new head
568
568
569 $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))'
569 $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))'
570 @ 33 mBC-revert-m-0
570 @ 33 mBC-revert-m-0
571 |\
571 |\
572 +---o 32 mCB-revert-m-0
572 +---o 32 mCB-revert-m-0
573 | |/
573 | |/
574 | o 6 c-1 delete d
574 | o 6 c-1 delete d
575 | |
575 | |
576 o | 5 b-1: b update
576 o | 5 b-1: b update
577 |/
577 |/
578 o 2 i-2: c -move-> d
578 o 2 i-2: c -move-> d
579 |
579 |
580 o 1 i-1: a -move-> c
580 o 1 i-1: a -move-> c
581 |
581 |
582 o 0 i-0 initial commit: a b h
582 o 0 i-0 initial commit: a b h
583
583
584
584
585
585
586 $ hg up null --quiet
586 $ hg up null --quiet
587
587
588 Merging a branch where a rename was deleted with a branch where the same file was renamed
588 Merging a branch where a rename was deleted with a branch where the same file was renamed
589 ------------------------------------------------------------------------------------------
589 ------------------------------------------------------------------------------------------
590
590
591 Create a "conflicting" merge where `d` get removed on one branch before its
591 Create a "conflicting" merge where `d` get removed on one branch before its
592 rename information actually conflict with the other branch.
592 rename information actually conflict with the other branch.
593
593
594 (the copy information from the branch that was not deleted should win).
594 (the copy information from the branch that was not deleted should win).
595
595
596 $ hg up 'desc("i-0")'
596 $ hg up 'desc("i-0")'
597 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
597 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
598 $ hg mv b d
598 $ hg mv b d
599 $ hg ci -m "h-1: b -(move)-> d"
599 $ hg ci -m "h-1: b -(move)-> d"
600 created new head
600 created new head
601
601
602 $ hg up 'desc("c-1")'
602 $ hg up 'desc("c-1")'
603 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
603 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
604 $ hg merge 'desc("h-1")'
604 $ hg merge 'desc("h-1")'
605 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
605 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
606 (branch merge, don't forget to commit)
606 (branch merge, don't forget to commit)
607 $ hg ci -m "mCH-delete-before-conflict-m-0"
607 $ hg ci -m "mCH-delete-before-conflict-m-0"
608
608
609 $ hg up 'desc("h-1")'
609 $ hg up 'desc("h-1")'
610 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
610 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
611 $ hg merge 'desc("c-1")'
611 $ hg merge 'desc("c-1")'
612 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
612 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
613 (branch merge, don't forget to commit)
613 (branch merge, don't forget to commit)
614 $ hg ci -m "mHC-delete-before-conflict-m-0"
614 $ hg ci -m "mHC-delete-before-conflict-m-0"
615 created new head
615 created new head
616 $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))'
616 $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))'
617 @ 36 mHC-delete-before-conflict-m-0
617 @ 36 mHC-delete-before-conflict-m-0
618 |\
618 |\
619 +---o 35 mCH-delete-before-conflict-m-0
619 +---o 35 mCH-delete-before-conflict-m-0
620 | |/
620 | |/
621 | o 34 h-1: b -(move)-> d
621 | o 34 h-1: b -(move)-> d
622 | |
622 | |
623 o | 6 c-1 delete d
623 o | 6 c-1 delete d
624 | |
624 | |
625 o | 2 i-2: c -move-> d
625 o | 2 i-2: c -move-> d
626 | |
626 | |
627 o | 1 i-1: a -move-> c
627 o | 1 i-1: a -move-> c
628 |/
628 |/
629 o 0 i-0 initial commit: a b h
629 o 0 i-0 initial commit: a b h
630
630
631
631
632
632
633 Summary of all created cases
633 Summary of all created cases
634 ----------------------------
634 ----------------------------
635
635
636 $ hg up --quiet null
636 $ hg up --quiet null
637
637
638 (This exists to help keeping a compact list of the various cases we have built)
638 (This exists to help keeping a compact list of the various cases we have built)
639
639
640 $ hg log -T '{desc|firstline}\n'| sort
640 $ hg log -T '{desc|firstline}\n'| sort
641 a-1: d -move-> e
641 a-1: d -move-> e
642 a-2: e -move-> f
642 a-2: e -move-> f
643 b-1: b update
643 b-1: b update
644 c-1 delete d
644 c-1 delete d
645 d-1 delete d
645 d-1 delete d
646 d-2 re-add d
646 d-2 re-add d
647 e-1 b -move-> g
647 e-1 b -move-> g
648 e-2 g -move-> f
648 e-2 g -move-> f
649 f-1: rename h -> i
649 f-1: rename h -> i
650 f-2: rename i -> d
650 f-2: rename i -> d
651 g-1: update d
651 g-1: update d
652 h-1: b -(move)-> d
652 h-1: b -(move)-> d
653 i-0 initial commit: a b h
653 i-0 initial commit: a b h
654 i-1: a -move-> c
654 i-1: a -move-> c
655 i-2: c -move-> d
655 i-2: c -move-> d
656 mABm-0 simple merge - the other way
656 mABm-0 simple merge - the other way
657 mAEm-0 simple merge - one way
657 mAEm-0 simple merge - one way
658 mBAm-0 simple merge - one way
658 mBAm-0 simple merge - one way
659 mBC-revert-m-0
659 mBC-revert-m-0
660 mBCm-0 simple merge - one way
660 mBCm-0 simple merge - one way
661 mBCm-1 re-add d
661 mBCm-1 re-add d
662 mBDm-0 simple merge - one way
662 mBDm-0 simple merge - one way
663 mBFm-0 simple merge - one way
663 mBFm-0 simple merge - one way
664 mCB-revert-m-0
664 mCB-revert-m-0
665 mCBm-0 simple merge - the other way
665 mCBm-0 simple merge - the other way
666 mCBm-1 re-add d
666 mCBm-1 re-add d
667 mCGm-0
667 mCGm-0
668 mCH-delete-before-conflict-m-0
668 mCH-delete-before-conflict-m-0
669 mDBm-0 simple merge - the other way
669 mDBm-0 simple merge - the other way
670 mDGm-0 simple merge - one way
670 mDGm-0 simple merge - one way
671 mEAm-0 simple merge - the other way
671 mEAm-0 simple merge - the other way
672 mFBm-0 simple merge - the other way
672 mFBm-0 simple merge - the other way
673 mFGm-0 simple merge - one way
673 mFGm-0 simple merge - one way
674 mGCm-0
674 mGCm-0
675 mGDm-0 simple merge - the other way
675 mGDm-0 simple merge - the other way
676 mGFm-0 simple merge - the other way
676 mGFm-0 simple merge - the other way
677 mHC-delete-before-conflict-m-0
677 mHC-delete-before-conflict-m-0
678
678
679
679
680 Test that sidedata computations during upgrades are correct
680 Test that sidedata computations during upgrades are correct
681 ===========================================================
681 ===========================================================
682
682
683 We upgrade a repository that is not using sidedata (the filelog case) and
683 We upgrade a repository that is not using sidedata (the filelog case) and
684 check that the same side data have been generated as if they were computed at
684 check that the same side data have been generated as if they were computed at
685 commit time.
685 commit time.
686
686
687
687
688 #if upgraded
688 #if upgraded
689 $ cat >> $HGRCPATH << EOF
689 $ cat >> $HGRCPATH << EOF
690 > [format]
690 > [format]
691 > exp-use-side-data = yes
691 > exp-use-side-data = yes
692 > exp-use-copies-side-data-changeset = yes
692 > exp-use-copies-side-data-changeset = yes
693 > EOF
693 > EOF
694 $ hg debugformat -v
694 $ hg debugformat -v
695 format-variant repo config default
695 format-variant repo config default
696 fncache: yes yes yes
696 fncache: yes yes yes
697 dotencode: yes yes yes
697 dotencode: yes yes yes
698 generaldelta: yes yes yes
698 generaldelta: yes yes yes
699 share-safe: no no no
699 share-safe: no no no
700 sparserevlog: yes yes yes
700 sparserevlog: yes yes yes
701 sidedata: no yes no
701 sidedata: no yes no
702 persistent-nodemap: no no no
702 persistent-nodemap: no no no
703 copies-sdc: no yes no
703 copies-sdc: no yes no
704 plain-cl-delta: yes yes yes
704 plain-cl-delta: yes yes yes
705 compression: * (glob)
705 compression: * (glob)
706 compression-level: default default default
706 compression-level: default default default
707 $ hg debugupgraderepo --run --quiet
707 $ hg debugupgraderepo --run --quiet
708 upgrade will perform the following actions:
708 upgrade will perform the following actions:
709
709
710 requirements
710 requirements
711 preserved: * (glob)
711 preserved: * (glob)
712 added: exp-copies-sidedata-changeset, exp-sidedata-flag
712 added: exp-copies-sidedata-changeset, exp-sidedata-flag
713
713
714 processed revlogs:
714 processed revlogs:
715 - all-filelogs
715 - all-filelogs
716 - changelog
716 - changelog
717 - manifest
717 - manifest
718
718
719 #endif
719 #endif
720
720
721
721
722 #if no-compatibility no-filelog no-changeset
722 #if no-compatibility no-filelog no-changeset
723
723
724 $ hg debugchangedfiles --compute 0
725 added : a, ;
726 added : b, ;
727 added : h, ;
728
724 $ for rev in `hg log --rev 'all()' -T '{rev}\n'`; do
729 $ for rev in `hg log --rev 'all()' -T '{rev}\n'`; do
725 > echo "##### revision $rev #####"
730 > echo "##### revision $rev #####"
726 > hg debugsidedata -c -v -- $rev
731 > hg debugsidedata -c -v -- $rev
727 > hg debugchangedfiles $rev
732 > hg debugchangedfiles $rev
728 > done
733 > done
729 ##### revision 0 #####
734 ##### revision 0 #####
730 1 sidedata entries
735 1 sidedata entries
731 entry-0014 size 34
736 entry-0014 size 34
732 '\x00\x00\x00\x03\x04\x00\x00\x00\x01\x00\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x00abh'
737 '\x00\x00\x00\x03\x04\x00\x00\x00\x01\x00\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x00abh'
733 added : a, ;
738 added : a, ;
734 added : b, ;
739 added : b, ;
735 added : h, ;
740 added : h, ;
736 ##### revision 1 #####
741 ##### revision 1 #####
737 1 sidedata entries
742 1 sidedata entries
738 entry-0014 size 24
743 entry-0014 size 24
739 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ac'
744 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ac'
740 removed : a, ;
745 removed : a, ;
741 added p1: c, a;
746 added p1: c, a;
742 ##### revision 2 #####
747 ##### revision 2 #####
743 1 sidedata entries
748 1 sidedata entries
744 entry-0014 size 24
749 entry-0014 size 24
745 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00cd'
750 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00cd'
746 removed : c, ;
751 removed : c, ;
747 added p1: d, c;
752 added p1: d, c;
748 ##### revision 3 #####
753 ##### revision 3 #####
749 1 sidedata entries
754 1 sidedata entries
750 entry-0014 size 24
755 entry-0014 size 24
751 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00de'
756 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00de'
752 removed : d, ;
757 removed : d, ;
753 added p1: e, d;
758 added p1: e, d;
754 ##### revision 4 #####
759 ##### revision 4 #####
755 1 sidedata entries
760 1 sidedata entries
756 entry-0014 size 24
761 entry-0014 size 24
757 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ef'
762 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ef'
758 removed : e, ;
763 removed : e, ;
759 added p1: f, e;
764 added p1: f, e;
760 ##### revision 5 #####
765 ##### revision 5 #####
761 1 sidedata entries
766 1 sidedata entries
762 entry-0014 size 14
767 entry-0014 size 14
763 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00b'
768 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00b'
764 touched : b, ;
769 touched : b, ;
765 ##### revision 6 #####
770 ##### revision 6 #####
766 1 sidedata entries
771 1 sidedata entries
767 entry-0014 size 14
772 entry-0014 size 14
768 '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d'
773 '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d'
769 removed : d, ;
774 removed : d, ;
770 ##### revision 7 #####
775 ##### revision 7 #####
771 1 sidedata entries
776 1 sidedata entries
772 entry-0014 size 14
777 entry-0014 size 14
773 '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d'
778 '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d'
774 removed : d, ;
779 removed : d, ;
775 ##### revision 8 #####
780 ##### revision 8 #####
776 1 sidedata entries
781 1 sidedata entries
777 entry-0014 size 14
782 entry-0014 size 14
778 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
783 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
779 added : d, ;
784 added : d, ;
780 ##### revision 9 #####
785 ##### revision 9 #####
781 1 sidedata entries
786 1 sidedata entries
782 entry-0014 size 24
787 entry-0014 size 24
783 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bg'
788 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bg'
784 removed : b, ;
789 removed : b, ;
785 added p1: g, b;
790 added p1: g, b;
786 ##### revision 10 #####
791 ##### revision 10 #####
787 1 sidedata entries
792 1 sidedata entries
788 entry-0014 size 24
793 entry-0014 size 24
789 '\x00\x00\x00\x02\x06\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00fg'
794 '\x00\x00\x00\x02\x06\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00fg'
790 added p1: f, g;
795 added p1: f, g;
791 removed : g, ;
796 removed : g, ;
792 ##### revision 11 #####
797 ##### revision 11 #####
793 1 sidedata entries
798 1 sidedata entries
794 entry-0014 size 4
799 entry-0014 size 4
795 '\x00\x00\x00\x00'
800 '\x00\x00\x00\x00'
796 ##### revision 12 #####
801 ##### revision 12 #####
797 1 sidedata entries
802 1 sidedata entries
798 entry-0014 size 4
803 entry-0014 size 4
799 '\x00\x00\x00\x00'
804 '\x00\x00\x00\x00'
800 ##### revision 13 #####
805 ##### revision 13 #####
801 1 sidedata entries
806 1 sidedata entries
802 entry-0014 size 4
807 entry-0014 size 4
803 '\x00\x00\x00\x00'
808 '\x00\x00\x00\x00'
804 ##### revision 14 #####
809 ##### revision 14 #####
805 1 sidedata entries
810 1 sidedata entries
806 entry-0014 size 14
811 entry-0014 size 14
807 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
812 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
808 added : d, ;
813 added : d, ;
809 ##### revision 15 #####
814 ##### revision 15 #####
810 1 sidedata entries
815 1 sidedata entries
811 entry-0014 size 4
816 entry-0014 size 4
812 '\x00\x00\x00\x00'
817 '\x00\x00\x00\x00'
813 ##### revision 16 #####
818 ##### revision 16 #####
814 1 sidedata entries
819 1 sidedata entries
815 entry-0014 size 14
820 entry-0014 size 14
816 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
821 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
817 added : d, ;
822 added : d, ;
818 ##### revision 17 #####
823 ##### revision 17 #####
819 1 sidedata entries
824 1 sidedata entries
820 entry-0014 size 4
825 entry-0014 size 4
821 '\x00\x00\x00\x00'
826 '\x00\x00\x00\x00'
822 ##### revision 18 #####
827 ##### revision 18 #####
823 1 sidedata entries
828 1 sidedata entries
824 entry-0014 size 4
829 entry-0014 size 4
825 '\x00\x00\x00\x00'
830 '\x00\x00\x00\x00'
826 ##### revision 19 #####
831 ##### revision 19 #####
827 1 sidedata entries
832 1 sidedata entries
828 entry-0014 size 14
833 entry-0014 size 14
829 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
834 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
830 merged : f, ;
835 merged : f, ;
831 ##### revision 20 #####
836 ##### revision 20 #####
832 1 sidedata entries
837 1 sidedata entries
833 entry-0014 size 14
838 entry-0014 size 14
834 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
839 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
835 merged : f, ;
840 merged : f, ;
836 ##### revision 21 #####
841 ##### revision 21 #####
837 1 sidedata entries
842 1 sidedata entries
838 entry-0014 size 24
843 entry-0014 size 24
839 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00hi'
844 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00hi'
840 removed : h, ;
845 removed : h, ;
841 added p1: i, h;
846 added p1: i, h;
842 ##### revision 22 #####
847 ##### revision 22 #####
843 1 sidedata entries
848 1 sidedata entries
844 entry-0014 size 24
849 entry-0014 size 24
845 '\x00\x00\x00\x02\x16\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00di'
850 '\x00\x00\x00\x02\x16\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00di'
846 touched p1: d, i;
851 touched p1: d, i;
847 removed : i, ;
852 removed : i, ;
848 ##### revision 23 #####
853 ##### revision 23 #####
849 1 sidedata entries
854 1 sidedata entries
850 entry-0014 size 4
855 entry-0014 size 4
851 '\x00\x00\x00\x00'
856 '\x00\x00\x00\x00'
852 ##### revision 24 #####
857 ##### revision 24 #####
853 1 sidedata entries
858 1 sidedata entries
854 entry-0014 size 4
859 entry-0014 size 4
855 '\x00\x00\x00\x00'
860 '\x00\x00\x00\x00'
856 ##### revision 25 #####
861 ##### revision 25 #####
857 1 sidedata entries
862 1 sidedata entries
858 entry-0014 size 14
863 entry-0014 size 14
859 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d'
864 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d'
860 touched : d, ;
865 touched : d, ;
861 ##### revision 26 #####
866 ##### revision 26 #####
862 1 sidedata entries
867 1 sidedata entries
863 entry-0014 size 14
868 entry-0014 size 14
864 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
869 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
865 merged : d, ;
870 merged : d, ;
866 ##### revision 27 #####
871 ##### revision 27 #####
867 1 sidedata entries
872 1 sidedata entries
868 entry-0014 size 14
873 entry-0014 size 14
869 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
874 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
870 merged : d, ;
875 merged : d, ;
871 ##### revision 28 #####
876 ##### revision 28 #####
872 1 sidedata entries
877 1 sidedata entries
873 entry-0014 size 14
878 entry-0014 size 14
874 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
879 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
875 merged : d, ;
880 merged : d, ;
876 ##### revision 29 #####
881 ##### revision 29 #####
877 1 sidedata entries
882 1 sidedata entries
878 entry-0014 size 14
883 entry-0014 size 14
879 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
884 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
880 merged : d, ;
885 merged : d, ;
881 ##### revision 30 #####
886 ##### revision 30 #####
882 1 sidedata entries
887 1 sidedata entries
883 entry-0014 size 14
888 entry-0014 size 14
884 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
889 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
885 salvaged : d, ;
890 salvaged : d, ;
886 ##### revision 31 #####
891 ##### revision 31 #####
887 1 sidedata entries
892 1 sidedata entries
888 entry-0014 size 14
893 entry-0014 size 14
889 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
894 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
890 salvaged : d, ;
895 salvaged : d, ;
891 ##### revision 32 #####
896 ##### revision 32 #####
892 1 sidedata entries
897 1 sidedata entries
893 entry-0014 size 14
898 entry-0014 size 14
894 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
899 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
895 salvaged : d, ;
900 salvaged : d, ;
896 ##### revision 33 #####
901 ##### revision 33 #####
897 1 sidedata entries
902 1 sidedata entries
898 entry-0014 size 14
903 entry-0014 size 14
899 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
904 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
900 salvaged : d, ;
905 salvaged : d, ;
901 ##### revision 34 #####
906 ##### revision 34 #####
902 1 sidedata entries
907 1 sidedata entries
903 entry-0014 size 24
908 entry-0014 size 24
904 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bd'
909 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bd'
905 removed : b, ;
910 removed : b, ;
906 added p1: d, b;
911 added p1: d, b;
907 ##### revision 35 #####
912 ##### revision 35 #####
908 1 sidedata entries
913 1 sidedata entries
909 entry-0014 size 4
914 entry-0014 size 4
910 '\x00\x00\x00\x00'
915 '\x00\x00\x00\x00'
911 ##### revision 36 #####
916 ##### revision 36 #####
912 1 sidedata entries
917 1 sidedata entries
913 entry-0014 size 4
918 entry-0014 size 4
914 '\x00\x00\x00\x00'
919 '\x00\x00\x00\x00'
915
920
916 #endif
921 #endif
917
922
918
923
919 Test copy information chaining
924 Test copy information chaining
920 ==============================
925 ==============================
921
926
922 Check that matching only affect the destination and not intermediate path
927 Check that matching only affect the destination and not intermediate path
923 -------------------------------------------------------------------------
928 -------------------------------------------------------------------------
924
929
925 The two status call should give the same value for f
930 The two status call should give the same value for f
926
931
927 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("a-2")'
932 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("a-2")'
928 A f
933 A f
929 a
934 a
930 R a
935 R a
931 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("a-2")' f
936 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("a-2")' f
932 A f
937 A f
933 a (no-changeset no-compatibility !)
938 a (no-changeset no-compatibility !)
934
939
935 merging with unrelated change does not interfere with the renames
940 merging with unrelated change does not interfere with the renames
936 ---------------------------------------------------------------
941 ---------------------------------------------------------------
937
942
938 - rename on one side
943 - rename on one side
939 - unrelated change on the other side
944 - unrelated change on the other side
940
945
941 $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))'
946 $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))'
942 o 12 mABm-0 simple merge - the other way
947 o 12 mABm-0 simple merge - the other way
943 |\
948 |\
944 +---o 11 mBAm-0 simple merge - one way
949 +---o 11 mBAm-0 simple merge - one way
945 | |/
950 | |/
946 | o 5 b-1: b update
951 | o 5 b-1: b update
947 | |
952 | |
948 o | 4 a-2: e -move-> f
953 o | 4 a-2: e -move-> f
949 | |
954 | |
950 o | 3 a-1: d -move-> e
955 o | 3 a-1: d -move-> e
951 |/
956 |/
952 o 2 i-2: c -move-> d
957 o 2 i-2: c -move-> d
953 |
958 |
954 o 1 i-1: a -move-> c
959 o 1 i-1: a -move-> c
955 |
960 |
956 o 0 i-0 initial commit: a b h
961 o 0 i-0 initial commit: a b h
957
962
958
963
959 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mABm")'
964 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mABm")'
960 A f
965 A f
961 d
966 d
962 R d
967 R d
963 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBAm")'
968 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBAm")'
964 A f
969 A f
965 d
970 d
966 R d
971 R d
967 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mABm")'
972 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mABm")'
968 M b
973 M b
969 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mBAm")'
974 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mBAm")'
970 M b
975 M b
971 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mABm")'
976 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mABm")'
972 M b
977 M b
973 A f
978 A f
974 d
979 d
975 R d
980 R d
976 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBAm")'
981 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBAm")'
977 M b
982 M b
978 A f
983 A f
979 d
984 d
980 R d
985 R d
981 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mABm")'
986 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mABm")'
982 M b
987 M b
983 A f
988 A f
984 a
989 a
985 R a
990 R a
986 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBAm")'
991 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBAm")'
987 M b
992 M b
988 A f
993 A f
989 a
994 a
990 R a
995 R a
991
996
992 merging with the side having a delete
997 merging with the side having a delete
993 -------------------------------------
998 -------------------------------------
994
999
995 case summary:
1000 case summary:
996 - one with change to an unrelated file
1001 - one with change to an unrelated file
997 - one deleting the change
1002 - one deleting the change
998 and recreate an unrelated file after the merge
1003 and recreate an unrelated file after the merge
999
1004
1000 $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))'
1005 $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))'
1001 o 16 mCBm-1 re-add d
1006 o 16 mCBm-1 re-add d
1002 |
1007 |
1003 o 15 mCBm-0 simple merge - the other way
1008 o 15 mCBm-0 simple merge - the other way
1004 |\
1009 |\
1005 | | o 14 mBCm-1 re-add d
1010 | | o 14 mBCm-1 re-add d
1006 | | |
1011 | | |
1007 +---o 13 mBCm-0 simple merge - one way
1012 +---o 13 mBCm-0 simple merge - one way
1008 | |/
1013 | |/
1009 | o 6 c-1 delete d
1014 | o 6 c-1 delete d
1010 | |
1015 | |
1011 o | 5 b-1: b update
1016 o | 5 b-1: b update
1012 |/
1017 |/
1013 o 2 i-2: c -move-> d
1018 o 2 i-2: c -move-> d
1014 |
1019 |
1015 o 1 i-1: a -move-> c
1020 o 1 i-1: a -move-> c
1016 |
1021 |
1017 o 0 i-0 initial commit: a b h
1022 o 0 i-0 initial commit: a b h
1018
1023
1019 - comparing from the merge
1024 - comparing from the merge
1020
1025
1021 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-0")'
1026 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-0")'
1022 R d
1027 R d
1023 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-0")'
1028 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-0")'
1024 R d
1029 R d
1025 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-0")'
1030 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-0")'
1026 M b
1031 M b
1027 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-0")'
1032 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-0")'
1028 M b
1033 M b
1029 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-0")'
1034 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-0")'
1030 M b
1035 M b
1031 R d
1036 R d
1032 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-0")'
1037 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-0")'
1033 M b
1038 M b
1034 R d
1039 R d
1035 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-0")'
1040 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-0")'
1036 M b
1041 M b
1037 R a
1042 R a
1038 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-0")'
1043 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-0")'
1039 M b
1044 M b
1040 R a
1045 R a
1041
1046
1042 - comparing with the merge children re-adding the file
1047 - comparing with the merge children re-adding the file
1043
1048
1044 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-1")'
1049 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-1")'
1045 M d
1050 M d
1046 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-1")'
1051 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-1")'
1047 M d
1052 M d
1048 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-1")'
1053 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-1")'
1049 M b
1054 M b
1050 A d
1055 A d
1051 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-1")'
1056 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-1")'
1052 M b
1057 M b
1053 A d
1058 A d
1054 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-1")'
1059 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-1")'
1055 M b
1060 M b
1056 M d
1061 M d
1057 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-1")'
1062 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-1")'
1058 M b
1063 M b
1059 M d
1064 M d
1060 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-1")'
1065 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-1")'
1061 M b
1066 M b
1062 A d
1067 A d
1063 R a
1068 R a
1064 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-1")'
1069 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-1")'
1065 M b
1070 M b
1066 A d
1071 A d
1067 R a
1072 R a
1068
1073
1069 Comparing with a merge re-adding the file afterward
1074 Comparing with a merge re-adding the file afterward
1070 ---------------------------------------------------
1075 ---------------------------------------------------
1071
1076
1072 Merge:
1077 Merge:
1073 - one with change to an unrelated file
1078 - one with change to an unrelated file
1074 - one deleting and recreating the change
1079 - one deleting and recreating the change
1075
1080
1076 $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))'
1081 $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))'
1077 o 18 mDBm-0 simple merge - the other way
1082 o 18 mDBm-0 simple merge - the other way
1078 |\
1083 |\
1079 +---o 17 mBDm-0 simple merge - one way
1084 +---o 17 mBDm-0 simple merge - one way
1080 | |/
1085 | |/
1081 | o 8 d-2 re-add d
1086 | o 8 d-2 re-add d
1082 | |
1087 | |
1083 | o 7 d-1 delete d
1088 | o 7 d-1 delete d
1084 | |
1089 | |
1085 o | 5 b-1: b update
1090 o | 5 b-1: b update
1086 |/
1091 |/
1087 o 2 i-2: c -move-> d
1092 o 2 i-2: c -move-> d
1088 |
1093 |
1089 o 1 i-1: a -move-> c
1094 o 1 i-1: a -move-> c
1090 |
1095 |
1091 o 0 i-0 initial commit: a b h
1096 o 0 i-0 initial commit: a b h
1092
1097
1093 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBDm-0")'
1098 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBDm-0")'
1094 M d
1099 M d
1095 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mDBm-0")'
1100 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mDBm-0")'
1096 M d
1101 M d
1097 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mBDm-0")'
1102 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mBDm-0")'
1098 M b
1103 M b
1099 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDBm-0")'
1104 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDBm-0")'
1100 M b
1105 M b
1101 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBDm-0")'
1106 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBDm-0")'
1102 M b
1107 M b
1103 M d
1108 M d
1104 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mDBm-0")'
1109 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mDBm-0")'
1105 M b
1110 M b
1106 M d
1111 M d
1107
1112
1108 The bugs makes recorded copy is different depending of where we started the merge from since
1113 The bugs makes recorded copy is different depending of where we started the merge from since
1109
1114
1110 $ hg manifest --debug --rev 'desc("mBDm-0")' | grep '644 d'
1115 $ hg manifest --debug --rev 'desc("mBDm-0")' | grep '644 d'
1111 b004912a8510032a0350a74daa2803dadfb00e12 644 d
1116 b004912a8510032a0350a74daa2803dadfb00e12 644 d
1112 $ hg manifest --debug --rev 'desc("mDBm-0")' | grep '644 d'
1117 $ hg manifest --debug --rev 'desc("mDBm-0")' | grep '644 d'
1113 b004912a8510032a0350a74daa2803dadfb00e12 644 d
1118 b004912a8510032a0350a74daa2803dadfb00e12 644 d
1114
1119
1115 $ hg manifest --debug --rev 'desc("d-2")' | grep '644 d'
1120 $ hg manifest --debug --rev 'desc("d-2")' | grep '644 d'
1116 b004912a8510032a0350a74daa2803dadfb00e12 644 d
1121 b004912a8510032a0350a74daa2803dadfb00e12 644 d
1117 $ hg manifest --debug --rev 'desc("b-1")' | grep '644 d'
1122 $ hg manifest --debug --rev 'desc("b-1")' | grep '644 d'
1118 169be882533bc917905d46c0c951aa9a1e288dcf 644 d (no-changeset !)
1123 169be882533bc917905d46c0c951aa9a1e288dcf 644 d (no-changeset !)
1119 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 d (changeset !)
1124 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 d (changeset !)
1120 $ hg debugindex d | head -n 4
1125 $ hg debugindex d | head -n 4
1121 rev linkrev nodeid p1 p2
1126 rev linkrev nodeid p1 p2
1122 0 2 169be882533b 000000000000 000000000000 (no-changeset !)
1127 0 2 169be882533b 000000000000 000000000000 (no-changeset !)
1123 0 2 b789fdd96dc2 000000000000 000000000000 (changeset !)
1128 0 2 b789fdd96dc2 000000000000 000000000000 (changeset !)
1124 1 8 b004912a8510 000000000000 000000000000
1129 1 8 b004912a8510 000000000000 000000000000
1125 2 22 4a067cf8965d 000000000000 000000000000 (no-changeset !)
1130 2 22 4a067cf8965d 000000000000 000000000000 (no-changeset !)
1126 2 22 fe6f8b4f507f 000000000000 000000000000 (changeset !)
1131 2 22 fe6f8b4f507f 000000000000 000000000000 (changeset !)
1127
1132
1128 Log output should not include a merge commit as it did not happen
1133 Log output should not include a merge commit as it did not happen
1129
1134
1130 $ hg log -Gfr 'desc("mBDm-0")' d
1135 $ hg log -Gfr 'desc("mBDm-0")' d
1131 o 8 d-2 re-add d
1136 o 8 d-2 re-add d
1132 |
1137 |
1133 ~
1138 ~
1134
1139
1135 $ hg log -Gfr 'desc("mDBm-0")' d
1140 $ hg log -Gfr 'desc("mDBm-0")' d
1136 o 8 d-2 re-add d
1141 o 8 d-2 re-add d
1137 |
1142 |
1138 ~
1143 ~
1139
1144
1140 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBDm-0")'
1145 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBDm-0")'
1141 M b
1146 M b
1142 A d
1147 A d
1143 R a
1148 R a
1144 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDBm-0")'
1149 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDBm-0")'
1145 M b
1150 M b
1146 A d
1151 A d
1147 R a
1152 R a
1148
1153
1149
1154
1150 Comparing with a merge with colliding rename
1155 Comparing with a merge with colliding rename
1151 --------------------------------------------
1156 --------------------------------------------
1152
1157
1153 - the "e-" branch renaming b to f (through 'g')
1158 - the "e-" branch renaming b to f (through 'g')
1154 - the "a-" branch renaming d to f (through e)
1159 - the "a-" branch renaming d to f (through e)
1155
1160
1156 $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))'
1161 $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))'
1157 o 20 mEAm-0 simple merge - the other way
1162 o 20 mEAm-0 simple merge - the other way
1158 |\
1163 |\
1159 +---o 19 mAEm-0 simple merge - one way
1164 +---o 19 mAEm-0 simple merge - one way
1160 | |/
1165 | |/
1161 | o 10 e-2 g -move-> f
1166 | o 10 e-2 g -move-> f
1162 | |
1167 | |
1163 | o 9 e-1 b -move-> g
1168 | o 9 e-1 b -move-> g
1164 | |
1169 | |
1165 o | 4 a-2: e -move-> f
1170 o | 4 a-2: e -move-> f
1166 | |
1171 | |
1167 o | 3 a-1: d -move-> e
1172 o | 3 a-1: d -move-> e
1168 |/
1173 |/
1169 o 2 i-2: c -move-> d
1174 o 2 i-2: c -move-> d
1170 |
1175 |
1171 o 1 i-1: a -move-> c
1176 o 1 i-1: a -move-> c
1172 |
1177 |
1173 o 0 i-0 initial commit: a b h
1178 o 0 i-0 initial commit: a b h
1174
1179
1175 #if no-changeset
1180 #if no-changeset
1176 $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f'
1181 $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f'
1177 c39c6083dad048d5138618a46f123e2f397f4f18 644 f
1182 c39c6083dad048d5138618a46f123e2f397f4f18 644 f
1178 $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f'
1183 $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f'
1179 a9a8bc3860c9d8fa5f2f7e6ea8d40498322737fd 644 f
1184 a9a8bc3860c9d8fa5f2f7e6ea8d40498322737fd 644 f
1180 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
1185 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
1181 263ea25e220aaeb7b9bac551c702037849aa75e8 644 f
1186 263ea25e220aaeb7b9bac551c702037849aa75e8 644 f
1182 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
1187 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
1183 71b9b7e73d973572ade6dd765477fcee6890e8b1 644 f
1188 71b9b7e73d973572ade6dd765477fcee6890e8b1 644 f
1184 $ hg debugindex f
1189 $ hg debugindex f
1185 rev linkrev nodeid p1 p2
1190 rev linkrev nodeid p1 p2
1186 0 4 263ea25e220a 000000000000 000000000000
1191 0 4 263ea25e220a 000000000000 000000000000
1187 1 10 71b9b7e73d97 000000000000 000000000000
1192 1 10 71b9b7e73d97 000000000000 000000000000
1188 2 19 c39c6083dad0 263ea25e220a 71b9b7e73d97
1193 2 19 c39c6083dad0 263ea25e220a 71b9b7e73d97
1189 3 20 a9a8bc3860c9 71b9b7e73d97 263ea25e220a
1194 3 20 a9a8bc3860c9 71b9b7e73d97 263ea25e220a
1190 #else
1195 #else
1191 $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f'
1196 $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f'
1192 498e8799f49f9da1ca06bb2d6d4accf165c5b572 644 f
1197 498e8799f49f9da1ca06bb2d6d4accf165c5b572 644 f
1193 $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f'
1198 $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f'
1194 c5b506a7118667a38a9c9348a1f63b679e382f57 644 f
1199 c5b506a7118667a38a9c9348a1f63b679e382f57 644 f
1195 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
1200 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
1196 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 f
1201 b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 644 f
1197 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
1202 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
1198 1e88685f5ddec574a34c70af492f95b6debc8741 644 f
1203 1e88685f5ddec574a34c70af492f95b6debc8741 644 f
1199 $ hg debugindex f
1204 $ hg debugindex f
1200 rev linkrev nodeid p1 p2
1205 rev linkrev nodeid p1 p2
1201 0 4 b789fdd96dc2 000000000000 000000000000
1206 0 4 b789fdd96dc2 000000000000 000000000000
1202 1 10 1e88685f5dde 000000000000 000000000000
1207 1 10 1e88685f5dde 000000000000 000000000000
1203 2 19 498e8799f49f b789fdd96dc2 1e88685f5dde
1208 2 19 498e8799f49f b789fdd96dc2 1e88685f5dde
1204 3 20 c5b506a71186 1e88685f5dde b789fdd96dc2
1209 3 20 c5b506a71186 1e88685f5dde b789fdd96dc2
1205 #endif
1210 #endif
1206
1211
1207 # Here the filelog based implementation is not looking at the rename
1212 # Here the filelog based implementation is not looking at the rename
1208 # information (because the file exist on both side). However the changelog
1213 # information (because the file exist on both side). However the changelog
1209 # based on works fine. We have different output.
1214 # based on works fine. We have different output.
1210
1215
1211 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAEm-0")'
1216 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAEm-0")'
1212 M f
1217 M f
1213 b (no-filelog !)
1218 b (no-filelog !)
1214 R b
1219 R b
1215 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEAm-0")'
1220 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEAm-0")'
1216 M f
1221 M f
1217 b (no-filelog !)
1222 b (no-filelog !)
1218 R b
1223 R b
1219 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAEm-0")'
1224 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAEm-0")'
1220 M f
1225 M f
1221 d (no-filelog !)
1226 d (no-filelog !)
1222 R d
1227 R d
1223 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEAm-0")'
1228 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEAm-0")'
1224 M f
1229 M f
1225 d (no-filelog !)
1230 d (no-filelog !)
1226 R d
1231 R d
1227 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")'
1232 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")'
1228 A f
1233 A f
1229 d
1234 d
1230 R d
1235 R d
1231 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("e-2")'
1236 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("e-2")'
1232 A f
1237 A f
1233 b
1238 b
1234 R b
1239 R b
1235
1240
1236 # From here, we run status against revision where both source file exists.
1241 # From here, we run status against revision where both source file exists.
1237 #
1242 #
1238 # The filelog based implementation picks an arbitrary side based on revision
1243 # The filelog based implementation picks an arbitrary side based on revision
1239 # numbers. So the same side "wins" whatever the parents order is. This is
1244 # numbers. So the same side "wins" whatever the parents order is. This is
1240 # sub-optimal because depending on revision numbers means the result can be
1245 # sub-optimal because depending on revision numbers means the result can be
1241 # different from one repository to the next.
1246 # different from one repository to the next.
1242 #
1247 #
1243 # The changeset based algorithm use the parent order to break tie on conflicting
1248 # The changeset based algorithm use the parent order to break tie on conflicting
1244 # information and will have a different order depending on who is p1 and p2.
1249 # information and will have a different order depending on who is p1 and p2.
1245 # That order is stable accross repositories. (data from p1 prevails)
1250 # That order is stable accross repositories. (data from p1 prevails)
1246
1251
1247 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAEm-0")'
1252 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAEm-0")'
1248 A f
1253 A f
1249 d
1254 d
1250 R b
1255 R b
1251 R d
1256 R d
1252 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEAm-0")'
1257 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEAm-0")'
1253 A f
1258 A f
1254 d (filelog !)
1259 d (filelog !)
1255 b (no-filelog !)
1260 b (no-filelog !)
1256 R b
1261 R b
1257 R d
1262 R d
1258 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm-0")'
1263 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm-0")'
1259 A f
1264 A f
1260 a
1265 a
1261 R a
1266 R a
1262 R b
1267 R b
1263 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm-0")'
1268 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm-0")'
1264 A f
1269 A f
1265 a (filelog !)
1270 a (filelog !)
1266 b (no-filelog !)
1271 b (no-filelog !)
1267 R a
1272 R a
1268 R b
1273 R b
1269
1274
1270
1275
1271 Note:
1276 Note:
1272 | In this case, one of the merge wrongly record a merge while there is none.
1277 | In this case, one of the merge wrongly record a merge while there is none.
1273 | This lead to bad copy tracing information to be dug up.
1278 | This lead to bad copy tracing information to be dug up.
1274
1279
1275
1280
1276 Merge:
1281 Merge:
1277 - one with change to an unrelated file (b)
1282 - one with change to an unrelated file (b)
1278 - one overwriting a file (d) with a rename (from h to i to d)
1283 - one overwriting a file (d) with a rename (from h to i to d)
1279
1284
1280 $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))'
1285 $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))'
1281 o 24 mFBm-0 simple merge - the other way
1286 o 24 mFBm-0 simple merge - the other way
1282 |\
1287 |\
1283 +---o 23 mBFm-0 simple merge - one way
1288 +---o 23 mBFm-0 simple merge - one way
1284 | |/
1289 | |/
1285 | o 22 f-2: rename i -> d
1290 | o 22 f-2: rename i -> d
1286 | |
1291 | |
1287 | o 21 f-1: rename h -> i
1292 | o 21 f-1: rename h -> i
1288 | |
1293 | |
1289 o | 5 b-1: b update
1294 o | 5 b-1: b update
1290 |/
1295 |/
1291 o 2 i-2: c -move-> d
1296 o 2 i-2: c -move-> d
1292 |
1297 |
1293 o 1 i-1: a -move-> c
1298 o 1 i-1: a -move-> c
1294 |
1299 |
1295 o 0 i-0 initial commit: a b h
1300 o 0 i-0 initial commit: a b h
1296
1301
1297 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBFm-0")'
1302 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBFm-0")'
1298 M b
1303 M b
1299 A d
1304 A d
1300 h
1305 h
1301 R a
1306 R a
1302 R h
1307 R h
1303 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFBm-0")'
1308 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFBm-0")'
1304 M b
1309 M b
1305 A d
1310 A d
1306 h
1311 h
1307 R a
1312 R a
1308 R h
1313 R h
1309 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBFm-0")'
1314 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBFm-0")'
1310 M d
1315 M d
1311 h (no-filelog !)
1316 h (no-filelog !)
1312 R h
1317 R h
1313 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mBFm-0")'
1318 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mBFm-0")'
1314 M b
1319 M b
1315 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mBFm-0")'
1320 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mBFm-0")'
1316 M b
1321 M b
1317 M d
1322 M d
1318 i (no-filelog !)
1323 i (no-filelog !)
1319 R i
1324 R i
1320 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mFBm-0")'
1325 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mFBm-0")'
1321 M d
1326 M d
1322 h (no-filelog !)
1327 h (no-filelog !)
1323 R h
1328 R h
1324 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFBm-0")'
1329 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFBm-0")'
1325 M b
1330 M b
1326 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFBm-0")'
1331 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFBm-0")'
1327 M b
1332 M b
1328 M d
1333 M d
1329 i (no-filelog !)
1334 i (no-filelog !)
1330 R i
1335 R i
1331
1336
1332 #if no-changeset
1337 #if no-changeset
1333 $ hg log -Gfr 'desc("mBFm-0")' d
1338 $ hg log -Gfr 'desc("mBFm-0")' d
1334 o 22 f-2: rename i -> d
1339 o 22 f-2: rename i -> d
1335 |
1340 |
1336 o 21 f-1: rename h -> i
1341 o 21 f-1: rename h -> i
1337 :
1342 :
1338 o 0 i-0 initial commit: a b h
1343 o 0 i-0 initial commit: a b h
1339
1344
1340 #else
1345 #else
1341 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1346 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1342 $ hg log -Gfr 'desc("mBFm-0")' d
1347 $ hg log -Gfr 'desc("mBFm-0")' d
1343 o 22 f-2: rename i -> d
1348 o 22 f-2: rename i -> d
1344 |
1349 |
1345 ~
1350 ~
1346 #endif
1351 #endif
1347
1352
1348 #if no-changeset
1353 #if no-changeset
1349 $ hg log -Gfr 'desc("mFBm-0")' d
1354 $ hg log -Gfr 'desc("mFBm-0")' d
1350 o 22 f-2: rename i -> d
1355 o 22 f-2: rename i -> d
1351 |
1356 |
1352 o 21 f-1: rename h -> i
1357 o 21 f-1: rename h -> i
1353 :
1358 :
1354 o 0 i-0 initial commit: a b h
1359 o 0 i-0 initial commit: a b h
1355
1360
1356 #else
1361 #else
1357 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1362 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1358 $ hg log -Gfr 'desc("mFBm-0")' d
1363 $ hg log -Gfr 'desc("mFBm-0")' d
1359 o 22 f-2: rename i -> d
1364 o 22 f-2: rename i -> d
1360 |
1365 |
1361 ~
1366 ~
1362 #endif
1367 #endif
1363
1368
1364
1369
1365 Merge:
1370 Merge:
1366 - one with change to a file
1371 - one with change to a file
1367 - one deleting and recreating the file
1372 - one deleting and recreating the file
1368
1373
1369 Unlike in the 'BD/DB' cases, an actual merge happened here. So we should
1374 Unlike in the 'BD/DB' cases, an actual merge happened here. So we should
1370 consider history and rename on both branch of the merge.
1375 consider history and rename on both branch of the merge.
1371
1376
1372 $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))'
1377 $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))'
1373 o 27 mGDm-0 simple merge - the other way
1378 o 27 mGDm-0 simple merge - the other way
1374 |\
1379 |\
1375 +---o 26 mDGm-0 simple merge - one way
1380 +---o 26 mDGm-0 simple merge - one way
1376 | |/
1381 | |/
1377 | o 25 g-1: update d
1382 | o 25 g-1: update d
1378 | |
1383 | |
1379 o | 8 d-2 re-add d
1384 o | 8 d-2 re-add d
1380 | |
1385 | |
1381 o | 7 d-1 delete d
1386 o | 7 d-1 delete d
1382 |/
1387 |/
1383 o 2 i-2: c -move-> d
1388 o 2 i-2: c -move-> d
1384 |
1389 |
1385 o 1 i-1: a -move-> c
1390 o 1 i-1: a -move-> c
1386 |
1391 |
1387 o 0 i-0 initial commit: a b h
1392 o 0 i-0 initial commit: a b h
1388
1393
1389 One side of the merge have a long history with rename. The other side of the
1394 One side of the merge have a long history with rename. The other side of the
1390 merge point to a new file with a smaller history. Each side is "valid".
1395 merge point to a new file with a smaller history. Each side is "valid".
1391
1396
1392 (and again the filelog based algorithm only explore one, with a pick based on
1397 (and again the filelog based algorithm only explore one, with a pick based on
1393 revision numbers)
1398 revision numbers)
1394
1399
1395 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDGm-0")'
1400 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDGm-0")'
1396 A d
1401 A d
1397 a (filelog !)
1402 a (filelog !)
1398 R a
1403 R a
1399 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGDm-0")'
1404 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGDm-0")'
1400 A d
1405 A d
1401 a
1406 a
1402 R a
1407 R a
1403 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDGm-0")'
1408 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDGm-0")'
1404 M d
1409 M d
1405 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mGDm-0")'
1410 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mGDm-0")'
1406 M d
1411 M d
1407 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mDGm-0")'
1412 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mDGm-0")'
1408 M d
1413 M d
1409 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGDm-0")'
1414 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGDm-0")'
1410 M d
1415 M d
1411
1416
1412 #if no-changeset
1417 #if no-changeset
1413 $ hg log -Gfr 'desc("mDGm-0")' d
1418 $ hg log -Gfr 'desc("mDGm-0")' d
1414 o 26 mDGm-0 simple merge - one way
1419 o 26 mDGm-0 simple merge - one way
1415 |\
1420 |\
1416 | o 25 g-1: update d
1421 | o 25 g-1: update d
1417 | |
1422 | |
1418 o | 8 d-2 re-add d
1423 o | 8 d-2 re-add d
1419 |/
1424 |/
1420 o 2 i-2: c -move-> d
1425 o 2 i-2: c -move-> d
1421 |
1426 |
1422 o 1 i-1: a -move-> c
1427 o 1 i-1: a -move-> c
1423 |
1428 |
1424 o 0 i-0 initial commit: a b h
1429 o 0 i-0 initial commit: a b h
1425
1430
1426 #else
1431 #else
1427 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1432 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1428 $ hg log -Gfr 'desc("mDGm-0")' d
1433 $ hg log -Gfr 'desc("mDGm-0")' d
1429 o 26 mDGm-0 simple merge - one way
1434 o 26 mDGm-0 simple merge - one way
1430 |\
1435 |\
1431 | o 25 g-1: update d
1436 | o 25 g-1: update d
1432 | |
1437 | |
1433 o | 8 d-2 re-add d
1438 o | 8 d-2 re-add d
1434 |/
1439 |/
1435 o 2 i-2: c -move-> d
1440 o 2 i-2: c -move-> d
1436 |
1441 |
1437 ~
1442 ~
1438 #endif
1443 #endif
1439
1444
1440
1445
1441 #if no-changeset
1446 #if no-changeset
1442 $ hg log -Gfr 'desc("mDGm-0")' d
1447 $ hg log -Gfr 'desc("mDGm-0")' d
1443 o 26 mDGm-0 simple merge - one way
1448 o 26 mDGm-0 simple merge - one way
1444 |\
1449 |\
1445 | o 25 g-1: update d
1450 | o 25 g-1: update d
1446 | |
1451 | |
1447 o | 8 d-2 re-add d
1452 o | 8 d-2 re-add d
1448 |/
1453 |/
1449 o 2 i-2: c -move-> d
1454 o 2 i-2: c -move-> d
1450 |
1455 |
1451 o 1 i-1: a -move-> c
1456 o 1 i-1: a -move-> c
1452 |
1457 |
1453 o 0 i-0 initial commit: a b h
1458 o 0 i-0 initial commit: a b h
1454
1459
1455 #else
1460 #else
1456 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1461 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1457 $ hg log -Gfr 'desc("mDGm-0")' d
1462 $ hg log -Gfr 'desc("mDGm-0")' d
1458 o 26 mDGm-0 simple merge - one way
1463 o 26 mDGm-0 simple merge - one way
1459 |\
1464 |\
1460 | o 25 g-1: update d
1465 | o 25 g-1: update d
1461 | |
1466 | |
1462 o | 8 d-2 re-add d
1467 o | 8 d-2 re-add d
1463 |/
1468 |/
1464 o 2 i-2: c -move-> d
1469 o 2 i-2: c -move-> d
1465 |
1470 |
1466 ~
1471 ~
1467 #endif
1472 #endif
1468
1473
1469
1474
1470 Merge:
1475 Merge:
1471 - one with change to a file (d)
1476 - one with change to a file (d)
1472 - one overwriting that file with a rename (from h to i, to d)
1477 - one overwriting that file with a rename (from h to i, to d)
1473
1478
1474 This case is similar to BF/FB, but an actual merge happens, so both side of the
1479 This case is similar to BF/FB, but an actual merge happens, so both side of the
1475 history are relevant.
1480 history are relevant.
1476
1481
1477
1482
1478 $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))'
1483 $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))'
1479 o 29 mGFm-0 simple merge - the other way
1484 o 29 mGFm-0 simple merge - the other way
1480 |\
1485 |\
1481 +---o 28 mFGm-0 simple merge - one way
1486 +---o 28 mFGm-0 simple merge - one way
1482 | |/
1487 | |/
1483 | o 25 g-1: update d
1488 | o 25 g-1: update d
1484 | |
1489 | |
1485 o | 22 f-2: rename i -> d
1490 o | 22 f-2: rename i -> d
1486 | |
1491 | |
1487 o | 21 f-1: rename h -> i
1492 o | 21 f-1: rename h -> i
1488 |/
1493 |/
1489 o 2 i-2: c -move-> d
1494 o 2 i-2: c -move-> d
1490 |
1495 |
1491 o 1 i-1: a -move-> c
1496 o 1 i-1: a -move-> c
1492 |
1497 |
1493 o 0 i-0 initial commit: a b h
1498 o 0 i-0 initial commit: a b h
1494
1499
1495
1500
1496 Note:
1501 Note:
1497 | In this case, the merge get conflicting information since on one side we have
1502 | In this case, the merge get conflicting information since on one side we have
1498 | "a -> c -> d". and one the other one we have "h -> i -> d".
1503 | "a -> c -> d". and one the other one we have "h -> i -> d".
1499 |
1504 |
1500 | The current code arbitrarily pick one side depending the ordering of the merged hash:
1505 | The current code arbitrarily pick one side depending the ordering of the merged hash:
1501
1506
1502 In this case, the file hash from "f-2" is lower, so it will be `p1` of the resulting filenode its copy tracing information will win (and trace back to "h"):
1507 In this case, the file hash from "f-2" is lower, so it will be `p1` of the resulting filenode its copy tracing information will win (and trace back to "h"):
1503
1508
1504 Details on this hash ordering pick:
1509 Details on this hash ordering pick:
1505
1510
1506 $ hg manifest --debug 'desc("g-1")' | egrep 'd$'
1511 $ hg manifest --debug 'desc("g-1")' | egrep 'd$'
1507 f2b277c39e0d2bbac99d8aae075c0d8b5304d266 644 d (no-changeset !)
1512 f2b277c39e0d2bbac99d8aae075c0d8b5304d266 644 d (no-changeset !)
1508 4ff57b4e8dceedb487e70e6965ea188a7c042cca 644 d (changeset !)
1513 4ff57b4e8dceedb487e70e6965ea188a7c042cca 644 d (changeset !)
1509 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("g-1")' d
1514 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("g-1")' d
1510 A d
1515 A d
1511 a (no-changeset no-compatibility !)
1516 a (no-changeset no-compatibility !)
1512
1517
1513 $ hg manifest --debug 'desc("f-2")' | egrep 'd$'
1518 $ hg manifest --debug 'desc("f-2")' | egrep 'd$'
1514 4a067cf8965d1bfff130057ade26b44f580231be 644 d (no-changeset !)
1519 4a067cf8965d1bfff130057ade26b44f580231be 644 d (no-changeset !)
1515 fe6f8b4f507fe3eb524c527192a84920a4288dac 644 d (changeset !)
1520 fe6f8b4f507fe3eb524c527192a84920a4288dac 644 d (changeset !)
1516 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("f-2")' d
1521 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("f-2")' d
1517 A d
1522 A d
1518 h (no-changeset no-compatibility !)
1523 h (no-changeset no-compatibility !)
1519
1524
1520 Copy tracing data on the resulting merge:
1525 Copy tracing data on the resulting merge:
1521
1526
1522 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm-0")'
1527 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm-0")'
1523 A d
1528 A d
1524 h
1529 h
1525 R a
1530 R a
1526 R h
1531 R h
1527 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm-0")'
1532 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm-0")'
1528 A d
1533 A d
1529 a (no-filelog !)
1534 a (no-filelog !)
1530 h (filelog !)
1535 h (filelog !)
1531 R a
1536 R a
1532 R h
1537 R h
1533 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFGm-0")'
1538 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFGm-0")'
1534 M d
1539 M d
1535 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mGFm-0")'
1540 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mGFm-0")'
1536 M d
1541 M d
1537 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFGm-0")'
1542 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFGm-0")'
1538 M d
1543 M d
1539 i (no-filelog !)
1544 i (no-filelog !)
1540 R i
1545 R i
1541 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mGFm-0")'
1546 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mGFm-0")'
1542 M d
1547 M d
1543 i (no-filelog !)
1548 i (no-filelog !)
1544 R i
1549 R i
1545 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mFGm-0")'
1550 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mFGm-0")'
1546 M d
1551 M d
1547 h (no-filelog !)
1552 h (no-filelog !)
1548 R h
1553 R h
1549 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGFm-0")'
1554 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGFm-0")'
1550 M d
1555 M d
1551 h (no-filelog !)
1556 h (no-filelog !)
1552 R h
1557 R h
1553
1558
1554 #if no-changeset
1559 #if no-changeset
1555 $ hg log -Gfr 'desc("mFGm-0")' d
1560 $ hg log -Gfr 'desc("mFGm-0")' d
1556 o 28 mFGm-0 simple merge - one way
1561 o 28 mFGm-0 simple merge - one way
1557 |\
1562 |\
1558 | o 25 g-1: update d
1563 | o 25 g-1: update d
1559 | |
1564 | |
1560 o | 22 f-2: rename i -> d
1565 o | 22 f-2: rename i -> d
1561 | |
1566 | |
1562 o | 21 f-1: rename h -> i
1567 o | 21 f-1: rename h -> i
1563 |/
1568 |/
1564 o 2 i-2: c -move-> d
1569 o 2 i-2: c -move-> d
1565 |
1570 |
1566 o 1 i-1: a -move-> c
1571 o 1 i-1: a -move-> c
1567 |
1572 |
1568 o 0 i-0 initial commit: a b h
1573 o 0 i-0 initial commit: a b h
1569
1574
1570 #else
1575 #else
1571 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1576 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1572 $ hg log -Gfr 'desc("mFGm-0")' d
1577 $ hg log -Gfr 'desc("mFGm-0")' d
1573 o 28 mFGm-0 simple merge - one way
1578 o 28 mFGm-0 simple merge - one way
1574 |\
1579 |\
1575 | o 25 g-1: update d
1580 | o 25 g-1: update d
1576 | |
1581 | |
1577 o | 22 f-2: rename i -> d
1582 o | 22 f-2: rename i -> d
1578 |/
1583 |/
1579 o 2 i-2: c -move-> d
1584 o 2 i-2: c -move-> d
1580 |
1585 |
1581 ~
1586 ~
1582 #endif
1587 #endif
1583
1588
1584 #if no-changeset
1589 #if no-changeset
1585 $ hg log -Gfr 'desc("mGFm-0")' d
1590 $ hg log -Gfr 'desc("mGFm-0")' d
1586 o 29 mGFm-0 simple merge - the other way
1591 o 29 mGFm-0 simple merge - the other way
1587 |\
1592 |\
1588 | o 25 g-1: update d
1593 | o 25 g-1: update d
1589 | |
1594 | |
1590 o | 22 f-2: rename i -> d
1595 o | 22 f-2: rename i -> d
1591 | |
1596 | |
1592 o | 21 f-1: rename h -> i
1597 o | 21 f-1: rename h -> i
1593 |/
1598 |/
1594 o 2 i-2: c -move-> d
1599 o 2 i-2: c -move-> d
1595 |
1600 |
1596 o 1 i-1: a -move-> c
1601 o 1 i-1: a -move-> c
1597 |
1602 |
1598 o 0 i-0 initial commit: a b h
1603 o 0 i-0 initial commit: a b h
1599
1604
1600 #else
1605 #else
1601 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1606 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
1602 $ hg log -Gfr 'desc("mGFm-0")' d
1607 $ hg log -Gfr 'desc("mGFm-0")' d
1603 o 29 mGFm-0 simple merge - the other way
1608 o 29 mGFm-0 simple merge - the other way
1604 |\
1609 |\
1605 | o 25 g-1: update d
1610 | o 25 g-1: update d
1606 | |
1611 | |
1607 o | 22 f-2: rename i -> d
1612 o | 22 f-2: rename i -> d
1608 |/
1613 |/
1609 o 2 i-2: c -move-> d
1614 o 2 i-2: c -move-> d
1610 |
1615 |
1611 ~
1616 ~
1612 #endif
1617 #endif
1613
1618
1614
1619
1615 Comparing with merging with a deletion (and keeping the file)
1620 Comparing with merging with a deletion (and keeping the file)
1616 -------------------------------------------------------------
1621 -------------------------------------------------------------
1617
1622
1618 Merge:
1623 Merge:
1619 - one removing a file (d)
1624 - one removing a file (d)
1620 - one updating that file
1625 - one updating that file
1621 - the merge keep the modified version of the file (canceling the delete)
1626 - the merge keep the modified version of the file (canceling the delete)
1622
1627
1623 In this case, the file keep on living after the merge. So we should not drop its
1628 In this case, the file keep on living after the merge. So we should not drop its
1624 copy tracing chain.
1629 copy tracing chain.
1625
1630
1626 $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))'
1631 $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))'
1627 o 31 mGCm-0
1632 o 31 mGCm-0
1628 |\
1633 |\
1629 +---o 30 mCGm-0
1634 +---o 30 mCGm-0
1630 | |/
1635 | |/
1631 | o 25 g-1: update d
1636 | o 25 g-1: update d
1632 | |
1637 | |
1633 o | 6 c-1 delete d
1638 o | 6 c-1 delete d
1634 |/
1639 |/
1635 o 2 i-2: c -move-> d
1640 o 2 i-2: c -move-> d
1636 |
1641 |
1637 o 1 i-1: a -move-> c
1642 o 1 i-1: a -move-> c
1638 |
1643 |
1639 o 0 i-0 initial commit: a b h
1644 o 0 i-0 initial commit: a b h
1640
1645
1641
1646
1642 'a' is the copy source of 'd'
1647 'a' is the copy source of 'd'
1643
1648
1644 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCGm-0")'
1649 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCGm-0")'
1645 A d
1650 A d
1646 a (no-compatibility no-changeset !)
1651 a (no-compatibility no-changeset !)
1647 R a
1652 R a
1648 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGCm-0")'
1653 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGCm-0")'
1649 A d
1654 A d
1650 a (no-compatibility no-changeset !)
1655 a (no-compatibility no-changeset !)
1651 R a
1656 R a
1652 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCGm-0")'
1657 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCGm-0")'
1653 A d
1658 A d
1654 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mGCm-0")'
1659 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mGCm-0")'
1655 A d
1660 A d
1656 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mCGm-0")'
1661 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mCGm-0")'
1657 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGCm-0")'
1662 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGCm-0")'
1658
1663
1659
1664
1660 Comparing with merge restoring an untouched deleted file
1665 Comparing with merge restoring an untouched deleted file
1661 --------------------------------------------------------
1666 --------------------------------------------------------
1662
1667
1663 Merge:
1668 Merge:
1664 - one removing a file (d)
1669 - one removing a file (d)
1665 - one leaving the file untouched
1670 - one leaving the file untouched
1666 - the merge actively restore the file to the same content.
1671 - the merge actively restore the file to the same content.
1667
1672
1668 In this case, the file keep on living after the merge. So we should not drop its
1673 In this case, the file keep on living after the merge. So we should not drop its
1669 copy tracing chain.
1674 copy tracing chain.
1670
1675
1671 $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))'
1676 $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))'
1672 o 33 mBC-revert-m-0
1677 o 33 mBC-revert-m-0
1673 |\
1678 |\
1674 +---o 32 mCB-revert-m-0
1679 +---o 32 mCB-revert-m-0
1675 | |/
1680 | |/
1676 | o 6 c-1 delete d
1681 | o 6 c-1 delete d
1677 | |
1682 | |
1678 o | 5 b-1: b update
1683 o | 5 b-1: b update
1679 |/
1684 |/
1680 o 2 i-2: c -move-> d
1685 o 2 i-2: c -move-> d
1681 |
1686 |
1682 o 1 i-1: a -move-> c
1687 o 1 i-1: a -move-> c
1683 |
1688 |
1684 o 0 i-0 initial commit: a b h
1689 o 0 i-0 initial commit: a b h
1685
1690
1686
1691
1687 'a' is the the copy source of 'd'
1692 'a' is the the copy source of 'd'
1688
1693
1689 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-revert-m-0")'
1694 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-revert-m-0")'
1690 M b
1695 M b
1691 A d
1696 A d
1692 a (no-compatibility no-changeset !)
1697 a (no-compatibility no-changeset !)
1693 R a
1698 R a
1694 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-revert-m-0")'
1699 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-revert-m-0")'
1695 M b
1700 M b
1696 A d
1701 A d
1697 a (no-compatibility no-changeset !)
1702 a (no-compatibility no-changeset !)
1698 R a
1703 R a
1699 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCB-revert-m-0")'
1704 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCB-revert-m-0")'
1700 M b
1705 M b
1701 A d
1706 A d
1702 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBC-revert-m-0")'
1707 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBC-revert-m-0")'
1703 M b
1708 M b
1704 A d
1709 A d
1705 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCB-revert-m-0")'
1710 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCB-revert-m-0")'
1706 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBC-revert-m-0")'
1711 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBC-revert-m-0")'
1707
1712
1708
1713
1709 Merging a branch where a rename was deleted with a branch where the same file was renamed
1714 Merging a branch where a rename was deleted with a branch where the same file was renamed
1710 ------------------------------------------------------------------------------------------
1715 ------------------------------------------------------------------------------------------
1711
1716
1712 Create a "conflicting" merge where `d` get removed on one branch before its
1717 Create a "conflicting" merge where `d` get removed on one branch before its
1713 rename information actually conflict with the other branch.
1718 rename information actually conflict with the other branch.
1714
1719
1715 (the copy information from the branch that was not deleted should win).
1720 (the copy information from the branch that was not deleted should win).
1716
1721
1717 $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))'
1722 $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))'
1718 o 36 mHC-delete-before-conflict-m-0
1723 o 36 mHC-delete-before-conflict-m-0
1719 |\
1724 |\
1720 +---o 35 mCH-delete-before-conflict-m-0
1725 +---o 35 mCH-delete-before-conflict-m-0
1721 | |/
1726 | |/
1722 | o 34 h-1: b -(move)-> d
1727 | o 34 h-1: b -(move)-> d
1723 | |
1728 | |
1724 o | 6 c-1 delete d
1729 o | 6 c-1 delete d
1725 | |
1730 | |
1726 o | 2 i-2: c -move-> d
1731 o | 2 i-2: c -move-> d
1727 | |
1732 | |
1728 o | 1 i-1: a -move-> c
1733 o | 1 i-1: a -move-> c
1729 |/
1734 |/
1730 o 0 i-0 initial commit: a b h
1735 o 0 i-0 initial commit: a b h
1731
1736
1732
1737
1733 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCH-delete-before-conflict-m")'
1738 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCH-delete-before-conflict-m")'
1734 A d
1739 A d
1735 b (no-compatibility no-changeset !)
1740 b (no-compatibility no-changeset !)
1736 R a
1741 R a
1737 R b
1742 R b
1738 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mHC-delete-before-conflict-m")'
1743 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mHC-delete-before-conflict-m")'
1739 A d
1744 A d
1740 b
1745 b
1741 R a
1746 R a
1742 R b
1747 R b
1743 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCH-delete-before-conflict-m")'
1748 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCH-delete-before-conflict-m")'
1744 A d
1749 A d
1745 b
1750 b
1746 R b
1751 R b
1747 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mHC-delete-before-conflict-m")'
1752 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mHC-delete-before-conflict-m")'
1748 A d
1753 A d
1749 b
1754 b
1750 R b
1755 R b
1751 $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mCH-delete-before-conflict-m")'
1756 $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mCH-delete-before-conflict-m")'
1752 R a
1757 R a
1753 $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mHC-delete-before-conflict-m")'
1758 $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mHC-delete-before-conflict-m")'
1754 R a
1759 R a
General Comments 0
You need to be logged in to leave comments. Login now