##// END OF EJS Templates
narrow: import experimental extension from narrowhg revision cb51d673e9c5...
Augie Fackler -
r36096:a2a6e724 default
parent child Browse files
Show More
@@ -0,0 +1,111 b''
1 # __init__.py - narrowhg extension
2 #
3 # Copyright 2017 Google, Inc.
4 #
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.
7 '''create clones which fetch history data for subset of files (EXPERIMENTAL)'''
8
9 from __future__ import absolute_import
10
11 from mercurial import __version__
12 if __version__.version < '3.7':
13 raise ImportError(
14 'narrowhg requires mercurial 3.7 or newer')
15
16 try:
17 from .__versionnum__ import version
18 __version__ = version
19 except ImportError:
20 pass
21
22 from mercurial import (
23 extensions,
24 hg,
25 localrepo,
26 registrar,
27 util,
28 verify as verifymod,
29 )
30
31 from . import (
32 narrowbundle2,
33 narrowchangegroup,
34 narrowcommands,
35 narrowcopies,
36 narrowdirstate,
37 narrowmerge,
38 narrowpatch,
39 narrowrepo,
40 narrowrevlog,
41 narrowtemplates,
42 narrowwirepeer,
43 )
44
45 configtable = {}
46 configitem = registrar.configitem(configtable)
47 # Narrowhg *has* support for serving ellipsis nodes (which are used at
48 # least by Google's internal server), but that support is pretty
49 # fragile and has a lot of problems on real-world repositories that
50 # have complex graph topologies. This could probably be corrected, but
51 # absent someone needing the full support for ellipsis nodes in
52 # repositories with merges, it's unlikely this work will get done. As
53 # of this writining in late 2017, all repositories large enough for
54 # ellipsis nodes to be a hard requirement also enforce strictly linear
55 # history for other scaling reasons.
56 configitem('experimental', 'narrowservebrokenellipses',
57 default=False,
58 alias=[('narrow', 'serveellipses')],
59 )
60
61 # Export the commands table for Mercurial to see.
62 cmdtable = narrowcommands.table
63
64 localrepo.localrepository._basesupported.add(narrowrepo.requirement)
65
66 def uisetup(ui):
67 """Wraps user-facing mercurial commands with narrow-aware versions."""
68 narrowrevlog.setup()
69 narrowbundle2.setup()
70 narrowmerge.setup()
71 narrowtemplates.setup()
72 narrowcommands.setup()
73 narrowchangegroup.setup()
74 narrowwirepeer.uisetup()
75
76 def reposetup(ui, repo):
77 """Wraps local repositories with narrow repo support."""
78 if not isinstance(repo, localrepo.localrepository):
79 return
80
81 if narrowrepo.requirement in repo.requirements:
82 narrowrepo.wraprepo(repo, True)
83 narrowcopies.setup(repo)
84 narrowdirstate.setup(repo)
85 narrowpatch.setup(repo)
86 narrowwirepeer.reposetup(repo)
87
88 def _narrowvalidpath(orig, repo, path):
89 matcher = getattr(repo, 'narrowmatch', None)
90 if matcher is None:
91 return orig(repo, path)
92 matcher = matcher()
93 if matcher.visitdir(path) or matcher(path):
94 return orig(repo, path)
95 return False
96
97 def _verifierinit(orig, self, repo, matcher=None):
98 # The verifier's matcher argument was desgined for narrowhg, so it should
99 # be None from core. If another extension passes a matcher (unlikely),
100 # we'll have to fail until matchers can be composed more easily.
101 assert matcher is None
102 matcher = getattr(repo, 'narrowmatch', lambda: None)()
103 orig(self, repo, matcher)
104
105 def extsetup(ui):
106 if util.safehasattr(verifymod, '_validpath'):
107 extensions.wrapfunction(verifymod, '_validpath', _narrowvalidpath)
108 else:
109 extensions.wrapfunction(verifymod.verifier, '__init__', _verifierinit)
110 extensions.wrapfunction(hg, 'postshare', narrowrepo.wrappostshare)
111 extensions.wrapfunction(hg, 'copystore', narrowrepo.unsharenarrowspec)
This diff has been collapsed as it changes many lines, (503 lines changed) Show them Hide them
@@ -0,0 +1,503 b''
1 # narrowbundle2.py - bundle2 extensions for narrow repository support
2 #
3 # Copyright 2017 Google, Inc.
4 #
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.
7
8 from __future__ import absolute_import
9
10 import collections
11 import errno
12 import struct
13
14 from mercurial.i18n import _
15 from mercurial.node import (
16 bin,
17 nullid,
18 nullrev,
19 )
20 from mercurial import (
21 bundle2,
22 changegroup,
23 dagutil,
24 error,
25 exchange,
26 extensions,
27 repair,
28 util,
29 wireproto,
30 )
31
32 from . import (
33 narrowrepo,
34 narrowspec,
35 )
36
37 narrowcap = 'narrow'
38 narrowacl_section = 'narrowhgacl'
39 changespecpart = narrowcap + ':changespec'
40 specpart = narrowcap + ':spec'
41 specpart_include = 'include'
42 specpart_exclude = 'exclude'
43 killnodesignal = 'KILL'
44 donesignal = 'DONE'
45 elidedcsheader = '>20s20s20sl' # cset id, p1, p2, len(text)
46 elidedmfheader = '>20s20s20s20sl' # manifest id, p1, p2, link id, len(text)
47 csheadersize = struct.calcsize(elidedcsheader)
48 mfheadersize = struct.calcsize(elidedmfheader)
49
50 # When advertising capabilities, always include narrow clone support.
51 def getrepocaps_narrow(orig, repo, **kwargs):
52 caps = orig(repo, **kwargs)
53 caps[narrowcap] = ['v0']
54 return caps
55
56 def _computeellipsis(repo, common, heads, known, match, depth=None):
57 """Compute the shape of a narrowed DAG.
58
59 Args:
60 repo: The repository we're transferring.
61 common: The roots of the DAG range we're transferring.
62 May be just [nullid], which means all ancestors of heads.
63 heads: The heads of the DAG range we're transferring.
64 match: The narrowmatcher that allows us to identify relevant changes.
65 depth: If not None, only consider nodes to be full nodes if they are at
66 most depth changesets away from one of heads.
67
68 Returns:
69 A tuple of (visitnodes, relevant_nodes, ellipsisroots) where:
70
71 visitnodes: The list of nodes (either full or ellipsis) which
72 need to be sent to the client.
73 relevant_nodes: The set of changelog nodes which change a file inside
74 the narrowspec. The client needs these as non-ellipsis nodes.
75 ellipsisroots: A dict of {rev: parents} that is used in
76 narrowchangegroup to produce ellipsis nodes with the
77 correct parents.
78 """
79 cl = repo.changelog
80 mfl = repo.manifestlog
81
82 cldag = dagutil.revlogdag(cl)
83 # dagutil does not like nullid/nullrev
84 commonrevs = cldag.internalizeall(common - set([nullid])) | set([nullrev])
85 headsrevs = cldag.internalizeall(heads)
86 if depth:
87 revdepth = {h: 0 for h in headsrevs}
88
89 ellipsisheads = collections.defaultdict(set)
90 ellipsisroots = collections.defaultdict(set)
91
92 def addroot(head, curchange):
93 """Add a root to an ellipsis head, splitting heads with 3 roots."""
94 ellipsisroots[head].add(curchange)
95 # Recursively split ellipsis heads with 3 roots by finding the
96 # roots' youngest common descendant which is an elided merge commit.
97 # That descendant takes 2 of the 3 roots as its own, and becomes a
98 # root of the head.
99 while len(ellipsisroots[head]) > 2:
100 child, roots = splithead(head)
101 splitroots(head, child, roots)
102 head = child # Recurse in case we just added a 3rd root
103
104 def splitroots(head, child, roots):
105 ellipsisroots[head].difference_update(roots)
106 ellipsisroots[head].add(child)
107 ellipsisroots[child].update(roots)
108 ellipsisroots[child].discard(child)
109
110 def splithead(head):
111 r1, r2, r3 = sorted(ellipsisroots[head])
112 for nr1, nr2 in ((r2, r3), (r1, r3), (r1, r2)):
113 mid = repo.revs('sort(merge() & %d::%d & %d::%d, -rev)',
114 nr1, head, nr2, head)
115 for j in mid:
116 if j == nr2:
117 return nr2, (nr1, nr2)
118 if j not in ellipsisroots or len(ellipsisroots[j]) < 2:
119 return j, (nr1, nr2)
120 raise error.Abort('Failed to split up ellipsis node! head: %d, '
121 'roots: %d %d %d' % (head, r1, r2, r3))
122
123 missing = list(cl.findmissingrevs(common=commonrevs, heads=headsrevs))
124 visit = reversed(missing)
125 relevant_nodes = set()
126 visitnodes = map(cl.node, missing)
127 required = set(headsrevs) | known
128 for rev in visit:
129 clrev = cl.changelogrevision(rev)
130 ps = cldag.parents(rev)
131 if depth is not None:
132 curdepth = revdepth[rev]
133 for p in ps:
134 revdepth[p] = min(curdepth + 1, revdepth.get(p, depth + 1))
135 needed = False
136 shallow_enough = depth is None or revdepth[rev] <= depth
137 if shallow_enough:
138 curmf = mfl[clrev.manifest].read()
139 if ps:
140 # We choose to not trust the changed files list in
141 # changesets because it's not always correct. TODO: could
142 # we trust it for the non-merge case?
143 p1mf = mfl[cl.changelogrevision(ps[0]).manifest].read()
144 needed = any(match(f) for f in curmf.diff(p1mf).iterkeys())
145 if not needed and len(ps) > 1:
146 # For merge changes, the list of changed files is not
147 # helpful, since we need to emit the merge if a file
148 # in the narrow spec has changed on either side of the
149 # merge. As a result, we do a manifest diff to check.
150 p2mf = mfl[cl.changelogrevision(ps[1]).manifest].read()
151 needed = any(match(f) for f in curmf.diff(p2mf).iterkeys())
152 else:
153 # For a root node, we need to include the node if any
154 # files in the node match the narrowspec.
155 needed = any(match(f) for f in curmf)
156
157 if needed:
158 for head in ellipsisheads[rev]:
159 addroot(head, rev)
160 for p in ps:
161 required.add(p)
162 relevant_nodes.add(cl.node(rev))
163 else:
164 if not ps:
165 ps = [nullrev]
166 if rev in required:
167 for head in ellipsisheads[rev]:
168 addroot(head, rev)
169 for p in ps:
170 ellipsisheads[p].add(rev)
171 else:
172 for p in ps:
173 ellipsisheads[p] |= ellipsisheads[rev]
174
175 # add common changesets as roots of their reachable ellipsis heads
176 for c in commonrevs:
177 for head in ellipsisheads[c]:
178 addroot(head, c)
179 return visitnodes, relevant_nodes, ellipsisroots
180
181 def _packellipsischangegroup(repo, common, match, relevant_nodes,
182 ellipsisroots, visitnodes, depth, source, version):
183 if version in ('01', '02'):
184 raise error.Abort(
185 'ellipsis nodes require at least cg3 on client and server, '
186 'but negotiated version %s' % version)
187 # We wrap cg1packer.revchunk, using a side channel to pass
188 # relevant_nodes into that area. Then if linknode isn't in the
189 # set, we know we have an ellipsis node and we should defer
190 # sending that node's data. We override close() to detect
191 # pending ellipsis nodes and flush them.
192 packer = changegroup.getbundler(version, repo)
193 # Let the packer have access to the narrow matcher so it can
194 # omit filelogs and dirlogs as needed
195 packer._narrow_matcher = lambda : match
196 # Give the packer the list of nodes which should not be
197 # ellipsis nodes. We store this rather than the set of nodes
198 # that should be an ellipsis because for very large histories
199 # we expect this to be significantly smaller.
200 packer.full_nodes = relevant_nodes
201 # Maps ellipsis revs to their roots at the changelog level.
202 packer.precomputed_ellipsis = ellipsisroots
203 # Maps CL revs to per-revlog revisions. Cleared in close() at
204 # the end of each group.
205 packer.clrev_to_localrev = {}
206 packer.next_clrev_to_localrev = {}
207 # Maps changelog nodes to changelog revs. Filled in once
208 # during changelog stage and then left unmodified.
209 packer.clnode_to_rev = {}
210 packer.changelog_done = False
211 # If true, informs the packer that it is serving shallow content and might
212 # need to pack file contents not introduced by the changes being packed.
213 packer.is_shallow = depth is not None
214
215 return packer.generate(common, visitnodes, False, source)
216
217 # Serve a changegroup for a client with a narrow clone.
218 def getbundlechangegrouppart_narrow(bundler, repo, source,
219 bundlecaps=None, b2caps=None, heads=None,
220 common=None, **kwargs):
221 cgversions = b2caps.get('changegroup')
222 getcgkwargs = {}
223 if cgversions: # 3.1 and 3.2 ship with an empty value
224 cgversions = [v for v in cgversions
225 if v in changegroup.supportedoutgoingversions(repo)]
226 if not cgversions:
227 raise ValueError(_('no common changegroup version'))
228 version = getcgkwargs['version'] = max(cgversions)
229 else:
230 raise ValueError(_("server does not advertise changegroup version,"
231 " can't negotiate support for ellipsis nodes"))
232
233 include = sorted(filter(bool, kwargs.get('includepats', [])))
234 exclude = sorted(filter(bool, kwargs.get('excludepats', [])))
235 newmatch = narrowspec.match(repo.root, include=include, exclude=exclude)
236 if not repo.ui.configbool("experimental", "narrowservebrokenellipses"):
237 outgoing = exchange._computeoutgoing(repo, heads, common)
238 if not outgoing.missing:
239 return
240 if util.safehasattr(changegroup, 'getsubsetraw'):
241 # getsubsetraw was replaced with makestream in hg in 92f1e2be8ab6
242 # (2017/09/10).
243 packer = changegroup.getbundler(version, repo)
244 packer._narrow_matcher = lambda : newmatch
245 cg = changegroup.getsubsetraw(repo, outgoing, packer, source)
246 else:
247 def wrappedgetbundler(orig, *args, **kwargs):
248 bundler = orig(*args, **kwargs)
249 bundler._narrow_matcher = lambda : newmatch
250 return bundler
251 with extensions.wrappedfunction(changegroup, 'getbundler',
252 wrappedgetbundler):
253 cg = changegroup.makestream(repo, outgoing, version, source)
254 part = bundler.newpart('changegroup', data=cg)
255 part.addparam('version', version)
256 if 'treemanifest' in repo.requirements:
257 part.addparam('treemanifest', '1')
258
259 if include or exclude:
260 narrowspecpart = bundler.newpart(specpart)
261 if include:
262 narrowspecpart.addparam(
263 specpart_include, '\n'.join(include), mandatory=True)
264 if exclude:
265 narrowspecpart.addparam(
266 specpart_exclude, '\n'.join(exclude), mandatory=True)
267
268 return
269
270 depth = kwargs.get('depth', None)
271 if depth is not None:
272 depth = int(depth)
273 if depth < 1:
274 raise error.Abort(_('depth must be positive, got %d') % depth)
275
276 heads = set(heads or repo.heads())
277 common = set(common or [nullid])
278 oldinclude = sorted(filter(bool, kwargs.get('oldincludepats', [])))
279 oldexclude = sorted(filter(bool, kwargs.get('oldexcludepats', [])))
280 known = {bin(n) for n in kwargs.get('known', [])}
281 if known and (oldinclude != include or oldexclude != exclude):
282 # Steps:
283 # 1. Send kill for "$known & ::common"
284 #
285 # 2. Send changegroup for ::common
286 #
287 # 3. Proceed.
288 #
289 # In the future, we can send kills for only the specific
290 # nodes we know should go away or change shape, and then
291 # send a data stream that tells the client something like this:
292 #
293 # a) apply this changegroup
294 # b) apply nodes XXX, YYY, ZZZ that you already have
295 # c) goto a
296 #
297 # until they've built up the full new state.
298 # Convert to revnums and intersect with "common". The client should
299 # have made it a subset of "common" already, but let's be safe.
300 known = set(repo.revs("%ln & ::%ln", known, common))
301 # TODO: we could send only roots() of this set, and the
302 # list of nodes in common, and the client could work out
303 # what to strip, instead of us explicitly sending every
304 # single node.
305 deadrevs = known
306 def genkills():
307 for r in deadrevs:
308 yield killnodesignal
309 yield repo.changelog.node(r)
310 yield donesignal
311 bundler.newpart(changespecpart, data=genkills())
312 newvisit, newfull, newellipsis = _computeellipsis(
313 repo, set(), common, known, newmatch)
314 if newvisit:
315 cg = _packellipsischangegroup(
316 repo, common, newmatch, newfull, newellipsis,
317 newvisit, depth, source, version)
318 part = bundler.newpart('changegroup', data=cg)
319 part.addparam('version', version)
320 if 'treemanifest' in repo.requirements:
321 part.addparam('treemanifest', '1')
322
323 visitnodes, relevant_nodes, ellipsisroots = _computeellipsis(
324 repo, common, heads, set(), newmatch, depth=depth)
325
326 repo.ui.debug('Found %d relevant revs\n' % len(relevant_nodes))
327 if visitnodes:
328 cg = _packellipsischangegroup(
329 repo, common, newmatch, relevant_nodes, ellipsisroots,
330 visitnodes, depth, source, version)
331 part = bundler.newpart('changegroup', data=cg)
332 part.addparam('version', version)
333 if 'treemanifest' in repo.requirements:
334 part.addparam('treemanifest', '1')
335
336 def applyacl_narrow(repo, kwargs):
337 username = repo.ui.shortuser(repo.ui.username())
338 user_includes = repo.ui.configlist(
339 narrowacl_section, username + '.includes',
340 repo.ui.configlist(narrowacl_section, 'default.includes'))
341 user_excludes = repo.ui.configlist(
342 narrowacl_section, username + '.excludes',
343 repo.ui.configlist(narrowacl_section, 'default.excludes'))
344 if not user_includes:
345 raise error.Abort(_("{} configuration for user {} is empty")
346 .format(narrowacl_section, username))
347
348 user_includes = [
349 'path:.' if p == '*' else 'path:' + p for p in user_includes]
350 user_excludes = [
351 'path:.' if p == '*' else 'path:' + p for p in user_excludes]
352
353 req_includes = set(kwargs.get('includepats', []))
354 req_excludes = set(kwargs.get('excludepats', []))
355
356 invalid_includes = []
357 req_includes, req_excludes = narrowspec.restrictpatterns(
358 req_includes, req_excludes,
359 user_includes, user_excludes, invalid_includes)
360
361 if invalid_includes:
362 raise error.Abort(
363 _("The following includes are not accessible for {}: {}")
364 .format(username, invalid_includes))
365
366 new_args = {}
367 new_args.update(kwargs)
368 new_args['includepats'] = req_includes
369 if req_excludes:
370 new_args['excludepats'] = req_excludes
371 return new_args
372
373 @bundle2.parthandler(specpart, (specpart_include, specpart_exclude))
374 def _handlechangespec_2(op, inpart):
375 includepats = set(inpart.params.get(specpart_include, '').splitlines())
376 excludepats = set(inpart.params.get(specpart_exclude, '').splitlines())
377 narrowspec.save(op.repo, includepats, excludepats)
378 if not narrowrepo.requirement in op.repo.requirements:
379 op.repo.requirements.add(narrowrepo.requirement)
380 op.repo._writerequirements()
381 op.repo.invalidate(clearfilecache=True)
382
383 @bundle2.parthandler(changespecpart)
384 def _handlechangespec(op, inpart):
385 repo = op.repo
386 cl = repo.changelog
387
388 # changesets which need to be stripped entirely. either they're no longer
389 # needed in the new narrow spec, or the server is sending a replacement
390 # in the changegroup part.
391 clkills = set()
392
393 # A changespec part contains all the updates to ellipsis nodes
394 # that will happen as a result of widening or narrowing a
395 # repo. All the changes that this block encounters are ellipsis
396 # nodes or flags to kill an existing ellipsis.
397 chunksignal = changegroup.readexactly(inpart, 4)
398 while chunksignal != donesignal:
399 if chunksignal == killnodesignal:
400 # a node used to be an ellipsis but isn't anymore
401 ck = changegroup.readexactly(inpart, 20)
402 if cl.hasnode(ck):
403 clkills.add(ck)
404 else:
405 raise error.Abort(
406 _('unexpected changespec node chunk type: %s') % chunksignal)
407 chunksignal = changegroup.readexactly(inpart, 4)
408
409 if clkills:
410 # preserve bookmarks that repair.strip() would otherwise strip
411 bmstore = repo._bookmarks
412 class dummybmstore(dict):
413 def applychanges(self, repo, tr, changes):
414 pass
415 def recordchange(self, tr): # legacy version
416 pass
417 repo._bookmarks = dummybmstore()
418 chgrpfile = repair.strip(op.ui, repo, list(clkills), backup=True,
419 topic='widen')
420 repo._bookmarks = bmstore
421 if chgrpfile:
422 # presence of _widen_bundle attribute activates widen handler later
423 op._widen_bundle = chgrpfile
424 # Set the new narrowspec if we're widening. The setnewnarrowpats() method
425 # will currently always be there when using the core+narrowhg server, but
426 # other servers may include a changespec part even when not widening (e.g.
427 # because we're deepening a shallow repo).
428 if util.safehasattr(repo, 'setnewnarrowpats'):
429 repo.setnewnarrowpats()
430
431 def handlechangegroup_widen(op, inpart):
432 """Changegroup exchange handler which restores temporarily-stripped nodes"""
433 # We saved a bundle with stripped node data we must now restore.
434 # This approach is based on mercurial/repair.py@6ee26a53c111.
435 repo = op.repo
436 ui = op.ui
437
438 chgrpfile = op._widen_bundle
439 del op._widen_bundle
440 vfs = repo.vfs
441
442 ui.note(_("adding branch\n"))
443 f = vfs.open(chgrpfile, "rb")
444 try:
445 gen = exchange.readbundle(ui, f, chgrpfile, vfs)
446 if not ui.verbose:
447 # silence internal shuffling chatter
448 ui.pushbuffer()
449 if isinstance(gen, bundle2.unbundle20):
450 with repo.transaction('strip') as tr:
451 bundle2.processbundle(repo, gen, lambda: tr)
452 else:
453 gen.apply(repo, 'strip', 'bundle:' + vfs.join(chgrpfile), True)
454 if not ui.verbose:
455 ui.popbuffer()
456 finally:
457 f.close()
458
459 # remove undo files
460 for undovfs, undofile in repo.undofiles():
461 try:
462 undovfs.unlink(undofile)
463 except OSError as e:
464 if e.errno != errno.ENOENT:
465 ui.warn(_('error removing %s: %s\n') %
466 (undovfs.join(undofile), str(e)))
467
468 # Remove partial backup only if there were no exceptions
469 vfs.unlink(chgrpfile)
470
471 def setup():
472 """Enable narrow repo support in bundle2-related extension points."""
473 extensions.wrapfunction(bundle2, 'getrepocaps', getrepocaps_narrow)
474
475 wireproto.gboptsmap['narrow'] = 'boolean'
476 wireproto.gboptsmap['depth'] = 'plain'
477 wireproto.gboptsmap['oldincludepats'] = 'csv'
478 wireproto.gboptsmap['oldexcludepats'] = 'csv'
479 wireproto.gboptsmap['includepats'] = 'csv'
480 wireproto.gboptsmap['excludepats'] = 'csv'
481 wireproto.gboptsmap['known'] = 'csv'
482
483 # Extend changegroup serving to handle requests from narrow clients.
484 origcgfn = exchange.getbundle2partsmapping['changegroup']
485 def wrappedcgfn(*args, **kwargs):
486 repo = args[1]
487 if repo.ui.has_section(narrowacl_section):
488 getbundlechangegrouppart_narrow(
489 *args, **applyacl_narrow(repo, kwargs))
490 elif kwargs.get('narrow', False):
491 getbundlechangegrouppart_narrow(*args, **kwargs)
492 else:
493 origcgfn(*args, **kwargs)
494 exchange.getbundle2partsmapping['changegroup'] = wrappedcgfn
495
496 # Extend changegroup receiver so client can fixup after widen requests.
497 origcghandler = bundle2.parthandlermapping['changegroup']
498 def wrappedcghandler(op, inpart):
499 origcghandler(op, inpart)
500 if util.safehasattr(op, '_widen_bundle'):
501 handlechangegroup_widen(op, inpart)
502 wrappedcghandler.params = origcghandler.params
503 bundle2.parthandlermapping['changegroup'] = wrappedcghandler
@@ -0,0 +1,385 b''
1 # narrowchangegroup.py - narrow clone changegroup creation and consumption
2 #
3 # Copyright 2017 Google, Inc.
4 #
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.
7
8 from __future__ import absolute_import
9
10 from mercurial.i18n import _
11 from mercurial import (
12 changegroup,
13 error,
14 extensions,
15 manifest,
16 mdiff,
17 node,
18 util,
19 )
20
21 from . import (
22 narrowrepo,
23 narrowrevlog,
24 )
25
26 def setup():
27
28 def supportedoutgoingversions(orig, repo):
29 versions = orig(repo)
30 if narrowrepo.requirement in repo.requirements:
31 versions.discard('01')
32 versions.discard('02')
33 return versions
34
35 extensions.wrapfunction(changegroup, 'supportedoutgoingversions',
36 supportedoutgoingversions)
37
38 def prune(orig, self, revlog, missing, commonrevs):
39 if isinstance(revlog, manifest.manifestrevlog):
40 matcher = getattr(self._repo, 'narrowmatch',
41 getattr(self, '_narrow_matcher', None))
42 if (matcher is not None and
43 not matcher().visitdir(revlog._dir[:-1] or '.')):
44 return []
45 return orig(self, revlog, missing, commonrevs)
46
47 extensions.wrapfunction(changegroup.cg1packer, 'prune', prune)
48
49 def generatefiles(orig, self, changedfiles, linknodes, commonrevs,
50 source):
51 matcher = getattr(self._repo, 'narrowmatch',
52 getattr(self, '_narrow_matcher', None))
53 if matcher is not None:
54 narrowmatch = matcher()
55 changedfiles = filter(narrowmatch, changedfiles)
56 if getattr(self, 'is_shallow', False):
57 # See comment in generate() for why this sadness is a thing.
58 mfdicts = self._mfdicts
59 del self._mfdicts
60 # In a shallow clone, the linknodes callback needs to also include
61 # those file nodes that are in the manifests we sent but weren't
62 # introduced by those manifests.
63 commonctxs = [self._repo[c] for c in commonrevs]
64 oldlinknodes = linknodes
65 clrev = self._repo.changelog.rev
66 def linknodes(flog, fname):
67 for c in commonctxs:
68 try:
69 fnode = c.filenode(fname)
70 self.clrev_to_localrev[c.rev()] = flog.rev(fnode)
71 except error.ManifestLookupError:
72 pass
73 links = oldlinknodes(flog, fname)
74 if len(links) != len(mfdicts):
75 for mf, lr in mfdicts:
76 fnode = mf.get(fname, None)
77 if fnode in links:
78 links[fnode] = min(links[fnode], lr, key=clrev)
79 elif fnode:
80 links[fnode] = lr
81 return links
82 return orig(self, changedfiles, linknodes, commonrevs, source)
83 extensions.wrapfunction(
84 changegroup.cg1packer, 'generatefiles', generatefiles)
85
86 def ellipsisdata(packer, rev, revlog, p1, p2, data, linknode):
87 n = revlog.node(rev)
88 p1n, p2n = revlog.node(p1), revlog.node(p2)
89 flags = revlog.flags(rev)
90 flags |= narrowrevlog.ELLIPSIS_NODE_FLAG
91 meta = packer.builddeltaheader(
92 n, p1n, p2n, node.nullid, linknode, flags)
93 # TODO: try and actually send deltas for ellipsis data blocks
94 diffheader = mdiff.trivialdiffheader(len(data))
95 l = len(meta) + len(diffheader) + len(data)
96 return ''.join((changegroup.chunkheader(l),
97 meta,
98 diffheader,
99 data))
100
101 def close(orig, self):
102 getattr(self, 'clrev_to_localrev', {}).clear()
103 if getattr(self, 'next_clrev_to_localrev', {}):
104 self.clrev_to_localrev = self.next_clrev_to_localrev
105 del self.next_clrev_to_localrev
106 self.changelog_done = True
107 return orig(self)
108 extensions.wrapfunction(changegroup.cg1packer, 'close', close)
109
110 # In a perfect world, we'd generate better ellipsis-ified graphs
111 # for non-changelog revlogs. In practice, we haven't started doing
112 # that yet, so the resulting DAGs for the manifestlog and filelogs
113 # are actually full of bogus parentage on all the ellipsis
114 # nodes. This has the side effect that, while the contents are
115 # correct, the individual DAGs might be completely out of whack in
116 # a case like 882681bc3166 and its ancestors (back about 10
117 # revisions or so) in the main hg repo.
118 #
119 # The one invariant we *know* holds is that the new (potentially
120 # bogus) DAG shape will be valid if we order the nodes in the
121 # order that they're introduced in dramatis personae by the
122 # changelog, so what we do is we sort the non-changelog histories
123 # by the order in which they are used by the changelog.
124 def _sortgroup(orig, self, revlog, nodelist, lookup):
125 if not util.safehasattr(self, 'full_nodes') or not self.clnode_to_rev:
126 return orig(self, revlog, nodelist, lookup)
127 key = lambda n: self.clnode_to_rev[lookup(n)]
128 return [revlog.rev(n) for n in sorted(nodelist, key=key)]
129
130 extensions.wrapfunction(changegroup.cg1packer, '_sortgroup', _sortgroup)
131
132 def generate(orig, self, commonrevs, clnodes, fastpathlinkrev, source):
133 '''yield a sequence of changegroup chunks (strings)'''
134 # Note: other than delegating to orig, the only deviation in
135 # logic from normal hg's generate is marked with BEGIN/END
136 # NARROW HACK.
137 if not util.safehasattr(self, 'full_nodes'):
138 # not sending a narrow bundle
139 for x in orig(self, commonrevs, clnodes, fastpathlinkrev, source):
140 yield x
141 return
142
143 repo = self._repo
144 cl = repo.changelog
145 mfl = repo.manifestlog
146 mfrevlog = mfl._revlog
147
148 clrevorder = {}
149 mfs = {} # needed manifests
150 fnodes = {} # needed file nodes
151 changedfiles = set()
152
153 # Callback for the changelog, used to collect changed files and manifest
154 # nodes.
155 # Returns the linkrev node (identity in the changelog case).
156 def lookupcl(x):
157 c = cl.read(x)
158 clrevorder[x] = len(clrevorder)
159 # BEGIN NARROW HACK
160 #
161 # Only update mfs if x is going to be sent. Otherwise we
162 # end up with bogus linkrevs specified for manifests and
163 # we skip some manifest nodes that we should otherwise
164 # have sent.
165 if x in self.full_nodes or cl.rev(x) in self.precomputed_ellipsis:
166 n = c[0]
167 # record the first changeset introducing this manifest version
168 mfs.setdefault(n, x)
169 # Set this narrow-specific dict so we have the lowest manifest
170 # revnum to look up for this cl revnum. (Part of mapping
171 # changelog ellipsis parents to manifest ellipsis parents)
172 self.next_clrev_to_localrev.setdefault(cl.rev(x),
173 mfrevlog.rev(n))
174 # We can't trust the changed files list in the changeset if the
175 # client requested a shallow clone.
176 if self.is_shallow:
177 changedfiles.update(mfl[c[0]].read().keys())
178 else:
179 changedfiles.update(c[3])
180 # END NARROW HACK
181 # Record a complete list of potentially-changed files in
182 # this manifest.
183 return x
184
185 self._verbosenote(_('uncompressed size of bundle content:\n'))
186 size = 0
187 for chunk in self.group(clnodes, cl, lookupcl, units=_('changesets')):
188 size += len(chunk)
189 yield chunk
190 self._verbosenote(_('%8.i (changelog)\n') % size)
191
192 # We need to make sure that the linkrev in the changegroup refers to
193 # the first changeset that introduced the manifest or file revision.
194 # The fastpath is usually safer than the slowpath, because the filelogs
195 # are walked in revlog order.
196 #
197 # When taking the slowpath with reorder=None and the manifest revlog
198 # uses generaldelta, the manifest may be walked in the "wrong" order.
199 # Without 'clrevorder', we would get an incorrect linkrev (see fix in
200 # cc0ff93d0c0c).
201 #
202 # When taking the fastpath, we are only vulnerable to reordering
203 # of the changelog itself. The changelog never uses generaldelta, so
204 # it is only reordered when reorder=True. To handle this case, we
205 # simply take the slowpath, which already has the 'clrevorder' logic.
206 # This was also fixed in cc0ff93d0c0c.
207 fastpathlinkrev = fastpathlinkrev and not self._reorder
208 # Treemanifests don't work correctly with fastpathlinkrev
209 # either, because we don't discover which directory nodes to
210 # send along with files. This could probably be fixed.
211 fastpathlinkrev = fastpathlinkrev and (
212 'treemanifest' not in repo.requirements)
213 # Shallow clones also don't work correctly with fastpathlinkrev
214 # because file nodes may need to be sent for a manifest even if they
215 # weren't introduced by that manifest.
216 fastpathlinkrev = fastpathlinkrev and not self.is_shallow
217
218 moreargs = []
219 if self.generatemanifests.func_code.co_argcount == 7:
220 # The source argument was added to generatemanifests in hg in
221 # 75cc1f1e11f2 (2017/09/11).
222 moreargs.append(source)
223 for chunk in self.generatemanifests(commonrevs, clrevorder,
224 fastpathlinkrev, mfs, fnodes, *moreargs):
225 yield chunk
226 # BEGIN NARROW HACK
227 mfdicts = None
228 if self.is_shallow:
229 mfdicts = [(self._repo.manifestlog[n].read(), lr)
230 for (n, lr) in mfs.iteritems()]
231 # END NARROW HACK
232 mfs.clear()
233 clrevs = set(cl.rev(x) for x in clnodes)
234
235 if not fastpathlinkrev:
236 def linknodes(unused, fname):
237 return fnodes.get(fname, {})
238 else:
239 cln = cl.node
240 def linknodes(filerevlog, fname):
241 llr = filerevlog.linkrev
242 fln = filerevlog.node
243 revs = ((r, llr(r)) for r in filerevlog)
244 return dict((fln(r), cln(lr)) for r, lr in revs if lr in clrevs)
245
246 # BEGIN NARROW HACK
247 #
248 # We need to pass the mfdicts variable down into
249 # generatefiles(), but more than one command might have
250 # wrapped generatefiles so we can't modify the function
251 # signature. Instead, we pass the data to ourselves using an
252 # instance attribute. I'm sorry.
253 self._mfdicts = mfdicts
254 # END NARROW HACK
255 for chunk in self.generatefiles(changedfiles, linknodes, commonrevs,
256 source):
257 yield chunk
258
259 yield self.close()
260
261 if clnodes:
262 repo.hook('outgoing', node=node.hex(clnodes[0]), source=source)
263 extensions.wrapfunction(changegroup.cg1packer, 'generate', generate)
264
265 def revchunk(orig, self, revlog, rev, prev, linknode):
266 if not util.safehasattr(self, 'full_nodes'):
267 # not sending a narrow changegroup
268 for x in orig(self, revlog, rev, prev, linknode):
269 yield x
270 return
271 # build up some mapping information that's useful later. See
272 # the local() nested function below.
273 if not self.changelog_done:
274 self.clnode_to_rev[linknode] = rev
275 linkrev = rev
276 self.clrev_to_localrev[linkrev] = rev
277 else:
278 linkrev = self.clnode_to_rev[linknode]
279 self.clrev_to_localrev[linkrev] = rev
280 # This is a node to send in full, because the changeset it
281 # corresponds to was a full changeset.
282 if linknode in self.full_nodes:
283 for x in orig(self, revlog, rev, prev, linknode):
284 yield x
285 return
286 # At this point, a node can either be one we should skip or an
287 # ellipsis. If it's not an ellipsis, bail immediately.
288 if linkrev not in self.precomputed_ellipsis:
289 return
290 linkparents = self.precomputed_ellipsis[linkrev]
291 def local(clrev):
292 """Turn a changelog revnum into a local revnum.
293
294 The ellipsis dag is stored as revnums on the changelog,
295 but when we're producing ellipsis entries for
296 non-changelog revlogs, we need to turn those numbers into
297 something local. This does that for us, and during the
298 changelog sending phase will also expand the stored
299 mappings as needed.
300 """
301 if clrev == node.nullrev:
302 return node.nullrev
303 if not self.changelog_done:
304 # If we're doing the changelog, it's possible that we
305 # have a parent that is already on the client, and we
306 # need to store some extra mapping information so that
307 # our contained ellipsis nodes will be able to resolve
308 # their parents.
309 if clrev not in self.clrev_to_localrev:
310 clnode = revlog.node(clrev)
311 self.clnode_to_rev[clnode] = clrev
312 return clrev
313 # Walk the ellipsis-ized changelog breadth-first looking for a
314 # change that has been linked from the current revlog.
315 #
316 # For a flat manifest revlog only a single step should be necessary
317 # as all relevant changelog entries are relevant to the flat
318 # manifest.
319 #
320 # For a filelog or tree manifest dirlog however not every changelog
321 # entry will have been relevant, so we need to skip some changelog
322 # nodes even after ellipsis-izing.
323 walk = [clrev]
324 while walk:
325 p = walk[0]
326 walk = walk[1:]
327 if p in self.clrev_to_localrev:
328 return self.clrev_to_localrev[p]
329 elif p in self.full_nodes:
330 walk.extend([pp for pp in self._repo.changelog.parentrevs(p)
331 if pp != node.nullrev])
332 elif p in self.precomputed_ellipsis:
333 walk.extend([pp for pp in self.precomputed_ellipsis[p]
334 if pp != node.nullrev])
335 else:
336 # In this case, we've got an ellipsis with parents
337 # outside the current bundle (likely an
338 # incremental pull). We "know" that we can use the
339 # value of this same revlog at whatever revision
340 # is pointed to by linknode. "Know" is in scare
341 # quotes because I haven't done enough examination
342 # of edge cases to convince myself this is really
343 # a fact - it works for all the (admittedly
344 # thorough) cases in our testsuite, but I would be
345 # somewhat unsurprised to find a case in the wild
346 # where this breaks down a bit. That said, I don't
347 # know if it would hurt anything.
348 for i in xrange(rev, 0, -1):
349 if revlog.linkrev(i) == clrev:
350 return i
351 # We failed to resolve a parent for this node, so
352 # we crash the changegroup construction.
353 raise error.Abort(
354 'unable to resolve parent while packing %r %r'
355 ' for changeset %r' % (revlog.indexfile, rev, clrev))
356 return node.nullrev
357
358 if not linkparents or (
359 revlog.parentrevs(rev) == (node.nullrev, node.nullrev)):
360 p1, p2 = node.nullrev, node.nullrev
361 elif len(linkparents) == 1:
362 p1, = sorted(local(p) for p in linkparents)
363 p2 = node.nullrev
364 else:
365 p1, p2 = sorted(local(p) for p in linkparents)
366 yield ellipsisdata(
367 self, rev, revlog, p1, p2, revlog.revision(rev), linknode)
368 extensions.wrapfunction(changegroup.cg1packer, 'revchunk', revchunk)
369
370 def deltaparent(orig, self, revlog, rev, p1, p2, prev):
371 if util.safehasattr(self, 'full_nodes'):
372 # TODO: send better deltas when in narrow mode.
373 #
374 # changegroup.group() loops over revisions to send,
375 # including revisions we'll skip. What this means is that
376 # `prev` will be a potentially useless delta base for all
377 # ellipsis nodes, as the client likely won't have it. In
378 # the future we should do bookkeeping about which nodes
379 # have been sent to the client, and try to be
380 # significantly smarter about delta bases. This is
381 # slightly tricky because this same code has to work for
382 # all revlogs, and we don't have the linkrev/linknode here.
383 return p1
384 return orig(self, revlog, rev, p1, p2, prev)
385 extensions.wrapfunction(changegroup.cg2packer, 'deltaparent', deltaparent)
@@ -0,0 +1,402 b''
1 # narrowcommands.py - command modifications for narrowhg extension
2 #
3 # Copyright 2017 Google, Inc.
4 #
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.
7 from __future__ import absolute_import
8
9 import itertools
10
11 from mercurial.i18n import _
12 from mercurial import (
13 cmdutil,
14 commands,
15 discovery,
16 error,
17 exchange,
18 extensions,
19 hg,
20 merge,
21 node,
22 registrar,
23 repair,
24 repoview,
25 util,
26 )
27
28 from . import (
29 narrowbundle2,
30 narrowrepo,
31 narrowspec,
32 )
33
34 table = {}
35 command = registrar.command(table)
36
37 def setup():
38 """Wraps user-facing mercurial commands with narrow-aware versions."""
39
40 entry = extensions.wrapcommand(commands.table, 'clone', clonenarrowcmd)
41 entry[1].append(('', 'narrow', None,
42 _("create a narrow clone of select files")))
43 entry[1].append(('', 'depth', '',
44 _("limit the history fetched by distance from heads")))
45 # TODO(durin42): unify sparse/narrow --include/--exclude logic a bit
46 if 'sparse' not in extensions.enabled():
47 entry[1].append(('', 'include', [],
48 _("specifically fetch this file/directory")))
49 entry[1].append(
50 ('', 'exclude', [],
51 _("do not fetch this file/directory, even if included")))
52
53 entry = extensions.wrapcommand(commands.table, 'pull', pullnarrowcmd)
54 entry[1].append(('', 'depth', '',
55 _("limit the history fetched by distance from heads")))
56
57 extensions.wrapcommand(commands.table, 'archive', archivenarrowcmd)
58
59 def expandpull(pullop, includepats, excludepats):
60 if not narrowspec.needsexpansion(includepats):
61 return includepats, excludepats
62
63 heads = pullop.heads or pullop.rheads
64 includepats, excludepats = pullop.remote.expandnarrow(
65 includepats, excludepats, heads)
66 pullop.repo.ui.debug('Expanded narrowspec to inc=%s, exc=%s\n' % (
67 includepats, excludepats))
68 return set(includepats), set(excludepats)
69
70 def clonenarrowcmd(orig, ui, repo, *args, **opts):
71 """Wraps clone command, so 'hg clone' first wraps localrepo.clone()."""
72 wrappedextraprepare = util.nullcontextmanager()
73 opts_narrow = opts['narrow']
74 if opts_narrow:
75 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
76 # Create narrow spec patterns from clone flags
77 includepats = narrowspec.parsepatterns(opts['include'])
78 excludepats = narrowspec.parsepatterns(opts['exclude'])
79
80 # If necessary, ask the server to expand the narrowspec.
81 includepats, excludepats = expandpull(
82 pullop, includepats, excludepats)
83
84 if not includepats and excludepats:
85 # If nothing was included, we assume the user meant to include
86 # everything, except what they asked to exclude.
87 includepats = {'path:.'}
88
89 narrowspec.save(pullop.repo, includepats, excludepats)
90
91 # This will populate 'includepats' etc with the values from the
92 # narrowspec we just saved.
93 orig(pullop, kwargs)
94
95 if opts.get('depth'):
96 kwargs['depth'] = opts['depth']
97 wrappedextraprepare = extensions.wrappedfunction(exchange,
98 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
99
100 def pullnarrow(orig, repo, *args, **kwargs):
101 narrowrepo.wraprepo(repo.unfiltered(), opts_narrow)
102 if isinstance(repo, repoview.repoview):
103 repo.__class__.__bases__ = (repo.__class__.__bases__[0],
104 repo.unfiltered().__class__)
105 if opts_narrow:
106 repo.requirements.add(narrowrepo.requirement)
107 repo._writerequirements()
108
109 return orig(repo, *args, **kwargs)
110
111 wrappedpull = extensions.wrappedfunction(exchange, 'pull', pullnarrow)
112
113 with wrappedextraprepare, wrappedpull:
114 return orig(ui, repo, *args, **opts)
115
116 def pullnarrowcmd(orig, ui, repo, *args, **opts):
117 """Wraps pull command to allow modifying narrow spec."""
118 wrappedextraprepare = util.nullcontextmanager()
119 if narrowrepo.requirement in repo.requirements:
120
121 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
122 orig(pullop, kwargs)
123 if opts.get('depth'):
124 kwargs['depth'] = opts['depth']
125 wrappedextraprepare = extensions.wrappedfunction(exchange,
126 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
127
128 with wrappedextraprepare:
129 return orig(ui, repo, *args, **opts)
130
131 def archivenarrowcmd(orig, ui, repo, *args, **opts):
132 """Wraps archive command to narrow the default includes."""
133 if narrowrepo.requirement in repo.requirements:
134 repo_includes, repo_excludes = repo.narrowpats
135 includes = set(opts.get('include', []))
136 excludes = set(opts.get('exclude', []))
137 includes, excludes = narrowspec.restrictpatterns(
138 includes, excludes, repo_includes, repo_excludes)
139 if includes:
140 opts['include'] = includes
141 if excludes:
142 opts['exclude'] = excludes
143 return orig(ui, repo, *args, **opts)
144
145 def pullbundle2extraprepare(orig, pullop, kwargs):
146 repo = pullop.repo
147 if narrowrepo.requirement not in repo.requirements:
148 return orig(pullop, kwargs)
149
150 if narrowbundle2.narrowcap not in pullop.remotebundle2caps:
151 raise error.Abort(_("server doesn't support narrow clones"))
152 orig(pullop, kwargs)
153 kwargs['narrow'] = True
154 include, exclude = repo.narrowpats
155 kwargs['oldincludepats'] = include
156 kwargs['oldexcludepats'] = exclude
157 kwargs['includepats'] = include
158 kwargs['excludepats'] = exclude
159 kwargs['known'] = [node.hex(ctx.node()) for ctx in
160 repo.set('::%ln', pullop.common)
161 if ctx.node() != node.nullid]
162 if not kwargs['known']:
163 # Mercurial serialized an empty list as '' and deserializes it as
164 # [''], so delete it instead to avoid handling the empty string on the
165 # server.
166 del kwargs['known']
167
168 extensions.wrapfunction(exchange,'_pullbundle2extraprepare',
169 pullbundle2extraprepare)
170
171 def _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
172 newincludes, newexcludes, force):
173 oldmatch = narrowspec.match(repo.root, oldincludes, oldexcludes)
174 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
175
176 # This is essentially doing "hg outgoing" to find all local-only
177 # commits. We will then check that the local-only commits don't
178 # have any changes to files that will be untracked.
179 unfi = repo.unfiltered()
180 outgoing = discovery.findcommonoutgoing(unfi, remote,
181 commoninc=commoninc)
182 ui.status(_('looking for local changes to affected paths\n'))
183 localnodes = []
184 for n in itertools.chain(outgoing.missing, outgoing.excluded):
185 if any(oldmatch(f) and not newmatch(f) for f in unfi[n].files()):
186 localnodes.append(n)
187 revstostrip = unfi.revs('descendants(%ln)', localnodes)
188 hiddenrevs = repoview.filterrevs(repo, 'visible')
189 visibletostrip = list(repo.changelog.node(r)
190 for r in (revstostrip - hiddenrevs))
191 if visibletostrip:
192 ui.status(_('The following changeset(s) or their ancestors have '
193 'local changes not on the remote:\n'))
194 maxnodes = 10
195 if ui.verbose or len(visibletostrip) <= maxnodes:
196 for n in visibletostrip:
197 ui.status('%s\n' % node.short(n))
198 else:
199 for n in visibletostrip[:maxnodes]:
200 ui.status('%s\n' % node.short(n))
201 ui.status(_('...and %d more, use --verbose to list all\n') %
202 (len(visibletostrip) - maxnodes))
203 if not force:
204 raise error.Abort(_('local changes found'),
205 hint=_('use --force-delete-local-changes to '
206 'ignore'))
207
208 if revstostrip:
209 tostrip = [unfi.changelog.node(r) for r in revstostrip]
210 if repo['.'].node() in tostrip:
211 # stripping working copy, so move to a different commit first
212 urev = max(repo.revs('(::%n) - %ln + null',
213 repo['.'].node(), visibletostrip))
214 hg.clean(repo, urev)
215 repair.strip(ui, unfi, tostrip, topic='narrow')
216
217 todelete = []
218 for f, f2, size in repo.store.datafiles():
219 if f.startswith('data/'):
220 file = f[5:-2]
221 if not newmatch(file):
222 todelete.append(f)
223 elif f.startswith('meta/'):
224 dir = f[5:-13]
225 dirs = ['.'] + sorted(util.dirs({dir})) + [dir]
226 include = True
227 for d in dirs:
228 visit = newmatch.visitdir(d)
229 if not visit:
230 include = False
231 break
232 if visit == 'all':
233 break
234 if not include:
235 todelete.append(f)
236
237 repo.destroying()
238
239 with repo.transaction("narrowing"):
240 for f in todelete:
241 ui.status(_('deleting %s\n') % f)
242 util.unlinkpath(repo.svfs.join(f))
243 repo.store.markremoved(f)
244
245 for f in repo.dirstate:
246 if not newmatch(f):
247 repo.dirstate.drop(f)
248 repo.wvfs.unlinkpath(f)
249 repo.setnarrowpats(newincludes, newexcludes)
250
251 repo.destroyed()
252
253 def _widen(ui, repo, remote, commoninc, newincludes, newexcludes):
254 newmatch = narrowspec.match(repo.root, newincludes, newexcludes)
255
256 # TODO(martinvonz): Get expansion working with widening/narrowing.
257 if narrowspec.needsexpansion(newincludes):
258 raise error.Abort('Expansion not yet supported on pull')
259
260 def pullbundle2extraprepare_widen(orig, pullop, kwargs):
261 orig(pullop, kwargs)
262 # The old{in,ex}cludepats have already been set by orig()
263 kwargs['includepats'] = newincludes
264 kwargs['excludepats'] = newexcludes
265 wrappedextraprepare = extensions.wrappedfunction(exchange,
266 '_pullbundle2extraprepare', pullbundle2extraprepare_widen)
267
268 # define a function that narrowbundle2 can call after creating the
269 # backup bundle, but before applying the bundle from the server
270 def setnewnarrowpats():
271 repo.setnarrowpats(newincludes, newexcludes)
272 repo.setnewnarrowpats = setnewnarrowpats
273
274 ds = repo.dirstate
275 p1, p2 = ds.p1(), ds.p2()
276 with ds.parentchange():
277 ds.setparents(node.nullid, node.nullid)
278 common = commoninc[0]
279 with wrappedextraprepare:
280 exchange.pull(repo, remote, heads=common)
281 with ds.parentchange():
282 ds.setparents(p1, p2)
283
284 actions = {k: [] for k in 'a am f g cd dc r dm dg m e k p pr'.split()}
285 addgaction = actions['g'].append
286
287 mf = repo['.'].manifest().matches(newmatch)
288 for f, fn in mf.iteritems():
289 if f not in repo.dirstate:
290 addgaction((f, (mf.flags(f), False),
291 "add from widened narrow clone"))
292
293 merge.applyupdates(repo, actions, wctx=repo[None],
294 mctx=repo['.'], overwrite=False)
295 merge.recordupdates(repo, actions, branchmerge=False)
296
297 # TODO(rdamazio): Make new matcher format and update description
298 @command('tracked',
299 [('', 'addinclude', [], _('new paths to include')),
300 ('', 'removeinclude', [], _('old paths to no longer include')),
301 ('', 'addexclude', [], _('new paths to exclude')),
302 ('', 'removeexclude', [], _('old paths to no longer exclude')),
303 ('', 'clear', False, _('whether to replace the existing narrowspec')),
304 ('', 'force-delete-local-changes', False,
305 _('forces deletion of local changes when narrowing')),
306 ] + commands.remoteopts,
307 _('[OPTIONS]... [REMOTE]'),
308 inferrepo=True)
309 def trackedcmd(ui, repo, remotepath=None, *pats, **opts):
310 """show or change the current narrowspec
311
312 With no argument, shows the current narrowspec entries, one per line. Each
313 line will be prefixed with 'I' or 'X' for included or excluded patterns,
314 respectively.
315
316 The narrowspec is comprised of expressions to match remote files and/or
317 directories that should be pulled into your client.
318 The narrowspec has *include* and *exclude* expressions, with excludes always
319 trumping includes: that is, if a file matches an exclude expression, it will
320 be excluded even if it also matches an include expression.
321 Excluding files that were never included has no effect.
322
323 Each included or excluded entry is in the format described by
324 'hg help patterns'.
325
326 The options allow you to add or remove included and excluded expressions.
327
328 If --clear is specified, then all previous includes and excludes are DROPPED
329 and replaced by the new ones specified to --addinclude and --addexclude.
330 If --clear is specified without any further options, the narrowspec will be
331 empty and will not match any files.
332 """
333 if narrowrepo.requirement not in repo.requirements:
334 ui.warn(_('The narrow command is only supported on respositories cloned'
335 ' with --narrow.\n'))
336 return 1
337
338 # Before supporting, decide whether it "hg tracked --clear" should mean
339 # tracking no paths or all paths.
340 if opts['clear']:
341 ui.warn(_('The --clear option is not yet supported.\n'))
342 return 1
343
344 if narrowspec.needsexpansion(opts['addinclude'] + opts['addexclude']):
345 raise error.Abort('Expansion not yet supported on widen/narrow')
346
347 addedincludes = narrowspec.parsepatterns(opts['addinclude'])
348 removedincludes = narrowspec.parsepatterns(opts['removeinclude'])
349 addedexcludes = narrowspec.parsepatterns(opts['addexclude'])
350 removedexcludes = narrowspec.parsepatterns(opts['removeexclude'])
351 widening = addedincludes or removedexcludes
352 narrowing = removedincludes or addedexcludes
353 only_show = not widening and not narrowing
354
355 # Only print the current narrowspec.
356 if only_show:
357 include, exclude = repo.narrowpats
358
359 ui.pager('tracked')
360 fm = ui.formatter('narrow', opts)
361 for i in sorted(include):
362 fm.startitem()
363 fm.write('status', '%s ', 'I', label='narrow.included')
364 fm.write('pat', '%s\n', i, label='narrow.included')
365 for i in sorted(exclude):
366 fm.startitem()
367 fm.write('status', '%s ', 'X', label='narrow.excluded')
368 fm.write('pat', '%s\n', i, label='narrow.excluded')
369 fm.end()
370 return 0
371
372 with repo.wlock(), repo.lock():
373 cmdutil.bailifchanged(repo)
374
375 # Find the revisions we have in common with the remote. These will
376 # be used for finding local-only changes for narrowing. They will
377 # also define the set of revisions to update for widening.
378 remotepath = ui.expandpath(remotepath or 'default')
379 url, branches = hg.parseurl(remotepath)
380 ui.status(_('comparing with %s\n') % util.hidepassword(url))
381 remote = hg.peer(repo, opts, url)
382 commoninc = discovery.findcommonincoming(repo, remote)
383
384 oldincludes, oldexcludes = repo.narrowpats
385 if narrowing:
386 newincludes = oldincludes - removedincludes
387 newexcludes = oldexcludes | addedexcludes
388 _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
389 newincludes, newexcludes,
390 opts['force_delete_local_changes'])
391 # _narrow() updated the narrowspec and _widen() below needs to
392 # use the updated values as its base (otherwise removed includes
393 # and addedexcludes will be lost in the resulting narrowspec)
394 oldincludes = newincludes
395 oldexcludes = newexcludes
396
397 if widening:
398 newincludes = oldincludes | addedincludes
399 newexcludes = oldexcludes - removedexcludes
400 _widen(ui, repo, remote, commoninc, newincludes, newexcludes)
401
402 return 0
@@ -0,0 +1,35 b''
1 # narrowcopies.py - extensions to mercurial copies module to support narrow
2 # clones
3 #
4 # Copyright 2017 Google, Inc.
5 #
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
8
9 from __future__ import absolute_import
10
11 from mercurial import (
12 copies,
13 extensions,
14 util,
15 )
16
17 def setup(repo):
18 def _computeforwardmissing(orig, a, b, match=None):
19 missing = orig(a, b, match)
20 if util.safehasattr(repo, 'narrowmatch'):
21 narrowmatch = repo.narrowmatch()
22 missing = filter(narrowmatch, missing)
23 return missing
24
25 def _checkcopies(orig, srcctx, dstctx, f, base, tca, remotebase, limit,
26 data):
27 if util.safehasattr(repo, 'narrowmatch'):
28 narrowmatch = repo.narrowmatch()
29 if not narrowmatch(f):
30 return
31 orig(srcctx, dstctx, f, base, tca, remotebase, limit, data)
32
33 extensions.wrapfunction(copies, '_computeforwardmissing',
34 _computeforwardmissing)
35 extensions.wrapfunction(copies, '_checkcopies', _checkcopies)
@@ -0,0 +1,80 b''
1 # narrowdirstate.py - extensions to mercurial dirstate to support narrow clones
2 #
3 # Copyright 2017 Google, Inc.
4 #
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.
7
8 from __future__ import absolute_import
9
10 from mercurial.i18n import _
11 from mercurial import (
12 dirstate,
13 error,
14 extensions,
15 match as matchmod,
16 util as hgutil,
17 )
18
19 from . import narrowspec
20
21 def setup(repo):
22 """Add narrow spec dirstate ignore, block changes outside narrow spec."""
23
24 def walk(orig, self, match, subrepos, unknown, ignored, full=True,
25 narrowonly=True):
26 if narrowonly:
27 narrowmatch = repo.narrowmatch()
28 match = matchmod.intersectmatchers(match, narrowmatch)
29 return orig(self, match, subrepos, unknown, ignored, full)
30
31 extensions.wrapfunction(dirstate.dirstate, 'walk', walk)
32
33 # Prevent adding files that are outside the sparse checkout
34 editfuncs = ['normal', 'add', 'normallookup', 'copy', 'remove', 'merge']
35 for func in editfuncs:
36 def _wrapper(orig, self, *args):
37 dirstate = repo.dirstate
38 narrowmatch = repo.narrowmatch()
39 for f in args:
40 if f is not None and not narrowmatch(f) and f not in dirstate:
41 raise error.Abort(_("cannot track '%s' - it is outside " +
42 "the narrow clone") % f)
43 return orig(self, *args)
44 extensions.wrapfunction(dirstate.dirstate, func, _wrapper)
45
46 def filterrebuild(orig, self, parent, allfiles, changedfiles=None):
47 if changedfiles is None:
48 # Rebuilding entire dirstate, let's filter allfiles to match the
49 # narrowspec.
50 allfiles = [f for f in allfiles if repo.narrowmatch()(f)]
51 orig(self, parent, allfiles, changedfiles)
52
53 extensions.wrapfunction(dirstate.dirstate, 'rebuild', filterrebuild)
54
55 def _narrowbackupname(backupname):
56 assert 'dirstate' in backupname
57 return backupname.replace('dirstate', narrowspec.FILENAME)
58
59 def restorebackup(orig, self, tr, backupname):
60 self._opener.rename(_narrowbackupname(backupname), narrowspec.FILENAME,
61 checkambig=True)
62 orig(self, tr, backupname)
63
64 extensions.wrapfunction(dirstate.dirstate, 'restorebackup', restorebackup)
65
66 def savebackup(orig, self, tr, backupname):
67 orig(self, tr, backupname)
68
69 narrowbackupname = _narrowbackupname(backupname)
70 self._opener.tryunlink(narrowbackupname)
71 hgutil.copyfile(self._opener.join(narrowspec.FILENAME),
72 self._opener.join(narrowbackupname), hardlink=True)
73
74 extensions.wrapfunction(dirstate.dirstate, 'savebackup', savebackup)
75
76 def clearbackup(orig, self, tr, backupname):
77 orig(self, tr, backupname)
78 self._opener.unlink(_narrowbackupname(backupname))
79
80 extensions.wrapfunction(dirstate.dirstate, 'clearbackup', clearbackup)
@@ -0,0 +1,76 b''
1 # narrowmerge.py - extensions to mercurial merge module to support narrow clones
2 #
3 # Copyright 2017 Google, Inc.
4 #
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.
7
8 from __future__ import absolute_import
9
10 from mercurial.i18n import _
11 from mercurial import (
12 copies,
13 error,
14 extensions,
15 merge,
16 util,
17 )
18
19 def setup():
20 def _manifestmerge(orig, repo, wctx, p2, pa, branchmerge, *args, **kwargs):
21 """Filter updates to only lay out files that match the narrow spec."""
22 actions, diverge, renamedelete = orig(
23 repo, wctx, p2, pa, branchmerge, *args, **kwargs)
24
25 if not util.safehasattr(repo, 'narrowmatch'):
26 return actions, diverge, renamedelete
27
28 nooptypes = set(['k']) # TODO: handle with nonconflicttypes
29 nonconflicttypes = set('a am c cm f g r e'.split())
30 narrowmatch = repo.narrowmatch()
31 for f, action in actions.items():
32 if narrowmatch(f):
33 pass
34 elif not branchmerge:
35 del actions[f] # just updating, ignore changes outside clone
36 elif action[0] in nooptypes:
37 del actions[f] # merge does not affect file
38 elif action[0] in nonconflicttypes:
39 raise error.Abort(_('merge affects file \'%s\' outside narrow, '
40 'which is not yet supported') % f,
41 hint=_('merging in the other direction '
42 'may work'))
43 else:
44 raise error.Abort(_('conflict in file \'%s\' is outside '
45 'narrow clone') % f)
46
47 return actions, diverge, renamedelete
48
49 extensions.wrapfunction(merge, 'manifestmerge', _manifestmerge)
50
51 def _checkcollision(orig, repo, wmf, actions):
52 if util.safehasattr(repo, 'narrowmatch'):
53 narrowmatch = repo.narrowmatch()
54 wmf = wmf.matches(narrowmatch)
55 if actions:
56 narrowactions = {}
57 for m, actionsfortype in actions.iteritems():
58 narrowactions[m] = []
59 for (f, args, msg) in actionsfortype:
60 if narrowmatch(f):
61 narrowactions[m].append((f, args, msg))
62 actions = narrowactions
63 return orig(repo, wmf, actions)
64
65 extensions.wrapfunction(merge, '_checkcollision', _checkcollision)
66
67 def _computenonoverlap(orig, repo, *args, **kwargs):
68 u1, u2 = orig(repo, *args, **kwargs)
69 if not util.safehasattr(repo, 'narrowmatch'):
70 return u1, u2
71
72 narrowmatch = repo.narrowmatch()
73 u1 = [f for f in u1 if narrowmatch(f)]
74 u2 = [f for f in u2 if narrowmatch(f)]
75 return u1, u2
76 extensions.wrapfunction(copies, '_computenonoverlap', _computenonoverlap)
@@ -0,0 +1,42 b''
1 # narrowpatch.py - extensions to mercurial patch module to support narrow clones
2 #
3 # Copyright 2017 Google, Inc.
4 #
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.
7
8 from __future__ import absolute_import
9
10 from mercurial import (
11 extensions,
12 patch,
13 util,
14 )
15
16 def setup(repo):
17 def _filepairs(orig, *args):
18 """Only includes files within the narrow spec in the diff."""
19 if util.safehasattr(repo, 'narrowmatch'):
20 narrowmatch = repo.narrowmatch()
21 for x in orig(*args):
22 f1, f2, copyop = x
23 if ((not f1 or narrowmatch(f1)) and
24 (not f2 or narrowmatch(f2))):
25 yield x
26 else:
27 for x in orig(*args):
28 yield x
29
30 def trydiff(orig, repo, revs, ctx1, ctx2, modified, added, removed,
31 copy, getfilectx, *args, **kwargs):
32 if util.safehasattr(repo, 'narrowmatch'):
33 narrowmatch = repo.narrowmatch()
34 modified = filter(narrowmatch, modified)
35 added = filter(narrowmatch, added)
36 removed = filter(narrowmatch, removed)
37 copy = {k: v for k, v in copy.iteritems() if narrowmatch(k)}
38 return orig(repo, revs, ctx1, ctx2, modified, added, removed, copy,
39 getfilectx, *args, **kwargs)
40
41 extensions.wrapfunction(patch, '_filepairs', _filepairs)
42 extensions.wrapfunction(patch, 'trydiff', trydiff)
@@ -0,0 +1,110 b''
1 # narrowrepo.py - repository which supports narrow revlogs, lazy loading
2 #
3 # Copyright 2017 Google, Inc.
4 #
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.
7
8 from __future__ import absolute_import
9
10 from mercurial import (
11 bundlerepo,
12 localrepo,
13 match as matchmod,
14 scmutil,
15 )
16
17 from .. import (
18 share,
19 )
20
21 from . import (
22 narrowrevlog,
23 narrowspec,
24 )
25
26 requirement = 'narrowhg'
27
28 def wrappostshare(orig, sourcerepo, destrepo, **kwargs):
29 orig(sourcerepo, destrepo, **kwargs)
30 if requirement in sourcerepo.requirements:
31 with destrepo.wlock():
32 with destrepo.vfs('shared', 'a') as fp:
33 fp.write(narrowspec.FILENAME + '\n')
34
35 def unsharenarrowspec(orig, ui, repo, repopath):
36 if (requirement in repo.requirements
37 and repo.path == repopath and repo.shared()):
38 srcrepo = share._getsrcrepo(repo)
39 with srcrepo.vfs(narrowspec.FILENAME) as f:
40 spec = f.read()
41 with repo.vfs(narrowspec.FILENAME, 'w') as f:
42 f.write(spec)
43 return orig(ui, repo, repopath)
44
45 def wraprepo(repo, opts_narrow):
46 """Enables narrow clone functionality on a single local repository."""
47
48 cacheprop = localrepo.storecache
49 if isinstance(repo, bundlerepo.bundlerepository):
50 # We have to use a different caching property decorator for
51 # bundlerepo because storecache blows up in strange ways on a
52 # bundlerepo. Fortunately, there's no risk of data changing in
53 # a bundlerepo.
54 cacheprop = lambda name: localrepo.unfilteredpropertycache
55
56 class narrowrepository(repo.__class__):
57
58 def _constructmanifest(self):
59 manifest = super(narrowrepository, self)._constructmanifest()
60 narrowrevlog.makenarrowmanifestrevlog(manifest, repo)
61 return manifest
62
63 @cacheprop('00manifest.i')
64 def manifestlog(self):
65 mfl = super(narrowrepository, self).manifestlog
66 narrowrevlog.makenarrowmanifestlog(mfl, self)
67 return mfl
68
69 def file(self, f):
70 fl = super(narrowrepository, self).file(f)
71 narrowrevlog.makenarrowfilelog(fl, self.narrowmatch())
72 return fl
73
74 @localrepo.repofilecache(narrowspec.FILENAME)
75 def narrowpats(self):
76 return narrowspec.load(self)
77
78 @localrepo.repofilecache(narrowspec.FILENAME)
79 def _narrowmatch(self):
80 include, exclude = self.narrowpats
81 if not opts_narrow and not include and not exclude:
82 return matchmod.always(self.root, '')
83 return narrowspec.match(self.root, include=include, exclude=exclude)
84
85 # TODO(martinvonz): make this property-like instead?
86 def narrowmatch(self):
87 return self._narrowmatch
88
89 def setnarrowpats(self, newincludes, newexcludes):
90 narrowspec.save(self, newincludes, newexcludes)
91 self.invalidate(clearfilecache=True)
92
93 # I'm not sure this is the right place to do this filter.
94 # context._manifestmatches() would probably be better, or perhaps
95 # move it to a later place, in case some of the callers do want to know
96 # which directories changed. This seems to work for now, though.
97 def status(self, *args, **kwargs):
98 s = super(narrowrepository, self).status(*args, **kwargs)
99 narrowmatch = self.narrowmatch()
100 modified = filter(narrowmatch, s.modified)
101 added = filter(narrowmatch, s.added)
102 removed = filter(narrowmatch, s.removed)
103 deleted = filter(narrowmatch, s.deleted)
104 unknown = filter(narrowmatch, s.unknown)
105 ignored = filter(narrowmatch, s.ignored)
106 clean = filter(narrowmatch, s.clean)
107 return scmutil.status(modified, added, removed, deleted, unknown,
108 ignored, clean)
109
110 repo.__class__ = narrowrepository
@@ -0,0 +1,163 b''
1 # narrowrevlog.py - revlog storing irrelevant nodes as "ellipsis" nodes
2 #
3 # Copyright 2017 Google, Inc.
4 #
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.
7
8 from __future__ import absolute_import
9
10 from mercurial import (
11 manifest,
12 revlog,
13 util,
14 )
15
16 ELLIPSIS_NODE_FLAG = 1 << 14
17 revlog.REVIDX_KNOWN_FLAGS |= ELLIPSIS_NODE_FLAG
18 if (util.safehasattr(revlog, 'REVIDX_FLAGS_ORDER') and
19 ELLIPSIS_NODE_FLAG not in revlog.REVIDX_FLAGS_ORDER):
20 revlog.REVIDX_FLAGS_ORDER.append(ELLIPSIS_NODE_FLAG)
21
22 def readtransform(self, text):
23 return text, False
24
25 def writetransform(self, text):
26 return text, False
27
28 def rawtransform(self, text):
29 return False
30
31 if util.safehasattr(revlog, 'addflagprocessor'):
32 revlog.addflagprocessor(ELLIPSIS_NODE_FLAG,
33 (readtransform, writetransform, rawtransform))
34
35 def setup():
36 # We just wanted to add the flag processor, which is done at module
37 # load time.
38 pass
39
40 class excludeddir(manifest.treemanifest):
41 def __init__(self, dir, node):
42 super(excludeddir, self).__init__(dir)
43 self._node = node
44 # Add an empty file, which will be included by iterators and such,
45 # appearing as the directory itself (i.e. something like "dir/")
46 self._files[''] = node
47 self._flags[''] = 't'
48
49 # Manifests outside the narrowspec should never be modified, so avoid
50 # copying. This makes a noticeable difference when there are very many
51 # directories outside the narrowspec. Also, it makes sense for the copy to
52 # be of the same type as the original, which would not happen with the
53 # super type's copy().
54 def copy(self):
55 return self
56
57 class excludeddirmanifestctx(manifest.treemanifestctx):
58 def __init__(self, dir, node):
59 self._dir = dir
60 self._node = node
61
62 def read(self):
63 return excludeddir(self._dir, self._node)
64
65 def write(self, *args):
66 raise AssertionError('Attempt to write manifest from excluded dir %s' %
67 self._dir)
68
69 class excludedmanifestrevlog(manifest.manifestrevlog):
70 def __init__(self, dir):
71 self._dir = dir
72
73 def __len__(self):
74 raise AssertionError('Attempt to get length of excluded dir %s' %
75 self._dir)
76
77 def rev(self, node):
78 raise AssertionError('Attempt to get rev from excluded dir %s' %
79 self._dir)
80
81 def linkrev(self, node):
82 raise AssertionError('Attempt to get linkrev from excluded dir %s' %
83 self._dir)
84
85 def node(self, rev):
86 raise AssertionError('Attempt to get node from excluded dir %s' %
87 self._dir)
88
89 def add(self, *args, **kwargs):
90 # We should never write entries in dirlogs outside the narrow clone.
91 # However, the method still gets called from writesubtree() in
92 # _addtree(), so we need to handle it. We should possibly make that
93 # avoid calling add() with a clean manifest (_dirty is always False
94 # in excludeddir instances).
95 pass
96
97 def makenarrowmanifestrevlog(mfrevlog, repo):
98 if util.safehasattr(mfrevlog, '_narrowed'):
99 return
100
101 class narrowmanifestrevlog(mfrevlog.__class__):
102 # This function is called via debug{revlog,index,data}, but also during
103 # at least some push operations. This will be used to wrap/exclude the
104 # child directories when using treemanifests.
105 def dirlog(self, dir):
106 if dir and not dir.endswith('/'):
107 dir = dir + '/'
108 if not repo.narrowmatch().visitdir(dir[:-1] or '.'):
109 return excludedmanifestrevlog(dir)
110 result = super(narrowmanifestrevlog, self).dirlog(dir)
111 makenarrowmanifestrevlog(result, repo)
112 return result
113
114 mfrevlog.__class__ = narrowmanifestrevlog
115 mfrevlog._narrowed = True
116
117 def makenarrowmanifestlog(mfl, repo):
118 class narrowmanifestlog(mfl.__class__):
119 def get(self, dir, node, verify=True):
120 if not repo.narrowmatch().visitdir(dir[:-1] or '.'):
121 return excludeddirmanifestctx(dir, node)
122 return super(narrowmanifestlog, self).get(dir, node, verify=verify)
123 mfl.__class__ = narrowmanifestlog
124
125 def makenarrowfilelog(fl, narrowmatch):
126 class narrowfilelog(fl.__class__):
127 def renamed(self, node):
128 m = super(narrowfilelog, self).renamed(node)
129 if m and not narrowmatch(m[0]):
130 return None
131 return m
132
133 def size(self, rev):
134 # We take advantage of the fact that remotefilelog
135 # lacks a node() method to just skip the
136 # rename-checking logic when on remotefilelog. This
137 # might be incorrect on other non-revlog-based storage
138 # engines, but for now this seems to be fine.
139 if util.safehasattr(self, 'node'):
140 node = self.node(rev)
141 # Because renamed() is overridden above to
142 # sometimes return None even if there is metadata
143 # in the revlog, size can be incorrect for
144 # copies/renames, so we need to make sure we call
145 # the super class's implementation of renamed()
146 # for the purpose of size calculation.
147 if super(narrowfilelog, self).renamed(node):
148 return len(self.read(node))
149 return super(narrowfilelog, self).size(rev)
150
151 def cmp(self, node, text):
152 different = super(narrowfilelog, self).cmp(node, text)
153 if different:
154 # Similar to size() above, if the file was copied from
155 # a file outside the narrowspec, the super class's
156 # would have returned True because we tricked it into
157 # thinking that the file was not renamed.
158 if super(narrowfilelog, self).renamed(node):
159 t2 = self.read(node)
160 return t2 != text
161 return different
162
163 fl.__class__ = narrowfilelog
@@ -0,0 +1,204 b''
1 # narrowspec.py - methods for working with a narrow view of a repository
2 #
3 # Copyright 2017 Google, Inc.
4 #
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.
7
8 from __future__ import absolute_import
9
10 import errno
11
12 from mercurial.i18n import _
13 from mercurial import (
14 error,
15 match as matchmod,
16 util,
17 )
18
19 from .. import (
20 share,
21 )
22
23 FILENAME = 'narrowspec'
24
25 def _parsestoredpatterns(text):
26 """Parses the narrowspec format that's stored on disk."""
27 patlist = None
28 includepats = []
29 excludepats = []
30 for l in text.splitlines():
31 if l == '[includes]':
32 if patlist is None:
33 patlist = includepats
34 else:
35 raise error.Abort(_('narrowspec includes section must appear '
36 'at most once, before excludes'))
37 elif l == '[excludes]':
38 if patlist is not excludepats:
39 patlist = excludepats
40 else:
41 raise error.Abort(_('narrowspec excludes section must appear '
42 'at most once'))
43 else:
44 patlist.append(l)
45
46 return set(includepats), set(excludepats)
47
48 def parseserverpatterns(text):
49 """Parses the narrowspec format that's returned by the server."""
50 includepats = set()
51 excludepats = set()
52
53 # We get one entry per line, in the format "<key> <value>".
54 # It's OK for value to contain other spaces.
55 for kp in (l.split(' ', 1) for l in text.splitlines()):
56 if len(kp) != 2:
57 raise error.Abort(_('Invalid narrowspec pattern line: "%s"') % kp)
58 key = kp[0]
59 pat = kp[1]
60 if key == 'include':
61 includepats.add(pat)
62 elif key == 'exclude':
63 excludepats.add(pat)
64 else:
65 raise error.Abort(_('Invalid key "%s" in server response') % key)
66
67 return includepats, excludepats
68
69 def normalizesplitpattern(kind, pat):
70 """Returns the normalized version of a pattern and kind.
71
72 Returns a tuple with the normalized kind and normalized pattern.
73 """
74 pat = pat.rstrip('/')
75 _validatepattern(pat)
76 return kind, pat
77
78 def _numlines(s):
79 """Returns the number of lines in s, including ending empty lines."""
80 # We use splitlines because it is Unicode-friendly and thus Python 3
81 # compatible. However, it does not count empty lines at the end, so trick
82 # it by adding a character at the end.
83 return len((s + 'x').splitlines())
84
85 def _validatepattern(pat):
86 """Validates the pattern and aborts if it is invalid."""
87
88 # We use newlines as separators in the narrowspec file, so don't allow them
89 # in patterns.
90 if _numlines(pat) > 1:
91 raise error.Abort('newlines are not allowed in narrowspec paths')
92
93 components = pat.split('/')
94 if '.' in components or '..' in components:
95 raise error.Abort(_('"." and ".." are not allowed in narrowspec paths'))
96
97 def normalizepattern(pattern, defaultkind='path'):
98 """Returns the normalized version of a text-format pattern.
99
100 If the pattern has no kind, the default will be added.
101 """
102 kind, pat = matchmod._patsplit(pattern, defaultkind)
103 return '%s:%s' % normalizesplitpattern(kind, pat)
104
105 def parsepatterns(pats):
106 """Parses a list of patterns into a typed pattern set."""
107 return set(normalizepattern(p) for p in pats)
108
109 def format(includes, excludes):
110 output = '[includes]\n'
111 for i in sorted(includes - excludes):
112 output += i + '\n'
113 output += '[excludes]\n'
114 for e in sorted(excludes):
115 output += e + '\n'
116 return output
117
118 def match(root, include=None, exclude=None):
119 if not include:
120 # Passing empty include and empty exclude to matchmod.match()
121 # gives a matcher that matches everything, so explicitly use
122 # the nevermatcher.
123 return matchmod.never(root, '')
124 return matchmod.match(root, '', [], include=include or [],
125 exclude=exclude or [])
126
127 def needsexpansion(includes):
128 return [i for i in includes if i.startswith('include:')]
129
130 def load(repo):
131 if repo.shared():
132 repo = share._getsrcrepo(repo)
133 try:
134 spec = repo.vfs.read(FILENAME)
135 except IOError as e:
136 # Treat "narrowspec does not exist" the same as "narrowspec file exists
137 # and is empty".
138 if e.errno == errno.ENOENT:
139 # Without this the next call to load will use the cached
140 # non-existence of the file, which can cause some odd issues.
141 repo.invalidate(clearfilecache=True)
142 return set(), set()
143 raise
144 return _parsestoredpatterns(spec)
145
146 def save(repo, includepats, excludepats):
147 spec = format(includepats, excludepats)
148 if repo.shared():
149 repo = share._getsrcrepo(repo)
150 repo.vfs.write(FILENAME, spec)
151
152 def restrictpatterns(req_includes, req_excludes, repo_includes, repo_excludes,
153 invalid_includes=None):
154 r""" Restricts the patterns according to repo settings,
155 results in a logical AND operation
156
157 :param req_includes: requested includes
158 :param req_excludes: requested excludes
159 :param repo_includes: repo includes
160 :param repo_excludes: repo excludes
161 :param invalid_includes: an array to collect invalid includes
162 :return: include and exclude patterns
163
164 >>> restrictpatterns({'f1','f2'}, {}, ['f1'], [])
165 (set(['f1']), {})
166 >>> restrictpatterns({'f1'}, {}, ['f1','f2'], [])
167 (set(['f1']), {})
168 >>> restrictpatterns({'f1/fc1', 'f3/fc3'}, {}, ['f1','f2'], [])
169 (set(['f1/fc1']), {})
170 >>> restrictpatterns({'f1_fc1'}, {}, ['f1','f2'], [])
171 ([], set(['path:.']))
172 >>> restrictpatterns({'f1/../f2/fc2'}, {}, ['f1','f2'], [])
173 (set(['f2/fc2']), {})
174 >>> restrictpatterns({'f1/../f3/fc3'}, {}, ['f1','f2'], [])
175 ([], set(['path:.']))
176 >>> restrictpatterns({'f1/$non_exitent_var'}, {}, ['f1','f2'], [])
177 (set(['f1/$non_exitent_var']), {})
178 """
179 res_excludes = req_excludes.copy()
180 res_excludes.update(repo_excludes)
181 if not req_includes:
182 res_includes = set(repo_includes)
183 elif 'path:.' not in repo_includes:
184 res_includes = []
185 for req_include in req_includes:
186 req_include = util.expandpath(util.normpath(req_include))
187 if req_include in repo_includes:
188 res_includes.append(req_include)
189 continue
190 valid = False
191 for repo_include in repo_includes:
192 if req_include.startswith(repo_include + '/'):
193 valid = True
194 res_includes.append(req_include)
195 break
196 if not valid and invalid_includes is not None:
197 invalid_includes.append(req_include)
198 if len(res_includes) == 0:
199 res_excludes = {'path:.'}
200 else:
201 res_includes = set(res_includes)
202 else:
203 res_includes = set(req_includes)
204 return res_includes, res_excludes
@@ -0,0 +1,50 b''
1 # narrowtemplates.py - added template keywords for narrow clones
2 #
3 # Copyright 2017 Google, Inc.
4 #
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.
7
8 from __future__ import absolute_import
9
10 from mercurial import (
11 revset,
12 templatekw,
13 util,
14 )
15
16 from . import narrowrevlog
17
18 def _isellipsis(repo, rev):
19 if repo.changelog.flags(rev) & narrowrevlog.ELLIPSIS_NODE_FLAG:
20 return True
21 return False
22
23 def ellipsis(repo, ctx, templ, **args):
24 """:ellipsis: String. 'ellipsis' if the change is an ellipsis node,
25 else ''."""
26 if _isellipsis(repo, ctx.rev()):
27 return 'ellipsis'
28 return ''
29
30 def outsidenarrow(repo, ctx, templ, **args):
31 """:outsidenarrow: String. 'outsidenarrow' if the change affects no
32 tracked files, else ''."""
33 if util.safehasattr(repo, 'narrowmatch'):
34 m = repo.narrowmatch()
35 if not any(m(f) for f in ctx.files()):
36 return 'outsidenarrow'
37 return ''
38
39 def ellipsisrevset(repo, subset, x):
40 """``ellipsis()``
41 Changesets that are ellipsis nodes.
42 """
43 return subset.filter(lambda r: _isellipsis(repo, r))
44
45 def setup():
46 templatekw.keywords['ellipsis'] = ellipsis
47 templatekw.keywords['outsidenarrow'] = outsidenarrow
48
49 revset.symbols['ellipsis'] = ellipsisrevset
50 revset.safesymbols.add('ellipsis')
@@ -0,0 +1,51 b''
1 # narrowwirepeer.py - passes narrow spec with unbundle command
2 #
3 # Copyright 2017 Google, Inc.
4 #
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.
7
8 from __future__ import absolute_import
9
10 from mercurial.i18n import _
11 from mercurial import (
12 error,
13 extensions,
14 hg,
15 node,
16 )
17
18 from . import narrowspec
19
20 def uisetup():
21 def peersetup(ui, peer):
22 # We must set up the expansion before reposetup below, since it's used
23 # at clone time before we have a repo.
24 class expandingpeer(peer.__class__):
25 def expandnarrow(self, narrow_include, narrow_exclude, nodes):
26 ui.status(_("expanding narrowspec\n"))
27 if not self.capable('expandnarrow'):
28 raise error.Abort(
29 'peer does not support expanding narrowspecs')
30
31 hex_nodes = (node.hex(n) for n in nodes)
32 new_narrowspec = self._call(
33 'expandnarrow',
34 includepats=','.join(narrow_include),
35 excludepats=','.join(narrow_exclude),
36 nodes=','.join(hex_nodes))
37
38 return narrowspec.parseserverpatterns(new_narrowspec)
39 peer.__class__ = expandingpeer
40 hg.wirepeersetupfuncs.append(peersetup)
41
42 def reposetup(repo):
43 def wirereposetup(ui, peer):
44 def wrapped(orig, cmd, *args, **kwargs):
45 if cmd == 'unbundle':
46 include, exclude = repo.narrowpats
47 kwargs["includepats"] = ','.join(include)
48 kwargs["excludepats"] = ','.join(exclude)
49 return orig(cmd, *args, **kwargs)
50 extensions.wrapfunction(peer, '_calltwowaystream', wrapped)
51 hg.wirepeersetupfuncs.append(wirereposetup)
@@ -0,0 +1,9 b''
1 cat >> $HGRCPATH <<EOF
2 [extensions]
3 narrow=
4 [ui]
5 ssh=python "$TESTDIR/dummyssh"
6 [experimental]
7 bundle2-exp = True
8 changegroup3 = True
9 EOF
@@ -0,0 +1,42 b''
1 Make a narrow clone then archive it
2 $ . "$TESTDIR/narrow-library.sh"
3
4 $ hg init master
5 $ cd master
6
7 $ for x in `$TESTDIR/seq.py 3`; do
8 > echo $x > "f$x"
9 > hg add "f$x"
10 > hg commit -m "Add $x"
11 > done
12 $ cat >> .hg/hgrc << EOF
13 > [narrowhgacl]
14 > default.includes=f1 f2
15 > EOF
16 $ hg serve -a localhost -p $HGPORT1 -d --pid-file=hg.pid
17 $ cat hg.pid >> "$DAEMON_PIDS"
18
19 $ cd ..
20 $ hg clone http://localhost:$HGPORT1 narrowclone1
21 requesting all changes
22 adding changesets
23 adding manifests
24 adding file changes
25 added 3 changesets with 2 changes to 2 files
26 new changesets * (glob)
27 updating to branch default
28 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
29
30 The clone directory should only contain f1 and f2
31 $ ls -1 narrowclone1 | sort
32 f1
33 f2
34
35 Requirements should contain narrowhg
36 $ cat narrowclone1/.hg/requires | grep narrowhg
37 narrowhg
38
39 NarrowHG should track f1 and f2
40 $ hg -R narrowclone1 tracked
41 I path:f1
42 I path:f2
@@ -0,0 +1,32 b''
1 Make a narrow clone then archive it
2 $ . "$TESTDIR/narrow-library.sh"
3
4 $ hg init master
5 $ cd master
6
7 $ for x in `$TESTDIR/seq.py 3`; do
8 > echo $x > "f$x"
9 > hg add "f$x"
10 > hg commit -m "Add $x"
11 > done
12
13 $ hg serve -a localhost -p $HGPORT1 -d --pid-file=hg.pid
14 $ cat hg.pid >> "$DAEMON_PIDS"
15
16 $ cd ..
17 $ hg clone --narrow --include f1 --include f2 http://localhost:$HGPORT1/ narrowclone1
18 requesting all changes
19 adding changesets
20 adding manifests
21 adding file changes
22 added 3 changesets with 2 changes to 2 files
23 new changesets * (glob)
24 updating to branch default
25 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
26
27 The tar should only contain f1 and f2
28 $ cd narrowclone1
29 $ hg archive -t tgz repo.tgz
30 $ tar tfz repo.tgz
31 repo/f1
32 repo/f2
@@ -0,0 +1,130 b''
1 $ . "$TESTDIR/narrow-library.sh"
2
3 $ hg init master
4 $ cd master
5 $ mkdir dir
6 $ mkdir dir/src
7 $ cd dir/src
8 $ for x in `$TESTDIR/seq.py 20`; do echo $x > "f$x"; hg add "f$x"; hg commit -m "Commit src $x"; done
9 $ cd ..
10 $ mkdir tests
11 $ cd tests
12 $ for x in `$TESTDIR/seq.py 20`; do echo $x > "t$x"; hg add "t$x"; hg commit -m "Commit test $x"; done
13 $ cd ../../..
14
15 narrow clone a file, f10
16
17 $ hg clone --narrow ssh://user@dummy/master narrow --noupdate --include "dir/src/f10"
18 requesting all changes
19 adding changesets
20 adding manifests
21 adding file changes
22 added 40 changesets with 1 changes to 1 files
23 new changesets *:* (glob)
24 $ cd narrow
25 $ cat .hg/requires | grep -v generaldelta
26 dotencode
27 fncache
28 narrowhg
29 revlogv1
30 store
31
32 $ cat .hg/narrowspec
33 [includes]
34 path:dir/src/f10
35 [excludes]
36 $ hg update
37 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
38 $ find * | sort
39 dir
40 dir/src
41 dir/src/f10
42 $ cat dir/src/f10
43 10
44
45 $ cd ..
46
47 narrow clone a directory, tests/, except tests/t19
48
49 $ hg clone --narrow ssh://user@dummy/master narrowdir --noupdate --include "dir/tests/" --exclude "dir/tests/t19"
50 requesting all changes
51 adding changesets
52 adding manifests
53 adding file changes
54 added 40 changesets with 19 changes to 19 files
55 new changesets *:* (glob)
56 $ cd narrowdir
57 $ cat .hg/narrowspec
58 [includes]
59 path:dir/tests
60 [excludes]
61 path:dir/tests/t19
62 $ hg update
63 19 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 $ find * | sort
65 dir
66 dir/tests
67 dir/tests/t1
68 dir/tests/t10
69 dir/tests/t11
70 dir/tests/t12
71 dir/tests/t13
72 dir/tests/t14
73 dir/tests/t15
74 dir/tests/t16
75 dir/tests/t17
76 dir/tests/t18
77 dir/tests/t2
78 dir/tests/t20
79 dir/tests/t3
80 dir/tests/t4
81 dir/tests/t5
82 dir/tests/t6
83 dir/tests/t7
84 dir/tests/t8
85 dir/tests/t9
86
87 $ cd ..
88
89 narrow clone everything but a directory (tests/)
90
91 $ hg clone --narrow ssh://user@dummy/master narrowroot --noupdate --exclude "dir/tests"
92 requesting all changes
93 adding changesets
94 adding manifests
95 adding file changes
96 added 40 changesets with 20 changes to 20 files
97 new changesets *:* (glob)
98 $ cd narrowroot
99 $ cat .hg/narrowspec
100 [includes]
101 path:.
102 [excludes]
103 path:dir/tests
104 $ hg update
105 20 files updated, 0 files merged, 0 files removed, 0 files unresolved
106 $ find * | sort
107 dir
108 dir/src
109 dir/src/f1
110 dir/src/f10
111 dir/src/f11
112 dir/src/f12
113 dir/src/f13
114 dir/src/f14
115 dir/src/f15
116 dir/src/f16
117 dir/src/f17
118 dir/src/f18
119 dir/src/f19
120 dir/src/f2
121 dir/src/f20
122 dir/src/f3
123 dir/src/f4
124 dir/src/f5
125 dir/src/f6
126 dir/src/f7
127 dir/src/f8
128 dir/src/f9
129
130 $ cd ..
@@ -0,0 +1,53 b''
1 Test attempting a narrow clone against a server that doesn't support narrowhg.
2
3 $ . "$TESTDIR/narrow-library.sh"
4
5 $ hg init master
6 $ cd master
7
8 $ for x in `$TESTDIR/seq.py 10`; do
9 > echo $x > "f$x"
10 > hg add "f$x"
11 > hg commit -m "Add $x"
12 > done
13
14 $ hg serve -a localhost -p $HGPORT1 --config extensions.narrow=! -d \
15 > --pid-file=hg.pid
16 $ cat hg.pid >> "$DAEMON_PIDS"
17 $ hg serve -a localhost -p $HGPORT2 -d --pid-file=hg.pid
18 $ cat hg.pid >> "$DAEMON_PIDS"
19
20 Verify that narrow is advertised in the bundle2 capabilities:
21 $ echo capabilities | hg -R . serve --stdio | \
22 > python -c "import sys, urllib; print urllib.unquote_plus(list(sys.stdin)[1])" | grep narrow
23 narrow=v0
24
25 $ cd ..
26
27 $ hg clone --narrow --include f1 http://localhost:$HGPORT1/ narrowclone
28 requesting all changes
29 abort: server doesn't support narrow clones
30 [255]
31
32 Make a narrow clone (via HGPORT2), then try to narrow and widen
33 into it (from HGPORT1) to prove that narrowing is fine and widening fails
34 gracefully:
35 $ hg clone -r 0 --narrow --include f1 http://localhost:$HGPORT2/ narrowclone
36 adding changesets
37 adding manifests
38 adding file changes
39 added 1 changesets with 1 changes to 1 files
40 new changesets * (glob)
41 updating to branch default
42 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
43 $ cd narrowclone
44 $ hg tracked --addexclude f2 http://localhost:$HGPORT1/
45 comparing with http://localhost:$HGPORT1/
46 searching for changes
47 looking for local changes to affected paths
48 $ hg tracked --addinclude f1 http://localhost:$HGPORT1/
49 comparing with http://localhost:$HGPORT1/
50 searching for changes
51 no changes found
52 abort: server doesn't support narrow clones
53 [255]
@@ -0,0 +1,148 b''
1 Testing narrow clones when changesets modifying a matching file exist on
2 multiple branches
3
4 $ . "$TESTDIR/narrow-library.sh"
5
6 $ hg init master
7 $ cd master
8 $ cat >> .hg/hgrc <<EOF
9 > [narrow]
10 > serveellipses=True
11 > EOF
12
13 $ hg branch default
14 marked working directory as branch default
15 (branches are permanent and global, did you want a bookmark?)
16 $ for x in `$TESTDIR/seq.py 10`; do
17 > echo $x > "f$x"
18 > hg add "f$x"
19 > hg commit -m "Add $x"
20 > done
21
22 $ hg branch release-v1
23 marked working directory as branch release-v1
24 (branches are permanent and global, did you want a bookmark?)
25 $ hg commit -m "Start release for v1"
26
27 $ hg update default
28 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
29 $ for x in `$TESTDIR/seq.py 10`; do
30 > echo "$x v2" > "f$x"
31 > hg commit -m "Update $x to v2"
32 > done
33
34 $ hg update release-v1
35 10 files updated, 0 files merged, 0 files removed, 0 files unresolved
36 $ hg branch release-v1
37 marked working directory as branch release-v1
38 $ for x in `$TESTDIR/seq.py 1 5`; do
39 > echo "$x v1 hotfix" > "f$x"
40 > hg commit -m "Hotfix $x in v1"
41 > done
42
43 $ hg update default
44 10 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 $ hg branch release-v2
46 marked working directory as branch release-v2
47 $ hg commit -m "Start release for v2"
48
49 $ hg update default
50 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
51 $ hg branch default
52 marked working directory as branch default
53 $ for x in `$TESTDIR/seq.py 10`; do
54 > echo "$x v3" > "f$x"
55 > hg commit -m "Update $x to v3"
56 > done
57
58 $ hg update release-v2
59 10 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 $ hg branch release-v2
61 marked working directory as branch release-v2
62 $ for x in `$TESTDIR/seq.py 4 9`; do
63 > echo "$x v2 hotfix" > "f$x"
64 > hg commit -m "Hotfix $x in v2"
65 > done
66
67 $ hg heads -T '{rev} <- {p1rev} ({branch}): {desc}\n'
68 42 <- 41 (release-v2): Hotfix 9 in v2
69 36 <- 35 (default): Update 10 to v3
70 25 <- 24 (release-v1): Hotfix 5 in v1
71
72 $ cd ..
73
74 We now have 3 branches: default, which has v3 of all files, release-v1 which
75 has v1 of all files, and release-v2 with v2 of all files.
76
77 Narrow clone which should get all branches
78
79 $ hg clone --narrow ssh://user@dummy/master narrow --include "f5"
80 requesting all changes
81 adding changesets
82 adding manifests
83 adding file changes
84 added 12 changesets with 5 changes to 1 files (+2 heads)
85 new changesets *:* (glob)
86 updating to branch default
87 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
88 $ cd narrow
89 $ hg log -G -T "{if(ellipsis, '...')}{node|short} ({branch}): {desc}\n"
90 o ...031f516143fe (release-v2): Hotfix 9 in v2
91 |
92 o 9cd7f7bb9ca1 (release-v2): Hotfix 5 in v2
93 |
94 o ...37bbc88f3ef0 (release-v2): Hotfix 4 in v2
95 |
96 | @ ...dae2f368ca07 (default): Update 10 to v3
97 | |
98 | o 9c224e89cb31 (default): Update 5 to v3
99 | |
100 | o ...04fb59c7c9dc (default): Update 4 to v3
101 |/
102 | o b2253e82401f (release-v1): Hotfix 5 in v1
103 | |
104 | o ...960ac37d74fd (release-v1): Hotfix 4 in v1
105 | |
106 o | 986298e3f347 (default): Update 5 to v2
107 | |
108 o | ...75d539c667ec (default): Update 4 to v2
109 |/
110 o 04c71bd5707f (default): Add 5
111 |
112 o ...881b3891d041 (default): Add 4
113
114
115 Narrow clone the first file, hitting edge condition where unaligned
116 changeset and manifest revnums cross branches.
117
118 $ hg clone --narrow ssh://user@dummy/master narrow --include "f1"
119 requesting all changes
120 adding changesets
121 adding manifests
122 adding file changes
123 added 10 changesets with 4 changes to 1 files (+2 heads)
124 new changesets *:* (glob)
125 updating to branch default
126 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 $ cd narrow
128 $ hg log -G -T "{if(ellipsis, '...')}{node|short} ({branch}): {desc}\n"
129 o ...031f516143fe (release-v2): Hotfix 9 in v2
130 |
131 | @ ...dae2f368ca07 (default): Update 10 to v3
132 | |
133 | o 1f5d184b8e96 (default): Update 1 to v3
134 |/
135 | o ...b2253e82401f (release-v1): Hotfix 5 in v1
136 | |
137 | o 133502f6b7e5 (release-v1): Hotfix 1 in v1
138 | |
139 o | ...79165c83d644 (default): Update 10 to v2
140 | |
141 o | c7b7a5f2f088 (default): Update 1 to v2
142 | |
143 | o ...f0531a3db7a9 (release-v1): Start release for v1
144 |/
145 o ...6a3f0f0abef3 (default): Add 10
146 |
147 o e012ac15eaaa (default): Add 1
148
@@ -0,0 +1,225 b''
1 $ . "$TESTDIR/narrow-library.sh"
2
3 $ hg init master
4 $ cd master
5 $ cat >> .hg/hgrc <<EOF
6 > [narrow]
7 > serveellipses=True
8 > EOF
9 $ mkdir dir
10 $ mkdir dir/src
11 $ cd dir/src
12 $ for x in `$TESTDIR/seq.py 20`; do echo $x > "f$x"; hg add "f$x"; hg commit -m "Commit src $x"; done
13 $ cd ..
14 $ mkdir tests
15 $ cd tests
16 $ for x in `$TESTDIR/seq.py 20`; do echo $x > "t$x"; hg add "t$x"; hg commit -m "Commit test $x"; done
17 $ cd ../../..
18
19 narrow clone a file, f10
20
21 $ hg clone --narrow ssh://user@dummy/master narrow --noupdate --include "dir/src/f10"
22 requesting all changes
23 adding changesets
24 adding manifests
25 adding file changes
26 added 3 changesets with 1 changes to 1 files
27 new changesets *:* (glob)
28 $ cd narrow
29 $ cat .hg/requires | grep -v generaldelta
30 dotencode
31 fncache
32 narrowhg
33 revlogv1
34 store
35
36 $ cat .hg/narrowspec
37 [includes]
38 path:dir/src/f10
39 [excludes]
40 $ hg tracked
41 I path:dir/src/f10
42 $ hg update
43 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 $ find * | sort
45 dir
46 dir/src
47 dir/src/f10
48 $ cat dir/src/f10
49 10
50
51 $ cd ..
52
53 narrow clone with a newline should fail
54
55 $ hg clone --narrow ssh://user@dummy/master narrow_fail --noupdate --include 'dir/src/f10
56 > '
57 requesting all changes
58 abort: newlines are not allowed in narrowspec paths
59 [255]
60
61 narrow clone a directory, tests/, except tests/t19
62
63 $ hg clone --narrow ssh://user@dummy/master narrowdir --noupdate --include "dir/tests/" --exclude "dir/tests/t19"
64 requesting all changes
65 adding changesets
66 adding manifests
67 adding file changes
68 added 21 changesets with 19 changes to 19 files
69 new changesets *:* (glob)
70 $ cd narrowdir
71 $ cat .hg/narrowspec
72 [includes]
73 path:dir/tests
74 [excludes]
75 path:dir/tests/t19
76 $ hg tracked
77 I path:dir/tests
78 X path:dir/tests/t19
79 $ hg update
80 19 files updated, 0 files merged, 0 files removed, 0 files unresolved
81 $ find * | sort
82 dir
83 dir/tests
84 dir/tests/t1
85 dir/tests/t10
86 dir/tests/t11
87 dir/tests/t12
88 dir/tests/t13
89 dir/tests/t14
90 dir/tests/t15
91 dir/tests/t16
92 dir/tests/t17
93 dir/tests/t18
94 dir/tests/t2
95 dir/tests/t20
96 dir/tests/t3
97 dir/tests/t4
98 dir/tests/t5
99 dir/tests/t6
100 dir/tests/t7
101 dir/tests/t8
102 dir/tests/t9
103
104 $ cd ..
105
106 narrow clone everything but a directory (tests/)
107
108 $ hg clone --narrow ssh://user@dummy/master narrowroot --noupdate --exclude "dir/tests"
109 requesting all changes
110 adding changesets
111 adding manifests
112 adding file changes
113 added 21 changesets with 20 changes to 20 files
114 new changesets *:* (glob)
115 $ cd narrowroot
116 $ cat .hg/narrowspec
117 [includes]
118 path:.
119 [excludes]
120 path:dir/tests
121 $ hg tracked
122 I path:.
123 X path:dir/tests
124 $ hg update
125 20 files updated, 0 files merged, 0 files removed, 0 files unresolved
126 $ find * | sort
127 dir
128 dir/src
129 dir/src/f1
130 dir/src/f10
131 dir/src/f11
132 dir/src/f12
133 dir/src/f13
134 dir/src/f14
135 dir/src/f15
136 dir/src/f16
137 dir/src/f17
138 dir/src/f18
139 dir/src/f19
140 dir/src/f2
141 dir/src/f20
142 dir/src/f3
143 dir/src/f4
144 dir/src/f5
145 dir/src/f6
146 dir/src/f7
147 dir/src/f8
148 dir/src/f9
149
150 $ cd ..
151
152 narrow clone no paths at all
153
154 $ hg clone --narrow ssh://user@dummy/master narrowempty --noupdate
155 requesting all changes
156 adding changesets
157 adding manifests
158 adding file changes
159 added 1 changesets with 0 changes to 0 files
160 new changesets * (glob)
161 $ cd narrowempty
162 $ hg tracked
163 $ hg update
164 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
165 $ ls
166
167 $ cd ..
168
169 simple clone
170 $ hg clone ssh://user@dummy/master simpleclone
171 requesting all changes
172 adding changesets
173 adding manifests
174 adding file changes
175 added 40 changesets with 40 changes to 40 files
176 new changesets * (glob)
177 updating to branch default
178 40 files updated, 0 files merged, 0 files removed, 0 files unresolved
179 $ cd simpleclone
180 $ find * | sort
181 dir
182 dir/src
183 dir/src/f1
184 dir/src/f10
185 dir/src/f11
186 dir/src/f12
187 dir/src/f13
188 dir/src/f14
189 dir/src/f15
190 dir/src/f16
191 dir/src/f17
192 dir/src/f18
193 dir/src/f19
194 dir/src/f2
195 dir/src/f20
196 dir/src/f3
197 dir/src/f4
198 dir/src/f5
199 dir/src/f6
200 dir/src/f7
201 dir/src/f8
202 dir/src/f9
203 dir/tests
204 dir/tests/t1
205 dir/tests/t10
206 dir/tests/t11
207 dir/tests/t12
208 dir/tests/t13
209 dir/tests/t14
210 dir/tests/t15
211 dir/tests/t16
212 dir/tests/t17
213 dir/tests/t18
214 dir/tests/t19
215 dir/tests/t2
216 dir/tests/t20
217 dir/tests/t3
218 dir/tests/t4
219 dir/tests/t5
220 dir/tests/t6
221 dir/tests/t7
222 dir/tests/t8
223 dir/tests/t9
224
225 $ cd ..
@@ -0,0 +1,21 b''
1 $ cd $TESTDIR && python $RUNTESTDIR/run-tests.py \
2 > --extra-config-opt experimental.treemanifest=1 test-narrow-commit.t 2>&1 | \
3 > grep -v 'unexpected mercurial lib' | egrep -v '\(expected'
4
5 --- */tests/test-narrow-commit.t (glob)
6 +++ */tests/test-narrow-commit.t.err (glob)
7 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
8 created new head
9 $ hg files -r .
10 inside/f1
11 - outside/f1
12 + outside/
13 Some filesystems (notably FAT/exFAT only store timestamps with 2
14 seconds of precision, so by sleeping for 3 seconds, we can ensure that
15 the timestamps of files stored by dirstate will appear older than the
16
17 ERROR: test-narrow-commit.t output changed
18 !
19 Failed test-narrow-commit.t: output changed
20 # Ran 1 tests, 0 skipped, 1 failed.
21 python hash seed: * (glob)
@@ -0,0 +1,79 b''
1 $ . "$TESTDIR/narrow-library.sh"
2
3 create full repo
4
5 $ hg init master
6 $ cd master
7
8 $ mkdir inside
9 $ echo inside > inside/f1
10 $ mkdir outside
11 $ echo outside > outside/f1
12 $ hg ci -Aqm 'initial'
13
14 $ echo modified > inside/f1
15 $ hg ci -qm 'modify inside'
16
17 $ echo modified > outside/f1
18 $ hg ci -qm 'modify outside'
19
20 $ cd ..
21
22 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
23 requesting all changes
24 adding changesets
25 adding manifests
26 adding file changes
27 added 3 changesets with 2 changes to 1 files
28 new changesets *:* (glob)
29 updating to branch default
30 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
31 $ cd narrow
32
33 $ hg update -q 0
34
35 Can not modify dirstate outside
36
37 $ mkdir outside
38 $ touch outside/f1
39 $ hg debugwalk -I 'relglob:f1'
40 matcher: <includematcher includes='(?:(?:|.*/)f1(?:/|$))'>
41 f inside/f1 inside/f1
42 $ hg add outside/f1
43 abort: cannot track 'outside/f1' - it is outside the narrow clone
44 [255]
45 $ touch outside/f3
46 $ hg add outside/f3
47 abort: cannot track 'outside/f3' - it is outside the narrow clone
48 [255]
49 $ rm -r outside
50
51 Can modify dirstate inside
52
53 $ echo modified > inside/f1
54 $ touch inside/f3
55 $ hg add inside/f3
56 $ hg status
57 M inside/f1
58 A inside/f3
59 $ hg revert -qC .
60 $ rm inside/f3
61
62 Can commit changes inside. Leaves outside unchanged.
63
64 $ hg update -q 'desc("initial")'
65 $ echo modified2 > inside/f1
66 $ hg commit -m 'modify inside/f1'
67 created new head
68 $ hg files -r .
69 inside/f1
70 outside/f1
71 Some filesystems (notably FAT/exFAT only store timestamps with 2
72 seconds of precision, so by sleeping for 3 seconds, we can ensure that
73 the timestamps of files stored by dirstate will appear older than the
74 dirstate file, and therefore we'll be able to get stable output from
75 debugdirstate. If we don't do this, the test can be slightly flaky.
76 $ sleep 3
77 $ hg status
78 $ hg debugdirstate --nodates
79 n 644 10 set inside/f1
@@ -0,0 +1,57 b''
1
2 $ . "$TESTDIR/narrow-library.sh"
3
4 create full repo
5
6 $ hg init master
7 $ cd master
8
9 $ mkdir inside
10 $ echo inside > inside/f1
11 $ mkdir outside
12 $ echo outside > outside/f2
13 $ hg ci -Aqm 'initial'
14
15 $ hg mv outside/f2 inside/f2
16 $ hg ci -qm 'move f2 from outside'
17
18 $ echo modified > inside/f2
19 $ hg ci -qm 'modify inside/f2'
20
21 $ cd ..
22
23 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
24 requesting all changes
25 adding changesets
26 adding manifests
27 adding file changes
28 added 3 changesets with 3 changes to 2 files
29 new changesets *:* (glob)
30 updating to branch default
31 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
32 $ cd narrow
33
34 $ hg co 'desc("move f2")'
35 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
36 $ hg status
37 $ hg diff
38 $ hg diff --change . --git
39 diff --git a/inside/f2 b/inside/f2
40 new file mode 100644
41 --- /dev/null
42 +++ b/inside/f2
43 @@ -0,0 +1,1 @@
44 +outside
45
46 $ hg log --follow inside/f2 -r tip
47 changeset: 2:bcfb756e0ca9
48 tag: tip
49 user: test
50 date: Thu Jan 01 00:00:00 1970 +0000
51 summary: modify inside/f2
52
53 changeset: 1:5a016133b2bb
54 user: test
55 date: Thu Jan 01 00:00:00 1970 +0000
56 summary: move f2 from outside
57
@@ -0,0 +1,43 b''
1 $ . "$TESTDIR/narrow-library.sh"
2 $ hg init repo
3 $ cd repo
4 $ cat << EOF > .hg/narrowspec
5 > [includes]
6 > path:foo
7 > [excludes]
8 > EOF
9 $ echo treemanifest >> .hg/requires
10 $ echo narrowhg >> .hg/requires
11 $ mkdir -p foo/bar
12 $ echo b > foo/f
13 $ echo c > foo/bar/f
14 $ hg commit -Am hi
15 adding foo/bar/f
16 adding foo/f
17 $ hg debugindex -m
18 rev offset length delta linkrev nodeid p1 p2
19 0 0 47 -1 0 14a5d056d75a 000000000000 000000000000
20 $ hg debugindex --dir foo
21 rev offset length delta linkrev nodeid p1 p2
22 0 0 77 -1 0 e635c7857aef 000000000000 000000000000
23 $ hg debugindex --dir foo/
24 rev offset length delta linkrev nodeid p1 p2
25 0 0 77 -1 0 e635c7857aef 000000000000 000000000000
26 $ hg debugindex --dir foo/bar
27 rev offset length delta linkrev nodeid p1 p2
28 0 0 44 -1 0 e091d4224761 000000000000 000000000000
29 $ hg debugindex --dir foo/bar/
30 rev offset length delta linkrev nodeid p1 p2
31 0 0 44 -1 0 e091d4224761 000000000000 000000000000
32 $ hg debugdata -m 0
33 foo\x00e635c7857aef92ac761ce5741a99da159abbbb24t (esc)
34 $ hg debugdata --dir foo 0
35 bar\x00e091d42247613adff5d41b67f15fe7189ee97b39t (esc)
36 f\x001e88685f5ddec574a34c70af492f95b6debc8741 (esc)
37 $ hg debugdata --dir foo/ 0
38 bar\x00e091d42247613adff5d41b67f15fe7189ee97b39t (esc)
39 f\x001e88685f5ddec574a34c70af492f95b6debc8741 (esc)
40 $ hg debugdata --dir foo/bar 0
41 f\x00149da44f2a4e14f488b7bd4157945a9837408c00 (esc)
42 $ hg debugdata --dir foo/bar/ 0
43 f\x00149da44f2a4e14f488b7bd4157945a9837408c00 (esc)
@@ -0,0 +1,31 b''
1 $ . "$TESTDIR/narrow-library.sh"
2 $ hg init master
3 $ cd master
4 $ echo treemanifest >> .hg/requires
5 $ echo 'contents of file' > file
6 $ mkdir foo
7 $ echo 'contents of foo/bar' > foo/bar
8 $ hg ci -Am 'some change'
9 adding file
10 adding foo/bar
11
12 $ cd ..
13 $ hg clone --narrow ssh://user@dummy/master copy --include=foo
14 requesting all changes
15 adding changesets
16 adding manifests
17 adding file changes
18 added 1 changesets with 1 changes to 1 files
19 new changesets * (glob)
20 updating to branch default
21 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 $ cd copy
23
24 $ hg debugdirstate
25 n * 20 unset foo/bar (glob)
26 $ mv .hg/dirstate .hg/old_dirstate
27 $ dd bs=40 count=1 if=.hg/old_dirstate of=.hg/dirstate 2>/dev/null
28 $ hg debugdirstate
29 $ hg debugrebuilddirstate
30 $ hg debugdirstate
31 n * * unset foo/bar (glob)
@@ -0,0 +1,207 b''
1
2 $ . "$TESTDIR/narrow-library.sh"
3
4 create full repo
5
6 $ hg init master
7 $ cd master
8 $ cat >> .hg/hgrc <<EOF
9 > [narrow]
10 > serveellipses=True
11 > EOF
12
13 $ mkdir inside
14 $ echo 1 > inside/f
15 $ hg commit -Aqm 'initial inside'
16
17 $ mkdir outside
18 $ echo 1 > outside/f
19 $ hg commit -Aqm 'initial outside'
20
21 $ echo 2a > outside/f
22 $ hg commit -Aqm 'outside 2a'
23 $ echo 3 > inside/f
24 $ hg commit -Aqm 'inside 3'
25 $ echo 4a > outside/f
26 $ hg commit -Aqm 'outside 4a'
27 $ hg update '.~3'
28 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
29
30 $ echo 2b > outside/f
31 $ hg commit -Aqm 'outside 2b'
32 $ echo 3 > inside/f
33 $ hg commit -Aqm 'inside 3'
34 $ echo 4b > outside/f
35 $ hg commit -Aqm 'outside 4b'
36 $ hg update '.~3'
37 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
38
39 $ echo 2c > outside/f
40 $ hg commit -Aqm 'outside 2c'
41 $ echo 3 > inside/f
42 $ hg commit -Aqm 'inside 3'
43 $ echo 4c > outside/f
44 $ hg commit -Aqm 'outside 4c'
45 $ hg update '.~3'
46 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
47
48 $ echo 2d > outside/f
49 $ hg commit -Aqm 'outside 2d'
50 $ echo 3 > inside/f
51 $ hg commit -Aqm 'inside 3'
52 $ echo 4d > outside/f
53 $ hg commit -Aqm 'outside 4d'
54
55 $ hg update -r 'desc("outside 4a")'
56 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
57 $ hg merge -r 'desc("outside 4b")' 2>&1 | egrep -v '(warning:|incomplete!)'
58 merging outside/f
59 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
60 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
61 $ echo 5 > outside/f
62 $ rm outside/f.orig
63 $ hg resolve --mark outside/f
64 (no more unresolved files)
65 $ hg commit -m 'merge a/b 5'
66 $ echo 6 > outside/f
67 $ hg commit -Aqm 'outside 6'
68
69 $ hg merge -r 'desc("outside 4c")' 2>&1 | egrep -v '(warning:|incomplete!)'
70 merging outside/f
71 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
72 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
73 $ echo 7 > outside/f
74 $ rm outside/f.orig
75 $ hg resolve --mark outside/f
76 (no more unresolved files)
77 $ hg commit -Aqm 'merge a/b/c 7'
78 $ echo 8 > outside/f
79 $ hg commit -Aqm 'outside 8'
80
81 $ hg merge -r 'desc("outside 4d")' 2>&1 | egrep -v '(warning:|incomplete!)'
82 merging outside/f
83 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
84 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
85 $ echo 9 > outside/f
86 $ rm outside/f.orig
87 $ hg resolve --mark outside/f
88 (no more unresolved files)
89 $ hg commit -Aqm 'merge a/b/c/d 9'
90 $ echo 10 > outside/f
91 $ hg commit -Aqm 'outside 10'
92
93 $ echo 11 > inside/f
94 $ hg commit -Aqm 'inside 11'
95 $ echo 12 > outside/f
96 $ hg commit -Aqm 'outside 12'
97
98 $ hg log -G -T '{rev} {node|short} {desc}\n'
99 @ 21 8d874d57adea outside 12
100 |
101 o 20 7ef88b4dd4fa inside 11
102 |
103 o 19 2a20009de83e outside 10
104 |
105 o 18 3ac1f5779de3 merge a/b/c/d 9
106 |\
107 | o 17 38a9c2f7e546 outside 8
108 | |
109 | o 16 094aa62fc898 merge a/b/c 7
110 | |\
111 | | o 15 f29d083d32e4 outside 6
112 | | |
113 | | o 14 2dc11382541d merge a/b 5
114 | | |\
115 o | | | 13 27d07ef97221 outside 4d
116 | | | |
117 o | | | 12 465567bdfb2d inside 3
118 | | | |
119 o | | | 11 d1c61993ec83 outside 2d
120 | | | |
121 | o | | 10 56859a8e33b9 outside 4c
122 | | | |
123 | o | | 9 bb96a08b062a inside 3
124 | | | |
125 | o | | 8 b844052e7b3b outside 2c
126 |/ / /
127 | | o 7 9db2d8fcc2a6 outside 4b
128 | | |
129 | | o 6 6418167787a6 inside 3
130 | | |
131 +---o 5 77344f344d83 outside 2b
132 | |
133 | o 4 9cadde08dc9f outside 4a
134 | |
135 | o 3 019ef06f125b inside 3
136 | |
137 | o 2 75e40c075a19 outside 2a
138 |/
139 o 1 906d6c682641 initial outside
140 |
141 o 0 9f8e82b51004 initial inside
142
143
144 Now narrow clone this and get a hopefully correct graph
145
146 $ cd ..
147 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
148 requesting all changes
149 adding changesets
150 adding manifests
151 adding file changes
152 added 14 changesets with 3 changes to 1 files
153 new changesets *:* (glob)
154 updating to branch default
155 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
156 $ cd narrow
157
158 To make updating the tests easier, we print the emitted nodes
159 sorted. This makes it easier to identify when the same node structure
160 has been emitted, just in a different order.
161
162 $ hg log -T '{if(ellipsis,"...")}{node|short} {p1node|short} {p2node|short} {desc}\n' | sort
163 ...094aa62fc898 6418167787a6 bb96a08b062a merge a/b/c 7
164 ...2a20009de83e 019ef06f125b 3ac1f5779de3 outside 10
165 ...3ac1f5779de3 465567bdfb2d 094aa62fc898 merge a/b/c/d 9
166 ...75e40c075a19 9f8e82b51004 000000000000 outside 2a
167 ...77344f344d83 9f8e82b51004 000000000000 outside 2b
168 ...8d874d57adea 7ef88b4dd4fa 000000000000 outside 12
169 ...b844052e7b3b 9f8e82b51004 000000000000 outside 2c
170 ...d1c61993ec83 9f8e82b51004 000000000000 outside 2d
171 019ef06f125b 75e40c075a19 000000000000 inside 3
172 465567bdfb2d d1c61993ec83 000000000000 inside 3
173 6418167787a6 77344f344d83 000000000000 inside 3
174 7ef88b4dd4fa 2a20009de83e 000000000000 inside 11
175 9f8e82b51004 000000000000 000000000000 initial inside
176 bb96a08b062a b844052e7b3b 000000000000 inside 3
177
178 But seeing the graph is also nice:
179 $ hg log -G -T '{if(ellipsis,"...")}{node|short} {desc}\n'
180 @ ...8d874d57adea outside 12
181 |
182 o 7ef88b4dd4fa inside 11
183 |
184 o ...2a20009de83e outside 10
185 |\
186 | o ...3ac1f5779de3 merge a/b/c/d 9
187 | |\
188 | | o ...094aa62fc898 merge a/b/c 7
189 | | |\
190 | o | | 465567bdfb2d inside 3
191 | | | |
192 | o | | ...d1c61993ec83 outside 2d
193 | | | |
194 | | | o bb96a08b062a inside 3
195 | | | |
196 | +---o ...b844052e7b3b outside 2c
197 | | |
198 | | o 6418167787a6 inside 3
199 | | |
200 | | o ...77344f344d83 outside 2b
201 | |/
202 o | 019ef06f125b inside 3
203 | |
204 o | ...75e40c075a19 outside 2a
205 |/
206 o 9f8e82b51004 initial inside
207
@@ -0,0 +1,210 b''
1
2 $ . "$TESTDIR/narrow-library.sh"
3
4 create full repo
5
6 $ hg init master
7 $ cd master
8 $ cat >> .hg/hgrc <<EOF
9 > [narrow]
10 > serveellipses=True
11 > EOF
12
13 $ mkdir inside
14 $ echo 1 > inside/f
15 $ mkdir inside2
16 $ echo 1 > inside2/f
17 $ mkdir outside
18 $ echo 1 > outside/f
19 $ hg ci -Aqm 'initial'
20
21 $ echo 2 > inside/f
22 $ hg ci -qm 'inside 2'
23
24 $ echo 2 > inside2/f
25 $ hg ci -qm 'inside2 2'
26
27 $ echo 2 > outside/f
28 $ hg ci -qm 'outside 2'
29
30 $ cd ..
31
32 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
33 requesting all changes
34 adding changesets
35 adding manifests
36 adding file changes
37 added 3 changesets with 2 changes to 1 files
38 new changesets *:* (glob)
39 updating to branch default
40 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
41
42 $ hg clone --narrow ssh://user@dummy/master narrow2 --include inside --include inside2
43 requesting all changes
44 adding changesets
45 adding manifests
46 adding file changes
47 added 4 changesets with 4 changes to 2 files
48 new changesets *:* (glob)
49 updating to branch default
50 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
51
52 Can push to wider repo if change does not affect paths in wider repo that are
53 not also in narrower repo
54
55 $ cd narrow
56 $ echo 3 > inside/f
57 $ hg ci -m 'inside 3'
58 $ hg push ssh://user@dummy/narrow2
59 pushing to ssh://user@dummy/narrow2
60 searching for changes
61 remote: adding changesets
62 remote: adding manifests
63 remote: adding file changes
64 remote: added 1 changesets with 1 changes to 1 files
65
66 Can push to narrower repo if change affects only paths within remote's
67 narrow spec
68
69 $ cd ../narrow2
70 $ cat >> .hg/hgrc <<EOF
71 > [narrow]
72 > serveellipses=True
73 > EOF
74 $ hg co -r 'desc("inside 3")'
75 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
76 $ echo 4 > inside/f
77 $ hg ci -m 'inside 4'
78 $ hg push ssh://user@dummy/narrow
79 pushing to ssh://user@dummy/narrow
80 searching for changes
81 remote: adding changesets
82 remote: adding manifests
83 remote: adding file changes
84 remote: added 1 changesets with 1 changes to 1 files
85
86 Can push to narrow repo if change affects only paths outside remote's
87 narrow spec
88
89 $ echo 3 > inside2/f
90 $ hg ci -m 'inside2 3'
91 TODO: this should be successful
92 $ hg push ssh://user@dummy/narrow
93 pushing to ssh://user@dummy/narrow
94 searching for changes
95 remote: adding changesets
96 remote: adding manifests
97 remote: adding file changes
98 remote: transaction abort!
99 remote: rollback completed
100 remote: abort: data/inside2/f.i@4a1aa07735e6: unknown parent!
101 abort: stream ended unexpectedly (got 0 bytes, expected 4)
102 [255]
103
104 Can pull from wider repo if change affects only paths outside remote's
105 narrow spec
106 $ echo 4 > inside2/f
107 $ hg ci -m 'inside2 4'
108 $ hg log -G -T '{rev} {node|short} {files}\n'
109 @ 7 d78a96df731d inside2/f
110 |
111 o 6 8c26f5218962 inside2/f
112 |
113 o 5 ba3480e2f9de inside/f
114 |
115 o 4 4e5edd526618 inside/f
116 |
117 o 3 81e7e07b7ab0 outside/f
118 |
119 o 2 f3993b8c0c2b inside2/f
120 |
121 o 1 8cd66ca966b4 inside/f
122 |
123 o 0 c8057d6f53ab inside/f inside2/f outside/f
124
125 $ cd ../narrow
126 $ hg log -G -T '{rev} {node|short} {files}\n'
127 o 4 ba3480e2f9de inside/f
128 |
129 @ 3 4e5edd526618 inside/f
130 |
131 o 2 81e7e07b7ab0 outside/f
132 |
133 o 1 8cd66ca966b4 inside/f
134 |
135 o 0 c8057d6f53ab inside/f inside2/f outside/f
136
137 $ hg pull ssh://user@dummy/narrow2
138 pulling from ssh://user@dummy/narrow2
139 searching for changes
140 remote: abort: unable to resolve parent while packing 'data/inside2/f.i' 3 for changeset 5 (?)
141 adding changesets
142 remote: abort: unexpected error: unable to resolve parent while packing 'data/inside2/f.i' 3 for changeset 5
143 transaction abort!
144 rollback completed
145 abort: pull failed on remote
146 [255]
147
148 Check that the resulting history is valid in the full repo
149
150 $ cd ../narrow2
151 $ hg push ssh://user@dummy/master
152 pushing to ssh://user@dummy/master
153 searching for changes
154 remote: adding changesets
155 remote: adding manifests
156 remote: adding file changes
157 remote: added 4 changesets with 4 changes to 2 files
158 $ cd ../master
159 $ hg verify
160 checking changesets
161 checking manifests
162 crosschecking files in changesets and manifests
163 checking files
164 3 files, 8 changesets, 10 total revisions
165
166 Can not push to wider repo if change affects paths in wider repo that are
167 not also in narrower repo
168 $ cd ../master
169 $ hg co -r 'desc("inside2 4")'
170 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
171 $ echo 5 > inside2/f
172 $ hg ci -m 'inside2 5'
173 $ hg log -G -T '{rev} {node|short} {files}\n'
174 @ 8 5970befb64ba inside2/f
175 |
176 o 7 d78a96df731d inside2/f
177 |
178 o 6 8c26f5218962 inside2/f
179 |
180 o 5 ba3480e2f9de inside/f
181 |
182 o 4 4e5edd526618 inside/f
183 |
184 o 3 81e7e07b7ab0 outside/f
185 |
186 o 2 f3993b8c0c2b inside2/f
187 |
188 o 1 8cd66ca966b4 inside/f
189 |
190 o 0 c8057d6f53ab inside/f inside2/f outside/f
191
192 $ cd ../narrow
193 $ hg pull
194 pulling from ssh://user@dummy/master
195 searching for changes
196 adding changesets
197 adding manifests
198 adding file changes
199 added 1 changesets with 0 changes to 0 files
200 new changesets * (glob)
201 (run 'hg update' to get a working copy)
202 TODO: this should tell the user that their narrow clone does not have the
203 necessary content to be able to push to the target
204 $ hg push ssh://user@dummy/narrow2
205 pushing to ssh://user@dummy/narrow2
206 searching for changes
207 remote has heads on branch 'default' that are not known locally: d78a96df731d
208 abort: push creates new remote head 5970befb64ba!
209 (pull and merge or see 'hg help push' for details about pushing new heads)
210 [255]
@@ -0,0 +1,170 b''
1 $ . "$TESTDIR/narrow-library.sh"
2
3 $ hg init master
4 $ cd master
5
6 $ mkdir inside
7 $ echo inside > inside/f1
8 $ mkdir outside
9 $ echo outside > outside/f2
10 $ mkdir patchdir
11 $ echo patch_this > patchdir/f3
12 $ hg ci -Aqm 'initial'
13
14 $ cd ..
15
16 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
17 requesting all changes
18 adding changesets
19 adding manifests
20 adding file changes
21 added 1 changesets with 1 changes to 1 files
22 new changesets dff6a2a6d433
23 updating to branch default
24 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
25
26 $ cd narrow
27
28 $ mkdir outside
29 $ echo other_contents > outside/f2
30 $ grep outside .hg/narrowspec
31 [1]
32 $ grep outside .hg/dirstate
33 [1]
34 $ hg status
35
36 `hg status` did not add outside.
37 $ grep outside .hg/narrowspec
38 [1]
39 $ grep outside .hg/dirstate
40 [1]
41
42 Unfortunately this is not really a candidate for adding to narrowhg proper,
43 since it depends on some other source for providing the manifests (when using
44 treemanifests) and file contents. Something like a virtual filesystem and/or
45 remotefilelog. We want to be useful when not using those systems, so we do not
46 have this method available in narrowhg proper at the moment.
47 $ cat > "$TESTTMP/expand_extension.py" <<EOF
48 > import os
49 > import sys
50 >
51 > from mercurial import extensions
52 > from mercurial import localrepo
53 > from mercurial import match as matchmod
54 > from mercurial import patch
55 > from mercurial import util as hgutil
56 >
57 > def expandnarrowspec(ui, repo, newincludes=None):
58 > if not newincludes:
59 > return
60 > import sys
61 > newincludes = set([newincludes])
62 > narrowhg = extensions.find('narrow')
63 > includes, excludes = repo.narrowpats
64 > currentmatcher = narrowhg.narrowspec.match(repo.root, includes, excludes)
65 > includes = includes | newincludes
66 > if not repo.currenttransaction():
67 > ui.develwarn('expandnarrowspec called outside of transaction!')
68 > repo.setnarrowpats(includes, excludes)
69 > newmatcher = narrowhg.narrowspec.match(repo.root, includes, excludes)
70 > added = matchmod.differencematcher(newmatcher, currentmatcher)
71 > for f in repo['.'].manifest().walk(added):
72 > repo.dirstate.normallookup(f)
73 >
74 > def makeds(ui, repo):
75 > def wrapds(orig, self):
76 > ds = orig(self)
77 > class expandingdirstate(ds.__class__):
78 > # Mercurial 4.4 uses this version.
79 > @hgutil.propertycache
80 > def _map(self):
81 > ret = super(expandingdirstate, self)._map
82 > with repo.wlock(), repo.lock(), repo.transaction(
83 > 'expandnarrowspec'):
84 > expandnarrowspec(ui, repo, os.environ.get('DIRSTATEINCLUDES'))
85 > return ret
86 > # Mercurial 4.3.3 and earlier uses this version. It seems that
87 > # narrowhg does not currently support this version, but we include
88 > # it just in case backwards compatibility is restored.
89 > def _read(self):
90 > ret = super(expandingdirstate, self)._read()
91 > with repo.wlock(), repo.lock(), repo.transaction(
92 > 'expandnarrowspec'):
93 > expandnarrowspec(ui, repo, os.environ.get('DIRSTATEINCLUDES'))
94 > return ret
95 > ds.__class__ = expandingdirstate
96 > return ds
97 > return wrapds
98 >
99 > def reposetup(ui, repo):
100 > extensions.wrapfilecache(localrepo.localrepository, 'dirstate',
101 > makeds(ui, repo))
102 > def overridepatch(orig, *args, **kwargs):
103 > with repo.wlock():
104 > expandnarrowspec(ui, repo, os.environ.get('PATCHINCLUDES'))
105 > return orig(*args, **kwargs)
106 >
107 > extensions.wrapfunction(patch, 'patch', overridepatch)
108 > EOF
109 $ cat >> ".hg/hgrc" <<EOF
110 > [extensions]
111 > expand_extension = $TESTTMP/expand_extension.py
112 > EOF
113
114 Since we do not have the ability to rely on a virtual filesystem or
115 remotefilelog in the test, we just fake it by copying the data from the 'master'
116 repo.
117 $ cp -a ../master/.hg/store/data/* .hg/store/data
118 Do that for patchdir as well.
119 $ cp -a ../master/patchdir .
120
121 `hg status` will now add outside, but not patchdir.
122 $ DIRSTATEINCLUDES=path:outside hg status
123 M outside/f2
124 $ grep outside .hg/narrowspec
125 path:outside
126 $ grep outside .hg/dirstate > /dev/null
127 $ grep patchdir .hg/narrowspec
128 [1]
129 $ grep patchdir .hg/dirstate
130 [1]
131
132 Get rid of the modification to outside/f2.
133 $ hg update -C .
134 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
135
136 This patch will not apply cleanly at the moment, so `hg import` will break
137 $ cat > "$TESTTMP/foo.patch" <<EOF
138 > --- patchdir/f3
139 > +++ patchdir/f3
140 > @@ -1,1 +1,1 @@
141 > -this should be "patch_this", but its not, so patch fails
142 > +this text is irrelevant
143 > EOF
144 $ PATCHINCLUDES=path:patchdir hg import -p0 -e "$TESTTMP/foo.patch" -m ignored
145 applying $TESTTMP/foo.patch
146 patching file patchdir/f3
147 Hunk #1 FAILED at 0
148 1 out of 1 hunks FAILED -- saving rejects to file patchdir/f3.rej
149 abort: patch failed to apply
150 [255]
151 $ grep patchdir .hg/narrowspec
152 [1]
153 $ grep patchdir .hg/dirstate > /dev/null
154 [1]
155
156 Let's make it apply cleanly and see that it *did* expand properly
157 $ cat > "$TESTTMP/foo.patch" <<EOF
158 > --- patchdir/f3
159 > +++ patchdir/f3
160 > @@ -1,1 +1,1 @@
161 > -patch_this
162 > +patched_this
163 > EOF
164 $ PATCHINCLUDES=path:patchdir hg import -p0 -e "$TESTTMP/foo.patch" -m message
165 applying $TESTTMP/foo.patch
166 $ cat patchdir/f3
167 patched_this
168 $ grep patchdir .hg/narrowspec
169 path:patchdir
170 $ grep patchdir .hg/dirstate > /dev/null
@@ -0,0 +1,28 b''
1 $ cd $TESTDIR && python $RUNTESTDIR/run-tests.py \
2 > --extra-config-opt experimental.treemanifest=1 test-narrow-merge.t 2>&1 | \
3 > grep -v 'unexpected mercurial lib' | egrep -v '\(expected'
4
5 --- */tests/test-narrow-merge.t (glob)
6 +++ */tests/test-narrow-merge.t.err (glob)
7 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
8
9 $ hg update -q 'desc("modify inside/f1")'
10 $ hg merge 'desc("modify outside/f1")'
11 - abort: merge affects file 'outside/f1' outside narrow, which is not yet supported
12 + abort: merge affects file 'outside/' outside narrow, which is not yet supported
13 (merging in the other direction may work)
14 [255]
15
16 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
17
18 $ hg update -q 'desc("modify outside/f1")'
19 $ hg merge 'desc("conflicting outside/f1")'
20 - abort: conflict in file 'outside/f1' is outside narrow clone
21 + abort: conflict in file 'outside/' is outside narrow clone
22 [255]
23
24 ERROR: test-narrow-merge.t output changed
25 !
26 Failed test-narrow-merge.t: output changed
27 # Ran 1 tests, 0 skipped, 1 failed.
28 python hash seed: * (glob)
@@ -0,0 +1,94 b''
1
2 $ . "$TESTDIR/narrow-library.sh"
3
4 create full repo
5
6 $ hg init master
7 $ cd master
8 $ cat >> .hg/hgrc <<EOF
9 > [narrow]
10 > serveellipses=True
11 > EOF
12
13 $ mkdir inside
14 $ echo inside1 > inside/f1
15 $ echo inside2 > inside/f2
16 $ mkdir outside
17 $ echo outside1 > outside/f1
18 $ echo outside2 > outside/f2
19 $ hg ci -Aqm 'initial'
20
21 $ echo modified > inside/f1
22 $ hg ci -qm 'modify inside/f1'
23
24 $ hg update -q 0
25 $ echo modified > inside/f2
26 $ hg ci -qm 'modify inside/f2'
27
28 $ hg update -q 0
29 $ echo modified2 > inside/f1
30 $ hg ci -qm 'conflicting inside/f1'
31
32 $ hg update -q 0
33 $ echo modified > outside/f1
34 $ hg ci -qm 'modify outside/f1'
35
36 $ hg update -q 0
37 $ echo modified2 > outside/f1
38 $ hg ci -qm 'conflicting outside/f1'
39
40 $ cd ..
41
42 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
43 requesting all changes
44 adding changesets
45 adding manifests
46 adding file changes
47 added 6 changesets with 5 changes to 2 files (+4 heads)
48 new changesets *:* (glob)
49 updating to branch default
50 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
51 $ cd narrow
52
53 $ hg update -q 0
54
55 Can merge in when no files outside narrow spec are involved
56
57 $ hg update -q 'desc("modify inside/f1")'
58 $ hg merge 'desc("modify inside/f2")'
59 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 (branch merge, don't forget to commit)
61 $ hg commit -m 'merge inside changes'
62
63 Can merge conflicting changes inside narrow spec
64
65 $ hg update -q 'desc("modify inside/f1")'
66 $ hg merge 'desc("conflicting inside/f1")' 2>&1 | egrep -v '(warning:|incomplete!)'
67 merging inside/f1
68 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
69 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
70 $ echo modified3 > inside/f1
71 $ hg resolve -m
72 (no more unresolved files)
73 $ hg commit -m 'merge inside/f1'
74
75 TODO: Can merge non-conflicting changes outside narrow spec
76
77 $ hg update -q 'desc("modify inside/f1")'
78 $ hg merge 'desc("modify outside/f1")'
79 abort: merge affects file 'outside/f1' outside narrow, which is not yet supported
80 (merging in the other direction may work)
81 [255]
82
83 $ hg update -q 'desc("modify outside/f1")'
84 $ hg merge 'desc("modify inside/f1")'
85 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
86 (branch merge, don't forget to commit)
87 $ hg ci -m 'merge from inside to outside'
88
89 Refuses merge of conflicting outside changes
90
91 $ hg update -q 'desc("modify outside/f1")'
92 $ hg merge 'desc("conflicting outside/f1")'
93 abort: conflict in file 'outside/f1' is outside narrow clone
94 [255]
@@ -0,0 +1,5 b''
1 $ cd $TESTDIR && python $RUNTESTDIR/run-tests.py \
2 > --extra-config-opt experimental.treemanifest=1 test-patch.t 2>&1 | \
3 > grep -v 'unexpected mercurial lib' | egrep -v '\(expected'
4 .
5 # Ran 1 tests, 0 skipped, 0 failed.
@@ -0,0 +1,76 b''
1
2 $ . "$TESTDIR/narrow-library.sh"
3
4 create full repo
5
6 $ hg init master
7 $ cd master
8
9 $ mkdir inside
10 $ echo inside > inside/f1
11 $ mkdir outside
12 $ echo outside > outside/f1
13 $ hg ci -Aqm 'initial'
14
15 $ echo modified > inside/f1
16 $ hg ci -qm 'modify inside'
17
18 $ echo modified > outside/f1
19 $ hg ci -qm 'modify outside'
20
21 $ cd ..
22
23 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
24 requesting all changes
25 adding changesets
26 adding manifests
27 adding file changes
28 added 3 changesets with 2 changes to 1 files
29 new changesets *:* (glob)
30 updating to branch default
31 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
32 $ cd narrow
33
34 Can show patch touching paths outside
35
36 $ hg log -p
37 changeset: 2:* (glob)
38 tag: tip
39 user: test
40 date: Thu Jan 01 00:00:00 1970 +0000
41 summary: modify outside
42
43
44 changeset: 1:* (glob)
45 user: test
46 date: Thu Jan 01 00:00:00 1970 +0000
47 summary: modify inside
48
49 diff -r * -r * inside/f1 (glob)
50 --- a/inside/f1 Thu Jan 01 00:00:00 1970 +0000
51 +++ b/inside/f1 Thu Jan 01 00:00:00 1970 +0000
52 @@ -1,1 +1,1 @@
53 -inside
54 +modified
55
56 changeset: 0:* (glob)
57 user: test
58 date: Thu Jan 01 00:00:00 1970 +0000
59 summary: initial
60
61 diff -r 000000000000 -r * inside/f1 (glob)
62 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
63 +++ b/inside/f1 Thu Jan 01 00:00:00 1970 +0000
64 @@ -0,0 +1,1 @@
65 +inside
66
67
68 $ hg status --rev 1 --rev 2
69
70 Can show copies inside the narrow clone
71
72 $ hg cp inside/f1 inside/f2
73 $ hg diff --git
74 diff --git a/inside/f1 b/inside/f2
75 copy from inside/f1
76 copy to inside/f2
@@ -0,0 +1,418 b''
1 $ . "$TESTDIR/narrow-library.sh"
2
3 initialize nested directories to validate complex include/exclude patterns
4
5 $ hg init master
6 $ cd master
7 $ cat >> .hg/hgrc <<EOF
8 > [narrow]
9 > serveellipses=True
10 > EOF
11
12 $ echo root > root
13 $ hg add root
14 $ hg commit -m 'add root'
15
16 $ for d in dir1 dir2 dir1/dirA dir1/dirB dir2/dirA dir2/dirB
17 > do
18 > mkdir -p $d
19 > echo $d/foo > $d/foo
20 > hg add $d/foo
21 > hg commit -m "add $d/foo"
22 > echo $d/bar > $d/bar
23 > hg add $d/bar
24 > hg commit -m "add $d/bar"
25 > done
26 $ chmod +x dir1/dirA/foo
27 $ hg commit -m "make dir1/dirA/foo executable"
28 $ hg log -G -T '{rev} {node|short} {files}\n'
29 @ 13 c87ca422d521 dir1/dirA/foo
30 |
31 o 12 951b8a83924e dir2/dirB/bar
32 |
33 o 11 01ae5a51b563 dir2/dirB/foo
34 |
35 o 10 5eababdf0ac5 dir2/dirA/bar
36 |
37 o 9 99d690663739 dir2/dirA/foo
38 |
39 o 8 8e80155d5445 dir1/dirB/bar
40 |
41 o 7 406760310428 dir1/dirB/foo
42 |
43 o 6 623466a5f475 dir1/dirA/bar
44 |
45 o 5 06ff3a5be997 dir1/dirA/foo
46 |
47 o 4 33227af02764 dir2/bar
48 |
49 o 3 5e1f9d8d7c69 dir2/foo
50 |
51 o 2 594bc4b13d4a dir1/bar
52 |
53 o 1 47f480a08324 dir1/foo
54 |
55 o 0 2a4f0c3b67da root
56
57 $ cd ..
58
59 clone a narrow portion of the master, such that we can widen it later
60
61 $ hg clone --narrow ssh://user@dummy/master narrow \
62 > --include dir1 \
63 > --include dir2 \
64 > --exclude dir1/dirA \
65 > --exclude dir1/dirB \
66 > --exclude dir2/dirA \
67 > --exclude dir2/dirB
68 requesting all changes
69 adding changesets
70 adding manifests
71 adding file changes
72 added 6 changesets with 4 changes to 4 files
73 new changesets *:* (glob)
74 updating to branch default
75 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
76
77 $ cd narrow
78 $ cat .hg/narrowspec
79 [includes]
80 path:dir1
81 path:dir2
82 [excludes]
83 path:dir1/dirA
84 path:dir1/dirB
85 path:dir2/dirA
86 path:dir2/dirB
87 $ hg manifest -r tip
88 dir1/bar
89 dir1/dirA/bar
90 dir1/dirA/foo
91 dir1/dirB/bar
92 dir1/dirB/foo
93 dir1/foo
94 dir2/bar
95 dir2/dirA/bar
96 dir2/dirA/foo
97 dir2/dirB/bar
98 dir2/dirB/foo
99 dir2/foo
100 root
101 $ find * | sort
102 dir1
103 dir1/bar
104 dir1/foo
105 dir2
106 dir2/bar
107 dir2/foo
108 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
109 @ 5 c87ca422d521... dir1/dirA/foo
110 |
111 o 4 33227af02764 dir2/bar
112 |
113 o 3 5e1f9d8d7c69 dir2/foo
114 |
115 o 2 594bc4b13d4a dir1/bar
116 |
117 o 1 47f480a08324 dir1/foo
118 |
119 o 0 2a4f0c3b67da... root
120
121
122 widen the narrow checkout
123
124 $ hg tracked --removeexclude dir1/dirA
125 comparing with ssh://user@dummy/master
126 searching for changes
127 no changes found
128 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
129 adding changesets
130 adding manifests
131 adding file changes
132 added 9 changesets with 6 changes to 6 files
133 new changesets *:* (glob)
134 $ cat .hg/narrowspec
135 [includes]
136 path:dir1
137 path:dir2
138 [excludes]
139 path:dir1/dirB
140 path:dir2/dirA
141 path:dir2/dirB
142 $ find * | sort
143 dir1
144 dir1/bar
145 dir1/dirA
146 dir1/dirA/bar
147 dir1/dirA/foo
148 dir1/foo
149 dir2
150 dir2/bar
151 dir2/foo
152 $ test -x dir1/dirA/foo && echo executable
153 executable
154 $ test -x dir1/dirA/bar || echo not executable
155 not executable
156 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
157 @ 8 c87ca422d521 dir1/dirA/foo
158 |
159 o 7 951b8a83924e... dir2/dirB/bar
160 |
161 o 6 623466a5f475 dir1/dirA/bar
162 |
163 o 5 06ff3a5be997 dir1/dirA/foo
164 |
165 o 4 33227af02764 dir2/bar
166 |
167 o 3 5e1f9d8d7c69 dir2/foo
168 |
169 o 2 594bc4b13d4a dir1/bar
170 |
171 o 1 47f480a08324 dir1/foo
172 |
173 o 0 2a4f0c3b67da... root
174
175
176 widen narrow spec again, but exclude a file in previously included spec
177
178 $ hg tracked --removeexclude dir2/dirB --addexclude dir1/dirA/bar
179 comparing with ssh://user@dummy/master
180 searching for changes
181 looking for local changes to affected paths
182 deleting data/dir1/dirA/bar.i
183 no changes found
184 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
185 adding changesets
186 adding manifests
187 adding file changes
188 added 11 changesets with 7 changes to 7 files
189 new changesets *:* (glob)
190 $ cat .hg/narrowspec
191 [includes]
192 path:dir1
193 path:dir2
194 [excludes]
195 path:dir1/dirA/bar
196 path:dir1/dirB
197 path:dir2/dirA
198 $ find * | sort
199 dir1
200 dir1/bar
201 dir1/dirA
202 dir1/dirA/foo
203 dir1/foo
204 dir2
205 dir2/bar
206 dir2/dirB
207 dir2/dirB/bar
208 dir2/dirB/foo
209 dir2/foo
210 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
211 @ 10 c87ca422d521 dir1/dirA/foo
212 |
213 o 9 951b8a83924e dir2/dirB/bar
214 |
215 o 8 01ae5a51b563 dir2/dirB/foo
216 |
217 o 7 5eababdf0ac5... dir2/dirA/bar
218 |
219 o 6 623466a5f475... dir1/dirA/bar
220 |
221 o 5 06ff3a5be997 dir1/dirA/foo
222 |
223 o 4 33227af02764 dir2/bar
224 |
225 o 3 5e1f9d8d7c69 dir2/foo
226 |
227 o 2 594bc4b13d4a dir1/bar
228 |
229 o 1 47f480a08324 dir1/foo
230 |
231 o 0 2a4f0c3b67da... root
232
233
234 widen narrow spec yet again, excluding a directory in previous spec
235
236 $ hg tracked --removeexclude dir2/dirA --addexclude dir1/dirA
237 comparing with ssh://user@dummy/master
238 searching for changes
239 looking for local changes to affected paths
240 deleting data/dir1/dirA/foo.i
241 no changes found
242 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
243 adding changesets
244 adding manifests
245 adding file changes
246 added 13 changesets with 8 changes to 8 files
247 new changesets *:* (glob)
248 $ cat .hg/narrowspec
249 [includes]
250 path:dir1
251 path:dir2
252 [excludes]
253 path:dir1/dirA
254 path:dir1/dirA/bar
255 path:dir1/dirB
256 $ find * | sort
257 dir1
258 dir1/bar
259 dir1/foo
260 dir2
261 dir2/bar
262 dir2/dirA
263 dir2/dirA/bar
264 dir2/dirA/foo
265 dir2/dirB
266 dir2/dirB/bar
267 dir2/dirB/foo
268 dir2/foo
269 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
270 @ 12 c87ca422d521... dir1/dirA/foo
271 |
272 o 11 951b8a83924e dir2/dirB/bar
273 |
274 o 10 01ae5a51b563 dir2/dirB/foo
275 |
276 o 9 5eababdf0ac5 dir2/dirA/bar
277 |
278 o 8 99d690663739 dir2/dirA/foo
279 |
280 o 7 8e80155d5445... dir1/dirB/bar
281 |
282 o 6 623466a5f475... dir1/dirA/bar
283 |
284 o 5 06ff3a5be997... dir1/dirA/foo
285 |
286 o 4 33227af02764 dir2/bar
287 |
288 o 3 5e1f9d8d7c69 dir2/foo
289 |
290 o 2 594bc4b13d4a dir1/bar
291 |
292 o 1 47f480a08324 dir1/foo
293 |
294 o 0 2a4f0c3b67da... root
295
296
297 include a directory that was previously explicitly excluded
298
299 $ hg tracked --removeexclude dir1/dirA
300 comparing with ssh://user@dummy/master
301 searching for changes
302 no changes found
303 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
304 adding changesets
305 adding manifests
306 adding file changes
307 added 13 changesets with 9 changes to 9 files
308 new changesets *:* (glob)
309 $ cat .hg/narrowspec
310 [includes]
311 path:dir1
312 path:dir2
313 [excludes]
314 path:dir1/dirA/bar
315 path:dir1/dirB
316 $ find * | sort
317 dir1
318 dir1/bar
319 dir1/dirA
320 dir1/dirA/foo
321 dir1/foo
322 dir2
323 dir2/bar
324 dir2/dirA
325 dir2/dirA/bar
326 dir2/dirA/foo
327 dir2/dirB
328 dir2/dirB/bar
329 dir2/dirB/foo
330 dir2/foo
331 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
332 @ 12 c87ca422d521 dir1/dirA/foo
333 |
334 o 11 951b8a83924e dir2/dirB/bar
335 |
336 o 10 01ae5a51b563 dir2/dirB/foo
337 |
338 o 9 5eababdf0ac5 dir2/dirA/bar
339 |
340 o 8 99d690663739 dir2/dirA/foo
341 |
342 o 7 8e80155d5445... dir1/dirB/bar
343 |
344 o 6 623466a5f475... dir1/dirA/bar
345 |
346 o 5 06ff3a5be997 dir1/dirA/foo
347 |
348 o 4 33227af02764 dir2/bar
349 |
350 o 3 5e1f9d8d7c69 dir2/foo
351 |
352 o 2 594bc4b13d4a dir1/bar
353 |
354 o 1 47f480a08324 dir1/foo
355 |
356 o 0 2a4f0c3b67da... root
357
358
359 $ cd ..
360
361 clone a narrow portion of the master, such that we can widen it later
362
363 $ hg clone --narrow ssh://user@dummy/master narrow2 --include dir1/dirA
364 requesting all changes
365 adding changesets
366 adding manifests
367 adding file changes
368 added 5 changesets with 2 changes to 2 files
369 new changesets *:* (glob)
370 updating to branch default
371 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
372 $ cd narrow2
373 $ find * | sort
374 dir1
375 dir1/dirA
376 dir1/dirA/bar
377 dir1/dirA/foo
378 $ hg tracked --addinclude dir1
379 comparing with ssh://user@dummy/master
380 searching for changes
381 no changes found
382 saved backup bundle to $TESTTMP/narrow2/.hg/strip-backup/*-widen.hg (glob)
383 adding changesets
384 adding manifests
385 adding file changes
386 added 10 changesets with 6 changes to 6 files
387 new changesets *:* (glob)
388 $ find * | sort
389 dir1
390 dir1/bar
391 dir1/dirA
392 dir1/dirA/bar
393 dir1/dirA/foo
394 dir1/dirB
395 dir1/dirB/bar
396 dir1/dirB/foo
397 dir1/foo
398 $ hg log -G -T '{rev} {node|short}{if(ellipsis, "...")} {files}\n'
399 @ 9 c87ca422d521 dir1/dirA/foo
400 |
401 o 8 951b8a83924e... dir2/dirB/bar
402 |
403 o 7 8e80155d5445 dir1/dirB/bar
404 |
405 o 6 406760310428 dir1/dirB/foo
406 |
407 o 5 623466a5f475 dir1/dirA/bar
408 |
409 o 4 06ff3a5be997 dir1/dirA/foo
410 |
411 o 3 33227af02764... dir2/bar
412 |
413 o 2 594bc4b13d4a dir1/bar
414 |
415 o 1 47f480a08324 dir1/foo
416 |
417 o 0 2a4f0c3b67da... root
418
@@ -0,0 +1,175 b''
1 $ . "$TESTDIR/narrow-library.sh"
2
3 $ hg init master
4 $ cd master
5 $ cat >> .hg/hgrc <<EOF
6 > [narrow]
7 > serveellipses=True
8 > EOF
9 $ for x in `$TESTDIR/seq.py 10`
10 > do
11 > echo $x > "f$x"
12 > hg add "f$x"
13 > hg commit -m "Commit f$x"
14 > done
15 $ cd ..
16
17 narrow clone a couple files, f2 and f8
18
19 $ hg clone --narrow ssh://user@dummy/master narrow --include "f2" --include "f8"
20 requesting all changes
21 adding changesets
22 adding manifests
23 adding file changes
24 added 5 changesets with 2 changes to 2 files
25 new changesets *:* (glob)
26 updating to branch default
27 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 $ cd narrow
29 $ ls
30 f2
31 f8
32 $ cat f2 f8
33 2
34 8
35
36 $ cd ..
37
38 change every upstream file twice
39
40 $ cd master
41 $ for x in `$TESTDIR/seq.py 10`
42 > do
43 > echo "update#1 $x" >> "f$x"
44 > hg commit -m "Update#1 to f$x" "f$x"
45 > done
46 $ for x in `$TESTDIR/seq.py 10`
47 > do
48 > echo "update#2 $x" >> "f$x"
49 > hg commit -m "Update#2 to f$x" "f$x"
50 > done
51 $ cd ..
52
53 look for incoming changes
54
55 $ cd narrow
56 $ hg incoming --limit 3
57 comparing with ssh://user@dummy/master
58 searching for changes
59 changeset: 5:ddc055582556
60 user: test
61 date: Thu Jan 01 00:00:00 1970 +0000
62 summary: Update#1 to f1
63
64 changeset: 6:f66eb5ad621d
65 user: test
66 date: Thu Jan 01 00:00:00 1970 +0000
67 summary: Update#1 to f2
68
69 changeset: 7:c42ecff04e99
70 user: test
71 date: Thu Jan 01 00:00:00 1970 +0000
72 summary: Update#1 to f3
73
74
75 Interrupting the pull is safe
76 $ hg --config hooks.pretxnchangegroup.bad=false pull -q
77 transaction abort!
78 rollback completed
79 abort: pretxnchangegroup.bad hook exited with status 1
80 [255]
81 $ hg id
82 223311e70a6f tip
83
84 pull new changes down to the narrow clone. Should get 8 new changesets: 4
85 relevant to the narrow spec, and 4 ellipsis nodes gluing them all together.
86
87 $ hg pull
88 pulling from ssh://user@dummy/master
89 searching for changes
90 adding changesets
91 adding manifests
92 adding file changes
93 added 9 changesets with 4 changes to 2 files
94 new changesets *:* (glob)
95 (run 'hg update' to get a working copy)
96 $ hg log -T '{rev}: {desc}\n'
97 13: Update#2 to f10
98 12: Update#2 to f8
99 11: Update#2 to f7
100 10: Update#2 to f2
101 9: Update#2 to f1
102 8: Update#1 to f8
103 7: Update#1 to f7
104 6: Update#1 to f2
105 5: Update#1 to f1
106 4: Commit f10
107 3: Commit f8
108 2: Commit f7
109 1: Commit f2
110 0: Commit f1
111 $ hg update tip
112 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
113
114 add a change and push it
115
116 $ echo "update#3 2" >> f2
117 $ hg commit -m "Update#3 to f2" f2
118 $ hg log f2 -T '{rev}: {desc}\n'
119 14: Update#3 to f2
120 10: Update#2 to f2
121 6: Update#1 to f2
122 1: Commit f2
123 $ hg push
124 pushing to ssh://user@dummy/master
125 searching for changes
126 remote: adding changesets
127 remote: adding manifests
128 remote: adding file changes
129 remote: added 1 changesets with 1 changes to 1 files
130 $ cd ..
131
132 $ cd master
133 $ hg log f2 -T '{rev}: {desc}\n'
134 30: Update#3 to f2
135 21: Update#2 to f2
136 11: Update#1 to f2
137 1: Commit f2
138 $ hg log -l 3 -T '{rev}: {desc}\n'
139 30: Update#3 to f2
140 29: Update#2 to f10
141 28: Update#2 to f9
142
143 Can pull into repo with a single commit
144
145 $ cd ..
146 $ hg clone -q --narrow ssh://user@dummy/master narrow2 --include "f1" -r 0
147 $ cd narrow2
148 $ hg pull -q -r 1
149 transaction abort!
150 rollback completed
151 abort: pull failed on remote
152 [255]
153
154 Can use 'hg share':
155 $ cat >> $HGRCPATH <<EOF
156 > [extensions]
157 > share=
158 > EOF
159
160 $ cd ..
161 $ hg share narrow2 narrow2-share
162 updating working directory
163 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
164 $ cd narrow2-share
165 $ hg status
166
167 We should also be able to unshare without breaking everything:
168 $ hg unshare
169 devel-warn: write with no wlock: "narrowspec" at: */hgext/narrow/narrowrepo.py:41 (unsharenarrowspec) (glob)
170 $ hg verify
171 checking changesets
172 checking manifests
173 crosschecking files in changesets and manifests
174 checking files
175 1 files, 1 changesets, 1 total revisions
@@ -0,0 +1,93 b''
1
2 $ . "$TESTDIR/narrow-library.sh"
3
4 create full repo
5
6 $ hg init master
7 $ cd master
8
9 $ mkdir inside
10 $ echo inside1 > inside/f1
11 $ echo inside2 > inside/f2
12 $ mkdir outside
13 $ echo outside1 > outside/f1
14 $ echo outside2 > outside/f2
15 $ hg ci -Aqm 'initial'
16
17 $ echo modified > inside/f1
18 $ hg ci -qm 'modify inside/f1'
19
20 $ hg update -q 0
21 $ echo modified2 > inside/f2
22 $ hg ci -qm 'modify inside/f2'
23
24 $ hg update -q 0
25 $ echo modified > outside/f1
26 $ hg ci -qm 'modify outside/f1'
27
28 $ hg update -q 0
29 $ echo modified2 > outside/f1
30 $ hg ci -qm 'conflicting outside/f1'
31
32 $ cd ..
33
34 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
35 requesting all changes
36 adding changesets
37 adding manifests
38 adding file changes
39 added 5 changesets with 4 changes to 2 files (+3 heads)
40 new changesets *:* (glob)
41 updating to branch default
42 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
43 $ cd narrow
44 $ cat >> $HGRCPATH <<EOF
45 > [extensions]
46 > rebase=
47 > EOF
48
49 $ hg update -q 0
50
51 Can rebase onto commit where no files outside narrow spec are involved
52
53 $ hg update -q 0
54 $ echo modified > inside/f2
55 $ hg ci -qm 'modify inside/f2'
56 $ hg rebase -d 'desc("modify inside/f1")'
57 rebasing 5:c2f36d04e05d "modify inside/f2" (tip)
58 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-rebase.hg (glob)
59
60 Can rebase onto conflicting changes inside narrow spec
61
62 $ hg update -q 0
63 $ echo conflicting > inside/f1
64 $ hg ci -qm 'conflicting inside/f1'
65 $ hg rebase -d 'desc("modify inside/f1")' 2>&1 | egrep -v '(warning:|incomplete!)'
66 rebasing 6:cdce97fbf653 "conflicting inside/f1" (tip)
67 merging inside/f1
68 unresolved conflicts (see hg resolve, then hg rebase --continue)
69 $ echo modified3 > inside/f1
70 $ hg resolve -m 2>&1 | grep -v continue:
71 (no more unresolved files)
72 $ hg rebase --continue
73 rebasing 6:cdce97fbf653 "conflicting inside/f1" (tip)
74 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-rebase.hg (glob)
75
76 Can rebase onto non-conflicting changes outside narrow spec
77
78 $ hg update -q 0
79 $ echo modified > inside/f2
80 $ hg ci -qm 'modify inside/f2'
81 $ hg rebase -d 'desc("modify outside/f1")'
82 rebasing 7:c2f36d04e05d "modify inside/f2" (tip)
83 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-rebase.hg (glob)
84
85 Rebase interrupts on conflicting changes outside narrow spec
86
87 $ hg update -q 'desc("conflicting outside/f1")'
88 $ hg phase -f -d .
89 no phases changed
90 $ hg rebase -d 'desc("modify outside/f1")'
91 rebasing 4:707c035aadb6 "conflicting outside/f1"
92 abort: conflict in file 'outside/f1' is outside narrow clone
93 [255]
@@ -0,0 +1,345 b''
1 $ . "$TESTDIR/narrow-library.sh"
2
3 create full repo
4
5 $ hg init master
6 $ cd master
7 $ cat >> .hg/hgrc <<EOF
8 > [narrow]
9 > serveellipses=True
10 > EOF
11
12 $ mkdir inside
13 $ echo 1 > inside/f
14 $ hg commit -Aqm 'initial inside'
15
16 $ mkdir outside
17 $ echo 1 > outside/f
18 $ hg commit -Aqm 'initial outside'
19
20 $ echo 2a > outside/f
21 $ hg commit -Aqm 'outside 2a'
22 $ echo 3 > inside/f
23 $ hg commit -Aqm 'inside 3'
24 $ echo 4a > outside/f
25 $ hg commit -Aqm 'outside 4a'
26 $ hg update '.~3'
27 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
28
29 $ echo 2b > outside/f
30 $ hg commit -Aqm 'outside 2b'
31 $ echo 3 > inside/f
32 $ hg commit -Aqm 'inside 3'
33 $ echo 4b > outside/f
34 $ hg commit -Aqm 'outside 4b'
35 $ hg update '.~3'
36 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
37
38 $ echo 2c > outside/f
39 $ hg commit -Aqm 'outside 2c'
40 $ echo 3 > inside/f
41 $ hg commit -Aqm 'inside 3'
42 $ echo 4c > outside/f
43 $ hg commit -Aqm 'outside 4c'
44 $ hg update '.~3'
45 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
46
47 $ echo 2d > outside/f
48 $ hg commit -Aqm 'outside 2d'
49 $ echo 3 > inside/f
50 $ hg commit -Aqm 'inside 3'
51 $ echo 4d > outside/f
52 $ hg commit -Aqm 'outside 4d'
53
54 $ hg update -r 'desc("outside 4a")'
55 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
56 $ hg merge -r 'desc("outside 4b")' 2>&1 | egrep -v '(warning:|incomplete!)'
57 merging outside/f
58 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
59 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
60 $ echo 5 > outside/f
61 $ rm outside/f.orig
62 $ hg resolve --mark outside/f
63 (no more unresolved files)
64 $ hg commit -m 'merge a/b 5'
65 $ echo 6 > outside/f
66 $ hg commit -Aqm 'outside 6'
67
68 $ hg merge -r 'desc("outside 4c")' 2>&1 | egrep -v '(warning:|incomplete!)'
69 merging outside/f
70 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
71 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
72 $ echo 7 > outside/f
73 $ rm outside/f.orig
74 $ hg resolve --mark outside/f
75 (no more unresolved files)
76 $ hg commit -Aqm 'merge a/b/c 7'
77 $ echo 8 > outside/f
78 $ hg commit -Aqm 'outside 8'
79
80 $ hg merge -r 'desc("outside 4d")' 2>&1 | egrep -v '(warning:|incomplete!)'
81 merging outside/f
82 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
83 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
84 $ echo 9 > outside/f
85 $ rm outside/f.orig
86 $ hg resolve --mark outside/f
87 (no more unresolved files)
88 $ hg commit -Aqm 'merge a/b/c/d 9'
89 $ echo 10 > outside/f
90 $ hg commit -Aqm 'outside 10'
91
92 $ echo 11 > inside/f
93 $ hg commit -Aqm 'inside 11'
94 $ echo 12 > outside/f
95 $ hg commit -Aqm 'outside 12'
96
97 $ hg log -G -T '{rev} {node|short} {desc}\n'
98 @ 21 8d874d57adea outside 12
99 |
100 o 20 7ef88b4dd4fa inside 11
101 |
102 o 19 2a20009de83e outside 10
103 |
104 o 18 3ac1f5779de3 merge a/b/c/d 9
105 |\
106 | o 17 38a9c2f7e546 outside 8
107 | |
108 | o 16 094aa62fc898 merge a/b/c 7
109 | |\
110 | | o 15 f29d083d32e4 outside 6
111 | | |
112 | | o 14 2dc11382541d merge a/b 5
113 | | |\
114 o | | | 13 27d07ef97221 outside 4d
115 | | | |
116 o | | | 12 465567bdfb2d inside 3
117 | | | |
118 o | | | 11 d1c61993ec83 outside 2d
119 | | | |
120 | o | | 10 56859a8e33b9 outside 4c
121 | | | |
122 | o | | 9 bb96a08b062a inside 3
123 | | | |
124 | o | | 8 b844052e7b3b outside 2c
125 |/ / /
126 | | o 7 9db2d8fcc2a6 outside 4b
127 | | |
128 | | o 6 6418167787a6 inside 3
129 | | |
130 +---o 5 77344f344d83 outside 2b
131 | |
132 | o 4 9cadde08dc9f outside 4a
133 | |
134 | o 3 019ef06f125b inside 3
135 | |
136 | o 2 75e40c075a19 outside 2a
137 |/
138 o 1 906d6c682641 initial outside
139 |
140 o 0 9f8e82b51004 initial inside
141
142
143 Now narrow and shallow clone this and get a hopefully correct graph
144
145 $ cd ..
146 $ hg clone --narrow ssh://user@dummy/master narrow --include inside --depth 7
147 requesting all changes
148 adding changesets
149 adding manifests
150 adding file changes
151 added 8 changesets with 3 changes to 1 files
152 new changesets *:* (glob)
153 updating to branch default
154 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
155 $ cd narrow
156
157 To make updating the tests easier, we print the emitted nodes
158 sorted. This makes it easier to identify when the same node structure
159 has been emitted, just in a different order.
160
161 $ hg log -G -T '{rev} {node|short}{if(ellipsis,"...")} {desc}\n'
162 @ 7 8d874d57adea... outside 12
163 |
164 o 6 7ef88b4dd4fa inside 11
165 |
166 o 5 2a20009de83e... outside 10
167 |
168 o 4 3ac1f5779de3... merge a/b/c/d 9
169 |\
170 | o 3 465567bdfb2d inside 3
171 | |
172 | o 2 d1c61993ec83... outside 2d
173 |
174 o 1 bb96a08b062a inside 3
175 |
176 o 0 b844052e7b3b... outside 2c
177
178
179 $ hg log -T '{if(ellipsis,"...")}{node|short} {p1node|short} {p2node|short} {desc}\n' | sort
180 ...2a20009de83e 000000000000 3ac1f5779de3 outside 10
181 ...3ac1f5779de3 bb96a08b062a 465567bdfb2d merge a/b/c/d 9
182 ...8d874d57adea 7ef88b4dd4fa 000000000000 outside 12
183 ...b844052e7b3b 000000000000 000000000000 outside 2c
184 ...d1c61993ec83 000000000000 000000000000 outside 2d
185 465567bdfb2d d1c61993ec83 000000000000 inside 3
186 7ef88b4dd4fa 2a20009de83e 000000000000 inside 11
187 bb96a08b062a b844052e7b3b 000000000000 inside 3
188
189 $ cd ..
190
191 Incremental test case: show a pull can pull in a conflicted merge even if elided
192
193 $ hg init pullmaster
194 $ cd pullmaster
195 $ cat >> .hg/hgrc <<EOF
196 > [narrow]
197 > serveellipses=True
198 > EOF
199 $ mkdir inside outside
200 $ echo v1 > inside/f
201 $ echo v1 > outside/f
202 $ hg add inside/f outside/f
203 $ hg commit -m init
204
205 $ for line in a b c d
206 > do
207 > hg update -r 0
208 > echo v2$line > outside/f
209 > hg commit -m "outside 2$line"
210 > echo v2$line > inside/f
211 > hg commit -m "inside 2$line"
212 > echo v3$line > outside/f
213 > hg commit -m "outside 3$line"
214 > echo v4$line > outside/f
215 > hg commit -m "outside 4$line"
216 > done
217 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
218 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
219 created new head
220 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
221 created new head
222 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
223 created new head
224
225 $ cd ..
226 $ hg clone --narrow ssh://user@dummy/pullmaster pullshallow \
227 > --include inside --depth 3
228 requesting all changes
229 adding changesets
230 adding manifests
231 adding file changes
232 added 12 changesets with 5 changes to 1 files (+3 heads)
233 new changesets *:* (glob)
234 updating to branch default
235 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
236 $ cd pullshallow
237
238 $ hg log -G -T '{rev} {node|short}{if(ellipsis,"...")} {desc}\n'
239 @ 11 0ebbd712a0c8... outside 4d
240 |
241 o 10 0d4c867aeb23 inside 2d
242 |
243 o 9 e932969c3961... outside 2d
244
245 o 8 33d530345455... outside 4c
246 |
247 o 7 0ce6481bfe07 inside 2c
248 |
249 o 6 caa65c940632... outside 2c
250
251 o 5 3df233defecc... outside 4b
252 |
253 o 4 7162cc6d11a4 inside 2b
254 |
255 o 3 f2a632f0082d... outside 2b
256
257 o 2 b8a3da16ba49... outside 4a
258 |
259 o 1 53f543eb8e45 inside 2a
260 |
261 o 0 1be3e5221c6a... outside 2a
262
263 $ hg log -T '{if(ellipsis,"...")}{node|short} {p1node|short} {p2node|short} {desc}\n' | sort
264 ...0ebbd712a0c8 0d4c867aeb23 000000000000 outside 4d
265 ...1be3e5221c6a 000000000000 000000000000 outside 2a
266 ...33d530345455 0ce6481bfe07 000000000000 outside 4c
267 ...3df233defecc 7162cc6d11a4 000000000000 outside 4b
268 ...b8a3da16ba49 53f543eb8e45 000000000000 outside 4a
269 ...caa65c940632 000000000000 000000000000 outside 2c
270 ...e932969c3961 000000000000 000000000000 outside 2d
271 ...f2a632f0082d 000000000000 000000000000 outside 2b
272 0ce6481bfe07 caa65c940632 000000000000 inside 2c
273 0d4c867aeb23 e932969c3961 000000000000 inside 2d
274 53f543eb8e45 1be3e5221c6a 000000000000 inside 2a
275 7162cc6d11a4 f2a632f0082d 000000000000 inside 2b
276
277 $ cd ../pullmaster
278 $ hg update -r 'desc("outside 4a")'
279 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
280 $ hg merge -r 'desc("outside 4b")' 2>&1 | egrep -v '(warning:|incomplete!)'
281 merging inside/f
282 merging outside/f
283 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
284 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
285 $ echo 3 > inside/f
286 $ echo 5 > outside/f
287 $ rm -f {in,out}side/f.orig
288 $ hg resolve --mark inside/f outside/f
289 (no more unresolved files)
290 $ hg commit -m 'merge a/b 5'
291
292 $ hg update -r 'desc("outside 4c")'
293 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
294 $ hg merge -r 'desc("outside 4d")' 2>&1 | egrep -v '(warning:|incomplete!)'
295 merging inside/f
296 merging outside/f
297 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
298 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
299 $ echo 3 > inside/f
300 $ echo 5 > outside/f
301 $ rm -f {in,out}side/f.orig
302 $ hg resolve --mark inside/f outside/f
303 (no more unresolved files)
304 $ hg commit -m 'merge c/d 5'
305
306 $ hg update -r 'desc("merge a/b 5")'
307 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
308 $ hg merge -r 'desc("merge c/d 5")'
309 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
310 (branch merge, don't forget to commit)
311 $ echo 6 > outside/f
312 $ hg commit -m 'outside 6'
313 $ echo 7 > outside/f
314 $ hg commit -m 'outside 7'
315 $ echo 8 > outside/f
316 $ hg commit -m 'outside 8'
317
318 $ cd ../pullshallow
319 $ hg pull --depth 3
320 pulling from ssh://user@dummy/pullmaster
321 searching for changes
322 adding changesets
323 adding manifests
324 adding file changes
325 added 4 changesets with 3 changes to 1 files (-3 heads)
326 new changesets *:* (glob)
327 (run 'hg update' to get a working copy)
328
329 $ hg log -T '{if(ellipsis,"...")}{node|short} {p1node|short} {p2node|short} {desc}\n' | sort
330 ...0ebbd712a0c8 0d4c867aeb23 000000000000 outside 4d
331 ...1be3e5221c6a 000000000000 000000000000 outside 2a
332 ...33d530345455 0ce6481bfe07 000000000000 outside 4c
333 ...3df233defecc 7162cc6d11a4 000000000000 outside 4b
334 ...b8a3da16ba49 53f543eb8e45 000000000000 outside 4a
335 ...bf545653453e 968003d40c60 000000000000 outside 8
336 ...caa65c940632 000000000000 000000000000 outside 2c
337 ...e932969c3961 000000000000 000000000000 outside 2d
338 ...f2a632f0082d 000000000000 000000000000 outside 2b
339 0ce6481bfe07 caa65c940632 000000000000 inside 2c
340 0d4c867aeb23 e932969c3961 000000000000 inside 2d
341 53f543eb8e45 1be3e5221c6a 000000000000 inside 2a
342 67d49c0bdbda b8a3da16ba49 3df233defecc merge a/b 5
343 7162cc6d11a4 f2a632f0082d 000000000000 inside 2b
344 968003d40c60 67d49c0bdbda e867021d52c2 outside 6
345 e867021d52c2 33d530345455 0ebbd712a0c8 merge c/d 5
@@ -0,0 +1,122 b''
1 $ . "$TESTDIR/narrow-library.sh"
2
3 $ hg init master
4 $ cd master
5 $ cat >> .hg/hgrc <<EOF
6 > [narrow]
7 > serveellipses=True
8 > EOF
9 $ for x in `$TESTDIR/seq.py 10`
10 > do
11 > echo $x > "f$x"
12 > hg add "f$x"
13 > done
14 $ hg commit -m "Add root files"
15 $ mkdir d1 d2
16 $ for x in `$TESTDIR/seq.py 10`
17 > do
18 > echo d1/$x > "d1/f$x"
19 > hg add "d1/f$x"
20 > echo d2/$x > "d2/f$x"
21 > hg add "d2/f$x"
22 > done
23 $ hg commit -m "Add d1 and d2"
24 $ for x in `$TESTDIR/seq.py 10`
25 > do
26 > echo f$x rev2 > "f$x"
27 > echo d1/f$x rev2 > "d1/f$x"
28 > echo d2/f$x rev2 > "d2/f$x"
29 > hg commit -m "Commit rev2 of f$x, d1/f$x, d2/f$x"
30 > done
31 $ cd ..
32
33 narrow and shallow clone the d2 directory
34
35 $ hg clone --narrow ssh://user@dummy/master shallow --include "d2" --depth 2
36 requesting all changes
37 adding changesets
38 adding manifests
39 adding file changes
40 added 4 changesets with 13 changes to 10 files
41 new changesets *:* (glob)
42 updating to branch default
43 10 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 $ cd shallow
45 $ hg log -T '{rev}{if(ellipsis,"...")}: {desc}\n'
46 3: Commit rev2 of f10, d1/f10, d2/f10
47 2: Commit rev2 of f9, d1/f9, d2/f9
48 1: Commit rev2 of f8, d1/f8, d2/f8
49 0...: Commit rev2 of f7, d1/f7, d2/f7
50 $ hg update 0
51 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
52 $ cat d2/f7 d2/f8
53 d2/f7 rev2
54 d2/8
55
56 $ cd ..
57
58 change every upstream file once
59
60 $ cd master
61 $ for x in `$TESTDIR/seq.py 10`
62 > do
63 > echo f$x rev3 > "f$x"
64 > echo d1/f$x rev3 > "d1/f$x"
65 > echo d2/f$x rev3 > "d2/f$x"
66 > hg commit -m "Commit rev3 of f$x, d1/f$x, d2/f$x"
67 > done
68 $ cd ..
69
70 pull new changes with --depth specified. There were 10 changes to the d2
71 directory but the shallow pull should only fetch 3.
72
73 $ cd shallow
74 $ hg pull --depth 2
75 pulling from ssh://user@dummy/master
76 searching for changes
77 adding changesets
78 adding manifests
79 adding file changes
80 added 4 changesets with 10 changes to 10 files
81 new changesets *:* (glob)
82 (run 'hg update' to get a working copy)
83 $ hg log -T '{rev}{if(ellipsis,"...")}: {desc}\n'
84 7: Commit rev3 of f10, d1/f10, d2/f10
85 6: Commit rev3 of f9, d1/f9, d2/f9
86 5: Commit rev3 of f8, d1/f8, d2/f8
87 4...: Commit rev3 of f7, d1/f7, d2/f7
88 3: Commit rev2 of f10, d1/f10, d2/f10
89 2: Commit rev2 of f9, d1/f9, d2/f9
90 1: Commit rev2 of f8, d1/f8, d2/f8
91 0...: Commit rev2 of f7, d1/f7, d2/f7
92 $ hg update 4
93 merging d2/f1
94 merging d2/f2
95 merging d2/f3
96 merging d2/f4
97 merging d2/f5
98 merging d2/f6
99 merging d2/f7
100 3 files updated, 7 files merged, 0 files removed, 0 files unresolved
101 $ cat d2/f7 d2/f8
102 d2/f7 rev3
103 d2/f8 rev2
104 $ hg update 7
105 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
106 $ cat d2/f10
107 d2/f10 rev3
108
109 $ cd ..
110
111 cannot clone with zero or negative depth
112
113 $ hg clone --narrow ssh://user@dummy/master bad --include "d2" --depth 0
114 requesting all changes
115 remote: abort: depth must be positive, got 0
116 abort: pull failed on remote
117 [255]
118 $ hg clone --narrow ssh://user@dummy/master bad --include "d2" --depth -1
119 requesting all changes
120 remote: abort: depth must be positive, got -1
121 abort: pull failed on remote
122 [255]
@@ -0,0 +1,52 b''
1 $ cd $TESTDIR && python $RUNTESTDIR/run-tests.py \
2 > --extra-config-opt experimental.treemanifest=1 test-narrow-strip.t 2>&1 | \
3 > grep -v 'unexpected mercurial lib' | egrep -v '\(expected'
4
5 --- */test-narrow-strip.t (glob)
6 +++ */test-narrow-strip.t.err (glob)
7 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
8 o 0 initial
9
10 $ hg debugdata -m 1
11 - inside/f1\x004d6a634d5ba06331a60c29ee0db8412490a54fcd (esc)
12 - outside/f1\x0084ba604d54dee1f13310ce3d4ac2e8a36636691a (esc)
13 + inside\x006a8bc41df94075d501f9740587a0c0e13c170dc5t (esc)
14 + outside\x00255c2627ebdd3c7dcaa6945246f9b9f02bd45a09t (esc)
15
16 $ rm -f $TESTTMP/narrow/.hg/strip-backup/*-backup.hg
17 $ hg strip .
18 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
19
20 Check that hash of file outside narrow spec got restored
21 $ hg debugdata -m 2
22 - inside/f1\x004d6a634d5ba06331a60c29ee0db8412490a54fcd (esc)
23 - outside/f1\x0084ba604d54dee1f13310ce3d4ac2e8a36636691a (esc)
24 + inside\x006a8bc41df94075d501f9740587a0c0e13c170dc5t (esc)
25 + outside\x00255c2627ebdd3c7dcaa6945246f9b9f02bd45a09t (esc)
26
27 Also verify we can apply the bundle with 'hg pull':
28 $ hg co -r 'desc("modify inside")'
29 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
30 date: Thu Jan 01 00:00:00 1970 +0000
31 summary: initial
32
33 - changeset: 1:9e48d953700d
34 + changeset: 1:3888164bccf0
35 user: test
36 date: Thu Jan 01 00:00:00 1970 +0000
37 summary: modify outside again
38
39 - changeset: 2:f505d5e96aa8
40 + changeset: 2:40b66f95a209
41 tag: tip
42 - parent: 0:a99f4d53924d
43 + parent: 0:c2a5fabcca3c
44 user: test
45 date: Thu Jan 01 00:00:00 1970 +0000
46 summary: modify inside
47
48 ERROR: test-narrow-strip.t output changed
49 !
50 Failed test-narrow-strip.t: output changed
51 # Ran 1 tests, 0 skipped, 1 failed.
52 python hash seed: * (glob)
@@ -0,0 +1,148 b''
1
2 $ . "$TESTDIR/narrow-library.sh"
3
4 create full repo
5
6 $ hg init master
7 $ cd master
8 $ cat >> .hg/hgrc <<EOF
9 > [narrow]
10 > serveellipses=True
11 > EOF
12
13 $ mkdir inside
14 $ echo inside > inside/f1
15 $ mkdir outside
16 $ echo outside > outside/f1
17 $ hg ci -Aqm 'initial'
18
19 $ echo modified > inside/f1
20 $ hg ci -qm 'modify inside'
21
22 $ hg co -q 0
23 $ echo modified > outside/f1
24 $ hg ci -qm 'modify outside'
25
26 $ echo modified again >> outside/f1
27 $ hg ci -qm 'modify outside again'
28
29 $ cd ..
30
31 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
32 requesting all changes
33 adding changesets
34 adding manifests
35 adding file changes
36 added 3 changesets with 2 changes to 1 files (+1 heads)
37 new changesets *:* (glob)
38 updating to branch default
39 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
40 $ cd narrow
41 $ cat >> $HGRCPATH <<EOF
42 > [extensions]
43 > strip=
44 > EOF
45
46 Can strip and recover changesets affecting only files within narrow spec
47
48 $ hg co -r 'desc("modify inside")'
49 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
50 $ rm -f $TESTTMP/narrow/.hg/strip-backup/*-backup.hg
51 $ hg strip .
52 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
53 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-backup.hg (glob)
54 $ hg unbundle .hg/strip-backup/*-backup.hg
55 adding changesets
56 adding manifests
57 adding file changes
58 added 1 changesets with 1 changes to 1 files (+1 heads)
59 new changesets * (glob)
60 (run 'hg heads' to see heads, 'hg merge' to merge)
61
62 Can strip and recover changesets affecting files outside of narrow spec
63
64 $ hg co -r 'desc("modify outside")'
65 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
66 $ hg log -G -T '{rev} {desc}\n'
67 o 2 modify inside
68 |
69 | @ 1 modify outside again
70 |/
71 o 0 initial
72
73 $ hg debugdata -m 1
74 inside/f1\x004d6a634d5ba06331a60c29ee0db8412490a54fcd (esc)
75 outside/f1\x0084ba604d54dee1f13310ce3d4ac2e8a36636691a (esc)
76
77 $ rm -f $TESTTMP/narrow/.hg/strip-backup/*-backup.hg
78 $ hg strip .
79 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
80 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-backup.hg (glob)
81 $ hg unbundle .hg/strip-backup/*-backup.hg
82 adding changesets
83 adding manifests
84 adding file changes
85 added 1 changesets with 0 changes to 0 files (+1 heads)
86 new changesets * (glob)
87 (run 'hg heads' to see heads, 'hg merge' to merge)
88 $ hg log -G -T '{rev} {desc}\n'
89 o 2 modify outside again
90 |
91 | o 1 modify inside
92 |/
93 @ 0 initial
94
95 Check that hash of file outside narrow spec got restored
96 $ hg debugdata -m 2
97 inside/f1\x004d6a634d5ba06331a60c29ee0db8412490a54fcd (esc)
98 outside/f1\x0084ba604d54dee1f13310ce3d4ac2e8a36636691a (esc)
99
100 Also verify we can apply the bundle with 'hg pull':
101 $ hg co -r 'desc("modify inside")'
102 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
103 $ rm .hg/strip-backup/*-backup.hg
104 $ hg strip .
105 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
106 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-backup.hg (glob)
107 $ hg pull .hg/strip-backup/*-backup.hg
108 pulling from .hg/strip-backup/*-backup.hg (glob)
109 searching for changes
110 adding changesets
111 adding manifests
112 adding file changes
113 added 1 changesets with 1 changes to 1 files (+1 heads)
114 new changesets * (glob)
115 (run 'hg heads' to see heads, 'hg merge' to merge)
116
117 $ rm .hg/strip-backup/*-backup.hg
118 $ hg strip 0
119 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
120 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-backup.hg (glob)
121 $ hg incoming .hg/strip-backup/*-backup.hg
122 comparing with .hg/strip-backup/*-backup.hg (glob)
123 changeset: 0:* (glob)
124 user: test
125 date: Thu Jan 01 00:00:00 1970 +0000
126 summary: initial
127
128 changeset: 1:9e48d953700d
129 user: test
130 date: Thu Jan 01 00:00:00 1970 +0000
131 summary: modify outside again
132
133 changeset: 2:f505d5e96aa8
134 tag: tip
135 parent: 0:a99f4d53924d
136 user: test
137 date: Thu Jan 01 00:00:00 1970 +0000
138 summary: modify inside
139
140 $ hg pull .hg/strip-backup/*-backup.hg
141 pulling from .hg/strip-backup/*-backup.hg (glob)
142 requesting all changes
143 adding changesets
144 adding manifests
145 adding file changes
146 added 3 changesets with 2 changes to 1 files (+1 heads)
147 new changesets *:* (glob)
148 (run 'hg heads' to see heads, 'hg merge' to merge)
@@ -0,0 +1,68 b''
1 $ cd $TESTDIR && python $RUNTESTDIR/run-tests.py \
2 > --extra-config-opt experimental.treemanifest=1 test-narrow-narrow.t 2>&1 | \
3 > grep -v 'unexpected mercurial lib' | egrep -v '\(expected'
4
5 --- /*/tests/test-narrow-narrow.t (glob)
6 +++ /*/tests/test-narrow-narrow.t.err (glob)
7 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
8 * (glob)
9 * (glob)
10 deleting data/d0/f.i
11 + deleting meta/d0/00manifest.i
12 $ hg log -T "{node|short}: {desc} {outsidenarrow}\n"
13 *: local change to d3 (glob)
14 *: add d10/f outsidenarrow (glob)
15 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
16 looking for local changes to affected paths
17 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
18 deleting data/d0/f.i
19 + deleting meta/d0/00manifest.i
20 Updates off of stripped commit if necessary
21 $ hg co -r 'desc("local change to d3")' -q
22 $ echo local change >> d6/f
23 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
24 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
25 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
26 deleting data/d3/f.i
27 + deleting meta/d3/00manifest.i
28 $ hg log -T '{desc}\n' -r .
29 add d10/f
30 Updates to nullid if necessary
31 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
32 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
33 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
34 deleting data/d3/f.i
35 + deleting meta/d3/00manifest.i
36 $ hg id
37 000000000000
38 $ cd ..
39 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
40 searching for changes
41 looking for local changes to affected paths
42 deleting data/d0/f.i
43 + deleting meta/d0/00manifest.i
44 $ hg tracked
45 $ hg files
46 [1]
47 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
48 searching for changes
49 looking for local changes to affected paths
50 deleting data/d6/f.i
51 + deleting meta/d6/00manifest.i
52 $ hg tracked
53 I path:d0
54 I path:d3
55 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
56 searching for changes
57 looking for local changes to affected paths
58 deleting data/d0/f.i
59 + deleting meta/d0/00manifest.i
60 $ hg tracked
61 I path:d3
62 I path:d9
63
64 ERROR: test-narrow-narrow.t output changed
65 !
66 Failed test-narrow-narrow.t: output changed
67 # Ran 1 tests, 0 skipped, 1 failed.
68 python hash seed: * (glob)
@@ -0,0 +1,76 b''
1
2 $ . "$TESTDIR/narrow-library.sh"
3
4 create full repo
5
6 $ hg init master
7 $ cd master
8 $ echo init > init
9 $ hg ci -Aqm 'initial'
10
11 $ mkdir inside
12 $ echo inside > inside/f1
13 $ mkdir outside
14 $ echo outside > outside/f1
15 $ hg ci -Aqm 'add inside and outside'
16
17 $ echo modified > inside/f1
18 $ hg ci -qm 'modify inside'
19
20 $ echo modified > outside/f1
21 $ hg ci -qm 'modify outside'
22
23 $ cd ..
24
25 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
26 requesting all changes
27 adding changesets
28 adding manifests
29 adding file changes
30 added 4 changesets with 2 changes to 1 files
31 new changesets *:* (glob)
32 updating to branch default
33 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
34 $ cd narrow
35 $ hg debugindex -c
36 rev offset length base linkrev nodeid p1 p2
37 0 0 64 0 0 9958b1af2add 000000000000 000000000000
38 1 64 81 1 1 2db4ce2a3bfe 9958b1af2add 000000000000
39 2 145 75 2 2 0980ee31a742 2db4ce2a3bfe 000000000000
40 3 220 (76|77) 3 3 4410145019b7 0980ee31a742 000000000000 (re)
41
42 $ hg update -q 0
43
44 Can update to revision with changes inside
45
46 $ hg update -q 'desc("add inside and outside")'
47 $ hg update -q 'desc("modify inside")'
48 $ find *
49 inside
50 inside/f1 (glob)
51 $ cat inside/f1
52 modified
53
54 Can update to revision with changes outside
55
56 $ hg update -q 'desc("modify outside")'
57 $ find *
58 inside
59 inside/f1 (glob)
60 $ cat inside/f1
61 modified
62
63 Can update with a deleted file inside
64
65 $ hg rm inside/f1
66 $ hg update -q 'desc("modify inside")'
67 $ hg update -q 'desc("modify outside")'
68 $ hg update -q 'desc("initial")'
69 $ hg update -q 'desc("modify inside")'
70
71 Can update with a moved file inside
72
73 $ hg mv inside/f1 inside/f2
74 $ hg update -q 'desc("modify outside")'
75 $ hg update -q 'desc("initial")'
76 $ hg update -q 'desc("modify inside")'
@@ -0,0 +1,28 b''
1 $ cd $TESTDIR && python $RUNTESTDIR/run-tests.py \
2 > --extra-config-opt experimental.treemanifest=1 test-narrow-widen.t 2>&1 | \
3 > grep -v 'unexpected mercurial lib' | egrep -v '\(expected'
4
5 --- */test-narrow-widen.t (glob)
6 +++ */test-narrow-widen.t.err (glob)
7 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
8 $ hg verify
9 checking changesets
10 checking manifests
11 + checking directory manifests
12 crosschecking files in changesets and manifests
13 checking files
14 4 files, 8 changesets, 4 total revisions
15 @@ -\d+,\d+ \+\d+,\d+ @@ (re)
16 $ hg verify
17 checking changesets
18 checking manifests
19 + checking directory manifests
20 crosschecking files in changesets and manifests
21 checking files
22 5 files, 9 changesets, 5 total revisions
23
24 ERROR: test-narrow-widen.t output changed
25 !
26 Failed test-narrow-widen.t: output changed
27 # Ran 1 tests, 0 skipped, 1 failed.
28 python hash seed: * (glob)
@@ -0,0 +1,355 b''
1 $ . "$TESTDIR/narrow-library.sh"
2
3 $ hg init master
4 $ cd master
5 $ cat >> .hg/hgrc <<EOF
6 > [narrow]
7 > serveellipses=True
8 > EOF
9
10 $ mkdir inside
11 $ echo 'inside' > inside/f
12 $ hg add inside/f
13 $ hg commit -m 'add inside'
14
15 $ mkdir widest
16 $ echo 'widest' > widest/f
17 $ hg add widest/f
18 $ hg commit -m 'add widest'
19
20 $ mkdir outside
21 $ echo 'outside' > outside/f
22 $ hg add outside/f
23 $ hg commit -m 'add outside'
24
25 $ cd ..
26
27 narrow clone the inside file
28
29 $ hg clone --narrow ssh://user@dummy/master narrow --include inside
30 requesting all changes
31 adding changesets
32 adding manifests
33 adding file changes
34 added 2 changesets with 1 changes to 1 files
35 new changesets *:* (glob)
36 updating to branch default
37 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
38 $ cd narrow
39 $ hg tracked
40 I path:inside
41 $ ls
42 inside
43 $ cat inside/f
44 inside
45 $ cd ..
46
47 add more upstream files which we will include in a wider narrow spec
48
49 $ cd master
50
51 $ mkdir wider
52 $ echo 'wider' > wider/f
53 $ hg add wider/f
54 $ echo 'widest v2' > widest/f
55 $ hg commit -m 'add wider, update widest'
56
57 $ echo 'widest v3' > widest/f
58 $ hg commit -m 'update widest v3'
59
60 $ echo 'inside v2' > inside/f
61 $ hg commit -m 'update inside'
62
63 $ mkdir outside2
64 $ echo 'outside2' > outside2/f
65 $ hg add outside2/f
66 $ hg commit -m 'add outside2'
67
68 $ echo 'widest v4' > widest/f
69 $ hg commit -m 'update widest v4'
70
71 $ hg log -T "{if(ellipsis, '...')}{node|short}: {desc}\n"
72 *: update widest v4 (glob)
73 *: add outside2 (glob)
74 *: update inside (glob)
75 *: update widest v3 (glob)
76 *: add wider, update widest (glob)
77 *: add outside (glob)
78 *: add widest (glob)
79 *: add inside (glob)
80
81 $ cd ..
82
83 Widen the narrow spec to see the wider file. This should not get the newly
84 added upstream revisions.
85
86 $ cd narrow
87 $ hg tracked --addinclude wider/f
88 comparing with ssh://user@dummy/master
89 searching for changes
90 no changes found
91 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
92 adding changesets
93 adding manifests
94 adding file changes
95 added 2 changesets with 1 changes to 1 files
96 new changesets *:* (glob)
97 $ hg tracked
98 I path:inside
99 I path:wider/f
100
101 Pull down the newly added upstream revision.
102
103 $ hg pull
104 pulling from ssh://user@dummy/master
105 searching for changes
106 adding changesets
107 adding manifests
108 adding file changes
109 added 4 changesets with 2 changes to 2 files
110 new changesets *:* (glob)
111 (run 'hg update' to get a working copy)
112 $ hg update -r 'desc("add wider")'
113 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
114 $ cat wider/f
115 wider
116
117 $ hg update -r 'desc("update inside")'
118 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
119 $ cat wider/f
120 wider
121 $ cat inside/f
122 inside v2
123
124 $ hg log -T "{if(ellipsis, '...')}{node|short}: {desc}\n"
125 ...*: update widest v4 (glob)
126 *: update inside (glob)
127 ...*: update widest v3 (glob)
128 *: add wider, update widest (glob)
129 ...*: add outside (glob)
130 *: add inside (glob)
131
132 Check that widening with a newline fails
133
134 $ hg tracked --addinclude 'widest
135 > '
136 abort: newlines are not allowed in narrowspec paths
137 [255]
138
139 widen the narrow spec to include the widest file
140
141 $ hg tracked --addinclude widest
142 comparing with ssh://user@dummy/master
143 searching for changes
144 no changes found
145 saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/*-widen.hg (glob)
146 adding changesets
147 adding manifests
148 adding file changes
149 added 8 changesets with 7 changes to 3 files
150 new changesets *:* (glob)
151 $ hg tracked
152 I path:inside
153 I path:wider/f
154 I path:widest
155 $ hg update 'desc("add widest")'
156 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
157 $ cat widest/f
158 widest
159 $ hg update 'desc("add wider, update widest")'
160 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
161 $ cat wider/f
162 wider
163 $ cat widest/f
164 widest v2
165 $ hg update 'desc("update widest v3")'
166 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
167 $ cat widest/f
168 widest v3
169 $ hg update 'desc("update widest v4")'
170 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
171 $ cat widest/f
172 widest v4
173
174 $ hg log -T "{if(ellipsis, '...')}{node|short}: {desc}\n"
175 *: update widest v4 (glob)
176 ...*: add outside2 (glob)
177 *: update inside (glob)
178 *: update widest v3 (glob)
179 *: add wider, update widest (glob)
180 ...*: add outside (glob)
181 *: add widest (glob)
182 *: add inside (glob)
183
184 separate suite of tests: files from 0-10 modified in changes 0-10. This allows
185 more obvious precise tests tickling particular corner cases.
186
187 $ cd ..
188 $ hg init upstream
189 $ cd upstream
190 $ cat >> .hg/hgrc <<EOF
191 > [narrow]
192 > serveellipses=True
193 > EOF
194 $ for x in `$TESTDIR/seq.py 0 10`
195 > do
196 > mkdir d$x
197 > echo $x > d$x/f
198 > hg add d$x/f
199 > hg commit -m "add d$x/f"
200 > done
201 $ hg log -T "{node|short}: {desc}\n"
202 *: add d10/f (glob)
203 *: add d9/f (glob)
204 *: add d8/f (glob)
205 *: add d7/f (glob)
206 *: add d6/f (glob)
207 *: add d5/f (glob)
208 *: add d4/f (glob)
209 *: add d3/f (glob)
210 *: add d2/f (glob)
211 *: add d1/f (glob)
212 *: add d0/f (glob)
213
214 make narrow clone with every third node.
215
216 $ cd ..
217 $ hg clone --narrow ssh://user@dummy/upstream narrow2 --include d0 --include d3 --include d6 --include d9
218 requesting all changes
219 adding changesets
220 adding manifests
221 adding file changes
222 added 8 changesets with 4 changes to 4 files
223 new changesets *:* (glob)
224 updating to branch default
225 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
226 $ cd narrow2
227 $ hg tracked
228 I path:d0
229 I path:d3
230 I path:d6
231 I path:d9
232 $ hg verify
233 checking changesets
234 checking manifests
235 crosschecking files in changesets and manifests
236 checking files
237 4 files, 8 changesets, 4 total revisions
238 $ hg log -T "{if(ellipsis, '...')}{node|short}: {desc}\n"
239 ...*: add d10/f (glob)
240 *: add d9/f (glob)
241 ...*: add d8/f (glob)
242 *: add d6/f (glob)
243 ...*: add d5/f (glob)
244 *: add d3/f (glob)
245 ...*: add d2/f (glob)
246 *: add d0/f (glob)
247 $ hg tracked --addinclude d1
248 comparing with ssh://user@dummy/upstream
249 searching for changes
250 no changes found
251 saved backup bundle to $TESTTMP/narrow2/.hg/strip-backup/*-widen.hg (glob)
252 adding changesets
253 adding manifests
254 adding file changes
255 added 9 changesets with 5 changes to 5 files
256 new changesets *:* (glob)
257 $ hg tracked
258 I path:d0
259 I path:d1
260 I path:d3
261 I path:d6
262 I path:d9
263 $ hg log -T "{if(ellipsis, '...')}{node|short}: {desc}\n"
264 ...*: add d10/f (glob)
265 *: add d9/f (glob)
266 ...*: add d8/f (glob)
267 *: add d6/f (glob)
268 ...*: add d5/f (glob)
269 *: add d3/f (glob)
270 ...*: add d2/f (glob)
271 *: add d1/f (glob)
272 *: add d0/f (glob)
273
274 Verify shouldn't claim the repo is corrupt after a widen.
275
276 $ hg verify
277 checking changesets
278 checking manifests
279 crosschecking files in changesets and manifests
280 checking files
281 5 files, 9 changesets, 5 total revisions
282
283 Widening preserves parent of local commit
284
285 $ cd ..
286 $ hg clone -q --narrow ssh://user@dummy/upstream narrow3 --include d2 -r 2
287 $ cd narrow3
288 $ hg log -T "{if(ellipsis, '...')}{node|short}: {desc}\n"
289 *: add d2/f (glob)
290 ...*: add d1/f (glob)
291 $ hg pull -q -r 3
292 $ hg co -q tip
293 $ hg pull -q -r 4
294 $ echo local > d2/f
295 $ hg ci -m local
296 created new head
297 $ hg tracked -q --addinclude d0 --addinclude d9
298
299 Widening preserves bookmarks
300
301 $ cd ..
302 $ hg clone -q --narrow ssh://user@dummy/upstream narrow-bookmarks --include d4
303 $ cd narrow-bookmarks
304 $ echo local > d4/f
305 $ hg ci -m local
306 $ hg bookmarks bookmark
307 $ hg bookmarks
308 * bookmark 3:* (glob)
309 $ hg -q tracked --addinclude d2
310 $ hg bookmarks
311 * bookmark 5:* (glob)
312 $ hg log -r bookmark -T '{desc}\n'
313 local
314
315 Widening that fails can be recovered from
316
317 $ cd ..
318 $ hg clone -q --narrow ssh://user@dummy/upstream interrupted --include d0
319 $ cd interrupted
320 $ echo local > d0/f
321 $ hg ci -m local
322 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
323 2: local
324 ...1: add d10/f
325 0: add d0/f
326 $ hg bookmarks bookmark
327 $ hg --config hooks.pretxnchangegroup.bad=false tracked --addinclude d1
328 comparing with ssh://user@dummy/upstream
329 searching for changes
330 no changes found
331 saved backup bundle to $TESTTMP/interrupted/.hg/strip-backup/*-widen.hg (glob)
332 adding changesets
333 adding manifests
334 adding file changes
335 added 3 changesets with 2 changes to 2 files
336 transaction abort!
337 rollback completed
338 abort: pretxnchangegroup.bad hook exited with status 1
339 [255]
340 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
341 $ hg bookmarks
342 no bookmarks set
343 $ hg unbundle .hg/strip-backup/*-widen.hg
344 adding changesets
345 adding manifests
346 adding file changes
347 added 3 changesets with 2 changes to 1 files
348 new changesets *:* (glob)
349 (run 'hg update' to get a working copy)
350 $ hg log -T "{if(ellipsis, '...')}{rev}: {desc}\n"
351 2: local
352 ...1: add d10/f
353 0: add d0/f
354 $ hg bookmarks
355 * bookmark 2:* (glob)
@@ -0,0 +1,358 b''
1 $ . "$TESTDIR/narrow-library.sh"
2
3 $ hg init master
4 $ cd master
5 $ cat >> .hg/hgrc <<EOF
6 > [narrow]
7 > serveellipses=True
8 > EOF
9 $ for x in `$TESTDIR/seq.py 0 10`
10 > do
11 > mkdir d$x
12 > echo $x > d$x/f
13 > hg add d$x/f
14 > hg commit -m "add d$x/f"
15 > done
16 $ hg log -T "{node|short}: {desc}\n"
17 *: add d10/f (glob)
18 *: add d9/f (glob)
19 *: add d8/f (glob)
20 *: add d7/f (glob)
21 *: add d6/f (glob)
22 *: add d5/f (glob)
23 *: add d4/f (glob)
24 *: add d3/f (glob)
25 *: add d2/f (glob)
26 *: add d1/f (glob)
27 *: add d0/f (glob)
28 $ cd ..
29
30 Error if '.' or '..' are in the directory to track.
31 $ hg clone --narrow ssh://user@dummy/master foo --include ./asdf
32 requesting all changes
33 abort: "." and ".." are not allowed in narrowspec paths
34 [255]
35 $ hg clone --narrow ssh://user@dummy/master foo --include asdf/..
36 requesting all changes
37 abort: "." and ".." are not allowed in narrowspec paths
38 [255]
39 $ hg clone --narrow ssh://user@dummy/master foo --include a/./c
40 requesting all changes
41 abort: "." and ".." are not allowed in narrowspec paths
42 [255]
43
44 Names with '.' in them are OK.
45 $ hg clone --narrow ssh://user@dummy/master $RANDOM --include a/.b/c
46 requesting all changes
47 adding changesets
48 adding manifests
49 adding file changes
50 added 1 changesets with 0 changes to 0 files
51 new changesets * (glob)
52 updating to branch default
53 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
54
55 Test repo with local changes
56 $ hg clone --narrow ssh://user@dummy/master narrow-local-changes --include d0 --include d3 --include d6
57 requesting all changes
58 adding changesets
59 adding manifests
60 adding file changes
61 added 6 changesets with 3 changes to 3 files
62 new changesets *:* (glob)
63 updating to branch default
64 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 $ cd narrow-local-changes
66 $ cat >> $HGRCPATH << EOF
67 > [experimental]
68 > evolution=createmarkers
69 > EOF
70 $ echo local change >> d0/f
71 $ hg ci -m 'local change to d0'
72 $ hg co '.^'
73 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
74 $ echo local change >> d3/f
75 $ hg ci -m 'local hidden change to d3'
76 created new head
77 $ hg ci --amend -m 'local change to d3'
78 $ hg tracked --removeinclude d0
79 comparing with ssh://user@dummy/master
80 searching for changes
81 looking for local changes to affected paths
82 The following changeset(s) or their ancestors have local changes not on the remote:
83 * (glob)
84 abort: local changes found
85 (use --force-delete-local-changes to ignore)
86 [255]
87 Check that nothing was removed by the failed attempts
88 $ hg tracked
89 I path:d0
90 I path:d3
91 I path:d6
92 $ hg files
93 d0/f
94 d3/f
95 d6/f
96 $ find *
97 d0
98 d0/f
99 d3
100 d3/f
101 d6
102 d6/f
103 $ hg verify -q
104 Force deletion of local changes
105 $ hg log -T "{node|short}: {desc} {outsidenarrow}\n"
106 *: local change to d3 (glob)
107 *: local change to d0 (glob)
108 *: add d10/f outsidenarrow (glob)
109 *: add d6/f (glob)
110 *: add d5/f outsidenarrow (glob)
111 *: add d3/f (glob)
112 *: add d2/f outsidenarrow (glob)
113 *: add d0/f (glob)
114 $ hg tracked --removeinclude d0 --force-delete-local-changes
115 comparing with ssh://user@dummy/master
116 searching for changes
117 looking for local changes to affected paths
118 The following changeset(s) or their ancestors have local changes not on the remote:
119 * (glob)
120 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
121 deleting data/d0/f.i
122 $ hg log -T "{node|short}: {desc} {outsidenarrow}\n"
123 *: local change to d3 (glob)
124 *: add d10/f outsidenarrow (glob)
125 *: add d6/f (glob)
126 *: add d5/f outsidenarrow (glob)
127 *: add d3/f (glob)
128 *: add d2/f outsidenarrow (glob)
129 *: add d0/f outsidenarrow (glob)
130 Can restore stripped local changes after widening
131 $ hg tracked --addinclude d0 -q
132 $ hg unbundle .hg/strip-backup/*-narrow.hg -q
133 $ hg --hidden co -r 'desc("local change to d0")' -q
134 $ cat d0/f
135 0
136 local change
137 Pruned commits affecting removed paths should not prevent narrowing
138 $ hg co '.^'
139 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
140 $ hg debugobsolete `hg log -T '{node}' -r 'desc("local change to d0")'`
141 obsoleted 1 changesets
142 $ hg tracked --removeinclude d0
143 comparing with ssh://user@dummy/master
144 searching for changes
145 looking for local changes to affected paths
146 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
147 deleting data/d0/f.i
148 Updates off of stripped commit if necessary
149 $ hg co -r 'desc("local change to d3")' -q
150 $ echo local change >> d6/f
151 $ hg ci -m 'local change to d6'
152 $ hg tracked --removeinclude d3 --force-delete-local-changes
153 comparing with ssh://user@dummy/master
154 searching for changes
155 looking for local changes to affected paths
156 The following changeset(s) or their ancestors have local changes not on the remote:
157 * (glob)
158 * (glob)
159 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
161 deleting data/d3/f.i
162 $ hg log -T '{desc}\n' -r .
163 add d10/f
164 Updates to nullid if necessary
165 $ hg tracked --addinclude d3 -q
166 $ hg co null -q
167 $ mkdir d3
168 $ echo local change > d3/f
169 $ hg add d3/f
170 $ hg ci -m 'local change to d3'
171 created new head
172 $ hg tracked --removeinclude d3 --force-delete-local-changes
173 comparing with ssh://user@dummy/master
174 searching for changes
175 looking for local changes to affected paths
176 The following changeset(s) or their ancestors have local changes not on the remote:
177 * (glob)
178 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
179 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
180 deleting data/d3/f.i
181 $ hg id
182 000000000000
183 $ cd ..
184
185 Can remove last include, making repo empty
186 $ hg clone --narrow ssh://user@dummy/master narrow-empty --include d0 -r 5
187 adding changesets
188 adding manifests
189 adding file changes
190 added 2 changesets with 1 changes to 1 files
191 new changesets *:* (glob)
192 updating to branch default
193 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
194 $ cd narrow-empty
195 $ hg tracked --removeinclude d0
196 comparing with ssh://user@dummy/master
197 searching for changes
198 looking for local changes to affected paths
199 deleting data/d0/f.i
200 $ hg tracked
201 $ hg files
202 [1]
203 $ test -d d0
204 [1]
205 Do some work in the empty clone
206 $ hg diff --change .
207 $ hg branch foo
208 marked working directory as branch foo
209 (branches are permanent and global, did you want a bookmark?)
210 $ hg ci -m empty
211 $ hg pull -q
212 Can widen the empty clone
213 $ hg tracked --addinclude d0
214 comparing with ssh://user@dummy/master
215 searching for changes
216 no changes found
217 saved backup bundle to $TESTTMP/narrow-empty/.hg/strip-backup/*-widen.hg (glob)
218 adding changesets
219 adding manifests
220 adding file changes
221 added 3 changesets with 1 changes to 1 files
222 new changesets *:* (glob)
223 $ hg tracked
224 I path:d0
225 $ hg files
226 d0/f
227 $ find *
228 d0
229 d0/f
230 $ cd ..
231
232 TODO(martinvonz): test including e.g. d3/g and then removing it once
233 https://bitbucket.org/Google/narrowhg/issues/6 is fixed
234
235 $ hg clone --narrow ssh://user@dummy/master narrow --include d0 --include d3 --include d6 --include d9
236 requesting all changes
237 adding changesets
238 adding manifests
239 adding file changes
240 added 8 changesets with 4 changes to 4 files
241 new changesets *:* (glob)
242 updating to branch default
243 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
244 $ cd narrow
245 $ hg tracked
246 I path:d0
247 I path:d3
248 I path:d6
249 I path:d9
250 $ hg tracked --removeinclude d6
251 comparing with ssh://user@dummy/master
252 searching for changes
253 looking for local changes to affected paths
254 deleting data/d6/f.i
255 $ hg tracked
256 I path:d0
257 I path:d3
258 I path:d9
259 $ hg debugrebuildfncache
260 fncache already up to date
261 $ find *
262 d0
263 d0/f
264 d3
265 d3/f
266 d9
267 d9/f
268 $ hg verify -q
269 $ hg tracked --addexclude d3/f
270 comparing with ssh://user@dummy/master
271 searching for changes
272 looking for local changes to affected paths
273 deleting data/d3/f.i
274 $ hg tracked
275 I path:d0
276 I path:d3
277 I path:d9
278 X path:d3/f
279 $ hg debugrebuildfncache
280 fncache already up to date
281 $ find *
282 d0
283 d0/f
284 d9
285 d9/f
286 $ hg verify -q
287 $ hg tracked --addexclude d0
288 comparing with ssh://user@dummy/master
289 searching for changes
290 looking for local changes to affected paths
291 deleting data/d0/f.i
292 $ hg tracked
293 I path:d3
294 I path:d9
295 X path:d0
296 X path:d3/f
297 $ hg debugrebuildfncache
298 fncache already up to date
299 $ find *
300 d9
301 d9/f
302
303 Make a 15 of changes to d9 to test the path without --verbose
304 (Note: using regexes instead of "* (glob)" because if the test fails, it
305 produces more sensible diffs)
306 $ hg tracked
307 I path:d3
308 I path:d9
309 X path:d0
310 X path:d3/f
311 $ for x in `$TESTDIR/seq.py 1 15`
312 > do
313 > echo local change >> d9/f
314 > hg commit -m "change $x to d9/f"
315 > done
316 $ hg tracked --removeinclude d9
317 comparing with ssh://user@dummy/master
318 searching for changes
319 looking for local changes to affected paths
320 The following changeset(s) or their ancestors have local changes not on the remote:
321 ^[0-9a-f]{12}$ (re)
322 ^[0-9a-f]{12}$ (re)
323 ^[0-9a-f]{12}$ (re)
324 ^[0-9a-f]{12}$ (re)
325 ^[0-9a-f]{12}$ (re)
326 ^[0-9a-f]{12}$ (re)
327 ^[0-9a-f]{12}$ (re)
328 ^[0-9a-f]{12}$ (re)
329 ^[0-9a-f]{12}$ (re)
330 ^[0-9a-f]{12}$ (re)
331 ...and 5 more, use --verbose to list all
332 abort: local changes found
333 (use --force-delete-local-changes to ignore)
334 [255]
335 Now test it *with* verbose.
336 $ hg tracked --removeinclude d9 --verbose
337 comparing with ssh://user@dummy/master
338 searching for changes
339 looking for local changes to affected paths
340 The following changeset(s) or their ancestors have local changes not on the remote:
341 ^[0-9a-f]{12}$ (re)
342 ^[0-9a-f]{12}$ (re)
343 ^[0-9a-f]{12}$ (re)
344 ^[0-9a-f]{12}$ (re)
345 ^[0-9a-f]{12}$ (re)
346 ^[0-9a-f]{12}$ (re)
347 ^[0-9a-f]{12}$ (re)
348 ^[0-9a-f]{12}$ (re)
349 ^[0-9a-f]{12}$ (re)
350 ^[0-9a-f]{12}$ (re)
351 ^[0-9a-f]{12}$ (re)
352 ^[0-9a-f]{12}$ (re)
353 ^[0-9a-f]{12}$ (re)
354 ^[0-9a-f]{12}$ (re)
355 ^[0-9a-f]{12}$ (re)
356 abort: local changes found
357 (use --force-delete-local-changes to ignore)
358 [255]
@@ -1,1034 +1,1035 b''
1 #
1 #
2 # This is the mercurial setup script.
2 # This is the mercurial setup script.
3 #
3 #
4 # 'python setup.py install', or
4 # 'python setup.py install', or
5 # 'python setup.py --help' for more options
5 # 'python setup.py --help' for more options
6
6
7 import os
7 import os
8
8
9 supportedpy = '~= 2.7'
9 supportedpy = '~= 2.7'
10 if os.environ.get('HGALLOWPYTHON3', ''):
10 if os.environ.get('HGALLOWPYTHON3', ''):
11 # Mercurial will never work on Python 3 before 3.5 due to a lack
11 # Mercurial will never work on Python 3 before 3.5 due to a lack
12 # of % formatting on bytestrings, and can't work on 3.6.0 or 3.6.1
12 # of % formatting on bytestrings, and can't work on 3.6.0 or 3.6.1
13 # due to a bug in % formatting in bytestrings.
13 # due to a bug in % formatting in bytestrings.
14 #
14 #
15 # TODO: when we actually work on Python 3, use this string as the
15 # TODO: when we actually work on Python 3, use this string as the
16 # actual supportedpy string.
16 # actual supportedpy string.
17 supportedpy = ','.join([
17 supportedpy = ','.join([
18 '>=2.7',
18 '>=2.7',
19 '!=3.0.*',
19 '!=3.0.*',
20 '!=3.1.*',
20 '!=3.1.*',
21 '!=3.2.*',
21 '!=3.2.*',
22 '!=3.3.*',
22 '!=3.3.*',
23 '!=3.4.*',
23 '!=3.4.*',
24 '!=3.6.0',
24 '!=3.6.0',
25 '!=3.6.1',
25 '!=3.6.1',
26 ])
26 ])
27
27
28 import sys, platform
28 import sys, platform
29 if sys.version_info[0] >= 3:
29 if sys.version_info[0] >= 3:
30 printf = eval('print')
30 printf = eval('print')
31 libdir_escape = 'unicode_escape'
31 libdir_escape = 'unicode_escape'
32 def sysstr(s):
32 def sysstr(s):
33 return s.decode('latin-1')
33 return s.decode('latin-1')
34 else:
34 else:
35 libdir_escape = 'string_escape'
35 libdir_escape = 'string_escape'
36 def printf(*args, **kwargs):
36 def printf(*args, **kwargs):
37 f = kwargs.get('file', sys.stdout)
37 f = kwargs.get('file', sys.stdout)
38 end = kwargs.get('end', '\n')
38 end = kwargs.get('end', '\n')
39 f.write(b' '.join(args) + end)
39 f.write(b' '.join(args) + end)
40 def sysstr(s):
40 def sysstr(s):
41 return s
41 return s
42
42
43 # Attempt to guide users to a modern pip - this means that 2.6 users
43 # Attempt to guide users to a modern pip - this means that 2.6 users
44 # should have a chance of getting a 4.2 release, and when we ratchet
44 # should have a chance of getting a 4.2 release, and when we ratchet
45 # the version requirement forward again hopefully everyone will get
45 # the version requirement forward again hopefully everyone will get
46 # something that works for them.
46 # something that works for them.
47 if sys.version_info < (2, 7, 0, 'final'):
47 if sys.version_info < (2, 7, 0, 'final'):
48 pip_message = ('This may be due to an out of date pip. '
48 pip_message = ('This may be due to an out of date pip. '
49 'Make sure you have pip >= 9.0.1.')
49 'Make sure you have pip >= 9.0.1.')
50 try:
50 try:
51 import pip
51 import pip
52 pip_version = tuple([int(x) for x in pip.__version__.split('.')[:3]])
52 pip_version = tuple([int(x) for x in pip.__version__.split('.')[:3]])
53 if pip_version < (9, 0, 1) :
53 if pip_version < (9, 0, 1) :
54 pip_message = (
54 pip_message = (
55 'Your pip version is out of date, please install '
55 'Your pip version is out of date, please install '
56 'pip >= 9.0.1. pip {} detected.'.format(pip.__version__))
56 'pip >= 9.0.1. pip {} detected.'.format(pip.__version__))
57 else:
57 else:
58 # pip is new enough - it must be something else
58 # pip is new enough - it must be something else
59 pip_message = ''
59 pip_message = ''
60 except Exception:
60 except Exception:
61 pass
61 pass
62 error = """
62 error = """
63 Mercurial does not support Python older than 2.7.
63 Mercurial does not support Python older than 2.7.
64 Python {py} detected.
64 Python {py} detected.
65 {pip}
65 {pip}
66 """.format(py=sys.version_info, pip=pip_message)
66 """.format(py=sys.version_info, pip=pip_message)
67 printf(error, file=sys.stderr)
67 printf(error, file=sys.stderr)
68 sys.exit(1)
68 sys.exit(1)
69
69
70 # Solaris Python packaging brain damage
70 # Solaris Python packaging brain damage
71 try:
71 try:
72 import hashlib
72 import hashlib
73 sha = hashlib.sha1()
73 sha = hashlib.sha1()
74 except ImportError:
74 except ImportError:
75 try:
75 try:
76 import sha
76 import sha
77 sha.sha # silence unused import warning
77 sha.sha # silence unused import warning
78 except ImportError:
78 except ImportError:
79 raise SystemExit(
79 raise SystemExit(
80 "Couldn't import standard hashlib (incomplete Python install).")
80 "Couldn't import standard hashlib (incomplete Python install).")
81
81
82 try:
82 try:
83 import zlib
83 import zlib
84 zlib.compressobj # silence unused import warning
84 zlib.compressobj # silence unused import warning
85 except ImportError:
85 except ImportError:
86 raise SystemExit(
86 raise SystemExit(
87 "Couldn't import standard zlib (incomplete Python install).")
87 "Couldn't import standard zlib (incomplete Python install).")
88
88
89 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
89 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
90 isironpython = False
90 isironpython = False
91 try:
91 try:
92 isironpython = (platform.python_implementation()
92 isironpython = (platform.python_implementation()
93 .lower().find("ironpython") != -1)
93 .lower().find("ironpython") != -1)
94 except AttributeError:
94 except AttributeError:
95 pass
95 pass
96
96
97 if isironpython:
97 if isironpython:
98 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
98 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
99 else:
99 else:
100 try:
100 try:
101 import bz2
101 import bz2
102 bz2.BZ2Compressor # silence unused import warning
102 bz2.BZ2Compressor # silence unused import warning
103 except ImportError:
103 except ImportError:
104 raise SystemExit(
104 raise SystemExit(
105 "Couldn't import standard bz2 (incomplete Python install).")
105 "Couldn't import standard bz2 (incomplete Python install).")
106
106
107 ispypy = "PyPy" in sys.version
107 ispypy = "PyPy" in sys.version
108
108
109 import ctypes
109 import ctypes
110 import stat, subprocess, time
110 import stat, subprocess, time
111 import re
111 import re
112 import shutil
112 import shutil
113 import tempfile
113 import tempfile
114 from distutils import log
114 from distutils import log
115 # We have issues with setuptools on some platforms and builders. Until
115 # We have issues with setuptools on some platforms and builders. Until
116 # those are resolved, setuptools is opt-in except for platforms where
116 # those are resolved, setuptools is opt-in except for platforms where
117 # we don't have issues.
117 # we don't have issues.
118 issetuptools = (os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ)
118 issetuptools = (os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ)
119 if issetuptools:
119 if issetuptools:
120 from setuptools import setup
120 from setuptools import setup
121 else:
121 else:
122 from distutils.core import setup
122 from distutils.core import setup
123 from distutils.ccompiler import new_compiler
123 from distutils.ccompiler import new_compiler
124 from distutils.core import Command, Extension
124 from distutils.core import Command, Extension
125 from distutils.dist import Distribution
125 from distutils.dist import Distribution
126 from distutils.command.build import build
126 from distutils.command.build import build
127 from distutils.command.build_ext import build_ext
127 from distutils.command.build_ext import build_ext
128 from distutils.command.build_py import build_py
128 from distutils.command.build_py import build_py
129 from distutils.command.build_scripts import build_scripts
129 from distutils.command.build_scripts import build_scripts
130 from distutils.command.install import install
130 from distutils.command.install import install
131 from distutils.command.install_lib import install_lib
131 from distutils.command.install_lib import install_lib
132 from distutils.command.install_scripts import install_scripts
132 from distutils.command.install_scripts import install_scripts
133 from distutils.spawn import spawn, find_executable
133 from distutils.spawn import spawn, find_executable
134 from distutils import file_util
134 from distutils import file_util
135 from distutils.errors import (
135 from distutils.errors import (
136 CCompilerError,
136 CCompilerError,
137 DistutilsError,
137 DistutilsError,
138 DistutilsExecError,
138 DistutilsExecError,
139 )
139 )
140 from distutils.sysconfig import get_python_inc, get_config_var
140 from distutils.sysconfig import get_python_inc, get_config_var
141 from distutils.version import StrictVersion
141 from distutils.version import StrictVersion
142
142
143 def write_if_changed(path, content):
143 def write_if_changed(path, content):
144 """Write content to a file iff the content hasn't changed."""
144 """Write content to a file iff the content hasn't changed."""
145 if os.path.exists(path):
145 if os.path.exists(path):
146 with open(path, 'rb') as fh:
146 with open(path, 'rb') as fh:
147 current = fh.read()
147 current = fh.read()
148 else:
148 else:
149 current = b''
149 current = b''
150
150
151 if current != content:
151 if current != content:
152 with open(path, 'wb') as fh:
152 with open(path, 'wb') as fh:
153 fh.write(content)
153 fh.write(content)
154
154
155 scripts = ['hg']
155 scripts = ['hg']
156 if os.name == 'nt':
156 if os.name == 'nt':
157 # We remove hg.bat if we are able to build hg.exe.
157 # We remove hg.bat if we are able to build hg.exe.
158 scripts.append('contrib/win32/hg.bat')
158 scripts.append('contrib/win32/hg.bat')
159
159
160 def cancompile(cc, code):
160 def cancompile(cc, code):
161 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
161 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
162 devnull = oldstderr = None
162 devnull = oldstderr = None
163 try:
163 try:
164 fname = os.path.join(tmpdir, 'testcomp.c')
164 fname = os.path.join(tmpdir, 'testcomp.c')
165 f = open(fname, 'w')
165 f = open(fname, 'w')
166 f.write(code)
166 f.write(code)
167 f.close()
167 f.close()
168 # Redirect stderr to /dev/null to hide any error messages
168 # Redirect stderr to /dev/null to hide any error messages
169 # from the compiler.
169 # from the compiler.
170 # This will have to be changed if we ever have to check
170 # This will have to be changed if we ever have to check
171 # for a function on Windows.
171 # for a function on Windows.
172 devnull = open('/dev/null', 'w')
172 devnull = open('/dev/null', 'w')
173 oldstderr = os.dup(sys.stderr.fileno())
173 oldstderr = os.dup(sys.stderr.fileno())
174 os.dup2(devnull.fileno(), sys.stderr.fileno())
174 os.dup2(devnull.fileno(), sys.stderr.fileno())
175 objects = cc.compile([fname], output_dir=tmpdir)
175 objects = cc.compile([fname], output_dir=tmpdir)
176 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
176 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
177 return True
177 return True
178 except Exception:
178 except Exception:
179 return False
179 return False
180 finally:
180 finally:
181 if oldstderr is not None:
181 if oldstderr is not None:
182 os.dup2(oldstderr, sys.stderr.fileno())
182 os.dup2(oldstderr, sys.stderr.fileno())
183 if devnull is not None:
183 if devnull is not None:
184 devnull.close()
184 devnull.close()
185 shutil.rmtree(tmpdir)
185 shutil.rmtree(tmpdir)
186
186
187 # simplified version of distutils.ccompiler.CCompiler.has_function
187 # simplified version of distutils.ccompiler.CCompiler.has_function
188 # that actually removes its temporary files.
188 # that actually removes its temporary files.
189 def hasfunction(cc, funcname):
189 def hasfunction(cc, funcname):
190 code = 'int main(void) { %s(); }\n' % funcname
190 code = 'int main(void) { %s(); }\n' % funcname
191 return cancompile(cc, code)
191 return cancompile(cc, code)
192
192
193 def hasheader(cc, headername):
193 def hasheader(cc, headername):
194 code = '#include <%s>\nint main(void) { return 0; }\n' % headername
194 code = '#include <%s>\nint main(void) { return 0; }\n' % headername
195 return cancompile(cc, code)
195 return cancompile(cc, code)
196
196
197 # py2exe needs to be installed to work
197 # py2exe needs to be installed to work
198 try:
198 try:
199 import py2exe
199 import py2exe
200 py2exe.Distribution # silence unused import warning
200 py2exe.Distribution # silence unused import warning
201 py2exeloaded = True
201 py2exeloaded = True
202 # import py2exe's patched Distribution class
202 # import py2exe's patched Distribution class
203 from distutils.core import Distribution
203 from distutils.core import Distribution
204 except ImportError:
204 except ImportError:
205 py2exeloaded = False
205 py2exeloaded = False
206
206
207 def runcmd(cmd, env):
207 def runcmd(cmd, env):
208 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
208 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
209 stderr=subprocess.PIPE, env=env)
209 stderr=subprocess.PIPE, env=env)
210 out, err = p.communicate()
210 out, err = p.communicate()
211 return p.returncode, out, err
211 return p.returncode, out, err
212
212
213 class hgcommand(object):
213 class hgcommand(object):
214 def __init__(self, cmd, env):
214 def __init__(self, cmd, env):
215 self.cmd = cmd
215 self.cmd = cmd
216 self.env = env
216 self.env = env
217
217
218 def run(self, args):
218 def run(self, args):
219 cmd = self.cmd + args
219 cmd = self.cmd + args
220 returncode, out, err = runcmd(cmd, self.env)
220 returncode, out, err = runcmd(cmd, self.env)
221 err = filterhgerr(err)
221 err = filterhgerr(err)
222 if err or returncode != 0:
222 if err or returncode != 0:
223 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
223 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
224 printf(err, file=sys.stderr)
224 printf(err, file=sys.stderr)
225 return ''
225 return ''
226 return out
226 return out
227
227
228 def filterhgerr(err):
228 def filterhgerr(err):
229 # If root is executing setup.py, but the repository is owned by
229 # If root is executing setup.py, but the repository is owned by
230 # another user (as in "sudo python setup.py install") we will get
230 # another user (as in "sudo python setup.py install") we will get
231 # trust warnings since the .hg/hgrc file is untrusted. That is
231 # trust warnings since the .hg/hgrc file is untrusted. That is
232 # fine, we don't want to load it anyway. Python may warn about
232 # fine, we don't want to load it anyway. Python may warn about
233 # a missing __init__.py in mercurial/locale, we also ignore that.
233 # a missing __init__.py in mercurial/locale, we also ignore that.
234 err = [e for e in err.splitlines()
234 err = [e for e in err.splitlines()
235 if (not e.startswith(b'not trusting file')
235 if (not e.startswith(b'not trusting file')
236 and not e.startswith(b'warning: Not importing')
236 and not e.startswith(b'warning: Not importing')
237 and not e.startswith(b'obsolete feature not enabled')
237 and not e.startswith(b'obsolete feature not enabled')
238 and not e.startswith(b'devel-warn:'))]
238 and not e.startswith(b'devel-warn:'))]
239 return b'\n'.join(b' ' + e for e in err)
239 return b'\n'.join(b' ' + e for e in err)
240
240
241 def findhg():
241 def findhg():
242 """Try to figure out how we should invoke hg for examining the local
242 """Try to figure out how we should invoke hg for examining the local
243 repository contents.
243 repository contents.
244
244
245 Returns an hgcommand object."""
245 Returns an hgcommand object."""
246 # By default, prefer the "hg" command in the user's path. This was
246 # By default, prefer the "hg" command in the user's path. This was
247 # presumably the hg command that the user used to create this repository.
247 # presumably the hg command that the user used to create this repository.
248 #
248 #
249 # This repository may require extensions or other settings that would not
249 # This repository may require extensions or other settings that would not
250 # be enabled by running the hg script directly from this local repository.
250 # be enabled by running the hg script directly from this local repository.
251 hgenv = os.environ.copy()
251 hgenv = os.environ.copy()
252 # Use HGPLAIN to disable hgrc settings that would change output formatting,
252 # Use HGPLAIN to disable hgrc settings that would change output formatting,
253 # and disable localization for the same reasons.
253 # and disable localization for the same reasons.
254 hgenv['HGPLAIN'] = '1'
254 hgenv['HGPLAIN'] = '1'
255 hgenv['LANGUAGE'] = 'C'
255 hgenv['LANGUAGE'] = 'C'
256 hgcmd = ['hg']
256 hgcmd = ['hg']
257 # Run a simple "hg log" command just to see if using hg from the user's
257 # Run a simple "hg log" command just to see if using hg from the user's
258 # path works and can successfully interact with this repository.
258 # path works and can successfully interact with this repository.
259 check_cmd = ['log', '-r.', '-Ttest']
259 check_cmd = ['log', '-r.', '-Ttest']
260 try:
260 try:
261 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
261 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
262 except EnvironmentError:
262 except EnvironmentError:
263 retcode = -1
263 retcode = -1
264 if retcode == 0 and not filterhgerr(err):
264 if retcode == 0 and not filterhgerr(err):
265 return hgcommand(hgcmd, hgenv)
265 return hgcommand(hgcmd, hgenv)
266
266
267 # Fall back to trying the local hg installation.
267 # Fall back to trying the local hg installation.
268 hgenv = localhgenv()
268 hgenv = localhgenv()
269 hgcmd = [sys.executable, 'hg']
269 hgcmd = [sys.executable, 'hg']
270 try:
270 try:
271 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
271 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
272 except EnvironmentError:
272 except EnvironmentError:
273 retcode = -1
273 retcode = -1
274 if retcode == 0 and not filterhgerr(err):
274 if retcode == 0 and not filterhgerr(err):
275 return hgcommand(hgcmd, hgenv)
275 return hgcommand(hgcmd, hgenv)
276
276
277 raise SystemExit('Unable to find a working hg binary to extract the '
277 raise SystemExit('Unable to find a working hg binary to extract the '
278 'version from the repository tags')
278 'version from the repository tags')
279
279
280 def localhgenv():
280 def localhgenv():
281 """Get an environment dictionary to use for invoking or importing
281 """Get an environment dictionary to use for invoking or importing
282 mercurial from the local repository."""
282 mercurial from the local repository."""
283 # Execute hg out of this directory with a custom environment which takes
283 # Execute hg out of this directory with a custom environment which takes
284 # care to not use any hgrc files and do no localization.
284 # care to not use any hgrc files and do no localization.
285 env = {'HGMODULEPOLICY': 'py',
285 env = {'HGMODULEPOLICY': 'py',
286 'HGRCPATH': '',
286 'HGRCPATH': '',
287 'LANGUAGE': 'C',
287 'LANGUAGE': 'C',
288 'PATH': ''} # make pypi modules that use os.environ['PATH'] happy
288 'PATH': ''} # make pypi modules that use os.environ['PATH'] happy
289 if 'LD_LIBRARY_PATH' in os.environ:
289 if 'LD_LIBRARY_PATH' in os.environ:
290 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
290 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
291 if 'SystemRoot' in os.environ:
291 if 'SystemRoot' in os.environ:
292 # SystemRoot is required by Windows to load various DLLs. See:
292 # SystemRoot is required by Windows to load various DLLs. See:
293 # https://bugs.python.org/issue13524#msg148850
293 # https://bugs.python.org/issue13524#msg148850
294 env['SystemRoot'] = os.environ['SystemRoot']
294 env['SystemRoot'] = os.environ['SystemRoot']
295 return env
295 return env
296
296
297 version = ''
297 version = ''
298
298
299 if os.path.isdir('.hg'):
299 if os.path.isdir('.hg'):
300 hg = findhg()
300 hg = findhg()
301 cmd = ['log', '-r', '.', '--template', '{tags}\n']
301 cmd = ['log', '-r', '.', '--template', '{tags}\n']
302 numerictags = [t for t in sysstr(hg.run(cmd)).split() if t[0:1].isdigit()]
302 numerictags = [t for t in sysstr(hg.run(cmd)).split() if t[0:1].isdigit()]
303 hgid = sysstr(hg.run(['id', '-i'])).strip()
303 hgid = sysstr(hg.run(['id', '-i'])).strip()
304 if not hgid:
304 if not hgid:
305 # Bail out if hg is having problems interacting with this repository,
305 # Bail out if hg is having problems interacting with this repository,
306 # rather than falling through and producing a bogus version number.
306 # rather than falling through and producing a bogus version number.
307 # Continuing with an invalid version number will break extensions
307 # Continuing with an invalid version number will break extensions
308 # that define minimumhgversion.
308 # that define minimumhgversion.
309 raise SystemExit('Unable to determine hg version from local repository')
309 raise SystemExit('Unable to determine hg version from local repository')
310 if numerictags: # tag(s) found
310 if numerictags: # tag(s) found
311 version = numerictags[-1]
311 version = numerictags[-1]
312 if hgid.endswith('+'): # propagate the dirty status to the tag
312 if hgid.endswith('+'): # propagate the dirty status to the tag
313 version += '+'
313 version += '+'
314 else: # no tag found
314 else: # no tag found
315 ltagcmd = ['parents', '--template', '{latesttag}']
315 ltagcmd = ['parents', '--template', '{latesttag}']
316 ltag = sysstr(hg.run(ltagcmd))
316 ltag = sysstr(hg.run(ltagcmd))
317 changessincecmd = ['log', '-T', 'x\n', '-r', "only(.,'%s')" % ltag]
317 changessincecmd = ['log', '-T', 'x\n', '-r', "only(.,'%s')" % ltag]
318 changessince = len(hg.run(changessincecmd).splitlines())
318 changessince = len(hg.run(changessincecmd).splitlines())
319 version = '%s+%s-%s' % (ltag, changessince, hgid)
319 version = '%s+%s-%s' % (ltag, changessince, hgid)
320 if version.endswith('+'):
320 if version.endswith('+'):
321 version += time.strftime('%Y%m%d')
321 version += time.strftime('%Y%m%d')
322 elif os.path.exists('.hg_archival.txt'):
322 elif os.path.exists('.hg_archival.txt'):
323 kw = dict([[t.strip() for t in l.split(':', 1)]
323 kw = dict([[t.strip() for t in l.split(':', 1)]
324 for l in open('.hg_archival.txt')])
324 for l in open('.hg_archival.txt')])
325 if 'tag' in kw:
325 if 'tag' in kw:
326 version = kw['tag']
326 version = kw['tag']
327 elif 'latesttag' in kw:
327 elif 'latesttag' in kw:
328 if 'changessincelatesttag' in kw:
328 if 'changessincelatesttag' in kw:
329 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
329 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
330 else:
330 else:
331 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
331 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
332 else:
332 else:
333 version = kw.get('node', '')[:12]
333 version = kw.get('node', '')[:12]
334
334
335 if version:
335 if version:
336 versionb = version
336 versionb = version
337 if not isinstance(versionb, bytes):
337 if not isinstance(versionb, bytes):
338 versionb = versionb.encode('ascii')
338 versionb = versionb.encode('ascii')
339
339
340 write_if_changed('mercurial/__version__.py', b''.join([
340 write_if_changed('mercurial/__version__.py', b''.join([
341 b'# this file is autogenerated by setup.py\n'
341 b'# this file is autogenerated by setup.py\n'
342 b'version = "%s"\n' % versionb,
342 b'version = "%s"\n' % versionb,
343 ]))
343 ]))
344
344
345 try:
345 try:
346 oldpolicy = os.environ.get('HGMODULEPOLICY', None)
346 oldpolicy = os.environ.get('HGMODULEPOLICY', None)
347 os.environ['HGMODULEPOLICY'] = 'py'
347 os.environ['HGMODULEPOLICY'] = 'py'
348 from mercurial import __version__
348 from mercurial import __version__
349 version = __version__.version
349 version = __version__.version
350 except ImportError:
350 except ImportError:
351 version = 'unknown'
351 version = 'unknown'
352 finally:
352 finally:
353 if oldpolicy is None:
353 if oldpolicy is None:
354 del os.environ['HGMODULEPOLICY']
354 del os.environ['HGMODULEPOLICY']
355 else:
355 else:
356 os.environ['HGMODULEPOLICY'] = oldpolicy
356 os.environ['HGMODULEPOLICY'] = oldpolicy
357
357
358 class hgbuild(build):
358 class hgbuild(build):
359 # Insert hgbuildmo first so that files in mercurial/locale/ are found
359 # Insert hgbuildmo first so that files in mercurial/locale/ are found
360 # when build_py is run next.
360 # when build_py is run next.
361 sub_commands = [('build_mo', None)] + build.sub_commands
361 sub_commands = [('build_mo', None)] + build.sub_commands
362
362
363 class hgbuildmo(build):
363 class hgbuildmo(build):
364
364
365 description = "build translations (.mo files)"
365 description = "build translations (.mo files)"
366
366
367 def run(self):
367 def run(self):
368 if not find_executable('msgfmt'):
368 if not find_executable('msgfmt'):
369 self.warn("could not find msgfmt executable, no translations "
369 self.warn("could not find msgfmt executable, no translations "
370 "will be built")
370 "will be built")
371 return
371 return
372
372
373 podir = 'i18n'
373 podir = 'i18n'
374 if not os.path.isdir(podir):
374 if not os.path.isdir(podir):
375 self.warn("could not find %s/ directory" % podir)
375 self.warn("could not find %s/ directory" % podir)
376 return
376 return
377
377
378 join = os.path.join
378 join = os.path.join
379 for po in os.listdir(podir):
379 for po in os.listdir(podir):
380 if not po.endswith('.po'):
380 if not po.endswith('.po'):
381 continue
381 continue
382 pofile = join(podir, po)
382 pofile = join(podir, po)
383 modir = join('locale', po[:-3], 'LC_MESSAGES')
383 modir = join('locale', po[:-3], 'LC_MESSAGES')
384 mofile = join(modir, 'hg.mo')
384 mofile = join(modir, 'hg.mo')
385 mobuildfile = join('mercurial', mofile)
385 mobuildfile = join('mercurial', mofile)
386 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
386 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
387 if sys.platform != 'sunos5':
387 if sys.platform != 'sunos5':
388 # msgfmt on Solaris does not know about -c
388 # msgfmt on Solaris does not know about -c
389 cmd.append('-c')
389 cmd.append('-c')
390 self.mkpath(join('mercurial', modir))
390 self.mkpath(join('mercurial', modir))
391 self.make_file([pofile], mobuildfile, spawn, (cmd,))
391 self.make_file([pofile], mobuildfile, spawn, (cmd,))
392
392
393
393
394 class hgdist(Distribution):
394 class hgdist(Distribution):
395 pure = False
395 pure = False
396 cffi = ispypy
396 cffi = ispypy
397
397
398 global_options = Distribution.global_options + \
398 global_options = Distribution.global_options + \
399 [('pure', None, "use pure (slow) Python "
399 [('pure', None, "use pure (slow) Python "
400 "code instead of C extensions"),
400 "code instead of C extensions"),
401 ]
401 ]
402
402
403 def has_ext_modules(self):
403 def has_ext_modules(self):
404 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
404 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
405 # too late for some cases
405 # too late for some cases
406 return not self.pure and Distribution.has_ext_modules(self)
406 return not self.pure and Distribution.has_ext_modules(self)
407
407
408 # This is ugly as a one-liner. So use a variable.
408 # This is ugly as a one-liner. So use a variable.
409 buildextnegops = dict(getattr(build_ext, 'negative_options', {}))
409 buildextnegops = dict(getattr(build_ext, 'negative_options', {}))
410 buildextnegops['no-zstd'] = 'zstd'
410 buildextnegops['no-zstd'] = 'zstd'
411
411
412 class hgbuildext(build_ext):
412 class hgbuildext(build_ext):
413 user_options = build_ext.user_options + [
413 user_options = build_ext.user_options + [
414 ('zstd', None, 'compile zstd bindings [default]'),
414 ('zstd', None, 'compile zstd bindings [default]'),
415 ('no-zstd', None, 'do not compile zstd bindings'),
415 ('no-zstd', None, 'do not compile zstd bindings'),
416 ]
416 ]
417
417
418 boolean_options = build_ext.boolean_options + ['zstd']
418 boolean_options = build_ext.boolean_options + ['zstd']
419 negative_opt = buildextnegops
419 negative_opt = buildextnegops
420
420
421 def initialize_options(self):
421 def initialize_options(self):
422 self.zstd = True
422 self.zstd = True
423 return build_ext.initialize_options(self)
423 return build_ext.initialize_options(self)
424
424
425 def build_extensions(self):
425 def build_extensions(self):
426 # Filter out zstd if disabled via argument.
426 # Filter out zstd if disabled via argument.
427 if not self.zstd:
427 if not self.zstd:
428 self.extensions = [e for e in self.extensions
428 self.extensions = [e for e in self.extensions
429 if e.name != 'mercurial.zstd']
429 if e.name != 'mercurial.zstd']
430
430
431 return build_ext.build_extensions(self)
431 return build_ext.build_extensions(self)
432
432
433 def build_extension(self, ext):
433 def build_extension(self, ext):
434 try:
434 try:
435 build_ext.build_extension(self, ext)
435 build_ext.build_extension(self, ext)
436 except CCompilerError:
436 except CCompilerError:
437 if not getattr(ext, 'optional', False):
437 if not getattr(ext, 'optional', False):
438 raise
438 raise
439 log.warn("Failed to build optional extension '%s' (skipping)",
439 log.warn("Failed to build optional extension '%s' (skipping)",
440 ext.name)
440 ext.name)
441
441
442 class hgbuildscripts(build_scripts):
442 class hgbuildscripts(build_scripts):
443 def run(self):
443 def run(self):
444 if os.name != 'nt' or self.distribution.pure:
444 if os.name != 'nt' or self.distribution.pure:
445 return build_scripts.run(self)
445 return build_scripts.run(self)
446
446
447 exebuilt = False
447 exebuilt = False
448 try:
448 try:
449 self.run_command('build_hgexe')
449 self.run_command('build_hgexe')
450 exebuilt = True
450 exebuilt = True
451 except (DistutilsError, CCompilerError):
451 except (DistutilsError, CCompilerError):
452 log.warn('failed to build optional hg.exe')
452 log.warn('failed to build optional hg.exe')
453
453
454 if exebuilt:
454 if exebuilt:
455 # Copying hg.exe to the scripts build directory ensures it is
455 # Copying hg.exe to the scripts build directory ensures it is
456 # installed by the install_scripts command.
456 # installed by the install_scripts command.
457 hgexecommand = self.get_finalized_command('build_hgexe')
457 hgexecommand = self.get_finalized_command('build_hgexe')
458 dest = os.path.join(self.build_dir, 'hg.exe')
458 dest = os.path.join(self.build_dir, 'hg.exe')
459 self.mkpath(self.build_dir)
459 self.mkpath(self.build_dir)
460 self.copy_file(hgexecommand.hgexepath, dest)
460 self.copy_file(hgexecommand.hgexepath, dest)
461
461
462 # Remove hg.bat because it is redundant with hg.exe.
462 # Remove hg.bat because it is redundant with hg.exe.
463 self.scripts.remove('contrib/win32/hg.bat')
463 self.scripts.remove('contrib/win32/hg.bat')
464
464
465 return build_scripts.run(self)
465 return build_scripts.run(self)
466
466
467 class hgbuildpy(build_py):
467 class hgbuildpy(build_py):
468 def finalize_options(self):
468 def finalize_options(self):
469 build_py.finalize_options(self)
469 build_py.finalize_options(self)
470
470
471 if self.distribution.pure:
471 if self.distribution.pure:
472 self.distribution.ext_modules = []
472 self.distribution.ext_modules = []
473 elif self.distribution.cffi:
473 elif self.distribution.cffi:
474 from mercurial.cffi import (
474 from mercurial.cffi import (
475 bdiffbuild,
475 bdiffbuild,
476 mpatchbuild,
476 mpatchbuild,
477 )
477 )
478 exts = [mpatchbuild.ffi.distutils_extension(),
478 exts = [mpatchbuild.ffi.distutils_extension(),
479 bdiffbuild.ffi.distutils_extension()]
479 bdiffbuild.ffi.distutils_extension()]
480 # cffi modules go here
480 # cffi modules go here
481 if sys.platform == 'darwin':
481 if sys.platform == 'darwin':
482 from mercurial.cffi import osutilbuild
482 from mercurial.cffi import osutilbuild
483 exts.append(osutilbuild.ffi.distutils_extension())
483 exts.append(osutilbuild.ffi.distutils_extension())
484 self.distribution.ext_modules = exts
484 self.distribution.ext_modules = exts
485 else:
485 else:
486 h = os.path.join(get_python_inc(), 'Python.h')
486 h = os.path.join(get_python_inc(), 'Python.h')
487 if not os.path.exists(h):
487 if not os.path.exists(h):
488 raise SystemExit('Python headers are required to build '
488 raise SystemExit('Python headers are required to build '
489 'Mercurial but weren\'t found in %s' % h)
489 'Mercurial but weren\'t found in %s' % h)
490
490
491 def run(self):
491 def run(self):
492 basepath = os.path.join(self.build_lib, 'mercurial')
492 basepath = os.path.join(self.build_lib, 'mercurial')
493 self.mkpath(basepath)
493 self.mkpath(basepath)
494
494
495 if self.distribution.pure:
495 if self.distribution.pure:
496 modulepolicy = 'py'
496 modulepolicy = 'py'
497 elif self.build_lib == '.':
497 elif self.build_lib == '.':
498 # in-place build should run without rebuilding C extensions
498 # in-place build should run without rebuilding C extensions
499 modulepolicy = 'allow'
499 modulepolicy = 'allow'
500 else:
500 else:
501 modulepolicy = 'c'
501 modulepolicy = 'c'
502
502
503 content = b''.join([
503 content = b''.join([
504 b'# this file is autogenerated by setup.py\n',
504 b'# this file is autogenerated by setup.py\n',
505 b'modulepolicy = b"%s"\n' % modulepolicy.encode('ascii'),
505 b'modulepolicy = b"%s"\n' % modulepolicy.encode('ascii'),
506 ])
506 ])
507 write_if_changed(os.path.join(basepath, '__modulepolicy__.py'),
507 write_if_changed(os.path.join(basepath, '__modulepolicy__.py'),
508 content)
508 content)
509
509
510 build_py.run(self)
510 build_py.run(self)
511
511
512 class buildhgextindex(Command):
512 class buildhgextindex(Command):
513 description = 'generate prebuilt index of hgext (for frozen package)'
513 description = 'generate prebuilt index of hgext (for frozen package)'
514 user_options = []
514 user_options = []
515 _indexfilename = 'hgext/__index__.py'
515 _indexfilename = 'hgext/__index__.py'
516
516
517 def initialize_options(self):
517 def initialize_options(self):
518 pass
518 pass
519
519
520 def finalize_options(self):
520 def finalize_options(self):
521 pass
521 pass
522
522
523 def run(self):
523 def run(self):
524 if os.path.exists(self._indexfilename):
524 if os.path.exists(self._indexfilename):
525 with open(self._indexfilename, 'w') as f:
525 with open(self._indexfilename, 'w') as f:
526 f.write('# empty\n')
526 f.write('# empty\n')
527
527
528 # here no extension enabled, disabled() lists up everything
528 # here no extension enabled, disabled() lists up everything
529 code = ('import pprint; from mercurial import extensions; '
529 code = ('import pprint; from mercurial import extensions; '
530 'pprint.pprint(extensions.disabled())')
530 'pprint.pprint(extensions.disabled())')
531 returncode, out, err = runcmd([sys.executable, '-c', code],
531 returncode, out, err = runcmd([sys.executable, '-c', code],
532 localhgenv())
532 localhgenv())
533 if err or returncode != 0:
533 if err or returncode != 0:
534 raise DistutilsExecError(err)
534 raise DistutilsExecError(err)
535
535
536 with open(self._indexfilename, 'w') as f:
536 with open(self._indexfilename, 'w') as f:
537 f.write('# this file is autogenerated by setup.py\n')
537 f.write('# this file is autogenerated by setup.py\n')
538 f.write('docs = ')
538 f.write('docs = ')
539 f.write(out)
539 f.write(out)
540
540
541 class buildhgexe(build_ext):
541 class buildhgexe(build_ext):
542 description = 'compile hg.exe from mercurial/exewrapper.c'
542 description = 'compile hg.exe from mercurial/exewrapper.c'
543 user_options = build_ext.user_options + [
543 user_options = build_ext.user_options + [
544 ('long-paths-support', None, 'enable support for long paths on '
544 ('long-paths-support', None, 'enable support for long paths on '
545 'Windows (off by default and '
545 'Windows (off by default and '
546 'experimental)'),
546 'experimental)'),
547 ]
547 ]
548
548
549 LONG_PATHS_MANIFEST = """
549 LONG_PATHS_MANIFEST = """
550 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
550 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
551 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
551 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
552 <application>
552 <application>
553 <windowsSettings
553 <windowsSettings
554 xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
554 xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
555 <ws2:longPathAware>true</ws2:longPathAware>
555 <ws2:longPathAware>true</ws2:longPathAware>
556 </windowsSettings>
556 </windowsSettings>
557 </application>
557 </application>
558 </assembly>"""
558 </assembly>"""
559
559
560 def initialize_options(self):
560 def initialize_options(self):
561 build_ext.initialize_options(self)
561 build_ext.initialize_options(self)
562 self.long_paths_support = False
562 self.long_paths_support = False
563
563
564 def build_extensions(self):
564 def build_extensions(self):
565 if os.name != 'nt':
565 if os.name != 'nt':
566 return
566 return
567 if isinstance(self.compiler, HackedMingw32CCompiler):
567 if isinstance(self.compiler, HackedMingw32CCompiler):
568 self.compiler.compiler_so = self.compiler.compiler # no -mdll
568 self.compiler.compiler_so = self.compiler.compiler # no -mdll
569 self.compiler.dll_libraries = [] # no -lmsrvc90
569 self.compiler.dll_libraries = [] # no -lmsrvc90
570
570
571 # Different Python installs can have different Python library
571 # Different Python installs can have different Python library
572 # names. e.g. the official CPython distribution uses pythonXY.dll
572 # names. e.g. the official CPython distribution uses pythonXY.dll
573 # and MinGW uses libpythonX.Y.dll.
573 # and MinGW uses libpythonX.Y.dll.
574 _kernel32 = ctypes.windll.kernel32
574 _kernel32 = ctypes.windll.kernel32
575 _kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p,
575 _kernel32.GetModuleFileNameA.argtypes = [ctypes.c_void_p,
576 ctypes.c_void_p,
576 ctypes.c_void_p,
577 ctypes.c_ulong]
577 ctypes.c_ulong]
578 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
578 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
579 size = 1000
579 size = 1000
580 buf = ctypes.create_string_buffer(size + 1)
580 buf = ctypes.create_string_buffer(size + 1)
581 filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf),
581 filelen = _kernel32.GetModuleFileNameA(sys.dllhandle, ctypes.byref(buf),
582 size)
582 size)
583
583
584 if filelen > 0 and filelen != size:
584 if filelen > 0 and filelen != size:
585 dllbasename = os.path.basename(buf.value)
585 dllbasename = os.path.basename(buf.value)
586 if not dllbasename.lower().endswith('.dll'):
586 if not dllbasename.lower().endswith('.dll'):
587 raise SystemExit('Python DLL does not end with .dll: %s' %
587 raise SystemExit('Python DLL does not end with .dll: %s' %
588 dllbasename)
588 dllbasename)
589 pythonlib = dllbasename[:-4]
589 pythonlib = dllbasename[:-4]
590 else:
590 else:
591 log.warn('could not determine Python DLL filename; '
591 log.warn('could not determine Python DLL filename; '
592 'assuming pythonXY')
592 'assuming pythonXY')
593
593
594 hv = sys.hexversion
594 hv = sys.hexversion
595 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
595 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
596
596
597 log.info('using %s as Python library name' % pythonlib)
597 log.info('using %s as Python library name' % pythonlib)
598 with open('mercurial/hgpythonlib.h', 'wb') as f:
598 with open('mercurial/hgpythonlib.h', 'wb') as f:
599 f.write('/* this file is autogenerated by setup.py */\n')
599 f.write('/* this file is autogenerated by setup.py */\n')
600 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
600 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
601 objects = self.compiler.compile(['mercurial/exewrapper.c'],
601 objects = self.compiler.compile(['mercurial/exewrapper.c'],
602 output_dir=self.build_temp)
602 output_dir=self.build_temp)
603 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
603 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
604 self.hgtarget = os.path.join(dir, 'hg')
604 self.hgtarget = os.path.join(dir, 'hg')
605 self.compiler.link_executable(objects, self.hgtarget,
605 self.compiler.link_executable(objects, self.hgtarget,
606 libraries=[],
606 libraries=[],
607 output_dir=self.build_temp)
607 output_dir=self.build_temp)
608 if self.long_paths_support:
608 if self.long_paths_support:
609 self.addlongpathsmanifest()
609 self.addlongpathsmanifest()
610
610
611 def addlongpathsmanifest(self):
611 def addlongpathsmanifest(self):
612 """Add manifest pieces so that hg.exe understands long paths
612 """Add manifest pieces so that hg.exe understands long paths
613
613
614 This is an EXPERIMENTAL feature, use with care.
614 This is an EXPERIMENTAL feature, use with care.
615 To enable long paths support, one needs to do two things:
615 To enable long paths support, one needs to do two things:
616 - build Mercurial with --long-paths-support option
616 - build Mercurial with --long-paths-support option
617 - change HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\
617 - change HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\
618 LongPathsEnabled to have value 1.
618 LongPathsEnabled to have value 1.
619
619
620 Please ignore 'warning 81010002: Unrecognized Element "longPathAware"';
620 Please ignore 'warning 81010002: Unrecognized Element "longPathAware"';
621 it happens because Mercurial uses mt.exe circa 2008, which is not
621 it happens because Mercurial uses mt.exe circa 2008, which is not
622 yet aware of long paths support in the manifest (I think so at least).
622 yet aware of long paths support in the manifest (I think so at least).
623 This does not stop mt.exe from embedding/merging the XML properly.
623 This does not stop mt.exe from embedding/merging the XML properly.
624
624
625 Why resource #1 should be used for .exe manifests? I don't know and
625 Why resource #1 should be used for .exe manifests? I don't know and
626 wasn't able to find an explanation for mortals. But it seems to work.
626 wasn't able to find an explanation for mortals. But it seems to work.
627 """
627 """
628 exefname = self.compiler.executable_filename(self.hgtarget)
628 exefname = self.compiler.executable_filename(self.hgtarget)
629 fdauto, manfname = tempfile.mkstemp(suffix='.hg.exe.manifest')
629 fdauto, manfname = tempfile.mkstemp(suffix='.hg.exe.manifest')
630 os.close(fdauto)
630 os.close(fdauto)
631 with open(manfname, 'w') as f:
631 with open(manfname, 'w') as f:
632 f.write(self.LONG_PATHS_MANIFEST)
632 f.write(self.LONG_PATHS_MANIFEST)
633 log.info("long paths manifest is written to '%s'" % manfname)
633 log.info("long paths manifest is written to '%s'" % manfname)
634 inputresource = '-inputresource:%s;#1' % exefname
634 inputresource = '-inputresource:%s;#1' % exefname
635 outputresource = '-outputresource:%s;#1' % exefname
635 outputresource = '-outputresource:%s;#1' % exefname
636 log.info("running mt.exe to update hg.exe's manifest in-place")
636 log.info("running mt.exe to update hg.exe's manifest in-place")
637 # supplying both -manifest and -inputresource to mt.exe makes
637 # supplying both -manifest and -inputresource to mt.exe makes
638 # it merge the embedded and supplied manifests in the -outputresource
638 # it merge the embedded and supplied manifests in the -outputresource
639 self.spawn(['mt.exe', '-nologo', '-manifest', manfname,
639 self.spawn(['mt.exe', '-nologo', '-manifest', manfname,
640 inputresource, outputresource])
640 inputresource, outputresource])
641 log.info("done updating hg.exe's manifest")
641 log.info("done updating hg.exe's manifest")
642 os.remove(manfname)
642 os.remove(manfname)
643
643
644 @property
644 @property
645 def hgexepath(self):
645 def hgexepath(self):
646 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
646 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
647 return os.path.join(self.build_temp, dir, 'hg.exe')
647 return os.path.join(self.build_temp, dir, 'hg.exe')
648
648
649 class hginstall(install):
649 class hginstall(install):
650
650
651 user_options = install.user_options + [
651 user_options = install.user_options + [
652 ('old-and-unmanageable', None,
652 ('old-and-unmanageable', None,
653 'noop, present for eggless setuptools compat'),
653 'noop, present for eggless setuptools compat'),
654 ('single-version-externally-managed', None,
654 ('single-version-externally-managed', None,
655 'noop, present for eggless setuptools compat'),
655 'noop, present for eggless setuptools compat'),
656 ]
656 ]
657
657
658 # Also helps setuptools not be sad while we refuse to create eggs.
658 # Also helps setuptools not be sad while we refuse to create eggs.
659 single_version_externally_managed = True
659 single_version_externally_managed = True
660
660
661 def get_sub_commands(self):
661 def get_sub_commands(self):
662 # Screen out egg related commands to prevent egg generation. But allow
662 # Screen out egg related commands to prevent egg generation. But allow
663 # mercurial.egg-info generation, since that is part of modern
663 # mercurial.egg-info generation, since that is part of modern
664 # packaging.
664 # packaging.
665 excl = set(['bdist_egg'])
665 excl = set(['bdist_egg'])
666 return filter(lambda x: x not in excl, install.get_sub_commands(self))
666 return filter(lambda x: x not in excl, install.get_sub_commands(self))
667
667
668 class hginstalllib(install_lib):
668 class hginstalllib(install_lib):
669 '''
669 '''
670 This is a specialization of install_lib that replaces the copy_file used
670 This is a specialization of install_lib that replaces the copy_file used
671 there so that it supports setting the mode of files after copying them,
671 there so that it supports setting the mode of files after copying them,
672 instead of just preserving the mode that the files originally had. If your
672 instead of just preserving the mode that the files originally had. If your
673 system has a umask of something like 027, preserving the permissions when
673 system has a umask of something like 027, preserving the permissions when
674 copying will lead to a broken install.
674 copying will lead to a broken install.
675
675
676 Note that just passing keep_permissions=False to copy_file would be
676 Note that just passing keep_permissions=False to copy_file would be
677 insufficient, as it might still be applying a umask.
677 insufficient, as it might still be applying a umask.
678 '''
678 '''
679
679
680 def run(self):
680 def run(self):
681 realcopyfile = file_util.copy_file
681 realcopyfile = file_util.copy_file
682 def copyfileandsetmode(*args, **kwargs):
682 def copyfileandsetmode(*args, **kwargs):
683 src, dst = args[0], args[1]
683 src, dst = args[0], args[1]
684 dst, copied = realcopyfile(*args, **kwargs)
684 dst, copied = realcopyfile(*args, **kwargs)
685 if copied:
685 if copied:
686 st = os.stat(src)
686 st = os.stat(src)
687 # Persist executable bit (apply it to group and other if user
687 # Persist executable bit (apply it to group and other if user
688 # has it)
688 # has it)
689 if st[stat.ST_MODE] & stat.S_IXUSR:
689 if st[stat.ST_MODE] & stat.S_IXUSR:
690 setmode = int('0755', 8)
690 setmode = int('0755', 8)
691 else:
691 else:
692 setmode = int('0644', 8)
692 setmode = int('0644', 8)
693 m = stat.S_IMODE(st[stat.ST_MODE])
693 m = stat.S_IMODE(st[stat.ST_MODE])
694 m = (m & ~int('0777', 8)) | setmode
694 m = (m & ~int('0777', 8)) | setmode
695 os.chmod(dst, m)
695 os.chmod(dst, m)
696 file_util.copy_file = copyfileandsetmode
696 file_util.copy_file = copyfileandsetmode
697 try:
697 try:
698 install_lib.run(self)
698 install_lib.run(self)
699 finally:
699 finally:
700 file_util.copy_file = realcopyfile
700 file_util.copy_file = realcopyfile
701
701
702 class hginstallscripts(install_scripts):
702 class hginstallscripts(install_scripts):
703 '''
703 '''
704 This is a specialization of install_scripts that replaces the @LIBDIR@ with
704 This is a specialization of install_scripts that replaces the @LIBDIR@ with
705 the configured directory for modules. If possible, the path is made relative
705 the configured directory for modules. If possible, the path is made relative
706 to the directory for scripts.
706 to the directory for scripts.
707 '''
707 '''
708
708
709 def initialize_options(self):
709 def initialize_options(self):
710 install_scripts.initialize_options(self)
710 install_scripts.initialize_options(self)
711
711
712 self.install_lib = None
712 self.install_lib = None
713
713
714 def finalize_options(self):
714 def finalize_options(self):
715 install_scripts.finalize_options(self)
715 install_scripts.finalize_options(self)
716 self.set_undefined_options('install',
716 self.set_undefined_options('install',
717 ('install_lib', 'install_lib'))
717 ('install_lib', 'install_lib'))
718
718
719 def run(self):
719 def run(self):
720 install_scripts.run(self)
720 install_scripts.run(self)
721
721
722 # It only makes sense to replace @LIBDIR@ with the install path if
722 # It only makes sense to replace @LIBDIR@ with the install path if
723 # the install path is known. For wheels, the logic below calculates
723 # the install path is known. For wheels, the logic below calculates
724 # the libdir to be "../..". This is because the internal layout of a
724 # the libdir to be "../..". This is because the internal layout of a
725 # wheel archive looks like:
725 # wheel archive looks like:
726 #
726 #
727 # mercurial-3.6.1.data/scripts/hg
727 # mercurial-3.6.1.data/scripts/hg
728 # mercurial/__init__.py
728 # mercurial/__init__.py
729 #
729 #
730 # When installing wheels, the subdirectories of the "<pkg>.data"
730 # When installing wheels, the subdirectories of the "<pkg>.data"
731 # directory are translated to system local paths and files therein
731 # directory are translated to system local paths and files therein
732 # are copied in place. The mercurial/* files are installed into the
732 # are copied in place. The mercurial/* files are installed into the
733 # site-packages directory. However, the site-packages directory
733 # site-packages directory. However, the site-packages directory
734 # isn't known until wheel install time. This means we have no clue
734 # isn't known until wheel install time. This means we have no clue
735 # at wheel generation time what the installed site-packages directory
735 # at wheel generation time what the installed site-packages directory
736 # will be. And, wheels don't appear to provide the ability to register
736 # will be. And, wheels don't appear to provide the ability to register
737 # custom code to run during wheel installation. This all means that
737 # custom code to run during wheel installation. This all means that
738 # we can't reliably set the libdir in wheels: the default behavior
738 # we can't reliably set the libdir in wheels: the default behavior
739 # of looking in sys.path must do.
739 # of looking in sys.path must do.
740
740
741 if (os.path.splitdrive(self.install_dir)[0] !=
741 if (os.path.splitdrive(self.install_dir)[0] !=
742 os.path.splitdrive(self.install_lib)[0]):
742 os.path.splitdrive(self.install_lib)[0]):
743 # can't make relative paths from one drive to another, so use an
743 # can't make relative paths from one drive to another, so use an
744 # absolute path instead
744 # absolute path instead
745 libdir = self.install_lib
745 libdir = self.install_lib
746 else:
746 else:
747 common = os.path.commonprefix((self.install_dir, self.install_lib))
747 common = os.path.commonprefix((self.install_dir, self.install_lib))
748 rest = self.install_dir[len(common):]
748 rest = self.install_dir[len(common):]
749 uplevel = len([n for n in os.path.split(rest) if n])
749 uplevel = len([n for n in os.path.split(rest) if n])
750
750
751 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
751 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
752
752
753 for outfile in self.outfiles:
753 for outfile in self.outfiles:
754 with open(outfile, 'rb') as fp:
754 with open(outfile, 'rb') as fp:
755 data = fp.read()
755 data = fp.read()
756
756
757 # skip binary files
757 # skip binary files
758 if b'\0' in data:
758 if b'\0' in data:
759 continue
759 continue
760
760
761 # During local installs, the shebang will be rewritten to the final
761 # During local installs, the shebang will be rewritten to the final
762 # install path. During wheel packaging, the shebang has a special
762 # install path. During wheel packaging, the shebang has a special
763 # value.
763 # value.
764 if data.startswith(b'#!python'):
764 if data.startswith(b'#!python'):
765 log.info('not rewriting @LIBDIR@ in %s because install path '
765 log.info('not rewriting @LIBDIR@ in %s because install path '
766 'not known' % outfile)
766 'not known' % outfile)
767 continue
767 continue
768
768
769 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
769 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
770 with open(outfile, 'wb') as fp:
770 with open(outfile, 'wb') as fp:
771 fp.write(data)
771 fp.write(data)
772
772
773 cmdclass = {'build': hgbuild,
773 cmdclass = {'build': hgbuild,
774 'build_mo': hgbuildmo,
774 'build_mo': hgbuildmo,
775 'build_ext': hgbuildext,
775 'build_ext': hgbuildext,
776 'build_py': hgbuildpy,
776 'build_py': hgbuildpy,
777 'build_scripts': hgbuildscripts,
777 'build_scripts': hgbuildscripts,
778 'build_hgextindex': buildhgextindex,
778 'build_hgextindex': buildhgextindex,
779 'install': hginstall,
779 'install': hginstall,
780 'install_lib': hginstalllib,
780 'install_lib': hginstalllib,
781 'install_scripts': hginstallscripts,
781 'install_scripts': hginstallscripts,
782 'build_hgexe': buildhgexe,
782 'build_hgexe': buildhgexe,
783 }
783 }
784
784
785 packages = ['mercurial',
785 packages = ['mercurial',
786 'mercurial.cext',
786 'mercurial.cext',
787 'mercurial.cffi',
787 'mercurial.cffi',
788 'mercurial.hgweb',
788 'mercurial.hgweb',
789 'mercurial.httpclient',
789 'mercurial.httpclient',
790 'mercurial.pure',
790 'mercurial.pure',
791 'mercurial.thirdparty',
791 'mercurial.thirdparty',
792 'mercurial.thirdparty.attr',
792 'mercurial.thirdparty.attr',
793 'hgext', 'hgext.convert', 'hgext.fsmonitor',
793 'hgext', 'hgext.convert', 'hgext.fsmonitor',
794 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
794 'hgext.fsmonitor.pywatchman', 'hgext.highlight',
795 'hgext.largefiles', 'hgext.lfs', 'hgext.zeroconf', 'hgext3rd',
795 'hgext.largefiles', 'hgext.lfs', 'hgext.narrow',
796 'hgext.zeroconf', 'hgext3rd',
796 'hgdemandimport']
797 'hgdemandimport']
797
798
798 common_depends = ['mercurial/bitmanipulation.h',
799 common_depends = ['mercurial/bitmanipulation.h',
799 'mercurial/compat.h',
800 'mercurial/compat.h',
800 'mercurial/cext/util.h']
801 'mercurial/cext/util.h']
801 common_include_dirs = ['mercurial']
802 common_include_dirs = ['mercurial']
802
803
803 osutil_cflags = []
804 osutil_cflags = []
804 osutil_ldflags = []
805 osutil_ldflags = []
805
806
806 # platform specific macros
807 # platform specific macros
807 for plat, func in [('bsd', 'setproctitle')]:
808 for plat, func in [('bsd', 'setproctitle')]:
808 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
809 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
809 osutil_cflags.append('-DHAVE_%s' % func.upper())
810 osutil_cflags.append('-DHAVE_%s' % func.upper())
810
811
811 for plat, macro, code in [
812 for plat, macro, code in [
812 ('bsd|darwin', 'BSD_STATFS', '''
813 ('bsd|darwin', 'BSD_STATFS', '''
813 #include <sys/param.h>
814 #include <sys/param.h>
814 #include <sys/mount.h>
815 #include <sys/mount.h>
815 int main() { struct statfs s; return sizeof(s.f_fstypename); }
816 int main() { struct statfs s; return sizeof(s.f_fstypename); }
816 '''),
817 '''),
817 ('linux', 'LINUX_STATFS', '''
818 ('linux', 'LINUX_STATFS', '''
818 #include <linux/magic.h>
819 #include <linux/magic.h>
819 #include <sys/vfs.h>
820 #include <sys/vfs.h>
820 int main() { struct statfs s; return sizeof(s.f_type); }
821 int main() { struct statfs s; return sizeof(s.f_type); }
821 '''),
822 '''),
822 ]:
823 ]:
823 if re.search(plat, sys.platform) and cancompile(new_compiler(), code):
824 if re.search(plat, sys.platform) and cancompile(new_compiler(), code):
824 osutil_cflags.append('-DHAVE_%s' % macro)
825 osutil_cflags.append('-DHAVE_%s' % macro)
825
826
826 if sys.platform == 'darwin':
827 if sys.platform == 'darwin':
827 osutil_ldflags += ['-framework', 'ApplicationServices']
828 osutil_ldflags += ['-framework', 'ApplicationServices']
828
829
829 extmodules = [
830 extmodules = [
830 Extension('mercurial.cext.base85', ['mercurial/cext/base85.c'],
831 Extension('mercurial.cext.base85', ['mercurial/cext/base85.c'],
831 include_dirs=common_include_dirs,
832 include_dirs=common_include_dirs,
832 depends=common_depends),
833 depends=common_depends),
833 Extension('mercurial.cext.bdiff', ['mercurial/bdiff.c',
834 Extension('mercurial.cext.bdiff', ['mercurial/bdiff.c',
834 'mercurial/cext/bdiff.c'],
835 'mercurial/cext/bdiff.c'],
835 include_dirs=common_include_dirs,
836 include_dirs=common_include_dirs,
836 depends=common_depends + ['mercurial/bdiff.h']),
837 depends=common_depends + ['mercurial/bdiff.h']),
837 Extension('mercurial.cext.diffhelpers', ['mercurial/cext/diffhelpers.c'],
838 Extension('mercurial.cext.diffhelpers', ['mercurial/cext/diffhelpers.c'],
838 include_dirs=common_include_dirs,
839 include_dirs=common_include_dirs,
839 depends=common_depends),
840 depends=common_depends),
840 Extension('mercurial.cext.mpatch', ['mercurial/mpatch.c',
841 Extension('mercurial.cext.mpatch', ['mercurial/mpatch.c',
841 'mercurial/cext/mpatch.c'],
842 'mercurial/cext/mpatch.c'],
842 include_dirs=common_include_dirs,
843 include_dirs=common_include_dirs,
843 depends=common_depends),
844 depends=common_depends),
844 Extension('mercurial.cext.parsers', ['mercurial/cext/charencode.c',
845 Extension('mercurial.cext.parsers', ['mercurial/cext/charencode.c',
845 'mercurial/cext/dirs.c',
846 'mercurial/cext/dirs.c',
846 'mercurial/cext/manifest.c',
847 'mercurial/cext/manifest.c',
847 'mercurial/cext/parsers.c',
848 'mercurial/cext/parsers.c',
848 'mercurial/cext/pathencode.c',
849 'mercurial/cext/pathencode.c',
849 'mercurial/cext/revlog.c'],
850 'mercurial/cext/revlog.c'],
850 include_dirs=common_include_dirs,
851 include_dirs=common_include_dirs,
851 depends=common_depends + ['mercurial/cext/charencode.h']),
852 depends=common_depends + ['mercurial/cext/charencode.h']),
852 Extension('mercurial.cext.osutil', ['mercurial/cext/osutil.c'],
853 Extension('mercurial.cext.osutil', ['mercurial/cext/osutil.c'],
853 include_dirs=common_include_dirs,
854 include_dirs=common_include_dirs,
854 extra_compile_args=osutil_cflags,
855 extra_compile_args=osutil_cflags,
855 extra_link_args=osutil_ldflags,
856 extra_link_args=osutil_ldflags,
856 depends=common_depends),
857 depends=common_depends),
857 Extension('hgext.fsmonitor.pywatchman.bser',
858 Extension('hgext.fsmonitor.pywatchman.bser',
858 ['hgext/fsmonitor/pywatchman/bser.c']),
859 ['hgext/fsmonitor/pywatchman/bser.c']),
859 ]
860 ]
860
861
861 sys.path.insert(0, 'contrib/python-zstandard')
862 sys.path.insert(0, 'contrib/python-zstandard')
862 import setup_zstd
863 import setup_zstd
863 extmodules.append(setup_zstd.get_c_extension(name='mercurial.zstd'))
864 extmodules.append(setup_zstd.get_c_extension(name='mercurial.zstd'))
864
865
865 try:
866 try:
866 from distutils import cygwinccompiler
867 from distutils import cygwinccompiler
867
868
868 # the -mno-cygwin option has been deprecated for years
869 # the -mno-cygwin option has been deprecated for years
869 mingw32compilerclass = cygwinccompiler.Mingw32CCompiler
870 mingw32compilerclass = cygwinccompiler.Mingw32CCompiler
870
871
871 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
872 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
872 def __init__(self, *args, **kwargs):
873 def __init__(self, *args, **kwargs):
873 mingw32compilerclass.__init__(self, *args, **kwargs)
874 mingw32compilerclass.__init__(self, *args, **kwargs)
874 for i in 'compiler compiler_so linker_exe linker_so'.split():
875 for i in 'compiler compiler_so linker_exe linker_so'.split():
875 try:
876 try:
876 getattr(self, i).remove('-mno-cygwin')
877 getattr(self, i).remove('-mno-cygwin')
877 except ValueError:
878 except ValueError:
878 pass
879 pass
879
880
880 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
881 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
881 except ImportError:
882 except ImportError:
882 # the cygwinccompiler package is not available on some Python
883 # the cygwinccompiler package is not available on some Python
883 # distributions like the ones from the optware project for Synology
884 # distributions like the ones from the optware project for Synology
884 # DiskStation boxes
885 # DiskStation boxes
885 class HackedMingw32CCompiler(object):
886 class HackedMingw32CCompiler(object):
886 pass
887 pass
887
888
888 if os.name == 'nt':
889 if os.name == 'nt':
889 # Allow compiler/linker flags to be added to Visual Studio builds. Passing
890 # Allow compiler/linker flags to be added to Visual Studio builds. Passing
890 # extra_link_args to distutils.extensions.Extension() doesn't have any
891 # extra_link_args to distutils.extensions.Extension() doesn't have any
891 # effect.
892 # effect.
892 from distutils import msvccompiler
893 from distutils import msvccompiler
893
894
894 msvccompilerclass = msvccompiler.MSVCCompiler
895 msvccompilerclass = msvccompiler.MSVCCompiler
895
896
896 class HackedMSVCCompiler(msvccompiler.MSVCCompiler):
897 class HackedMSVCCompiler(msvccompiler.MSVCCompiler):
897 def initialize(self):
898 def initialize(self):
898 msvccompilerclass.initialize(self)
899 msvccompilerclass.initialize(self)
899 # "warning LNK4197: export 'func' specified multiple times"
900 # "warning LNK4197: export 'func' specified multiple times"
900 self.ldflags_shared.append('/ignore:4197')
901 self.ldflags_shared.append('/ignore:4197')
901 self.ldflags_shared_debug.append('/ignore:4197')
902 self.ldflags_shared_debug.append('/ignore:4197')
902
903
903 msvccompiler.MSVCCompiler = HackedMSVCCompiler
904 msvccompiler.MSVCCompiler = HackedMSVCCompiler
904
905
905 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
906 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
906 'help/*.txt',
907 'help/*.txt',
907 'help/internals/*.txt',
908 'help/internals/*.txt',
908 'default.d/*.rc',
909 'default.d/*.rc',
909 'dummycert.pem']}
910 'dummycert.pem']}
910
911
911 def ordinarypath(p):
912 def ordinarypath(p):
912 return p and p[0] != '.' and p[-1] != '~'
913 return p and p[0] != '.' and p[-1] != '~'
913
914
914 for root in ('templates',):
915 for root in ('templates',):
915 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
916 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
916 curdir = curdir.split(os.sep, 1)[1]
917 curdir = curdir.split(os.sep, 1)[1]
917 dirs[:] = filter(ordinarypath, dirs)
918 dirs[:] = filter(ordinarypath, dirs)
918 for f in filter(ordinarypath, files):
919 for f in filter(ordinarypath, files):
919 f = os.path.join(curdir, f)
920 f = os.path.join(curdir, f)
920 packagedata['mercurial'].append(f)
921 packagedata['mercurial'].append(f)
921
922
922 datafiles = []
923 datafiles = []
923
924
924 # distutils expects version to be str/unicode. Converting it to
925 # distutils expects version to be str/unicode. Converting it to
925 # unicode on Python 2 still works because it won't contain any
926 # unicode on Python 2 still works because it won't contain any
926 # non-ascii bytes and will be implicitly converted back to bytes
927 # non-ascii bytes and will be implicitly converted back to bytes
927 # when operated on.
928 # when operated on.
928 assert isinstance(version, bytes)
929 assert isinstance(version, bytes)
929 setupversion = version.decode('ascii')
930 setupversion = version.decode('ascii')
930
931
931 extra = {}
932 extra = {}
932
933
933 if issetuptools:
934 if issetuptools:
934 extra['python_requires'] = supportedpy
935 extra['python_requires'] = supportedpy
935 if py2exeloaded:
936 if py2exeloaded:
936 extra['console'] = [
937 extra['console'] = [
937 {'script':'hg',
938 {'script':'hg',
938 'copyright':'Copyright (C) 2005-2018 Matt Mackall and others',
939 'copyright':'Copyright (C) 2005-2018 Matt Mackall and others',
939 'product_version':version}]
940 'product_version':version}]
940 # sub command of 'build' because 'py2exe' does not handle sub_commands
941 # sub command of 'build' because 'py2exe' does not handle sub_commands
941 build.sub_commands.insert(0, ('build_hgextindex', None))
942 build.sub_commands.insert(0, ('build_hgextindex', None))
942 # put dlls in sub directory so that they won't pollute PATH
943 # put dlls in sub directory so that they won't pollute PATH
943 extra['zipfile'] = 'lib/library.zip'
944 extra['zipfile'] = 'lib/library.zip'
944
945
945 if os.name == 'nt':
946 if os.name == 'nt':
946 # Windows binary file versions for exe/dll files must have the
947 # Windows binary file versions for exe/dll files must have the
947 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
948 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
948 setupversion = version.split('+', 1)[0]
949 setupversion = version.split('+', 1)[0]
949
950
950 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
951 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
951 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[1].splitlines()
952 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[1].splitlines()
952 if version:
953 if version:
953 version = version[0]
954 version = version[0]
954 if sys.version_info[0] == 3:
955 if sys.version_info[0] == 3:
955 version = version.decode('utf-8')
956 version = version.decode('utf-8')
956 xcode4 = (version.startswith('Xcode') and
957 xcode4 = (version.startswith('Xcode') and
957 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
958 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
958 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
959 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
959 else:
960 else:
960 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
961 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
961 # installed, but instead with only command-line tools. Assume
962 # installed, but instead with only command-line tools. Assume
962 # that only happens on >= Lion, thus no PPC support.
963 # that only happens on >= Lion, thus no PPC support.
963 xcode4 = True
964 xcode4 = True
964 xcode51 = False
965 xcode51 = False
965
966
966 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
967 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
967 # distutils.sysconfig
968 # distutils.sysconfig
968 if xcode4:
969 if xcode4:
969 os.environ['ARCHFLAGS'] = ''
970 os.environ['ARCHFLAGS'] = ''
970
971
971 # XCode 5.1 changes clang such that it now fails to compile if the
972 # XCode 5.1 changes clang such that it now fails to compile if the
972 # -mno-fused-madd flag is passed, but the version of Python shipped with
973 # -mno-fused-madd flag is passed, but the version of Python shipped with
973 # OS X 10.9 Mavericks includes this flag. This causes problems in all
974 # OS X 10.9 Mavericks includes this flag. This causes problems in all
974 # C extension modules, and a bug has been filed upstream at
975 # C extension modules, and a bug has been filed upstream at
975 # http://bugs.python.org/issue21244. We also need to patch this here
976 # http://bugs.python.org/issue21244. We also need to patch this here
976 # so Mercurial can continue to compile in the meantime.
977 # so Mercurial can continue to compile in the meantime.
977 if xcode51:
978 if xcode51:
978 cflags = get_config_var('CFLAGS')
979 cflags = get_config_var('CFLAGS')
979 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
980 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
980 os.environ['CFLAGS'] = (
981 os.environ['CFLAGS'] = (
981 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
982 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
982
983
983 setup(name='mercurial',
984 setup(name='mercurial',
984 version=setupversion,
985 version=setupversion,
985 author='Matt Mackall and many others',
986 author='Matt Mackall and many others',
986 author_email='mercurial@mercurial-scm.org',
987 author_email='mercurial@mercurial-scm.org',
987 url='https://mercurial-scm.org/',
988 url='https://mercurial-scm.org/',
988 download_url='https://mercurial-scm.org/release/',
989 download_url='https://mercurial-scm.org/release/',
989 description=('Fast scalable distributed SCM (revision control, version '
990 description=('Fast scalable distributed SCM (revision control, version '
990 'control) system'),
991 'control) system'),
991 long_description=('Mercurial is a distributed SCM tool written in Python.'
992 long_description=('Mercurial is a distributed SCM tool written in Python.'
992 ' It is used by a number of large projects that require'
993 ' It is used by a number of large projects that require'
993 ' fast, reliable distributed revision control, such as '
994 ' fast, reliable distributed revision control, such as '
994 'Mozilla.'),
995 'Mozilla.'),
995 license='GNU GPLv2 or any later version',
996 license='GNU GPLv2 or any later version',
996 classifiers=[
997 classifiers=[
997 'Development Status :: 6 - Mature',
998 'Development Status :: 6 - Mature',
998 'Environment :: Console',
999 'Environment :: Console',
999 'Intended Audience :: Developers',
1000 'Intended Audience :: Developers',
1000 'Intended Audience :: System Administrators',
1001 'Intended Audience :: System Administrators',
1001 'License :: OSI Approved :: GNU General Public License (GPL)',
1002 'License :: OSI Approved :: GNU General Public License (GPL)',
1002 'Natural Language :: Danish',
1003 'Natural Language :: Danish',
1003 'Natural Language :: English',
1004 'Natural Language :: English',
1004 'Natural Language :: German',
1005 'Natural Language :: German',
1005 'Natural Language :: Italian',
1006 'Natural Language :: Italian',
1006 'Natural Language :: Japanese',
1007 'Natural Language :: Japanese',
1007 'Natural Language :: Portuguese (Brazilian)',
1008 'Natural Language :: Portuguese (Brazilian)',
1008 'Operating System :: Microsoft :: Windows',
1009 'Operating System :: Microsoft :: Windows',
1009 'Operating System :: OS Independent',
1010 'Operating System :: OS Independent',
1010 'Operating System :: POSIX',
1011 'Operating System :: POSIX',
1011 'Programming Language :: C',
1012 'Programming Language :: C',
1012 'Programming Language :: Python',
1013 'Programming Language :: Python',
1013 'Topic :: Software Development :: Version Control',
1014 'Topic :: Software Development :: Version Control',
1014 ],
1015 ],
1015 scripts=scripts,
1016 scripts=scripts,
1016 packages=packages,
1017 packages=packages,
1017 ext_modules=extmodules,
1018 ext_modules=extmodules,
1018 data_files=datafiles,
1019 data_files=datafiles,
1019 package_data=packagedata,
1020 package_data=packagedata,
1020 cmdclass=cmdclass,
1021 cmdclass=cmdclass,
1021 distclass=hgdist,
1022 distclass=hgdist,
1022 options={'py2exe': {'packages': ['hgdemandimport', 'hgext', 'email',
1023 options={'py2exe': {'packages': ['hgdemandimport', 'hgext', 'email',
1023 # implicitly imported per module policy
1024 # implicitly imported per module policy
1024 # (cffi wouldn't be used as a frozen exe)
1025 # (cffi wouldn't be used as a frozen exe)
1025 'mercurial.cext',
1026 'mercurial.cext',
1026 #'mercurial.cffi',
1027 #'mercurial.cffi',
1027 'mercurial.pure']},
1028 'mercurial.pure']},
1028 'bdist_mpkg': {'zipdist': False,
1029 'bdist_mpkg': {'zipdist': False,
1029 'license': 'COPYING',
1030 'license': 'COPYING',
1030 'readme': 'contrib/macosx/Readme.html',
1031 'readme': 'contrib/macosx/Readme.html',
1031 'welcome': 'contrib/macosx/Welcome.html',
1032 'welcome': 'contrib/macosx/Welcome.html',
1032 },
1033 },
1033 },
1034 },
1034 **extra)
1035 **extra)
@@ -1,3394 +1,3396 b''
1 Short help:
1 Short help:
2
2
3 $ hg
3 $ hg
4 Mercurial Distributed SCM
4 Mercurial Distributed SCM
5
5
6 basic commands:
6 basic commands:
7
7
8 add add the specified files on the next commit
8 add add the specified files on the next commit
9 annotate show changeset information by line for each file
9 annotate show changeset information by line for each file
10 clone make a copy of an existing repository
10 clone make a copy of an existing repository
11 commit commit the specified files or all outstanding changes
11 commit commit the specified files or all outstanding changes
12 diff diff repository (or selected files)
12 diff diff repository (or selected files)
13 export dump the header and diffs for one or more changesets
13 export dump the header and diffs for one or more changesets
14 forget forget the specified files on the next commit
14 forget forget the specified files on the next commit
15 init create a new repository in the given directory
15 init create a new repository in the given directory
16 log show revision history of entire repository or files
16 log show revision history of entire repository or files
17 merge merge another revision into working directory
17 merge merge another revision into working directory
18 pull pull changes from the specified source
18 pull pull changes from the specified source
19 push push changes to the specified destination
19 push push changes to the specified destination
20 remove remove the specified files on the next commit
20 remove remove the specified files on the next commit
21 serve start stand-alone webserver
21 serve start stand-alone webserver
22 status show changed files in the working directory
22 status show changed files in the working directory
23 summary summarize working directory state
23 summary summarize working directory state
24 update update working directory (or switch revisions)
24 update update working directory (or switch revisions)
25
25
26 (use 'hg help' for the full list of commands or 'hg -v' for details)
26 (use 'hg help' for the full list of commands or 'hg -v' for details)
27
27
28 $ hg -q
28 $ hg -q
29 add add the specified files on the next commit
29 add add the specified files on the next commit
30 annotate show changeset information by line for each file
30 annotate show changeset information by line for each file
31 clone make a copy of an existing repository
31 clone make a copy of an existing repository
32 commit commit the specified files or all outstanding changes
32 commit commit the specified files or all outstanding changes
33 diff diff repository (or selected files)
33 diff diff repository (or selected files)
34 export dump the header and diffs for one or more changesets
34 export dump the header and diffs for one or more changesets
35 forget forget the specified files on the next commit
35 forget forget the specified files on the next commit
36 init create a new repository in the given directory
36 init create a new repository in the given directory
37 log show revision history of entire repository or files
37 log show revision history of entire repository or files
38 merge merge another revision into working directory
38 merge merge another revision into working directory
39 pull pull changes from the specified source
39 pull pull changes from the specified source
40 push push changes to the specified destination
40 push push changes to the specified destination
41 remove remove the specified files on the next commit
41 remove remove the specified files on the next commit
42 serve start stand-alone webserver
42 serve start stand-alone webserver
43 status show changed files in the working directory
43 status show changed files in the working directory
44 summary summarize working directory state
44 summary summarize working directory state
45 update update working directory (or switch revisions)
45 update update working directory (or switch revisions)
46
46
47 $ hg help
47 $ hg help
48 Mercurial Distributed SCM
48 Mercurial Distributed SCM
49
49
50 list of commands:
50 list of commands:
51
51
52 add add the specified files on the next commit
52 add add the specified files on the next commit
53 addremove add all new files, delete all missing files
53 addremove add all new files, delete all missing files
54 annotate show changeset information by line for each file
54 annotate show changeset information by line for each file
55 archive create an unversioned archive of a repository revision
55 archive create an unversioned archive of a repository revision
56 backout reverse effect of earlier changeset
56 backout reverse effect of earlier changeset
57 bisect subdivision search of changesets
57 bisect subdivision search of changesets
58 bookmarks create a new bookmark or list existing bookmarks
58 bookmarks create a new bookmark or list existing bookmarks
59 branch set or show the current branch name
59 branch set or show the current branch name
60 branches list repository named branches
60 branches list repository named branches
61 bundle create a bundle file
61 bundle create a bundle file
62 cat output the current or given revision of files
62 cat output the current or given revision of files
63 clone make a copy of an existing repository
63 clone make a copy of an existing repository
64 commit commit the specified files or all outstanding changes
64 commit commit the specified files or all outstanding changes
65 config show combined config settings from all hgrc files
65 config show combined config settings from all hgrc files
66 copy mark files as copied for the next commit
66 copy mark files as copied for the next commit
67 diff diff repository (or selected files)
67 diff diff repository (or selected files)
68 export dump the header and diffs for one or more changesets
68 export dump the header and diffs for one or more changesets
69 files list tracked files
69 files list tracked files
70 forget forget the specified files on the next commit
70 forget forget the specified files on the next commit
71 graft copy changes from other branches onto the current branch
71 graft copy changes from other branches onto the current branch
72 grep search revision history for a pattern in specified files
72 grep search revision history for a pattern in specified files
73 heads show branch heads
73 heads show branch heads
74 help show help for a given topic or a help overview
74 help show help for a given topic or a help overview
75 identify identify the working directory or specified revision
75 identify identify the working directory or specified revision
76 import import an ordered set of patches
76 import import an ordered set of patches
77 incoming show new changesets found in source
77 incoming show new changesets found in source
78 init create a new repository in the given directory
78 init create a new repository in the given directory
79 log show revision history of entire repository or files
79 log show revision history of entire repository or files
80 manifest output the current or given revision of the project manifest
80 manifest output the current or given revision of the project manifest
81 merge merge another revision into working directory
81 merge merge another revision into working directory
82 outgoing show changesets not found in the destination
82 outgoing show changesets not found in the destination
83 paths show aliases for remote repositories
83 paths show aliases for remote repositories
84 phase set or show the current phase name
84 phase set or show the current phase name
85 pull pull changes from the specified source
85 pull pull changes from the specified source
86 push push changes to the specified destination
86 push push changes to the specified destination
87 recover roll back an interrupted transaction
87 recover roll back an interrupted transaction
88 remove remove the specified files on the next commit
88 remove remove the specified files on the next commit
89 rename rename files; equivalent of copy + remove
89 rename rename files; equivalent of copy + remove
90 resolve redo merges or set/view the merge status of files
90 resolve redo merges or set/view the merge status of files
91 revert restore files to their checkout state
91 revert restore files to their checkout state
92 root print the root (top) of the current working directory
92 root print the root (top) of the current working directory
93 serve start stand-alone webserver
93 serve start stand-alone webserver
94 status show changed files in the working directory
94 status show changed files in the working directory
95 summary summarize working directory state
95 summary summarize working directory state
96 tag add one or more tags for the current or given revision
96 tag add one or more tags for the current or given revision
97 tags list repository tags
97 tags list repository tags
98 unbundle apply one or more bundle files
98 unbundle apply one or more bundle files
99 update update working directory (or switch revisions)
99 update update working directory (or switch revisions)
100 verify verify the integrity of the repository
100 verify verify the integrity of the repository
101 version output version and copyright information
101 version output version and copyright information
102
102
103 additional help topics:
103 additional help topics:
104
104
105 bundlespec Bundle File Formats
105 bundlespec Bundle File Formats
106 color Colorizing Outputs
106 color Colorizing Outputs
107 config Configuration Files
107 config Configuration Files
108 dates Date Formats
108 dates Date Formats
109 diffs Diff Formats
109 diffs Diff Formats
110 environment Environment Variables
110 environment Environment Variables
111 extensions Using Additional Features
111 extensions Using Additional Features
112 filesets Specifying File Sets
112 filesets Specifying File Sets
113 flags Command-line flags
113 flags Command-line flags
114 glossary Glossary
114 glossary Glossary
115 hgignore Syntax for Mercurial Ignore Files
115 hgignore Syntax for Mercurial Ignore Files
116 hgweb Configuring hgweb
116 hgweb Configuring hgweb
117 internals Technical implementation topics
117 internals Technical implementation topics
118 merge-tools Merge Tools
118 merge-tools Merge Tools
119 pager Pager Support
119 pager Pager Support
120 patterns File Name Patterns
120 patterns File Name Patterns
121 phases Working with Phases
121 phases Working with Phases
122 revisions Specifying Revisions
122 revisions Specifying Revisions
123 scripting Using Mercurial from scripts and automation
123 scripting Using Mercurial from scripts and automation
124 subrepos Subrepositories
124 subrepos Subrepositories
125 templating Template Usage
125 templating Template Usage
126 urls URL Paths
126 urls URL Paths
127
127
128 (use 'hg help -v' to show built-in aliases and global options)
128 (use 'hg help -v' to show built-in aliases and global options)
129
129
130 $ hg -q help
130 $ hg -q help
131 add add the specified files on the next commit
131 add add the specified files on the next commit
132 addremove add all new files, delete all missing files
132 addremove add all new files, delete all missing files
133 annotate show changeset information by line for each file
133 annotate show changeset information by line for each file
134 archive create an unversioned archive of a repository revision
134 archive create an unversioned archive of a repository revision
135 backout reverse effect of earlier changeset
135 backout reverse effect of earlier changeset
136 bisect subdivision search of changesets
136 bisect subdivision search of changesets
137 bookmarks create a new bookmark or list existing bookmarks
137 bookmarks create a new bookmark or list existing bookmarks
138 branch set or show the current branch name
138 branch set or show the current branch name
139 branches list repository named branches
139 branches list repository named branches
140 bundle create a bundle file
140 bundle create a bundle file
141 cat output the current or given revision of files
141 cat output the current or given revision of files
142 clone make a copy of an existing repository
142 clone make a copy of an existing repository
143 commit commit the specified files or all outstanding changes
143 commit commit the specified files or all outstanding changes
144 config show combined config settings from all hgrc files
144 config show combined config settings from all hgrc files
145 copy mark files as copied for the next commit
145 copy mark files as copied for the next commit
146 diff diff repository (or selected files)
146 diff diff repository (or selected files)
147 export dump the header and diffs for one or more changesets
147 export dump the header and diffs for one or more changesets
148 files list tracked files
148 files list tracked files
149 forget forget the specified files on the next commit
149 forget forget the specified files on the next commit
150 graft copy changes from other branches onto the current branch
150 graft copy changes from other branches onto the current branch
151 grep search revision history for a pattern in specified files
151 grep search revision history for a pattern in specified files
152 heads show branch heads
152 heads show branch heads
153 help show help for a given topic or a help overview
153 help show help for a given topic or a help overview
154 identify identify the working directory or specified revision
154 identify identify the working directory or specified revision
155 import import an ordered set of patches
155 import import an ordered set of patches
156 incoming show new changesets found in source
156 incoming show new changesets found in source
157 init create a new repository in the given directory
157 init create a new repository in the given directory
158 log show revision history of entire repository or files
158 log show revision history of entire repository or files
159 manifest output the current or given revision of the project manifest
159 manifest output the current or given revision of the project manifest
160 merge merge another revision into working directory
160 merge merge another revision into working directory
161 outgoing show changesets not found in the destination
161 outgoing show changesets not found in the destination
162 paths show aliases for remote repositories
162 paths show aliases for remote repositories
163 phase set or show the current phase name
163 phase set or show the current phase name
164 pull pull changes from the specified source
164 pull pull changes from the specified source
165 push push changes to the specified destination
165 push push changes to the specified destination
166 recover roll back an interrupted transaction
166 recover roll back an interrupted transaction
167 remove remove the specified files on the next commit
167 remove remove the specified files on the next commit
168 rename rename files; equivalent of copy + remove
168 rename rename files; equivalent of copy + remove
169 resolve redo merges or set/view the merge status of files
169 resolve redo merges or set/view the merge status of files
170 revert restore files to their checkout state
170 revert restore files to their checkout state
171 root print the root (top) of the current working directory
171 root print the root (top) of the current working directory
172 serve start stand-alone webserver
172 serve start stand-alone webserver
173 status show changed files in the working directory
173 status show changed files in the working directory
174 summary summarize working directory state
174 summary summarize working directory state
175 tag add one or more tags for the current or given revision
175 tag add one or more tags for the current or given revision
176 tags list repository tags
176 tags list repository tags
177 unbundle apply one or more bundle files
177 unbundle apply one or more bundle files
178 update update working directory (or switch revisions)
178 update update working directory (or switch revisions)
179 verify verify the integrity of the repository
179 verify verify the integrity of the repository
180 version output version and copyright information
180 version output version and copyright information
181
181
182 additional help topics:
182 additional help topics:
183
183
184 bundlespec Bundle File Formats
184 bundlespec Bundle File Formats
185 color Colorizing Outputs
185 color Colorizing Outputs
186 config Configuration Files
186 config Configuration Files
187 dates Date Formats
187 dates Date Formats
188 diffs Diff Formats
188 diffs Diff Formats
189 environment Environment Variables
189 environment Environment Variables
190 extensions Using Additional Features
190 extensions Using Additional Features
191 filesets Specifying File Sets
191 filesets Specifying File Sets
192 flags Command-line flags
192 flags Command-line flags
193 glossary Glossary
193 glossary Glossary
194 hgignore Syntax for Mercurial Ignore Files
194 hgignore Syntax for Mercurial Ignore Files
195 hgweb Configuring hgweb
195 hgweb Configuring hgweb
196 internals Technical implementation topics
196 internals Technical implementation topics
197 merge-tools Merge Tools
197 merge-tools Merge Tools
198 pager Pager Support
198 pager Pager Support
199 patterns File Name Patterns
199 patterns File Name Patterns
200 phases Working with Phases
200 phases Working with Phases
201 revisions Specifying Revisions
201 revisions Specifying Revisions
202 scripting Using Mercurial from scripts and automation
202 scripting Using Mercurial from scripts and automation
203 subrepos Subrepositories
203 subrepos Subrepositories
204 templating Template Usage
204 templating Template Usage
205 urls URL Paths
205 urls URL Paths
206
206
207 Test extension help:
207 Test extension help:
208 $ hg help extensions --config extensions.rebase= --config extensions.children=
208 $ hg help extensions --config extensions.rebase= --config extensions.children=
209 Using Additional Features
209 Using Additional Features
210 """""""""""""""""""""""""
210 """""""""""""""""""""""""
211
211
212 Mercurial has the ability to add new features through the use of
212 Mercurial has the ability to add new features through the use of
213 extensions. Extensions may add new commands, add options to existing
213 extensions. Extensions may add new commands, add options to existing
214 commands, change the default behavior of commands, or implement hooks.
214 commands, change the default behavior of commands, or implement hooks.
215
215
216 To enable the "foo" extension, either shipped with Mercurial or in the
216 To enable the "foo" extension, either shipped with Mercurial or in the
217 Python search path, create an entry for it in your configuration file,
217 Python search path, create an entry for it in your configuration file,
218 like this:
218 like this:
219
219
220 [extensions]
220 [extensions]
221 foo =
221 foo =
222
222
223 You may also specify the full path to an extension:
223 You may also specify the full path to an extension:
224
224
225 [extensions]
225 [extensions]
226 myfeature = ~/.hgext/myfeature.py
226 myfeature = ~/.hgext/myfeature.py
227
227
228 See 'hg help config' for more information on configuration files.
228 See 'hg help config' for more information on configuration files.
229
229
230 Extensions are not loaded by default for a variety of reasons: they can
230 Extensions are not loaded by default for a variety of reasons: they can
231 increase startup overhead; they may be meant for advanced usage only; they
231 increase startup overhead; they may be meant for advanced usage only; they
232 may provide potentially dangerous abilities (such as letting you destroy
232 may provide potentially dangerous abilities (such as letting you destroy
233 or modify history); they might not be ready for prime time; or they may
233 or modify history); they might not be ready for prime time; or they may
234 alter some usual behaviors of stock Mercurial. It is thus up to the user
234 alter some usual behaviors of stock Mercurial. It is thus up to the user
235 to activate extensions as needed.
235 to activate extensions as needed.
236
236
237 To explicitly disable an extension enabled in a configuration file of
237 To explicitly disable an extension enabled in a configuration file of
238 broader scope, prepend its path with !:
238 broader scope, prepend its path with !:
239
239
240 [extensions]
240 [extensions]
241 # disabling extension bar residing in /path/to/extension/bar.py
241 # disabling extension bar residing in /path/to/extension/bar.py
242 bar = !/path/to/extension/bar.py
242 bar = !/path/to/extension/bar.py
243 # ditto, but no path was supplied for extension baz
243 # ditto, but no path was supplied for extension baz
244 baz = !
244 baz = !
245
245
246 enabled extensions:
246 enabled extensions:
247
247
248 children command to display child changesets (DEPRECATED)
248 children command to display child changesets (DEPRECATED)
249 rebase command to move sets of revisions to a different ancestor
249 rebase command to move sets of revisions to a different ancestor
250
250
251 disabled extensions:
251 disabled extensions:
252
252
253 acl hooks for controlling repository access
253 acl hooks for controlling repository access
254 blackbox log repository events to a blackbox for debugging
254 blackbox log repository events to a blackbox for debugging
255 bugzilla hooks for integrating with the Bugzilla bug tracker
255 bugzilla hooks for integrating with the Bugzilla bug tracker
256 censor erase file content at a given revision
256 censor erase file content at a given revision
257 churn command to display statistics about repository history
257 churn command to display statistics about repository history
258 clonebundles advertise pre-generated bundles to seed clones
258 clonebundles advertise pre-generated bundles to seed clones
259 convert import revisions from foreign VCS repositories into
259 convert import revisions from foreign VCS repositories into
260 Mercurial
260 Mercurial
261 eol automatically manage newlines in repository files
261 eol automatically manage newlines in repository files
262 extdiff command to allow external programs to compare revisions
262 extdiff command to allow external programs to compare revisions
263 factotum http authentication with factotum
263 factotum http authentication with factotum
264 githelp try mapping git commands to Mercurial commands
264 githelp try mapping git commands to Mercurial commands
265 gpg commands to sign and verify changesets
265 gpg commands to sign and verify changesets
266 hgk browse the repository in a graphical way
266 hgk browse the repository in a graphical way
267 highlight syntax highlighting for hgweb (requires Pygments)
267 highlight syntax highlighting for hgweb (requires Pygments)
268 histedit interactive history editing
268 histedit interactive history editing
269 keyword expand keywords in tracked files
269 keyword expand keywords in tracked files
270 largefiles track large binary files
270 largefiles track large binary files
271 mq manage a stack of patches
271 mq manage a stack of patches
272 notify hooks for sending email push notifications
272 notify hooks for sending email push notifications
273 patchbomb command to send changesets as (a series of) patch emails
273 patchbomb command to send changesets as (a series of) patch emails
274 purge command to delete untracked files from the working
274 purge command to delete untracked files from the working
275 directory
275 directory
276 relink recreates hardlinks between repository clones
276 relink recreates hardlinks between repository clones
277 remotenames showing remotebookmarks and remotebranches in UI
277 remotenames showing remotebookmarks and remotebranches in UI
278 schemes extend schemes with shortcuts to repository swarms
278 schemes extend schemes with shortcuts to repository swarms
279 share share a common history between several working directories
279 share share a common history between several working directories
280 shelve save and restore changes to the working directory
280 shelve save and restore changes to the working directory
281 strip strip changesets and their descendants from history
281 strip strip changesets and their descendants from history
282 transplant command to transplant changesets from another branch
282 transplant command to transplant changesets from another branch
283 win32mbcs allow the use of MBCS paths with problematic encodings
283 win32mbcs allow the use of MBCS paths with problematic encodings
284 zeroconf discover and advertise repositories on the local network
284 zeroconf discover and advertise repositories on the local network
285
285
286 Verify that extension keywords appear in help templates
286 Verify that extension keywords appear in help templates
287
287
288 $ hg help --config extensions.transplant= templating|grep transplant > /dev/null
288 $ hg help --config extensions.transplant= templating|grep transplant > /dev/null
289
289
290 Test short command list with verbose option
290 Test short command list with verbose option
291
291
292 $ hg -v help shortlist
292 $ hg -v help shortlist
293 Mercurial Distributed SCM
293 Mercurial Distributed SCM
294
294
295 basic commands:
295 basic commands:
296
296
297 add add the specified files on the next commit
297 add add the specified files on the next commit
298 annotate, blame
298 annotate, blame
299 show changeset information by line for each file
299 show changeset information by line for each file
300 clone make a copy of an existing repository
300 clone make a copy of an existing repository
301 commit, ci commit the specified files or all outstanding changes
301 commit, ci commit the specified files or all outstanding changes
302 diff diff repository (or selected files)
302 diff diff repository (or selected files)
303 export dump the header and diffs for one or more changesets
303 export dump the header and diffs for one or more changesets
304 forget forget the specified files on the next commit
304 forget forget the specified files on the next commit
305 init create a new repository in the given directory
305 init create a new repository in the given directory
306 log, history show revision history of entire repository or files
306 log, history show revision history of entire repository or files
307 merge merge another revision into working directory
307 merge merge another revision into working directory
308 pull pull changes from the specified source
308 pull pull changes from the specified source
309 push push changes to the specified destination
309 push push changes to the specified destination
310 remove, rm remove the specified files on the next commit
310 remove, rm remove the specified files on the next commit
311 serve start stand-alone webserver
311 serve start stand-alone webserver
312 status, st show changed files in the working directory
312 status, st show changed files in the working directory
313 summary, sum summarize working directory state
313 summary, sum summarize working directory state
314 update, up, checkout, co
314 update, up, checkout, co
315 update working directory (or switch revisions)
315 update working directory (or switch revisions)
316
316
317 global options ([+] can be repeated):
317 global options ([+] can be repeated):
318
318
319 -R --repository REPO repository root directory or name of overlay bundle
319 -R --repository REPO repository root directory or name of overlay bundle
320 file
320 file
321 --cwd DIR change working directory
321 --cwd DIR change working directory
322 -y --noninteractive do not prompt, automatically pick the first choice for
322 -y --noninteractive do not prompt, automatically pick the first choice for
323 all prompts
323 all prompts
324 -q --quiet suppress output
324 -q --quiet suppress output
325 -v --verbose enable additional output
325 -v --verbose enable additional output
326 --color TYPE when to colorize (boolean, always, auto, never, or
326 --color TYPE when to colorize (boolean, always, auto, never, or
327 debug)
327 debug)
328 --config CONFIG [+] set/override config option (use 'section.name=value')
328 --config CONFIG [+] set/override config option (use 'section.name=value')
329 --debug enable debugging output
329 --debug enable debugging output
330 --debugger start debugger
330 --debugger start debugger
331 --encoding ENCODE set the charset encoding (default: ascii)
331 --encoding ENCODE set the charset encoding (default: ascii)
332 --encodingmode MODE set the charset encoding mode (default: strict)
332 --encodingmode MODE set the charset encoding mode (default: strict)
333 --traceback always print a traceback on exception
333 --traceback always print a traceback on exception
334 --time time how long the command takes
334 --time time how long the command takes
335 --profile print command execution profile
335 --profile print command execution profile
336 --version output version information and exit
336 --version output version information and exit
337 -h --help display help and exit
337 -h --help display help and exit
338 --hidden consider hidden changesets
338 --hidden consider hidden changesets
339 --pager TYPE when to paginate (boolean, always, auto, or never)
339 --pager TYPE when to paginate (boolean, always, auto, or never)
340 (default: auto)
340 (default: auto)
341
341
342 (use 'hg help' for the full list of commands)
342 (use 'hg help' for the full list of commands)
343
343
344 $ hg add -h
344 $ hg add -h
345 hg add [OPTION]... [FILE]...
345 hg add [OPTION]... [FILE]...
346
346
347 add the specified files on the next commit
347 add the specified files on the next commit
348
348
349 Schedule files to be version controlled and added to the repository.
349 Schedule files to be version controlled and added to the repository.
350
350
351 The files will be added to the repository at the next commit. To undo an
351 The files will be added to the repository at the next commit. To undo an
352 add before that, see 'hg forget'.
352 add before that, see 'hg forget'.
353
353
354 If no names are given, add all files to the repository (except files
354 If no names are given, add all files to the repository (except files
355 matching ".hgignore").
355 matching ".hgignore").
356
356
357 Returns 0 if all files are successfully added.
357 Returns 0 if all files are successfully added.
358
358
359 options ([+] can be repeated):
359 options ([+] can be repeated):
360
360
361 -I --include PATTERN [+] include names matching the given patterns
361 -I --include PATTERN [+] include names matching the given patterns
362 -X --exclude PATTERN [+] exclude names matching the given patterns
362 -X --exclude PATTERN [+] exclude names matching the given patterns
363 -S --subrepos recurse into subrepositories
363 -S --subrepos recurse into subrepositories
364 -n --dry-run do not perform actions, just print output
364 -n --dry-run do not perform actions, just print output
365
365
366 (some details hidden, use --verbose to show complete help)
366 (some details hidden, use --verbose to show complete help)
367
367
368 Verbose help for add
368 Verbose help for add
369
369
370 $ hg add -hv
370 $ hg add -hv
371 hg add [OPTION]... [FILE]...
371 hg add [OPTION]... [FILE]...
372
372
373 add the specified files on the next commit
373 add the specified files on the next commit
374
374
375 Schedule files to be version controlled and added to the repository.
375 Schedule files to be version controlled and added to the repository.
376
376
377 The files will be added to the repository at the next commit. To undo an
377 The files will be added to the repository at the next commit. To undo an
378 add before that, see 'hg forget'.
378 add before that, see 'hg forget'.
379
379
380 If no names are given, add all files to the repository (except files
380 If no names are given, add all files to the repository (except files
381 matching ".hgignore").
381 matching ".hgignore").
382
382
383 Examples:
383 Examples:
384
384
385 - New (unknown) files are added automatically by 'hg add':
385 - New (unknown) files are added automatically by 'hg add':
386
386
387 $ ls
387 $ ls
388 foo.c
388 foo.c
389 $ hg status
389 $ hg status
390 ? foo.c
390 ? foo.c
391 $ hg add
391 $ hg add
392 adding foo.c
392 adding foo.c
393 $ hg status
393 $ hg status
394 A foo.c
394 A foo.c
395
395
396 - Specific files to be added can be specified:
396 - Specific files to be added can be specified:
397
397
398 $ ls
398 $ ls
399 bar.c foo.c
399 bar.c foo.c
400 $ hg status
400 $ hg status
401 ? bar.c
401 ? bar.c
402 ? foo.c
402 ? foo.c
403 $ hg add bar.c
403 $ hg add bar.c
404 $ hg status
404 $ hg status
405 A bar.c
405 A bar.c
406 ? foo.c
406 ? foo.c
407
407
408 Returns 0 if all files are successfully added.
408 Returns 0 if all files are successfully added.
409
409
410 options ([+] can be repeated):
410 options ([+] can be repeated):
411
411
412 -I --include PATTERN [+] include names matching the given patterns
412 -I --include PATTERN [+] include names matching the given patterns
413 -X --exclude PATTERN [+] exclude names matching the given patterns
413 -X --exclude PATTERN [+] exclude names matching the given patterns
414 -S --subrepos recurse into subrepositories
414 -S --subrepos recurse into subrepositories
415 -n --dry-run do not perform actions, just print output
415 -n --dry-run do not perform actions, just print output
416
416
417 global options ([+] can be repeated):
417 global options ([+] can be repeated):
418
418
419 -R --repository REPO repository root directory or name of overlay bundle
419 -R --repository REPO repository root directory or name of overlay bundle
420 file
420 file
421 --cwd DIR change working directory
421 --cwd DIR change working directory
422 -y --noninteractive do not prompt, automatically pick the first choice for
422 -y --noninteractive do not prompt, automatically pick the first choice for
423 all prompts
423 all prompts
424 -q --quiet suppress output
424 -q --quiet suppress output
425 -v --verbose enable additional output
425 -v --verbose enable additional output
426 --color TYPE when to colorize (boolean, always, auto, never, or
426 --color TYPE when to colorize (boolean, always, auto, never, or
427 debug)
427 debug)
428 --config CONFIG [+] set/override config option (use 'section.name=value')
428 --config CONFIG [+] set/override config option (use 'section.name=value')
429 --debug enable debugging output
429 --debug enable debugging output
430 --debugger start debugger
430 --debugger start debugger
431 --encoding ENCODE set the charset encoding (default: ascii)
431 --encoding ENCODE set the charset encoding (default: ascii)
432 --encodingmode MODE set the charset encoding mode (default: strict)
432 --encodingmode MODE set the charset encoding mode (default: strict)
433 --traceback always print a traceback on exception
433 --traceback always print a traceback on exception
434 --time time how long the command takes
434 --time time how long the command takes
435 --profile print command execution profile
435 --profile print command execution profile
436 --version output version information and exit
436 --version output version information and exit
437 -h --help display help and exit
437 -h --help display help and exit
438 --hidden consider hidden changesets
438 --hidden consider hidden changesets
439 --pager TYPE when to paginate (boolean, always, auto, or never)
439 --pager TYPE when to paginate (boolean, always, auto, or never)
440 (default: auto)
440 (default: auto)
441
441
442 Test the textwidth config option
442 Test the textwidth config option
443
443
444 $ hg root -h --config ui.textwidth=50
444 $ hg root -h --config ui.textwidth=50
445 hg root
445 hg root
446
446
447 print the root (top) of the current working
447 print the root (top) of the current working
448 directory
448 directory
449
449
450 Print the root directory of the current
450 Print the root directory of the current
451 repository.
451 repository.
452
452
453 Returns 0 on success.
453 Returns 0 on success.
454
454
455 (some details hidden, use --verbose to show
455 (some details hidden, use --verbose to show
456 complete help)
456 complete help)
457
457
458 Test help option with version option
458 Test help option with version option
459
459
460 $ hg add -h --version
460 $ hg add -h --version
461 Mercurial Distributed SCM (version *) (glob)
461 Mercurial Distributed SCM (version *) (glob)
462 (see https://mercurial-scm.org for more information)
462 (see https://mercurial-scm.org for more information)
463
463
464 Copyright (C) 2005-* Matt Mackall and others (glob)
464 Copyright (C) 2005-* Matt Mackall and others (glob)
465 This is free software; see the source for copying conditions. There is NO
465 This is free software; see the source for copying conditions. There is NO
466 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
466 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
467
467
468 $ hg add --skjdfks
468 $ hg add --skjdfks
469 hg add: option --skjdfks not recognized
469 hg add: option --skjdfks not recognized
470 hg add [OPTION]... [FILE]...
470 hg add [OPTION]... [FILE]...
471
471
472 add the specified files on the next commit
472 add the specified files on the next commit
473
473
474 options ([+] can be repeated):
474 options ([+] can be repeated):
475
475
476 -I --include PATTERN [+] include names matching the given patterns
476 -I --include PATTERN [+] include names matching the given patterns
477 -X --exclude PATTERN [+] exclude names matching the given patterns
477 -X --exclude PATTERN [+] exclude names matching the given patterns
478 -S --subrepos recurse into subrepositories
478 -S --subrepos recurse into subrepositories
479 -n --dry-run do not perform actions, just print output
479 -n --dry-run do not perform actions, just print output
480
480
481 (use 'hg add -h' to show more help)
481 (use 'hg add -h' to show more help)
482 [255]
482 [255]
483
483
484 Test ambiguous command help
484 Test ambiguous command help
485
485
486 $ hg help ad
486 $ hg help ad
487 list of commands:
487 list of commands:
488
488
489 add add the specified files on the next commit
489 add add the specified files on the next commit
490 addremove add all new files, delete all missing files
490 addremove add all new files, delete all missing files
491
491
492 (use 'hg help -v ad' to show built-in aliases and global options)
492 (use 'hg help -v ad' to show built-in aliases and global options)
493
493
494 Test command without options
494 Test command without options
495
495
496 $ hg help verify
496 $ hg help verify
497 hg verify
497 hg verify
498
498
499 verify the integrity of the repository
499 verify the integrity of the repository
500
500
501 Verify the integrity of the current repository.
501 Verify the integrity of the current repository.
502
502
503 This will perform an extensive check of the repository's integrity,
503 This will perform an extensive check of the repository's integrity,
504 validating the hashes and checksums of each entry in the changelog,
504 validating the hashes and checksums of each entry in the changelog,
505 manifest, and tracked files, as well as the integrity of their crosslinks
505 manifest, and tracked files, as well as the integrity of their crosslinks
506 and indices.
506 and indices.
507
507
508 Please see https://mercurial-scm.org/wiki/RepositoryCorruption for more
508 Please see https://mercurial-scm.org/wiki/RepositoryCorruption for more
509 information about recovery from corruption of the repository.
509 information about recovery from corruption of the repository.
510
510
511 Returns 0 on success, 1 if errors are encountered.
511 Returns 0 on success, 1 if errors are encountered.
512
512
513 (some details hidden, use --verbose to show complete help)
513 (some details hidden, use --verbose to show complete help)
514
514
515 $ hg help diff
515 $ hg help diff
516 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
516 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
517
517
518 diff repository (or selected files)
518 diff repository (or selected files)
519
519
520 Show differences between revisions for the specified files.
520 Show differences between revisions for the specified files.
521
521
522 Differences between files are shown using the unified diff format.
522 Differences between files are shown using the unified diff format.
523
523
524 Note:
524 Note:
525 'hg diff' may generate unexpected results for merges, as it will
525 'hg diff' may generate unexpected results for merges, as it will
526 default to comparing against the working directory's first parent
526 default to comparing against the working directory's first parent
527 changeset if no revisions are specified.
527 changeset if no revisions are specified.
528
528
529 When two revision arguments are given, then changes are shown between
529 When two revision arguments are given, then changes are shown between
530 those revisions. If only one revision is specified then that revision is
530 those revisions. If only one revision is specified then that revision is
531 compared to the working directory, and, when no revisions are specified,
531 compared to the working directory, and, when no revisions are specified,
532 the working directory files are compared to its first parent.
532 the working directory files are compared to its first parent.
533
533
534 Alternatively you can specify -c/--change with a revision to see the
534 Alternatively you can specify -c/--change with a revision to see the
535 changes in that changeset relative to its first parent.
535 changes in that changeset relative to its first parent.
536
536
537 Without the -a/--text option, diff will avoid generating diffs of files it
537 Without the -a/--text option, diff will avoid generating diffs of files it
538 detects as binary. With -a, diff will generate a diff anyway, probably
538 detects as binary. With -a, diff will generate a diff anyway, probably
539 with undesirable results.
539 with undesirable results.
540
540
541 Use the -g/--git option to generate diffs in the git extended diff format.
541 Use the -g/--git option to generate diffs in the git extended diff format.
542 For more information, read 'hg help diffs'.
542 For more information, read 'hg help diffs'.
543
543
544 Returns 0 on success.
544 Returns 0 on success.
545
545
546 options ([+] can be repeated):
546 options ([+] can be repeated):
547
547
548 -r --rev REV [+] revision
548 -r --rev REV [+] revision
549 -c --change REV change made by revision
549 -c --change REV change made by revision
550 -a --text treat all files as text
550 -a --text treat all files as text
551 -g --git use git extended diff format
551 -g --git use git extended diff format
552 --binary generate binary diffs in git mode (default)
552 --binary generate binary diffs in git mode (default)
553 --nodates omit dates from diff headers
553 --nodates omit dates from diff headers
554 --noprefix omit a/ and b/ prefixes from filenames
554 --noprefix omit a/ and b/ prefixes from filenames
555 -p --show-function show which function each change is in
555 -p --show-function show which function each change is in
556 --reverse produce a diff that undoes the changes
556 --reverse produce a diff that undoes the changes
557 -w --ignore-all-space ignore white space when comparing lines
557 -w --ignore-all-space ignore white space when comparing lines
558 -b --ignore-space-change ignore changes in the amount of white space
558 -b --ignore-space-change ignore changes in the amount of white space
559 -B --ignore-blank-lines ignore changes whose lines are all blank
559 -B --ignore-blank-lines ignore changes whose lines are all blank
560 -Z --ignore-space-at-eol ignore changes in whitespace at EOL
560 -Z --ignore-space-at-eol ignore changes in whitespace at EOL
561 -U --unified NUM number of lines of context to show
561 -U --unified NUM number of lines of context to show
562 --stat output diffstat-style summary of changes
562 --stat output diffstat-style summary of changes
563 --root DIR produce diffs relative to subdirectory
563 --root DIR produce diffs relative to subdirectory
564 -I --include PATTERN [+] include names matching the given patterns
564 -I --include PATTERN [+] include names matching the given patterns
565 -X --exclude PATTERN [+] exclude names matching the given patterns
565 -X --exclude PATTERN [+] exclude names matching the given patterns
566 -S --subrepos recurse into subrepositories
566 -S --subrepos recurse into subrepositories
567
567
568 (some details hidden, use --verbose to show complete help)
568 (some details hidden, use --verbose to show complete help)
569
569
570 $ hg help status
570 $ hg help status
571 hg status [OPTION]... [FILE]...
571 hg status [OPTION]... [FILE]...
572
572
573 aliases: st
573 aliases: st
574
574
575 show changed files in the working directory
575 show changed files in the working directory
576
576
577 Show status of files in the repository. If names are given, only files
577 Show status of files in the repository. If names are given, only files
578 that match are shown. Files that are clean or ignored or the source of a
578 that match are shown. Files that are clean or ignored or the source of a
579 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
579 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
580 -C/--copies or -A/--all are given. Unless options described with "show
580 -C/--copies or -A/--all are given. Unless options described with "show
581 only ..." are given, the options -mardu are used.
581 only ..." are given, the options -mardu are used.
582
582
583 Option -q/--quiet hides untracked (unknown and ignored) files unless
583 Option -q/--quiet hides untracked (unknown and ignored) files unless
584 explicitly requested with -u/--unknown or -i/--ignored.
584 explicitly requested with -u/--unknown or -i/--ignored.
585
585
586 Note:
586 Note:
587 'hg status' may appear to disagree with diff if permissions have
587 'hg status' may appear to disagree with diff if permissions have
588 changed or a merge has occurred. The standard diff format does not
588 changed or a merge has occurred. The standard diff format does not
589 report permission changes and diff only reports changes relative to one
589 report permission changes and diff only reports changes relative to one
590 merge parent.
590 merge parent.
591
591
592 If one revision is given, it is used as the base revision. If two
592 If one revision is given, it is used as the base revision. If two
593 revisions are given, the differences between them are shown. The --change
593 revisions are given, the differences between them are shown. The --change
594 option can also be used as a shortcut to list the changed files of a
594 option can also be used as a shortcut to list the changed files of a
595 revision from its first parent.
595 revision from its first parent.
596
596
597 The codes used to show the status of files are:
597 The codes used to show the status of files are:
598
598
599 M = modified
599 M = modified
600 A = added
600 A = added
601 R = removed
601 R = removed
602 C = clean
602 C = clean
603 ! = missing (deleted by non-hg command, but still tracked)
603 ! = missing (deleted by non-hg command, but still tracked)
604 ? = not tracked
604 ? = not tracked
605 I = ignored
605 I = ignored
606 = origin of the previous file (with --copies)
606 = origin of the previous file (with --copies)
607
607
608 Returns 0 on success.
608 Returns 0 on success.
609
609
610 options ([+] can be repeated):
610 options ([+] can be repeated):
611
611
612 -A --all show status of all files
612 -A --all show status of all files
613 -m --modified show only modified files
613 -m --modified show only modified files
614 -a --added show only added files
614 -a --added show only added files
615 -r --removed show only removed files
615 -r --removed show only removed files
616 -d --deleted show only deleted (but tracked) files
616 -d --deleted show only deleted (but tracked) files
617 -c --clean show only files without changes
617 -c --clean show only files without changes
618 -u --unknown show only unknown (not tracked) files
618 -u --unknown show only unknown (not tracked) files
619 -i --ignored show only ignored files
619 -i --ignored show only ignored files
620 -n --no-status hide status prefix
620 -n --no-status hide status prefix
621 -C --copies show source of copied files
621 -C --copies show source of copied files
622 -0 --print0 end filenames with NUL, for use with xargs
622 -0 --print0 end filenames with NUL, for use with xargs
623 --rev REV [+] show difference from revision
623 --rev REV [+] show difference from revision
624 --change REV list the changed files of a revision
624 --change REV list the changed files of a revision
625 -I --include PATTERN [+] include names matching the given patterns
625 -I --include PATTERN [+] include names matching the given patterns
626 -X --exclude PATTERN [+] exclude names matching the given patterns
626 -X --exclude PATTERN [+] exclude names matching the given patterns
627 -S --subrepos recurse into subrepositories
627 -S --subrepos recurse into subrepositories
628
628
629 (some details hidden, use --verbose to show complete help)
629 (some details hidden, use --verbose to show complete help)
630
630
631 $ hg -q help status
631 $ hg -q help status
632 hg status [OPTION]... [FILE]...
632 hg status [OPTION]... [FILE]...
633
633
634 show changed files in the working directory
634 show changed files in the working directory
635
635
636 $ hg help foo
636 $ hg help foo
637 abort: no such help topic: foo
637 abort: no such help topic: foo
638 (try 'hg help --keyword foo')
638 (try 'hg help --keyword foo')
639 [255]
639 [255]
640
640
641 $ hg skjdfks
641 $ hg skjdfks
642 hg: unknown command 'skjdfks'
642 hg: unknown command 'skjdfks'
643 Mercurial Distributed SCM
643 Mercurial Distributed SCM
644
644
645 basic commands:
645 basic commands:
646
646
647 add add the specified files on the next commit
647 add add the specified files on the next commit
648 annotate show changeset information by line for each file
648 annotate show changeset information by line for each file
649 clone make a copy of an existing repository
649 clone make a copy of an existing repository
650 commit commit the specified files or all outstanding changes
650 commit commit the specified files or all outstanding changes
651 diff diff repository (or selected files)
651 diff diff repository (or selected files)
652 export dump the header and diffs for one or more changesets
652 export dump the header and diffs for one or more changesets
653 forget forget the specified files on the next commit
653 forget forget the specified files on the next commit
654 init create a new repository in the given directory
654 init create a new repository in the given directory
655 log show revision history of entire repository or files
655 log show revision history of entire repository or files
656 merge merge another revision into working directory
656 merge merge another revision into working directory
657 pull pull changes from the specified source
657 pull pull changes from the specified source
658 push push changes to the specified destination
658 push push changes to the specified destination
659 remove remove the specified files on the next commit
659 remove remove the specified files on the next commit
660 serve start stand-alone webserver
660 serve start stand-alone webserver
661 status show changed files in the working directory
661 status show changed files in the working directory
662 summary summarize working directory state
662 summary summarize working directory state
663 update update working directory (or switch revisions)
663 update update working directory (or switch revisions)
664
664
665 (use 'hg help' for the full list of commands or 'hg -v' for details)
665 (use 'hg help' for the full list of commands or 'hg -v' for details)
666 [255]
666 [255]
667
667
668 Typoed command gives suggestion
668 Typoed command gives suggestion
669 $ hg puls
669 $ hg puls
670 hg: unknown command 'puls'
670 hg: unknown command 'puls'
671 (did you mean one of pull, push?)
671 (did you mean one of pull, push?)
672 [255]
672 [255]
673
673
674 Not enabled extension gets suggested
674 Not enabled extension gets suggested
675
675
676 $ hg rebase
676 $ hg rebase
677 hg: unknown command 'rebase'
677 hg: unknown command 'rebase'
678 'rebase' is provided by the following extension:
678 'rebase' is provided by the following extension:
679
679
680 rebase command to move sets of revisions to a different ancestor
680 rebase command to move sets of revisions to a different ancestor
681
681
682 (use 'hg help extensions' for information on enabling extensions)
682 (use 'hg help extensions' for information on enabling extensions)
683 [255]
683 [255]
684
684
685 Disabled extension gets suggested
685 Disabled extension gets suggested
686 $ hg --config extensions.rebase=! rebase
686 $ hg --config extensions.rebase=! rebase
687 hg: unknown command 'rebase'
687 hg: unknown command 'rebase'
688 'rebase' is provided by the following extension:
688 'rebase' is provided by the following extension:
689
689
690 rebase command to move sets of revisions to a different ancestor
690 rebase command to move sets of revisions to a different ancestor
691
691
692 (use 'hg help extensions' for information on enabling extensions)
692 (use 'hg help extensions' for information on enabling extensions)
693 [255]
693 [255]
694
694
695 Make sure that we don't run afoul of the help system thinking that
695 Make sure that we don't run afoul of the help system thinking that
696 this is a section and erroring out weirdly.
696 this is a section and erroring out weirdly.
697
697
698 $ hg .log
698 $ hg .log
699 hg: unknown command '.log'
699 hg: unknown command '.log'
700 (did you mean log?)
700 (did you mean log?)
701 [255]
701 [255]
702
702
703 $ hg log.
703 $ hg log.
704 hg: unknown command 'log.'
704 hg: unknown command 'log.'
705 (did you mean log?)
705 (did you mean log?)
706 [255]
706 [255]
707 $ hg pu.lh
707 $ hg pu.lh
708 hg: unknown command 'pu.lh'
708 hg: unknown command 'pu.lh'
709 (did you mean one of pull, push?)
709 (did you mean one of pull, push?)
710 [255]
710 [255]
711
711
712 $ cat > helpext.py <<EOF
712 $ cat > helpext.py <<EOF
713 > import os
713 > import os
714 > from mercurial import commands, registrar
714 > from mercurial import commands, registrar
715 >
715 >
716 > cmdtable = {}
716 > cmdtable = {}
717 > command = registrar.command(cmdtable)
717 > command = registrar.command(cmdtable)
718 >
718 >
719 > @command(b'nohelp',
719 > @command(b'nohelp',
720 > [(b'', b'longdesc', 3, b'x'*90),
720 > [(b'', b'longdesc', 3, b'x'*90),
721 > (b'n', b'', None, b'normal desc'),
721 > (b'n', b'', None, b'normal desc'),
722 > (b'', b'newline', b'', b'line1\nline2')],
722 > (b'', b'newline', b'', b'line1\nline2')],
723 > b'hg nohelp',
723 > b'hg nohelp',
724 > norepo=True)
724 > norepo=True)
725 > @command(b'debugoptADV', [(b'', b'aopt', None, b'option is (ADVANCED)')])
725 > @command(b'debugoptADV', [(b'', b'aopt', None, b'option is (ADVANCED)')])
726 > @command(b'debugoptDEP', [(b'', b'dopt', None, b'option is (DEPRECATED)')])
726 > @command(b'debugoptDEP', [(b'', b'dopt', None, b'option is (DEPRECATED)')])
727 > @command(b'debugoptEXP', [(b'', b'eopt', None, b'option is (EXPERIMENTAL)')])
727 > @command(b'debugoptEXP', [(b'', b'eopt', None, b'option is (EXPERIMENTAL)')])
728 > def nohelp(ui, *args, **kwargs):
728 > def nohelp(ui, *args, **kwargs):
729 > pass
729 > pass
730 >
730 >
731 > def uisetup(ui):
731 > def uisetup(ui):
732 > ui.setconfig(b'alias', b'shellalias', b'!echo hi', b'helpext')
732 > ui.setconfig(b'alias', b'shellalias', b'!echo hi', b'helpext')
733 > ui.setconfig(b'alias', b'hgalias', b'summary', b'helpext')
733 > ui.setconfig(b'alias', b'hgalias', b'summary', b'helpext')
734 >
734 >
735 > EOF
735 > EOF
736 $ echo '[extensions]' >> $HGRCPATH
736 $ echo '[extensions]' >> $HGRCPATH
737 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
737 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
738
738
739 Test for aliases
739 Test for aliases
740
740
741 $ hg help hgalias
741 $ hg help hgalias
742 hg hgalias [--remote]
742 hg hgalias [--remote]
743
743
744 alias for: hg summary
744 alias for: hg summary
745
745
746 summarize working directory state
746 summarize working directory state
747
747
748 This generates a brief summary of the working directory state, including
748 This generates a brief summary of the working directory state, including
749 parents, branch, commit status, phase and available updates.
749 parents, branch, commit status, phase and available updates.
750
750
751 With the --remote option, this will check the default paths for incoming
751 With the --remote option, this will check the default paths for incoming
752 and outgoing changes. This can be time-consuming.
752 and outgoing changes. This can be time-consuming.
753
753
754 Returns 0 on success.
754 Returns 0 on success.
755
755
756 defined by: helpext
756 defined by: helpext
757
757
758 options:
758 options:
759
759
760 --remote check for push and pull
760 --remote check for push and pull
761
761
762 (some details hidden, use --verbose to show complete help)
762 (some details hidden, use --verbose to show complete help)
763
763
764 $ hg help shellalias
764 $ hg help shellalias
765 hg shellalias
765 hg shellalias
766
766
767 shell alias for:
767 shell alias for:
768
768
769 echo hi
769 echo hi
770
770
771 defined by: helpext
771 defined by: helpext
772
772
773 (some details hidden, use --verbose to show complete help)
773 (some details hidden, use --verbose to show complete help)
774
774
775 Test command with no help text
775 Test command with no help text
776
776
777 $ hg help nohelp
777 $ hg help nohelp
778 hg nohelp
778 hg nohelp
779
779
780 (no help text available)
780 (no help text available)
781
781
782 options:
782 options:
783
783
784 --longdesc VALUE xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
784 --longdesc VALUE xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
785 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (default: 3)
785 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (default: 3)
786 -n -- normal desc
786 -n -- normal desc
787 --newline VALUE line1 line2
787 --newline VALUE line1 line2
788
788
789 (some details hidden, use --verbose to show complete help)
789 (some details hidden, use --verbose to show complete help)
790
790
791 $ hg help -k nohelp
791 $ hg help -k nohelp
792 Commands:
792 Commands:
793
793
794 nohelp hg nohelp
794 nohelp hg nohelp
795
795
796 Extension Commands:
796 Extension Commands:
797
797
798 nohelp (no help text available)
798 nohelp (no help text available)
799
799
800 Test that default list of commands omits extension commands
800 Test that default list of commands omits extension commands
801
801
802 $ hg help
802 $ hg help
803 Mercurial Distributed SCM
803 Mercurial Distributed SCM
804
804
805 list of commands:
805 list of commands:
806
806
807 add add the specified files on the next commit
807 add add the specified files on the next commit
808 addremove add all new files, delete all missing files
808 addremove add all new files, delete all missing files
809 annotate show changeset information by line for each file
809 annotate show changeset information by line for each file
810 archive create an unversioned archive of a repository revision
810 archive create an unversioned archive of a repository revision
811 backout reverse effect of earlier changeset
811 backout reverse effect of earlier changeset
812 bisect subdivision search of changesets
812 bisect subdivision search of changesets
813 bookmarks create a new bookmark or list existing bookmarks
813 bookmarks create a new bookmark or list existing bookmarks
814 branch set or show the current branch name
814 branch set or show the current branch name
815 branches list repository named branches
815 branches list repository named branches
816 bundle create a bundle file
816 bundle create a bundle file
817 cat output the current or given revision of files
817 cat output the current or given revision of files
818 clone make a copy of an existing repository
818 clone make a copy of an existing repository
819 commit commit the specified files or all outstanding changes
819 commit commit the specified files or all outstanding changes
820 config show combined config settings from all hgrc files
820 config show combined config settings from all hgrc files
821 copy mark files as copied for the next commit
821 copy mark files as copied for the next commit
822 diff diff repository (or selected files)
822 diff diff repository (or selected files)
823 export dump the header and diffs for one or more changesets
823 export dump the header and diffs for one or more changesets
824 files list tracked files
824 files list tracked files
825 forget forget the specified files on the next commit
825 forget forget the specified files on the next commit
826 graft copy changes from other branches onto the current branch
826 graft copy changes from other branches onto the current branch
827 grep search revision history for a pattern in specified files
827 grep search revision history for a pattern in specified files
828 heads show branch heads
828 heads show branch heads
829 help show help for a given topic or a help overview
829 help show help for a given topic or a help overview
830 identify identify the working directory or specified revision
830 identify identify the working directory or specified revision
831 import import an ordered set of patches
831 import import an ordered set of patches
832 incoming show new changesets found in source
832 incoming show new changesets found in source
833 init create a new repository in the given directory
833 init create a new repository in the given directory
834 log show revision history of entire repository or files
834 log show revision history of entire repository or files
835 manifest output the current or given revision of the project manifest
835 manifest output the current or given revision of the project manifest
836 merge merge another revision into working directory
836 merge merge another revision into working directory
837 outgoing show changesets not found in the destination
837 outgoing show changesets not found in the destination
838 paths show aliases for remote repositories
838 paths show aliases for remote repositories
839 phase set or show the current phase name
839 phase set or show the current phase name
840 pull pull changes from the specified source
840 pull pull changes from the specified source
841 push push changes to the specified destination
841 push push changes to the specified destination
842 recover roll back an interrupted transaction
842 recover roll back an interrupted transaction
843 remove remove the specified files on the next commit
843 remove remove the specified files on the next commit
844 rename rename files; equivalent of copy + remove
844 rename rename files; equivalent of copy + remove
845 resolve redo merges or set/view the merge status of files
845 resolve redo merges or set/view the merge status of files
846 revert restore files to their checkout state
846 revert restore files to their checkout state
847 root print the root (top) of the current working directory
847 root print the root (top) of the current working directory
848 serve start stand-alone webserver
848 serve start stand-alone webserver
849 status show changed files in the working directory
849 status show changed files in the working directory
850 summary summarize working directory state
850 summary summarize working directory state
851 tag add one or more tags for the current or given revision
851 tag add one or more tags for the current or given revision
852 tags list repository tags
852 tags list repository tags
853 unbundle apply one or more bundle files
853 unbundle apply one or more bundle files
854 update update working directory (or switch revisions)
854 update update working directory (or switch revisions)
855 verify verify the integrity of the repository
855 verify verify the integrity of the repository
856 version output version and copyright information
856 version output version and copyright information
857
857
858 enabled extensions:
858 enabled extensions:
859
859
860 helpext (no help text available)
860 helpext (no help text available)
861
861
862 additional help topics:
862 additional help topics:
863
863
864 bundlespec Bundle File Formats
864 bundlespec Bundle File Formats
865 color Colorizing Outputs
865 color Colorizing Outputs
866 config Configuration Files
866 config Configuration Files
867 dates Date Formats
867 dates Date Formats
868 diffs Diff Formats
868 diffs Diff Formats
869 environment Environment Variables
869 environment Environment Variables
870 extensions Using Additional Features
870 extensions Using Additional Features
871 filesets Specifying File Sets
871 filesets Specifying File Sets
872 flags Command-line flags
872 flags Command-line flags
873 glossary Glossary
873 glossary Glossary
874 hgignore Syntax for Mercurial Ignore Files
874 hgignore Syntax for Mercurial Ignore Files
875 hgweb Configuring hgweb
875 hgweb Configuring hgweb
876 internals Technical implementation topics
876 internals Technical implementation topics
877 merge-tools Merge Tools
877 merge-tools Merge Tools
878 pager Pager Support
878 pager Pager Support
879 patterns File Name Patterns
879 patterns File Name Patterns
880 phases Working with Phases
880 phases Working with Phases
881 revisions Specifying Revisions
881 revisions Specifying Revisions
882 scripting Using Mercurial from scripts and automation
882 scripting Using Mercurial from scripts and automation
883 subrepos Subrepositories
883 subrepos Subrepositories
884 templating Template Usage
884 templating Template Usage
885 urls URL Paths
885 urls URL Paths
886
886
887 (use 'hg help -v' to show built-in aliases and global options)
887 (use 'hg help -v' to show built-in aliases and global options)
888
888
889
889
890 Test list of internal help commands
890 Test list of internal help commands
891
891
892 $ hg help debug
892 $ hg help debug
893 debug commands (internal and unsupported):
893 debug commands (internal and unsupported):
894
894
895 debugancestor
895 debugancestor
896 find the ancestor revision of two revisions in a given index
896 find the ancestor revision of two revisions in a given index
897 debugapplystreamclonebundle
897 debugapplystreamclonebundle
898 apply a stream clone bundle file
898 apply a stream clone bundle file
899 debugbuilddag
899 debugbuilddag
900 builds a repo with a given DAG from scratch in the current
900 builds a repo with a given DAG from scratch in the current
901 empty repo
901 empty repo
902 debugbundle lists the contents of a bundle
902 debugbundle lists the contents of a bundle
903 debugcapabilities
903 debugcapabilities
904 lists the capabilities of a remote peer
904 lists the capabilities of a remote peer
905 debugcheckstate
905 debugcheckstate
906 validate the correctness of the current dirstate
906 validate the correctness of the current dirstate
907 debugcolor show available color, effects or style
907 debugcolor show available color, effects or style
908 debugcommands
908 debugcommands
909 list all available commands and options
909 list all available commands and options
910 debugcomplete
910 debugcomplete
911 returns the completion list associated with the given command
911 returns the completion list associated with the given command
912 debugcreatestreamclonebundle
912 debugcreatestreamclonebundle
913 create a stream clone bundle file
913 create a stream clone bundle file
914 debugdag format the changelog or an index DAG as a concise textual
914 debugdag format the changelog or an index DAG as a concise textual
915 description
915 description
916 debugdata dump the contents of a data file revision
916 debugdata dump the contents of a data file revision
917 debugdate parse and display a date
917 debugdate parse and display a date
918 debugdeltachain
918 debugdeltachain
919 dump information about delta chains in a revlog
919 dump information about delta chains in a revlog
920 debugdirstate
920 debugdirstate
921 show the contents of the current dirstate
921 show the contents of the current dirstate
922 debugdiscovery
922 debugdiscovery
923 runs the changeset discovery protocol in isolation
923 runs the changeset discovery protocol in isolation
924 debugdownload
924 debugdownload
925 download a resource using Mercurial logic and config
925 download a resource using Mercurial logic and config
926 debugextensions
926 debugextensions
927 show information about active extensions
927 show information about active extensions
928 debugfileset parse and apply a fileset specification
928 debugfileset parse and apply a fileset specification
929 debugformat display format information about the current repository
929 debugformat display format information about the current repository
930 debugfsinfo show information detected about current filesystem
930 debugfsinfo show information detected about current filesystem
931 debuggetbundle
931 debuggetbundle
932 retrieves a bundle from a repo
932 retrieves a bundle from a repo
933 debugignore display the combined ignore pattern and information about
933 debugignore display the combined ignore pattern and information about
934 ignored files
934 ignored files
935 debugindex dump the contents of an index file
935 debugindex dump the contents of an index file
936 debugindexdot
936 debugindexdot
937 dump an index DAG as a graphviz dot file
937 dump an index DAG as a graphviz dot file
938 debuginstall test Mercurial installation
938 debuginstall test Mercurial installation
939 debugknown test whether node ids are known to a repo
939 debugknown test whether node ids are known to a repo
940 debuglocks show or modify state of locks
940 debuglocks show or modify state of locks
941 debugmergestate
941 debugmergestate
942 print merge state
942 print merge state
943 debugnamecomplete
943 debugnamecomplete
944 complete "names" - tags, open branch names, bookmark names
944 complete "names" - tags, open branch names, bookmark names
945 debugobsolete
945 debugobsolete
946 create arbitrary obsolete marker
946 create arbitrary obsolete marker
947 debugoptADV (no help text available)
947 debugoptADV (no help text available)
948 debugoptDEP (no help text available)
948 debugoptDEP (no help text available)
949 debugoptEXP (no help text available)
949 debugoptEXP (no help text available)
950 debugpathcomplete
950 debugpathcomplete
951 complete part or all of a tracked path
951 complete part or all of a tracked path
952 debugpeer establish a connection to a peer repository
952 debugpeer establish a connection to a peer repository
953 debugpickmergetool
953 debugpickmergetool
954 examine which merge tool is chosen for specified file
954 examine which merge tool is chosen for specified file
955 debugpushkey access the pushkey key/value protocol
955 debugpushkey access the pushkey key/value protocol
956 debugpvec (no help text available)
956 debugpvec (no help text available)
957 debugrebuilddirstate
957 debugrebuilddirstate
958 rebuild the dirstate as it would look like for the given
958 rebuild the dirstate as it would look like for the given
959 revision
959 revision
960 debugrebuildfncache
960 debugrebuildfncache
961 rebuild the fncache file
961 rebuild the fncache file
962 debugrename dump rename information
962 debugrename dump rename information
963 debugrevlog show data and statistics about a revlog
963 debugrevlog show data and statistics about a revlog
964 debugrevspec parse and apply a revision specification
964 debugrevspec parse and apply a revision specification
965 debugsetparents
965 debugsetparents
966 manually set the parents of the current working directory
966 manually set the parents of the current working directory
967 debugssl test a secure connection to a server
967 debugssl test a secure connection to a server
968 debugsub (no help text available)
968 debugsub (no help text available)
969 debugsuccessorssets
969 debugsuccessorssets
970 show set of successors for revision
970 show set of successors for revision
971 debugtemplate
971 debugtemplate
972 parse and apply a template
972 parse and apply a template
973 debugupdatecaches
973 debugupdatecaches
974 warm all known caches in the repository
974 warm all known caches in the repository
975 debugupgraderepo
975 debugupgraderepo
976 upgrade a repository to use different features
976 upgrade a repository to use different features
977 debugwalk show how files match on given patterns
977 debugwalk show how files match on given patterns
978 debugwireargs
978 debugwireargs
979 (no help text available)
979 (no help text available)
980
980
981 (use 'hg help -v debug' to show built-in aliases and global options)
981 (use 'hg help -v debug' to show built-in aliases and global options)
982
982
983 internals topic renders index of available sub-topics
983 internals topic renders index of available sub-topics
984
984
985 $ hg help internals
985 $ hg help internals
986 Technical implementation topics
986 Technical implementation topics
987 """""""""""""""""""""""""""""""
987 """""""""""""""""""""""""""""""
988
988
989 To access a subtopic, use "hg help internals.{subtopic-name}"
989 To access a subtopic, use "hg help internals.{subtopic-name}"
990
990
991 bundles Bundles
991 bundles Bundles
992 censor Censor
992 censor Censor
993 changegroups Changegroups
993 changegroups Changegroups
994 config Config Registrar
994 config Config Registrar
995 requirements Repository Requirements
995 requirements Repository Requirements
996 revlogs Revision Logs
996 revlogs Revision Logs
997 wireprotocol Wire Protocol
997 wireprotocol Wire Protocol
998
998
999 sub-topics can be accessed
999 sub-topics can be accessed
1000
1000
1001 $ hg help internals.changegroups
1001 $ hg help internals.changegroups
1002 Changegroups
1002 Changegroups
1003 """"""""""""
1003 """"""""""""
1004
1004
1005 Changegroups are representations of repository revlog data, specifically
1005 Changegroups are representations of repository revlog data, specifically
1006 the changelog data, root/flat manifest data, treemanifest data, and
1006 the changelog data, root/flat manifest data, treemanifest data, and
1007 filelogs.
1007 filelogs.
1008
1008
1009 There are 3 versions of changegroups: "1", "2", and "3". From a high-
1009 There are 3 versions of changegroups: "1", "2", and "3". From a high-
1010 level, versions "1" and "2" are almost exactly the same, with the only
1010 level, versions "1" and "2" are almost exactly the same, with the only
1011 difference being an additional item in the *delta header*. Version "3"
1011 difference being an additional item in the *delta header*. Version "3"
1012 adds support for revlog flags in the *delta header* and optionally
1012 adds support for revlog flags in the *delta header* and optionally
1013 exchanging treemanifests (enabled by setting an option on the
1013 exchanging treemanifests (enabled by setting an option on the
1014 "changegroup" part in the bundle2).
1014 "changegroup" part in the bundle2).
1015
1015
1016 Changegroups when not exchanging treemanifests consist of 3 logical
1016 Changegroups when not exchanging treemanifests consist of 3 logical
1017 segments:
1017 segments:
1018
1018
1019 +---------------------------------+
1019 +---------------------------------+
1020 | | | |
1020 | | | |
1021 | changeset | manifest | filelogs |
1021 | changeset | manifest | filelogs |
1022 | | | |
1022 | | | |
1023 | | | |
1023 | | | |
1024 +---------------------------------+
1024 +---------------------------------+
1025
1025
1026 When exchanging treemanifests, there are 4 logical segments:
1026 When exchanging treemanifests, there are 4 logical segments:
1027
1027
1028 +-------------------------------------------------+
1028 +-------------------------------------------------+
1029 | | | | |
1029 | | | | |
1030 | changeset | root | treemanifests | filelogs |
1030 | changeset | root | treemanifests | filelogs |
1031 | | manifest | | |
1031 | | manifest | | |
1032 | | | | |
1032 | | | | |
1033 +-------------------------------------------------+
1033 +-------------------------------------------------+
1034
1034
1035 The principle building block of each segment is a *chunk*. A *chunk* is a
1035 The principle building block of each segment is a *chunk*. A *chunk* is a
1036 framed piece of data:
1036 framed piece of data:
1037
1037
1038 +---------------------------------------+
1038 +---------------------------------------+
1039 | | |
1039 | | |
1040 | length | data |
1040 | length | data |
1041 | (4 bytes) | (<length - 4> bytes) |
1041 | (4 bytes) | (<length - 4> bytes) |
1042 | | |
1042 | | |
1043 +---------------------------------------+
1043 +---------------------------------------+
1044
1044
1045 All integers are big-endian signed integers. Each chunk starts with a
1045 All integers are big-endian signed integers. Each chunk starts with a
1046 32-bit integer indicating the length of the entire chunk (including the
1046 32-bit integer indicating the length of the entire chunk (including the
1047 length field itself).
1047 length field itself).
1048
1048
1049 There is a special case chunk that has a value of 0 for the length
1049 There is a special case chunk that has a value of 0 for the length
1050 ("0x00000000"). We call this an *empty chunk*.
1050 ("0x00000000"). We call this an *empty chunk*.
1051
1051
1052 Delta Groups
1052 Delta Groups
1053 ============
1053 ============
1054
1054
1055 A *delta group* expresses the content of a revlog as a series of deltas,
1055 A *delta group* expresses the content of a revlog as a series of deltas,
1056 or patches against previous revisions.
1056 or patches against previous revisions.
1057
1057
1058 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
1058 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
1059 to signal the end of the delta group:
1059 to signal the end of the delta group:
1060
1060
1061 +------------------------------------------------------------------------+
1061 +------------------------------------------------------------------------+
1062 | | | | | |
1062 | | | | | |
1063 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
1063 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
1064 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
1064 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
1065 | | | | | |
1065 | | | | | |
1066 +------------------------------------------------------------------------+
1066 +------------------------------------------------------------------------+
1067
1067
1068 Each *chunk*'s data consists of the following:
1068 Each *chunk*'s data consists of the following:
1069
1069
1070 +---------------------------------------+
1070 +---------------------------------------+
1071 | | |
1071 | | |
1072 | delta header | delta data |
1072 | delta header | delta data |
1073 | (various by version) | (various) |
1073 | (various by version) | (various) |
1074 | | |
1074 | | |
1075 +---------------------------------------+
1075 +---------------------------------------+
1076
1076
1077 The *delta data* is a series of *delta*s that describe a diff from an
1077 The *delta data* is a series of *delta*s that describe a diff from an
1078 existing entry (either that the recipient already has, or previously
1078 existing entry (either that the recipient already has, or previously
1079 specified in the bundle/changegroup).
1079 specified in the bundle/changegroup).
1080
1080
1081 The *delta header* is different between versions "1", "2", and "3" of the
1081 The *delta header* is different between versions "1", "2", and "3" of the
1082 changegroup format.
1082 changegroup format.
1083
1083
1084 Version 1 (headerlen=80):
1084 Version 1 (headerlen=80):
1085
1085
1086 +------------------------------------------------------+
1086 +------------------------------------------------------+
1087 | | | | |
1087 | | | | |
1088 | node | p1 node | p2 node | link node |
1088 | node | p1 node | p2 node | link node |
1089 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1089 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1090 | | | | |
1090 | | | | |
1091 +------------------------------------------------------+
1091 +------------------------------------------------------+
1092
1092
1093 Version 2 (headerlen=100):
1093 Version 2 (headerlen=100):
1094
1094
1095 +------------------------------------------------------------------+
1095 +------------------------------------------------------------------+
1096 | | | | | |
1096 | | | | | |
1097 | node | p1 node | p2 node | base node | link node |
1097 | node | p1 node | p2 node | base node | link node |
1098 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1098 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1099 | | | | | |
1099 | | | | | |
1100 +------------------------------------------------------------------+
1100 +------------------------------------------------------------------+
1101
1101
1102 Version 3 (headerlen=102):
1102 Version 3 (headerlen=102):
1103
1103
1104 +------------------------------------------------------------------------------+
1104 +------------------------------------------------------------------------------+
1105 | | | | | | |
1105 | | | | | | |
1106 | node | p1 node | p2 node | base node | link node | flags |
1106 | node | p1 node | p2 node | base node | link node | flags |
1107 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
1107 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
1108 | | | | | | |
1108 | | | | | | |
1109 +------------------------------------------------------------------------------+
1109 +------------------------------------------------------------------------------+
1110
1110
1111 The *delta data* consists of "chunklen - 4 - headerlen" bytes, which
1111 The *delta data* consists of "chunklen - 4 - headerlen" bytes, which
1112 contain a series of *delta*s, densely packed (no separators). These deltas
1112 contain a series of *delta*s, densely packed (no separators). These deltas
1113 describe a diff from an existing entry (either that the recipient already
1113 describe a diff from an existing entry (either that the recipient already
1114 has, or previously specified in the bundle/changegroup). The format is
1114 has, or previously specified in the bundle/changegroup). The format is
1115 described more fully in "hg help internals.bdiff", but briefly:
1115 described more fully in "hg help internals.bdiff", but briefly:
1116
1116
1117 +---------------------------------------------------------------+
1117 +---------------------------------------------------------------+
1118 | | | | |
1118 | | | | |
1119 | start offset | end offset | new length | content |
1119 | start offset | end offset | new length | content |
1120 | (4 bytes) | (4 bytes) | (4 bytes) | (<new length> bytes) |
1120 | (4 bytes) | (4 bytes) | (4 bytes) | (<new length> bytes) |
1121 | | | | |
1121 | | | | |
1122 +---------------------------------------------------------------+
1122 +---------------------------------------------------------------+
1123
1123
1124 Please note that the length field in the delta data does *not* include
1124 Please note that the length field in the delta data does *not* include
1125 itself.
1125 itself.
1126
1126
1127 In version 1, the delta is always applied against the previous node from
1127 In version 1, the delta is always applied against the previous node from
1128 the changegroup or the first parent if this is the first entry in the
1128 the changegroup or the first parent if this is the first entry in the
1129 changegroup.
1129 changegroup.
1130
1130
1131 In version 2 and up, the delta base node is encoded in the entry in the
1131 In version 2 and up, the delta base node is encoded in the entry in the
1132 changegroup. This allows the delta to be expressed against any parent,
1132 changegroup. This allows the delta to be expressed against any parent,
1133 which can result in smaller deltas and more efficient encoding of data.
1133 which can result in smaller deltas and more efficient encoding of data.
1134
1134
1135 Changeset Segment
1135 Changeset Segment
1136 =================
1136 =================
1137
1137
1138 The *changeset segment* consists of a single *delta group* holding
1138 The *changeset segment* consists of a single *delta group* holding
1139 changelog data. The *empty chunk* at the end of the *delta group* denotes
1139 changelog data. The *empty chunk* at the end of the *delta group* denotes
1140 the boundary to the *manifest segment*.
1140 the boundary to the *manifest segment*.
1141
1141
1142 Manifest Segment
1142 Manifest Segment
1143 ================
1143 ================
1144
1144
1145 The *manifest segment* consists of a single *delta group* holding manifest
1145 The *manifest segment* consists of a single *delta group* holding manifest
1146 data. If treemanifests are in use, it contains only the manifest for the
1146 data. If treemanifests are in use, it contains only the manifest for the
1147 root directory of the repository. Otherwise, it contains the entire
1147 root directory of the repository. Otherwise, it contains the entire
1148 manifest data. The *empty chunk* at the end of the *delta group* denotes
1148 manifest data. The *empty chunk* at the end of the *delta group* denotes
1149 the boundary to the next segment (either the *treemanifests segment* or
1149 the boundary to the next segment (either the *treemanifests segment* or
1150 the *filelogs segment*, depending on version and the request options).
1150 the *filelogs segment*, depending on version and the request options).
1151
1151
1152 Treemanifests Segment
1152 Treemanifests Segment
1153 ---------------------
1153 ---------------------
1154
1154
1155 The *treemanifests segment* only exists in changegroup version "3", and
1155 The *treemanifests segment* only exists in changegroup version "3", and
1156 only if the 'treemanifest' param is part of the bundle2 changegroup part
1156 only if the 'treemanifest' param is part of the bundle2 changegroup part
1157 (it is not possible to use changegroup version 3 outside of bundle2).
1157 (it is not possible to use changegroup version 3 outside of bundle2).
1158 Aside from the filenames in the *treemanifests segment* containing a
1158 Aside from the filenames in the *treemanifests segment* containing a
1159 trailing "/" character, it behaves identically to the *filelogs segment*
1159 trailing "/" character, it behaves identically to the *filelogs segment*
1160 (see below). The final sub-segment is followed by an *empty chunk*
1160 (see below). The final sub-segment is followed by an *empty chunk*
1161 (logically, a sub-segment with filename size 0). This denotes the boundary
1161 (logically, a sub-segment with filename size 0). This denotes the boundary
1162 to the *filelogs segment*.
1162 to the *filelogs segment*.
1163
1163
1164 Filelogs Segment
1164 Filelogs Segment
1165 ================
1165 ================
1166
1166
1167 The *filelogs segment* consists of multiple sub-segments, each
1167 The *filelogs segment* consists of multiple sub-segments, each
1168 corresponding to an individual file whose data is being described:
1168 corresponding to an individual file whose data is being described:
1169
1169
1170 +--------------------------------------------------+
1170 +--------------------------------------------------+
1171 | | | | | |
1171 | | | | | |
1172 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
1172 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
1173 | | | | | (4 bytes) |
1173 | | | | | (4 bytes) |
1174 | | | | | |
1174 | | | | | |
1175 +--------------------------------------------------+
1175 +--------------------------------------------------+
1176
1176
1177 The final filelog sub-segment is followed by an *empty chunk* (logically,
1177 The final filelog sub-segment is followed by an *empty chunk* (logically,
1178 a sub-segment with filename size 0). This denotes the end of the segment
1178 a sub-segment with filename size 0). This denotes the end of the segment
1179 and of the overall changegroup.
1179 and of the overall changegroup.
1180
1180
1181 Each filelog sub-segment consists of the following:
1181 Each filelog sub-segment consists of the following:
1182
1182
1183 +------------------------------------------------------+
1183 +------------------------------------------------------+
1184 | | | |
1184 | | | |
1185 | filename length | filename | delta group |
1185 | filename length | filename | delta group |
1186 | (4 bytes) | (<length - 4> bytes) | (various) |
1186 | (4 bytes) | (<length - 4> bytes) | (various) |
1187 | | | |
1187 | | | |
1188 +------------------------------------------------------+
1188 +------------------------------------------------------+
1189
1189
1190 That is, a *chunk* consisting of the filename (not terminated or padded)
1190 That is, a *chunk* consisting of the filename (not terminated or padded)
1191 followed by N chunks constituting the *delta group* for this file. The
1191 followed by N chunks constituting the *delta group* for this file. The
1192 *empty chunk* at the end of each *delta group* denotes the boundary to the
1192 *empty chunk* at the end of each *delta group* denotes the boundary to the
1193 next filelog sub-segment.
1193 next filelog sub-segment.
1194
1194
1195 Test list of commands with command with no help text
1195 Test list of commands with command with no help text
1196
1196
1197 $ hg help helpext
1197 $ hg help helpext
1198 helpext extension - no help text available
1198 helpext extension - no help text available
1199
1199
1200 list of commands:
1200 list of commands:
1201
1201
1202 nohelp (no help text available)
1202 nohelp (no help text available)
1203
1203
1204 (use 'hg help -v helpext' to show built-in aliases and global options)
1204 (use 'hg help -v helpext' to show built-in aliases and global options)
1205
1205
1206
1206
1207 test advanced, deprecated and experimental options are hidden in command help
1207 test advanced, deprecated and experimental options are hidden in command help
1208 $ hg help debugoptADV
1208 $ hg help debugoptADV
1209 hg debugoptADV
1209 hg debugoptADV
1210
1210
1211 (no help text available)
1211 (no help text available)
1212
1212
1213 options:
1213 options:
1214
1214
1215 (some details hidden, use --verbose to show complete help)
1215 (some details hidden, use --verbose to show complete help)
1216 $ hg help debugoptDEP
1216 $ hg help debugoptDEP
1217 hg debugoptDEP
1217 hg debugoptDEP
1218
1218
1219 (no help text available)
1219 (no help text available)
1220
1220
1221 options:
1221 options:
1222
1222
1223 (some details hidden, use --verbose to show complete help)
1223 (some details hidden, use --verbose to show complete help)
1224
1224
1225 $ hg help debugoptEXP
1225 $ hg help debugoptEXP
1226 hg debugoptEXP
1226 hg debugoptEXP
1227
1227
1228 (no help text available)
1228 (no help text available)
1229
1229
1230 options:
1230 options:
1231
1231
1232 (some details hidden, use --verbose to show complete help)
1232 (some details hidden, use --verbose to show complete help)
1233
1233
1234 test advanced, deprecated and experimental options are shown with -v
1234 test advanced, deprecated and experimental options are shown with -v
1235 $ hg help -v debugoptADV | grep aopt
1235 $ hg help -v debugoptADV | grep aopt
1236 --aopt option is (ADVANCED)
1236 --aopt option is (ADVANCED)
1237 $ hg help -v debugoptDEP | grep dopt
1237 $ hg help -v debugoptDEP | grep dopt
1238 --dopt option is (DEPRECATED)
1238 --dopt option is (DEPRECATED)
1239 $ hg help -v debugoptEXP | grep eopt
1239 $ hg help -v debugoptEXP | grep eopt
1240 --eopt option is (EXPERIMENTAL)
1240 --eopt option is (EXPERIMENTAL)
1241
1241
1242 #if gettext
1242 #if gettext
1243 test deprecated option is hidden with translation with untranslated description
1243 test deprecated option is hidden with translation with untranslated description
1244 (use many globy for not failing on changed transaction)
1244 (use many globy for not failing on changed transaction)
1245 $ LANGUAGE=sv hg help debugoptDEP
1245 $ LANGUAGE=sv hg help debugoptDEP
1246 hg debugoptDEP
1246 hg debugoptDEP
1247
1247
1248 (*) (glob)
1248 (*) (glob)
1249
1249
1250 options:
1250 options:
1251
1251
1252 (some details hidden, use --verbose to show complete help)
1252 (some details hidden, use --verbose to show complete help)
1253 #endif
1253 #endif
1254
1254
1255 Test commands that collide with topics (issue4240)
1255 Test commands that collide with topics (issue4240)
1256
1256
1257 $ hg config -hq
1257 $ hg config -hq
1258 hg config [-u] [NAME]...
1258 hg config [-u] [NAME]...
1259
1259
1260 show combined config settings from all hgrc files
1260 show combined config settings from all hgrc files
1261 $ hg showconfig -hq
1261 $ hg showconfig -hq
1262 hg config [-u] [NAME]...
1262 hg config [-u] [NAME]...
1263
1263
1264 show combined config settings from all hgrc files
1264 show combined config settings from all hgrc files
1265
1265
1266 Test a help topic
1266 Test a help topic
1267
1267
1268 $ hg help dates
1268 $ hg help dates
1269 Date Formats
1269 Date Formats
1270 """"""""""""
1270 """"""""""""
1271
1271
1272 Some commands allow the user to specify a date, e.g.:
1272 Some commands allow the user to specify a date, e.g.:
1273
1273
1274 - backout, commit, import, tag: Specify the commit date.
1274 - backout, commit, import, tag: Specify the commit date.
1275 - log, revert, update: Select revision(s) by date.
1275 - log, revert, update: Select revision(s) by date.
1276
1276
1277 Many date formats are valid. Here are some examples:
1277 Many date formats are valid. Here are some examples:
1278
1278
1279 - "Wed Dec 6 13:18:29 2006" (local timezone assumed)
1279 - "Wed Dec 6 13:18:29 2006" (local timezone assumed)
1280 - "Dec 6 13:18 -0600" (year assumed, time offset provided)
1280 - "Dec 6 13:18 -0600" (year assumed, time offset provided)
1281 - "Dec 6 13:18 UTC" (UTC and GMT are aliases for +0000)
1281 - "Dec 6 13:18 UTC" (UTC and GMT are aliases for +0000)
1282 - "Dec 6" (midnight)
1282 - "Dec 6" (midnight)
1283 - "13:18" (today assumed)
1283 - "13:18" (today assumed)
1284 - "3:39" (3:39AM assumed)
1284 - "3:39" (3:39AM assumed)
1285 - "3:39pm" (15:39)
1285 - "3:39pm" (15:39)
1286 - "2006-12-06 13:18:29" (ISO 8601 format)
1286 - "2006-12-06 13:18:29" (ISO 8601 format)
1287 - "2006-12-6 13:18"
1287 - "2006-12-6 13:18"
1288 - "2006-12-6"
1288 - "2006-12-6"
1289 - "12-6"
1289 - "12-6"
1290 - "12/6"
1290 - "12/6"
1291 - "12/6/6" (Dec 6 2006)
1291 - "12/6/6" (Dec 6 2006)
1292 - "today" (midnight)
1292 - "today" (midnight)
1293 - "yesterday" (midnight)
1293 - "yesterday" (midnight)
1294 - "now" - right now
1294 - "now" - right now
1295
1295
1296 Lastly, there is Mercurial's internal format:
1296 Lastly, there is Mercurial's internal format:
1297
1297
1298 - "1165411109 0" (Wed Dec 6 13:18:29 2006 UTC)
1298 - "1165411109 0" (Wed Dec 6 13:18:29 2006 UTC)
1299
1299
1300 This is the internal representation format for dates. The first number is
1300 This is the internal representation format for dates. The first number is
1301 the number of seconds since the epoch (1970-01-01 00:00 UTC). The second
1301 the number of seconds since the epoch (1970-01-01 00:00 UTC). The second
1302 is the offset of the local timezone, in seconds west of UTC (negative if
1302 is the offset of the local timezone, in seconds west of UTC (negative if
1303 the timezone is east of UTC).
1303 the timezone is east of UTC).
1304
1304
1305 The log command also accepts date ranges:
1305 The log command also accepts date ranges:
1306
1306
1307 - "<DATE" - at or before a given date/time
1307 - "<DATE" - at or before a given date/time
1308 - ">DATE" - on or after a given date/time
1308 - ">DATE" - on or after a given date/time
1309 - "DATE to DATE" - a date range, inclusive
1309 - "DATE to DATE" - a date range, inclusive
1310 - "-DAYS" - within a given number of days of today
1310 - "-DAYS" - within a given number of days of today
1311
1311
1312 Test repeated config section name
1312 Test repeated config section name
1313
1313
1314 $ hg help config.host
1314 $ hg help config.host
1315 "http_proxy.host"
1315 "http_proxy.host"
1316 Host name and (optional) port of the proxy server, for example
1316 Host name and (optional) port of the proxy server, for example
1317 "myproxy:8000".
1317 "myproxy:8000".
1318
1318
1319 "smtp.host"
1319 "smtp.host"
1320 Host name of mail server, e.g. "mail.example.com".
1320 Host name of mail server, e.g. "mail.example.com".
1321
1321
1322 Unrelated trailing paragraphs shouldn't be included
1322 Unrelated trailing paragraphs shouldn't be included
1323
1323
1324 $ hg help config.extramsg | grep '^$'
1324 $ hg help config.extramsg | grep '^$'
1325
1325
1326
1326
1327 Test capitalized section name
1327 Test capitalized section name
1328
1328
1329 $ hg help scripting.HGPLAIN > /dev/null
1329 $ hg help scripting.HGPLAIN > /dev/null
1330
1330
1331 Help subsection:
1331 Help subsection:
1332
1332
1333 $ hg help config.charsets |grep "Email example:" > /dev/null
1333 $ hg help config.charsets |grep "Email example:" > /dev/null
1334 [1]
1334 [1]
1335
1335
1336 Show nested definitions
1336 Show nested definitions
1337 ("profiling.type"[break]"ls"[break]"stat"[break])
1337 ("profiling.type"[break]"ls"[break]"stat"[break])
1338
1338
1339 $ hg help config.type | egrep '^$'|wc -l
1339 $ hg help config.type | egrep '^$'|wc -l
1340 \s*3 (re)
1340 \s*3 (re)
1341
1341
1342 Separate sections from subsections
1342 Separate sections from subsections
1343
1343
1344 $ hg help config.format | egrep '^ ("|-)|^\s*$' | uniq
1344 $ hg help config.format | egrep '^ ("|-)|^\s*$' | uniq
1345 "format"
1345 "format"
1346 --------
1346 --------
1347
1347
1348 "usegeneraldelta"
1348 "usegeneraldelta"
1349
1349
1350 "dotencode"
1350 "dotencode"
1351
1351
1352 "usefncache"
1352 "usefncache"
1353
1353
1354 "usestore"
1354 "usestore"
1355
1355
1356 "profiling"
1356 "profiling"
1357 -----------
1357 -----------
1358
1358
1359 "format"
1359 "format"
1360
1360
1361 "progress"
1361 "progress"
1362 ----------
1362 ----------
1363
1363
1364 "format"
1364 "format"
1365
1365
1366
1366
1367 Last item in help config.*:
1367 Last item in help config.*:
1368
1368
1369 $ hg help config.`hg help config|grep '^ "'| \
1369 $ hg help config.`hg help config|grep '^ "'| \
1370 > tail -1|sed 's![ "]*!!g'`| \
1370 > tail -1|sed 's![ "]*!!g'`| \
1371 > grep 'hg help -c config' > /dev/null
1371 > grep 'hg help -c config' > /dev/null
1372 [1]
1372 [1]
1373
1373
1374 note to use help -c for general hg help config:
1374 note to use help -c for general hg help config:
1375
1375
1376 $ hg help config |grep 'hg help -c config' > /dev/null
1376 $ hg help config |grep 'hg help -c config' > /dev/null
1377
1377
1378 Test templating help
1378 Test templating help
1379
1379
1380 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
1380 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
1381 desc String. The text of the changeset description.
1381 desc String. The text of the changeset description.
1382 diffstat String. Statistics of changes with the following format:
1382 diffstat String. Statistics of changes with the following format:
1383 firstline Any text. Returns the first line of text.
1383 firstline Any text. Returns the first line of text.
1384 nonempty Any text. Returns '(none)' if the string is empty.
1384 nonempty Any text. Returns '(none)' if the string is empty.
1385
1385
1386 Test deprecated items
1386 Test deprecated items
1387
1387
1388 $ hg help -v templating | grep currentbookmark
1388 $ hg help -v templating | grep currentbookmark
1389 currentbookmark
1389 currentbookmark
1390 $ hg help templating | (grep currentbookmark || true)
1390 $ hg help templating | (grep currentbookmark || true)
1391
1391
1392 Test help hooks
1392 Test help hooks
1393
1393
1394 $ cat > helphook1.py <<EOF
1394 $ cat > helphook1.py <<EOF
1395 > from mercurial import help
1395 > from mercurial import help
1396 >
1396 >
1397 > def rewrite(ui, topic, doc):
1397 > def rewrite(ui, topic, doc):
1398 > return doc + '\nhelphook1\n'
1398 > return doc + '\nhelphook1\n'
1399 >
1399 >
1400 > def extsetup(ui):
1400 > def extsetup(ui):
1401 > help.addtopichook('revisions', rewrite)
1401 > help.addtopichook('revisions', rewrite)
1402 > EOF
1402 > EOF
1403 $ cat > helphook2.py <<EOF
1403 $ cat > helphook2.py <<EOF
1404 > from mercurial import help
1404 > from mercurial import help
1405 >
1405 >
1406 > def rewrite(ui, topic, doc):
1406 > def rewrite(ui, topic, doc):
1407 > return doc + '\nhelphook2\n'
1407 > return doc + '\nhelphook2\n'
1408 >
1408 >
1409 > def extsetup(ui):
1409 > def extsetup(ui):
1410 > help.addtopichook('revisions', rewrite)
1410 > help.addtopichook('revisions', rewrite)
1411 > EOF
1411 > EOF
1412 $ echo '[extensions]' >> $HGRCPATH
1412 $ echo '[extensions]' >> $HGRCPATH
1413 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
1413 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
1414 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
1414 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
1415 $ hg help revsets | grep helphook
1415 $ hg help revsets | grep helphook
1416 helphook1
1416 helphook1
1417 helphook2
1417 helphook2
1418
1418
1419 help -c should only show debug --debug
1419 help -c should only show debug --debug
1420
1420
1421 $ hg help -c --debug|egrep debug|wc -l|egrep '^\s*0\s*$'
1421 $ hg help -c --debug|egrep debug|wc -l|egrep '^\s*0\s*$'
1422 [1]
1422 [1]
1423
1423
1424 help -c should only show deprecated for -v
1424 help -c should only show deprecated for -v
1425
1425
1426 $ hg help -c -v|egrep DEPRECATED|wc -l|egrep '^\s*0\s*$'
1426 $ hg help -c -v|egrep DEPRECATED|wc -l|egrep '^\s*0\s*$'
1427 [1]
1427 [1]
1428
1428
1429 Test -s / --system
1429 Test -s / --system
1430
1430
1431 $ hg help config.files -s windows |grep 'etc/mercurial' | \
1431 $ hg help config.files -s windows |grep 'etc/mercurial' | \
1432 > wc -l | sed -e 's/ //g'
1432 > wc -l | sed -e 's/ //g'
1433 0
1433 0
1434 $ hg help config.files --system unix | grep 'USER' | \
1434 $ hg help config.files --system unix | grep 'USER' | \
1435 > wc -l | sed -e 's/ //g'
1435 > wc -l | sed -e 's/ //g'
1436 0
1436 0
1437
1437
1438 Test -e / -c / -k combinations
1438 Test -e / -c / -k combinations
1439
1439
1440 $ hg help -c|egrep '^[A-Z].*:|^ debug'
1440 $ hg help -c|egrep '^[A-Z].*:|^ debug'
1441 Commands:
1441 Commands:
1442 $ hg help -e|egrep '^[A-Z].*:|^ debug'
1442 $ hg help -e|egrep '^[A-Z].*:|^ debug'
1443 Extensions:
1443 Extensions:
1444 $ hg help -k|egrep '^[A-Z].*:|^ debug'
1444 $ hg help -k|egrep '^[A-Z].*:|^ debug'
1445 Topics:
1445 Topics:
1446 Commands:
1446 Commands:
1447 Extensions:
1447 Extensions:
1448 Extension Commands:
1448 Extension Commands:
1449 $ hg help -c schemes
1449 $ hg help -c schemes
1450 abort: no such help topic: schemes
1450 abort: no such help topic: schemes
1451 (try 'hg help --keyword schemes')
1451 (try 'hg help --keyword schemes')
1452 [255]
1452 [255]
1453 $ hg help -e schemes |head -1
1453 $ hg help -e schemes |head -1
1454 schemes extension - extend schemes with shortcuts to repository swarms
1454 schemes extension - extend schemes with shortcuts to repository swarms
1455 $ hg help -c -k dates |egrep '^(Topics|Extensions|Commands):'
1455 $ hg help -c -k dates |egrep '^(Topics|Extensions|Commands):'
1456 Commands:
1456 Commands:
1457 $ hg help -e -k a |egrep '^(Topics|Extensions|Commands):'
1457 $ hg help -e -k a |egrep '^(Topics|Extensions|Commands):'
1458 Extensions:
1458 Extensions:
1459 $ hg help -e -c -k date |egrep '^(Topics|Extensions|Commands):'
1459 $ hg help -e -c -k date |egrep '^(Topics|Extensions|Commands):'
1460 Extensions:
1460 Extensions:
1461 Commands:
1461 Commands:
1462 $ hg help -c commit > /dev/null
1462 $ hg help -c commit > /dev/null
1463 $ hg help -e -c commit > /dev/null
1463 $ hg help -e -c commit > /dev/null
1464 $ hg help -e commit > /dev/null
1464 $ hg help -e commit > /dev/null
1465 abort: no such help topic: commit
1465 abort: no such help topic: commit
1466 (try 'hg help --keyword commit')
1466 (try 'hg help --keyword commit')
1467 [255]
1467 [255]
1468
1468
1469 Test keyword search help
1469 Test keyword search help
1470
1470
1471 $ cat > prefixedname.py <<EOF
1471 $ cat > prefixedname.py <<EOF
1472 > '''matched against word "clone"
1472 > '''matched against word "clone"
1473 > '''
1473 > '''
1474 > EOF
1474 > EOF
1475 $ echo '[extensions]' >> $HGRCPATH
1475 $ echo '[extensions]' >> $HGRCPATH
1476 $ echo "dot.dot.prefixedname = `pwd`/prefixedname.py" >> $HGRCPATH
1476 $ echo "dot.dot.prefixedname = `pwd`/prefixedname.py" >> $HGRCPATH
1477 $ hg help -k clone
1477 $ hg help -k clone
1478 Topics:
1478 Topics:
1479
1479
1480 config Configuration Files
1480 config Configuration Files
1481 extensions Using Additional Features
1481 extensions Using Additional Features
1482 glossary Glossary
1482 glossary Glossary
1483 phases Working with Phases
1483 phases Working with Phases
1484 subrepos Subrepositories
1484 subrepos Subrepositories
1485 urls URL Paths
1485 urls URL Paths
1486
1486
1487 Commands:
1487 Commands:
1488
1488
1489 bookmarks create a new bookmark or list existing bookmarks
1489 bookmarks create a new bookmark or list existing bookmarks
1490 clone make a copy of an existing repository
1490 clone make a copy of an existing repository
1491 paths show aliases for remote repositories
1491 paths show aliases for remote repositories
1492 update update working directory (or switch revisions)
1492 update update working directory (or switch revisions)
1493
1493
1494 Extensions:
1494 Extensions:
1495
1495
1496 clonebundles advertise pre-generated bundles to seed clones
1496 clonebundles advertise pre-generated bundles to seed clones
1497 narrow create clones which fetch history data for subset of files
1498 (EXPERIMENTAL)
1497 prefixedname matched against word "clone"
1499 prefixedname matched against word "clone"
1498 relink recreates hardlinks between repository clones
1500 relink recreates hardlinks between repository clones
1499
1501
1500 Extension Commands:
1502 Extension Commands:
1501
1503
1502 qclone clone main and patch repository at same time
1504 qclone clone main and patch repository at same time
1503
1505
1504 Test unfound topic
1506 Test unfound topic
1505
1507
1506 $ hg help nonexistingtopicthatwillneverexisteverever
1508 $ hg help nonexistingtopicthatwillneverexisteverever
1507 abort: no such help topic: nonexistingtopicthatwillneverexisteverever
1509 abort: no such help topic: nonexistingtopicthatwillneverexisteverever
1508 (try 'hg help --keyword nonexistingtopicthatwillneverexisteverever')
1510 (try 'hg help --keyword nonexistingtopicthatwillneverexisteverever')
1509 [255]
1511 [255]
1510
1512
1511 Test unfound keyword
1513 Test unfound keyword
1512
1514
1513 $ hg help --keyword nonexistingwordthatwillneverexisteverever
1515 $ hg help --keyword nonexistingwordthatwillneverexisteverever
1514 abort: no matches
1516 abort: no matches
1515 (try 'hg help' for a list of topics)
1517 (try 'hg help' for a list of topics)
1516 [255]
1518 [255]
1517
1519
1518 Test omit indicating for help
1520 Test omit indicating for help
1519
1521
1520 $ cat > addverboseitems.py <<EOF
1522 $ cat > addverboseitems.py <<EOF
1521 > '''extension to test omit indicating.
1523 > '''extension to test omit indicating.
1522 >
1524 >
1523 > This paragraph is never omitted (for extension)
1525 > This paragraph is never omitted (for extension)
1524 >
1526 >
1525 > .. container:: verbose
1527 > .. container:: verbose
1526 >
1528 >
1527 > This paragraph is omitted,
1529 > This paragraph is omitted,
1528 > if :hg:\`help\` is invoked without \`\`-v\`\` (for extension)
1530 > if :hg:\`help\` is invoked without \`\`-v\`\` (for extension)
1529 >
1531 >
1530 > This paragraph is never omitted, too (for extension)
1532 > This paragraph is never omitted, too (for extension)
1531 > '''
1533 > '''
1532 > from __future__ import absolute_import
1534 > from __future__ import absolute_import
1533 > from mercurial import commands, help
1535 > from mercurial import commands, help
1534 > testtopic = """This paragraph is never omitted (for topic).
1536 > testtopic = """This paragraph is never omitted (for topic).
1535 >
1537 >
1536 > .. container:: verbose
1538 > .. container:: verbose
1537 >
1539 >
1538 > This paragraph is omitted,
1540 > This paragraph is omitted,
1539 > if :hg:\`help\` is invoked without \`\`-v\`\` (for topic)
1541 > if :hg:\`help\` is invoked without \`\`-v\`\` (for topic)
1540 >
1542 >
1541 > This paragraph is never omitted, too (for topic)
1543 > This paragraph is never omitted, too (for topic)
1542 > """
1544 > """
1543 > def extsetup(ui):
1545 > def extsetup(ui):
1544 > help.helptable.append((["topic-containing-verbose"],
1546 > help.helptable.append((["topic-containing-verbose"],
1545 > "This is the topic to test omit indicating.",
1547 > "This is the topic to test omit indicating.",
1546 > lambda ui: testtopic))
1548 > lambda ui: testtopic))
1547 > EOF
1549 > EOF
1548 $ echo '[extensions]' >> $HGRCPATH
1550 $ echo '[extensions]' >> $HGRCPATH
1549 $ echo "addverboseitems = `pwd`/addverboseitems.py" >> $HGRCPATH
1551 $ echo "addverboseitems = `pwd`/addverboseitems.py" >> $HGRCPATH
1550 $ hg help addverboseitems
1552 $ hg help addverboseitems
1551 addverboseitems extension - extension to test omit indicating.
1553 addverboseitems extension - extension to test omit indicating.
1552
1554
1553 This paragraph is never omitted (for extension)
1555 This paragraph is never omitted (for extension)
1554
1556
1555 This paragraph is never omitted, too (for extension)
1557 This paragraph is never omitted, too (for extension)
1556
1558
1557 (some details hidden, use --verbose to show complete help)
1559 (some details hidden, use --verbose to show complete help)
1558
1560
1559 no commands defined
1561 no commands defined
1560 $ hg help -v addverboseitems
1562 $ hg help -v addverboseitems
1561 addverboseitems extension - extension to test omit indicating.
1563 addverboseitems extension - extension to test omit indicating.
1562
1564
1563 This paragraph is never omitted (for extension)
1565 This paragraph is never omitted (for extension)
1564
1566
1565 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1567 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1566 extension)
1568 extension)
1567
1569
1568 This paragraph is never omitted, too (for extension)
1570 This paragraph is never omitted, too (for extension)
1569
1571
1570 no commands defined
1572 no commands defined
1571 $ hg help topic-containing-verbose
1573 $ hg help topic-containing-verbose
1572 This is the topic to test omit indicating.
1574 This is the topic to test omit indicating.
1573 """"""""""""""""""""""""""""""""""""""""""
1575 """"""""""""""""""""""""""""""""""""""""""
1574
1576
1575 This paragraph is never omitted (for topic).
1577 This paragraph is never omitted (for topic).
1576
1578
1577 This paragraph is never omitted, too (for topic)
1579 This paragraph is never omitted, too (for topic)
1578
1580
1579 (some details hidden, use --verbose to show complete help)
1581 (some details hidden, use --verbose to show complete help)
1580 $ hg help -v topic-containing-verbose
1582 $ hg help -v topic-containing-verbose
1581 This is the topic to test omit indicating.
1583 This is the topic to test omit indicating.
1582 """"""""""""""""""""""""""""""""""""""""""
1584 """"""""""""""""""""""""""""""""""""""""""
1583
1585
1584 This paragraph is never omitted (for topic).
1586 This paragraph is never omitted (for topic).
1585
1587
1586 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1588 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1587 topic)
1589 topic)
1588
1590
1589 This paragraph is never omitted, too (for topic)
1591 This paragraph is never omitted, too (for topic)
1590
1592
1591 Test section lookup
1593 Test section lookup
1592
1594
1593 $ hg help revset.merge
1595 $ hg help revset.merge
1594 "merge()"
1596 "merge()"
1595 Changeset is a merge changeset.
1597 Changeset is a merge changeset.
1596
1598
1597 $ hg help glossary.dag
1599 $ hg help glossary.dag
1598 DAG
1600 DAG
1599 The repository of changesets of a distributed version control system
1601 The repository of changesets of a distributed version control system
1600 (DVCS) can be described as a directed acyclic graph (DAG), consisting
1602 (DVCS) can be described as a directed acyclic graph (DAG), consisting
1601 of nodes and edges, where nodes correspond to changesets and edges
1603 of nodes and edges, where nodes correspond to changesets and edges
1602 imply a parent -> child relation. This graph can be visualized by
1604 imply a parent -> child relation. This graph can be visualized by
1603 graphical tools such as 'hg log --graph'. In Mercurial, the DAG is
1605 graphical tools such as 'hg log --graph'. In Mercurial, the DAG is
1604 limited by the requirement for children to have at most two parents.
1606 limited by the requirement for children to have at most two parents.
1605
1607
1606
1608
1607 $ hg help hgrc.paths
1609 $ hg help hgrc.paths
1608 "paths"
1610 "paths"
1609 -------
1611 -------
1610
1612
1611 Assigns symbolic names and behavior to repositories.
1613 Assigns symbolic names and behavior to repositories.
1612
1614
1613 Options are symbolic names defining the URL or directory that is the
1615 Options are symbolic names defining the URL or directory that is the
1614 location of the repository. Example:
1616 location of the repository. Example:
1615
1617
1616 [paths]
1618 [paths]
1617 my_server = https://example.com/my_repo
1619 my_server = https://example.com/my_repo
1618 local_path = /home/me/repo
1620 local_path = /home/me/repo
1619
1621
1620 These symbolic names can be used from the command line. To pull from
1622 These symbolic names can be used from the command line. To pull from
1621 "my_server": 'hg pull my_server'. To push to "local_path": 'hg push
1623 "my_server": 'hg pull my_server'. To push to "local_path": 'hg push
1622 local_path'.
1624 local_path'.
1623
1625
1624 Options containing colons (":") denote sub-options that can influence
1626 Options containing colons (":") denote sub-options that can influence
1625 behavior for that specific path. Example:
1627 behavior for that specific path. Example:
1626
1628
1627 [paths]
1629 [paths]
1628 my_server = https://example.com/my_path
1630 my_server = https://example.com/my_path
1629 my_server:pushurl = ssh://example.com/my_path
1631 my_server:pushurl = ssh://example.com/my_path
1630
1632
1631 The following sub-options can be defined:
1633 The following sub-options can be defined:
1632
1634
1633 "pushurl"
1635 "pushurl"
1634 The URL to use for push operations. If not defined, the location
1636 The URL to use for push operations. If not defined, the location
1635 defined by the path's main entry is used.
1637 defined by the path's main entry is used.
1636
1638
1637 "pushrev"
1639 "pushrev"
1638 A revset defining which revisions to push by default.
1640 A revset defining which revisions to push by default.
1639
1641
1640 When 'hg push' is executed without a "-r" argument, the revset defined
1642 When 'hg push' is executed without a "-r" argument, the revset defined
1641 by this sub-option is evaluated to determine what to push.
1643 by this sub-option is evaluated to determine what to push.
1642
1644
1643 For example, a value of "." will push the working directory's revision
1645 For example, a value of "." will push the working directory's revision
1644 by default.
1646 by default.
1645
1647
1646 Revsets specifying bookmarks will not result in the bookmark being
1648 Revsets specifying bookmarks will not result in the bookmark being
1647 pushed.
1649 pushed.
1648
1650
1649 The following special named paths exist:
1651 The following special named paths exist:
1650
1652
1651 "default"
1653 "default"
1652 The URL or directory to use when no source or remote is specified.
1654 The URL or directory to use when no source or remote is specified.
1653
1655
1654 'hg clone' will automatically define this path to the location the
1656 'hg clone' will automatically define this path to the location the
1655 repository was cloned from.
1657 repository was cloned from.
1656
1658
1657 "default-push"
1659 "default-push"
1658 (deprecated) The URL or directory for the default 'hg push' location.
1660 (deprecated) The URL or directory for the default 'hg push' location.
1659 "default:pushurl" should be used instead.
1661 "default:pushurl" should be used instead.
1660
1662
1661 $ hg help glossary.mcguffin
1663 $ hg help glossary.mcguffin
1662 abort: help section not found: glossary.mcguffin
1664 abort: help section not found: glossary.mcguffin
1663 [255]
1665 [255]
1664
1666
1665 $ hg help glossary.mc.guffin
1667 $ hg help glossary.mc.guffin
1666 abort: help section not found: glossary.mc.guffin
1668 abort: help section not found: glossary.mc.guffin
1667 [255]
1669 [255]
1668
1670
1669 $ hg help template.files
1671 $ hg help template.files
1670 files List of strings. All files modified, added, or removed by
1672 files List of strings. All files modified, added, or removed by
1671 this changeset.
1673 this changeset.
1672 files(pattern)
1674 files(pattern)
1673 All files of the current changeset matching the pattern. See
1675 All files of the current changeset matching the pattern. See
1674 'hg help patterns'.
1676 'hg help patterns'.
1675
1677
1676 Test section lookup by translated message
1678 Test section lookup by translated message
1677
1679
1678 str.lower() instead of encoding.lower(str) on translated message might
1680 str.lower() instead of encoding.lower(str) on translated message might
1679 make message meaningless, because some encoding uses 0x41(A) - 0x5a(Z)
1681 make message meaningless, because some encoding uses 0x41(A) - 0x5a(Z)
1680 as the second or later byte of multi-byte character.
1682 as the second or later byte of multi-byte character.
1681
1683
1682 For example, "\x8bL\x98^" (translation of "record" in ja_JP.cp932)
1684 For example, "\x8bL\x98^" (translation of "record" in ja_JP.cp932)
1683 contains 0x4c (L). str.lower() replaces 0x4c(L) by 0x6c(l) and this
1685 contains 0x4c (L). str.lower() replaces 0x4c(L) by 0x6c(l) and this
1684 replacement makes message meaningless.
1686 replacement makes message meaningless.
1685
1687
1686 This tests that section lookup by translated string isn't broken by
1688 This tests that section lookup by translated string isn't broken by
1687 such str.lower().
1689 such str.lower().
1688
1690
1689 $ $PYTHON <<EOF
1691 $ $PYTHON <<EOF
1690 > def escape(s):
1692 > def escape(s):
1691 > return ''.join('\u%x' % ord(uc) for uc in s.decode('cp932'))
1693 > return ''.join('\u%x' % ord(uc) for uc in s.decode('cp932'))
1692 > # translation of "record" in ja_JP.cp932
1694 > # translation of "record" in ja_JP.cp932
1693 > upper = "\x8bL\x98^"
1695 > upper = "\x8bL\x98^"
1694 > # str.lower()-ed section name should be treated as different one
1696 > # str.lower()-ed section name should be treated as different one
1695 > lower = "\x8bl\x98^"
1697 > lower = "\x8bl\x98^"
1696 > with open('ambiguous.py', 'w') as fp:
1698 > with open('ambiguous.py', 'w') as fp:
1697 > fp.write("""# ambiguous section names in ja_JP.cp932
1699 > fp.write("""# ambiguous section names in ja_JP.cp932
1698 > u'''summary of extension
1700 > u'''summary of extension
1699 >
1701 >
1700 > %s
1702 > %s
1701 > ----
1703 > ----
1702 >
1704 >
1703 > Upper name should show only this message
1705 > Upper name should show only this message
1704 >
1706 >
1705 > %s
1707 > %s
1706 > ----
1708 > ----
1707 >
1709 >
1708 > Lower name should show only this message
1710 > Lower name should show only this message
1709 >
1711 >
1710 > subsequent section
1712 > subsequent section
1711 > ------------------
1713 > ------------------
1712 >
1714 >
1713 > This should be hidden at 'hg help ambiguous' with section name.
1715 > This should be hidden at 'hg help ambiguous' with section name.
1714 > '''
1716 > '''
1715 > """ % (escape(upper), escape(lower)))
1717 > """ % (escape(upper), escape(lower)))
1716 > EOF
1718 > EOF
1717
1719
1718 $ cat >> $HGRCPATH <<EOF
1720 $ cat >> $HGRCPATH <<EOF
1719 > [extensions]
1721 > [extensions]
1720 > ambiguous = ./ambiguous.py
1722 > ambiguous = ./ambiguous.py
1721 > EOF
1723 > EOF
1722
1724
1723 $ $PYTHON <<EOF | sh
1725 $ $PYTHON <<EOF | sh
1724 > upper = "\x8bL\x98^"
1726 > upper = "\x8bL\x98^"
1725 > print("hg --encoding cp932 help -e ambiguous.%s" % upper)
1727 > print("hg --encoding cp932 help -e ambiguous.%s" % upper)
1726 > EOF
1728 > EOF
1727 \x8bL\x98^ (esc)
1729 \x8bL\x98^ (esc)
1728 ----
1730 ----
1729
1731
1730 Upper name should show only this message
1732 Upper name should show only this message
1731
1733
1732
1734
1733 $ $PYTHON <<EOF | sh
1735 $ $PYTHON <<EOF | sh
1734 > lower = "\x8bl\x98^"
1736 > lower = "\x8bl\x98^"
1735 > print("hg --encoding cp932 help -e ambiguous.%s" % lower)
1737 > print("hg --encoding cp932 help -e ambiguous.%s" % lower)
1736 > EOF
1738 > EOF
1737 \x8bl\x98^ (esc)
1739 \x8bl\x98^ (esc)
1738 ----
1740 ----
1739
1741
1740 Lower name should show only this message
1742 Lower name should show only this message
1741
1743
1742
1744
1743 $ cat >> $HGRCPATH <<EOF
1745 $ cat >> $HGRCPATH <<EOF
1744 > [extensions]
1746 > [extensions]
1745 > ambiguous = !
1747 > ambiguous = !
1746 > EOF
1748 > EOF
1747
1749
1748 Show help content of disabled extensions
1750 Show help content of disabled extensions
1749
1751
1750 $ cat >> $HGRCPATH <<EOF
1752 $ cat >> $HGRCPATH <<EOF
1751 > [extensions]
1753 > [extensions]
1752 > ambiguous = !./ambiguous.py
1754 > ambiguous = !./ambiguous.py
1753 > EOF
1755 > EOF
1754 $ hg help -e ambiguous
1756 $ hg help -e ambiguous
1755 ambiguous extension - (no help text available)
1757 ambiguous extension - (no help text available)
1756
1758
1757 (use 'hg help extensions' for information on enabling extensions)
1759 (use 'hg help extensions' for information on enabling extensions)
1758
1760
1759 Test dynamic list of merge tools only shows up once
1761 Test dynamic list of merge tools only shows up once
1760 $ hg help merge-tools
1762 $ hg help merge-tools
1761 Merge Tools
1763 Merge Tools
1762 """""""""""
1764 """""""""""
1763
1765
1764 To merge files Mercurial uses merge tools.
1766 To merge files Mercurial uses merge tools.
1765
1767
1766 A merge tool combines two different versions of a file into a merged file.
1768 A merge tool combines two different versions of a file into a merged file.
1767 Merge tools are given the two files and the greatest common ancestor of
1769 Merge tools are given the two files and the greatest common ancestor of
1768 the two file versions, so they can determine the changes made on both
1770 the two file versions, so they can determine the changes made on both
1769 branches.
1771 branches.
1770
1772
1771 Merge tools are used both for 'hg resolve', 'hg merge', 'hg update', 'hg
1773 Merge tools are used both for 'hg resolve', 'hg merge', 'hg update', 'hg
1772 backout' and in several extensions.
1774 backout' and in several extensions.
1773
1775
1774 Usually, the merge tool tries to automatically reconcile the files by
1776 Usually, the merge tool tries to automatically reconcile the files by
1775 combining all non-overlapping changes that occurred separately in the two
1777 combining all non-overlapping changes that occurred separately in the two
1776 different evolutions of the same initial base file. Furthermore, some
1778 different evolutions of the same initial base file. Furthermore, some
1777 interactive merge programs make it easier to manually resolve conflicting
1779 interactive merge programs make it easier to manually resolve conflicting
1778 merges, either in a graphical way, or by inserting some conflict markers.
1780 merges, either in a graphical way, or by inserting some conflict markers.
1779 Mercurial does not include any interactive merge programs but relies on
1781 Mercurial does not include any interactive merge programs but relies on
1780 external tools for that.
1782 external tools for that.
1781
1783
1782 Available merge tools
1784 Available merge tools
1783 =====================
1785 =====================
1784
1786
1785 External merge tools and their properties are configured in the merge-
1787 External merge tools and their properties are configured in the merge-
1786 tools configuration section - see hgrc(5) - but they can often just be
1788 tools configuration section - see hgrc(5) - but they can often just be
1787 named by their executable.
1789 named by their executable.
1788
1790
1789 A merge tool is generally usable if its executable can be found on the
1791 A merge tool is generally usable if its executable can be found on the
1790 system and if it can handle the merge. The executable is found if it is an
1792 system and if it can handle the merge. The executable is found if it is an
1791 absolute or relative executable path or the name of an application in the
1793 absolute or relative executable path or the name of an application in the
1792 executable search path. The tool is assumed to be able to handle the merge
1794 executable search path. The tool is assumed to be able to handle the merge
1793 if it can handle symlinks if the file is a symlink, if it can handle
1795 if it can handle symlinks if the file is a symlink, if it can handle
1794 binary files if the file is binary, and if a GUI is available if the tool
1796 binary files if the file is binary, and if a GUI is available if the tool
1795 requires a GUI.
1797 requires a GUI.
1796
1798
1797 There are some internal merge tools which can be used. The internal merge
1799 There are some internal merge tools which can be used. The internal merge
1798 tools are:
1800 tools are:
1799
1801
1800 ":dump"
1802 ":dump"
1801 Creates three versions of the files to merge, containing the contents of
1803 Creates three versions of the files to merge, containing the contents of
1802 local, other and base. These files can then be used to perform a merge
1804 local, other and base. These files can then be used to perform a merge
1803 manually. If the file to be merged is named "a.txt", these files will
1805 manually. If the file to be merged is named "a.txt", these files will
1804 accordingly be named "a.txt.local", "a.txt.other" and "a.txt.base" and
1806 accordingly be named "a.txt.local", "a.txt.other" and "a.txt.base" and
1805 they will be placed in the same directory as "a.txt".
1807 they will be placed in the same directory as "a.txt".
1806
1808
1807 This implies premerge. Therefore, files aren't dumped, if premerge runs
1809 This implies premerge. Therefore, files aren't dumped, if premerge runs
1808 successfully. Use :forcedump to forcibly write files out.
1810 successfully. Use :forcedump to forcibly write files out.
1809
1811
1810 ":fail"
1812 ":fail"
1811 Rather than attempting to merge files that were modified on both
1813 Rather than attempting to merge files that were modified on both
1812 branches, it marks them as unresolved. The resolve command must be used
1814 branches, it marks them as unresolved. The resolve command must be used
1813 to resolve these conflicts.
1815 to resolve these conflicts.
1814
1816
1815 ":forcedump"
1817 ":forcedump"
1816 Creates three versions of the files as same as :dump, but omits
1818 Creates three versions of the files as same as :dump, but omits
1817 premerge.
1819 premerge.
1818
1820
1819 ":local"
1821 ":local"
1820 Uses the local 'p1()' version of files as the merged version.
1822 Uses the local 'p1()' version of files as the merged version.
1821
1823
1822 ":merge"
1824 ":merge"
1823 Uses the internal non-interactive simple merge algorithm for merging
1825 Uses the internal non-interactive simple merge algorithm for merging
1824 files. It will fail if there are any conflicts and leave markers in the
1826 files. It will fail if there are any conflicts and leave markers in the
1825 partially merged file. Markers will have two sections, one for each side
1827 partially merged file. Markers will have two sections, one for each side
1826 of merge.
1828 of merge.
1827
1829
1828 ":merge-local"
1830 ":merge-local"
1829 Like :merge, but resolve all conflicts non-interactively in favor of the
1831 Like :merge, but resolve all conflicts non-interactively in favor of the
1830 local 'p1()' changes.
1832 local 'p1()' changes.
1831
1833
1832 ":merge-other"
1834 ":merge-other"
1833 Like :merge, but resolve all conflicts non-interactively in favor of the
1835 Like :merge, but resolve all conflicts non-interactively in favor of the
1834 other 'p2()' changes.
1836 other 'p2()' changes.
1835
1837
1836 ":merge3"
1838 ":merge3"
1837 Uses the internal non-interactive simple merge algorithm for merging
1839 Uses the internal non-interactive simple merge algorithm for merging
1838 files. It will fail if there are any conflicts and leave markers in the
1840 files. It will fail if there are any conflicts and leave markers in the
1839 partially merged file. Marker will have three sections, one from each
1841 partially merged file. Marker will have three sections, one from each
1840 side of the merge and one for the base content.
1842 side of the merge and one for the base content.
1841
1843
1842 ":other"
1844 ":other"
1843 Uses the other 'p2()' version of files as the merged version.
1845 Uses the other 'p2()' version of files as the merged version.
1844
1846
1845 ":prompt"
1847 ":prompt"
1846 Asks the user which of the local 'p1()' or the other 'p2()' version to
1848 Asks the user which of the local 'p1()' or the other 'p2()' version to
1847 keep as the merged version.
1849 keep as the merged version.
1848
1850
1849 ":tagmerge"
1851 ":tagmerge"
1850 Uses the internal tag merge algorithm (experimental).
1852 Uses the internal tag merge algorithm (experimental).
1851
1853
1852 ":union"
1854 ":union"
1853 Uses the internal non-interactive simple merge algorithm for merging
1855 Uses the internal non-interactive simple merge algorithm for merging
1854 files. It will use both left and right sides for conflict regions. No
1856 files. It will use both left and right sides for conflict regions. No
1855 markers are inserted.
1857 markers are inserted.
1856
1858
1857 Internal tools are always available and do not require a GUI but will by
1859 Internal tools are always available and do not require a GUI but will by
1858 default not handle symlinks or binary files.
1860 default not handle symlinks or binary files.
1859
1861
1860 Choosing a merge tool
1862 Choosing a merge tool
1861 =====================
1863 =====================
1862
1864
1863 Mercurial uses these rules when deciding which merge tool to use:
1865 Mercurial uses these rules when deciding which merge tool to use:
1864
1866
1865 1. If a tool has been specified with the --tool option to merge or
1867 1. If a tool has been specified with the --tool option to merge or
1866 resolve, it is used. If it is the name of a tool in the merge-tools
1868 resolve, it is used. If it is the name of a tool in the merge-tools
1867 configuration, its configuration is used. Otherwise the specified tool
1869 configuration, its configuration is used. Otherwise the specified tool
1868 must be executable by the shell.
1870 must be executable by the shell.
1869 2. If the "HGMERGE" environment variable is present, its value is used and
1871 2. If the "HGMERGE" environment variable is present, its value is used and
1870 must be executable by the shell.
1872 must be executable by the shell.
1871 3. If the filename of the file to be merged matches any of the patterns in
1873 3. If the filename of the file to be merged matches any of the patterns in
1872 the merge-patterns configuration section, the first usable merge tool
1874 the merge-patterns configuration section, the first usable merge tool
1873 corresponding to a matching pattern is used. Here, binary capabilities
1875 corresponding to a matching pattern is used. Here, binary capabilities
1874 of the merge tool are not considered.
1876 of the merge tool are not considered.
1875 4. If ui.merge is set it will be considered next. If the value is not the
1877 4. If ui.merge is set it will be considered next. If the value is not the
1876 name of a configured tool, the specified value is used and must be
1878 name of a configured tool, the specified value is used and must be
1877 executable by the shell. Otherwise the named tool is used if it is
1879 executable by the shell. Otherwise the named tool is used if it is
1878 usable.
1880 usable.
1879 5. If any usable merge tools are present in the merge-tools configuration
1881 5. If any usable merge tools are present in the merge-tools configuration
1880 section, the one with the highest priority is used.
1882 section, the one with the highest priority is used.
1881 6. If a program named "hgmerge" can be found on the system, it is used -
1883 6. If a program named "hgmerge" can be found on the system, it is used -
1882 but it will by default not be used for symlinks and binary files.
1884 but it will by default not be used for symlinks and binary files.
1883 7. If the file to be merged is not binary and is not a symlink, then
1885 7. If the file to be merged is not binary and is not a symlink, then
1884 internal ":merge" is used.
1886 internal ":merge" is used.
1885 8. Otherwise, ":prompt" is used.
1887 8. Otherwise, ":prompt" is used.
1886
1888
1887 Note:
1889 Note:
1888 After selecting a merge program, Mercurial will by default attempt to
1890 After selecting a merge program, Mercurial will by default attempt to
1889 merge the files using a simple merge algorithm first. Only if it
1891 merge the files using a simple merge algorithm first. Only if it
1890 doesn't succeed because of conflicting changes will Mercurial actually
1892 doesn't succeed because of conflicting changes will Mercurial actually
1891 execute the merge program. Whether to use the simple merge algorithm
1893 execute the merge program. Whether to use the simple merge algorithm
1892 first can be controlled by the premerge setting of the merge tool.
1894 first can be controlled by the premerge setting of the merge tool.
1893 Premerge is enabled by default unless the file is binary or a symlink.
1895 Premerge is enabled by default unless the file is binary or a symlink.
1894
1896
1895 See the merge-tools and ui sections of hgrc(5) for details on the
1897 See the merge-tools and ui sections of hgrc(5) for details on the
1896 configuration of merge tools.
1898 configuration of merge tools.
1897
1899
1898 Compression engines listed in `hg help bundlespec`
1900 Compression engines listed in `hg help bundlespec`
1899
1901
1900 $ hg help bundlespec | grep gzip
1902 $ hg help bundlespec | grep gzip
1901 "v1" bundles can only use the "gzip", "bzip2", and "none" compression
1903 "v1" bundles can only use the "gzip", "bzip2", and "none" compression
1902 An algorithm that produces smaller bundles than "gzip".
1904 An algorithm that produces smaller bundles than "gzip".
1903 This engine will likely produce smaller bundles than "gzip" but will be
1905 This engine will likely produce smaller bundles than "gzip" but will be
1904 "gzip"
1906 "gzip"
1905 better compression than "gzip". It also frequently yields better (?)
1907 better compression than "gzip". It also frequently yields better (?)
1906
1908
1907 Test usage of section marks in help documents
1909 Test usage of section marks in help documents
1908
1910
1909 $ cd "$TESTDIR"/../doc
1911 $ cd "$TESTDIR"/../doc
1910 $ $PYTHON check-seclevel.py
1912 $ $PYTHON check-seclevel.py
1911 $ cd $TESTTMP
1913 $ cd $TESTTMP
1912
1914
1913 #if serve
1915 #if serve
1914
1916
1915 Test the help pages in hgweb.
1917 Test the help pages in hgweb.
1916
1918
1917 Dish up an empty repo; serve it cold.
1919 Dish up an empty repo; serve it cold.
1918
1920
1919 $ hg init "$TESTTMP/test"
1921 $ hg init "$TESTTMP/test"
1920 $ hg serve -R "$TESTTMP/test" -n test -p $HGPORT -d --pid-file=hg.pid
1922 $ hg serve -R "$TESTTMP/test" -n test -p $HGPORT -d --pid-file=hg.pid
1921 $ cat hg.pid >> $DAEMON_PIDS
1923 $ cat hg.pid >> $DAEMON_PIDS
1922
1924
1923 $ get-with-headers.py $LOCALIP:$HGPORT "help"
1925 $ get-with-headers.py $LOCALIP:$HGPORT "help"
1924 200 Script output follows
1926 200 Script output follows
1925
1927
1926 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1928 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1927 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1929 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1928 <head>
1930 <head>
1929 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1931 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1930 <meta name="robots" content="index, nofollow" />
1932 <meta name="robots" content="index, nofollow" />
1931 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1933 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1932 <script type="text/javascript" src="/static/mercurial.js"></script>
1934 <script type="text/javascript" src="/static/mercurial.js"></script>
1933
1935
1934 <title>Help: Index</title>
1936 <title>Help: Index</title>
1935 </head>
1937 </head>
1936 <body>
1938 <body>
1937
1939
1938 <div class="container">
1940 <div class="container">
1939 <div class="menu">
1941 <div class="menu">
1940 <div class="logo">
1942 <div class="logo">
1941 <a href="https://mercurial-scm.org/">
1943 <a href="https://mercurial-scm.org/">
1942 <img src="/static/hglogo.png" alt="mercurial" /></a>
1944 <img src="/static/hglogo.png" alt="mercurial" /></a>
1943 </div>
1945 </div>
1944 <ul>
1946 <ul>
1945 <li><a href="/shortlog">log</a></li>
1947 <li><a href="/shortlog">log</a></li>
1946 <li><a href="/graph">graph</a></li>
1948 <li><a href="/graph">graph</a></li>
1947 <li><a href="/tags">tags</a></li>
1949 <li><a href="/tags">tags</a></li>
1948 <li><a href="/bookmarks">bookmarks</a></li>
1950 <li><a href="/bookmarks">bookmarks</a></li>
1949 <li><a href="/branches">branches</a></li>
1951 <li><a href="/branches">branches</a></li>
1950 </ul>
1952 </ul>
1951 <ul>
1953 <ul>
1952 <li class="active">help</li>
1954 <li class="active">help</li>
1953 </ul>
1955 </ul>
1954 </div>
1956 </div>
1955
1957
1956 <div class="main">
1958 <div class="main">
1957 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1959 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1958
1960
1959 <form class="search" action="/log">
1961 <form class="search" action="/log">
1960
1962
1961 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
1963 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
1962 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1964 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1963 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1965 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1964 </form>
1966 </form>
1965 <table class="bigtable">
1967 <table class="bigtable">
1966 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
1968 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
1967
1969
1968 <tr><td>
1970 <tr><td>
1969 <a href="/help/bundlespec">
1971 <a href="/help/bundlespec">
1970 bundlespec
1972 bundlespec
1971 </a>
1973 </a>
1972 </td><td>
1974 </td><td>
1973 Bundle File Formats
1975 Bundle File Formats
1974 </td></tr>
1976 </td></tr>
1975 <tr><td>
1977 <tr><td>
1976 <a href="/help/color">
1978 <a href="/help/color">
1977 color
1979 color
1978 </a>
1980 </a>
1979 </td><td>
1981 </td><td>
1980 Colorizing Outputs
1982 Colorizing Outputs
1981 </td></tr>
1983 </td></tr>
1982 <tr><td>
1984 <tr><td>
1983 <a href="/help/config">
1985 <a href="/help/config">
1984 config
1986 config
1985 </a>
1987 </a>
1986 </td><td>
1988 </td><td>
1987 Configuration Files
1989 Configuration Files
1988 </td></tr>
1990 </td></tr>
1989 <tr><td>
1991 <tr><td>
1990 <a href="/help/dates">
1992 <a href="/help/dates">
1991 dates
1993 dates
1992 </a>
1994 </a>
1993 </td><td>
1995 </td><td>
1994 Date Formats
1996 Date Formats
1995 </td></tr>
1997 </td></tr>
1996 <tr><td>
1998 <tr><td>
1997 <a href="/help/diffs">
1999 <a href="/help/diffs">
1998 diffs
2000 diffs
1999 </a>
2001 </a>
2000 </td><td>
2002 </td><td>
2001 Diff Formats
2003 Diff Formats
2002 </td></tr>
2004 </td></tr>
2003 <tr><td>
2005 <tr><td>
2004 <a href="/help/environment">
2006 <a href="/help/environment">
2005 environment
2007 environment
2006 </a>
2008 </a>
2007 </td><td>
2009 </td><td>
2008 Environment Variables
2010 Environment Variables
2009 </td></tr>
2011 </td></tr>
2010 <tr><td>
2012 <tr><td>
2011 <a href="/help/extensions">
2013 <a href="/help/extensions">
2012 extensions
2014 extensions
2013 </a>
2015 </a>
2014 </td><td>
2016 </td><td>
2015 Using Additional Features
2017 Using Additional Features
2016 </td></tr>
2018 </td></tr>
2017 <tr><td>
2019 <tr><td>
2018 <a href="/help/filesets">
2020 <a href="/help/filesets">
2019 filesets
2021 filesets
2020 </a>
2022 </a>
2021 </td><td>
2023 </td><td>
2022 Specifying File Sets
2024 Specifying File Sets
2023 </td></tr>
2025 </td></tr>
2024 <tr><td>
2026 <tr><td>
2025 <a href="/help/flags">
2027 <a href="/help/flags">
2026 flags
2028 flags
2027 </a>
2029 </a>
2028 </td><td>
2030 </td><td>
2029 Command-line flags
2031 Command-line flags
2030 </td></tr>
2032 </td></tr>
2031 <tr><td>
2033 <tr><td>
2032 <a href="/help/glossary">
2034 <a href="/help/glossary">
2033 glossary
2035 glossary
2034 </a>
2036 </a>
2035 </td><td>
2037 </td><td>
2036 Glossary
2038 Glossary
2037 </td></tr>
2039 </td></tr>
2038 <tr><td>
2040 <tr><td>
2039 <a href="/help/hgignore">
2041 <a href="/help/hgignore">
2040 hgignore
2042 hgignore
2041 </a>
2043 </a>
2042 </td><td>
2044 </td><td>
2043 Syntax for Mercurial Ignore Files
2045 Syntax for Mercurial Ignore Files
2044 </td></tr>
2046 </td></tr>
2045 <tr><td>
2047 <tr><td>
2046 <a href="/help/hgweb">
2048 <a href="/help/hgweb">
2047 hgweb
2049 hgweb
2048 </a>
2050 </a>
2049 </td><td>
2051 </td><td>
2050 Configuring hgweb
2052 Configuring hgweb
2051 </td></tr>
2053 </td></tr>
2052 <tr><td>
2054 <tr><td>
2053 <a href="/help/internals">
2055 <a href="/help/internals">
2054 internals
2056 internals
2055 </a>
2057 </a>
2056 </td><td>
2058 </td><td>
2057 Technical implementation topics
2059 Technical implementation topics
2058 </td></tr>
2060 </td></tr>
2059 <tr><td>
2061 <tr><td>
2060 <a href="/help/merge-tools">
2062 <a href="/help/merge-tools">
2061 merge-tools
2063 merge-tools
2062 </a>
2064 </a>
2063 </td><td>
2065 </td><td>
2064 Merge Tools
2066 Merge Tools
2065 </td></tr>
2067 </td></tr>
2066 <tr><td>
2068 <tr><td>
2067 <a href="/help/pager">
2069 <a href="/help/pager">
2068 pager
2070 pager
2069 </a>
2071 </a>
2070 </td><td>
2072 </td><td>
2071 Pager Support
2073 Pager Support
2072 </td></tr>
2074 </td></tr>
2073 <tr><td>
2075 <tr><td>
2074 <a href="/help/patterns">
2076 <a href="/help/patterns">
2075 patterns
2077 patterns
2076 </a>
2078 </a>
2077 </td><td>
2079 </td><td>
2078 File Name Patterns
2080 File Name Patterns
2079 </td></tr>
2081 </td></tr>
2080 <tr><td>
2082 <tr><td>
2081 <a href="/help/phases">
2083 <a href="/help/phases">
2082 phases
2084 phases
2083 </a>
2085 </a>
2084 </td><td>
2086 </td><td>
2085 Working with Phases
2087 Working with Phases
2086 </td></tr>
2088 </td></tr>
2087 <tr><td>
2089 <tr><td>
2088 <a href="/help/revisions">
2090 <a href="/help/revisions">
2089 revisions
2091 revisions
2090 </a>
2092 </a>
2091 </td><td>
2093 </td><td>
2092 Specifying Revisions
2094 Specifying Revisions
2093 </td></tr>
2095 </td></tr>
2094 <tr><td>
2096 <tr><td>
2095 <a href="/help/scripting">
2097 <a href="/help/scripting">
2096 scripting
2098 scripting
2097 </a>
2099 </a>
2098 </td><td>
2100 </td><td>
2099 Using Mercurial from scripts and automation
2101 Using Mercurial from scripts and automation
2100 </td></tr>
2102 </td></tr>
2101 <tr><td>
2103 <tr><td>
2102 <a href="/help/subrepos">
2104 <a href="/help/subrepos">
2103 subrepos
2105 subrepos
2104 </a>
2106 </a>
2105 </td><td>
2107 </td><td>
2106 Subrepositories
2108 Subrepositories
2107 </td></tr>
2109 </td></tr>
2108 <tr><td>
2110 <tr><td>
2109 <a href="/help/templating">
2111 <a href="/help/templating">
2110 templating
2112 templating
2111 </a>
2113 </a>
2112 </td><td>
2114 </td><td>
2113 Template Usage
2115 Template Usage
2114 </td></tr>
2116 </td></tr>
2115 <tr><td>
2117 <tr><td>
2116 <a href="/help/urls">
2118 <a href="/help/urls">
2117 urls
2119 urls
2118 </a>
2120 </a>
2119 </td><td>
2121 </td><td>
2120 URL Paths
2122 URL Paths
2121 </td></tr>
2123 </td></tr>
2122 <tr><td>
2124 <tr><td>
2123 <a href="/help/topic-containing-verbose">
2125 <a href="/help/topic-containing-verbose">
2124 topic-containing-verbose
2126 topic-containing-verbose
2125 </a>
2127 </a>
2126 </td><td>
2128 </td><td>
2127 This is the topic to test omit indicating.
2129 This is the topic to test omit indicating.
2128 </td></tr>
2130 </td></tr>
2129
2131
2130
2132
2131 <tr><td colspan="2"><h2><a name="main" href="#main">Main Commands</a></h2></td></tr>
2133 <tr><td colspan="2"><h2><a name="main" href="#main">Main Commands</a></h2></td></tr>
2132
2134
2133 <tr><td>
2135 <tr><td>
2134 <a href="/help/add">
2136 <a href="/help/add">
2135 add
2137 add
2136 </a>
2138 </a>
2137 </td><td>
2139 </td><td>
2138 add the specified files on the next commit
2140 add the specified files on the next commit
2139 </td></tr>
2141 </td></tr>
2140 <tr><td>
2142 <tr><td>
2141 <a href="/help/annotate">
2143 <a href="/help/annotate">
2142 annotate
2144 annotate
2143 </a>
2145 </a>
2144 </td><td>
2146 </td><td>
2145 show changeset information by line for each file
2147 show changeset information by line for each file
2146 </td></tr>
2148 </td></tr>
2147 <tr><td>
2149 <tr><td>
2148 <a href="/help/clone">
2150 <a href="/help/clone">
2149 clone
2151 clone
2150 </a>
2152 </a>
2151 </td><td>
2153 </td><td>
2152 make a copy of an existing repository
2154 make a copy of an existing repository
2153 </td></tr>
2155 </td></tr>
2154 <tr><td>
2156 <tr><td>
2155 <a href="/help/commit">
2157 <a href="/help/commit">
2156 commit
2158 commit
2157 </a>
2159 </a>
2158 </td><td>
2160 </td><td>
2159 commit the specified files or all outstanding changes
2161 commit the specified files or all outstanding changes
2160 </td></tr>
2162 </td></tr>
2161 <tr><td>
2163 <tr><td>
2162 <a href="/help/diff">
2164 <a href="/help/diff">
2163 diff
2165 diff
2164 </a>
2166 </a>
2165 </td><td>
2167 </td><td>
2166 diff repository (or selected files)
2168 diff repository (or selected files)
2167 </td></tr>
2169 </td></tr>
2168 <tr><td>
2170 <tr><td>
2169 <a href="/help/export">
2171 <a href="/help/export">
2170 export
2172 export
2171 </a>
2173 </a>
2172 </td><td>
2174 </td><td>
2173 dump the header and diffs for one or more changesets
2175 dump the header and diffs for one or more changesets
2174 </td></tr>
2176 </td></tr>
2175 <tr><td>
2177 <tr><td>
2176 <a href="/help/forget">
2178 <a href="/help/forget">
2177 forget
2179 forget
2178 </a>
2180 </a>
2179 </td><td>
2181 </td><td>
2180 forget the specified files on the next commit
2182 forget the specified files on the next commit
2181 </td></tr>
2183 </td></tr>
2182 <tr><td>
2184 <tr><td>
2183 <a href="/help/init">
2185 <a href="/help/init">
2184 init
2186 init
2185 </a>
2187 </a>
2186 </td><td>
2188 </td><td>
2187 create a new repository in the given directory
2189 create a new repository in the given directory
2188 </td></tr>
2190 </td></tr>
2189 <tr><td>
2191 <tr><td>
2190 <a href="/help/log">
2192 <a href="/help/log">
2191 log
2193 log
2192 </a>
2194 </a>
2193 </td><td>
2195 </td><td>
2194 show revision history of entire repository or files
2196 show revision history of entire repository or files
2195 </td></tr>
2197 </td></tr>
2196 <tr><td>
2198 <tr><td>
2197 <a href="/help/merge">
2199 <a href="/help/merge">
2198 merge
2200 merge
2199 </a>
2201 </a>
2200 </td><td>
2202 </td><td>
2201 merge another revision into working directory
2203 merge another revision into working directory
2202 </td></tr>
2204 </td></tr>
2203 <tr><td>
2205 <tr><td>
2204 <a href="/help/pull">
2206 <a href="/help/pull">
2205 pull
2207 pull
2206 </a>
2208 </a>
2207 </td><td>
2209 </td><td>
2208 pull changes from the specified source
2210 pull changes from the specified source
2209 </td></tr>
2211 </td></tr>
2210 <tr><td>
2212 <tr><td>
2211 <a href="/help/push">
2213 <a href="/help/push">
2212 push
2214 push
2213 </a>
2215 </a>
2214 </td><td>
2216 </td><td>
2215 push changes to the specified destination
2217 push changes to the specified destination
2216 </td></tr>
2218 </td></tr>
2217 <tr><td>
2219 <tr><td>
2218 <a href="/help/remove">
2220 <a href="/help/remove">
2219 remove
2221 remove
2220 </a>
2222 </a>
2221 </td><td>
2223 </td><td>
2222 remove the specified files on the next commit
2224 remove the specified files on the next commit
2223 </td></tr>
2225 </td></tr>
2224 <tr><td>
2226 <tr><td>
2225 <a href="/help/serve">
2227 <a href="/help/serve">
2226 serve
2228 serve
2227 </a>
2229 </a>
2228 </td><td>
2230 </td><td>
2229 start stand-alone webserver
2231 start stand-alone webserver
2230 </td></tr>
2232 </td></tr>
2231 <tr><td>
2233 <tr><td>
2232 <a href="/help/status">
2234 <a href="/help/status">
2233 status
2235 status
2234 </a>
2236 </a>
2235 </td><td>
2237 </td><td>
2236 show changed files in the working directory
2238 show changed files in the working directory
2237 </td></tr>
2239 </td></tr>
2238 <tr><td>
2240 <tr><td>
2239 <a href="/help/summary">
2241 <a href="/help/summary">
2240 summary
2242 summary
2241 </a>
2243 </a>
2242 </td><td>
2244 </td><td>
2243 summarize working directory state
2245 summarize working directory state
2244 </td></tr>
2246 </td></tr>
2245 <tr><td>
2247 <tr><td>
2246 <a href="/help/update">
2248 <a href="/help/update">
2247 update
2249 update
2248 </a>
2250 </a>
2249 </td><td>
2251 </td><td>
2250 update working directory (or switch revisions)
2252 update working directory (or switch revisions)
2251 </td></tr>
2253 </td></tr>
2252
2254
2253
2255
2254
2256
2255 <tr><td colspan="2"><h2><a name="other" href="#other">Other Commands</a></h2></td></tr>
2257 <tr><td colspan="2"><h2><a name="other" href="#other">Other Commands</a></h2></td></tr>
2256
2258
2257 <tr><td>
2259 <tr><td>
2258 <a href="/help/addremove">
2260 <a href="/help/addremove">
2259 addremove
2261 addremove
2260 </a>
2262 </a>
2261 </td><td>
2263 </td><td>
2262 add all new files, delete all missing files
2264 add all new files, delete all missing files
2263 </td></tr>
2265 </td></tr>
2264 <tr><td>
2266 <tr><td>
2265 <a href="/help/archive">
2267 <a href="/help/archive">
2266 archive
2268 archive
2267 </a>
2269 </a>
2268 </td><td>
2270 </td><td>
2269 create an unversioned archive of a repository revision
2271 create an unversioned archive of a repository revision
2270 </td></tr>
2272 </td></tr>
2271 <tr><td>
2273 <tr><td>
2272 <a href="/help/backout">
2274 <a href="/help/backout">
2273 backout
2275 backout
2274 </a>
2276 </a>
2275 </td><td>
2277 </td><td>
2276 reverse effect of earlier changeset
2278 reverse effect of earlier changeset
2277 </td></tr>
2279 </td></tr>
2278 <tr><td>
2280 <tr><td>
2279 <a href="/help/bisect">
2281 <a href="/help/bisect">
2280 bisect
2282 bisect
2281 </a>
2283 </a>
2282 </td><td>
2284 </td><td>
2283 subdivision search of changesets
2285 subdivision search of changesets
2284 </td></tr>
2286 </td></tr>
2285 <tr><td>
2287 <tr><td>
2286 <a href="/help/bookmarks">
2288 <a href="/help/bookmarks">
2287 bookmarks
2289 bookmarks
2288 </a>
2290 </a>
2289 </td><td>
2291 </td><td>
2290 create a new bookmark or list existing bookmarks
2292 create a new bookmark or list existing bookmarks
2291 </td></tr>
2293 </td></tr>
2292 <tr><td>
2294 <tr><td>
2293 <a href="/help/branch">
2295 <a href="/help/branch">
2294 branch
2296 branch
2295 </a>
2297 </a>
2296 </td><td>
2298 </td><td>
2297 set or show the current branch name
2299 set or show the current branch name
2298 </td></tr>
2300 </td></tr>
2299 <tr><td>
2301 <tr><td>
2300 <a href="/help/branches">
2302 <a href="/help/branches">
2301 branches
2303 branches
2302 </a>
2304 </a>
2303 </td><td>
2305 </td><td>
2304 list repository named branches
2306 list repository named branches
2305 </td></tr>
2307 </td></tr>
2306 <tr><td>
2308 <tr><td>
2307 <a href="/help/bundle">
2309 <a href="/help/bundle">
2308 bundle
2310 bundle
2309 </a>
2311 </a>
2310 </td><td>
2312 </td><td>
2311 create a bundle file
2313 create a bundle file
2312 </td></tr>
2314 </td></tr>
2313 <tr><td>
2315 <tr><td>
2314 <a href="/help/cat">
2316 <a href="/help/cat">
2315 cat
2317 cat
2316 </a>
2318 </a>
2317 </td><td>
2319 </td><td>
2318 output the current or given revision of files
2320 output the current or given revision of files
2319 </td></tr>
2321 </td></tr>
2320 <tr><td>
2322 <tr><td>
2321 <a href="/help/config">
2323 <a href="/help/config">
2322 config
2324 config
2323 </a>
2325 </a>
2324 </td><td>
2326 </td><td>
2325 show combined config settings from all hgrc files
2327 show combined config settings from all hgrc files
2326 </td></tr>
2328 </td></tr>
2327 <tr><td>
2329 <tr><td>
2328 <a href="/help/copy">
2330 <a href="/help/copy">
2329 copy
2331 copy
2330 </a>
2332 </a>
2331 </td><td>
2333 </td><td>
2332 mark files as copied for the next commit
2334 mark files as copied for the next commit
2333 </td></tr>
2335 </td></tr>
2334 <tr><td>
2336 <tr><td>
2335 <a href="/help/files">
2337 <a href="/help/files">
2336 files
2338 files
2337 </a>
2339 </a>
2338 </td><td>
2340 </td><td>
2339 list tracked files
2341 list tracked files
2340 </td></tr>
2342 </td></tr>
2341 <tr><td>
2343 <tr><td>
2342 <a href="/help/graft">
2344 <a href="/help/graft">
2343 graft
2345 graft
2344 </a>
2346 </a>
2345 </td><td>
2347 </td><td>
2346 copy changes from other branches onto the current branch
2348 copy changes from other branches onto the current branch
2347 </td></tr>
2349 </td></tr>
2348 <tr><td>
2350 <tr><td>
2349 <a href="/help/grep">
2351 <a href="/help/grep">
2350 grep
2352 grep
2351 </a>
2353 </a>
2352 </td><td>
2354 </td><td>
2353 search revision history for a pattern in specified files
2355 search revision history for a pattern in specified files
2354 </td></tr>
2356 </td></tr>
2355 <tr><td>
2357 <tr><td>
2356 <a href="/help/heads">
2358 <a href="/help/heads">
2357 heads
2359 heads
2358 </a>
2360 </a>
2359 </td><td>
2361 </td><td>
2360 show branch heads
2362 show branch heads
2361 </td></tr>
2363 </td></tr>
2362 <tr><td>
2364 <tr><td>
2363 <a href="/help/help">
2365 <a href="/help/help">
2364 help
2366 help
2365 </a>
2367 </a>
2366 </td><td>
2368 </td><td>
2367 show help for a given topic or a help overview
2369 show help for a given topic or a help overview
2368 </td></tr>
2370 </td></tr>
2369 <tr><td>
2371 <tr><td>
2370 <a href="/help/hgalias">
2372 <a href="/help/hgalias">
2371 hgalias
2373 hgalias
2372 </a>
2374 </a>
2373 </td><td>
2375 </td><td>
2374 summarize working directory state
2376 summarize working directory state
2375 </td></tr>
2377 </td></tr>
2376 <tr><td>
2378 <tr><td>
2377 <a href="/help/identify">
2379 <a href="/help/identify">
2378 identify
2380 identify
2379 </a>
2381 </a>
2380 </td><td>
2382 </td><td>
2381 identify the working directory or specified revision
2383 identify the working directory or specified revision
2382 </td></tr>
2384 </td></tr>
2383 <tr><td>
2385 <tr><td>
2384 <a href="/help/import">
2386 <a href="/help/import">
2385 import
2387 import
2386 </a>
2388 </a>
2387 </td><td>
2389 </td><td>
2388 import an ordered set of patches
2390 import an ordered set of patches
2389 </td></tr>
2391 </td></tr>
2390 <tr><td>
2392 <tr><td>
2391 <a href="/help/incoming">
2393 <a href="/help/incoming">
2392 incoming
2394 incoming
2393 </a>
2395 </a>
2394 </td><td>
2396 </td><td>
2395 show new changesets found in source
2397 show new changesets found in source
2396 </td></tr>
2398 </td></tr>
2397 <tr><td>
2399 <tr><td>
2398 <a href="/help/manifest">
2400 <a href="/help/manifest">
2399 manifest
2401 manifest
2400 </a>
2402 </a>
2401 </td><td>
2403 </td><td>
2402 output the current or given revision of the project manifest
2404 output the current or given revision of the project manifest
2403 </td></tr>
2405 </td></tr>
2404 <tr><td>
2406 <tr><td>
2405 <a href="/help/nohelp">
2407 <a href="/help/nohelp">
2406 nohelp
2408 nohelp
2407 </a>
2409 </a>
2408 </td><td>
2410 </td><td>
2409 (no help text available)
2411 (no help text available)
2410 </td></tr>
2412 </td></tr>
2411 <tr><td>
2413 <tr><td>
2412 <a href="/help/outgoing">
2414 <a href="/help/outgoing">
2413 outgoing
2415 outgoing
2414 </a>
2416 </a>
2415 </td><td>
2417 </td><td>
2416 show changesets not found in the destination
2418 show changesets not found in the destination
2417 </td></tr>
2419 </td></tr>
2418 <tr><td>
2420 <tr><td>
2419 <a href="/help/paths">
2421 <a href="/help/paths">
2420 paths
2422 paths
2421 </a>
2423 </a>
2422 </td><td>
2424 </td><td>
2423 show aliases for remote repositories
2425 show aliases for remote repositories
2424 </td></tr>
2426 </td></tr>
2425 <tr><td>
2427 <tr><td>
2426 <a href="/help/phase">
2428 <a href="/help/phase">
2427 phase
2429 phase
2428 </a>
2430 </a>
2429 </td><td>
2431 </td><td>
2430 set or show the current phase name
2432 set or show the current phase name
2431 </td></tr>
2433 </td></tr>
2432 <tr><td>
2434 <tr><td>
2433 <a href="/help/recover">
2435 <a href="/help/recover">
2434 recover
2436 recover
2435 </a>
2437 </a>
2436 </td><td>
2438 </td><td>
2437 roll back an interrupted transaction
2439 roll back an interrupted transaction
2438 </td></tr>
2440 </td></tr>
2439 <tr><td>
2441 <tr><td>
2440 <a href="/help/rename">
2442 <a href="/help/rename">
2441 rename
2443 rename
2442 </a>
2444 </a>
2443 </td><td>
2445 </td><td>
2444 rename files; equivalent of copy + remove
2446 rename files; equivalent of copy + remove
2445 </td></tr>
2447 </td></tr>
2446 <tr><td>
2448 <tr><td>
2447 <a href="/help/resolve">
2449 <a href="/help/resolve">
2448 resolve
2450 resolve
2449 </a>
2451 </a>
2450 </td><td>
2452 </td><td>
2451 redo merges or set/view the merge status of files
2453 redo merges or set/view the merge status of files
2452 </td></tr>
2454 </td></tr>
2453 <tr><td>
2455 <tr><td>
2454 <a href="/help/revert">
2456 <a href="/help/revert">
2455 revert
2457 revert
2456 </a>
2458 </a>
2457 </td><td>
2459 </td><td>
2458 restore files to their checkout state
2460 restore files to their checkout state
2459 </td></tr>
2461 </td></tr>
2460 <tr><td>
2462 <tr><td>
2461 <a href="/help/root">
2463 <a href="/help/root">
2462 root
2464 root
2463 </a>
2465 </a>
2464 </td><td>
2466 </td><td>
2465 print the root (top) of the current working directory
2467 print the root (top) of the current working directory
2466 </td></tr>
2468 </td></tr>
2467 <tr><td>
2469 <tr><td>
2468 <a href="/help/shellalias">
2470 <a href="/help/shellalias">
2469 shellalias
2471 shellalias
2470 </a>
2472 </a>
2471 </td><td>
2473 </td><td>
2472 (no help text available)
2474 (no help text available)
2473 </td></tr>
2475 </td></tr>
2474 <tr><td>
2476 <tr><td>
2475 <a href="/help/tag">
2477 <a href="/help/tag">
2476 tag
2478 tag
2477 </a>
2479 </a>
2478 </td><td>
2480 </td><td>
2479 add one or more tags for the current or given revision
2481 add one or more tags for the current or given revision
2480 </td></tr>
2482 </td></tr>
2481 <tr><td>
2483 <tr><td>
2482 <a href="/help/tags">
2484 <a href="/help/tags">
2483 tags
2485 tags
2484 </a>
2486 </a>
2485 </td><td>
2487 </td><td>
2486 list repository tags
2488 list repository tags
2487 </td></tr>
2489 </td></tr>
2488 <tr><td>
2490 <tr><td>
2489 <a href="/help/unbundle">
2491 <a href="/help/unbundle">
2490 unbundle
2492 unbundle
2491 </a>
2493 </a>
2492 </td><td>
2494 </td><td>
2493 apply one or more bundle files
2495 apply one or more bundle files
2494 </td></tr>
2496 </td></tr>
2495 <tr><td>
2497 <tr><td>
2496 <a href="/help/verify">
2498 <a href="/help/verify">
2497 verify
2499 verify
2498 </a>
2500 </a>
2499 </td><td>
2501 </td><td>
2500 verify the integrity of the repository
2502 verify the integrity of the repository
2501 </td></tr>
2503 </td></tr>
2502 <tr><td>
2504 <tr><td>
2503 <a href="/help/version">
2505 <a href="/help/version">
2504 version
2506 version
2505 </a>
2507 </a>
2506 </td><td>
2508 </td><td>
2507 output version and copyright information
2509 output version and copyright information
2508 </td></tr>
2510 </td></tr>
2509
2511
2510
2512
2511 </table>
2513 </table>
2512 </div>
2514 </div>
2513 </div>
2515 </div>
2514
2516
2515
2517
2516
2518
2517 </body>
2519 </body>
2518 </html>
2520 </html>
2519
2521
2520
2522
2521 $ get-with-headers.py $LOCALIP:$HGPORT "help/add"
2523 $ get-with-headers.py $LOCALIP:$HGPORT "help/add"
2522 200 Script output follows
2524 200 Script output follows
2523
2525
2524 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2526 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2525 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2527 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2526 <head>
2528 <head>
2527 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2529 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2528 <meta name="robots" content="index, nofollow" />
2530 <meta name="robots" content="index, nofollow" />
2529 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2531 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2530 <script type="text/javascript" src="/static/mercurial.js"></script>
2532 <script type="text/javascript" src="/static/mercurial.js"></script>
2531
2533
2532 <title>Help: add</title>
2534 <title>Help: add</title>
2533 </head>
2535 </head>
2534 <body>
2536 <body>
2535
2537
2536 <div class="container">
2538 <div class="container">
2537 <div class="menu">
2539 <div class="menu">
2538 <div class="logo">
2540 <div class="logo">
2539 <a href="https://mercurial-scm.org/">
2541 <a href="https://mercurial-scm.org/">
2540 <img src="/static/hglogo.png" alt="mercurial" /></a>
2542 <img src="/static/hglogo.png" alt="mercurial" /></a>
2541 </div>
2543 </div>
2542 <ul>
2544 <ul>
2543 <li><a href="/shortlog">log</a></li>
2545 <li><a href="/shortlog">log</a></li>
2544 <li><a href="/graph">graph</a></li>
2546 <li><a href="/graph">graph</a></li>
2545 <li><a href="/tags">tags</a></li>
2547 <li><a href="/tags">tags</a></li>
2546 <li><a href="/bookmarks">bookmarks</a></li>
2548 <li><a href="/bookmarks">bookmarks</a></li>
2547 <li><a href="/branches">branches</a></li>
2549 <li><a href="/branches">branches</a></li>
2548 </ul>
2550 </ul>
2549 <ul>
2551 <ul>
2550 <li class="active"><a href="/help">help</a></li>
2552 <li class="active"><a href="/help">help</a></li>
2551 </ul>
2553 </ul>
2552 </div>
2554 </div>
2553
2555
2554 <div class="main">
2556 <div class="main">
2555 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2557 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2556 <h3>Help: add</h3>
2558 <h3>Help: add</h3>
2557
2559
2558 <form class="search" action="/log">
2560 <form class="search" action="/log">
2559
2561
2560 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2562 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2561 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2563 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2562 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2564 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2563 </form>
2565 </form>
2564 <div id="doc">
2566 <div id="doc">
2565 <p>
2567 <p>
2566 hg add [OPTION]... [FILE]...
2568 hg add [OPTION]... [FILE]...
2567 </p>
2569 </p>
2568 <p>
2570 <p>
2569 add the specified files on the next commit
2571 add the specified files on the next commit
2570 </p>
2572 </p>
2571 <p>
2573 <p>
2572 Schedule files to be version controlled and added to the
2574 Schedule files to be version controlled and added to the
2573 repository.
2575 repository.
2574 </p>
2576 </p>
2575 <p>
2577 <p>
2576 The files will be added to the repository at the next commit. To
2578 The files will be added to the repository at the next commit. To
2577 undo an add before that, see 'hg forget'.
2579 undo an add before that, see 'hg forget'.
2578 </p>
2580 </p>
2579 <p>
2581 <p>
2580 If no names are given, add all files to the repository (except
2582 If no names are given, add all files to the repository (except
2581 files matching &quot;.hgignore&quot;).
2583 files matching &quot;.hgignore&quot;).
2582 </p>
2584 </p>
2583 <p>
2585 <p>
2584 Examples:
2586 Examples:
2585 </p>
2587 </p>
2586 <ul>
2588 <ul>
2587 <li> New (unknown) files are added automatically by 'hg add':
2589 <li> New (unknown) files are added automatically by 'hg add':
2588 <pre>
2590 <pre>
2589 \$ ls (re)
2591 \$ ls (re)
2590 foo.c
2592 foo.c
2591 \$ hg status (re)
2593 \$ hg status (re)
2592 ? foo.c
2594 ? foo.c
2593 \$ hg add (re)
2595 \$ hg add (re)
2594 adding foo.c
2596 adding foo.c
2595 \$ hg status (re)
2597 \$ hg status (re)
2596 A foo.c
2598 A foo.c
2597 </pre>
2599 </pre>
2598 <li> Specific files to be added can be specified:
2600 <li> Specific files to be added can be specified:
2599 <pre>
2601 <pre>
2600 \$ ls (re)
2602 \$ ls (re)
2601 bar.c foo.c
2603 bar.c foo.c
2602 \$ hg status (re)
2604 \$ hg status (re)
2603 ? bar.c
2605 ? bar.c
2604 ? foo.c
2606 ? foo.c
2605 \$ hg add bar.c (re)
2607 \$ hg add bar.c (re)
2606 \$ hg status (re)
2608 \$ hg status (re)
2607 A bar.c
2609 A bar.c
2608 ? foo.c
2610 ? foo.c
2609 </pre>
2611 </pre>
2610 </ul>
2612 </ul>
2611 <p>
2613 <p>
2612 Returns 0 if all files are successfully added.
2614 Returns 0 if all files are successfully added.
2613 </p>
2615 </p>
2614 <p>
2616 <p>
2615 options ([+] can be repeated):
2617 options ([+] can be repeated):
2616 </p>
2618 </p>
2617 <table>
2619 <table>
2618 <tr><td>-I</td>
2620 <tr><td>-I</td>
2619 <td>--include PATTERN [+]</td>
2621 <td>--include PATTERN [+]</td>
2620 <td>include names matching the given patterns</td></tr>
2622 <td>include names matching the given patterns</td></tr>
2621 <tr><td>-X</td>
2623 <tr><td>-X</td>
2622 <td>--exclude PATTERN [+]</td>
2624 <td>--exclude PATTERN [+]</td>
2623 <td>exclude names matching the given patterns</td></tr>
2625 <td>exclude names matching the given patterns</td></tr>
2624 <tr><td>-S</td>
2626 <tr><td>-S</td>
2625 <td>--subrepos</td>
2627 <td>--subrepos</td>
2626 <td>recurse into subrepositories</td></tr>
2628 <td>recurse into subrepositories</td></tr>
2627 <tr><td>-n</td>
2629 <tr><td>-n</td>
2628 <td>--dry-run</td>
2630 <td>--dry-run</td>
2629 <td>do not perform actions, just print output</td></tr>
2631 <td>do not perform actions, just print output</td></tr>
2630 </table>
2632 </table>
2631 <p>
2633 <p>
2632 global options ([+] can be repeated):
2634 global options ([+] can be repeated):
2633 </p>
2635 </p>
2634 <table>
2636 <table>
2635 <tr><td>-R</td>
2637 <tr><td>-R</td>
2636 <td>--repository REPO</td>
2638 <td>--repository REPO</td>
2637 <td>repository root directory or name of overlay bundle file</td></tr>
2639 <td>repository root directory or name of overlay bundle file</td></tr>
2638 <tr><td></td>
2640 <tr><td></td>
2639 <td>--cwd DIR</td>
2641 <td>--cwd DIR</td>
2640 <td>change working directory</td></tr>
2642 <td>change working directory</td></tr>
2641 <tr><td>-y</td>
2643 <tr><td>-y</td>
2642 <td>--noninteractive</td>
2644 <td>--noninteractive</td>
2643 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
2645 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
2644 <tr><td>-q</td>
2646 <tr><td>-q</td>
2645 <td>--quiet</td>
2647 <td>--quiet</td>
2646 <td>suppress output</td></tr>
2648 <td>suppress output</td></tr>
2647 <tr><td>-v</td>
2649 <tr><td>-v</td>
2648 <td>--verbose</td>
2650 <td>--verbose</td>
2649 <td>enable additional output</td></tr>
2651 <td>enable additional output</td></tr>
2650 <tr><td></td>
2652 <tr><td></td>
2651 <td>--color TYPE</td>
2653 <td>--color TYPE</td>
2652 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
2654 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
2653 <tr><td></td>
2655 <tr><td></td>
2654 <td>--config CONFIG [+]</td>
2656 <td>--config CONFIG [+]</td>
2655 <td>set/override config option (use 'section.name=value')</td></tr>
2657 <td>set/override config option (use 'section.name=value')</td></tr>
2656 <tr><td></td>
2658 <tr><td></td>
2657 <td>--debug</td>
2659 <td>--debug</td>
2658 <td>enable debugging output</td></tr>
2660 <td>enable debugging output</td></tr>
2659 <tr><td></td>
2661 <tr><td></td>
2660 <td>--debugger</td>
2662 <td>--debugger</td>
2661 <td>start debugger</td></tr>
2663 <td>start debugger</td></tr>
2662 <tr><td></td>
2664 <tr><td></td>
2663 <td>--encoding ENCODE</td>
2665 <td>--encoding ENCODE</td>
2664 <td>set the charset encoding (default: ascii)</td></tr>
2666 <td>set the charset encoding (default: ascii)</td></tr>
2665 <tr><td></td>
2667 <tr><td></td>
2666 <td>--encodingmode MODE</td>
2668 <td>--encodingmode MODE</td>
2667 <td>set the charset encoding mode (default: strict)</td></tr>
2669 <td>set the charset encoding mode (default: strict)</td></tr>
2668 <tr><td></td>
2670 <tr><td></td>
2669 <td>--traceback</td>
2671 <td>--traceback</td>
2670 <td>always print a traceback on exception</td></tr>
2672 <td>always print a traceback on exception</td></tr>
2671 <tr><td></td>
2673 <tr><td></td>
2672 <td>--time</td>
2674 <td>--time</td>
2673 <td>time how long the command takes</td></tr>
2675 <td>time how long the command takes</td></tr>
2674 <tr><td></td>
2676 <tr><td></td>
2675 <td>--profile</td>
2677 <td>--profile</td>
2676 <td>print command execution profile</td></tr>
2678 <td>print command execution profile</td></tr>
2677 <tr><td></td>
2679 <tr><td></td>
2678 <td>--version</td>
2680 <td>--version</td>
2679 <td>output version information and exit</td></tr>
2681 <td>output version information and exit</td></tr>
2680 <tr><td>-h</td>
2682 <tr><td>-h</td>
2681 <td>--help</td>
2683 <td>--help</td>
2682 <td>display help and exit</td></tr>
2684 <td>display help and exit</td></tr>
2683 <tr><td></td>
2685 <tr><td></td>
2684 <td>--hidden</td>
2686 <td>--hidden</td>
2685 <td>consider hidden changesets</td></tr>
2687 <td>consider hidden changesets</td></tr>
2686 <tr><td></td>
2688 <tr><td></td>
2687 <td>--pager TYPE</td>
2689 <td>--pager TYPE</td>
2688 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
2690 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
2689 </table>
2691 </table>
2690
2692
2691 </div>
2693 </div>
2692 </div>
2694 </div>
2693 </div>
2695 </div>
2694
2696
2695
2697
2696
2698
2697 </body>
2699 </body>
2698 </html>
2700 </html>
2699
2701
2700
2702
2701 $ get-with-headers.py $LOCALIP:$HGPORT "help/remove"
2703 $ get-with-headers.py $LOCALIP:$HGPORT "help/remove"
2702 200 Script output follows
2704 200 Script output follows
2703
2705
2704 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2706 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2705 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2707 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2706 <head>
2708 <head>
2707 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2709 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2708 <meta name="robots" content="index, nofollow" />
2710 <meta name="robots" content="index, nofollow" />
2709 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2711 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2710 <script type="text/javascript" src="/static/mercurial.js"></script>
2712 <script type="text/javascript" src="/static/mercurial.js"></script>
2711
2713
2712 <title>Help: remove</title>
2714 <title>Help: remove</title>
2713 </head>
2715 </head>
2714 <body>
2716 <body>
2715
2717
2716 <div class="container">
2718 <div class="container">
2717 <div class="menu">
2719 <div class="menu">
2718 <div class="logo">
2720 <div class="logo">
2719 <a href="https://mercurial-scm.org/">
2721 <a href="https://mercurial-scm.org/">
2720 <img src="/static/hglogo.png" alt="mercurial" /></a>
2722 <img src="/static/hglogo.png" alt="mercurial" /></a>
2721 </div>
2723 </div>
2722 <ul>
2724 <ul>
2723 <li><a href="/shortlog">log</a></li>
2725 <li><a href="/shortlog">log</a></li>
2724 <li><a href="/graph">graph</a></li>
2726 <li><a href="/graph">graph</a></li>
2725 <li><a href="/tags">tags</a></li>
2727 <li><a href="/tags">tags</a></li>
2726 <li><a href="/bookmarks">bookmarks</a></li>
2728 <li><a href="/bookmarks">bookmarks</a></li>
2727 <li><a href="/branches">branches</a></li>
2729 <li><a href="/branches">branches</a></li>
2728 </ul>
2730 </ul>
2729 <ul>
2731 <ul>
2730 <li class="active"><a href="/help">help</a></li>
2732 <li class="active"><a href="/help">help</a></li>
2731 </ul>
2733 </ul>
2732 </div>
2734 </div>
2733
2735
2734 <div class="main">
2736 <div class="main">
2735 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2737 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2736 <h3>Help: remove</h3>
2738 <h3>Help: remove</h3>
2737
2739
2738 <form class="search" action="/log">
2740 <form class="search" action="/log">
2739
2741
2740 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2742 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2741 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2743 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2742 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2744 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2743 </form>
2745 </form>
2744 <div id="doc">
2746 <div id="doc">
2745 <p>
2747 <p>
2746 hg remove [OPTION]... FILE...
2748 hg remove [OPTION]... FILE...
2747 </p>
2749 </p>
2748 <p>
2750 <p>
2749 aliases: rm
2751 aliases: rm
2750 </p>
2752 </p>
2751 <p>
2753 <p>
2752 remove the specified files on the next commit
2754 remove the specified files on the next commit
2753 </p>
2755 </p>
2754 <p>
2756 <p>
2755 Schedule the indicated files for removal from the current branch.
2757 Schedule the indicated files for removal from the current branch.
2756 </p>
2758 </p>
2757 <p>
2759 <p>
2758 This command schedules the files to be removed at the next commit.
2760 This command schedules the files to be removed at the next commit.
2759 To undo a remove before that, see 'hg revert'. To undo added
2761 To undo a remove before that, see 'hg revert'. To undo added
2760 files, see 'hg forget'.
2762 files, see 'hg forget'.
2761 </p>
2763 </p>
2762 <p>
2764 <p>
2763 -A/--after can be used to remove only files that have already
2765 -A/--after can be used to remove only files that have already
2764 been deleted, -f/--force can be used to force deletion, and -Af
2766 been deleted, -f/--force can be used to force deletion, and -Af
2765 can be used to remove files from the next revision without
2767 can be used to remove files from the next revision without
2766 deleting them from the working directory.
2768 deleting them from the working directory.
2767 </p>
2769 </p>
2768 <p>
2770 <p>
2769 The following table details the behavior of remove for different
2771 The following table details the behavior of remove for different
2770 file states (columns) and option combinations (rows). The file
2772 file states (columns) and option combinations (rows). The file
2771 states are Added [A], Clean [C], Modified [M] and Missing [!]
2773 states are Added [A], Clean [C], Modified [M] and Missing [!]
2772 (as reported by 'hg status'). The actions are Warn, Remove
2774 (as reported by 'hg status'). The actions are Warn, Remove
2773 (from branch) and Delete (from disk):
2775 (from branch) and Delete (from disk):
2774 </p>
2776 </p>
2775 <table>
2777 <table>
2776 <tr><td>opt/state</td>
2778 <tr><td>opt/state</td>
2777 <td>A</td>
2779 <td>A</td>
2778 <td>C</td>
2780 <td>C</td>
2779 <td>M</td>
2781 <td>M</td>
2780 <td>!</td></tr>
2782 <td>!</td></tr>
2781 <tr><td>none</td>
2783 <tr><td>none</td>
2782 <td>W</td>
2784 <td>W</td>
2783 <td>RD</td>
2785 <td>RD</td>
2784 <td>W</td>
2786 <td>W</td>
2785 <td>R</td></tr>
2787 <td>R</td></tr>
2786 <tr><td>-f</td>
2788 <tr><td>-f</td>
2787 <td>R</td>
2789 <td>R</td>
2788 <td>RD</td>
2790 <td>RD</td>
2789 <td>RD</td>
2791 <td>RD</td>
2790 <td>R</td></tr>
2792 <td>R</td></tr>
2791 <tr><td>-A</td>
2793 <tr><td>-A</td>
2792 <td>W</td>
2794 <td>W</td>
2793 <td>W</td>
2795 <td>W</td>
2794 <td>W</td>
2796 <td>W</td>
2795 <td>R</td></tr>
2797 <td>R</td></tr>
2796 <tr><td>-Af</td>
2798 <tr><td>-Af</td>
2797 <td>R</td>
2799 <td>R</td>
2798 <td>R</td>
2800 <td>R</td>
2799 <td>R</td>
2801 <td>R</td>
2800 <td>R</td></tr>
2802 <td>R</td></tr>
2801 </table>
2803 </table>
2802 <p>
2804 <p>
2803 <b>Note:</b>
2805 <b>Note:</b>
2804 </p>
2806 </p>
2805 <p>
2807 <p>
2806 'hg remove' never deletes files in Added [A] state from the
2808 'hg remove' never deletes files in Added [A] state from the
2807 working directory, not even if &quot;--force&quot; is specified.
2809 working directory, not even if &quot;--force&quot; is specified.
2808 </p>
2810 </p>
2809 <p>
2811 <p>
2810 Returns 0 on success, 1 if any warnings encountered.
2812 Returns 0 on success, 1 if any warnings encountered.
2811 </p>
2813 </p>
2812 <p>
2814 <p>
2813 options ([+] can be repeated):
2815 options ([+] can be repeated):
2814 </p>
2816 </p>
2815 <table>
2817 <table>
2816 <tr><td>-A</td>
2818 <tr><td>-A</td>
2817 <td>--after</td>
2819 <td>--after</td>
2818 <td>record delete for missing files</td></tr>
2820 <td>record delete for missing files</td></tr>
2819 <tr><td>-f</td>
2821 <tr><td>-f</td>
2820 <td>--force</td>
2822 <td>--force</td>
2821 <td>forget added files, delete modified files</td></tr>
2823 <td>forget added files, delete modified files</td></tr>
2822 <tr><td>-S</td>
2824 <tr><td>-S</td>
2823 <td>--subrepos</td>
2825 <td>--subrepos</td>
2824 <td>recurse into subrepositories</td></tr>
2826 <td>recurse into subrepositories</td></tr>
2825 <tr><td>-I</td>
2827 <tr><td>-I</td>
2826 <td>--include PATTERN [+]</td>
2828 <td>--include PATTERN [+]</td>
2827 <td>include names matching the given patterns</td></tr>
2829 <td>include names matching the given patterns</td></tr>
2828 <tr><td>-X</td>
2830 <tr><td>-X</td>
2829 <td>--exclude PATTERN [+]</td>
2831 <td>--exclude PATTERN [+]</td>
2830 <td>exclude names matching the given patterns</td></tr>
2832 <td>exclude names matching the given patterns</td></tr>
2831 </table>
2833 </table>
2832 <p>
2834 <p>
2833 global options ([+] can be repeated):
2835 global options ([+] can be repeated):
2834 </p>
2836 </p>
2835 <table>
2837 <table>
2836 <tr><td>-R</td>
2838 <tr><td>-R</td>
2837 <td>--repository REPO</td>
2839 <td>--repository REPO</td>
2838 <td>repository root directory or name of overlay bundle file</td></tr>
2840 <td>repository root directory or name of overlay bundle file</td></tr>
2839 <tr><td></td>
2841 <tr><td></td>
2840 <td>--cwd DIR</td>
2842 <td>--cwd DIR</td>
2841 <td>change working directory</td></tr>
2843 <td>change working directory</td></tr>
2842 <tr><td>-y</td>
2844 <tr><td>-y</td>
2843 <td>--noninteractive</td>
2845 <td>--noninteractive</td>
2844 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
2846 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
2845 <tr><td>-q</td>
2847 <tr><td>-q</td>
2846 <td>--quiet</td>
2848 <td>--quiet</td>
2847 <td>suppress output</td></tr>
2849 <td>suppress output</td></tr>
2848 <tr><td>-v</td>
2850 <tr><td>-v</td>
2849 <td>--verbose</td>
2851 <td>--verbose</td>
2850 <td>enable additional output</td></tr>
2852 <td>enable additional output</td></tr>
2851 <tr><td></td>
2853 <tr><td></td>
2852 <td>--color TYPE</td>
2854 <td>--color TYPE</td>
2853 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
2855 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
2854 <tr><td></td>
2856 <tr><td></td>
2855 <td>--config CONFIG [+]</td>
2857 <td>--config CONFIG [+]</td>
2856 <td>set/override config option (use 'section.name=value')</td></tr>
2858 <td>set/override config option (use 'section.name=value')</td></tr>
2857 <tr><td></td>
2859 <tr><td></td>
2858 <td>--debug</td>
2860 <td>--debug</td>
2859 <td>enable debugging output</td></tr>
2861 <td>enable debugging output</td></tr>
2860 <tr><td></td>
2862 <tr><td></td>
2861 <td>--debugger</td>
2863 <td>--debugger</td>
2862 <td>start debugger</td></tr>
2864 <td>start debugger</td></tr>
2863 <tr><td></td>
2865 <tr><td></td>
2864 <td>--encoding ENCODE</td>
2866 <td>--encoding ENCODE</td>
2865 <td>set the charset encoding (default: ascii)</td></tr>
2867 <td>set the charset encoding (default: ascii)</td></tr>
2866 <tr><td></td>
2868 <tr><td></td>
2867 <td>--encodingmode MODE</td>
2869 <td>--encodingmode MODE</td>
2868 <td>set the charset encoding mode (default: strict)</td></tr>
2870 <td>set the charset encoding mode (default: strict)</td></tr>
2869 <tr><td></td>
2871 <tr><td></td>
2870 <td>--traceback</td>
2872 <td>--traceback</td>
2871 <td>always print a traceback on exception</td></tr>
2873 <td>always print a traceback on exception</td></tr>
2872 <tr><td></td>
2874 <tr><td></td>
2873 <td>--time</td>
2875 <td>--time</td>
2874 <td>time how long the command takes</td></tr>
2876 <td>time how long the command takes</td></tr>
2875 <tr><td></td>
2877 <tr><td></td>
2876 <td>--profile</td>
2878 <td>--profile</td>
2877 <td>print command execution profile</td></tr>
2879 <td>print command execution profile</td></tr>
2878 <tr><td></td>
2880 <tr><td></td>
2879 <td>--version</td>
2881 <td>--version</td>
2880 <td>output version information and exit</td></tr>
2882 <td>output version information and exit</td></tr>
2881 <tr><td>-h</td>
2883 <tr><td>-h</td>
2882 <td>--help</td>
2884 <td>--help</td>
2883 <td>display help and exit</td></tr>
2885 <td>display help and exit</td></tr>
2884 <tr><td></td>
2886 <tr><td></td>
2885 <td>--hidden</td>
2887 <td>--hidden</td>
2886 <td>consider hidden changesets</td></tr>
2888 <td>consider hidden changesets</td></tr>
2887 <tr><td></td>
2889 <tr><td></td>
2888 <td>--pager TYPE</td>
2890 <td>--pager TYPE</td>
2889 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
2891 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
2890 </table>
2892 </table>
2891
2893
2892 </div>
2894 </div>
2893 </div>
2895 </div>
2894 </div>
2896 </div>
2895
2897
2896
2898
2897
2899
2898 </body>
2900 </body>
2899 </html>
2901 </html>
2900
2902
2901
2903
2902 $ get-with-headers.py $LOCALIP:$HGPORT "help/dates"
2904 $ get-with-headers.py $LOCALIP:$HGPORT "help/dates"
2903 200 Script output follows
2905 200 Script output follows
2904
2906
2905 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2907 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2906 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2908 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2907 <head>
2909 <head>
2908 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2910 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2909 <meta name="robots" content="index, nofollow" />
2911 <meta name="robots" content="index, nofollow" />
2910 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2912 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2911 <script type="text/javascript" src="/static/mercurial.js"></script>
2913 <script type="text/javascript" src="/static/mercurial.js"></script>
2912
2914
2913 <title>Help: dates</title>
2915 <title>Help: dates</title>
2914 </head>
2916 </head>
2915 <body>
2917 <body>
2916
2918
2917 <div class="container">
2919 <div class="container">
2918 <div class="menu">
2920 <div class="menu">
2919 <div class="logo">
2921 <div class="logo">
2920 <a href="https://mercurial-scm.org/">
2922 <a href="https://mercurial-scm.org/">
2921 <img src="/static/hglogo.png" alt="mercurial" /></a>
2923 <img src="/static/hglogo.png" alt="mercurial" /></a>
2922 </div>
2924 </div>
2923 <ul>
2925 <ul>
2924 <li><a href="/shortlog">log</a></li>
2926 <li><a href="/shortlog">log</a></li>
2925 <li><a href="/graph">graph</a></li>
2927 <li><a href="/graph">graph</a></li>
2926 <li><a href="/tags">tags</a></li>
2928 <li><a href="/tags">tags</a></li>
2927 <li><a href="/bookmarks">bookmarks</a></li>
2929 <li><a href="/bookmarks">bookmarks</a></li>
2928 <li><a href="/branches">branches</a></li>
2930 <li><a href="/branches">branches</a></li>
2929 </ul>
2931 </ul>
2930 <ul>
2932 <ul>
2931 <li class="active"><a href="/help">help</a></li>
2933 <li class="active"><a href="/help">help</a></li>
2932 </ul>
2934 </ul>
2933 </div>
2935 </div>
2934
2936
2935 <div class="main">
2937 <div class="main">
2936 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2938 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2937 <h3>Help: dates</h3>
2939 <h3>Help: dates</h3>
2938
2940
2939 <form class="search" action="/log">
2941 <form class="search" action="/log">
2940
2942
2941 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2943 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2942 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2944 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2943 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2945 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2944 </form>
2946 </form>
2945 <div id="doc">
2947 <div id="doc">
2946 <h1>Date Formats</h1>
2948 <h1>Date Formats</h1>
2947 <p>
2949 <p>
2948 Some commands allow the user to specify a date, e.g.:
2950 Some commands allow the user to specify a date, e.g.:
2949 </p>
2951 </p>
2950 <ul>
2952 <ul>
2951 <li> backout, commit, import, tag: Specify the commit date.
2953 <li> backout, commit, import, tag: Specify the commit date.
2952 <li> log, revert, update: Select revision(s) by date.
2954 <li> log, revert, update: Select revision(s) by date.
2953 </ul>
2955 </ul>
2954 <p>
2956 <p>
2955 Many date formats are valid. Here are some examples:
2957 Many date formats are valid. Here are some examples:
2956 </p>
2958 </p>
2957 <ul>
2959 <ul>
2958 <li> &quot;Wed Dec 6 13:18:29 2006&quot; (local timezone assumed)
2960 <li> &quot;Wed Dec 6 13:18:29 2006&quot; (local timezone assumed)
2959 <li> &quot;Dec 6 13:18 -0600&quot; (year assumed, time offset provided)
2961 <li> &quot;Dec 6 13:18 -0600&quot; (year assumed, time offset provided)
2960 <li> &quot;Dec 6 13:18 UTC&quot; (UTC and GMT are aliases for +0000)
2962 <li> &quot;Dec 6 13:18 UTC&quot; (UTC and GMT are aliases for +0000)
2961 <li> &quot;Dec 6&quot; (midnight)
2963 <li> &quot;Dec 6&quot; (midnight)
2962 <li> &quot;13:18&quot; (today assumed)
2964 <li> &quot;13:18&quot; (today assumed)
2963 <li> &quot;3:39&quot; (3:39AM assumed)
2965 <li> &quot;3:39&quot; (3:39AM assumed)
2964 <li> &quot;3:39pm&quot; (15:39)
2966 <li> &quot;3:39pm&quot; (15:39)
2965 <li> &quot;2006-12-06 13:18:29&quot; (ISO 8601 format)
2967 <li> &quot;2006-12-06 13:18:29&quot; (ISO 8601 format)
2966 <li> &quot;2006-12-6 13:18&quot;
2968 <li> &quot;2006-12-6 13:18&quot;
2967 <li> &quot;2006-12-6&quot;
2969 <li> &quot;2006-12-6&quot;
2968 <li> &quot;12-6&quot;
2970 <li> &quot;12-6&quot;
2969 <li> &quot;12/6&quot;
2971 <li> &quot;12/6&quot;
2970 <li> &quot;12/6/6&quot; (Dec 6 2006)
2972 <li> &quot;12/6/6&quot; (Dec 6 2006)
2971 <li> &quot;today&quot; (midnight)
2973 <li> &quot;today&quot; (midnight)
2972 <li> &quot;yesterday&quot; (midnight)
2974 <li> &quot;yesterday&quot; (midnight)
2973 <li> &quot;now&quot; - right now
2975 <li> &quot;now&quot; - right now
2974 </ul>
2976 </ul>
2975 <p>
2977 <p>
2976 Lastly, there is Mercurial's internal format:
2978 Lastly, there is Mercurial's internal format:
2977 </p>
2979 </p>
2978 <ul>
2980 <ul>
2979 <li> &quot;1165411109 0&quot; (Wed Dec 6 13:18:29 2006 UTC)
2981 <li> &quot;1165411109 0&quot; (Wed Dec 6 13:18:29 2006 UTC)
2980 </ul>
2982 </ul>
2981 <p>
2983 <p>
2982 This is the internal representation format for dates. The first number
2984 This is the internal representation format for dates. The first number
2983 is the number of seconds since the epoch (1970-01-01 00:00 UTC). The
2985 is the number of seconds since the epoch (1970-01-01 00:00 UTC). The
2984 second is the offset of the local timezone, in seconds west of UTC
2986 second is the offset of the local timezone, in seconds west of UTC
2985 (negative if the timezone is east of UTC).
2987 (negative if the timezone is east of UTC).
2986 </p>
2988 </p>
2987 <p>
2989 <p>
2988 The log command also accepts date ranges:
2990 The log command also accepts date ranges:
2989 </p>
2991 </p>
2990 <ul>
2992 <ul>
2991 <li> &quot;&lt;DATE&quot; - at or before a given date/time
2993 <li> &quot;&lt;DATE&quot; - at or before a given date/time
2992 <li> &quot;&gt;DATE&quot; - on or after a given date/time
2994 <li> &quot;&gt;DATE&quot; - on or after a given date/time
2993 <li> &quot;DATE to DATE&quot; - a date range, inclusive
2995 <li> &quot;DATE to DATE&quot; - a date range, inclusive
2994 <li> &quot;-DAYS&quot; - within a given number of days of today
2996 <li> &quot;-DAYS&quot; - within a given number of days of today
2995 </ul>
2997 </ul>
2996
2998
2997 </div>
2999 </div>
2998 </div>
3000 </div>
2999 </div>
3001 </div>
3000
3002
3001
3003
3002
3004
3003 </body>
3005 </body>
3004 </html>
3006 </html>
3005
3007
3006
3008
3007 Sub-topic indexes rendered properly
3009 Sub-topic indexes rendered properly
3008
3010
3009 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals"
3011 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals"
3010 200 Script output follows
3012 200 Script output follows
3011
3013
3012 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3014 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3013 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3015 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3014 <head>
3016 <head>
3015 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3017 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3016 <meta name="robots" content="index, nofollow" />
3018 <meta name="robots" content="index, nofollow" />
3017 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3019 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3018 <script type="text/javascript" src="/static/mercurial.js"></script>
3020 <script type="text/javascript" src="/static/mercurial.js"></script>
3019
3021
3020 <title>Help: internals</title>
3022 <title>Help: internals</title>
3021 </head>
3023 </head>
3022 <body>
3024 <body>
3023
3025
3024 <div class="container">
3026 <div class="container">
3025 <div class="menu">
3027 <div class="menu">
3026 <div class="logo">
3028 <div class="logo">
3027 <a href="https://mercurial-scm.org/">
3029 <a href="https://mercurial-scm.org/">
3028 <img src="/static/hglogo.png" alt="mercurial" /></a>
3030 <img src="/static/hglogo.png" alt="mercurial" /></a>
3029 </div>
3031 </div>
3030 <ul>
3032 <ul>
3031 <li><a href="/shortlog">log</a></li>
3033 <li><a href="/shortlog">log</a></li>
3032 <li><a href="/graph">graph</a></li>
3034 <li><a href="/graph">graph</a></li>
3033 <li><a href="/tags">tags</a></li>
3035 <li><a href="/tags">tags</a></li>
3034 <li><a href="/bookmarks">bookmarks</a></li>
3036 <li><a href="/bookmarks">bookmarks</a></li>
3035 <li><a href="/branches">branches</a></li>
3037 <li><a href="/branches">branches</a></li>
3036 </ul>
3038 </ul>
3037 <ul>
3039 <ul>
3038 <li><a href="/help">help</a></li>
3040 <li><a href="/help">help</a></li>
3039 </ul>
3041 </ul>
3040 </div>
3042 </div>
3041
3043
3042 <div class="main">
3044 <div class="main">
3043 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3045 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3044
3046
3045 <form class="search" action="/log">
3047 <form class="search" action="/log">
3046
3048
3047 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3049 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3048 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3050 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3049 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3051 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3050 </form>
3052 </form>
3051 <table class="bigtable">
3053 <table class="bigtable">
3052 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
3054 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
3053
3055
3054 <tr><td>
3056 <tr><td>
3055 <a href="/help/internals.bundles">
3057 <a href="/help/internals.bundles">
3056 bundles
3058 bundles
3057 </a>
3059 </a>
3058 </td><td>
3060 </td><td>
3059 Bundles
3061 Bundles
3060 </td></tr>
3062 </td></tr>
3061 <tr><td>
3063 <tr><td>
3062 <a href="/help/internals.censor">
3064 <a href="/help/internals.censor">
3063 censor
3065 censor
3064 </a>
3066 </a>
3065 </td><td>
3067 </td><td>
3066 Censor
3068 Censor
3067 </td></tr>
3069 </td></tr>
3068 <tr><td>
3070 <tr><td>
3069 <a href="/help/internals.changegroups">
3071 <a href="/help/internals.changegroups">
3070 changegroups
3072 changegroups
3071 </a>
3073 </a>
3072 </td><td>
3074 </td><td>
3073 Changegroups
3075 Changegroups
3074 </td></tr>
3076 </td></tr>
3075 <tr><td>
3077 <tr><td>
3076 <a href="/help/internals.config">
3078 <a href="/help/internals.config">
3077 config
3079 config
3078 </a>
3080 </a>
3079 </td><td>
3081 </td><td>
3080 Config Registrar
3082 Config Registrar
3081 </td></tr>
3083 </td></tr>
3082 <tr><td>
3084 <tr><td>
3083 <a href="/help/internals.requirements">
3085 <a href="/help/internals.requirements">
3084 requirements
3086 requirements
3085 </a>
3087 </a>
3086 </td><td>
3088 </td><td>
3087 Repository Requirements
3089 Repository Requirements
3088 </td></tr>
3090 </td></tr>
3089 <tr><td>
3091 <tr><td>
3090 <a href="/help/internals.revlogs">
3092 <a href="/help/internals.revlogs">
3091 revlogs
3093 revlogs
3092 </a>
3094 </a>
3093 </td><td>
3095 </td><td>
3094 Revision Logs
3096 Revision Logs
3095 </td></tr>
3097 </td></tr>
3096 <tr><td>
3098 <tr><td>
3097 <a href="/help/internals.wireprotocol">
3099 <a href="/help/internals.wireprotocol">
3098 wireprotocol
3100 wireprotocol
3099 </a>
3101 </a>
3100 </td><td>
3102 </td><td>
3101 Wire Protocol
3103 Wire Protocol
3102 </td></tr>
3104 </td></tr>
3103
3105
3104
3106
3105
3107
3106
3108
3107
3109
3108 </table>
3110 </table>
3109 </div>
3111 </div>
3110 </div>
3112 </div>
3111
3113
3112
3114
3113
3115
3114 </body>
3116 </body>
3115 </html>
3117 </html>
3116
3118
3117
3119
3118 Sub-topic topics rendered properly
3120 Sub-topic topics rendered properly
3119
3121
3120 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals.changegroups"
3122 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals.changegroups"
3121 200 Script output follows
3123 200 Script output follows
3122
3124
3123 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3125 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3124 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3126 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3125 <head>
3127 <head>
3126 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3128 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3127 <meta name="robots" content="index, nofollow" />
3129 <meta name="robots" content="index, nofollow" />
3128 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3130 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3129 <script type="text/javascript" src="/static/mercurial.js"></script>
3131 <script type="text/javascript" src="/static/mercurial.js"></script>
3130
3132
3131 <title>Help: internals.changegroups</title>
3133 <title>Help: internals.changegroups</title>
3132 </head>
3134 </head>
3133 <body>
3135 <body>
3134
3136
3135 <div class="container">
3137 <div class="container">
3136 <div class="menu">
3138 <div class="menu">
3137 <div class="logo">
3139 <div class="logo">
3138 <a href="https://mercurial-scm.org/">
3140 <a href="https://mercurial-scm.org/">
3139 <img src="/static/hglogo.png" alt="mercurial" /></a>
3141 <img src="/static/hglogo.png" alt="mercurial" /></a>
3140 </div>
3142 </div>
3141 <ul>
3143 <ul>
3142 <li><a href="/shortlog">log</a></li>
3144 <li><a href="/shortlog">log</a></li>
3143 <li><a href="/graph">graph</a></li>
3145 <li><a href="/graph">graph</a></li>
3144 <li><a href="/tags">tags</a></li>
3146 <li><a href="/tags">tags</a></li>
3145 <li><a href="/bookmarks">bookmarks</a></li>
3147 <li><a href="/bookmarks">bookmarks</a></li>
3146 <li><a href="/branches">branches</a></li>
3148 <li><a href="/branches">branches</a></li>
3147 </ul>
3149 </ul>
3148 <ul>
3150 <ul>
3149 <li class="active"><a href="/help">help</a></li>
3151 <li class="active"><a href="/help">help</a></li>
3150 </ul>
3152 </ul>
3151 </div>
3153 </div>
3152
3154
3153 <div class="main">
3155 <div class="main">
3154 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3156 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3155 <h3>Help: internals.changegroups</h3>
3157 <h3>Help: internals.changegroups</h3>
3156
3158
3157 <form class="search" action="/log">
3159 <form class="search" action="/log">
3158
3160
3159 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3161 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3160 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3162 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3161 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3163 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3162 </form>
3164 </form>
3163 <div id="doc">
3165 <div id="doc">
3164 <h1>Changegroups</h1>
3166 <h1>Changegroups</h1>
3165 <p>
3167 <p>
3166 Changegroups are representations of repository revlog data, specifically
3168 Changegroups are representations of repository revlog data, specifically
3167 the changelog data, root/flat manifest data, treemanifest data, and
3169 the changelog data, root/flat manifest data, treemanifest data, and
3168 filelogs.
3170 filelogs.
3169 </p>
3171 </p>
3170 <p>
3172 <p>
3171 There are 3 versions of changegroups: &quot;1&quot;, &quot;2&quot;, and &quot;3&quot;. From a
3173 There are 3 versions of changegroups: &quot;1&quot;, &quot;2&quot;, and &quot;3&quot;. From a
3172 high-level, versions &quot;1&quot; and &quot;2&quot; are almost exactly the same, with the
3174 high-level, versions &quot;1&quot; and &quot;2&quot; are almost exactly the same, with the
3173 only difference being an additional item in the *delta header*. Version
3175 only difference being an additional item in the *delta header*. Version
3174 &quot;3&quot; adds support for revlog flags in the *delta header* and optionally
3176 &quot;3&quot; adds support for revlog flags in the *delta header* and optionally
3175 exchanging treemanifests (enabled by setting an option on the
3177 exchanging treemanifests (enabled by setting an option on the
3176 &quot;changegroup&quot; part in the bundle2).
3178 &quot;changegroup&quot; part in the bundle2).
3177 </p>
3179 </p>
3178 <p>
3180 <p>
3179 Changegroups when not exchanging treemanifests consist of 3 logical
3181 Changegroups when not exchanging treemanifests consist of 3 logical
3180 segments:
3182 segments:
3181 </p>
3183 </p>
3182 <pre>
3184 <pre>
3183 +---------------------------------+
3185 +---------------------------------+
3184 | | | |
3186 | | | |
3185 | changeset | manifest | filelogs |
3187 | changeset | manifest | filelogs |
3186 | | | |
3188 | | | |
3187 | | | |
3189 | | | |
3188 +---------------------------------+
3190 +---------------------------------+
3189 </pre>
3191 </pre>
3190 <p>
3192 <p>
3191 When exchanging treemanifests, there are 4 logical segments:
3193 When exchanging treemanifests, there are 4 logical segments:
3192 </p>
3194 </p>
3193 <pre>
3195 <pre>
3194 +-------------------------------------------------+
3196 +-------------------------------------------------+
3195 | | | | |
3197 | | | | |
3196 | changeset | root | treemanifests | filelogs |
3198 | changeset | root | treemanifests | filelogs |
3197 | | manifest | | |
3199 | | manifest | | |
3198 | | | | |
3200 | | | | |
3199 +-------------------------------------------------+
3201 +-------------------------------------------------+
3200 </pre>
3202 </pre>
3201 <p>
3203 <p>
3202 The principle building block of each segment is a *chunk*. A *chunk*
3204 The principle building block of each segment is a *chunk*. A *chunk*
3203 is a framed piece of data:
3205 is a framed piece of data:
3204 </p>
3206 </p>
3205 <pre>
3207 <pre>
3206 +---------------------------------------+
3208 +---------------------------------------+
3207 | | |
3209 | | |
3208 | length | data |
3210 | length | data |
3209 | (4 bytes) | (&lt;length - 4&gt; bytes) |
3211 | (4 bytes) | (&lt;length - 4&gt; bytes) |
3210 | | |
3212 | | |
3211 +---------------------------------------+
3213 +---------------------------------------+
3212 </pre>
3214 </pre>
3213 <p>
3215 <p>
3214 All integers are big-endian signed integers. Each chunk starts with a 32-bit
3216 All integers are big-endian signed integers. Each chunk starts with a 32-bit
3215 integer indicating the length of the entire chunk (including the length field
3217 integer indicating the length of the entire chunk (including the length field
3216 itself).
3218 itself).
3217 </p>
3219 </p>
3218 <p>
3220 <p>
3219 There is a special case chunk that has a value of 0 for the length
3221 There is a special case chunk that has a value of 0 for the length
3220 (&quot;0x00000000&quot;). We call this an *empty chunk*.
3222 (&quot;0x00000000&quot;). We call this an *empty chunk*.
3221 </p>
3223 </p>
3222 <h2>Delta Groups</h2>
3224 <h2>Delta Groups</h2>
3223 <p>
3225 <p>
3224 A *delta group* expresses the content of a revlog as a series of deltas,
3226 A *delta group* expresses the content of a revlog as a series of deltas,
3225 or patches against previous revisions.
3227 or patches against previous revisions.
3226 </p>
3228 </p>
3227 <p>
3229 <p>
3228 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
3230 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
3229 to signal the end of the delta group:
3231 to signal the end of the delta group:
3230 </p>
3232 </p>
3231 <pre>
3233 <pre>
3232 +------------------------------------------------------------------------+
3234 +------------------------------------------------------------------------+
3233 | | | | | |
3235 | | | | | |
3234 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
3236 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
3235 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
3237 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
3236 | | | | | |
3238 | | | | | |
3237 +------------------------------------------------------------------------+
3239 +------------------------------------------------------------------------+
3238 </pre>
3240 </pre>
3239 <p>
3241 <p>
3240 Each *chunk*'s data consists of the following:
3242 Each *chunk*'s data consists of the following:
3241 </p>
3243 </p>
3242 <pre>
3244 <pre>
3243 +---------------------------------------+
3245 +---------------------------------------+
3244 | | |
3246 | | |
3245 | delta header | delta data |
3247 | delta header | delta data |
3246 | (various by version) | (various) |
3248 | (various by version) | (various) |
3247 | | |
3249 | | |
3248 +---------------------------------------+
3250 +---------------------------------------+
3249 </pre>
3251 </pre>
3250 <p>
3252 <p>
3251 The *delta data* is a series of *delta*s that describe a diff from an existing
3253 The *delta data* is a series of *delta*s that describe a diff from an existing
3252 entry (either that the recipient already has, or previously specified in the
3254 entry (either that the recipient already has, or previously specified in the
3253 bundle/changegroup).
3255 bundle/changegroup).
3254 </p>
3256 </p>
3255 <p>
3257 <p>
3256 The *delta header* is different between versions &quot;1&quot;, &quot;2&quot;, and
3258 The *delta header* is different between versions &quot;1&quot;, &quot;2&quot;, and
3257 &quot;3&quot; of the changegroup format.
3259 &quot;3&quot; of the changegroup format.
3258 </p>
3260 </p>
3259 <p>
3261 <p>
3260 Version 1 (headerlen=80):
3262 Version 1 (headerlen=80):
3261 </p>
3263 </p>
3262 <pre>
3264 <pre>
3263 +------------------------------------------------------+
3265 +------------------------------------------------------+
3264 | | | | |
3266 | | | | |
3265 | node | p1 node | p2 node | link node |
3267 | node | p1 node | p2 node | link node |
3266 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3268 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3267 | | | | |
3269 | | | | |
3268 +------------------------------------------------------+
3270 +------------------------------------------------------+
3269 </pre>
3271 </pre>
3270 <p>
3272 <p>
3271 Version 2 (headerlen=100):
3273 Version 2 (headerlen=100):
3272 </p>
3274 </p>
3273 <pre>
3275 <pre>
3274 +------------------------------------------------------------------+
3276 +------------------------------------------------------------------+
3275 | | | | | |
3277 | | | | | |
3276 | node | p1 node | p2 node | base node | link node |
3278 | node | p1 node | p2 node | base node | link node |
3277 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3279 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3278 | | | | | |
3280 | | | | | |
3279 +------------------------------------------------------------------+
3281 +------------------------------------------------------------------+
3280 </pre>
3282 </pre>
3281 <p>
3283 <p>
3282 Version 3 (headerlen=102):
3284 Version 3 (headerlen=102):
3283 </p>
3285 </p>
3284 <pre>
3286 <pre>
3285 +------------------------------------------------------------------------------+
3287 +------------------------------------------------------------------------------+
3286 | | | | | | |
3288 | | | | | | |
3287 | node | p1 node | p2 node | base node | link node | flags |
3289 | node | p1 node | p2 node | base node | link node | flags |
3288 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
3290 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
3289 | | | | | | |
3291 | | | | | | |
3290 +------------------------------------------------------------------------------+
3292 +------------------------------------------------------------------------------+
3291 </pre>
3293 </pre>
3292 <p>
3294 <p>
3293 The *delta data* consists of &quot;chunklen - 4 - headerlen&quot; bytes, which contain a
3295 The *delta data* consists of &quot;chunklen - 4 - headerlen&quot; bytes, which contain a
3294 series of *delta*s, densely packed (no separators). These deltas describe a diff
3296 series of *delta*s, densely packed (no separators). These deltas describe a diff
3295 from an existing entry (either that the recipient already has, or previously
3297 from an existing entry (either that the recipient already has, or previously
3296 specified in the bundle/changegroup). The format is described more fully in
3298 specified in the bundle/changegroup). The format is described more fully in
3297 &quot;hg help internals.bdiff&quot;, but briefly:
3299 &quot;hg help internals.bdiff&quot;, but briefly:
3298 </p>
3300 </p>
3299 <pre>
3301 <pre>
3300 +---------------------------------------------------------------+
3302 +---------------------------------------------------------------+
3301 | | | | |
3303 | | | | |
3302 | start offset | end offset | new length | content |
3304 | start offset | end offset | new length | content |
3303 | (4 bytes) | (4 bytes) | (4 bytes) | (&lt;new length&gt; bytes) |
3305 | (4 bytes) | (4 bytes) | (4 bytes) | (&lt;new length&gt; bytes) |
3304 | | | | |
3306 | | | | |
3305 +---------------------------------------------------------------+
3307 +---------------------------------------------------------------+
3306 </pre>
3308 </pre>
3307 <p>
3309 <p>
3308 Please note that the length field in the delta data does *not* include itself.
3310 Please note that the length field in the delta data does *not* include itself.
3309 </p>
3311 </p>
3310 <p>
3312 <p>
3311 In version 1, the delta is always applied against the previous node from
3313 In version 1, the delta is always applied against the previous node from
3312 the changegroup or the first parent if this is the first entry in the
3314 the changegroup or the first parent if this is the first entry in the
3313 changegroup.
3315 changegroup.
3314 </p>
3316 </p>
3315 <p>
3317 <p>
3316 In version 2 and up, the delta base node is encoded in the entry in the
3318 In version 2 and up, the delta base node is encoded in the entry in the
3317 changegroup. This allows the delta to be expressed against any parent,
3319 changegroup. This allows the delta to be expressed against any parent,
3318 which can result in smaller deltas and more efficient encoding of data.
3320 which can result in smaller deltas and more efficient encoding of data.
3319 </p>
3321 </p>
3320 <h2>Changeset Segment</h2>
3322 <h2>Changeset Segment</h2>
3321 <p>
3323 <p>
3322 The *changeset segment* consists of a single *delta group* holding
3324 The *changeset segment* consists of a single *delta group* holding
3323 changelog data. The *empty chunk* at the end of the *delta group* denotes
3325 changelog data. The *empty chunk* at the end of the *delta group* denotes
3324 the boundary to the *manifest segment*.
3326 the boundary to the *manifest segment*.
3325 </p>
3327 </p>
3326 <h2>Manifest Segment</h2>
3328 <h2>Manifest Segment</h2>
3327 <p>
3329 <p>
3328 The *manifest segment* consists of a single *delta group* holding manifest
3330 The *manifest segment* consists of a single *delta group* holding manifest
3329 data. If treemanifests are in use, it contains only the manifest for the
3331 data. If treemanifests are in use, it contains only the manifest for the
3330 root directory of the repository. Otherwise, it contains the entire
3332 root directory of the repository. Otherwise, it contains the entire
3331 manifest data. The *empty chunk* at the end of the *delta group* denotes
3333 manifest data. The *empty chunk* at the end of the *delta group* denotes
3332 the boundary to the next segment (either the *treemanifests segment* or the
3334 the boundary to the next segment (either the *treemanifests segment* or the
3333 *filelogs segment*, depending on version and the request options).
3335 *filelogs segment*, depending on version and the request options).
3334 </p>
3336 </p>
3335 <h3>Treemanifests Segment</h3>
3337 <h3>Treemanifests Segment</h3>
3336 <p>
3338 <p>
3337 The *treemanifests segment* only exists in changegroup version &quot;3&quot;, and
3339 The *treemanifests segment* only exists in changegroup version &quot;3&quot;, and
3338 only if the 'treemanifest' param is part of the bundle2 changegroup part
3340 only if the 'treemanifest' param is part of the bundle2 changegroup part
3339 (it is not possible to use changegroup version 3 outside of bundle2).
3341 (it is not possible to use changegroup version 3 outside of bundle2).
3340 Aside from the filenames in the *treemanifests segment* containing a
3342 Aside from the filenames in the *treemanifests segment* containing a
3341 trailing &quot;/&quot; character, it behaves identically to the *filelogs segment*
3343 trailing &quot;/&quot; character, it behaves identically to the *filelogs segment*
3342 (see below). The final sub-segment is followed by an *empty chunk* (logically,
3344 (see below). The final sub-segment is followed by an *empty chunk* (logically,
3343 a sub-segment with filename size 0). This denotes the boundary to the
3345 a sub-segment with filename size 0). This denotes the boundary to the
3344 *filelogs segment*.
3346 *filelogs segment*.
3345 </p>
3347 </p>
3346 <h2>Filelogs Segment</h2>
3348 <h2>Filelogs Segment</h2>
3347 <p>
3349 <p>
3348 The *filelogs segment* consists of multiple sub-segments, each
3350 The *filelogs segment* consists of multiple sub-segments, each
3349 corresponding to an individual file whose data is being described:
3351 corresponding to an individual file whose data is being described:
3350 </p>
3352 </p>
3351 <pre>
3353 <pre>
3352 +--------------------------------------------------+
3354 +--------------------------------------------------+
3353 | | | | | |
3355 | | | | | |
3354 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
3356 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
3355 | | | | | (4 bytes) |
3357 | | | | | (4 bytes) |
3356 | | | | | |
3358 | | | | | |
3357 +--------------------------------------------------+
3359 +--------------------------------------------------+
3358 </pre>
3360 </pre>
3359 <p>
3361 <p>
3360 The final filelog sub-segment is followed by an *empty chunk* (logically,
3362 The final filelog sub-segment is followed by an *empty chunk* (logically,
3361 a sub-segment with filename size 0). This denotes the end of the segment
3363 a sub-segment with filename size 0). This denotes the end of the segment
3362 and of the overall changegroup.
3364 and of the overall changegroup.
3363 </p>
3365 </p>
3364 <p>
3366 <p>
3365 Each filelog sub-segment consists of the following:
3367 Each filelog sub-segment consists of the following:
3366 </p>
3368 </p>
3367 <pre>
3369 <pre>
3368 +------------------------------------------------------+
3370 +------------------------------------------------------+
3369 | | | |
3371 | | | |
3370 | filename length | filename | delta group |
3372 | filename length | filename | delta group |
3371 | (4 bytes) | (&lt;length - 4&gt; bytes) | (various) |
3373 | (4 bytes) | (&lt;length - 4&gt; bytes) | (various) |
3372 | | | |
3374 | | | |
3373 +------------------------------------------------------+
3375 +------------------------------------------------------+
3374 </pre>
3376 </pre>
3375 <p>
3377 <p>
3376 That is, a *chunk* consisting of the filename (not terminated or padded)
3378 That is, a *chunk* consisting of the filename (not terminated or padded)
3377 followed by N chunks constituting the *delta group* for this file. The
3379 followed by N chunks constituting the *delta group* for this file. The
3378 *empty chunk* at the end of each *delta group* denotes the boundary to the
3380 *empty chunk* at the end of each *delta group* denotes the boundary to the
3379 next filelog sub-segment.
3381 next filelog sub-segment.
3380 </p>
3382 </p>
3381
3383
3382 </div>
3384 </div>
3383 </div>
3385 </div>
3384 </div>
3386 </div>
3385
3387
3386
3388
3387
3389
3388 </body>
3390 </body>
3389 </html>
3391 </html>
3390
3392
3391
3393
3392 $ killdaemons.py
3394 $ killdaemons.py
3393
3395
3394 #endif
3396 #endif
General Comments 0
You need to be logged in to leave comments. Login now