##// END OF EJS Templates
changegroup.writebundle: HG2Y support...
Eric Sumner -
r23896:becfecaf default
parent child Browse files
Show More
@@ -1,869 +1,884 b''
1 1 # changegroup.py - Mercurial changegroup manipulation functions
2 2 #
3 3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 import weakref
9 9 from i18n import _
10 10 from node import nullrev, nullid, hex, short
11 11 import mdiff, util, dagutil
12 12 import struct, os, bz2, zlib, tempfile
13 13 import discovery, error, phases, branchmap
14 14
15 15 _CHANGEGROUPV1_DELTA_HEADER = "20s20s20s20s"
16 16 _CHANGEGROUPV2_DELTA_HEADER = "20s20s20s20s20s"
17 17
18 18 def readexactly(stream, n):
19 19 '''read n bytes from stream.read and abort if less was available'''
20 20 s = stream.read(n)
21 21 if len(s) < n:
22 22 raise util.Abort(_("stream ended unexpectedly"
23 23 " (got %d bytes, expected %d)")
24 24 % (len(s), n))
25 25 return s
26 26
27 27 def getchunk(stream):
28 28 """return the next chunk from stream as a string"""
29 29 d = readexactly(stream, 4)
30 30 l = struct.unpack(">l", d)[0]
31 31 if l <= 4:
32 32 if l:
33 33 raise util.Abort(_("invalid chunk length %d") % l)
34 34 return ""
35 35 return readexactly(stream, l - 4)
36 36
37 37 def chunkheader(length):
38 38 """return a changegroup chunk header (string)"""
39 39 return struct.pack(">l", length + 4)
40 40
41 41 def closechunk():
42 42 """return a changegroup chunk header (string) for a zero-length chunk"""
43 43 return struct.pack(">l", 0)
44 44
45 45 def combineresults(results):
46 46 """logic to combine 0 or more addchangegroup results into one"""
47 47 changedheads = 0
48 48 result = 1
49 49 for ret in results:
50 50 # If any changegroup result is 0, return 0
51 51 if ret == 0:
52 52 result = 0
53 53 break
54 54 if ret < -1:
55 55 changedheads += ret + 1
56 56 elif ret > 1:
57 57 changedheads += ret - 1
58 58 if changedheads > 0:
59 59 result = 1 + changedheads
60 60 elif changedheads < 0:
61 61 result = -1 + changedheads
62 62 return result
63 63
64 64 class nocompress(object):
65 65 def compress(self, x):
66 66 return x
67 67 def flush(self):
68 68 return ""
69 69
70 70 bundletypes = {
71 71 "": ("", nocompress), # only when using unbundle on ssh and old http servers
72 72 # since the unification ssh accepts a header but there
73 73 # is no capability signaling it.
74 "HG2Y": (), # special-cased below
74 75 "HG10UN": ("HG10UN", nocompress),
75 76 "HG10BZ": ("HG10", lambda: bz2.BZ2Compressor()),
76 77 "HG10GZ": ("HG10GZ", lambda: zlib.compressobj()),
77 78 }
78 79
79 80 # hgweb uses this list to communicate its preferred type
80 81 bundlepriority = ['HG10GZ', 'HG10BZ', 'HG10UN']
81 82
82 83 def writebundle(ui, cg, filename, bundletype, vfs=None):
83 84 """Write a bundle file and return its filename.
84 85
85 86 Existing files will not be overwritten.
86 87 If no filename is specified, a temporary file is created.
87 88 bz2 compression can be turned off.
88 89 The bundle file will be deleted in case of errors.
89 90 """
90 91
91 92 fh = None
92 93 cleanup = None
93 94 try:
94 95 if filename:
95 96 if vfs:
96 97 fh = vfs.open(filename, "wb")
97 98 else:
98 99 fh = open(filename, "wb")
99 100 else:
100 101 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
101 102 fh = os.fdopen(fd, "wb")
102 103 cleanup = filename
103 104
105 if bundletype == "HG2Y":
106 import bundle2
107 bundle = bundle2.bundle20(ui)
108 part = bundle.newpart('b2x:changegroup', data=cg.getchunks())
109 part.addparam('version', cg.version)
110 z = nocompress()
111 chunkiter = bundle.getchunks()
112 else:
113 if cg.version != '01':
114 raise util.Abort(_('Bundle1 only supports v1 changegroups\n'))
104 115 header, compressor = bundletypes[bundletype]
105 116 fh.write(header)
106 117 z = compressor()
118 chunkiter = cg.getchunks()
107 119
108 120 # parse the changegroup data, otherwise we will block
109 121 # in case of sshrepo because we don't know the end of the stream
110 122
111 123 # an empty chunkgroup is the end of the changegroup
112 124 # a changegroup has at least 2 chunkgroups (changelog and manifest).
113 125 # after that, an empty chunkgroup is the end of the changegroup
114 for chunk in cg.getchunks():
126 for chunk in chunkiter:
115 127 fh.write(z.compress(chunk))
116 128 fh.write(z.flush())
117 129 cleanup = None
118 130 return filename
119 131 finally:
120 132 if fh is not None:
121 133 fh.close()
122 134 if cleanup is not None:
123 135 if filename and vfs:
124 136 vfs.unlink(cleanup)
125 137 else:
126 138 os.unlink(cleanup)
127 139
128 140 def decompressor(fh, alg):
129 141 if alg == 'UN':
130 142 return fh
131 143 elif alg == 'GZ':
132 144 def generator(f):
133 145 zd = zlib.decompressobj()
134 146 for chunk in util.filechunkiter(f):
135 147 yield zd.decompress(chunk)
136 148 elif alg == 'BZ':
137 149 def generator(f):
138 150 zd = bz2.BZ2Decompressor()
139 151 zd.decompress("BZ")
140 152 for chunk in util.filechunkiter(f, 4096):
141 153 yield zd.decompress(chunk)
142 154 else:
143 155 raise util.Abort("unknown bundle compression '%s'" % alg)
144 156 return util.chunkbuffer(generator(fh))
145 157
146 158 class cg1unpacker(object):
147 159 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
148 160 deltaheadersize = struct.calcsize(deltaheader)
161 version = '01'
149 162 def __init__(self, fh, alg):
150 163 self._stream = decompressor(fh, alg)
151 164 self._type = alg
152 165 self.callback = None
153 166 def compressed(self):
154 167 return self._type != 'UN'
155 168 def read(self, l):
156 169 return self._stream.read(l)
157 170 def seek(self, pos):
158 171 return self._stream.seek(pos)
159 172 def tell(self):
160 173 return self._stream.tell()
161 174 def close(self):
162 175 return self._stream.close()
163 176
164 177 def chunklength(self):
165 178 d = readexactly(self._stream, 4)
166 179 l = struct.unpack(">l", d)[0]
167 180 if l <= 4:
168 181 if l:
169 182 raise util.Abort(_("invalid chunk length %d") % l)
170 183 return 0
171 184 if self.callback:
172 185 self.callback()
173 186 return l - 4
174 187
175 188 def changelogheader(self):
176 189 """v10 does not have a changelog header chunk"""
177 190 return {}
178 191
179 192 def manifestheader(self):
180 193 """v10 does not have a manifest header chunk"""
181 194 return {}
182 195
183 196 def filelogheader(self):
184 197 """return the header of the filelogs chunk, v10 only has the filename"""
185 198 l = self.chunklength()
186 199 if not l:
187 200 return {}
188 201 fname = readexactly(self._stream, l)
189 202 return {'filename': fname}
190 203
191 204 def _deltaheader(self, headertuple, prevnode):
192 205 node, p1, p2, cs = headertuple
193 206 if prevnode is None:
194 207 deltabase = p1
195 208 else:
196 209 deltabase = prevnode
197 210 return node, p1, p2, deltabase, cs
198 211
199 212 def deltachunk(self, prevnode):
200 213 l = self.chunklength()
201 214 if not l:
202 215 return {}
203 216 headerdata = readexactly(self._stream, self.deltaheadersize)
204 217 header = struct.unpack(self.deltaheader, headerdata)
205 218 delta = readexactly(self._stream, l - self.deltaheadersize)
206 219 node, p1, p2, deltabase, cs = self._deltaheader(header, prevnode)
207 220 return {'node': node, 'p1': p1, 'p2': p2, 'cs': cs,
208 221 'deltabase': deltabase, 'delta': delta}
209 222
210 223 def getchunks(self):
211 224 """returns all the chunks contains in the bundle
212 225
213 226 Used when you need to forward the binary stream to a file or another
214 227 network API. To do so, it parse the changegroup data, otherwise it will
215 228 block in case of sshrepo because it don't know the end of the stream.
216 229 """
217 230 # an empty chunkgroup is the end of the changegroup
218 231 # a changegroup has at least 2 chunkgroups (changelog and manifest).
219 232 # after that, an empty chunkgroup is the end of the changegroup
220 233 empty = False
221 234 count = 0
222 235 while not empty or count <= 2:
223 236 empty = True
224 237 count += 1
225 238 while True:
226 239 chunk = getchunk(self)
227 240 if not chunk:
228 241 break
229 242 empty = False
230 243 yield chunkheader(len(chunk))
231 244 pos = 0
232 245 while pos < len(chunk):
233 246 next = pos + 2**20
234 247 yield chunk[pos:next]
235 248 pos = next
236 249 yield closechunk()
237 250
238 251 class cg2unpacker(cg1unpacker):
239 252 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
240 253 deltaheadersize = struct.calcsize(deltaheader)
254 version = '02'
241 255
242 256 def _deltaheader(self, headertuple, prevnode):
243 257 node, p1, p2, deltabase, cs = headertuple
244 258 return node, p1, p2, deltabase, cs
245 259
246 260 class headerlessfixup(object):
247 261 def __init__(self, fh, h):
248 262 self._h = h
249 263 self._fh = fh
250 264 def read(self, n):
251 265 if self._h:
252 266 d, self._h = self._h[:n], self._h[n:]
253 267 if len(d) < n:
254 268 d += readexactly(self._fh, n - len(d))
255 269 return d
256 270 return readexactly(self._fh, n)
257 271
258 272 class cg1packer(object):
259 273 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
274 version = '01'
260 275 def __init__(self, repo, bundlecaps=None):
261 276 """Given a source repo, construct a bundler.
262 277
263 278 bundlecaps is optional and can be used to specify the set of
264 279 capabilities which can be used to build the bundle.
265 280 """
266 281 # Set of capabilities we can use to build the bundle.
267 282 if bundlecaps is None:
268 283 bundlecaps = set()
269 284 self._bundlecaps = bundlecaps
270 285 self._changelog = repo.changelog
271 286 self._manifest = repo.manifest
272 287 reorder = repo.ui.config('bundle', 'reorder', 'auto')
273 288 if reorder == 'auto':
274 289 reorder = None
275 290 else:
276 291 reorder = util.parsebool(reorder)
277 292 self._repo = repo
278 293 self._reorder = reorder
279 294 self._progress = repo.ui.progress
280 295 if self._repo.ui.verbose and not self._repo.ui.debugflag:
281 296 self._verbosenote = self._repo.ui.note
282 297 else:
283 298 self._verbosenote = lambda s: None
284 299
285 300 def close(self):
286 301 return closechunk()
287 302
288 303 def fileheader(self, fname):
289 304 return chunkheader(len(fname)) + fname
290 305
291 306 def group(self, nodelist, revlog, lookup, units=None, reorder=None):
292 307 """Calculate a delta group, yielding a sequence of changegroup chunks
293 308 (strings).
294 309
295 310 Given a list of changeset revs, return a set of deltas and
296 311 metadata corresponding to nodes. The first delta is
297 312 first parent(nodelist[0]) -> nodelist[0], the receiver is
298 313 guaranteed to have this parent as it has all history before
299 314 these changesets. In the case firstparent is nullrev the
300 315 changegroup starts with a full revision.
301 316
302 317 If units is not None, progress detail will be generated, units specifies
303 318 the type of revlog that is touched (changelog, manifest, etc.).
304 319 """
305 320 # if we don't have any revisions touched by these changesets, bail
306 321 if len(nodelist) == 0:
307 322 yield self.close()
308 323 return
309 324
310 325 # for generaldelta revlogs, we linearize the revs; this will both be
311 326 # much quicker and generate a much smaller bundle
312 327 if (revlog._generaldelta and reorder is not False) or reorder:
313 328 dag = dagutil.revlogdag(revlog)
314 329 revs = set(revlog.rev(n) for n in nodelist)
315 330 revs = dag.linearize(revs)
316 331 else:
317 332 revs = sorted([revlog.rev(n) for n in nodelist])
318 333
319 334 # add the parent of the first rev
320 335 p = revlog.parentrevs(revs[0])[0]
321 336 revs.insert(0, p)
322 337
323 338 # build deltas
324 339 total = len(revs) - 1
325 340 msgbundling = _('bundling')
326 341 for r in xrange(len(revs) - 1):
327 342 if units is not None:
328 343 self._progress(msgbundling, r + 1, unit=units, total=total)
329 344 prev, curr = revs[r], revs[r + 1]
330 345 linknode = lookup(revlog.node(curr))
331 346 for c in self.revchunk(revlog, curr, prev, linknode):
332 347 yield c
333 348
334 349 yield self.close()
335 350
336 351 # filter any nodes that claim to be part of the known set
337 352 def prune(self, revlog, missing, commonrevs, source):
338 353 rr, rl = revlog.rev, revlog.linkrev
339 354 return [n for n in missing if rl(rr(n)) not in commonrevs]
340 355
341 356 def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
342 357 '''yield a sequence of changegroup chunks (strings)'''
343 358 repo = self._repo
344 359 cl = self._changelog
345 360 mf = self._manifest
346 361 reorder = self._reorder
347 362 progress = self._progress
348 363
349 364 # for progress output
350 365 msgbundling = _('bundling')
351 366
352 367 clrevorder = {}
353 368 mfs = {} # needed manifests
354 369 fnodes = {} # needed file nodes
355 370 changedfiles = set()
356 371
357 372 # Callback for the changelog, used to collect changed files and manifest
358 373 # nodes.
359 374 # Returns the linkrev node (identity in the changelog case).
360 375 def lookupcl(x):
361 376 c = cl.read(x)
362 377 clrevorder[x] = len(clrevorder)
363 378 changedfiles.update(c[3])
364 379 # record the first changeset introducing this manifest version
365 380 mfs.setdefault(c[0], x)
366 381 return x
367 382
368 383 self._verbosenote(_('uncompressed size of bundle content:\n'))
369 384 size = 0
370 385 for chunk in self.group(clnodes, cl, lookupcl, units=_('changesets'),
371 386 reorder=reorder):
372 387 size += len(chunk)
373 388 yield chunk
374 389 self._verbosenote(_('%8.i (changelog)\n') % size)
375 390 progress(msgbundling, None)
376 391
377 392 # Callback for the manifest, used to collect linkrevs for filelog
378 393 # revisions.
379 394 # Returns the linkrev node (collected in lookupcl).
380 395 def lookupmf(x):
381 396 clnode = mfs[x]
382 397 if not fastpathlinkrev or reorder:
383 398 mdata = mf.readfast(x)
384 399 for f, n in mdata.iteritems():
385 400 if f in changedfiles:
386 401 # record the first changeset introducing this filelog
387 402 # version
388 403 fclnodes = fnodes.setdefault(f, {})
389 404 fclnode = fclnodes.setdefault(n, clnode)
390 405 if clrevorder[clnode] < clrevorder[fclnode]:
391 406 fclnodes[n] = clnode
392 407 return clnode
393 408
394 409 mfnodes = self.prune(mf, mfs, commonrevs, source)
395 410 size = 0
396 411 for chunk in self.group(mfnodes, mf, lookupmf, units=_('manifests'),
397 412 reorder=reorder):
398 413 size += len(chunk)
399 414 yield chunk
400 415 self._verbosenote(_('%8.i (manifests)\n') % size)
401 416 progress(msgbundling, None)
402 417
403 418 mfs.clear()
404 419 needed = set(cl.rev(x) for x in clnodes)
405 420
406 421 def linknodes(filerevlog, fname):
407 422 if fastpathlinkrev and not reorder:
408 423 llr = filerevlog.linkrev
409 424 def genfilenodes():
410 425 for r in filerevlog:
411 426 linkrev = llr(r)
412 427 if linkrev in needed:
413 428 yield filerevlog.node(r), cl.node(linkrev)
414 429 return dict(genfilenodes())
415 430 return fnodes.get(fname, {})
416 431
417 432 for chunk in self.generatefiles(changedfiles, linknodes, commonrevs,
418 433 source):
419 434 yield chunk
420 435
421 436 yield self.close()
422 437 progress(msgbundling, None)
423 438
424 439 if clnodes:
425 440 repo.hook('outgoing', node=hex(clnodes[0]), source=source)
426 441
427 442 def generatefiles(self, changedfiles, linknodes, commonrevs, source):
428 443 repo = self._repo
429 444 progress = self._progress
430 445 reorder = self._reorder
431 446 msgbundling = _('bundling')
432 447
433 448 total = len(changedfiles)
434 449 # for progress output
435 450 msgfiles = _('files')
436 451 for i, fname in enumerate(sorted(changedfiles)):
437 452 filerevlog = repo.file(fname)
438 453 if not filerevlog:
439 454 raise util.Abort(_("empty or missing revlog for %s") % fname)
440 455
441 456 linkrevnodes = linknodes(filerevlog, fname)
442 457 # Lookup for filenodes, we collected the linkrev nodes above in the
443 458 # fastpath case and with lookupmf in the slowpath case.
444 459 def lookupfilelog(x):
445 460 return linkrevnodes[x]
446 461
447 462 filenodes = self.prune(filerevlog, linkrevnodes, commonrevs, source)
448 463 if filenodes:
449 464 progress(msgbundling, i + 1, item=fname, unit=msgfiles,
450 465 total=total)
451 466 h = self.fileheader(fname)
452 467 size = len(h)
453 468 yield h
454 469 for chunk in self.group(filenodes, filerevlog, lookupfilelog,
455 470 reorder=reorder):
456 471 size += len(chunk)
457 472 yield chunk
458 473 self._verbosenote(_('%8.i %s\n') % (size, fname))
459 474
460 475 def deltaparent(self, revlog, rev, p1, p2, prev):
461 476 return prev
462 477
463 478 def revchunk(self, revlog, rev, prev, linknode):
464 479 node = revlog.node(rev)
465 480 p1, p2 = revlog.parentrevs(rev)
466 481 base = self.deltaparent(revlog, rev, p1, p2, prev)
467 482
468 483 prefix = ''
469 484 if base == nullrev:
470 485 delta = revlog.revision(node)
471 486 prefix = mdiff.trivialdiffheader(len(delta))
472 487 else:
473 488 delta = revlog.revdiff(base, rev)
474 489 p1n, p2n = revlog.parents(node)
475 490 basenode = revlog.node(base)
476 491 meta = self.builddeltaheader(node, p1n, p2n, basenode, linknode)
477 492 meta += prefix
478 493 l = len(meta) + len(delta)
479 494 yield chunkheader(l)
480 495 yield meta
481 496 yield delta
482 497 def builddeltaheader(self, node, p1n, p2n, basenode, linknode):
483 498 # do nothing with basenode, it is implicitly the previous one in HG10
484 499 return struct.pack(self.deltaheader, node, p1n, p2n, linknode)
485 500
486 501 class cg2packer(cg1packer):
487
502 version = '02'
488 503 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
489 504
490 505 def group(self, nodelist, revlog, lookup, units=None, reorder=None):
491 506 if (revlog._generaldelta and reorder is not True):
492 507 reorder = False
493 508 return super(cg2packer, self).group(nodelist, revlog, lookup,
494 509 units=units, reorder=reorder)
495 510
496 511 def deltaparent(self, revlog, rev, p1, p2, prev):
497 512 dp = revlog.deltaparent(rev)
498 513 # avoid storing full revisions; pick prev in those cases
499 514 # also pick prev when we can't be sure remote has dp
500 515 if dp == nullrev or (dp != p1 and dp != p2 and dp != prev):
501 516 return prev
502 517 return dp
503 518
504 519 def builddeltaheader(self, node, p1n, p2n, basenode, linknode):
505 520 return struct.pack(self.deltaheader, node, p1n, p2n, basenode, linknode)
506 521
507 522 packermap = {'01': (cg1packer, cg1unpacker),
508 523 '02': (cg2packer, cg2unpacker)}
509 524
510 525 def _changegroupinfo(repo, nodes, source):
511 526 if repo.ui.verbose or source == 'bundle':
512 527 repo.ui.status(_("%d changesets found\n") % len(nodes))
513 528 if repo.ui.debugflag:
514 529 repo.ui.debug("list of changesets:\n")
515 530 for node in nodes:
516 531 repo.ui.debug("%s\n" % hex(node))
517 532
518 533 def getsubsetraw(repo, outgoing, bundler, source, fastpath=False):
519 534 repo = repo.unfiltered()
520 535 commonrevs = outgoing.common
521 536 csets = outgoing.missing
522 537 heads = outgoing.missingheads
523 538 # We go through the fast path if we get told to, or if all (unfiltered
524 539 # heads have been requested (since we then know there all linkrevs will
525 540 # be pulled by the client).
526 541 heads.sort()
527 542 fastpathlinkrev = fastpath or (
528 543 repo.filtername is None and heads == sorted(repo.heads()))
529 544
530 545 repo.hook('preoutgoing', throw=True, source=source)
531 546 _changegroupinfo(repo, csets, source)
532 547 return bundler.generate(commonrevs, csets, fastpathlinkrev, source)
533 548
534 549 def getsubset(repo, outgoing, bundler, source, fastpath=False):
535 550 gengroup = getsubsetraw(repo, outgoing, bundler, source, fastpath)
536 551 return cg1unpacker(util.chunkbuffer(gengroup), 'UN')
537 552
538 553 def changegroupsubset(repo, roots, heads, source):
539 554 """Compute a changegroup consisting of all the nodes that are
540 555 descendants of any of the roots and ancestors of any of the heads.
541 556 Return a chunkbuffer object whose read() method will return
542 557 successive changegroup chunks.
543 558
544 559 It is fairly complex as determining which filenodes and which
545 560 manifest nodes need to be included for the changeset to be complete
546 561 is non-trivial.
547 562
548 563 Another wrinkle is doing the reverse, figuring out which changeset in
549 564 the changegroup a particular filenode or manifestnode belongs to.
550 565 """
551 566 cl = repo.changelog
552 567 if not roots:
553 568 roots = [nullid]
554 569 # TODO: remove call to nodesbetween.
555 570 csets, roots, heads = cl.nodesbetween(roots, heads)
556 571 discbases = []
557 572 for n in roots:
558 573 discbases.extend([p for p in cl.parents(n) if p != nullid])
559 574 outgoing = discovery.outgoing(cl, discbases, heads)
560 575 bundler = cg1packer(repo)
561 576 return getsubset(repo, outgoing, bundler, source)
562 577
563 578 def getlocalchangegroupraw(repo, source, outgoing, bundlecaps=None,
564 579 version='01'):
565 580 """Like getbundle, but taking a discovery.outgoing as an argument.
566 581
567 582 This is only implemented for local repos and reuses potentially
568 583 precomputed sets in outgoing. Returns a raw changegroup generator."""
569 584 if not outgoing.missing:
570 585 return None
571 586 bundler = packermap[version][0](repo, bundlecaps)
572 587 return getsubsetraw(repo, outgoing, bundler, source)
573 588
574 589 def getlocalchangegroup(repo, source, outgoing, bundlecaps=None):
575 590 """Like getbundle, but taking a discovery.outgoing as an argument.
576 591
577 592 This is only implemented for local repos and reuses potentially
578 593 precomputed sets in outgoing."""
579 594 if not outgoing.missing:
580 595 return None
581 596 bundler = cg1packer(repo, bundlecaps)
582 597 return getsubset(repo, outgoing, bundler, source)
583 598
584 599 def _computeoutgoing(repo, heads, common):
585 600 """Computes which revs are outgoing given a set of common
586 601 and a set of heads.
587 602
588 603 This is a separate function so extensions can have access to
589 604 the logic.
590 605
591 606 Returns a discovery.outgoing object.
592 607 """
593 608 cl = repo.changelog
594 609 if common:
595 610 hasnode = cl.hasnode
596 611 common = [n for n in common if hasnode(n)]
597 612 else:
598 613 common = [nullid]
599 614 if not heads:
600 615 heads = cl.heads()
601 616 return discovery.outgoing(cl, common, heads)
602 617
603 618 def getchangegroupraw(repo, source, heads=None, common=None, bundlecaps=None,
604 619 version='01'):
605 620 """Like changegroupsubset, but returns the set difference between the
606 621 ancestors of heads and the ancestors common.
607 622
608 623 If heads is None, use the local heads. If common is None, use [nullid].
609 624
610 625 If version is None, use a version '1' changegroup.
611 626
612 627 The nodes in common might not all be known locally due to the way the
613 628 current discovery protocol works. Returns a raw changegroup generator.
614 629 """
615 630 outgoing = _computeoutgoing(repo, heads, common)
616 631 return getlocalchangegroupraw(repo, source, outgoing, bundlecaps=bundlecaps,
617 632 version=version)
618 633
619 634 def getchangegroup(repo, source, heads=None, common=None, bundlecaps=None):
620 635 """Like changegroupsubset, but returns the set difference between the
621 636 ancestors of heads and the ancestors common.
622 637
623 638 If heads is None, use the local heads. If common is None, use [nullid].
624 639
625 640 The nodes in common might not all be known locally due to the way the
626 641 current discovery protocol works.
627 642 """
628 643 outgoing = _computeoutgoing(repo, heads, common)
629 644 return getlocalchangegroup(repo, source, outgoing, bundlecaps=bundlecaps)
630 645
631 646 def changegroup(repo, basenodes, source):
632 647 # to avoid a race we use changegroupsubset() (issue1320)
633 648 return changegroupsubset(repo, basenodes, repo.heads(), source)
634 649
635 650 def addchangegroupfiles(repo, source, revmap, trp, pr, needfiles):
636 651 revisions = 0
637 652 files = 0
638 653 while True:
639 654 chunkdata = source.filelogheader()
640 655 if not chunkdata:
641 656 break
642 657 f = chunkdata["filename"]
643 658 repo.ui.debug("adding %s revisions\n" % f)
644 659 pr()
645 660 fl = repo.file(f)
646 661 o = len(fl)
647 662 if not fl.addgroup(source, revmap, trp):
648 663 raise util.Abort(_("received file revlog group is empty"))
649 664 revisions += len(fl) - o
650 665 files += 1
651 666 if f in needfiles:
652 667 needs = needfiles[f]
653 668 for new in xrange(o, len(fl)):
654 669 n = fl.node(new)
655 670 if n in needs:
656 671 needs.remove(n)
657 672 else:
658 673 raise util.Abort(
659 674 _("received spurious file revlog entry"))
660 675 if not needs:
661 676 del needfiles[f]
662 677 repo.ui.progress(_('files'), None)
663 678
664 679 for f, needs in needfiles.iteritems():
665 680 fl = repo.file(f)
666 681 for n in needs:
667 682 try:
668 683 fl.rev(n)
669 684 except error.LookupError:
670 685 raise util.Abort(
671 686 _('missing file data for %s:%s - run hg verify') %
672 687 (f, hex(n)))
673 688
674 689 return revisions, files
675 690
676 691 def addchangegroup(repo, source, srctype, url, emptyok=False,
677 692 targetphase=phases.draft):
678 693 """Add the changegroup returned by source.read() to this repo.
679 694 srctype is a string like 'push', 'pull', or 'unbundle'. url is
680 695 the URL of the repo where this changegroup is coming from.
681 696
682 697 Return an integer summarizing the change to this repo:
683 698 - nothing changed or no source: 0
684 699 - more heads than before: 1+added heads (2..n)
685 700 - fewer heads than before: -1-removed heads (-2..-n)
686 701 - number of heads stays the same: 1
687 702 """
688 703 repo = repo.unfiltered()
689 704 def csmap(x):
690 705 repo.ui.debug("add changeset %s\n" % short(x))
691 706 return len(cl)
692 707
693 708 def revmap(x):
694 709 return cl.rev(x)
695 710
696 711 if not source:
697 712 return 0
698 713
699 714 changesets = files = revisions = 0
700 715 efiles = set()
701 716
702 717 tr = repo.transaction("\n".join([srctype, util.hidepassword(url)]))
703 718 # The transaction could have been created before and already carries source
704 719 # information. In this case we use the top level data. We overwrite the
705 720 # argument because we need to use the top level value (if they exist) in
706 721 # this function.
707 722 srctype = tr.hookargs.setdefault('source', srctype)
708 723 url = tr.hookargs.setdefault('url', url)
709 724
710 725 # write changelog data to temp files so concurrent readers will not see
711 726 # inconsistent view
712 727 cl = repo.changelog
713 728 cl.delayupdate(tr)
714 729 oldheads = cl.heads()
715 730 try:
716 731 repo.hook('prechangegroup', throw=True, **tr.hookargs)
717 732
718 733 trp = weakref.proxy(tr)
719 734 # pull off the changeset group
720 735 repo.ui.status(_("adding changesets\n"))
721 736 clstart = len(cl)
722 737 class prog(object):
723 738 step = _('changesets')
724 739 count = 1
725 740 ui = repo.ui
726 741 total = None
727 742 def __call__(repo):
728 743 repo.ui.progress(repo.step, repo.count, unit=_('chunks'),
729 744 total=repo.total)
730 745 repo.count += 1
731 746 pr = prog()
732 747 source.callback = pr
733 748
734 749 source.changelogheader()
735 750 srccontent = cl.addgroup(source, csmap, trp)
736 751 if not (srccontent or emptyok):
737 752 raise util.Abort(_("received changelog group is empty"))
738 753 clend = len(cl)
739 754 changesets = clend - clstart
740 755 for c in xrange(clstart, clend):
741 756 efiles.update(repo[c].files())
742 757 efiles = len(efiles)
743 758 repo.ui.progress(_('changesets'), None)
744 759
745 760 # pull off the manifest group
746 761 repo.ui.status(_("adding manifests\n"))
747 762 pr.step = _('manifests')
748 763 pr.count = 1
749 764 pr.total = changesets # manifests <= changesets
750 765 # no need to check for empty manifest group here:
751 766 # if the result of the merge of 1 and 2 is the same in 3 and 4,
752 767 # no new manifest will be created and the manifest group will
753 768 # be empty during the pull
754 769 source.manifestheader()
755 770 repo.manifest.addgroup(source, revmap, trp)
756 771 repo.ui.progress(_('manifests'), None)
757 772
758 773 needfiles = {}
759 774 if repo.ui.configbool('server', 'validate', default=False):
760 775 # validate incoming csets have their manifests
761 776 for cset in xrange(clstart, clend):
762 777 mfest = repo.changelog.read(repo.changelog.node(cset))[0]
763 778 mfest = repo.manifest.readdelta(mfest)
764 779 # store file nodes we must see
765 780 for f, n in mfest.iteritems():
766 781 needfiles.setdefault(f, set()).add(n)
767 782
768 783 # process the files
769 784 repo.ui.status(_("adding file changes\n"))
770 785 pr.step = _('files')
771 786 pr.count = 1
772 787 pr.total = efiles
773 788 source.callback = None
774 789
775 790 newrevs, newfiles = addchangegroupfiles(repo, source, revmap, trp, pr,
776 791 needfiles)
777 792 revisions += newrevs
778 793 files += newfiles
779 794
780 795 dh = 0
781 796 if oldheads:
782 797 heads = cl.heads()
783 798 dh = len(heads) - len(oldheads)
784 799 for h in heads:
785 800 if h not in oldheads and repo[h].closesbranch():
786 801 dh -= 1
787 802 htext = ""
788 803 if dh:
789 804 htext = _(" (%+d heads)") % dh
790 805
791 806 repo.ui.status(_("added %d changesets"
792 807 " with %d changes to %d files%s\n")
793 808 % (changesets, revisions, files, htext))
794 809 repo.invalidatevolatilesets()
795 810
796 811 if changesets > 0:
797 812 p = lambda: tr.writepending() and repo.root or ""
798 813 if 'node' not in tr.hookargs:
799 814 tr.hookargs['node'] = hex(cl.node(clstart))
800 815 hookargs = dict(tr.hookargs)
801 816 else:
802 817 hookargs = dict(tr.hookargs)
803 818 hookargs['node'] = hex(cl.node(clstart))
804 819 repo.hook('pretxnchangegroup', throw=True, pending=p, **hookargs)
805 820
806 821 added = [cl.node(r) for r in xrange(clstart, clend)]
807 822 publishing = repo.ui.configbool('phases', 'publish', True)
808 823 if srctype in ('push', 'serve'):
809 824 # Old servers can not push the boundary themselves.
810 825 # New servers won't push the boundary if changeset already
811 826 # exists locally as secret
812 827 #
813 828 # We should not use added here but the list of all change in
814 829 # the bundle
815 830 if publishing:
816 831 phases.advanceboundary(repo, tr, phases.public, srccontent)
817 832 else:
818 833 # Those changesets have been pushed from the outside, their
819 834 # phases are going to be pushed alongside. Therefor
820 835 # `targetphase` is ignored.
821 836 phases.advanceboundary(repo, tr, phases.draft, srccontent)
822 837 phases.retractboundary(repo, tr, phases.draft, added)
823 838 elif srctype != 'strip':
824 839 # publishing only alter behavior during push
825 840 #
826 841 # strip should not touch boundary at all
827 842 phases.retractboundary(repo, tr, targetphase, added)
828 843
829 844 if changesets > 0:
830 845 if srctype != 'strip':
831 846 # During strip, branchcache is invalid but coming call to
832 847 # `destroyed` will repair it.
833 848 # In other case we can safely update cache on disk.
834 849 branchmap.updatecache(repo.filtered('served'))
835 850
836 851 def runhooks():
837 852 # These hooks run when the lock releases, not when the
838 853 # transaction closes. So it's possible for the changelog
839 854 # to have changed since we last saw it.
840 855 if clstart >= len(repo):
841 856 return
842 857
843 858 # forcefully update the on-disk branch cache
844 859 repo.ui.debug("updating the branch cache\n")
845 860 repo.hook("changegroup", **hookargs)
846 861
847 862 for n in added:
848 863 args = hookargs.copy()
849 864 args['node'] = hex(n)
850 865 repo.hook("incoming", **args)
851 866
852 867 newheads = [h for h in repo.heads() if h not in oldheads]
853 868 repo.ui.log("incoming",
854 869 "%s incoming changes - new heads: %s\n",
855 870 len(added),
856 871 ', '.join([hex(c[:6]) for c in newheads]))
857 872
858 873 tr.addpostclose('changegroup-runhooks-%020i' % clstart,
859 874 lambda tr: repo._afterlock(runhooks))
860 875
861 876 tr.close()
862 877
863 878 finally:
864 879 tr.release()
865 880 # never return 0 here:
866 881 if dh < 0:
867 882 return dh - 1
868 883 else:
869 884 return dh + 1
@@ -1,6317 +1,6323 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from node import hex, bin, nullid, nullrev, short
9 9 from lock import release
10 10 from i18n import _
11 11 import os, re, difflib, time, tempfile, errno, shlex
12 12 import sys, socket
13 13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 14 import patch, help, encoding, templatekw, discovery
15 15 import archival, changegroup, cmdutil, hbisect
16 16 import sshserver, hgweb, commandserver
17 17 import extensions
18 18 from hgweb import server as hgweb_server
19 19 import merge as mergemod
20 20 import minirst, revset, fileset
21 21 import dagparser, context, simplemerge, graphmod, copies
22 22 import random
23 23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
24 24 import phases, obsolete, exchange, bundle2
25 25 import ui as uimod
26 26
27 27 table = {}
28 28
29 29 command = cmdutil.command(table)
30 30
31 31 # Space delimited list of commands that don't require local repositories.
32 32 # This should be populated by passing norepo=True into the @command decorator.
33 33 norepo = ''
34 34 # Space delimited list of commands that optionally require local repositories.
35 35 # This should be populated by passing optionalrepo=True into the @command
36 36 # decorator.
37 37 optionalrepo = ''
38 38 # Space delimited list of commands that will examine arguments looking for
39 39 # a repository. This should be populated by passing inferrepo=True into the
40 40 # @command decorator.
41 41 inferrepo = ''
42 42
43 43 # common command options
44 44
45 45 globalopts = [
46 46 ('R', 'repository', '',
47 47 _('repository root directory or name of overlay bundle file'),
48 48 _('REPO')),
49 49 ('', 'cwd', '',
50 50 _('change working directory'), _('DIR')),
51 51 ('y', 'noninteractive', None,
52 52 _('do not prompt, automatically pick the first choice for all prompts')),
53 53 ('q', 'quiet', None, _('suppress output')),
54 54 ('v', 'verbose', None, _('enable additional output')),
55 55 ('', 'config', [],
56 56 _('set/override config option (use \'section.name=value\')'),
57 57 _('CONFIG')),
58 58 ('', 'debug', None, _('enable debugging output')),
59 59 ('', 'debugger', None, _('start debugger')),
60 60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
61 61 _('ENCODE')),
62 62 ('', 'encodingmode', encoding.encodingmode,
63 63 _('set the charset encoding mode'), _('MODE')),
64 64 ('', 'traceback', None, _('always print a traceback on exception')),
65 65 ('', 'time', None, _('time how long the command takes')),
66 66 ('', 'profile', None, _('print command execution profile')),
67 67 ('', 'version', None, _('output version information and exit')),
68 68 ('h', 'help', None, _('display help and exit')),
69 69 ('', 'hidden', False, _('consider hidden changesets')),
70 70 ]
71 71
72 72 dryrunopts = [('n', 'dry-run', None,
73 73 _('do not perform actions, just print output'))]
74 74
75 75 remoteopts = [
76 76 ('e', 'ssh', '',
77 77 _('specify ssh command to use'), _('CMD')),
78 78 ('', 'remotecmd', '',
79 79 _('specify hg command to run on the remote side'), _('CMD')),
80 80 ('', 'insecure', None,
81 81 _('do not verify server certificate (ignoring web.cacerts config)')),
82 82 ]
83 83
84 84 walkopts = [
85 85 ('I', 'include', [],
86 86 _('include names matching the given patterns'), _('PATTERN')),
87 87 ('X', 'exclude', [],
88 88 _('exclude names matching the given patterns'), _('PATTERN')),
89 89 ]
90 90
91 91 commitopts = [
92 92 ('m', 'message', '',
93 93 _('use text as commit message'), _('TEXT')),
94 94 ('l', 'logfile', '',
95 95 _('read commit message from file'), _('FILE')),
96 96 ]
97 97
98 98 commitopts2 = [
99 99 ('d', 'date', '',
100 100 _('record the specified date as commit date'), _('DATE')),
101 101 ('u', 'user', '',
102 102 _('record the specified user as committer'), _('USER')),
103 103 ]
104 104
105 105 # hidden for now
106 106 formatteropts = [
107 107 ('T', 'template', '',
108 108 _('display with template (DEPRECATED)'), _('TEMPLATE')),
109 109 ]
110 110
111 111 templateopts = [
112 112 ('', 'style', '',
113 113 _('display using template map file (DEPRECATED)'), _('STYLE')),
114 114 ('T', 'template', '',
115 115 _('display with template'), _('TEMPLATE')),
116 116 ]
117 117
118 118 logopts = [
119 119 ('p', 'patch', None, _('show patch')),
120 120 ('g', 'git', None, _('use git extended diff format')),
121 121 ('l', 'limit', '',
122 122 _('limit number of changes displayed'), _('NUM')),
123 123 ('M', 'no-merges', None, _('do not show merges')),
124 124 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 125 ('G', 'graph', None, _("show the revision DAG")),
126 126 ] + templateopts
127 127
128 128 diffopts = [
129 129 ('a', 'text', None, _('treat all files as text')),
130 130 ('g', 'git', None, _('use git extended diff format')),
131 131 ('', 'nodates', None, _('omit dates from diff headers'))
132 132 ]
133 133
134 134 diffwsopts = [
135 135 ('w', 'ignore-all-space', None,
136 136 _('ignore white space when comparing lines')),
137 137 ('b', 'ignore-space-change', None,
138 138 _('ignore changes in the amount of white space')),
139 139 ('B', 'ignore-blank-lines', None,
140 140 _('ignore changes whose lines are all blank')),
141 141 ]
142 142
143 143 diffopts2 = [
144 144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
145 145 ('p', 'show-function', None, _('show which function each change is in')),
146 146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
147 147 ] + diffwsopts + [
148 148 ('U', 'unified', '',
149 149 _('number of lines of context to show'), _('NUM')),
150 150 ('', 'stat', None, _('output diffstat-style summary of changes')),
151 151 ]
152 152
153 153 mergetoolopts = [
154 154 ('t', 'tool', '', _('specify merge tool')),
155 155 ]
156 156
157 157 similarityopts = [
158 158 ('s', 'similarity', '',
159 159 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
160 160 ]
161 161
162 162 subrepoopts = [
163 163 ('S', 'subrepos', None,
164 164 _('recurse into subrepositories'))
165 165 ]
166 166
167 167 # Commands start here, listed alphabetically
168 168
169 169 @command('^add',
170 170 walkopts + subrepoopts + dryrunopts,
171 171 _('[OPTION]... [FILE]...'),
172 172 inferrepo=True)
173 173 def add(ui, repo, *pats, **opts):
174 174 """add the specified files on the next commit
175 175
176 176 Schedule files to be version controlled and added to the
177 177 repository.
178 178
179 179 The files will be added to the repository at the next commit. To
180 180 undo an add before that, see :hg:`forget`.
181 181
182 182 If no names are given, add all files to the repository.
183 183
184 184 .. container:: verbose
185 185
186 186 An example showing how new (unknown) files are added
187 187 automatically by :hg:`add`::
188 188
189 189 $ ls
190 190 foo.c
191 191 $ hg status
192 192 ? foo.c
193 193 $ hg add
194 194 adding foo.c
195 195 $ hg status
196 196 A foo.c
197 197
198 198 Returns 0 if all files are successfully added.
199 199 """
200 200
201 201 m = scmutil.match(repo[None], pats, opts)
202 202 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
203 203 return rejected and 1 or 0
204 204
205 205 @command('addremove',
206 206 similarityopts + subrepoopts + walkopts + dryrunopts,
207 207 _('[OPTION]... [FILE]...'),
208 208 inferrepo=True)
209 209 def addremove(ui, repo, *pats, **opts):
210 210 """add all new files, delete all missing files
211 211
212 212 Add all new files and remove all missing files from the
213 213 repository.
214 214
215 215 New files are ignored if they match any of the patterns in
216 216 ``.hgignore``. As with add, these changes take effect at the next
217 217 commit.
218 218
219 219 Use the -s/--similarity option to detect renamed files. This
220 220 option takes a percentage between 0 (disabled) and 100 (files must
221 221 be identical) as its parameter. With a parameter greater than 0,
222 222 this compares every removed file with every added file and records
223 223 those similar enough as renames. Detecting renamed files this way
224 224 can be expensive. After using this option, :hg:`status -C` can be
225 225 used to check which files were identified as moved or renamed. If
226 226 not specified, -s/--similarity defaults to 100 and only renames of
227 227 identical files are detected.
228 228
229 229 Returns 0 if all files are successfully added.
230 230 """
231 231 try:
232 232 sim = float(opts.get('similarity') or 100)
233 233 except ValueError:
234 234 raise util.Abort(_('similarity must be a number'))
235 235 if sim < 0 or sim > 100:
236 236 raise util.Abort(_('similarity must be between 0 and 100'))
237 237 matcher = scmutil.match(repo[None], pats, opts)
238 238 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
239 239
240 240 @command('^annotate|blame',
241 241 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
242 242 ('', 'follow', None,
243 243 _('follow copies/renames and list the filename (DEPRECATED)')),
244 244 ('', 'no-follow', None, _("don't follow copies and renames")),
245 245 ('a', 'text', None, _('treat all files as text')),
246 246 ('u', 'user', None, _('list the author (long with -v)')),
247 247 ('f', 'file', None, _('list the filename')),
248 248 ('d', 'date', None, _('list the date (short with -q)')),
249 249 ('n', 'number', None, _('list the revision number (default)')),
250 250 ('c', 'changeset', None, _('list the changeset')),
251 251 ('l', 'line-number', None, _('show line number at the first appearance'))
252 252 ] + diffwsopts + walkopts + formatteropts,
253 253 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
254 254 inferrepo=True)
255 255 def annotate(ui, repo, *pats, **opts):
256 256 """show changeset information by line for each file
257 257
258 258 List changes in files, showing the revision id responsible for
259 259 each line
260 260
261 261 This command is useful for discovering when a change was made and
262 262 by whom.
263 263
264 264 Without the -a/--text option, annotate will avoid processing files
265 265 it detects as binary. With -a, annotate will annotate the file
266 266 anyway, although the results will probably be neither useful
267 267 nor desirable.
268 268
269 269 Returns 0 on success.
270 270 """
271 271 if not pats:
272 272 raise util.Abort(_('at least one filename or pattern is required'))
273 273
274 274 if opts.get('follow'):
275 275 # --follow is deprecated and now just an alias for -f/--file
276 276 # to mimic the behavior of Mercurial before version 1.5
277 277 opts['file'] = True
278 278
279 279 fm = ui.formatter('annotate', opts)
280 280 datefunc = ui.quiet and util.shortdate or util.datestr
281 281 hexfn = fm.hexfunc
282 282
283 283 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
284 284 ('number', ' ', lambda x: x[0].rev(), str),
285 285 ('changeset', ' ', lambda x: hexfn(x[0].node()), str),
286 286 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
287 287 ('file', ' ', lambda x: x[0].path(), str),
288 288 ('line_number', ':', lambda x: x[1], str),
289 289 ]
290 290 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
291 291
292 292 if (not opts.get('user') and not opts.get('changeset')
293 293 and not opts.get('date') and not opts.get('file')):
294 294 opts['number'] = True
295 295
296 296 linenumber = opts.get('line_number') is not None
297 297 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
298 298 raise util.Abort(_('at least one of -n/-c is required for -l'))
299 299
300 300 if fm:
301 301 def makefunc(get, fmt):
302 302 return get
303 303 else:
304 304 def makefunc(get, fmt):
305 305 return lambda x: fmt(get(x))
306 306 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
307 307 if opts.get(op)]
308 308 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
309 309 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
310 310 if opts.get(op))
311 311
312 312 def bad(x, y):
313 313 raise util.Abort("%s: %s" % (x, y))
314 314
315 315 ctx = scmutil.revsingle(repo, opts.get('rev'))
316 316 m = scmutil.match(ctx, pats, opts)
317 317 m.bad = bad
318 318 follow = not opts.get('no_follow')
319 319 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
320 320 whitespace=True)
321 321 for abs in ctx.walk(m):
322 322 fctx = ctx[abs]
323 323 if not opts.get('text') and util.binary(fctx.data()):
324 324 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
325 325 continue
326 326
327 327 lines = fctx.annotate(follow=follow, linenumber=linenumber,
328 328 diffopts=diffopts)
329 329 formats = []
330 330 pieces = []
331 331
332 332 for f, sep in funcmap:
333 333 l = [f(n) for n, dummy in lines]
334 334 if l:
335 335 if fm:
336 336 formats.append(['%s' for x in l])
337 337 else:
338 338 sizes = [encoding.colwidth(x) for x in l]
339 339 ml = max(sizes)
340 340 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
341 341 pieces.append(l)
342 342
343 343 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
344 344 fm.startitem()
345 345 fm.write(fields, "".join(f), *p)
346 346 fm.write('line', ": %s", l[1])
347 347
348 348 if lines and not lines[-1][1].endswith('\n'):
349 349 fm.plain('\n')
350 350
351 351 fm.end()
352 352
353 353 @command('archive',
354 354 [('', 'no-decode', None, _('do not pass files through decoders')),
355 355 ('p', 'prefix', '', _('directory prefix for files in archive'),
356 356 _('PREFIX')),
357 357 ('r', 'rev', '', _('revision to distribute'), _('REV')),
358 358 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
359 359 ] + subrepoopts + walkopts,
360 360 _('[OPTION]... DEST'))
361 361 def archive(ui, repo, dest, **opts):
362 362 '''create an unversioned archive of a repository revision
363 363
364 364 By default, the revision used is the parent of the working
365 365 directory; use -r/--rev to specify a different revision.
366 366
367 367 The archive type is automatically detected based on file
368 368 extension (or override using -t/--type).
369 369
370 370 .. container:: verbose
371 371
372 372 Examples:
373 373
374 374 - create a zip file containing the 1.0 release::
375 375
376 376 hg archive -r 1.0 project-1.0.zip
377 377
378 378 - create a tarball excluding .hg files::
379 379
380 380 hg archive project.tar.gz -X ".hg*"
381 381
382 382 Valid types are:
383 383
384 384 :``files``: a directory full of files (default)
385 385 :``tar``: tar archive, uncompressed
386 386 :``tbz2``: tar archive, compressed using bzip2
387 387 :``tgz``: tar archive, compressed using gzip
388 388 :``uzip``: zip archive, uncompressed
389 389 :``zip``: zip archive, compressed using deflate
390 390
391 391 The exact name of the destination archive or directory is given
392 392 using a format string; see :hg:`help export` for details.
393 393
394 394 Each member added to an archive file has a directory prefix
395 395 prepended. Use -p/--prefix to specify a format string for the
396 396 prefix. The default is the basename of the archive, with suffixes
397 397 removed.
398 398
399 399 Returns 0 on success.
400 400 '''
401 401
402 402 ctx = scmutil.revsingle(repo, opts.get('rev'))
403 403 if not ctx:
404 404 raise util.Abort(_('no working directory: please specify a revision'))
405 405 node = ctx.node()
406 406 dest = cmdutil.makefilename(repo, dest, node)
407 407 if os.path.realpath(dest) == repo.root:
408 408 raise util.Abort(_('repository root cannot be destination'))
409 409
410 410 kind = opts.get('type') or archival.guesskind(dest) or 'files'
411 411 prefix = opts.get('prefix')
412 412
413 413 if dest == '-':
414 414 if kind == 'files':
415 415 raise util.Abort(_('cannot archive plain files to stdout'))
416 416 dest = cmdutil.makefileobj(repo, dest)
417 417 if not prefix:
418 418 prefix = os.path.basename(repo.root) + '-%h'
419 419
420 420 prefix = cmdutil.makefilename(repo, prefix, node)
421 421 matchfn = scmutil.match(ctx, [], opts)
422 422 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
423 423 matchfn, prefix, subrepos=opts.get('subrepos'))
424 424
425 425 @command('backout',
426 426 [('', 'merge', None, _('merge with old dirstate parent after backout')),
427 427 ('', 'commit', None, _('commit if no conflicts were encountered')),
428 428 ('', 'parent', '',
429 429 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
430 430 ('r', 'rev', '', _('revision to backout'), _('REV')),
431 431 ('e', 'edit', False, _('invoke editor on commit messages')),
432 432 ] + mergetoolopts + walkopts + commitopts + commitopts2,
433 433 _('[OPTION]... [-r] REV'))
434 434 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
435 435 '''reverse effect of earlier changeset
436 436
437 437 Prepare a new changeset with the effect of REV undone in the
438 438 current working directory.
439 439
440 440 If REV is the parent of the working directory, then this new changeset
441 441 is committed automatically. Otherwise, hg needs to merge the
442 442 changes and the merged result is left uncommitted.
443 443
444 444 .. note::
445 445
446 446 backout cannot be used to fix either an unwanted or
447 447 incorrect merge.
448 448
449 449 .. container:: verbose
450 450
451 451 By default, the pending changeset will have one parent,
452 452 maintaining a linear history. With --merge, the pending
453 453 changeset will instead have two parents: the old parent of the
454 454 working directory and a new child of REV that simply undoes REV.
455 455
456 456 Before version 1.7, the behavior without --merge was equivalent
457 457 to specifying --merge followed by :hg:`update --clean .` to
458 458 cancel the merge and leave the child of REV as a head to be
459 459 merged separately.
460 460
461 461 See :hg:`help dates` for a list of formats valid for -d/--date.
462 462
463 463 Returns 0 on success, 1 if nothing to backout or there are unresolved
464 464 files.
465 465 '''
466 466 if rev and node:
467 467 raise util.Abort(_("please specify just one revision"))
468 468
469 469 if not rev:
470 470 rev = node
471 471
472 472 if not rev:
473 473 raise util.Abort(_("please specify a revision to backout"))
474 474
475 475 date = opts.get('date')
476 476 if date:
477 477 opts['date'] = util.parsedate(date)
478 478
479 479 cmdutil.checkunfinished(repo)
480 480 cmdutil.bailifchanged(repo)
481 481 node = scmutil.revsingle(repo, rev).node()
482 482
483 483 op1, op2 = repo.dirstate.parents()
484 484 if not repo.changelog.isancestor(node, op1):
485 485 raise util.Abort(_('cannot backout change that is not an ancestor'))
486 486
487 487 p1, p2 = repo.changelog.parents(node)
488 488 if p1 == nullid:
489 489 raise util.Abort(_('cannot backout a change with no parents'))
490 490 if p2 != nullid:
491 491 if not opts.get('parent'):
492 492 raise util.Abort(_('cannot backout a merge changeset'))
493 493 p = repo.lookup(opts['parent'])
494 494 if p not in (p1, p2):
495 495 raise util.Abort(_('%s is not a parent of %s') %
496 496 (short(p), short(node)))
497 497 parent = p
498 498 else:
499 499 if opts.get('parent'):
500 500 raise util.Abort(_('cannot use --parent on non-merge changeset'))
501 501 parent = p1
502 502
503 503 # the backout should appear on the same branch
504 504 wlock = repo.wlock()
505 505 try:
506 506 branch = repo.dirstate.branch()
507 507 bheads = repo.branchheads(branch)
508 508 rctx = scmutil.revsingle(repo, hex(parent))
509 509 if not opts.get('merge') and op1 != node:
510 510 try:
511 511 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
512 512 'backout')
513 513 repo.dirstate.beginparentchange()
514 514 stats = mergemod.update(repo, parent, True, True, False,
515 515 node, False)
516 516 repo.setparents(op1, op2)
517 517 repo.dirstate.endparentchange()
518 518 hg._showstats(repo, stats)
519 519 if stats[3]:
520 520 repo.ui.status(_("use 'hg resolve' to retry unresolved "
521 521 "file merges\n"))
522 522 return 1
523 523 elif not commit:
524 524 msg = _("changeset %s backed out, "
525 525 "don't forget to commit.\n")
526 526 ui.status(msg % short(node))
527 527 return 0
528 528 finally:
529 529 ui.setconfig('ui', 'forcemerge', '', '')
530 530 else:
531 531 hg.clean(repo, node, show_stats=False)
532 532 repo.dirstate.setbranch(branch)
533 533 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
534 534
535 535
536 536 def commitfunc(ui, repo, message, match, opts):
537 537 editform = 'backout'
538 538 e = cmdutil.getcommiteditor(editform=editform, **opts)
539 539 if not message:
540 540 # we don't translate commit messages
541 541 message = "Backed out changeset %s" % short(node)
542 542 e = cmdutil.getcommiteditor(edit=True, editform=editform)
543 543 return repo.commit(message, opts.get('user'), opts.get('date'),
544 544 match, editor=e)
545 545 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
546 546 if not newnode:
547 547 ui.status(_("nothing changed\n"))
548 548 return 1
549 549 cmdutil.commitstatus(repo, newnode, branch, bheads)
550 550
551 551 def nice(node):
552 552 return '%d:%s' % (repo.changelog.rev(node), short(node))
553 553 ui.status(_('changeset %s backs out changeset %s\n') %
554 554 (nice(repo.changelog.tip()), nice(node)))
555 555 if opts.get('merge') and op1 != node:
556 556 hg.clean(repo, op1, show_stats=False)
557 557 ui.status(_('merging with changeset %s\n')
558 558 % nice(repo.changelog.tip()))
559 559 try:
560 560 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
561 561 'backout')
562 562 return hg.merge(repo, hex(repo.changelog.tip()))
563 563 finally:
564 564 ui.setconfig('ui', 'forcemerge', '', '')
565 565 finally:
566 566 wlock.release()
567 567 return 0
568 568
569 569 @command('bisect',
570 570 [('r', 'reset', False, _('reset bisect state')),
571 571 ('g', 'good', False, _('mark changeset good')),
572 572 ('b', 'bad', False, _('mark changeset bad')),
573 573 ('s', 'skip', False, _('skip testing changeset')),
574 574 ('e', 'extend', False, _('extend the bisect range')),
575 575 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
576 576 ('U', 'noupdate', False, _('do not update to target'))],
577 577 _("[-gbsr] [-U] [-c CMD] [REV]"))
578 578 def bisect(ui, repo, rev=None, extra=None, command=None,
579 579 reset=None, good=None, bad=None, skip=None, extend=None,
580 580 noupdate=None):
581 581 """subdivision search of changesets
582 582
583 583 This command helps to find changesets which introduce problems. To
584 584 use, mark the earliest changeset you know exhibits the problem as
585 585 bad, then mark the latest changeset which is free from the problem
586 586 as good. Bisect will update your working directory to a revision
587 587 for testing (unless the -U/--noupdate option is specified). Once
588 588 you have performed tests, mark the working directory as good or
589 589 bad, and bisect will either update to another candidate changeset
590 590 or announce that it has found the bad revision.
591 591
592 592 As a shortcut, you can also use the revision argument to mark a
593 593 revision as good or bad without checking it out first.
594 594
595 595 If you supply a command, it will be used for automatic bisection.
596 596 The environment variable HG_NODE will contain the ID of the
597 597 changeset being tested. The exit status of the command will be
598 598 used to mark revisions as good or bad: status 0 means good, 125
599 599 means to skip the revision, 127 (command not found) will abort the
600 600 bisection, and any other non-zero exit status means the revision
601 601 is bad.
602 602
603 603 .. container:: verbose
604 604
605 605 Some examples:
606 606
607 607 - start a bisection with known bad revision 34, and good revision 12::
608 608
609 609 hg bisect --bad 34
610 610 hg bisect --good 12
611 611
612 612 - advance the current bisection by marking current revision as good or
613 613 bad::
614 614
615 615 hg bisect --good
616 616 hg bisect --bad
617 617
618 618 - mark the current revision, or a known revision, to be skipped (e.g. if
619 619 that revision is not usable because of another issue)::
620 620
621 621 hg bisect --skip
622 622 hg bisect --skip 23
623 623
624 624 - skip all revisions that do not touch directories ``foo`` or ``bar``::
625 625
626 626 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
627 627
628 628 - forget the current bisection::
629 629
630 630 hg bisect --reset
631 631
632 632 - use 'make && make tests' to automatically find the first broken
633 633 revision::
634 634
635 635 hg bisect --reset
636 636 hg bisect --bad 34
637 637 hg bisect --good 12
638 638 hg bisect --command "make && make tests"
639 639
640 640 - see all changesets whose states are already known in the current
641 641 bisection::
642 642
643 643 hg log -r "bisect(pruned)"
644 644
645 645 - see the changeset currently being bisected (especially useful
646 646 if running with -U/--noupdate)::
647 647
648 648 hg log -r "bisect(current)"
649 649
650 650 - see all changesets that took part in the current bisection::
651 651
652 652 hg log -r "bisect(range)"
653 653
654 654 - you can even get a nice graph::
655 655
656 656 hg log --graph -r "bisect(range)"
657 657
658 658 See :hg:`help revsets` for more about the `bisect()` keyword.
659 659
660 660 Returns 0 on success.
661 661 """
662 662 def extendbisectrange(nodes, good):
663 663 # bisect is incomplete when it ends on a merge node and
664 664 # one of the parent was not checked.
665 665 parents = repo[nodes[0]].parents()
666 666 if len(parents) > 1:
667 667 side = good and state['bad'] or state['good']
668 668 num = len(set(i.node() for i in parents) & set(side))
669 669 if num == 1:
670 670 return parents[0].ancestor(parents[1])
671 671 return None
672 672
673 673 def print_result(nodes, good):
674 674 displayer = cmdutil.show_changeset(ui, repo, {})
675 675 if len(nodes) == 1:
676 676 # narrowed it down to a single revision
677 677 if good:
678 678 ui.write(_("The first good revision is:\n"))
679 679 else:
680 680 ui.write(_("The first bad revision is:\n"))
681 681 displayer.show(repo[nodes[0]])
682 682 extendnode = extendbisectrange(nodes, good)
683 683 if extendnode is not None:
684 684 ui.write(_('Not all ancestors of this changeset have been'
685 685 ' checked.\nUse bisect --extend to continue the '
686 686 'bisection from\nthe common ancestor, %s.\n')
687 687 % extendnode)
688 688 else:
689 689 # multiple possible revisions
690 690 if good:
691 691 ui.write(_("Due to skipped revisions, the first "
692 692 "good revision could be any of:\n"))
693 693 else:
694 694 ui.write(_("Due to skipped revisions, the first "
695 695 "bad revision could be any of:\n"))
696 696 for n in nodes:
697 697 displayer.show(repo[n])
698 698 displayer.close()
699 699
700 700 def check_state(state, interactive=True):
701 701 if not state['good'] or not state['bad']:
702 702 if (good or bad or skip or reset) and interactive:
703 703 return
704 704 if not state['good']:
705 705 raise util.Abort(_('cannot bisect (no known good revisions)'))
706 706 else:
707 707 raise util.Abort(_('cannot bisect (no known bad revisions)'))
708 708 return True
709 709
710 710 # backward compatibility
711 711 if rev in "good bad reset init".split():
712 712 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
713 713 cmd, rev, extra = rev, extra, None
714 714 if cmd == "good":
715 715 good = True
716 716 elif cmd == "bad":
717 717 bad = True
718 718 else:
719 719 reset = True
720 720 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
721 721 raise util.Abort(_('incompatible arguments'))
722 722
723 723 cmdutil.checkunfinished(repo)
724 724
725 725 if reset:
726 726 p = repo.join("bisect.state")
727 727 if os.path.exists(p):
728 728 os.unlink(p)
729 729 return
730 730
731 731 state = hbisect.load_state(repo)
732 732
733 733 if command:
734 734 changesets = 1
735 735 if noupdate:
736 736 try:
737 737 node = state['current'][0]
738 738 except LookupError:
739 739 raise util.Abort(_('current bisect revision is unknown - '
740 740 'start a new bisect to fix'))
741 741 else:
742 742 node, p2 = repo.dirstate.parents()
743 743 if p2 != nullid:
744 744 raise util.Abort(_('current bisect revision is a merge'))
745 745 try:
746 746 while changesets:
747 747 # update state
748 748 state['current'] = [node]
749 749 hbisect.save_state(repo, state)
750 750 status = ui.system(command, environ={'HG_NODE': hex(node)})
751 751 if status == 125:
752 752 transition = "skip"
753 753 elif status == 0:
754 754 transition = "good"
755 755 # status < 0 means process was killed
756 756 elif status == 127:
757 757 raise util.Abort(_("failed to execute %s") % command)
758 758 elif status < 0:
759 759 raise util.Abort(_("%s killed") % command)
760 760 else:
761 761 transition = "bad"
762 762 ctx = scmutil.revsingle(repo, rev, node)
763 763 rev = None # clear for future iterations
764 764 state[transition].append(ctx.node())
765 765 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
766 766 check_state(state, interactive=False)
767 767 # bisect
768 768 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
769 769 # update to next check
770 770 node = nodes[0]
771 771 if not noupdate:
772 772 cmdutil.bailifchanged(repo)
773 773 hg.clean(repo, node, show_stats=False)
774 774 finally:
775 775 state['current'] = [node]
776 776 hbisect.save_state(repo, state)
777 777 print_result(nodes, bgood)
778 778 return
779 779
780 780 # update state
781 781
782 782 if rev:
783 783 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
784 784 else:
785 785 nodes = [repo.lookup('.')]
786 786
787 787 if good or bad or skip:
788 788 if good:
789 789 state['good'] += nodes
790 790 elif bad:
791 791 state['bad'] += nodes
792 792 elif skip:
793 793 state['skip'] += nodes
794 794 hbisect.save_state(repo, state)
795 795
796 796 if not check_state(state):
797 797 return
798 798
799 799 # actually bisect
800 800 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
801 801 if extend:
802 802 if not changesets:
803 803 extendnode = extendbisectrange(nodes, good)
804 804 if extendnode is not None:
805 805 ui.write(_("Extending search to changeset %d:%s\n")
806 806 % (extendnode.rev(), extendnode))
807 807 state['current'] = [extendnode.node()]
808 808 hbisect.save_state(repo, state)
809 809 if noupdate:
810 810 return
811 811 cmdutil.bailifchanged(repo)
812 812 return hg.clean(repo, extendnode.node())
813 813 raise util.Abort(_("nothing to extend"))
814 814
815 815 if changesets == 0:
816 816 print_result(nodes, good)
817 817 else:
818 818 assert len(nodes) == 1 # only a single node can be tested next
819 819 node = nodes[0]
820 820 # compute the approximate number of remaining tests
821 821 tests, size = 0, 2
822 822 while size <= changesets:
823 823 tests, size = tests + 1, size * 2
824 824 rev = repo.changelog.rev(node)
825 825 ui.write(_("Testing changeset %d:%s "
826 826 "(%d changesets remaining, ~%d tests)\n")
827 827 % (rev, short(node), changesets, tests))
828 828 state['current'] = [node]
829 829 hbisect.save_state(repo, state)
830 830 if not noupdate:
831 831 cmdutil.bailifchanged(repo)
832 832 return hg.clean(repo, node)
833 833
834 834 @command('bookmarks|bookmark',
835 835 [('f', 'force', False, _('force')),
836 836 ('r', 'rev', '', _('revision'), _('REV')),
837 837 ('d', 'delete', False, _('delete a given bookmark')),
838 838 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
839 839 ('i', 'inactive', False, _('mark a bookmark inactive')),
840 840 ] + formatteropts,
841 841 _('hg bookmarks [OPTIONS]... [NAME]...'))
842 842 def bookmark(ui, repo, *names, **opts):
843 843 '''create a new bookmark or list existing bookmarks
844 844
845 845 Bookmarks are labels on changesets to help track lines of development.
846 846 Bookmarks are unversioned and can be moved, renamed and deleted.
847 847 Deleting or moving a bookmark has no effect on the associated changesets.
848 848
849 849 Creating or updating to a bookmark causes it to be marked as 'active'.
850 850 The active bookmark is indicated with a '*'.
851 851 When a commit is made, the active bookmark will advance to the new commit.
852 852 A plain :hg:`update` will also advance an active bookmark, if possible.
853 853 Updating away from a bookmark will cause it to be deactivated.
854 854
855 855 Bookmarks can be pushed and pulled between repositories (see
856 856 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
857 857 diverged, a new 'divergent bookmark' of the form 'name@path' will
858 858 be created. Using :hg:`merge` will resolve the divergence.
859 859
860 860 A bookmark named '@' has the special property that :hg:`clone` will
861 861 check it out by default if it exists.
862 862
863 863 .. container:: verbose
864 864
865 865 Examples:
866 866
867 867 - create an active bookmark for a new line of development::
868 868
869 869 hg book new-feature
870 870
871 871 - create an inactive bookmark as a place marker::
872 872
873 873 hg book -i reviewed
874 874
875 875 - create an inactive bookmark on another changeset::
876 876
877 877 hg book -r .^ tested
878 878
879 879 - move the '@' bookmark from another branch::
880 880
881 881 hg book -f @
882 882 '''
883 883 force = opts.get('force')
884 884 rev = opts.get('rev')
885 885 delete = opts.get('delete')
886 886 rename = opts.get('rename')
887 887 inactive = opts.get('inactive')
888 888
889 889 def checkformat(mark):
890 890 mark = mark.strip()
891 891 if not mark:
892 892 raise util.Abort(_("bookmark names cannot consist entirely of "
893 893 "whitespace"))
894 894 scmutil.checknewlabel(repo, mark, 'bookmark')
895 895 return mark
896 896
897 897 def checkconflict(repo, mark, cur, force=False, target=None):
898 898 if mark in marks and not force:
899 899 if target:
900 900 if marks[mark] == target and target == cur:
901 901 # re-activating a bookmark
902 902 return
903 903 anc = repo.changelog.ancestors([repo[target].rev()])
904 904 bmctx = repo[marks[mark]]
905 905 divs = [repo[b].node() for b in marks
906 906 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
907 907
908 908 # allow resolving a single divergent bookmark even if moving
909 909 # the bookmark across branches when a revision is specified
910 910 # that contains a divergent bookmark
911 911 if bmctx.rev() not in anc and target in divs:
912 912 bookmarks.deletedivergent(repo, [target], mark)
913 913 return
914 914
915 915 deletefrom = [b for b in divs
916 916 if repo[b].rev() in anc or b == target]
917 917 bookmarks.deletedivergent(repo, deletefrom, mark)
918 918 if bookmarks.validdest(repo, bmctx, repo[target]):
919 919 ui.status(_("moving bookmark '%s' forward from %s\n") %
920 920 (mark, short(bmctx.node())))
921 921 return
922 922 raise util.Abort(_("bookmark '%s' already exists "
923 923 "(use -f to force)") % mark)
924 924 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
925 925 and not force):
926 926 raise util.Abort(
927 927 _("a bookmark cannot have the name of an existing branch"))
928 928
929 929 if delete and rename:
930 930 raise util.Abort(_("--delete and --rename are incompatible"))
931 931 if delete and rev:
932 932 raise util.Abort(_("--rev is incompatible with --delete"))
933 933 if rename and rev:
934 934 raise util.Abort(_("--rev is incompatible with --rename"))
935 935 if not names and (delete or rev):
936 936 raise util.Abort(_("bookmark name required"))
937 937
938 938 if delete or rename or names or inactive:
939 939 wlock = repo.wlock()
940 940 try:
941 941 cur = repo.changectx('.').node()
942 942 marks = repo._bookmarks
943 943 if delete:
944 944 for mark in names:
945 945 if mark not in marks:
946 946 raise util.Abort(_("bookmark '%s' does not exist") %
947 947 mark)
948 948 if mark == repo._bookmarkcurrent:
949 949 bookmarks.unsetcurrent(repo)
950 950 del marks[mark]
951 951 marks.write()
952 952
953 953 elif rename:
954 954 if not names:
955 955 raise util.Abort(_("new bookmark name required"))
956 956 elif len(names) > 1:
957 957 raise util.Abort(_("only one new bookmark name allowed"))
958 958 mark = checkformat(names[0])
959 959 if rename not in marks:
960 960 raise util.Abort(_("bookmark '%s' does not exist") % rename)
961 961 checkconflict(repo, mark, cur, force)
962 962 marks[mark] = marks[rename]
963 963 if repo._bookmarkcurrent == rename and not inactive:
964 964 bookmarks.setcurrent(repo, mark)
965 965 del marks[rename]
966 966 marks.write()
967 967
968 968 elif names:
969 969 newact = None
970 970 for mark in names:
971 971 mark = checkformat(mark)
972 972 if newact is None:
973 973 newact = mark
974 974 if inactive and mark == repo._bookmarkcurrent:
975 975 bookmarks.unsetcurrent(repo)
976 976 return
977 977 tgt = cur
978 978 if rev:
979 979 tgt = scmutil.revsingle(repo, rev).node()
980 980 checkconflict(repo, mark, cur, force, tgt)
981 981 marks[mark] = tgt
982 982 if not inactive and cur == marks[newact] and not rev:
983 983 bookmarks.setcurrent(repo, newact)
984 984 elif cur != tgt and newact == repo._bookmarkcurrent:
985 985 bookmarks.unsetcurrent(repo)
986 986 marks.write()
987 987
988 988 elif inactive:
989 989 if len(marks) == 0:
990 990 ui.status(_("no bookmarks set\n"))
991 991 elif not repo._bookmarkcurrent:
992 992 ui.status(_("no active bookmark\n"))
993 993 else:
994 994 bookmarks.unsetcurrent(repo)
995 995 finally:
996 996 wlock.release()
997 997 else: # show bookmarks
998 998 fm = ui.formatter('bookmarks', opts)
999 999 hexfn = fm.hexfunc
1000 1000 marks = repo._bookmarks
1001 1001 if len(marks) == 0 and not fm:
1002 1002 ui.status(_("no bookmarks set\n"))
1003 1003 for bmark, n in sorted(marks.iteritems()):
1004 1004 current = repo._bookmarkcurrent
1005 1005 if bmark == current:
1006 1006 prefix, label = '*', 'bookmarks.current'
1007 1007 else:
1008 1008 prefix, label = ' ', ''
1009 1009
1010 1010 fm.startitem()
1011 1011 if not ui.quiet:
1012 1012 fm.plain(' %s ' % prefix, label=label)
1013 1013 fm.write('bookmark', '%s', bmark, label=label)
1014 1014 pad = " " * (25 - encoding.colwidth(bmark))
1015 1015 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1016 1016 repo.changelog.rev(n), hexfn(n), label=label)
1017 1017 fm.data(active=(bmark == current))
1018 1018 fm.plain('\n')
1019 1019 fm.end()
1020 1020
1021 1021 @command('branch',
1022 1022 [('f', 'force', None,
1023 1023 _('set branch name even if it shadows an existing branch')),
1024 1024 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1025 1025 _('[-fC] [NAME]'))
1026 1026 def branch(ui, repo, label=None, **opts):
1027 1027 """set or show the current branch name
1028 1028
1029 1029 .. note::
1030 1030
1031 1031 Branch names are permanent and global. Use :hg:`bookmark` to create a
1032 1032 light-weight bookmark instead. See :hg:`help glossary` for more
1033 1033 information about named branches and bookmarks.
1034 1034
1035 1035 With no argument, show the current branch name. With one argument,
1036 1036 set the working directory branch name (the branch will not exist
1037 1037 in the repository until the next commit). Standard practice
1038 1038 recommends that primary development take place on the 'default'
1039 1039 branch.
1040 1040
1041 1041 Unless -f/--force is specified, branch will not let you set a
1042 1042 branch name that already exists.
1043 1043
1044 1044 Use -C/--clean to reset the working directory branch to that of
1045 1045 the parent of the working directory, negating a previous branch
1046 1046 change.
1047 1047
1048 1048 Use the command :hg:`update` to switch to an existing branch. Use
1049 1049 :hg:`commit --close-branch` to mark this branch as closed.
1050 1050
1051 1051 Returns 0 on success.
1052 1052 """
1053 1053 if label:
1054 1054 label = label.strip()
1055 1055
1056 1056 if not opts.get('clean') and not label:
1057 1057 ui.write("%s\n" % repo.dirstate.branch())
1058 1058 return
1059 1059
1060 1060 wlock = repo.wlock()
1061 1061 try:
1062 1062 if opts.get('clean'):
1063 1063 label = repo[None].p1().branch()
1064 1064 repo.dirstate.setbranch(label)
1065 1065 ui.status(_('reset working directory to branch %s\n') % label)
1066 1066 elif label:
1067 1067 if not opts.get('force') and label in repo.branchmap():
1068 1068 if label not in [p.branch() for p in repo.parents()]:
1069 1069 raise util.Abort(_('a branch of the same name already'
1070 1070 ' exists'),
1071 1071 # i18n: "it" refers to an existing branch
1072 1072 hint=_("use 'hg update' to switch to it"))
1073 1073 scmutil.checknewlabel(repo, label, 'branch')
1074 1074 repo.dirstate.setbranch(label)
1075 1075 ui.status(_('marked working directory as branch %s\n') % label)
1076 1076 ui.status(_('(branches are permanent and global, '
1077 1077 'did you want a bookmark?)\n'))
1078 1078 finally:
1079 1079 wlock.release()
1080 1080
1081 1081 @command('branches',
1082 1082 [('a', 'active', False,
1083 1083 _('show only branches that have unmerged heads (DEPRECATED)')),
1084 1084 ('c', 'closed', False, _('show normal and closed branches')),
1085 1085 ] + formatteropts,
1086 1086 _('[-ac]'))
1087 1087 def branches(ui, repo, active=False, closed=False, **opts):
1088 1088 """list repository named branches
1089 1089
1090 1090 List the repository's named branches, indicating which ones are
1091 1091 inactive. If -c/--closed is specified, also list branches which have
1092 1092 been marked closed (see :hg:`commit --close-branch`).
1093 1093
1094 1094 Use the command :hg:`update` to switch to an existing branch.
1095 1095
1096 1096 Returns 0.
1097 1097 """
1098 1098
1099 1099 fm = ui.formatter('branches', opts)
1100 1100 hexfunc = fm.hexfunc
1101 1101
1102 1102 allheads = set(repo.heads())
1103 1103 branches = []
1104 1104 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1105 1105 isactive = not isclosed and bool(set(heads) & allheads)
1106 1106 branches.append((tag, repo[tip], isactive, not isclosed))
1107 1107 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1108 1108 reverse=True)
1109 1109
1110 1110 for tag, ctx, isactive, isopen in branches:
1111 1111 if active and not isactive:
1112 1112 continue
1113 1113 if isactive:
1114 1114 label = 'branches.active'
1115 1115 notice = ''
1116 1116 elif not isopen:
1117 1117 if not closed:
1118 1118 continue
1119 1119 label = 'branches.closed'
1120 1120 notice = _(' (closed)')
1121 1121 else:
1122 1122 label = 'branches.inactive'
1123 1123 notice = _(' (inactive)')
1124 1124 current = (tag == repo.dirstate.branch())
1125 1125 if current:
1126 1126 label = 'branches.current'
1127 1127
1128 1128 fm.startitem()
1129 1129 fm.write('branch', '%s', tag, label=label)
1130 1130 rev = ctx.rev()
1131 1131 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1132 1132 fmt = ' ' * padsize + ' %d:%s'
1133 1133 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1134 1134 label='log.changeset changeset.%s' % ctx.phasestr())
1135 1135 fm.data(active=isactive, closed=not isopen, current=current)
1136 1136 if not ui.quiet:
1137 1137 fm.plain(notice)
1138 1138 fm.plain('\n')
1139 1139 fm.end()
1140 1140
1141 1141 @command('bundle',
1142 1142 [('f', 'force', None, _('run even when the destination is unrelated')),
1143 1143 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1144 1144 _('REV')),
1145 1145 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1146 1146 _('BRANCH')),
1147 1147 ('', 'base', [],
1148 1148 _('a base changeset assumed to be available at the destination'),
1149 1149 _('REV')),
1150 1150 ('a', 'all', None, _('bundle all changesets in the repository')),
1151 1151 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1152 1152 ] + remoteopts,
1153 1153 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1154 1154 def bundle(ui, repo, fname, dest=None, **opts):
1155 1155 """create a changegroup file
1156 1156
1157 1157 Generate a compressed changegroup file collecting changesets not
1158 1158 known to be in another repository.
1159 1159
1160 1160 If you omit the destination repository, then hg assumes the
1161 1161 destination will have all the nodes you specify with --base
1162 1162 parameters. To create a bundle containing all changesets, use
1163 1163 -a/--all (or --base null).
1164 1164
1165 1165 You can change compression method with the -t/--type option.
1166 1166 The available compression methods are: none, bzip2, and
1167 1167 gzip (by default, bundles are compressed using bzip2).
1168 1168
1169 1169 The bundle file can then be transferred using conventional means
1170 1170 and applied to another repository with the unbundle or pull
1171 1171 command. This is useful when direct push and pull are not
1172 1172 available or when exporting an entire repository is undesirable.
1173 1173
1174 1174 Applying bundles preserves all changeset contents including
1175 1175 permissions, copy/rename information, and revision history.
1176 1176
1177 1177 Returns 0 on success, 1 if no changes found.
1178 1178 """
1179 1179 revs = None
1180 1180 if 'rev' in opts:
1181 1181 revs = scmutil.revrange(repo, opts['rev'])
1182 1182
1183 1183 bundletype = opts.get('type', 'bzip2').lower()
1184 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1184 btypes = {'none': 'HG10UN',
1185 'bzip2': 'HG10BZ',
1186 'gzip': 'HG10GZ',
1187 'bundle2': 'HG2Y'}
1185 1188 bundletype = btypes.get(bundletype)
1186 1189 if bundletype not in changegroup.bundletypes:
1187 1190 raise util.Abort(_('unknown bundle type specified with --type'))
1188 1191
1189 1192 if opts.get('all'):
1190 1193 base = ['null']
1191 1194 else:
1192 1195 base = scmutil.revrange(repo, opts.get('base'))
1193 1196 # TODO: get desired bundlecaps from command line.
1194 1197 bundlecaps = None
1195 1198 if base:
1196 1199 if dest:
1197 1200 raise util.Abort(_("--base is incompatible with specifying "
1198 1201 "a destination"))
1199 1202 common = [repo.lookup(rev) for rev in base]
1200 1203 heads = revs and map(repo.lookup, revs) or revs
1201 1204 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1202 1205 common=common, bundlecaps=bundlecaps)
1203 1206 outgoing = None
1204 1207 else:
1205 1208 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1206 1209 dest, branches = hg.parseurl(dest, opts.get('branch'))
1207 1210 other = hg.peer(repo, opts, dest)
1208 1211 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1209 1212 heads = revs and map(repo.lookup, revs) or revs
1210 1213 outgoing = discovery.findcommonoutgoing(repo, other,
1211 1214 onlyheads=heads,
1212 1215 force=opts.get('force'),
1213 1216 portable=True)
1214 1217 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1215 1218 bundlecaps)
1216 1219 if not cg:
1217 1220 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1218 1221 return 1
1219 1222
1220 1223 changegroup.writebundle(ui, cg, fname, bundletype)
1221 1224
1222 1225 @command('cat',
1223 1226 [('o', 'output', '',
1224 1227 _('print output to file with formatted name'), _('FORMAT')),
1225 1228 ('r', 'rev', '', _('print the given revision'), _('REV')),
1226 1229 ('', 'decode', None, _('apply any matching decode filter')),
1227 1230 ] + walkopts,
1228 1231 _('[OPTION]... FILE...'),
1229 1232 inferrepo=True)
1230 1233 def cat(ui, repo, file1, *pats, **opts):
1231 1234 """output the current or given revision of files
1232 1235
1233 1236 Print the specified files as they were at the given revision. If
1234 1237 no revision is given, the parent of the working directory is used.
1235 1238
1236 1239 Output may be to a file, in which case the name of the file is
1237 1240 given using a format string. The formatting rules as follows:
1238 1241
1239 1242 :``%%``: literal "%" character
1240 1243 :``%s``: basename of file being printed
1241 1244 :``%d``: dirname of file being printed, or '.' if in repository root
1242 1245 :``%p``: root-relative path name of file being printed
1243 1246 :``%H``: changeset hash (40 hexadecimal digits)
1244 1247 :``%R``: changeset revision number
1245 1248 :``%h``: short-form changeset hash (12 hexadecimal digits)
1246 1249 :``%r``: zero-padded changeset revision number
1247 1250 :``%b``: basename of the exporting repository
1248 1251
1249 1252 Returns 0 on success.
1250 1253 """
1251 1254 ctx = scmutil.revsingle(repo, opts.get('rev'))
1252 1255 m = scmutil.match(ctx, (file1,) + pats, opts)
1253 1256
1254 1257 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1255 1258
1256 1259 @command('^clone',
1257 1260 [('U', 'noupdate', None,
1258 1261 _('the clone will include an empty working copy (only a repository)')),
1259 1262 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1260 1263 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1261 1264 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1262 1265 ('', 'pull', None, _('use pull protocol to copy metadata')),
1263 1266 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1264 1267 ] + remoteopts,
1265 1268 _('[OPTION]... SOURCE [DEST]'),
1266 1269 norepo=True)
1267 1270 def clone(ui, source, dest=None, **opts):
1268 1271 """make a copy of an existing repository
1269 1272
1270 1273 Create a copy of an existing repository in a new directory.
1271 1274
1272 1275 If no destination directory name is specified, it defaults to the
1273 1276 basename of the source.
1274 1277
1275 1278 The location of the source is added to the new repository's
1276 1279 ``.hg/hgrc`` file, as the default to be used for future pulls.
1277 1280
1278 1281 Only local paths and ``ssh://`` URLs are supported as
1279 1282 destinations. For ``ssh://`` destinations, no working directory or
1280 1283 ``.hg/hgrc`` will be created on the remote side.
1281 1284
1282 1285 To pull only a subset of changesets, specify one or more revisions
1283 1286 identifiers with -r/--rev or branches with -b/--branch. The
1284 1287 resulting clone will contain only the specified changesets and
1285 1288 their ancestors. These options (or 'clone src#rev dest') imply
1286 1289 --pull, even for local source repositories. Note that specifying a
1287 1290 tag will include the tagged changeset but not the changeset
1288 1291 containing the tag.
1289 1292
1290 1293 If the source repository has a bookmark called '@' set, that
1291 1294 revision will be checked out in the new repository by default.
1292 1295
1293 1296 To check out a particular version, use -u/--update, or
1294 1297 -U/--noupdate to create a clone with no working directory.
1295 1298
1296 1299 .. container:: verbose
1297 1300
1298 1301 For efficiency, hardlinks are used for cloning whenever the
1299 1302 source and destination are on the same filesystem (note this
1300 1303 applies only to the repository data, not to the working
1301 1304 directory). Some filesystems, such as AFS, implement hardlinking
1302 1305 incorrectly, but do not report errors. In these cases, use the
1303 1306 --pull option to avoid hardlinking.
1304 1307
1305 1308 In some cases, you can clone repositories and the working
1306 1309 directory using full hardlinks with ::
1307 1310
1308 1311 $ cp -al REPO REPOCLONE
1309 1312
1310 1313 This is the fastest way to clone, but it is not always safe. The
1311 1314 operation is not atomic (making sure REPO is not modified during
1312 1315 the operation is up to you) and you have to make sure your
1313 1316 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1314 1317 so). Also, this is not compatible with certain extensions that
1315 1318 place their metadata under the .hg directory, such as mq.
1316 1319
1317 1320 Mercurial will update the working directory to the first applicable
1318 1321 revision from this list:
1319 1322
1320 1323 a) null if -U or the source repository has no changesets
1321 1324 b) if -u . and the source repository is local, the first parent of
1322 1325 the source repository's working directory
1323 1326 c) the changeset specified with -u (if a branch name, this means the
1324 1327 latest head of that branch)
1325 1328 d) the changeset specified with -r
1326 1329 e) the tipmost head specified with -b
1327 1330 f) the tipmost head specified with the url#branch source syntax
1328 1331 g) the revision marked with the '@' bookmark, if present
1329 1332 h) the tipmost head of the default branch
1330 1333 i) tip
1331 1334
1332 1335 Examples:
1333 1336
1334 1337 - clone a remote repository to a new directory named hg/::
1335 1338
1336 1339 hg clone http://selenic.com/hg
1337 1340
1338 1341 - create a lightweight local clone::
1339 1342
1340 1343 hg clone project/ project-feature/
1341 1344
1342 1345 - clone from an absolute path on an ssh server (note double-slash)::
1343 1346
1344 1347 hg clone ssh://user@server//home/projects/alpha/
1345 1348
1346 1349 - do a high-speed clone over a LAN while checking out a
1347 1350 specified version::
1348 1351
1349 1352 hg clone --uncompressed http://server/repo -u 1.5
1350 1353
1351 1354 - create a repository without changesets after a particular revision::
1352 1355
1353 1356 hg clone -r 04e544 experimental/ good/
1354 1357
1355 1358 - clone (and track) a particular named branch::
1356 1359
1357 1360 hg clone http://selenic.com/hg#stable
1358 1361
1359 1362 See :hg:`help urls` for details on specifying URLs.
1360 1363
1361 1364 Returns 0 on success.
1362 1365 """
1363 1366 if opts.get('noupdate') and opts.get('updaterev'):
1364 1367 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1365 1368
1366 1369 r = hg.clone(ui, opts, source, dest,
1367 1370 pull=opts.get('pull'),
1368 1371 stream=opts.get('uncompressed'),
1369 1372 rev=opts.get('rev'),
1370 1373 update=opts.get('updaterev') or not opts.get('noupdate'),
1371 1374 branch=opts.get('branch'))
1372 1375
1373 1376 return r is None
1374 1377
1375 1378 @command('^commit|ci',
1376 1379 [('A', 'addremove', None,
1377 1380 _('mark new/missing files as added/removed before committing')),
1378 1381 ('', 'close-branch', None,
1379 1382 _('mark a branch as closed, hiding it from the branch list')),
1380 1383 ('', 'amend', None, _('amend the parent of the working dir')),
1381 1384 ('s', 'secret', None, _('use the secret phase for committing')),
1382 1385 ('e', 'edit', None, _('invoke editor on commit messages')),
1383 1386 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1384 1387 _('[OPTION]... [FILE]...'),
1385 1388 inferrepo=True)
1386 1389 def commit(ui, repo, *pats, **opts):
1387 1390 """commit the specified files or all outstanding changes
1388 1391
1389 1392 Commit changes to the given files into the repository. Unlike a
1390 1393 centralized SCM, this operation is a local operation. See
1391 1394 :hg:`push` for a way to actively distribute your changes.
1392 1395
1393 1396 If a list of files is omitted, all changes reported by :hg:`status`
1394 1397 will be committed.
1395 1398
1396 1399 If you are committing the result of a merge, do not provide any
1397 1400 filenames or -I/-X filters.
1398 1401
1399 1402 If no commit message is specified, Mercurial starts your
1400 1403 configured editor where you can enter a message. In case your
1401 1404 commit fails, you will find a backup of your message in
1402 1405 ``.hg/last-message.txt``.
1403 1406
1404 1407 The --amend flag can be used to amend the parent of the
1405 1408 working directory with a new commit that contains the changes
1406 1409 in the parent in addition to those currently reported by :hg:`status`,
1407 1410 if there are any. The old commit is stored in a backup bundle in
1408 1411 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1409 1412 on how to restore it).
1410 1413
1411 1414 Message, user and date are taken from the amended commit unless
1412 1415 specified. When a message isn't specified on the command line,
1413 1416 the editor will open with the message of the amended commit.
1414 1417
1415 1418 It is not possible to amend public changesets (see :hg:`help phases`)
1416 1419 or changesets that have children.
1417 1420
1418 1421 See :hg:`help dates` for a list of formats valid for -d/--date.
1419 1422
1420 1423 Returns 0 on success, 1 if nothing changed.
1421 1424 """
1422 1425 if opts.get('subrepos'):
1423 1426 if opts.get('amend'):
1424 1427 raise util.Abort(_('cannot amend with --subrepos'))
1425 1428 # Let --subrepos on the command line override config setting.
1426 1429 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1427 1430
1428 1431 cmdutil.checkunfinished(repo, commit=True)
1429 1432
1430 1433 branch = repo[None].branch()
1431 1434 bheads = repo.branchheads(branch)
1432 1435
1433 1436 extra = {}
1434 1437 if opts.get('close_branch'):
1435 1438 extra['close'] = 1
1436 1439
1437 1440 if not bheads:
1438 1441 raise util.Abort(_('can only close branch heads'))
1439 1442 elif opts.get('amend'):
1440 1443 if repo.parents()[0].p1().branch() != branch and \
1441 1444 repo.parents()[0].p2().branch() != branch:
1442 1445 raise util.Abort(_('can only close branch heads'))
1443 1446
1444 1447 if opts.get('amend'):
1445 1448 if ui.configbool('ui', 'commitsubrepos'):
1446 1449 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1447 1450
1448 1451 old = repo['.']
1449 1452 if not old.mutable():
1450 1453 raise util.Abort(_('cannot amend public changesets'))
1451 1454 if len(repo[None].parents()) > 1:
1452 1455 raise util.Abort(_('cannot amend while merging'))
1453 1456 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1454 1457 if not allowunstable and old.children():
1455 1458 raise util.Abort(_('cannot amend changeset with children'))
1456 1459
1457 1460 # commitfunc is used only for temporary amend commit by cmdutil.amend
1458 1461 def commitfunc(ui, repo, message, match, opts):
1459 1462 return repo.commit(message,
1460 1463 opts.get('user') or old.user(),
1461 1464 opts.get('date') or old.date(),
1462 1465 match,
1463 1466 extra=extra)
1464 1467
1465 1468 current = repo._bookmarkcurrent
1466 1469 marks = old.bookmarks()
1467 1470 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1468 1471 if node == old.node():
1469 1472 ui.status(_("nothing changed\n"))
1470 1473 return 1
1471 1474 elif marks:
1472 1475 ui.debug('moving bookmarks %r from %s to %s\n' %
1473 1476 (marks, old.hex(), hex(node)))
1474 1477 newmarks = repo._bookmarks
1475 1478 for bm in marks:
1476 1479 newmarks[bm] = node
1477 1480 if bm == current:
1478 1481 bookmarks.setcurrent(repo, bm)
1479 1482 newmarks.write()
1480 1483 else:
1481 1484 def commitfunc(ui, repo, message, match, opts):
1482 1485 backup = ui.backupconfig('phases', 'new-commit')
1483 1486 baseui = repo.baseui
1484 1487 basebackup = baseui.backupconfig('phases', 'new-commit')
1485 1488 try:
1486 1489 if opts.get('secret'):
1487 1490 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1488 1491 # Propagate to subrepos
1489 1492 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1490 1493
1491 1494 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1492 1495 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1493 1496 return repo.commit(message, opts.get('user'), opts.get('date'),
1494 1497 match,
1495 1498 editor=editor,
1496 1499 extra=extra)
1497 1500 finally:
1498 1501 ui.restoreconfig(backup)
1499 1502 repo.baseui.restoreconfig(basebackup)
1500 1503
1501 1504
1502 1505 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1503 1506
1504 1507 if not node:
1505 1508 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1506 1509 if stat[3]:
1507 1510 ui.status(_("nothing changed (%d missing files, see "
1508 1511 "'hg status')\n") % len(stat[3]))
1509 1512 else:
1510 1513 ui.status(_("nothing changed\n"))
1511 1514 return 1
1512 1515
1513 1516 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1514 1517
1515 1518 @command('config|showconfig|debugconfig',
1516 1519 [('u', 'untrusted', None, _('show untrusted configuration options')),
1517 1520 ('e', 'edit', None, _('edit user config')),
1518 1521 ('l', 'local', None, _('edit repository config')),
1519 1522 ('g', 'global', None, _('edit global config'))],
1520 1523 _('[-u] [NAME]...'),
1521 1524 optionalrepo=True)
1522 1525 def config(ui, repo, *values, **opts):
1523 1526 """show combined config settings from all hgrc files
1524 1527
1525 1528 With no arguments, print names and values of all config items.
1526 1529
1527 1530 With one argument of the form section.name, print just the value
1528 1531 of that config item.
1529 1532
1530 1533 With multiple arguments, print names and values of all config
1531 1534 items with matching section names.
1532 1535
1533 1536 With --edit, start an editor on the user-level config file. With
1534 1537 --global, edit the system-wide config file. With --local, edit the
1535 1538 repository-level config file.
1536 1539
1537 1540 With --debug, the source (filename and line number) is printed
1538 1541 for each config item.
1539 1542
1540 1543 See :hg:`help config` for more information about config files.
1541 1544
1542 1545 Returns 0 on success, 1 if NAME does not exist.
1543 1546
1544 1547 """
1545 1548
1546 1549 if opts.get('edit') or opts.get('local') or opts.get('global'):
1547 1550 if opts.get('local') and opts.get('global'):
1548 1551 raise util.Abort(_("can't use --local and --global together"))
1549 1552
1550 1553 if opts.get('local'):
1551 1554 if not repo:
1552 1555 raise util.Abort(_("can't use --local outside a repository"))
1553 1556 paths = [repo.join('hgrc')]
1554 1557 elif opts.get('global'):
1555 1558 paths = scmutil.systemrcpath()
1556 1559 else:
1557 1560 paths = scmutil.userrcpath()
1558 1561
1559 1562 for f in paths:
1560 1563 if os.path.exists(f):
1561 1564 break
1562 1565 else:
1563 1566 if opts.get('global'):
1564 1567 samplehgrc = uimod.samplehgrcs['global']
1565 1568 elif opts.get('local'):
1566 1569 samplehgrc = uimod.samplehgrcs['local']
1567 1570 else:
1568 1571 samplehgrc = uimod.samplehgrcs['user']
1569 1572
1570 1573 f = paths[0]
1571 1574 fp = open(f, "w")
1572 1575 fp.write(samplehgrc)
1573 1576 fp.close()
1574 1577
1575 1578 editor = ui.geteditor()
1576 1579 ui.system("%s \"%s\"" % (editor, f),
1577 1580 onerr=util.Abort, errprefix=_("edit failed"))
1578 1581 return
1579 1582
1580 1583 for f in scmutil.rcpath():
1581 1584 ui.debug('read config from: %s\n' % f)
1582 1585 untrusted = bool(opts.get('untrusted'))
1583 1586 if values:
1584 1587 sections = [v for v in values if '.' not in v]
1585 1588 items = [v for v in values if '.' in v]
1586 1589 if len(items) > 1 or items and sections:
1587 1590 raise util.Abort(_('only one config item permitted'))
1588 1591 matched = False
1589 1592 for section, name, value in ui.walkconfig(untrusted=untrusted):
1590 1593 value = str(value).replace('\n', '\\n')
1591 1594 sectname = section + '.' + name
1592 1595 if values:
1593 1596 for v in values:
1594 1597 if v == section:
1595 1598 ui.debug('%s: ' %
1596 1599 ui.configsource(section, name, untrusted))
1597 1600 ui.write('%s=%s\n' % (sectname, value))
1598 1601 matched = True
1599 1602 elif v == sectname:
1600 1603 ui.debug('%s: ' %
1601 1604 ui.configsource(section, name, untrusted))
1602 1605 ui.write(value, '\n')
1603 1606 matched = True
1604 1607 else:
1605 1608 ui.debug('%s: ' %
1606 1609 ui.configsource(section, name, untrusted))
1607 1610 ui.write('%s=%s\n' % (sectname, value))
1608 1611 matched = True
1609 1612 if matched:
1610 1613 return 0
1611 1614 return 1
1612 1615
1613 1616 @command('copy|cp',
1614 1617 [('A', 'after', None, _('record a copy that has already occurred')),
1615 1618 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1616 1619 ] + walkopts + dryrunopts,
1617 1620 _('[OPTION]... [SOURCE]... DEST'))
1618 1621 def copy(ui, repo, *pats, **opts):
1619 1622 """mark files as copied for the next commit
1620 1623
1621 1624 Mark dest as having copies of source files. If dest is a
1622 1625 directory, copies are put in that directory. If dest is a file,
1623 1626 the source must be a single file.
1624 1627
1625 1628 By default, this command copies the contents of files as they
1626 1629 exist in the working directory. If invoked with -A/--after, the
1627 1630 operation is recorded, but no copying is performed.
1628 1631
1629 1632 This command takes effect with the next commit. To undo a copy
1630 1633 before that, see :hg:`revert`.
1631 1634
1632 1635 Returns 0 on success, 1 if errors are encountered.
1633 1636 """
1634 1637 wlock = repo.wlock(False)
1635 1638 try:
1636 1639 return cmdutil.copy(ui, repo, pats, opts)
1637 1640 finally:
1638 1641 wlock.release()
1639 1642
1640 1643 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1641 1644 def debugancestor(ui, repo, *args):
1642 1645 """find the ancestor revision of two revisions in a given index"""
1643 1646 if len(args) == 3:
1644 1647 index, rev1, rev2 = args
1645 1648 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1646 1649 lookup = r.lookup
1647 1650 elif len(args) == 2:
1648 1651 if not repo:
1649 1652 raise util.Abort(_("there is no Mercurial repository here "
1650 1653 "(.hg not found)"))
1651 1654 rev1, rev2 = args
1652 1655 r = repo.changelog
1653 1656 lookup = repo.lookup
1654 1657 else:
1655 1658 raise util.Abort(_('either two or three arguments required'))
1656 1659 a = r.ancestor(lookup(rev1), lookup(rev2))
1657 1660 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1658 1661
1659 1662 @command('debugbuilddag',
1660 1663 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1661 1664 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1662 1665 ('n', 'new-file', None, _('add new file at each rev'))],
1663 1666 _('[OPTION]... [TEXT]'))
1664 1667 def debugbuilddag(ui, repo, text=None,
1665 1668 mergeable_file=False,
1666 1669 overwritten_file=False,
1667 1670 new_file=False):
1668 1671 """builds a repo with a given DAG from scratch in the current empty repo
1669 1672
1670 1673 The description of the DAG is read from stdin if not given on the
1671 1674 command line.
1672 1675
1673 1676 Elements:
1674 1677
1675 1678 - "+n" is a linear run of n nodes based on the current default parent
1676 1679 - "." is a single node based on the current default parent
1677 1680 - "$" resets the default parent to null (implied at the start);
1678 1681 otherwise the default parent is always the last node created
1679 1682 - "<p" sets the default parent to the backref p
1680 1683 - "*p" is a fork at parent p, which is a backref
1681 1684 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1682 1685 - "/p2" is a merge of the preceding node and p2
1683 1686 - ":tag" defines a local tag for the preceding node
1684 1687 - "@branch" sets the named branch for subsequent nodes
1685 1688 - "#...\\n" is a comment up to the end of the line
1686 1689
1687 1690 Whitespace between the above elements is ignored.
1688 1691
1689 1692 A backref is either
1690 1693
1691 1694 - a number n, which references the node curr-n, where curr is the current
1692 1695 node, or
1693 1696 - the name of a local tag you placed earlier using ":tag", or
1694 1697 - empty to denote the default parent.
1695 1698
1696 1699 All string valued-elements are either strictly alphanumeric, or must
1697 1700 be enclosed in double quotes ("..."), with "\\" as escape character.
1698 1701 """
1699 1702
1700 1703 if text is None:
1701 1704 ui.status(_("reading DAG from stdin\n"))
1702 1705 text = ui.fin.read()
1703 1706
1704 1707 cl = repo.changelog
1705 1708 if len(cl) > 0:
1706 1709 raise util.Abort(_('repository is not empty'))
1707 1710
1708 1711 # determine number of revs in DAG
1709 1712 total = 0
1710 1713 for type, data in dagparser.parsedag(text):
1711 1714 if type == 'n':
1712 1715 total += 1
1713 1716
1714 1717 if mergeable_file:
1715 1718 linesperrev = 2
1716 1719 # make a file with k lines per rev
1717 1720 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1718 1721 initialmergedlines.append("")
1719 1722
1720 1723 tags = []
1721 1724
1722 1725 lock = tr = None
1723 1726 try:
1724 1727 lock = repo.lock()
1725 1728 tr = repo.transaction("builddag")
1726 1729
1727 1730 at = -1
1728 1731 atbranch = 'default'
1729 1732 nodeids = []
1730 1733 id = 0
1731 1734 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1732 1735 for type, data in dagparser.parsedag(text):
1733 1736 if type == 'n':
1734 1737 ui.note(('node %s\n' % str(data)))
1735 1738 id, ps = data
1736 1739
1737 1740 files = []
1738 1741 fctxs = {}
1739 1742
1740 1743 p2 = None
1741 1744 if mergeable_file:
1742 1745 fn = "mf"
1743 1746 p1 = repo[ps[0]]
1744 1747 if len(ps) > 1:
1745 1748 p2 = repo[ps[1]]
1746 1749 pa = p1.ancestor(p2)
1747 1750 base, local, other = [x[fn].data() for x in (pa, p1,
1748 1751 p2)]
1749 1752 m3 = simplemerge.Merge3Text(base, local, other)
1750 1753 ml = [l.strip() for l in m3.merge_lines()]
1751 1754 ml.append("")
1752 1755 elif at > 0:
1753 1756 ml = p1[fn].data().split("\n")
1754 1757 else:
1755 1758 ml = initialmergedlines
1756 1759 ml[id * linesperrev] += " r%i" % id
1757 1760 mergedtext = "\n".join(ml)
1758 1761 files.append(fn)
1759 1762 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1760 1763
1761 1764 if overwritten_file:
1762 1765 fn = "of"
1763 1766 files.append(fn)
1764 1767 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1765 1768
1766 1769 if new_file:
1767 1770 fn = "nf%i" % id
1768 1771 files.append(fn)
1769 1772 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1770 1773 if len(ps) > 1:
1771 1774 if not p2:
1772 1775 p2 = repo[ps[1]]
1773 1776 for fn in p2:
1774 1777 if fn.startswith("nf"):
1775 1778 files.append(fn)
1776 1779 fctxs[fn] = p2[fn]
1777 1780
1778 1781 def fctxfn(repo, cx, path):
1779 1782 return fctxs.get(path)
1780 1783
1781 1784 if len(ps) == 0 or ps[0] < 0:
1782 1785 pars = [None, None]
1783 1786 elif len(ps) == 1:
1784 1787 pars = [nodeids[ps[0]], None]
1785 1788 else:
1786 1789 pars = [nodeids[p] for p in ps]
1787 1790 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1788 1791 date=(id, 0),
1789 1792 user="debugbuilddag",
1790 1793 extra={'branch': atbranch})
1791 1794 nodeid = repo.commitctx(cx)
1792 1795 nodeids.append(nodeid)
1793 1796 at = id
1794 1797 elif type == 'l':
1795 1798 id, name = data
1796 1799 ui.note(('tag %s\n' % name))
1797 1800 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1798 1801 elif type == 'a':
1799 1802 ui.note(('branch %s\n' % data))
1800 1803 atbranch = data
1801 1804 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1802 1805 tr.close()
1803 1806
1804 1807 if tags:
1805 1808 repo.vfs.write("localtags", "".join(tags))
1806 1809 finally:
1807 1810 ui.progress(_('building'), None)
1808 1811 release(tr, lock)
1809 1812
1810 1813 @command('debugbundle',
1811 1814 [('a', 'all', None, _('show all details'))],
1812 1815 _('FILE'),
1813 1816 norepo=True)
1814 1817 def debugbundle(ui, bundlepath, all=None, **opts):
1815 1818 """lists the contents of a bundle"""
1816 1819 f = hg.openpath(ui, bundlepath)
1817 1820 try:
1818 1821 gen = exchange.readbundle(ui, f, bundlepath)
1819 1822 if isinstance(gen, bundle2.unbundle20):
1820 1823 return _debugbundle2(ui, gen, all=all, **opts)
1821 1824 if all:
1822 1825 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1823 1826
1824 1827 def showchunks(named):
1825 1828 ui.write("\n%s\n" % named)
1826 1829 chain = None
1827 1830 while True:
1828 1831 chunkdata = gen.deltachunk(chain)
1829 1832 if not chunkdata:
1830 1833 break
1831 1834 node = chunkdata['node']
1832 1835 p1 = chunkdata['p1']
1833 1836 p2 = chunkdata['p2']
1834 1837 cs = chunkdata['cs']
1835 1838 deltabase = chunkdata['deltabase']
1836 1839 delta = chunkdata['delta']
1837 1840 ui.write("%s %s %s %s %s %s\n" %
1838 1841 (hex(node), hex(p1), hex(p2),
1839 1842 hex(cs), hex(deltabase), len(delta)))
1840 1843 chain = node
1841 1844
1842 1845 chunkdata = gen.changelogheader()
1843 1846 showchunks("changelog")
1844 1847 chunkdata = gen.manifestheader()
1845 1848 showchunks("manifest")
1846 1849 while True:
1847 1850 chunkdata = gen.filelogheader()
1848 1851 if not chunkdata:
1849 1852 break
1850 1853 fname = chunkdata['filename']
1851 1854 showchunks(fname)
1852 1855 else:
1853 1856 if isinstance(gen, bundle2.unbundle20):
1854 1857 raise util.Abort(_('use debugbundle2 for this file'))
1855 1858 chunkdata = gen.changelogheader()
1856 1859 chain = None
1857 1860 while True:
1858 1861 chunkdata = gen.deltachunk(chain)
1859 1862 if not chunkdata:
1860 1863 break
1861 1864 node = chunkdata['node']
1862 1865 ui.write("%s\n" % hex(node))
1863 1866 chain = node
1864 1867 finally:
1865 1868 f.close()
1866 1869
1867 1870 def _debugbundle2(ui, gen, **opts):
1868 1871 """lists the contents of a bundle2"""
1869 1872 if not isinstance(gen, bundle2.unbundle20):
1870 1873 raise util.Abort(_('not a bundle2 file'))
1871 1874 ui.write(('Stream params: %s\n' % repr(gen.params)))
1872 1875 for part in gen.iterparts():
1873 1876 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1874 1877 if part.type == 'b2x:changegroup':
1875 1878 version = part.params.get('version', '01')
1876 1879 cg = changegroup.packermap[version][1](part, 'UN')
1877 1880 chunkdata = cg.changelogheader()
1878 1881 chain = None
1879 1882 while True:
1880 1883 chunkdata = cg.deltachunk(chain)
1881 1884 if not chunkdata:
1882 1885 break
1883 1886 node = chunkdata['node']
1884 1887 ui.write(" %s\n" % hex(node))
1885 1888 chain = node
1886 1889
1887 1890 @command('debugcheckstate', [], '')
1888 1891 def debugcheckstate(ui, repo):
1889 1892 """validate the correctness of the current dirstate"""
1890 1893 parent1, parent2 = repo.dirstate.parents()
1891 1894 m1 = repo[parent1].manifest()
1892 1895 m2 = repo[parent2].manifest()
1893 1896 errors = 0
1894 1897 for f in repo.dirstate:
1895 1898 state = repo.dirstate[f]
1896 1899 if state in "nr" and f not in m1:
1897 1900 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1898 1901 errors += 1
1899 1902 if state in "a" and f in m1:
1900 1903 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1901 1904 errors += 1
1902 1905 if state in "m" and f not in m1 and f not in m2:
1903 1906 ui.warn(_("%s in state %s, but not in either manifest\n") %
1904 1907 (f, state))
1905 1908 errors += 1
1906 1909 for f in m1:
1907 1910 state = repo.dirstate[f]
1908 1911 if state not in "nrm":
1909 1912 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1910 1913 errors += 1
1911 1914 if errors:
1912 1915 error = _(".hg/dirstate inconsistent with current parent's manifest")
1913 1916 raise util.Abort(error)
1914 1917
1915 1918 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1916 1919 def debugcommands(ui, cmd='', *args):
1917 1920 """list all available commands and options"""
1918 1921 for cmd, vals in sorted(table.iteritems()):
1919 1922 cmd = cmd.split('|')[0].strip('^')
1920 1923 opts = ', '.join([i[1] for i in vals[1]])
1921 1924 ui.write('%s: %s\n' % (cmd, opts))
1922 1925
1923 1926 @command('debugcomplete',
1924 1927 [('o', 'options', None, _('show the command options'))],
1925 1928 _('[-o] CMD'),
1926 1929 norepo=True)
1927 1930 def debugcomplete(ui, cmd='', **opts):
1928 1931 """returns the completion list associated with the given command"""
1929 1932
1930 1933 if opts.get('options'):
1931 1934 options = []
1932 1935 otables = [globalopts]
1933 1936 if cmd:
1934 1937 aliases, entry = cmdutil.findcmd(cmd, table, False)
1935 1938 otables.append(entry[1])
1936 1939 for t in otables:
1937 1940 for o in t:
1938 1941 if "(DEPRECATED)" in o[3]:
1939 1942 continue
1940 1943 if o[0]:
1941 1944 options.append('-%s' % o[0])
1942 1945 options.append('--%s' % o[1])
1943 1946 ui.write("%s\n" % "\n".join(options))
1944 1947 return
1945 1948
1946 1949 cmdlist = cmdutil.findpossible(cmd, table)
1947 1950 if ui.verbose:
1948 1951 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1949 1952 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1950 1953
1951 1954 @command('debugdag',
1952 1955 [('t', 'tags', None, _('use tags as labels')),
1953 1956 ('b', 'branches', None, _('annotate with branch names')),
1954 1957 ('', 'dots', None, _('use dots for runs')),
1955 1958 ('s', 'spaces', None, _('separate elements by spaces'))],
1956 1959 _('[OPTION]... [FILE [REV]...]'),
1957 1960 optionalrepo=True)
1958 1961 def debugdag(ui, repo, file_=None, *revs, **opts):
1959 1962 """format the changelog or an index DAG as a concise textual description
1960 1963
1961 1964 If you pass a revlog index, the revlog's DAG is emitted. If you list
1962 1965 revision numbers, they get labeled in the output as rN.
1963 1966
1964 1967 Otherwise, the changelog DAG of the current repo is emitted.
1965 1968 """
1966 1969 spaces = opts.get('spaces')
1967 1970 dots = opts.get('dots')
1968 1971 if file_:
1969 1972 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1970 1973 revs = set((int(r) for r in revs))
1971 1974 def events():
1972 1975 for r in rlog:
1973 1976 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1974 1977 if p != -1))
1975 1978 if r in revs:
1976 1979 yield 'l', (r, "r%i" % r)
1977 1980 elif repo:
1978 1981 cl = repo.changelog
1979 1982 tags = opts.get('tags')
1980 1983 branches = opts.get('branches')
1981 1984 if tags:
1982 1985 labels = {}
1983 1986 for l, n in repo.tags().items():
1984 1987 labels.setdefault(cl.rev(n), []).append(l)
1985 1988 def events():
1986 1989 b = "default"
1987 1990 for r in cl:
1988 1991 if branches:
1989 1992 newb = cl.read(cl.node(r))[5]['branch']
1990 1993 if newb != b:
1991 1994 yield 'a', newb
1992 1995 b = newb
1993 1996 yield 'n', (r, list(p for p in cl.parentrevs(r)
1994 1997 if p != -1))
1995 1998 if tags:
1996 1999 ls = labels.get(r)
1997 2000 if ls:
1998 2001 for l in ls:
1999 2002 yield 'l', (r, l)
2000 2003 else:
2001 2004 raise util.Abort(_('need repo for changelog dag'))
2002 2005
2003 2006 for line in dagparser.dagtextlines(events(),
2004 2007 addspaces=spaces,
2005 2008 wraplabels=True,
2006 2009 wrapannotations=True,
2007 2010 wrapnonlinear=dots,
2008 2011 usedots=dots,
2009 2012 maxlinewidth=70):
2010 2013 ui.write(line)
2011 2014 ui.write("\n")
2012 2015
2013 2016 @command('debugdata',
2014 2017 [('c', 'changelog', False, _('open changelog')),
2015 2018 ('m', 'manifest', False, _('open manifest'))],
2016 2019 _('-c|-m|FILE REV'))
2017 2020 def debugdata(ui, repo, file_, rev=None, **opts):
2018 2021 """dump the contents of a data file revision"""
2019 2022 if opts.get('changelog') or opts.get('manifest'):
2020 2023 file_, rev = None, file_
2021 2024 elif rev is None:
2022 2025 raise error.CommandError('debugdata', _('invalid arguments'))
2023 2026 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2024 2027 try:
2025 2028 ui.write(r.revision(r.lookup(rev)))
2026 2029 except KeyError:
2027 2030 raise util.Abort(_('invalid revision identifier %s') % rev)
2028 2031
2029 2032 @command('debugdate',
2030 2033 [('e', 'extended', None, _('try extended date formats'))],
2031 2034 _('[-e] DATE [RANGE]'),
2032 2035 norepo=True, optionalrepo=True)
2033 2036 def debugdate(ui, date, range=None, **opts):
2034 2037 """parse and display a date"""
2035 2038 if opts["extended"]:
2036 2039 d = util.parsedate(date, util.extendeddateformats)
2037 2040 else:
2038 2041 d = util.parsedate(date)
2039 2042 ui.write(("internal: %s %s\n") % d)
2040 2043 ui.write(("standard: %s\n") % util.datestr(d))
2041 2044 if range:
2042 2045 m = util.matchdate(range)
2043 2046 ui.write(("match: %s\n") % m(d[0]))
2044 2047
2045 2048 @command('debugdiscovery',
2046 2049 [('', 'old', None, _('use old-style discovery')),
2047 2050 ('', 'nonheads', None,
2048 2051 _('use old-style discovery with non-heads included')),
2049 2052 ] + remoteopts,
2050 2053 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2051 2054 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2052 2055 """runs the changeset discovery protocol in isolation"""
2053 2056 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2054 2057 opts.get('branch'))
2055 2058 remote = hg.peer(repo, opts, remoteurl)
2056 2059 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2057 2060
2058 2061 # make sure tests are repeatable
2059 2062 random.seed(12323)
2060 2063
2061 2064 def doit(localheads, remoteheads, remote=remote):
2062 2065 if opts.get('old'):
2063 2066 if localheads:
2064 2067 raise util.Abort('cannot use localheads with old style '
2065 2068 'discovery')
2066 2069 if not util.safehasattr(remote, 'branches'):
2067 2070 # enable in-client legacy support
2068 2071 remote = localrepo.locallegacypeer(remote.local())
2069 2072 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2070 2073 force=True)
2071 2074 common = set(common)
2072 2075 if not opts.get('nonheads'):
2073 2076 ui.write(("unpruned common: %s\n") %
2074 2077 " ".join(sorted(short(n) for n in common)))
2075 2078 dag = dagutil.revlogdag(repo.changelog)
2076 2079 all = dag.ancestorset(dag.internalizeall(common))
2077 2080 common = dag.externalizeall(dag.headsetofconnecteds(all))
2078 2081 else:
2079 2082 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2080 2083 common = set(common)
2081 2084 rheads = set(hds)
2082 2085 lheads = set(repo.heads())
2083 2086 ui.write(("common heads: %s\n") %
2084 2087 " ".join(sorted(short(n) for n in common)))
2085 2088 if lheads <= common:
2086 2089 ui.write(("local is subset\n"))
2087 2090 elif rheads <= common:
2088 2091 ui.write(("remote is subset\n"))
2089 2092
2090 2093 serverlogs = opts.get('serverlog')
2091 2094 if serverlogs:
2092 2095 for filename in serverlogs:
2093 2096 logfile = open(filename, 'r')
2094 2097 try:
2095 2098 line = logfile.readline()
2096 2099 while line:
2097 2100 parts = line.strip().split(';')
2098 2101 op = parts[1]
2099 2102 if op == 'cg':
2100 2103 pass
2101 2104 elif op == 'cgss':
2102 2105 doit(parts[2].split(' '), parts[3].split(' '))
2103 2106 elif op == 'unb':
2104 2107 doit(parts[3].split(' '), parts[2].split(' '))
2105 2108 line = logfile.readline()
2106 2109 finally:
2107 2110 logfile.close()
2108 2111
2109 2112 else:
2110 2113 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2111 2114 opts.get('remote_head'))
2112 2115 localrevs = opts.get('local_head')
2113 2116 doit(localrevs, remoterevs)
2114 2117
2115 2118 @command('debugfileset',
2116 2119 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2117 2120 _('[-r REV] FILESPEC'))
2118 2121 def debugfileset(ui, repo, expr, **opts):
2119 2122 '''parse and apply a fileset specification'''
2120 2123 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2121 2124 if ui.verbose:
2122 2125 tree = fileset.parse(expr)[0]
2123 2126 ui.note(tree, "\n")
2124 2127
2125 2128 for f in ctx.getfileset(expr):
2126 2129 ui.write("%s\n" % f)
2127 2130
2128 2131 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2129 2132 def debugfsinfo(ui, path="."):
2130 2133 """show information detected about current filesystem"""
2131 2134 util.writefile('.debugfsinfo', '')
2132 2135 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2133 2136 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2134 2137 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2135 2138 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2136 2139 and 'yes' or 'no'))
2137 2140 os.unlink('.debugfsinfo')
2138 2141
2139 2142 @command('debuggetbundle',
2140 2143 [('H', 'head', [], _('id of head node'), _('ID')),
2141 2144 ('C', 'common', [], _('id of common node'), _('ID')),
2142 2145 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2143 2146 _('REPO FILE [-H|-C ID]...'),
2144 2147 norepo=True)
2145 2148 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2146 2149 """retrieves a bundle from a repo
2147 2150
2148 2151 Every ID must be a full-length hex node id string. Saves the bundle to the
2149 2152 given file.
2150 2153 """
2151 2154 repo = hg.peer(ui, opts, repopath)
2152 2155 if not repo.capable('getbundle'):
2153 2156 raise util.Abort("getbundle() not supported by target repository")
2154 2157 args = {}
2155 2158 if common:
2156 2159 args['common'] = [bin(s) for s in common]
2157 2160 if head:
2158 2161 args['heads'] = [bin(s) for s in head]
2159 2162 # TODO: get desired bundlecaps from command line.
2160 2163 args['bundlecaps'] = None
2161 2164 bundle = repo.getbundle('debug', **args)
2162 2165
2163 2166 bundletype = opts.get('type', 'bzip2').lower()
2164 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2167 btypes = {'none': 'HG10UN',
2168 'bzip2': 'HG10BZ',
2169 'gzip': 'HG10GZ',
2170 'bundle2': 'HG2Y'}
2165 2171 bundletype = btypes.get(bundletype)
2166 2172 if bundletype not in changegroup.bundletypes:
2167 2173 raise util.Abort(_('unknown bundle type specified with --type'))
2168 2174 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2169 2175
2170 2176 @command('debugignore', [], '')
2171 2177 def debugignore(ui, repo, *values, **opts):
2172 2178 """display the combined ignore pattern"""
2173 2179 ignore = repo.dirstate._ignore
2174 2180 includepat = getattr(ignore, 'includepat', None)
2175 2181 if includepat is not None:
2176 2182 ui.write("%s\n" % includepat)
2177 2183 else:
2178 2184 raise util.Abort(_("no ignore patterns found"))
2179 2185
2180 2186 @command('debugindex',
2181 2187 [('c', 'changelog', False, _('open changelog')),
2182 2188 ('m', 'manifest', False, _('open manifest')),
2183 2189 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2184 2190 _('[-f FORMAT] -c|-m|FILE'),
2185 2191 optionalrepo=True)
2186 2192 def debugindex(ui, repo, file_=None, **opts):
2187 2193 """dump the contents of an index file"""
2188 2194 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2189 2195 format = opts.get('format', 0)
2190 2196 if format not in (0, 1):
2191 2197 raise util.Abort(_("unknown format %d") % format)
2192 2198
2193 2199 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2194 2200 if generaldelta:
2195 2201 basehdr = ' delta'
2196 2202 else:
2197 2203 basehdr = ' base'
2198 2204
2199 2205 if ui.debugflag:
2200 2206 shortfn = hex
2201 2207 else:
2202 2208 shortfn = short
2203 2209
2204 2210 # There might not be anything in r, so have a sane default
2205 2211 idlen = 12
2206 2212 for i in r:
2207 2213 idlen = len(shortfn(r.node(i)))
2208 2214 break
2209 2215
2210 2216 if format == 0:
2211 2217 ui.write(" rev offset length " + basehdr + " linkrev"
2212 2218 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2213 2219 elif format == 1:
2214 2220 ui.write(" rev flag offset length"
2215 2221 " size " + basehdr + " link p1 p2"
2216 2222 " %s\n" % "nodeid".rjust(idlen))
2217 2223
2218 2224 for i in r:
2219 2225 node = r.node(i)
2220 2226 if generaldelta:
2221 2227 base = r.deltaparent(i)
2222 2228 else:
2223 2229 base = r.chainbase(i)
2224 2230 if format == 0:
2225 2231 try:
2226 2232 pp = r.parents(node)
2227 2233 except Exception:
2228 2234 pp = [nullid, nullid]
2229 2235 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2230 2236 i, r.start(i), r.length(i), base, r.linkrev(i),
2231 2237 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2232 2238 elif format == 1:
2233 2239 pr = r.parentrevs(i)
2234 2240 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2235 2241 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2236 2242 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2237 2243
2238 2244 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2239 2245 def debugindexdot(ui, repo, file_):
2240 2246 """dump an index DAG as a graphviz dot file"""
2241 2247 r = None
2242 2248 if repo:
2243 2249 filelog = repo.file(file_)
2244 2250 if len(filelog):
2245 2251 r = filelog
2246 2252 if not r:
2247 2253 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2248 2254 ui.write(("digraph G {\n"))
2249 2255 for i in r:
2250 2256 node = r.node(i)
2251 2257 pp = r.parents(node)
2252 2258 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2253 2259 if pp[1] != nullid:
2254 2260 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2255 2261 ui.write("}\n")
2256 2262
2257 2263 @command('debuginstall', [], '', norepo=True)
2258 2264 def debuginstall(ui):
2259 2265 '''test Mercurial installation
2260 2266
2261 2267 Returns 0 on success.
2262 2268 '''
2263 2269
2264 2270 def writetemp(contents):
2265 2271 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2266 2272 f = os.fdopen(fd, "wb")
2267 2273 f.write(contents)
2268 2274 f.close()
2269 2275 return name
2270 2276
2271 2277 problems = 0
2272 2278
2273 2279 # encoding
2274 2280 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2275 2281 try:
2276 2282 encoding.fromlocal("test")
2277 2283 except util.Abort, inst:
2278 2284 ui.write(" %s\n" % inst)
2279 2285 ui.write(_(" (check that your locale is properly set)\n"))
2280 2286 problems += 1
2281 2287
2282 2288 # Python
2283 2289 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2284 2290 ui.status(_("checking Python version (%s)\n")
2285 2291 % ("%s.%s.%s" % sys.version_info[:3]))
2286 2292 ui.status(_("checking Python lib (%s)...\n")
2287 2293 % os.path.dirname(os.__file__))
2288 2294
2289 2295 # compiled modules
2290 2296 ui.status(_("checking installed modules (%s)...\n")
2291 2297 % os.path.dirname(__file__))
2292 2298 try:
2293 2299 import bdiff, mpatch, base85, osutil
2294 2300 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2295 2301 except Exception, inst:
2296 2302 ui.write(" %s\n" % inst)
2297 2303 ui.write(_(" One or more extensions could not be found"))
2298 2304 ui.write(_(" (check that you compiled the extensions)\n"))
2299 2305 problems += 1
2300 2306
2301 2307 # templates
2302 2308 import templater
2303 2309 p = templater.templatepaths()
2304 2310 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2305 2311 if p:
2306 2312 m = templater.templatepath("map-cmdline.default")
2307 2313 if m:
2308 2314 # template found, check if it is working
2309 2315 try:
2310 2316 templater.templater(m)
2311 2317 except Exception, inst:
2312 2318 ui.write(" %s\n" % inst)
2313 2319 p = None
2314 2320 else:
2315 2321 ui.write(_(" template 'default' not found\n"))
2316 2322 p = None
2317 2323 else:
2318 2324 ui.write(_(" no template directories found\n"))
2319 2325 if not p:
2320 2326 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2321 2327 problems += 1
2322 2328
2323 2329 # editor
2324 2330 ui.status(_("checking commit editor...\n"))
2325 2331 editor = ui.geteditor()
2326 2332 cmdpath = util.findexe(shlex.split(editor)[0])
2327 2333 if not cmdpath:
2328 2334 if editor == 'vi':
2329 2335 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2330 2336 ui.write(_(" (specify a commit editor in your configuration"
2331 2337 " file)\n"))
2332 2338 else:
2333 2339 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2334 2340 ui.write(_(" (specify a commit editor in your configuration"
2335 2341 " file)\n"))
2336 2342 problems += 1
2337 2343
2338 2344 # check username
2339 2345 ui.status(_("checking username...\n"))
2340 2346 try:
2341 2347 ui.username()
2342 2348 except util.Abort, e:
2343 2349 ui.write(" %s\n" % e)
2344 2350 ui.write(_(" (specify a username in your configuration file)\n"))
2345 2351 problems += 1
2346 2352
2347 2353 if not problems:
2348 2354 ui.status(_("no problems detected\n"))
2349 2355 else:
2350 2356 ui.write(_("%s problems detected,"
2351 2357 " please check your install!\n") % problems)
2352 2358
2353 2359 return problems
2354 2360
2355 2361 @command('debugknown', [], _('REPO ID...'), norepo=True)
2356 2362 def debugknown(ui, repopath, *ids, **opts):
2357 2363 """test whether node ids are known to a repo
2358 2364
2359 2365 Every ID must be a full-length hex node id string. Returns a list of 0s
2360 2366 and 1s indicating unknown/known.
2361 2367 """
2362 2368 repo = hg.peer(ui, opts, repopath)
2363 2369 if not repo.capable('known'):
2364 2370 raise util.Abort("known() not supported by target repository")
2365 2371 flags = repo.known([bin(s) for s in ids])
2366 2372 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2367 2373
2368 2374 @command('debuglabelcomplete', [], _('LABEL...'))
2369 2375 def debuglabelcomplete(ui, repo, *args):
2370 2376 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2371 2377 debugnamecomplete(ui, repo, *args)
2372 2378
2373 2379 @command('debugnamecomplete', [], _('NAME...'))
2374 2380 def debugnamecomplete(ui, repo, *args):
2375 2381 '''complete "names" - tags, open branch names, bookmark names'''
2376 2382
2377 2383 names = set()
2378 2384 # since we previously only listed open branches, we will handle that
2379 2385 # specially (after this for loop)
2380 2386 for name, ns in repo.names.iteritems():
2381 2387 if name != 'branches':
2382 2388 names.update(ns.listnames(repo))
2383 2389 names.update(tag for (tag, heads, tip, closed)
2384 2390 in repo.branchmap().iterbranches() if not closed)
2385 2391 completions = set()
2386 2392 if not args:
2387 2393 args = ['']
2388 2394 for a in args:
2389 2395 completions.update(n for n in names if n.startswith(a))
2390 2396 ui.write('\n'.join(sorted(completions)))
2391 2397 ui.write('\n')
2392 2398
2393 2399 @command('debuglocks',
2394 2400 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2395 2401 ('W', 'force-wlock', None,
2396 2402 _('free the working state lock (DANGEROUS)'))],
2397 2403 _('[OPTION]...'))
2398 2404 def debuglocks(ui, repo, **opts):
2399 2405 """show or modify state of locks
2400 2406
2401 2407 By default, this command will show which locks are held. This
2402 2408 includes the user and process holding the lock, the amount of time
2403 2409 the lock has been held, and the machine name where the process is
2404 2410 running if it's not local.
2405 2411
2406 2412 Locks protect the integrity of Mercurial's data, so should be
2407 2413 treated with care. System crashes or other interruptions may cause
2408 2414 locks to not be properly released, though Mercurial will usually
2409 2415 detect and remove such stale locks automatically.
2410 2416
2411 2417 However, detecting stale locks may not always be possible (for
2412 2418 instance, on a shared filesystem). Removing locks may also be
2413 2419 blocked by filesystem permissions.
2414 2420
2415 2421 Returns 0 if no locks are held.
2416 2422
2417 2423 """
2418 2424
2419 2425 if opts.get('force_lock'):
2420 2426 repo.svfs.unlink('lock')
2421 2427 if opts.get('force_wlock'):
2422 2428 repo.vfs.unlink('wlock')
2423 2429 if opts.get('force_lock') or opts.get('force_lock'):
2424 2430 return 0
2425 2431
2426 2432 now = time.time()
2427 2433 held = 0
2428 2434
2429 2435 def report(vfs, name, method):
2430 2436 # this causes stale locks to get reaped for more accurate reporting
2431 2437 try:
2432 2438 l = method(False)
2433 2439 except error.LockHeld:
2434 2440 l = None
2435 2441
2436 2442 if l:
2437 2443 l.release()
2438 2444 else:
2439 2445 try:
2440 2446 stat = repo.svfs.lstat(name)
2441 2447 age = now - stat.st_mtime
2442 2448 user = util.username(stat.st_uid)
2443 2449 locker = vfs.readlock(name)
2444 2450 if ":" in locker:
2445 2451 host, pid = locker.split(':')
2446 2452 if host == socket.gethostname():
2447 2453 locker = 'user %s, process %s' % (user, pid)
2448 2454 else:
2449 2455 locker = 'user %s, process %s, host %s' \
2450 2456 % (user, pid, host)
2451 2457 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2452 2458 return 1
2453 2459 except OSError, e:
2454 2460 if e.errno != errno.ENOENT:
2455 2461 raise
2456 2462
2457 2463 ui.write("%-6s free\n" % (name + ":"))
2458 2464 return 0
2459 2465
2460 2466 held += report(repo.svfs, "lock", repo.lock)
2461 2467 held += report(repo.vfs, "wlock", repo.wlock)
2462 2468
2463 2469 return held
2464 2470
2465 2471 @command('debugobsolete',
2466 2472 [('', 'flags', 0, _('markers flag')),
2467 2473 ('', 'record-parents', False,
2468 2474 _('record parent information for the precursor')),
2469 2475 ('r', 'rev', [], _('display markers relevant to REV')),
2470 2476 ] + commitopts2,
2471 2477 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2472 2478 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2473 2479 """create arbitrary obsolete marker
2474 2480
2475 2481 With no arguments, displays the list of obsolescence markers."""
2476 2482
2477 2483 def parsenodeid(s):
2478 2484 try:
2479 2485 # We do not use revsingle/revrange functions here to accept
2480 2486 # arbitrary node identifiers, possibly not present in the
2481 2487 # local repository.
2482 2488 n = bin(s)
2483 2489 if len(n) != len(nullid):
2484 2490 raise TypeError()
2485 2491 return n
2486 2492 except TypeError:
2487 2493 raise util.Abort('changeset references must be full hexadecimal '
2488 2494 'node identifiers')
2489 2495
2490 2496 if precursor is not None:
2491 2497 if opts['rev']:
2492 2498 raise util.Abort('cannot select revision when creating marker')
2493 2499 metadata = {}
2494 2500 metadata['user'] = opts['user'] or ui.username()
2495 2501 succs = tuple(parsenodeid(succ) for succ in successors)
2496 2502 l = repo.lock()
2497 2503 try:
2498 2504 tr = repo.transaction('debugobsolete')
2499 2505 try:
2500 2506 try:
2501 2507 date = opts.get('date')
2502 2508 if date:
2503 2509 date = util.parsedate(date)
2504 2510 else:
2505 2511 date = None
2506 2512 prec = parsenodeid(precursor)
2507 2513 parents = None
2508 2514 if opts['record_parents']:
2509 2515 if prec not in repo.unfiltered():
2510 2516 raise util.Abort('cannot used --record-parents on '
2511 2517 'unknown changesets')
2512 2518 parents = repo.unfiltered()[prec].parents()
2513 2519 parents = tuple(p.node() for p in parents)
2514 2520 repo.obsstore.create(tr, prec, succs, opts['flags'],
2515 2521 parents=parents, date=date,
2516 2522 metadata=metadata)
2517 2523 tr.close()
2518 2524 except ValueError, exc:
2519 2525 raise util.Abort(_('bad obsmarker input: %s') % exc)
2520 2526 finally:
2521 2527 tr.release()
2522 2528 finally:
2523 2529 l.release()
2524 2530 else:
2525 2531 if opts['rev']:
2526 2532 revs = scmutil.revrange(repo, opts['rev'])
2527 2533 nodes = [repo[r].node() for r in revs]
2528 2534 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2529 2535 markers.sort(key=lambda x: x._data)
2530 2536 else:
2531 2537 markers = obsolete.getmarkers(repo)
2532 2538
2533 2539 for m in markers:
2534 2540 cmdutil.showmarker(ui, m)
2535 2541
2536 2542 @command('debugpathcomplete',
2537 2543 [('f', 'full', None, _('complete an entire path')),
2538 2544 ('n', 'normal', None, _('show only normal files')),
2539 2545 ('a', 'added', None, _('show only added files')),
2540 2546 ('r', 'removed', None, _('show only removed files'))],
2541 2547 _('FILESPEC...'))
2542 2548 def debugpathcomplete(ui, repo, *specs, **opts):
2543 2549 '''complete part or all of a tracked path
2544 2550
2545 2551 This command supports shells that offer path name completion. It
2546 2552 currently completes only files already known to the dirstate.
2547 2553
2548 2554 Completion extends only to the next path segment unless
2549 2555 --full is specified, in which case entire paths are used.'''
2550 2556
2551 2557 def complete(path, acceptable):
2552 2558 dirstate = repo.dirstate
2553 2559 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2554 2560 rootdir = repo.root + os.sep
2555 2561 if spec != repo.root and not spec.startswith(rootdir):
2556 2562 return [], []
2557 2563 if os.path.isdir(spec):
2558 2564 spec += '/'
2559 2565 spec = spec[len(rootdir):]
2560 2566 fixpaths = os.sep != '/'
2561 2567 if fixpaths:
2562 2568 spec = spec.replace(os.sep, '/')
2563 2569 speclen = len(spec)
2564 2570 fullpaths = opts['full']
2565 2571 files, dirs = set(), set()
2566 2572 adddir, addfile = dirs.add, files.add
2567 2573 for f, st in dirstate.iteritems():
2568 2574 if f.startswith(spec) and st[0] in acceptable:
2569 2575 if fixpaths:
2570 2576 f = f.replace('/', os.sep)
2571 2577 if fullpaths:
2572 2578 addfile(f)
2573 2579 continue
2574 2580 s = f.find(os.sep, speclen)
2575 2581 if s >= 0:
2576 2582 adddir(f[:s])
2577 2583 else:
2578 2584 addfile(f)
2579 2585 return files, dirs
2580 2586
2581 2587 acceptable = ''
2582 2588 if opts['normal']:
2583 2589 acceptable += 'nm'
2584 2590 if opts['added']:
2585 2591 acceptable += 'a'
2586 2592 if opts['removed']:
2587 2593 acceptable += 'r'
2588 2594 cwd = repo.getcwd()
2589 2595 if not specs:
2590 2596 specs = ['.']
2591 2597
2592 2598 files, dirs = set(), set()
2593 2599 for spec in specs:
2594 2600 f, d = complete(spec, acceptable or 'nmar')
2595 2601 files.update(f)
2596 2602 dirs.update(d)
2597 2603 files.update(dirs)
2598 2604 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2599 2605 ui.write('\n')
2600 2606
2601 2607 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2602 2608 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2603 2609 '''access the pushkey key/value protocol
2604 2610
2605 2611 With two args, list the keys in the given namespace.
2606 2612
2607 2613 With five args, set a key to new if it currently is set to old.
2608 2614 Reports success or failure.
2609 2615 '''
2610 2616
2611 2617 target = hg.peer(ui, {}, repopath)
2612 2618 if keyinfo:
2613 2619 key, old, new = keyinfo
2614 2620 r = target.pushkey(namespace, key, old, new)
2615 2621 ui.status(str(r) + '\n')
2616 2622 return not r
2617 2623 else:
2618 2624 for k, v in sorted(target.listkeys(namespace).iteritems()):
2619 2625 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2620 2626 v.encode('string-escape')))
2621 2627
2622 2628 @command('debugpvec', [], _('A B'))
2623 2629 def debugpvec(ui, repo, a, b=None):
2624 2630 ca = scmutil.revsingle(repo, a)
2625 2631 cb = scmutil.revsingle(repo, b)
2626 2632 pa = pvec.ctxpvec(ca)
2627 2633 pb = pvec.ctxpvec(cb)
2628 2634 if pa == pb:
2629 2635 rel = "="
2630 2636 elif pa > pb:
2631 2637 rel = ">"
2632 2638 elif pa < pb:
2633 2639 rel = "<"
2634 2640 elif pa | pb:
2635 2641 rel = "|"
2636 2642 ui.write(_("a: %s\n") % pa)
2637 2643 ui.write(_("b: %s\n") % pb)
2638 2644 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2639 2645 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2640 2646 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2641 2647 pa.distance(pb), rel))
2642 2648
2643 2649 @command('debugrebuilddirstate|debugrebuildstate',
2644 2650 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2645 2651 _('[-r REV]'))
2646 2652 def debugrebuilddirstate(ui, repo, rev):
2647 2653 """rebuild the dirstate as it would look like for the given revision
2648 2654
2649 2655 If no revision is specified the first current parent will be used.
2650 2656
2651 2657 The dirstate will be set to the files of the given revision.
2652 2658 The actual working directory content or existing dirstate
2653 2659 information such as adds or removes is not considered.
2654 2660
2655 2661 One use of this command is to make the next :hg:`status` invocation
2656 2662 check the actual file content.
2657 2663 """
2658 2664 ctx = scmutil.revsingle(repo, rev)
2659 2665 wlock = repo.wlock()
2660 2666 try:
2661 2667 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2662 2668 finally:
2663 2669 wlock.release()
2664 2670
2665 2671 @command('debugrename',
2666 2672 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2667 2673 _('[-r REV] FILE'))
2668 2674 def debugrename(ui, repo, file1, *pats, **opts):
2669 2675 """dump rename information"""
2670 2676
2671 2677 ctx = scmutil.revsingle(repo, opts.get('rev'))
2672 2678 m = scmutil.match(ctx, (file1,) + pats, opts)
2673 2679 for abs in ctx.walk(m):
2674 2680 fctx = ctx[abs]
2675 2681 o = fctx.filelog().renamed(fctx.filenode())
2676 2682 rel = m.rel(abs)
2677 2683 if o:
2678 2684 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2679 2685 else:
2680 2686 ui.write(_("%s not renamed\n") % rel)
2681 2687
2682 2688 @command('debugrevlog',
2683 2689 [('c', 'changelog', False, _('open changelog')),
2684 2690 ('m', 'manifest', False, _('open manifest')),
2685 2691 ('d', 'dump', False, _('dump index data'))],
2686 2692 _('-c|-m|FILE'),
2687 2693 optionalrepo=True)
2688 2694 def debugrevlog(ui, repo, file_=None, **opts):
2689 2695 """show data and statistics about a revlog"""
2690 2696 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2691 2697
2692 2698 if opts.get("dump"):
2693 2699 numrevs = len(r)
2694 2700 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2695 2701 " rawsize totalsize compression heads chainlen\n")
2696 2702 ts = 0
2697 2703 heads = set()
2698 2704
2699 2705 for rev in xrange(numrevs):
2700 2706 dbase = r.deltaparent(rev)
2701 2707 if dbase == -1:
2702 2708 dbase = rev
2703 2709 cbase = r.chainbase(rev)
2704 2710 clen = r.chainlen(rev)
2705 2711 p1, p2 = r.parentrevs(rev)
2706 2712 rs = r.rawsize(rev)
2707 2713 ts = ts + rs
2708 2714 heads -= set(r.parentrevs(rev))
2709 2715 heads.add(rev)
2710 2716 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2711 2717 "%11d %5d %8d\n" %
2712 2718 (rev, p1, p2, r.start(rev), r.end(rev),
2713 2719 r.start(dbase), r.start(cbase),
2714 2720 r.start(p1), r.start(p2),
2715 2721 rs, ts, ts / r.end(rev), len(heads), clen))
2716 2722 return 0
2717 2723
2718 2724 v = r.version
2719 2725 format = v & 0xFFFF
2720 2726 flags = []
2721 2727 gdelta = False
2722 2728 if v & revlog.REVLOGNGINLINEDATA:
2723 2729 flags.append('inline')
2724 2730 if v & revlog.REVLOGGENERALDELTA:
2725 2731 gdelta = True
2726 2732 flags.append('generaldelta')
2727 2733 if not flags:
2728 2734 flags = ['(none)']
2729 2735
2730 2736 nummerges = 0
2731 2737 numfull = 0
2732 2738 numprev = 0
2733 2739 nump1 = 0
2734 2740 nump2 = 0
2735 2741 numother = 0
2736 2742 nump1prev = 0
2737 2743 nump2prev = 0
2738 2744 chainlengths = []
2739 2745
2740 2746 datasize = [None, 0, 0L]
2741 2747 fullsize = [None, 0, 0L]
2742 2748 deltasize = [None, 0, 0L]
2743 2749
2744 2750 def addsize(size, l):
2745 2751 if l[0] is None or size < l[0]:
2746 2752 l[0] = size
2747 2753 if size > l[1]:
2748 2754 l[1] = size
2749 2755 l[2] += size
2750 2756
2751 2757 numrevs = len(r)
2752 2758 for rev in xrange(numrevs):
2753 2759 p1, p2 = r.parentrevs(rev)
2754 2760 delta = r.deltaparent(rev)
2755 2761 if format > 0:
2756 2762 addsize(r.rawsize(rev), datasize)
2757 2763 if p2 != nullrev:
2758 2764 nummerges += 1
2759 2765 size = r.length(rev)
2760 2766 if delta == nullrev:
2761 2767 chainlengths.append(0)
2762 2768 numfull += 1
2763 2769 addsize(size, fullsize)
2764 2770 else:
2765 2771 chainlengths.append(chainlengths[delta] + 1)
2766 2772 addsize(size, deltasize)
2767 2773 if delta == rev - 1:
2768 2774 numprev += 1
2769 2775 if delta == p1:
2770 2776 nump1prev += 1
2771 2777 elif delta == p2:
2772 2778 nump2prev += 1
2773 2779 elif delta == p1:
2774 2780 nump1 += 1
2775 2781 elif delta == p2:
2776 2782 nump2 += 1
2777 2783 elif delta != nullrev:
2778 2784 numother += 1
2779 2785
2780 2786 # Adjust size min value for empty cases
2781 2787 for size in (datasize, fullsize, deltasize):
2782 2788 if size[0] is None:
2783 2789 size[0] = 0
2784 2790
2785 2791 numdeltas = numrevs - numfull
2786 2792 numoprev = numprev - nump1prev - nump2prev
2787 2793 totalrawsize = datasize[2]
2788 2794 datasize[2] /= numrevs
2789 2795 fulltotal = fullsize[2]
2790 2796 fullsize[2] /= numfull
2791 2797 deltatotal = deltasize[2]
2792 2798 if numrevs - numfull > 0:
2793 2799 deltasize[2] /= numrevs - numfull
2794 2800 totalsize = fulltotal + deltatotal
2795 2801 avgchainlen = sum(chainlengths) / numrevs
2796 2802 compratio = totalrawsize / totalsize
2797 2803
2798 2804 basedfmtstr = '%%%dd\n'
2799 2805 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2800 2806
2801 2807 def dfmtstr(max):
2802 2808 return basedfmtstr % len(str(max))
2803 2809 def pcfmtstr(max, padding=0):
2804 2810 return basepcfmtstr % (len(str(max)), ' ' * padding)
2805 2811
2806 2812 def pcfmt(value, total):
2807 2813 return (value, 100 * float(value) / total)
2808 2814
2809 2815 ui.write(('format : %d\n') % format)
2810 2816 ui.write(('flags : %s\n') % ', '.join(flags))
2811 2817
2812 2818 ui.write('\n')
2813 2819 fmt = pcfmtstr(totalsize)
2814 2820 fmt2 = dfmtstr(totalsize)
2815 2821 ui.write(('revisions : ') + fmt2 % numrevs)
2816 2822 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2817 2823 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2818 2824 ui.write(('revisions : ') + fmt2 % numrevs)
2819 2825 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2820 2826 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2821 2827 ui.write(('revision size : ') + fmt2 % totalsize)
2822 2828 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2823 2829 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2824 2830
2825 2831 ui.write('\n')
2826 2832 fmt = dfmtstr(max(avgchainlen, compratio))
2827 2833 ui.write(('avg chain length : ') + fmt % avgchainlen)
2828 2834 ui.write(('compression ratio : ') + fmt % compratio)
2829 2835
2830 2836 if format > 0:
2831 2837 ui.write('\n')
2832 2838 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2833 2839 % tuple(datasize))
2834 2840 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2835 2841 % tuple(fullsize))
2836 2842 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2837 2843 % tuple(deltasize))
2838 2844
2839 2845 if numdeltas > 0:
2840 2846 ui.write('\n')
2841 2847 fmt = pcfmtstr(numdeltas)
2842 2848 fmt2 = pcfmtstr(numdeltas, 4)
2843 2849 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2844 2850 if numprev > 0:
2845 2851 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2846 2852 numprev))
2847 2853 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2848 2854 numprev))
2849 2855 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2850 2856 numprev))
2851 2857 if gdelta:
2852 2858 ui.write(('deltas against p1 : ')
2853 2859 + fmt % pcfmt(nump1, numdeltas))
2854 2860 ui.write(('deltas against p2 : ')
2855 2861 + fmt % pcfmt(nump2, numdeltas))
2856 2862 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2857 2863 numdeltas))
2858 2864
2859 2865 @command('debugrevspec',
2860 2866 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2861 2867 ('REVSPEC'))
2862 2868 def debugrevspec(ui, repo, expr, **opts):
2863 2869 """parse and apply a revision specification
2864 2870
2865 2871 Use --verbose to print the parsed tree before and after aliases
2866 2872 expansion.
2867 2873 """
2868 2874 if ui.verbose:
2869 2875 tree = revset.parse(expr)[0]
2870 2876 ui.note(revset.prettyformat(tree), "\n")
2871 2877 newtree = revset.findaliases(ui, tree)
2872 2878 if newtree != tree:
2873 2879 ui.note(revset.prettyformat(newtree), "\n")
2874 2880 tree = newtree
2875 2881 newtree = revset.foldconcat(tree)
2876 2882 if newtree != tree:
2877 2883 ui.note(revset.prettyformat(newtree), "\n")
2878 2884 if opts["optimize"]:
2879 2885 weight, optimizedtree = revset.optimize(newtree, True)
2880 2886 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2881 2887 func = revset.match(ui, expr)
2882 2888 for c in func(repo, revset.spanset(repo)):
2883 2889 ui.write("%s\n" % c)
2884 2890
2885 2891 @command('debugsetparents', [], _('REV1 [REV2]'))
2886 2892 def debugsetparents(ui, repo, rev1, rev2=None):
2887 2893 """manually set the parents of the current working directory
2888 2894
2889 2895 This is useful for writing repository conversion tools, but should
2890 2896 be used with care.
2891 2897
2892 2898 Returns 0 on success.
2893 2899 """
2894 2900
2895 2901 r1 = scmutil.revsingle(repo, rev1).node()
2896 2902 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2897 2903
2898 2904 wlock = repo.wlock()
2899 2905 try:
2900 2906 repo.dirstate.beginparentchange()
2901 2907 repo.setparents(r1, r2)
2902 2908 repo.dirstate.endparentchange()
2903 2909 finally:
2904 2910 wlock.release()
2905 2911
2906 2912 @command('debugdirstate|debugstate',
2907 2913 [('', 'nodates', None, _('do not display the saved mtime')),
2908 2914 ('', 'datesort', None, _('sort by saved mtime'))],
2909 2915 _('[OPTION]...'))
2910 2916 def debugstate(ui, repo, nodates=None, datesort=None):
2911 2917 """show the contents of the current dirstate"""
2912 2918 timestr = ""
2913 2919 if datesort:
2914 2920 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2915 2921 else:
2916 2922 keyfunc = None # sort by filename
2917 2923 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2918 2924 if ent[3] == -1:
2919 2925 timestr = 'unset '
2920 2926 elif nodates:
2921 2927 timestr = 'set '
2922 2928 else:
2923 2929 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2924 2930 time.localtime(ent[3]))
2925 2931 if ent[1] & 020000:
2926 2932 mode = 'lnk'
2927 2933 else:
2928 2934 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2929 2935 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2930 2936 for f in repo.dirstate.copies():
2931 2937 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2932 2938
2933 2939 @command('debugsub',
2934 2940 [('r', 'rev', '',
2935 2941 _('revision to check'), _('REV'))],
2936 2942 _('[-r REV] [REV]'))
2937 2943 def debugsub(ui, repo, rev=None):
2938 2944 ctx = scmutil.revsingle(repo, rev, None)
2939 2945 for k, v in sorted(ctx.substate.items()):
2940 2946 ui.write(('path %s\n') % k)
2941 2947 ui.write((' source %s\n') % v[0])
2942 2948 ui.write((' revision %s\n') % v[1])
2943 2949
2944 2950 @command('debugsuccessorssets',
2945 2951 [],
2946 2952 _('[REV]'))
2947 2953 def debugsuccessorssets(ui, repo, *revs):
2948 2954 """show set of successors for revision
2949 2955
2950 2956 A successors set of changeset A is a consistent group of revisions that
2951 2957 succeed A. It contains non-obsolete changesets only.
2952 2958
2953 2959 In most cases a changeset A has a single successors set containing a single
2954 2960 successor (changeset A replaced by A').
2955 2961
2956 2962 A changeset that is made obsolete with no successors are called "pruned".
2957 2963 Such changesets have no successors sets at all.
2958 2964
2959 2965 A changeset that has been "split" will have a successors set containing
2960 2966 more than one successor.
2961 2967
2962 2968 A changeset that has been rewritten in multiple different ways is called
2963 2969 "divergent". Such changesets have multiple successor sets (each of which
2964 2970 may also be split, i.e. have multiple successors).
2965 2971
2966 2972 Results are displayed as follows::
2967 2973
2968 2974 <rev1>
2969 2975 <successors-1A>
2970 2976 <rev2>
2971 2977 <successors-2A>
2972 2978 <successors-2B1> <successors-2B2> <successors-2B3>
2973 2979
2974 2980 Here rev2 has two possible (i.e. divergent) successors sets. The first
2975 2981 holds one element, whereas the second holds three (i.e. the changeset has
2976 2982 been split).
2977 2983 """
2978 2984 # passed to successorssets caching computation from one call to another
2979 2985 cache = {}
2980 2986 ctx2str = str
2981 2987 node2str = short
2982 2988 if ui.debug():
2983 2989 def ctx2str(ctx):
2984 2990 return ctx.hex()
2985 2991 node2str = hex
2986 2992 for rev in scmutil.revrange(repo, revs):
2987 2993 ctx = repo[rev]
2988 2994 ui.write('%s\n'% ctx2str(ctx))
2989 2995 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2990 2996 if succsset:
2991 2997 ui.write(' ')
2992 2998 ui.write(node2str(succsset[0]))
2993 2999 for node in succsset[1:]:
2994 3000 ui.write(' ')
2995 3001 ui.write(node2str(node))
2996 3002 ui.write('\n')
2997 3003
2998 3004 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2999 3005 def debugwalk(ui, repo, *pats, **opts):
3000 3006 """show how files match on given patterns"""
3001 3007 m = scmutil.match(repo[None], pats, opts)
3002 3008 items = list(repo.walk(m))
3003 3009 if not items:
3004 3010 return
3005 3011 f = lambda fn: fn
3006 3012 if ui.configbool('ui', 'slash') and os.sep != '/':
3007 3013 f = lambda fn: util.normpath(fn)
3008 3014 fmt = 'f %%-%ds %%-%ds %%s' % (
3009 3015 max([len(abs) for abs in items]),
3010 3016 max([len(m.rel(abs)) for abs in items]))
3011 3017 for abs in items:
3012 3018 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3013 3019 ui.write("%s\n" % line.rstrip())
3014 3020
3015 3021 @command('debugwireargs',
3016 3022 [('', 'three', '', 'three'),
3017 3023 ('', 'four', '', 'four'),
3018 3024 ('', 'five', '', 'five'),
3019 3025 ] + remoteopts,
3020 3026 _('REPO [OPTIONS]... [ONE [TWO]]'),
3021 3027 norepo=True)
3022 3028 def debugwireargs(ui, repopath, *vals, **opts):
3023 3029 repo = hg.peer(ui, opts, repopath)
3024 3030 for opt in remoteopts:
3025 3031 del opts[opt[1]]
3026 3032 args = {}
3027 3033 for k, v in opts.iteritems():
3028 3034 if v:
3029 3035 args[k] = v
3030 3036 # run twice to check that we don't mess up the stream for the next command
3031 3037 res1 = repo.debugwireargs(*vals, **args)
3032 3038 res2 = repo.debugwireargs(*vals, **args)
3033 3039 ui.write("%s\n" % res1)
3034 3040 if res1 != res2:
3035 3041 ui.warn("%s\n" % res2)
3036 3042
3037 3043 @command('^diff',
3038 3044 [('r', 'rev', [], _('revision'), _('REV')),
3039 3045 ('c', 'change', '', _('change made by revision'), _('REV'))
3040 3046 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3041 3047 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3042 3048 inferrepo=True)
3043 3049 def diff(ui, repo, *pats, **opts):
3044 3050 """diff repository (or selected files)
3045 3051
3046 3052 Show differences between revisions for the specified files.
3047 3053
3048 3054 Differences between files are shown using the unified diff format.
3049 3055
3050 3056 .. note::
3051 3057
3052 3058 diff may generate unexpected results for merges, as it will
3053 3059 default to comparing against the working directory's first
3054 3060 parent changeset if no revisions are specified.
3055 3061
3056 3062 When two revision arguments are given, then changes are shown
3057 3063 between those revisions. If only one revision is specified then
3058 3064 that revision is compared to the working directory, and, when no
3059 3065 revisions are specified, the working directory files are compared
3060 3066 to its parent.
3061 3067
3062 3068 Alternatively you can specify -c/--change with a revision to see
3063 3069 the changes in that changeset relative to its first parent.
3064 3070
3065 3071 Without the -a/--text option, diff will avoid generating diffs of
3066 3072 files it detects as binary. With -a, diff will generate a diff
3067 3073 anyway, probably with undesirable results.
3068 3074
3069 3075 Use the -g/--git option to generate diffs in the git extended diff
3070 3076 format. For more information, read :hg:`help diffs`.
3071 3077
3072 3078 .. container:: verbose
3073 3079
3074 3080 Examples:
3075 3081
3076 3082 - compare a file in the current working directory to its parent::
3077 3083
3078 3084 hg diff foo.c
3079 3085
3080 3086 - compare two historical versions of a directory, with rename info::
3081 3087
3082 3088 hg diff --git -r 1.0:1.2 lib/
3083 3089
3084 3090 - get change stats relative to the last change on some date::
3085 3091
3086 3092 hg diff --stat -r "date('may 2')"
3087 3093
3088 3094 - diff all newly-added files that contain a keyword::
3089 3095
3090 3096 hg diff "set:added() and grep(GNU)"
3091 3097
3092 3098 - compare a revision and its parents::
3093 3099
3094 3100 hg diff -c 9353 # compare against first parent
3095 3101 hg diff -r 9353^:9353 # same using revset syntax
3096 3102 hg diff -r 9353^2:9353 # compare against the second parent
3097 3103
3098 3104 Returns 0 on success.
3099 3105 """
3100 3106
3101 3107 revs = opts.get('rev')
3102 3108 change = opts.get('change')
3103 3109 stat = opts.get('stat')
3104 3110 reverse = opts.get('reverse')
3105 3111
3106 3112 if revs and change:
3107 3113 msg = _('cannot specify --rev and --change at the same time')
3108 3114 raise util.Abort(msg)
3109 3115 elif change:
3110 3116 node2 = scmutil.revsingle(repo, change, None).node()
3111 3117 node1 = repo[node2].p1().node()
3112 3118 else:
3113 3119 node1, node2 = scmutil.revpair(repo, revs)
3114 3120
3115 3121 if reverse:
3116 3122 node1, node2 = node2, node1
3117 3123
3118 3124 diffopts = patch.diffallopts(ui, opts)
3119 3125 m = scmutil.match(repo[node2], pats, opts)
3120 3126 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3121 3127 listsubrepos=opts.get('subrepos'))
3122 3128
3123 3129 @command('^export',
3124 3130 [('o', 'output', '',
3125 3131 _('print output to file with formatted name'), _('FORMAT')),
3126 3132 ('', 'switch-parent', None, _('diff against the second parent')),
3127 3133 ('r', 'rev', [], _('revisions to export'), _('REV')),
3128 3134 ] + diffopts,
3129 3135 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3130 3136 def export(ui, repo, *changesets, **opts):
3131 3137 """dump the header and diffs for one or more changesets
3132 3138
3133 3139 Print the changeset header and diffs for one or more revisions.
3134 3140 If no revision is given, the parent of the working directory is used.
3135 3141
3136 3142 The information shown in the changeset header is: author, date,
3137 3143 branch name (if non-default), changeset hash, parent(s) and commit
3138 3144 comment.
3139 3145
3140 3146 .. note::
3141 3147
3142 3148 export may generate unexpected diff output for merge
3143 3149 changesets, as it will compare the merge changeset against its
3144 3150 first parent only.
3145 3151
3146 3152 Output may be to a file, in which case the name of the file is
3147 3153 given using a format string. The formatting rules are as follows:
3148 3154
3149 3155 :``%%``: literal "%" character
3150 3156 :``%H``: changeset hash (40 hexadecimal digits)
3151 3157 :``%N``: number of patches being generated
3152 3158 :``%R``: changeset revision number
3153 3159 :``%b``: basename of the exporting repository
3154 3160 :``%h``: short-form changeset hash (12 hexadecimal digits)
3155 3161 :``%m``: first line of the commit message (only alphanumeric characters)
3156 3162 :``%n``: zero-padded sequence number, starting at 1
3157 3163 :``%r``: zero-padded changeset revision number
3158 3164
3159 3165 Without the -a/--text option, export will avoid generating diffs
3160 3166 of files it detects as binary. With -a, export will generate a
3161 3167 diff anyway, probably with undesirable results.
3162 3168
3163 3169 Use the -g/--git option to generate diffs in the git extended diff
3164 3170 format. See :hg:`help diffs` for more information.
3165 3171
3166 3172 With the --switch-parent option, the diff will be against the
3167 3173 second parent. It can be useful to review a merge.
3168 3174
3169 3175 .. container:: verbose
3170 3176
3171 3177 Examples:
3172 3178
3173 3179 - use export and import to transplant a bugfix to the current
3174 3180 branch::
3175 3181
3176 3182 hg export -r 9353 | hg import -
3177 3183
3178 3184 - export all the changesets between two revisions to a file with
3179 3185 rename information::
3180 3186
3181 3187 hg export --git -r 123:150 > changes.txt
3182 3188
3183 3189 - split outgoing changes into a series of patches with
3184 3190 descriptive names::
3185 3191
3186 3192 hg export -r "outgoing()" -o "%n-%m.patch"
3187 3193
3188 3194 Returns 0 on success.
3189 3195 """
3190 3196 changesets += tuple(opts.get('rev', []))
3191 3197 if not changesets:
3192 3198 changesets = ['.']
3193 3199 revs = scmutil.revrange(repo, changesets)
3194 3200 if not revs:
3195 3201 raise util.Abort(_("export requires at least one changeset"))
3196 3202 if len(revs) > 1:
3197 3203 ui.note(_('exporting patches:\n'))
3198 3204 else:
3199 3205 ui.note(_('exporting patch:\n'))
3200 3206 cmdutil.export(repo, revs, template=opts.get('output'),
3201 3207 switch_parent=opts.get('switch_parent'),
3202 3208 opts=patch.diffallopts(ui, opts))
3203 3209
3204 3210 @command('files',
3205 3211 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3206 3212 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3207 3213 ] + walkopts + formatteropts,
3208 3214 _('[OPTION]... [PATTERN]...'))
3209 3215 def files(ui, repo, *pats, **opts):
3210 3216 """list tracked files
3211 3217
3212 3218 Print files under Mercurial control in the working directory or
3213 3219 specified revision whose names match the given patterns (excluding
3214 3220 removed files).
3215 3221
3216 3222 If no patterns are given to match, this command prints the names
3217 3223 of all files under Mercurial control in the working copy.
3218 3224
3219 3225 .. container:: verbose
3220 3226
3221 3227 Examples:
3222 3228
3223 3229 - list all files under the current directory::
3224 3230
3225 3231 hg files .
3226 3232
3227 3233 - shows sizes and flags for current revision::
3228 3234
3229 3235 hg files -vr .
3230 3236
3231 3237 - list all files named README::
3232 3238
3233 3239 hg files -I "**/README"
3234 3240
3235 3241 - list all binary files::
3236 3242
3237 3243 hg files "set:binary()"
3238 3244
3239 3245 - find files containing a regular expression::
3240 3246
3241 3247 hg files "set:grep('bob')"
3242 3248
3243 3249 - search tracked file contents with xargs and grep::
3244 3250
3245 3251 hg files -0 | xargs -0 grep foo
3246 3252
3247 3253 See :hg:`help patterns` and :hg:`help filesets` for more information
3248 3254 on specifying file patterns.
3249 3255
3250 3256 Returns 0 if a match is found, 1 otherwise.
3251 3257
3252 3258 """
3253 3259 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3254 3260 rev = ctx.rev()
3255 3261 ret = 1
3256 3262
3257 3263 end = '\n'
3258 3264 if opts.get('print0'):
3259 3265 end = '\0'
3260 3266 fm = ui.formatter('files', opts)
3261 3267 fmt = '%s' + end
3262 3268
3263 3269 m = scmutil.match(ctx, pats, opts)
3264 3270 ds = repo.dirstate
3265 3271 for f in ctx.matches(m):
3266 3272 if rev is None and ds[f] == 'r':
3267 3273 continue
3268 3274 fm.startitem()
3269 3275 if ui.verbose:
3270 3276 fc = ctx[f]
3271 3277 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
3272 3278 fm.data(abspath=f)
3273 3279 fm.write('path', fmt, m.rel(f))
3274 3280 ret = 0
3275 3281
3276 3282 fm.end()
3277 3283
3278 3284 return ret
3279 3285
3280 3286 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3281 3287 def forget(ui, repo, *pats, **opts):
3282 3288 """forget the specified files on the next commit
3283 3289
3284 3290 Mark the specified files so they will no longer be tracked
3285 3291 after the next commit.
3286 3292
3287 3293 This only removes files from the current branch, not from the
3288 3294 entire project history, and it does not delete them from the
3289 3295 working directory.
3290 3296
3291 3297 To undo a forget before the next commit, see :hg:`add`.
3292 3298
3293 3299 .. container:: verbose
3294 3300
3295 3301 Examples:
3296 3302
3297 3303 - forget newly-added binary files::
3298 3304
3299 3305 hg forget "set:added() and binary()"
3300 3306
3301 3307 - forget files that would be excluded by .hgignore::
3302 3308
3303 3309 hg forget "set:hgignore()"
3304 3310
3305 3311 Returns 0 on success.
3306 3312 """
3307 3313
3308 3314 if not pats:
3309 3315 raise util.Abort(_('no files specified'))
3310 3316
3311 3317 m = scmutil.match(repo[None], pats, opts)
3312 3318 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3313 3319 return rejected and 1 or 0
3314 3320
3315 3321 @command(
3316 3322 'graft',
3317 3323 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3318 3324 ('c', 'continue', False, _('resume interrupted graft')),
3319 3325 ('e', 'edit', False, _('invoke editor on commit messages')),
3320 3326 ('', 'log', None, _('append graft info to log message')),
3321 3327 ('f', 'force', False, _('force graft')),
3322 3328 ('D', 'currentdate', False,
3323 3329 _('record the current date as commit date')),
3324 3330 ('U', 'currentuser', False,
3325 3331 _('record the current user as committer'), _('DATE'))]
3326 3332 + commitopts2 + mergetoolopts + dryrunopts,
3327 3333 _('[OPTION]... [-r] REV...'))
3328 3334 def graft(ui, repo, *revs, **opts):
3329 3335 '''copy changes from other branches onto the current branch
3330 3336
3331 3337 This command uses Mercurial's merge logic to copy individual
3332 3338 changes from other branches without merging branches in the
3333 3339 history graph. This is sometimes known as 'backporting' or
3334 3340 'cherry-picking'. By default, graft will copy user, date, and
3335 3341 description from the source changesets.
3336 3342
3337 3343 Changesets that are ancestors of the current revision, that have
3338 3344 already been grafted, or that are merges will be skipped.
3339 3345
3340 3346 If --log is specified, log messages will have a comment appended
3341 3347 of the form::
3342 3348
3343 3349 (grafted from CHANGESETHASH)
3344 3350
3345 3351 If --force is specified, revisions will be grafted even if they
3346 3352 are already ancestors of or have been grafted to the destination.
3347 3353 This is useful when the revisions have since been backed out.
3348 3354
3349 3355 If a graft merge results in conflicts, the graft process is
3350 3356 interrupted so that the current merge can be manually resolved.
3351 3357 Once all conflicts are addressed, the graft process can be
3352 3358 continued with the -c/--continue option.
3353 3359
3354 3360 .. note::
3355 3361
3356 3362 The -c/--continue option does not reapply earlier options, except
3357 3363 for --force.
3358 3364
3359 3365 .. container:: verbose
3360 3366
3361 3367 Examples:
3362 3368
3363 3369 - copy a single change to the stable branch and edit its description::
3364 3370
3365 3371 hg update stable
3366 3372 hg graft --edit 9393
3367 3373
3368 3374 - graft a range of changesets with one exception, updating dates::
3369 3375
3370 3376 hg graft -D "2085::2093 and not 2091"
3371 3377
3372 3378 - continue a graft after resolving conflicts::
3373 3379
3374 3380 hg graft -c
3375 3381
3376 3382 - show the source of a grafted changeset::
3377 3383
3378 3384 hg log --debug -r .
3379 3385
3380 3386 See :hg:`help revisions` and :hg:`help revsets` for more about
3381 3387 specifying revisions.
3382 3388
3383 3389 Returns 0 on successful completion.
3384 3390 '''
3385 3391
3386 3392 revs = list(revs)
3387 3393 revs.extend(opts['rev'])
3388 3394
3389 3395 if not opts.get('user') and opts.get('currentuser'):
3390 3396 opts['user'] = ui.username()
3391 3397 if not opts.get('date') and opts.get('currentdate'):
3392 3398 opts['date'] = "%d %d" % util.makedate()
3393 3399
3394 3400 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3395 3401
3396 3402 cont = False
3397 3403 if opts['continue']:
3398 3404 cont = True
3399 3405 if revs:
3400 3406 raise util.Abort(_("can't specify --continue and revisions"))
3401 3407 # read in unfinished revisions
3402 3408 try:
3403 3409 nodes = repo.vfs.read('graftstate').splitlines()
3404 3410 revs = [repo[node].rev() for node in nodes]
3405 3411 except IOError, inst:
3406 3412 if inst.errno != errno.ENOENT:
3407 3413 raise
3408 3414 raise util.Abort(_("no graft state found, can't continue"))
3409 3415 else:
3410 3416 cmdutil.checkunfinished(repo)
3411 3417 cmdutil.bailifchanged(repo)
3412 3418 if not revs:
3413 3419 raise util.Abort(_('no revisions specified'))
3414 3420 revs = scmutil.revrange(repo, revs)
3415 3421
3416 3422 skipped = set()
3417 3423 # check for merges
3418 3424 for rev in repo.revs('%ld and merge()', revs):
3419 3425 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3420 3426 skipped.add(rev)
3421 3427 revs = [r for r in revs if r not in skipped]
3422 3428 if not revs:
3423 3429 return -1
3424 3430
3425 3431 # Don't check in the --continue case, in effect retaining --force across
3426 3432 # --continues. That's because without --force, any revisions we decided to
3427 3433 # skip would have been filtered out here, so they wouldn't have made their
3428 3434 # way to the graftstate. With --force, any revisions we would have otherwise
3429 3435 # skipped would not have been filtered out, and if they hadn't been applied
3430 3436 # already, they'd have been in the graftstate.
3431 3437 if not (cont or opts.get('force')):
3432 3438 # check for ancestors of dest branch
3433 3439 crev = repo['.'].rev()
3434 3440 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3435 3441 # Cannot use x.remove(y) on smart set, this has to be a list.
3436 3442 # XXX make this lazy in the future
3437 3443 revs = list(revs)
3438 3444 # don't mutate while iterating, create a copy
3439 3445 for rev in list(revs):
3440 3446 if rev in ancestors:
3441 3447 ui.warn(_('skipping ancestor revision %d:%s\n') %
3442 3448 (rev, repo[rev]))
3443 3449 # XXX remove on list is slow
3444 3450 revs.remove(rev)
3445 3451 if not revs:
3446 3452 return -1
3447 3453
3448 3454 # analyze revs for earlier grafts
3449 3455 ids = {}
3450 3456 for ctx in repo.set("%ld", revs):
3451 3457 ids[ctx.hex()] = ctx.rev()
3452 3458 n = ctx.extra().get('source')
3453 3459 if n:
3454 3460 ids[n] = ctx.rev()
3455 3461
3456 3462 # check ancestors for earlier grafts
3457 3463 ui.debug('scanning for duplicate grafts\n')
3458 3464
3459 3465 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3460 3466 ctx = repo[rev]
3461 3467 n = ctx.extra().get('source')
3462 3468 if n in ids:
3463 3469 try:
3464 3470 r = repo[n].rev()
3465 3471 except error.RepoLookupError:
3466 3472 r = None
3467 3473 if r in revs:
3468 3474 ui.warn(_('skipping revision %d:%s '
3469 3475 '(already grafted to %d:%s)\n')
3470 3476 % (r, repo[r], rev, ctx))
3471 3477 revs.remove(r)
3472 3478 elif ids[n] in revs:
3473 3479 if r is None:
3474 3480 ui.warn(_('skipping already grafted revision %d:%s '
3475 3481 '(%d:%s also has unknown origin %s)\n')
3476 3482 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3477 3483 else:
3478 3484 ui.warn(_('skipping already grafted revision %d:%s '
3479 3485 '(%d:%s also has origin %d:%s)\n')
3480 3486 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3481 3487 revs.remove(ids[n])
3482 3488 elif ctx.hex() in ids:
3483 3489 r = ids[ctx.hex()]
3484 3490 ui.warn(_('skipping already grafted revision %d:%s '
3485 3491 '(was grafted from %d:%s)\n') %
3486 3492 (r, repo[r], rev, ctx))
3487 3493 revs.remove(r)
3488 3494 if not revs:
3489 3495 return -1
3490 3496
3491 3497 wlock = repo.wlock()
3492 3498 try:
3493 3499 for pos, ctx in enumerate(repo.set("%ld", revs)):
3494 3500 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3495 3501 ctx.description().split('\n', 1)[0])
3496 3502 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3497 3503 if names:
3498 3504 desc += ' (%s)' % ' '.join(names)
3499 3505 ui.status(_('grafting %s\n') % desc)
3500 3506 if opts.get('dry_run'):
3501 3507 continue
3502 3508
3503 3509 source = ctx.extra().get('source')
3504 3510 if not source:
3505 3511 source = ctx.hex()
3506 3512 extra = {'source': source}
3507 3513 user = ctx.user()
3508 3514 if opts.get('user'):
3509 3515 user = opts['user']
3510 3516 date = ctx.date()
3511 3517 if opts.get('date'):
3512 3518 date = opts['date']
3513 3519 message = ctx.description()
3514 3520 if opts.get('log'):
3515 3521 message += '\n(grafted from %s)' % ctx.hex()
3516 3522
3517 3523 # we don't merge the first commit when continuing
3518 3524 if not cont:
3519 3525 # perform the graft merge with p1(rev) as 'ancestor'
3520 3526 try:
3521 3527 # ui.forcemerge is an internal variable, do not document
3522 3528 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3523 3529 'graft')
3524 3530 stats = mergemod.graft(repo, ctx, ctx.p1(),
3525 3531 ['local', 'graft'])
3526 3532 finally:
3527 3533 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3528 3534 # report any conflicts
3529 3535 if stats and stats[3] > 0:
3530 3536 # write out state for --continue
3531 3537 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3532 3538 repo.vfs.write('graftstate', ''.join(nodelines))
3533 3539 raise util.Abort(
3534 3540 _("unresolved conflicts, can't continue"),
3535 3541 hint=_('use hg resolve and hg graft --continue'))
3536 3542 else:
3537 3543 cont = False
3538 3544
3539 3545 # commit
3540 3546 node = repo.commit(text=message, user=user,
3541 3547 date=date, extra=extra, editor=editor)
3542 3548 if node is None:
3543 3549 ui.warn(
3544 3550 _('note: graft of %d:%s created no changes to commit\n') %
3545 3551 (ctx.rev(), ctx))
3546 3552 finally:
3547 3553 wlock.release()
3548 3554
3549 3555 # remove state when we complete successfully
3550 3556 if not opts.get('dry_run'):
3551 3557 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3552 3558
3553 3559 return 0
3554 3560
3555 3561 @command('grep',
3556 3562 [('0', 'print0', None, _('end fields with NUL')),
3557 3563 ('', 'all', None, _('print all revisions that match')),
3558 3564 ('a', 'text', None, _('treat all files as text')),
3559 3565 ('f', 'follow', None,
3560 3566 _('follow changeset history,'
3561 3567 ' or file history across copies and renames')),
3562 3568 ('i', 'ignore-case', None, _('ignore case when matching')),
3563 3569 ('l', 'files-with-matches', None,
3564 3570 _('print only filenames and revisions that match')),
3565 3571 ('n', 'line-number', None, _('print matching line numbers')),
3566 3572 ('r', 'rev', [],
3567 3573 _('only search files changed within revision range'), _('REV')),
3568 3574 ('u', 'user', None, _('list the author (long with -v)')),
3569 3575 ('d', 'date', None, _('list the date (short with -q)')),
3570 3576 ] + walkopts,
3571 3577 _('[OPTION]... PATTERN [FILE]...'),
3572 3578 inferrepo=True)
3573 3579 def grep(ui, repo, pattern, *pats, **opts):
3574 3580 """search for a pattern in specified files and revisions
3575 3581
3576 3582 Search revisions of files for a regular expression.
3577 3583
3578 3584 This command behaves differently than Unix grep. It only accepts
3579 3585 Python/Perl regexps. It searches repository history, not the
3580 3586 working directory. It always prints the revision number in which a
3581 3587 match appears.
3582 3588
3583 3589 By default, grep only prints output for the first revision of a
3584 3590 file in which it finds a match. To get it to print every revision
3585 3591 that contains a change in match status ("-" for a match that
3586 3592 becomes a non-match, or "+" for a non-match that becomes a match),
3587 3593 use the --all flag.
3588 3594
3589 3595 Returns 0 if a match is found, 1 otherwise.
3590 3596 """
3591 3597 reflags = re.M
3592 3598 if opts.get('ignore_case'):
3593 3599 reflags |= re.I
3594 3600 try:
3595 3601 regexp = util.re.compile(pattern, reflags)
3596 3602 except re.error, inst:
3597 3603 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3598 3604 return 1
3599 3605 sep, eol = ':', '\n'
3600 3606 if opts.get('print0'):
3601 3607 sep = eol = '\0'
3602 3608
3603 3609 getfile = util.lrucachefunc(repo.file)
3604 3610
3605 3611 def matchlines(body):
3606 3612 begin = 0
3607 3613 linenum = 0
3608 3614 while begin < len(body):
3609 3615 match = regexp.search(body, begin)
3610 3616 if not match:
3611 3617 break
3612 3618 mstart, mend = match.span()
3613 3619 linenum += body.count('\n', begin, mstart) + 1
3614 3620 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3615 3621 begin = body.find('\n', mend) + 1 or len(body) + 1
3616 3622 lend = begin - 1
3617 3623 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3618 3624
3619 3625 class linestate(object):
3620 3626 def __init__(self, line, linenum, colstart, colend):
3621 3627 self.line = line
3622 3628 self.linenum = linenum
3623 3629 self.colstart = colstart
3624 3630 self.colend = colend
3625 3631
3626 3632 def __hash__(self):
3627 3633 return hash((self.linenum, self.line))
3628 3634
3629 3635 def __eq__(self, other):
3630 3636 return self.line == other.line
3631 3637
3632 3638 def __iter__(self):
3633 3639 yield (self.line[:self.colstart], '')
3634 3640 yield (self.line[self.colstart:self.colend], 'grep.match')
3635 3641 rest = self.line[self.colend:]
3636 3642 while rest != '':
3637 3643 match = regexp.search(rest)
3638 3644 if not match:
3639 3645 yield (rest, '')
3640 3646 break
3641 3647 mstart, mend = match.span()
3642 3648 yield (rest[:mstart], '')
3643 3649 yield (rest[mstart:mend], 'grep.match')
3644 3650 rest = rest[mend:]
3645 3651
3646 3652 matches = {}
3647 3653 copies = {}
3648 3654 def grepbody(fn, rev, body):
3649 3655 matches[rev].setdefault(fn, [])
3650 3656 m = matches[rev][fn]
3651 3657 for lnum, cstart, cend, line in matchlines(body):
3652 3658 s = linestate(line, lnum, cstart, cend)
3653 3659 m.append(s)
3654 3660
3655 3661 def difflinestates(a, b):
3656 3662 sm = difflib.SequenceMatcher(None, a, b)
3657 3663 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3658 3664 if tag == 'insert':
3659 3665 for i in xrange(blo, bhi):
3660 3666 yield ('+', b[i])
3661 3667 elif tag == 'delete':
3662 3668 for i in xrange(alo, ahi):
3663 3669 yield ('-', a[i])
3664 3670 elif tag == 'replace':
3665 3671 for i in xrange(alo, ahi):
3666 3672 yield ('-', a[i])
3667 3673 for i in xrange(blo, bhi):
3668 3674 yield ('+', b[i])
3669 3675
3670 3676 def display(fn, ctx, pstates, states):
3671 3677 rev = ctx.rev()
3672 3678 datefunc = ui.quiet and util.shortdate or util.datestr
3673 3679 found = False
3674 3680 @util.cachefunc
3675 3681 def binary():
3676 3682 flog = getfile(fn)
3677 3683 return util.binary(flog.read(ctx.filenode(fn)))
3678 3684
3679 3685 if opts.get('all'):
3680 3686 iter = difflinestates(pstates, states)
3681 3687 else:
3682 3688 iter = [('', l) for l in states]
3683 3689 for change, l in iter:
3684 3690 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3685 3691
3686 3692 if opts.get('line_number'):
3687 3693 cols.append((str(l.linenum), 'grep.linenumber'))
3688 3694 if opts.get('all'):
3689 3695 cols.append((change, 'grep.change'))
3690 3696 if opts.get('user'):
3691 3697 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3692 3698 if opts.get('date'):
3693 3699 cols.append((datefunc(ctx.date()), 'grep.date'))
3694 3700 for col, label in cols[:-1]:
3695 3701 ui.write(col, label=label)
3696 3702 ui.write(sep, label='grep.sep')
3697 3703 ui.write(cols[-1][0], label=cols[-1][1])
3698 3704 if not opts.get('files_with_matches'):
3699 3705 ui.write(sep, label='grep.sep')
3700 3706 if not opts.get('text') and binary():
3701 3707 ui.write(" Binary file matches")
3702 3708 else:
3703 3709 for s, label in l:
3704 3710 ui.write(s, label=label)
3705 3711 ui.write(eol)
3706 3712 found = True
3707 3713 if opts.get('files_with_matches'):
3708 3714 break
3709 3715 return found
3710 3716
3711 3717 skip = {}
3712 3718 revfiles = {}
3713 3719 matchfn = scmutil.match(repo[None], pats, opts)
3714 3720 found = False
3715 3721 follow = opts.get('follow')
3716 3722
3717 3723 def prep(ctx, fns):
3718 3724 rev = ctx.rev()
3719 3725 pctx = ctx.p1()
3720 3726 parent = pctx.rev()
3721 3727 matches.setdefault(rev, {})
3722 3728 matches.setdefault(parent, {})
3723 3729 files = revfiles.setdefault(rev, [])
3724 3730 for fn in fns:
3725 3731 flog = getfile(fn)
3726 3732 try:
3727 3733 fnode = ctx.filenode(fn)
3728 3734 except error.LookupError:
3729 3735 continue
3730 3736
3731 3737 copied = flog.renamed(fnode)
3732 3738 copy = follow and copied and copied[0]
3733 3739 if copy:
3734 3740 copies.setdefault(rev, {})[fn] = copy
3735 3741 if fn in skip:
3736 3742 if copy:
3737 3743 skip[copy] = True
3738 3744 continue
3739 3745 files.append(fn)
3740 3746
3741 3747 if fn not in matches[rev]:
3742 3748 grepbody(fn, rev, flog.read(fnode))
3743 3749
3744 3750 pfn = copy or fn
3745 3751 if pfn not in matches[parent]:
3746 3752 try:
3747 3753 fnode = pctx.filenode(pfn)
3748 3754 grepbody(pfn, parent, flog.read(fnode))
3749 3755 except error.LookupError:
3750 3756 pass
3751 3757
3752 3758 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3753 3759 rev = ctx.rev()
3754 3760 parent = ctx.p1().rev()
3755 3761 for fn in sorted(revfiles.get(rev, [])):
3756 3762 states = matches[rev][fn]
3757 3763 copy = copies.get(rev, {}).get(fn)
3758 3764 if fn in skip:
3759 3765 if copy:
3760 3766 skip[copy] = True
3761 3767 continue
3762 3768 pstates = matches.get(parent, {}).get(copy or fn, [])
3763 3769 if pstates or states:
3764 3770 r = display(fn, ctx, pstates, states)
3765 3771 found = found or r
3766 3772 if r and not opts.get('all'):
3767 3773 skip[fn] = True
3768 3774 if copy:
3769 3775 skip[copy] = True
3770 3776 del matches[rev]
3771 3777 del revfiles[rev]
3772 3778
3773 3779 return not found
3774 3780
3775 3781 @command('heads',
3776 3782 [('r', 'rev', '',
3777 3783 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3778 3784 ('t', 'topo', False, _('show topological heads only')),
3779 3785 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3780 3786 ('c', 'closed', False, _('show normal and closed branch heads')),
3781 3787 ] + templateopts,
3782 3788 _('[-ct] [-r STARTREV] [REV]...'))
3783 3789 def heads(ui, repo, *branchrevs, **opts):
3784 3790 """show branch heads
3785 3791
3786 3792 With no arguments, show all open branch heads in the repository.
3787 3793 Branch heads are changesets that have no descendants on the
3788 3794 same branch. They are where development generally takes place and
3789 3795 are the usual targets for update and merge operations.
3790 3796
3791 3797 If one or more REVs are given, only open branch heads on the
3792 3798 branches associated with the specified changesets are shown. This
3793 3799 means that you can use :hg:`heads .` to see the heads on the
3794 3800 currently checked-out branch.
3795 3801
3796 3802 If -c/--closed is specified, also show branch heads marked closed
3797 3803 (see :hg:`commit --close-branch`).
3798 3804
3799 3805 If STARTREV is specified, only those heads that are descendants of
3800 3806 STARTREV will be displayed.
3801 3807
3802 3808 If -t/--topo is specified, named branch mechanics will be ignored and only
3803 3809 topological heads (changesets with no children) will be shown.
3804 3810
3805 3811 Returns 0 if matching heads are found, 1 if not.
3806 3812 """
3807 3813
3808 3814 start = None
3809 3815 if 'rev' in opts:
3810 3816 start = scmutil.revsingle(repo, opts['rev'], None).node()
3811 3817
3812 3818 if opts.get('topo'):
3813 3819 heads = [repo[h] for h in repo.heads(start)]
3814 3820 else:
3815 3821 heads = []
3816 3822 for branch in repo.branchmap():
3817 3823 heads += repo.branchheads(branch, start, opts.get('closed'))
3818 3824 heads = [repo[h] for h in heads]
3819 3825
3820 3826 if branchrevs:
3821 3827 branches = set(repo[br].branch() for br in branchrevs)
3822 3828 heads = [h for h in heads if h.branch() in branches]
3823 3829
3824 3830 if opts.get('active') and branchrevs:
3825 3831 dagheads = repo.heads(start)
3826 3832 heads = [h for h in heads if h.node() in dagheads]
3827 3833
3828 3834 if branchrevs:
3829 3835 haveheads = set(h.branch() for h in heads)
3830 3836 if branches - haveheads:
3831 3837 headless = ', '.join(b for b in branches - haveheads)
3832 3838 msg = _('no open branch heads found on branches %s')
3833 3839 if opts.get('rev'):
3834 3840 msg += _(' (started at %s)') % opts['rev']
3835 3841 ui.warn((msg + '\n') % headless)
3836 3842
3837 3843 if not heads:
3838 3844 return 1
3839 3845
3840 3846 heads = sorted(heads, key=lambda x: -x.rev())
3841 3847 displayer = cmdutil.show_changeset(ui, repo, opts)
3842 3848 for ctx in heads:
3843 3849 displayer.show(ctx)
3844 3850 displayer.close()
3845 3851
3846 3852 @command('help',
3847 3853 [('e', 'extension', None, _('show only help for extensions')),
3848 3854 ('c', 'command', None, _('show only help for commands')),
3849 3855 ('k', 'keyword', '', _('show topics matching keyword')),
3850 3856 ],
3851 3857 _('[-ec] [TOPIC]'),
3852 3858 norepo=True)
3853 3859 def help_(ui, name=None, **opts):
3854 3860 """show help for a given topic or a help overview
3855 3861
3856 3862 With no arguments, print a list of commands with short help messages.
3857 3863
3858 3864 Given a topic, extension, or command name, print help for that
3859 3865 topic.
3860 3866
3861 3867 Returns 0 if successful.
3862 3868 """
3863 3869
3864 3870 textwidth = min(ui.termwidth(), 80) - 2
3865 3871
3866 3872 keep = []
3867 3873 if ui.verbose:
3868 3874 keep.append('verbose')
3869 3875 if sys.platform.startswith('win'):
3870 3876 keep.append('windows')
3871 3877 elif sys.platform == 'OpenVMS':
3872 3878 keep.append('vms')
3873 3879 elif sys.platform == 'plan9':
3874 3880 keep.append('plan9')
3875 3881 else:
3876 3882 keep.append('unix')
3877 3883 keep.append(sys.platform.lower())
3878 3884
3879 3885 section = None
3880 3886 if name and '.' in name:
3881 3887 name, section = name.split('.', 1)
3882 3888
3883 3889 text = help.help_(ui, name, **opts)
3884 3890
3885 3891 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3886 3892 section=section)
3887 3893 if section and not formatted:
3888 3894 raise util.Abort(_("help section not found"))
3889 3895
3890 3896 if 'verbose' in pruned:
3891 3897 keep.append('omitted')
3892 3898 else:
3893 3899 keep.append('notomitted')
3894 3900 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3895 3901 section=section)
3896 3902 ui.write(formatted)
3897 3903
3898 3904
3899 3905 @command('identify|id',
3900 3906 [('r', 'rev', '',
3901 3907 _('identify the specified revision'), _('REV')),
3902 3908 ('n', 'num', None, _('show local revision number')),
3903 3909 ('i', 'id', None, _('show global revision id')),
3904 3910 ('b', 'branch', None, _('show branch')),
3905 3911 ('t', 'tags', None, _('show tags')),
3906 3912 ('B', 'bookmarks', None, _('show bookmarks')),
3907 3913 ] + remoteopts,
3908 3914 _('[-nibtB] [-r REV] [SOURCE]'),
3909 3915 optionalrepo=True)
3910 3916 def identify(ui, repo, source=None, rev=None,
3911 3917 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3912 3918 """identify the working copy or specified revision
3913 3919
3914 3920 Print a summary identifying the repository state at REV using one or
3915 3921 two parent hash identifiers, followed by a "+" if the working
3916 3922 directory has uncommitted changes, the branch name (if not default),
3917 3923 a list of tags, and a list of bookmarks.
3918 3924
3919 3925 When REV is not given, print a summary of the current state of the
3920 3926 repository.
3921 3927
3922 3928 Specifying a path to a repository root or Mercurial bundle will
3923 3929 cause lookup to operate on that repository/bundle.
3924 3930
3925 3931 .. container:: verbose
3926 3932
3927 3933 Examples:
3928 3934
3929 3935 - generate a build identifier for the working directory::
3930 3936
3931 3937 hg id --id > build-id.dat
3932 3938
3933 3939 - find the revision corresponding to a tag::
3934 3940
3935 3941 hg id -n -r 1.3
3936 3942
3937 3943 - check the most recent revision of a remote repository::
3938 3944
3939 3945 hg id -r tip http://selenic.com/hg/
3940 3946
3941 3947 Returns 0 if successful.
3942 3948 """
3943 3949
3944 3950 if not repo and not source:
3945 3951 raise util.Abort(_("there is no Mercurial repository here "
3946 3952 "(.hg not found)"))
3947 3953
3948 3954 hexfunc = ui.debugflag and hex or short
3949 3955 default = not (num or id or branch or tags or bookmarks)
3950 3956 output = []
3951 3957 revs = []
3952 3958
3953 3959 if source:
3954 3960 source, branches = hg.parseurl(ui.expandpath(source))
3955 3961 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3956 3962 repo = peer.local()
3957 3963 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3958 3964
3959 3965 if not repo:
3960 3966 if num or branch or tags:
3961 3967 raise util.Abort(
3962 3968 _("can't query remote revision number, branch, or tags"))
3963 3969 if not rev and revs:
3964 3970 rev = revs[0]
3965 3971 if not rev:
3966 3972 rev = "tip"
3967 3973
3968 3974 remoterev = peer.lookup(rev)
3969 3975 if default or id:
3970 3976 output = [hexfunc(remoterev)]
3971 3977
3972 3978 def getbms():
3973 3979 bms = []
3974 3980
3975 3981 if 'bookmarks' in peer.listkeys('namespaces'):
3976 3982 hexremoterev = hex(remoterev)
3977 3983 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3978 3984 if bmr == hexremoterev]
3979 3985
3980 3986 return sorted(bms)
3981 3987
3982 3988 if bookmarks:
3983 3989 output.extend(getbms())
3984 3990 elif default and not ui.quiet:
3985 3991 # multiple bookmarks for a single parent separated by '/'
3986 3992 bm = '/'.join(getbms())
3987 3993 if bm:
3988 3994 output.append(bm)
3989 3995 else:
3990 3996 if not rev:
3991 3997 ctx = repo[None]
3992 3998 parents = ctx.parents()
3993 3999 changed = ""
3994 4000 if default or id or num:
3995 4001 if (util.any(repo.status())
3996 4002 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3997 4003 changed = '+'
3998 4004 if default or id:
3999 4005 output = ["%s%s" %
4000 4006 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4001 4007 if num:
4002 4008 output.append("%s%s" %
4003 4009 ('+'.join([str(p.rev()) for p in parents]), changed))
4004 4010 else:
4005 4011 ctx = scmutil.revsingle(repo, rev)
4006 4012 if default or id:
4007 4013 output = [hexfunc(ctx.node())]
4008 4014 if num:
4009 4015 output.append(str(ctx.rev()))
4010 4016
4011 4017 if default and not ui.quiet:
4012 4018 b = ctx.branch()
4013 4019 if b != 'default':
4014 4020 output.append("(%s)" % b)
4015 4021
4016 4022 # multiple tags for a single parent separated by '/'
4017 4023 t = '/'.join(ctx.tags())
4018 4024 if t:
4019 4025 output.append(t)
4020 4026
4021 4027 # multiple bookmarks for a single parent separated by '/'
4022 4028 bm = '/'.join(ctx.bookmarks())
4023 4029 if bm:
4024 4030 output.append(bm)
4025 4031 else:
4026 4032 if branch:
4027 4033 output.append(ctx.branch())
4028 4034
4029 4035 if tags:
4030 4036 output.extend(ctx.tags())
4031 4037
4032 4038 if bookmarks:
4033 4039 output.extend(ctx.bookmarks())
4034 4040
4035 4041 ui.write("%s\n" % ' '.join(output))
4036 4042
4037 4043 @command('import|patch',
4038 4044 [('p', 'strip', 1,
4039 4045 _('directory strip option for patch. This has the same '
4040 4046 'meaning as the corresponding patch option'), _('NUM')),
4041 4047 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4042 4048 ('e', 'edit', False, _('invoke editor on commit messages')),
4043 4049 ('f', 'force', None,
4044 4050 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4045 4051 ('', 'no-commit', None,
4046 4052 _("don't commit, just update the working directory")),
4047 4053 ('', 'bypass', None,
4048 4054 _("apply patch without touching the working directory")),
4049 4055 ('', 'partial', None,
4050 4056 _('commit even if some hunks fail')),
4051 4057 ('', 'exact', None,
4052 4058 _('apply patch to the nodes from which it was generated')),
4053 4059 ('', 'import-branch', None,
4054 4060 _('use any branch information in patch (implied by --exact)'))] +
4055 4061 commitopts + commitopts2 + similarityopts,
4056 4062 _('[OPTION]... PATCH...'))
4057 4063 def import_(ui, repo, patch1=None, *patches, **opts):
4058 4064 """import an ordered set of patches
4059 4065
4060 4066 Import a list of patches and commit them individually (unless
4061 4067 --no-commit is specified).
4062 4068
4063 4069 Because import first applies changes to the working directory,
4064 4070 import will abort if there are outstanding changes.
4065 4071
4066 4072 You can import a patch straight from a mail message. Even patches
4067 4073 as attachments work (to use the body part, it must have type
4068 4074 text/plain or text/x-patch). From and Subject headers of email
4069 4075 message are used as default committer and commit message. All
4070 4076 text/plain body parts before first diff are added to commit
4071 4077 message.
4072 4078
4073 4079 If the imported patch was generated by :hg:`export`, user and
4074 4080 description from patch override values from message headers and
4075 4081 body. Values given on command line with -m/--message and -u/--user
4076 4082 override these.
4077 4083
4078 4084 If --exact is specified, import will set the working directory to
4079 4085 the parent of each patch before applying it, and will abort if the
4080 4086 resulting changeset has a different ID than the one recorded in
4081 4087 the patch. This may happen due to character set problems or other
4082 4088 deficiencies in the text patch format.
4083 4089
4084 4090 Use --bypass to apply and commit patches directly to the
4085 4091 repository, not touching the working directory. Without --exact,
4086 4092 patches will be applied on top of the working directory parent
4087 4093 revision.
4088 4094
4089 4095 With -s/--similarity, hg will attempt to discover renames and
4090 4096 copies in the patch in the same way as :hg:`addremove`.
4091 4097
4092 4098 Use --partial to ensure a changeset will be created from the patch
4093 4099 even if some hunks fail to apply. Hunks that fail to apply will be
4094 4100 written to a <target-file>.rej file. Conflicts can then be resolved
4095 4101 by hand before :hg:`commit --amend` is run to update the created
4096 4102 changeset. This flag exists to let people import patches that
4097 4103 partially apply without losing the associated metadata (author,
4098 4104 date, description, ...). Note that when none of the hunk applies
4099 4105 cleanly, :hg:`import --partial` will create an empty changeset,
4100 4106 importing only the patch metadata.
4101 4107
4102 4108 To read a patch from standard input, use "-" as the patch name. If
4103 4109 a URL is specified, the patch will be downloaded from it.
4104 4110 See :hg:`help dates` for a list of formats valid for -d/--date.
4105 4111
4106 4112 .. container:: verbose
4107 4113
4108 4114 Examples:
4109 4115
4110 4116 - import a traditional patch from a website and detect renames::
4111 4117
4112 4118 hg import -s 80 http://example.com/bugfix.patch
4113 4119
4114 4120 - import a changeset from an hgweb server::
4115 4121
4116 4122 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4117 4123
4118 4124 - import all the patches in an Unix-style mbox::
4119 4125
4120 4126 hg import incoming-patches.mbox
4121 4127
4122 4128 - attempt to exactly restore an exported changeset (not always
4123 4129 possible)::
4124 4130
4125 4131 hg import --exact proposed-fix.patch
4126 4132
4127 4133 Returns 0 on success, 1 on partial success (see --partial).
4128 4134 """
4129 4135
4130 4136 if not patch1:
4131 4137 raise util.Abort(_('need at least one patch to import'))
4132 4138
4133 4139 patches = (patch1,) + patches
4134 4140
4135 4141 date = opts.get('date')
4136 4142 if date:
4137 4143 opts['date'] = util.parsedate(date)
4138 4144
4139 4145 update = not opts.get('bypass')
4140 4146 if not update and opts.get('no_commit'):
4141 4147 raise util.Abort(_('cannot use --no-commit with --bypass'))
4142 4148 try:
4143 4149 sim = float(opts.get('similarity') or 0)
4144 4150 except ValueError:
4145 4151 raise util.Abort(_('similarity must be a number'))
4146 4152 if sim < 0 or sim > 100:
4147 4153 raise util.Abort(_('similarity must be between 0 and 100'))
4148 4154 if sim and not update:
4149 4155 raise util.Abort(_('cannot use --similarity with --bypass'))
4150 4156 if opts.get('exact') and opts.get('edit'):
4151 4157 raise util.Abort(_('cannot use --exact with --edit'))
4152 4158
4153 4159 if update:
4154 4160 cmdutil.checkunfinished(repo)
4155 4161 if (opts.get('exact') or not opts.get('force')) and update:
4156 4162 cmdutil.bailifchanged(repo)
4157 4163
4158 4164 base = opts["base"]
4159 4165 wlock = lock = tr = None
4160 4166 msgs = []
4161 4167 ret = 0
4162 4168
4163 4169
4164 4170 try:
4165 4171 try:
4166 4172 wlock = repo.wlock()
4167 4173 repo.dirstate.beginparentchange()
4168 4174 if not opts.get('no_commit'):
4169 4175 lock = repo.lock()
4170 4176 tr = repo.transaction('import')
4171 4177 parents = repo.parents()
4172 4178 for patchurl in patches:
4173 4179 if patchurl == '-':
4174 4180 ui.status(_('applying patch from stdin\n'))
4175 4181 patchfile = ui.fin
4176 4182 patchurl = 'stdin' # for error message
4177 4183 else:
4178 4184 patchurl = os.path.join(base, patchurl)
4179 4185 ui.status(_('applying %s\n') % patchurl)
4180 4186 patchfile = hg.openpath(ui, patchurl)
4181 4187
4182 4188 haspatch = False
4183 4189 for hunk in patch.split(patchfile):
4184 4190 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4185 4191 parents, opts,
4186 4192 msgs, hg.clean)
4187 4193 if msg:
4188 4194 haspatch = True
4189 4195 ui.note(msg + '\n')
4190 4196 if update or opts.get('exact'):
4191 4197 parents = repo.parents()
4192 4198 else:
4193 4199 parents = [repo[node]]
4194 4200 if rej:
4195 4201 ui.write_err(_("patch applied partially\n"))
4196 4202 ui.write_err(_("(fix the .rej files and run "
4197 4203 "`hg commit --amend`)\n"))
4198 4204 ret = 1
4199 4205 break
4200 4206
4201 4207 if not haspatch:
4202 4208 raise util.Abort(_('%s: no diffs found') % patchurl)
4203 4209
4204 4210 if tr:
4205 4211 tr.close()
4206 4212 if msgs:
4207 4213 repo.savecommitmessage('\n* * *\n'.join(msgs))
4208 4214 repo.dirstate.endparentchange()
4209 4215 return ret
4210 4216 except: # re-raises
4211 4217 # wlock.release() indirectly calls dirstate.write(): since
4212 4218 # we're crashing, we do not want to change the working dir
4213 4219 # parent after all, so make sure it writes nothing
4214 4220 repo.dirstate.invalidate()
4215 4221 raise
4216 4222 finally:
4217 4223 if tr:
4218 4224 tr.release()
4219 4225 release(lock, wlock)
4220 4226
4221 4227 @command('incoming|in',
4222 4228 [('f', 'force', None,
4223 4229 _('run even if remote repository is unrelated')),
4224 4230 ('n', 'newest-first', None, _('show newest record first')),
4225 4231 ('', 'bundle', '',
4226 4232 _('file to store the bundles into'), _('FILE')),
4227 4233 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4228 4234 ('B', 'bookmarks', False, _("compare bookmarks")),
4229 4235 ('b', 'branch', [],
4230 4236 _('a specific branch you would like to pull'), _('BRANCH')),
4231 4237 ] + logopts + remoteopts + subrepoopts,
4232 4238 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4233 4239 def incoming(ui, repo, source="default", **opts):
4234 4240 """show new changesets found in source
4235 4241
4236 4242 Show new changesets found in the specified path/URL or the default
4237 4243 pull location. These are the changesets that would have been pulled
4238 4244 if a pull at the time you issued this command.
4239 4245
4240 4246 For remote repository, using --bundle avoids downloading the
4241 4247 changesets twice if the incoming is followed by a pull.
4242 4248
4243 4249 See pull for valid source format details.
4244 4250
4245 4251 .. container:: verbose
4246 4252
4247 4253 Examples:
4248 4254
4249 4255 - show incoming changes with patches and full description::
4250 4256
4251 4257 hg incoming -vp
4252 4258
4253 4259 - show incoming changes excluding merges, store a bundle::
4254 4260
4255 4261 hg in -vpM --bundle incoming.hg
4256 4262 hg pull incoming.hg
4257 4263
4258 4264 - briefly list changes inside a bundle::
4259 4265
4260 4266 hg in changes.hg -T "{desc|firstline}\\n"
4261 4267
4262 4268 Returns 0 if there are incoming changes, 1 otherwise.
4263 4269 """
4264 4270 if opts.get('graph'):
4265 4271 cmdutil.checkunsupportedgraphflags([], opts)
4266 4272 def display(other, chlist, displayer):
4267 4273 revdag = cmdutil.graphrevs(other, chlist, opts)
4268 4274 showparents = [ctx.node() for ctx in repo[None].parents()]
4269 4275 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4270 4276 graphmod.asciiedges)
4271 4277
4272 4278 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4273 4279 return 0
4274 4280
4275 4281 if opts.get('bundle') and opts.get('subrepos'):
4276 4282 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4277 4283
4278 4284 if opts.get('bookmarks'):
4279 4285 source, branches = hg.parseurl(ui.expandpath(source),
4280 4286 opts.get('branch'))
4281 4287 other = hg.peer(repo, opts, source)
4282 4288 if 'bookmarks' not in other.listkeys('namespaces'):
4283 4289 ui.warn(_("remote doesn't support bookmarks\n"))
4284 4290 return 0
4285 4291 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4286 4292 return bookmarks.diff(ui, repo, other)
4287 4293
4288 4294 repo._subtoppath = ui.expandpath(source)
4289 4295 try:
4290 4296 return hg.incoming(ui, repo, source, opts)
4291 4297 finally:
4292 4298 del repo._subtoppath
4293 4299
4294 4300
4295 4301 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4296 4302 norepo=True)
4297 4303 def init(ui, dest=".", **opts):
4298 4304 """create a new repository in the given directory
4299 4305
4300 4306 Initialize a new repository in the given directory. If the given
4301 4307 directory does not exist, it will be created.
4302 4308
4303 4309 If no directory is given, the current directory is used.
4304 4310
4305 4311 It is possible to specify an ``ssh://`` URL as the destination.
4306 4312 See :hg:`help urls` for more information.
4307 4313
4308 4314 Returns 0 on success.
4309 4315 """
4310 4316 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4311 4317
4312 4318 @command('locate',
4313 4319 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4314 4320 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4315 4321 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4316 4322 ] + walkopts,
4317 4323 _('[OPTION]... [PATTERN]...'))
4318 4324 def locate(ui, repo, *pats, **opts):
4319 4325 """locate files matching specific patterns (DEPRECATED)
4320 4326
4321 4327 Print files under Mercurial control in the working directory whose
4322 4328 names match the given patterns.
4323 4329
4324 4330 By default, this command searches all directories in the working
4325 4331 directory. To search just the current directory and its
4326 4332 subdirectories, use "--include .".
4327 4333
4328 4334 If no patterns are given to match, this command prints the names
4329 4335 of all files under Mercurial control in the working directory.
4330 4336
4331 4337 If you want to feed the output of this command into the "xargs"
4332 4338 command, use the -0 option to both this command and "xargs". This
4333 4339 will avoid the problem of "xargs" treating single filenames that
4334 4340 contain whitespace as multiple filenames.
4335 4341
4336 4342 See :hg:`help files` for a more versatile command.
4337 4343
4338 4344 Returns 0 if a match is found, 1 otherwise.
4339 4345 """
4340 4346 end = opts.get('print0') and '\0' or '\n'
4341 4347 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4342 4348
4343 4349 ret = 1
4344 4350 ctx = repo[rev]
4345 4351 m = scmutil.match(ctx, pats, opts, default='relglob')
4346 4352 m.bad = lambda x, y: False
4347 4353
4348 4354 for abs in ctx.matches(m):
4349 4355 if opts.get('fullpath'):
4350 4356 ui.write(repo.wjoin(abs), end)
4351 4357 else:
4352 4358 ui.write(((pats and m.rel(abs)) or abs), end)
4353 4359 ret = 0
4354 4360
4355 4361 return ret
4356 4362
4357 4363 @command('^log|history',
4358 4364 [('f', 'follow', None,
4359 4365 _('follow changeset history, or file history across copies and renames')),
4360 4366 ('', 'follow-first', None,
4361 4367 _('only follow the first parent of merge changesets (DEPRECATED)')),
4362 4368 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4363 4369 ('C', 'copies', None, _('show copied files')),
4364 4370 ('k', 'keyword', [],
4365 4371 _('do case-insensitive search for a given text'), _('TEXT')),
4366 4372 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4367 4373 ('', 'removed', None, _('include revisions where files were removed')),
4368 4374 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4369 4375 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4370 4376 ('', 'only-branch', [],
4371 4377 _('show only changesets within the given named branch (DEPRECATED)'),
4372 4378 _('BRANCH')),
4373 4379 ('b', 'branch', [],
4374 4380 _('show changesets within the given named branch'), _('BRANCH')),
4375 4381 ('P', 'prune', [],
4376 4382 _('do not display revision or any of its ancestors'), _('REV')),
4377 4383 ] + logopts + walkopts,
4378 4384 _('[OPTION]... [FILE]'),
4379 4385 inferrepo=True)
4380 4386 def log(ui, repo, *pats, **opts):
4381 4387 """show revision history of entire repository or files
4382 4388
4383 4389 Print the revision history of the specified files or the entire
4384 4390 project.
4385 4391
4386 4392 If no revision range is specified, the default is ``tip:0`` unless
4387 4393 --follow is set, in which case the working directory parent is
4388 4394 used as the starting revision.
4389 4395
4390 4396 File history is shown without following rename or copy history of
4391 4397 files. Use -f/--follow with a filename to follow history across
4392 4398 renames and copies. --follow without a filename will only show
4393 4399 ancestors or descendants of the starting revision.
4394 4400
4395 4401 By default this command prints revision number and changeset id,
4396 4402 tags, non-trivial parents, user, date and time, and a summary for
4397 4403 each commit. When the -v/--verbose switch is used, the list of
4398 4404 changed files and full commit message are shown.
4399 4405
4400 4406 With --graph the revisions are shown as an ASCII art DAG with the most
4401 4407 recent changeset at the top.
4402 4408 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4403 4409 and '+' represents a fork where the changeset from the lines below is a
4404 4410 parent of the 'o' merge on the same line.
4405 4411
4406 4412 .. note::
4407 4413
4408 4414 log -p/--patch may generate unexpected diff output for merge
4409 4415 changesets, as it will only compare the merge changeset against
4410 4416 its first parent. Also, only files different from BOTH parents
4411 4417 will appear in files:.
4412 4418
4413 4419 .. note::
4414 4420
4415 4421 for performance reasons, log FILE may omit duplicate changes
4416 4422 made on branches and will not show removals or mode changes. To
4417 4423 see all such changes, use the --removed switch.
4418 4424
4419 4425 .. container:: verbose
4420 4426
4421 4427 Some examples:
4422 4428
4423 4429 - changesets with full descriptions and file lists::
4424 4430
4425 4431 hg log -v
4426 4432
4427 4433 - changesets ancestral to the working directory::
4428 4434
4429 4435 hg log -f
4430 4436
4431 4437 - last 10 commits on the current branch::
4432 4438
4433 4439 hg log -l 10 -b .
4434 4440
4435 4441 - changesets showing all modifications of a file, including removals::
4436 4442
4437 4443 hg log --removed file.c
4438 4444
4439 4445 - all changesets that touch a directory, with diffs, excluding merges::
4440 4446
4441 4447 hg log -Mp lib/
4442 4448
4443 4449 - all revision numbers that match a keyword::
4444 4450
4445 4451 hg log -k bug --template "{rev}\\n"
4446 4452
4447 4453 - list available log templates::
4448 4454
4449 4455 hg log -T list
4450 4456
4451 4457 - check if a given changeset is included in a tagged release::
4452 4458
4453 4459 hg log -r "a21ccf and ancestor(1.9)"
4454 4460
4455 4461 - find all changesets by some user in a date range::
4456 4462
4457 4463 hg log -k alice -d "may 2008 to jul 2008"
4458 4464
4459 4465 - summary of all changesets after the last tag::
4460 4466
4461 4467 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4462 4468
4463 4469 See :hg:`help dates` for a list of formats valid for -d/--date.
4464 4470
4465 4471 See :hg:`help revisions` and :hg:`help revsets` for more about
4466 4472 specifying revisions.
4467 4473
4468 4474 See :hg:`help templates` for more about pre-packaged styles and
4469 4475 specifying custom templates.
4470 4476
4471 4477 Returns 0 on success.
4472 4478
4473 4479 """
4474 4480 if opts.get('graph'):
4475 4481 return cmdutil.graphlog(ui, repo, *pats, **opts)
4476 4482
4477 4483 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4478 4484 limit = cmdutil.loglimit(opts)
4479 4485 count = 0
4480 4486
4481 4487 getrenamed = None
4482 4488 if opts.get('copies'):
4483 4489 endrev = None
4484 4490 if opts.get('rev'):
4485 4491 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4486 4492 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4487 4493
4488 4494 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4489 4495 for rev in revs:
4490 4496 if count == limit:
4491 4497 break
4492 4498 ctx = repo[rev]
4493 4499 copies = None
4494 4500 if getrenamed is not None and rev:
4495 4501 copies = []
4496 4502 for fn in ctx.files():
4497 4503 rename = getrenamed(fn, rev)
4498 4504 if rename:
4499 4505 copies.append((fn, rename[0]))
4500 4506 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4501 4507 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4502 4508 if displayer.flush(rev):
4503 4509 count += 1
4504 4510
4505 4511 displayer.close()
4506 4512
4507 4513 @command('manifest',
4508 4514 [('r', 'rev', '', _('revision to display'), _('REV')),
4509 4515 ('', 'all', False, _("list files from all revisions"))]
4510 4516 + formatteropts,
4511 4517 _('[-r REV]'))
4512 4518 def manifest(ui, repo, node=None, rev=None, **opts):
4513 4519 """output the current or given revision of the project manifest
4514 4520
4515 4521 Print a list of version controlled files for the given revision.
4516 4522 If no revision is given, the first parent of the working directory
4517 4523 is used, or the null revision if no revision is checked out.
4518 4524
4519 4525 With -v, print file permissions, symlink and executable bits.
4520 4526 With --debug, print file revision hashes.
4521 4527
4522 4528 If option --all is specified, the list of all files from all revisions
4523 4529 is printed. This includes deleted and renamed files.
4524 4530
4525 4531 Returns 0 on success.
4526 4532 """
4527 4533
4528 4534 fm = ui.formatter('manifest', opts)
4529 4535
4530 4536 if opts.get('all'):
4531 4537 if rev or node:
4532 4538 raise util.Abort(_("can't specify a revision with --all"))
4533 4539
4534 4540 res = []
4535 4541 prefix = "data/"
4536 4542 suffix = ".i"
4537 4543 plen = len(prefix)
4538 4544 slen = len(suffix)
4539 4545 lock = repo.lock()
4540 4546 try:
4541 4547 for fn, b, size in repo.store.datafiles():
4542 4548 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4543 4549 res.append(fn[plen:-slen])
4544 4550 finally:
4545 4551 lock.release()
4546 4552 for f in res:
4547 4553 fm.startitem()
4548 4554 fm.write("path", '%s\n', f)
4549 4555 fm.end()
4550 4556 return
4551 4557
4552 4558 if rev and node:
4553 4559 raise util.Abort(_("please specify just one revision"))
4554 4560
4555 4561 if not node:
4556 4562 node = rev
4557 4563
4558 4564 char = {'l': '@', 'x': '*', '': ''}
4559 4565 mode = {'l': '644', 'x': '755', '': '644'}
4560 4566 ctx = scmutil.revsingle(repo, node)
4561 4567 mf = ctx.manifest()
4562 4568 for f in ctx:
4563 4569 fm.startitem()
4564 4570 fl = ctx[f].flags()
4565 4571 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4566 4572 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4567 4573 fm.write('path', '%s\n', f)
4568 4574 fm.end()
4569 4575
4570 4576 @command('^merge',
4571 4577 [('f', 'force', None,
4572 4578 _('force a merge including outstanding changes (DEPRECATED)')),
4573 4579 ('r', 'rev', '', _('revision to merge'), _('REV')),
4574 4580 ('P', 'preview', None,
4575 4581 _('review revisions to merge (no merge is performed)'))
4576 4582 ] + mergetoolopts,
4577 4583 _('[-P] [-f] [[-r] REV]'))
4578 4584 def merge(ui, repo, node=None, **opts):
4579 4585 """merge another revision into working directory
4580 4586
4581 4587 The current working directory is updated with all changes made in
4582 4588 the requested revision since the last common predecessor revision.
4583 4589
4584 4590 Files that changed between either parent are marked as changed for
4585 4591 the next commit and a commit must be performed before any further
4586 4592 updates to the repository are allowed. The next commit will have
4587 4593 two parents.
4588 4594
4589 4595 ``--tool`` can be used to specify the merge tool used for file
4590 4596 merges. It overrides the HGMERGE environment variable and your
4591 4597 configuration files. See :hg:`help merge-tools` for options.
4592 4598
4593 4599 If no revision is specified, the working directory's parent is a
4594 4600 head revision, and the current branch contains exactly one other
4595 4601 head, the other head is merged with by default. Otherwise, an
4596 4602 explicit revision with which to merge with must be provided.
4597 4603
4598 4604 :hg:`resolve` must be used to resolve unresolved files.
4599 4605
4600 4606 To undo an uncommitted merge, use :hg:`update --clean .` which
4601 4607 will check out a clean copy of the original merge parent, losing
4602 4608 all changes.
4603 4609
4604 4610 Returns 0 on success, 1 if there are unresolved files.
4605 4611 """
4606 4612
4607 4613 if opts.get('rev') and node:
4608 4614 raise util.Abort(_("please specify just one revision"))
4609 4615 if not node:
4610 4616 node = opts.get('rev')
4611 4617
4612 4618 if node:
4613 4619 node = scmutil.revsingle(repo, node).node()
4614 4620
4615 4621 if not node and repo._bookmarkcurrent:
4616 4622 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4617 4623 curhead = repo[repo._bookmarkcurrent].node()
4618 4624 if len(bmheads) == 2:
4619 4625 if curhead == bmheads[0]:
4620 4626 node = bmheads[1]
4621 4627 else:
4622 4628 node = bmheads[0]
4623 4629 elif len(bmheads) > 2:
4624 4630 raise util.Abort(_("multiple matching bookmarks to merge - "
4625 4631 "please merge with an explicit rev or bookmark"),
4626 4632 hint=_("run 'hg heads' to see all heads"))
4627 4633 elif len(bmheads) <= 1:
4628 4634 raise util.Abort(_("no matching bookmark to merge - "
4629 4635 "please merge with an explicit rev or bookmark"),
4630 4636 hint=_("run 'hg heads' to see all heads"))
4631 4637
4632 4638 if not node and not repo._bookmarkcurrent:
4633 4639 branch = repo[None].branch()
4634 4640 bheads = repo.branchheads(branch)
4635 4641 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4636 4642
4637 4643 if len(nbhs) > 2:
4638 4644 raise util.Abort(_("branch '%s' has %d heads - "
4639 4645 "please merge with an explicit rev")
4640 4646 % (branch, len(bheads)),
4641 4647 hint=_("run 'hg heads .' to see heads"))
4642 4648
4643 4649 parent = repo.dirstate.p1()
4644 4650 if len(nbhs) <= 1:
4645 4651 if len(bheads) > 1:
4646 4652 raise util.Abort(_("heads are bookmarked - "
4647 4653 "please merge with an explicit rev"),
4648 4654 hint=_("run 'hg heads' to see all heads"))
4649 4655 if len(repo.heads()) > 1:
4650 4656 raise util.Abort(_("branch '%s' has one head - "
4651 4657 "please merge with an explicit rev")
4652 4658 % branch,
4653 4659 hint=_("run 'hg heads' to see all heads"))
4654 4660 msg, hint = _('nothing to merge'), None
4655 4661 if parent != repo.lookup(branch):
4656 4662 hint = _("use 'hg update' instead")
4657 4663 raise util.Abort(msg, hint=hint)
4658 4664
4659 4665 if parent not in bheads:
4660 4666 raise util.Abort(_('working directory not at a head revision'),
4661 4667 hint=_("use 'hg update' or merge with an "
4662 4668 "explicit revision"))
4663 4669 if parent == nbhs[0]:
4664 4670 node = nbhs[-1]
4665 4671 else:
4666 4672 node = nbhs[0]
4667 4673
4668 4674 if opts.get('preview'):
4669 4675 # find nodes that are ancestors of p2 but not of p1
4670 4676 p1 = repo.lookup('.')
4671 4677 p2 = repo.lookup(node)
4672 4678 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4673 4679
4674 4680 displayer = cmdutil.show_changeset(ui, repo, opts)
4675 4681 for node in nodes:
4676 4682 displayer.show(repo[node])
4677 4683 displayer.close()
4678 4684 return 0
4679 4685
4680 4686 try:
4681 4687 # ui.forcemerge is an internal variable, do not document
4682 4688 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4683 4689 return hg.merge(repo, node, force=opts.get('force'))
4684 4690 finally:
4685 4691 ui.setconfig('ui', 'forcemerge', '', 'merge')
4686 4692
4687 4693 @command('outgoing|out',
4688 4694 [('f', 'force', None, _('run even when the destination is unrelated')),
4689 4695 ('r', 'rev', [],
4690 4696 _('a changeset intended to be included in the destination'), _('REV')),
4691 4697 ('n', 'newest-first', None, _('show newest record first')),
4692 4698 ('B', 'bookmarks', False, _('compare bookmarks')),
4693 4699 ('b', 'branch', [], _('a specific branch you would like to push'),
4694 4700 _('BRANCH')),
4695 4701 ] + logopts + remoteopts + subrepoopts,
4696 4702 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4697 4703 def outgoing(ui, repo, dest=None, **opts):
4698 4704 """show changesets not found in the destination
4699 4705
4700 4706 Show changesets not found in the specified destination repository
4701 4707 or the default push location. These are the changesets that would
4702 4708 be pushed if a push was requested.
4703 4709
4704 4710 See pull for details of valid destination formats.
4705 4711
4706 4712 Returns 0 if there are outgoing changes, 1 otherwise.
4707 4713 """
4708 4714 if opts.get('graph'):
4709 4715 cmdutil.checkunsupportedgraphflags([], opts)
4710 4716 o, other = hg._outgoing(ui, repo, dest, opts)
4711 4717 if not o:
4712 4718 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4713 4719 return
4714 4720
4715 4721 revdag = cmdutil.graphrevs(repo, o, opts)
4716 4722 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4717 4723 showparents = [ctx.node() for ctx in repo[None].parents()]
4718 4724 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4719 4725 graphmod.asciiedges)
4720 4726 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4721 4727 return 0
4722 4728
4723 4729 if opts.get('bookmarks'):
4724 4730 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4725 4731 dest, branches = hg.parseurl(dest, opts.get('branch'))
4726 4732 other = hg.peer(repo, opts, dest)
4727 4733 if 'bookmarks' not in other.listkeys('namespaces'):
4728 4734 ui.warn(_("remote doesn't support bookmarks\n"))
4729 4735 return 0
4730 4736 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4731 4737 return bookmarks.diff(ui, other, repo)
4732 4738
4733 4739 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4734 4740 try:
4735 4741 return hg.outgoing(ui, repo, dest, opts)
4736 4742 finally:
4737 4743 del repo._subtoppath
4738 4744
4739 4745 @command('parents',
4740 4746 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4741 4747 ] + templateopts,
4742 4748 _('[-r REV] [FILE]'),
4743 4749 inferrepo=True)
4744 4750 def parents(ui, repo, file_=None, **opts):
4745 4751 """show the parents of the working directory or revision (DEPRECATED)
4746 4752
4747 4753 Print the working directory's parent revisions. If a revision is
4748 4754 given via -r/--rev, the parent of that revision will be printed.
4749 4755 If a file argument is given, the revision in which the file was
4750 4756 last changed (before the working directory revision or the
4751 4757 argument to --rev if given) is printed.
4752 4758
4753 4759 See :hg:`summary` and :hg:`help revsets` for related information.
4754 4760
4755 4761 Returns 0 on success.
4756 4762 """
4757 4763
4758 4764 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4759 4765
4760 4766 if file_:
4761 4767 m = scmutil.match(ctx, (file_,), opts)
4762 4768 if m.anypats() or len(m.files()) != 1:
4763 4769 raise util.Abort(_('can only specify an explicit filename'))
4764 4770 file_ = m.files()[0]
4765 4771 filenodes = []
4766 4772 for cp in ctx.parents():
4767 4773 if not cp:
4768 4774 continue
4769 4775 try:
4770 4776 filenodes.append(cp.filenode(file_))
4771 4777 except error.LookupError:
4772 4778 pass
4773 4779 if not filenodes:
4774 4780 raise util.Abort(_("'%s' not found in manifest!") % file_)
4775 4781 p = []
4776 4782 for fn in filenodes:
4777 4783 fctx = repo.filectx(file_, fileid=fn)
4778 4784 p.append(fctx.node())
4779 4785 else:
4780 4786 p = [cp.node() for cp in ctx.parents()]
4781 4787
4782 4788 displayer = cmdutil.show_changeset(ui, repo, opts)
4783 4789 for n in p:
4784 4790 if n != nullid:
4785 4791 displayer.show(repo[n])
4786 4792 displayer.close()
4787 4793
4788 4794 @command('paths', [], _('[NAME]'), optionalrepo=True)
4789 4795 def paths(ui, repo, search=None):
4790 4796 """show aliases for remote repositories
4791 4797
4792 4798 Show definition of symbolic path name NAME. If no name is given,
4793 4799 show definition of all available names.
4794 4800
4795 4801 Option -q/--quiet suppresses all output when searching for NAME
4796 4802 and shows only the path names when listing all definitions.
4797 4803
4798 4804 Path names are defined in the [paths] section of your
4799 4805 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4800 4806 repository, ``.hg/hgrc`` is used, too.
4801 4807
4802 4808 The path names ``default`` and ``default-push`` have a special
4803 4809 meaning. When performing a push or pull operation, they are used
4804 4810 as fallbacks if no location is specified on the command-line.
4805 4811 When ``default-push`` is set, it will be used for push and
4806 4812 ``default`` will be used for pull; otherwise ``default`` is used
4807 4813 as the fallback for both. When cloning a repository, the clone
4808 4814 source is written as ``default`` in ``.hg/hgrc``. Note that
4809 4815 ``default`` and ``default-push`` apply to all inbound (e.g.
4810 4816 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4811 4817 :hg:`bundle`) operations.
4812 4818
4813 4819 See :hg:`help urls` for more information.
4814 4820
4815 4821 Returns 0 on success.
4816 4822 """
4817 4823 if search:
4818 4824 for name, path in ui.configitems("paths"):
4819 4825 if name == search:
4820 4826 ui.status("%s\n" % util.hidepassword(path))
4821 4827 return
4822 4828 if not ui.quiet:
4823 4829 ui.warn(_("not found!\n"))
4824 4830 return 1
4825 4831 else:
4826 4832 for name, path in ui.configitems("paths"):
4827 4833 if ui.quiet:
4828 4834 ui.write("%s\n" % name)
4829 4835 else:
4830 4836 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4831 4837
4832 4838 @command('phase',
4833 4839 [('p', 'public', False, _('set changeset phase to public')),
4834 4840 ('d', 'draft', False, _('set changeset phase to draft')),
4835 4841 ('s', 'secret', False, _('set changeset phase to secret')),
4836 4842 ('f', 'force', False, _('allow to move boundary backward')),
4837 4843 ('r', 'rev', [], _('target revision'), _('REV')),
4838 4844 ],
4839 4845 _('[-p|-d|-s] [-f] [-r] REV...'))
4840 4846 def phase(ui, repo, *revs, **opts):
4841 4847 """set or show the current phase name
4842 4848
4843 4849 With no argument, show the phase name of specified revisions.
4844 4850
4845 4851 With one of -p/--public, -d/--draft or -s/--secret, change the
4846 4852 phase value of the specified revisions.
4847 4853
4848 4854 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4849 4855 lower phase to an higher phase. Phases are ordered as follows::
4850 4856
4851 4857 public < draft < secret
4852 4858
4853 4859 Returns 0 on success, 1 if no phases were changed or some could not
4854 4860 be changed.
4855 4861 """
4856 4862 # search for a unique phase argument
4857 4863 targetphase = None
4858 4864 for idx, name in enumerate(phases.phasenames):
4859 4865 if opts[name]:
4860 4866 if targetphase is not None:
4861 4867 raise util.Abort(_('only one phase can be specified'))
4862 4868 targetphase = idx
4863 4869
4864 4870 # look for specified revision
4865 4871 revs = list(revs)
4866 4872 revs.extend(opts['rev'])
4867 4873 if not revs:
4868 4874 raise util.Abort(_('no revisions specified'))
4869 4875
4870 4876 revs = scmutil.revrange(repo, revs)
4871 4877
4872 4878 lock = None
4873 4879 ret = 0
4874 4880 if targetphase is None:
4875 4881 # display
4876 4882 for r in revs:
4877 4883 ctx = repo[r]
4878 4884 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4879 4885 else:
4880 4886 tr = None
4881 4887 lock = repo.lock()
4882 4888 try:
4883 4889 tr = repo.transaction("phase")
4884 4890 # set phase
4885 4891 if not revs:
4886 4892 raise util.Abort(_('empty revision set'))
4887 4893 nodes = [repo[r].node() for r in revs]
4888 4894 # moving revision from public to draft may hide them
4889 4895 # We have to check result on an unfiltered repository
4890 4896 unfi = repo.unfiltered()
4891 4897 getphase = unfi._phasecache.phase
4892 4898 olddata = [getphase(unfi, r) for r in unfi]
4893 4899 phases.advanceboundary(repo, tr, targetphase, nodes)
4894 4900 if opts['force']:
4895 4901 phases.retractboundary(repo, tr, targetphase, nodes)
4896 4902 tr.close()
4897 4903 finally:
4898 4904 if tr is not None:
4899 4905 tr.release()
4900 4906 lock.release()
4901 4907 getphase = unfi._phasecache.phase
4902 4908 newdata = [getphase(unfi, r) for r in unfi]
4903 4909 changes = sum(newdata[r] != olddata[r] for r in unfi)
4904 4910 cl = unfi.changelog
4905 4911 rejected = [n for n in nodes
4906 4912 if newdata[cl.rev(n)] < targetphase]
4907 4913 if rejected:
4908 4914 ui.warn(_('cannot move %i changesets to a higher '
4909 4915 'phase, use --force\n') % len(rejected))
4910 4916 ret = 1
4911 4917 if changes:
4912 4918 msg = _('phase changed for %i changesets\n') % changes
4913 4919 if ret:
4914 4920 ui.status(msg)
4915 4921 else:
4916 4922 ui.note(msg)
4917 4923 else:
4918 4924 ui.warn(_('no phases changed\n'))
4919 4925 ret = 1
4920 4926 return ret
4921 4927
4922 4928 def postincoming(ui, repo, modheads, optupdate, checkout):
4923 4929 if modheads == 0:
4924 4930 return
4925 4931 if optupdate:
4926 4932 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4927 4933 try:
4928 4934 ret = hg.update(repo, checkout)
4929 4935 except util.Abort, inst:
4930 4936 ui.warn(_("not updating: %s\n") % str(inst))
4931 4937 if inst.hint:
4932 4938 ui.warn(_("(%s)\n") % inst.hint)
4933 4939 return 0
4934 4940 if not ret and not checkout:
4935 4941 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4936 4942 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4937 4943 return ret
4938 4944 if modheads > 1:
4939 4945 currentbranchheads = len(repo.branchheads())
4940 4946 if currentbranchheads == modheads:
4941 4947 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4942 4948 elif currentbranchheads > 1:
4943 4949 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4944 4950 "merge)\n"))
4945 4951 else:
4946 4952 ui.status(_("(run 'hg heads' to see heads)\n"))
4947 4953 else:
4948 4954 ui.status(_("(run 'hg update' to get a working copy)\n"))
4949 4955
4950 4956 @command('^pull',
4951 4957 [('u', 'update', None,
4952 4958 _('update to new branch head if changesets were pulled')),
4953 4959 ('f', 'force', None, _('run even when remote repository is unrelated')),
4954 4960 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4955 4961 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4956 4962 ('b', 'branch', [], _('a specific branch you would like to pull'),
4957 4963 _('BRANCH')),
4958 4964 ] + remoteopts,
4959 4965 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4960 4966 def pull(ui, repo, source="default", **opts):
4961 4967 """pull changes from the specified source
4962 4968
4963 4969 Pull changes from a remote repository to a local one.
4964 4970
4965 4971 This finds all changes from the repository at the specified path
4966 4972 or URL and adds them to a local repository (the current one unless
4967 4973 -R is specified). By default, this does not update the copy of the
4968 4974 project in the working directory.
4969 4975
4970 4976 Use :hg:`incoming` if you want to see what would have been added
4971 4977 by a pull at the time you issued this command. If you then decide
4972 4978 to add those changes to the repository, you should use :hg:`pull
4973 4979 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4974 4980
4975 4981 If SOURCE is omitted, the 'default' path will be used.
4976 4982 See :hg:`help urls` for more information.
4977 4983
4978 4984 Returns 0 on success, 1 if an update had unresolved files.
4979 4985 """
4980 4986 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4981 4987 other = hg.peer(repo, opts, source)
4982 4988 try:
4983 4989 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4984 4990 revs, checkout = hg.addbranchrevs(repo, other, branches,
4985 4991 opts.get('rev'))
4986 4992
4987 4993 remotebookmarks = other.listkeys('bookmarks')
4988 4994
4989 4995 if opts.get('bookmark'):
4990 4996 if not revs:
4991 4997 revs = []
4992 4998 for b in opts['bookmark']:
4993 4999 if b not in remotebookmarks:
4994 5000 raise util.Abort(_('remote bookmark %s not found!') % b)
4995 5001 revs.append(remotebookmarks[b])
4996 5002
4997 5003 if revs:
4998 5004 try:
4999 5005 revs = [other.lookup(rev) for rev in revs]
5000 5006 except error.CapabilityError:
5001 5007 err = _("other repository doesn't support revision lookup, "
5002 5008 "so a rev cannot be specified.")
5003 5009 raise util.Abort(err)
5004 5010
5005 5011 modheads = exchange.pull(repo, other, heads=revs,
5006 5012 force=opts.get('force'),
5007 5013 bookmarks=opts.get('bookmark', ())).cgresult
5008 5014 if checkout:
5009 5015 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5010 5016 repo._subtoppath = source
5011 5017 try:
5012 5018 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5013 5019
5014 5020 finally:
5015 5021 del repo._subtoppath
5016 5022
5017 5023 finally:
5018 5024 other.close()
5019 5025 return ret
5020 5026
5021 5027 @command('^push',
5022 5028 [('f', 'force', None, _('force push')),
5023 5029 ('r', 'rev', [],
5024 5030 _('a changeset intended to be included in the destination'),
5025 5031 _('REV')),
5026 5032 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5027 5033 ('b', 'branch', [],
5028 5034 _('a specific branch you would like to push'), _('BRANCH')),
5029 5035 ('', 'new-branch', False, _('allow pushing a new branch')),
5030 5036 ] + remoteopts,
5031 5037 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5032 5038 def push(ui, repo, dest=None, **opts):
5033 5039 """push changes to the specified destination
5034 5040
5035 5041 Push changesets from the local repository to the specified
5036 5042 destination.
5037 5043
5038 5044 This operation is symmetrical to pull: it is identical to a pull
5039 5045 in the destination repository from the current one.
5040 5046
5041 5047 By default, push will not allow creation of new heads at the
5042 5048 destination, since multiple heads would make it unclear which head
5043 5049 to use. In this situation, it is recommended to pull and merge
5044 5050 before pushing.
5045 5051
5046 5052 Use --new-branch if you want to allow push to create a new named
5047 5053 branch that is not present at the destination. This allows you to
5048 5054 only create a new branch without forcing other changes.
5049 5055
5050 5056 .. note::
5051 5057
5052 5058 Extra care should be taken with the -f/--force option,
5053 5059 which will push all new heads on all branches, an action which will
5054 5060 almost always cause confusion for collaborators.
5055 5061
5056 5062 If -r/--rev is used, the specified revision and all its ancestors
5057 5063 will be pushed to the remote repository.
5058 5064
5059 5065 If -B/--bookmark is used, the specified bookmarked revision, its
5060 5066 ancestors, and the bookmark will be pushed to the remote
5061 5067 repository.
5062 5068
5063 5069 Please see :hg:`help urls` for important details about ``ssh://``
5064 5070 URLs. If DESTINATION is omitted, a default path will be used.
5065 5071
5066 5072 Returns 0 if push was successful, 1 if nothing to push.
5067 5073 """
5068 5074
5069 5075 if opts.get('bookmark'):
5070 5076 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5071 5077 for b in opts['bookmark']:
5072 5078 # translate -B options to -r so changesets get pushed
5073 5079 if b in repo._bookmarks:
5074 5080 opts.setdefault('rev', []).append(b)
5075 5081 else:
5076 5082 # if we try to push a deleted bookmark, translate it to null
5077 5083 # this lets simultaneous -r, -b options continue working
5078 5084 opts.setdefault('rev', []).append("null")
5079 5085
5080 5086 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5081 5087 dest, branches = hg.parseurl(dest, opts.get('branch'))
5082 5088 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5083 5089 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5084 5090 try:
5085 5091 other = hg.peer(repo, opts, dest)
5086 5092 except error.RepoError:
5087 5093 if dest == "default-push":
5088 5094 raise util.Abort(_("default repository not configured!"),
5089 5095 hint=_('see the "path" section in "hg help config"'))
5090 5096 else:
5091 5097 raise
5092 5098
5093 5099 if revs:
5094 5100 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5095 5101
5096 5102 repo._subtoppath = dest
5097 5103 try:
5098 5104 # push subrepos depth-first for coherent ordering
5099 5105 c = repo['']
5100 5106 subs = c.substate # only repos that are committed
5101 5107 for s in sorted(subs):
5102 5108 result = c.sub(s).push(opts)
5103 5109 if result == 0:
5104 5110 return not result
5105 5111 finally:
5106 5112 del repo._subtoppath
5107 5113 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5108 5114 newbranch=opts.get('new_branch'),
5109 5115 bookmarks=opts.get('bookmark', ()))
5110 5116
5111 5117 result = not pushop.cgresult
5112 5118
5113 5119 if pushop.bkresult is not None:
5114 5120 if pushop.bkresult == 2:
5115 5121 result = 2
5116 5122 elif not result and pushop.bkresult:
5117 5123 result = 2
5118 5124
5119 5125 return result
5120 5126
5121 5127 @command('recover', [])
5122 5128 def recover(ui, repo):
5123 5129 """roll back an interrupted transaction
5124 5130
5125 5131 Recover from an interrupted commit or pull.
5126 5132
5127 5133 This command tries to fix the repository status after an
5128 5134 interrupted operation. It should only be necessary when Mercurial
5129 5135 suggests it.
5130 5136
5131 5137 Returns 0 if successful, 1 if nothing to recover or verify fails.
5132 5138 """
5133 5139 if repo.recover():
5134 5140 return hg.verify(repo)
5135 5141 return 1
5136 5142
5137 5143 @command('^remove|rm',
5138 5144 [('A', 'after', None, _('record delete for missing files')),
5139 5145 ('f', 'force', None,
5140 5146 _('remove (and delete) file even if added or modified')),
5141 5147 ] + subrepoopts + walkopts,
5142 5148 _('[OPTION]... FILE...'),
5143 5149 inferrepo=True)
5144 5150 def remove(ui, repo, *pats, **opts):
5145 5151 """remove the specified files on the next commit
5146 5152
5147 5153 Schedule the indicated files for removal from the current branch.
5148 5154
5149 5155 This command schedules the files to be removed at the next commit.
5150 5156 To undo a remove before that, see :hg:`revert`. To undo added
5151 5157 files, see :hg:`forget`.
5152 5158
5153 5159 .. container:: verbose
5154 5160
5155 5161 -A/--after can be used to remove only files that have already
5156 5162 been deleted, -f/--force can be used to force deletion, and -Af
5157 5163 can be used to remove files from the next revision without
5158 5164 deleting them from the working directory.
5159 5165
5160 5166 The following table details the behavior of remove for different
5161 5167 file states (columns) and option combinations (rows). The file
5162 5168 states are Added [A], Clean [C], Modified [M] and Missing [!]
5163 5169 (as reported by :hg:`status`). The actions are Warn, Remove
5164 5170 (from branch) and Delete (from disk):
5165 5171
5166 5172 ========= == == == ==
5167 5173 opt/state A C M !
5168 5174 ========= == == == ==
5169 5175 none W RD W R
5170 5176 -f R RD RD R
5171 5177 -A W W W R
5172 5178 -Af R R R R
5173 5179 ========= == == == ==
5174 5180
5175 5181 Note that remove never deletes files in Added [A] state from the
5176 5182 working directory, not even if option --force is specified.
5177 5183
5178 5184 Returns 0 on success, 1 if any warnings encountered.
5179 5185 """
5180 5186
5181 5187 after, force = opts.get('after'), opts.get('force')
5182 5188 if not pats and not after:
5183 5189 raise util.Abort(_('no files specified'))
5184 5190
5185 5191 m = scmutil.match(repo[None], pats, opts)
5186 5192 subrepos = opts.get('subrepos')
5187 5193 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5188 5194
5189 5195 @command('rename|move|mv',
5190 5196 [('A', 'after', None, _('record a rename that has already occurred')),
5191 5197 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5192 5198 ] + walkopts + dryrunopts,
5193 5199 _('[OPTION]... SOURCE... DEST'))
5194 5200 def rename(ui, repo, *pats, **opts):
5195 5201 """rename files; equivalent of copy + remove
5196 5202
5197 5203 Mark dest as copies of sources; mark sources for deletion. If dest
5198 5204 is a directory, copies are put in that directory. If dest is a
5199 5205 file, there can only be one source.
5200 5206
5201 5207 By default, this command copies the contents of files as they
5202 5208 exist in the working directory. If invoked with -A/--after, the
5203 5209 operation is recorded, but no copying is performed.
5204 5210
5205 5211 This command takes effect at the next commit. To undo a rename
5206 5212 before that, see :hg:`revert`.
5207 5213
5208 5214 Returns 0 on success, 1 if errors are encountered.
5209 5215 """
5210 5216 wlock = repo.wlock(False)
5211 5217 try:
5212 5218 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5213 5219 finally:
5214 5220 wlock.release()
5215 5221
5216 5222 @command('resolve',
5217 5223 [('a', 'all', None, _('select all unresolved files')),
5218 5224 ('l', 'list', None, _('list state of files needing merge')),
5219 5225 ('m', 'mark', None, _('mark files as resolved')),
5220 5226 ('u', 'unmark', None, _('mark files as unresolved')),
5221 5227 ('n', 'no-status', None, _('hide status prefix'))]
5222 5228 + mergetoolopts + walkopts,
5223 5229 _('[OPTION]... [FILE]...'),
5224 5230 inferrepo=True)
5225 5231 def resolve(ui, repo, *pats, **opts):
5226 5232 """redo merges or set/view the merge status of files
5227 5233
5228 5234 Merges with unresolved conflicts are often the result of
5229 5235 non-interactive merging using the ``internal:merge`` configuration
5230 5236 setting, or a command-line merge tool like ``diff3``. The resolve
5231 5237 command is used to manage the files involved in a merge, after
5232 5238 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5233 5239 working directory must have two parents). See :hg:`help
5234 5240 merge-tools` for information on configuring merge tools.
5235 5241
5236 5242 The resolve command can be used in the following ways:
5237 5243
5238 5244 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5239 5245 files, discarding any previous merge attempts. Re-merging is not
5240 5246 performed for files already marked as resolved. Use ``--all/-a``
5241 5247 to select all unresolved files. ``--tool`` can be used to specify
5242 5248 the merge tool used for the given files. It overrides the HGMERGE
5243 5249 environment variable and your configuration files. Previous file
5244 5250 contents are saved with a ``.orig`` suffix.
5245 5251
5246 5252 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5247 5253 (e.g. after having manually fixed-up the files). The default is
5248 5254 to mark all unresolved files.
5249 5255
5250 5256 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5251 5257 default is to mark all resolved files.
5252 5258
5253 5259 - :hg:`resolve -l`: list files which had or still have conflicts.
5254 5260 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5255 5261
5256 5262 Note that Mercurial will not let you commit files with unresolved
5257 5263 merge conflicts. You must use :hg:`resolve -m ...` before you can
5258 5264 commit after a conflicting merge.
5259 5265
5260 5266 Returns 0 on success, 1 if any files fail a resolve attempt.
5261 5267 """
5262 5268
5263 5269 all, mark, unmark, show, nostatus = \
5264 5270 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5265 5271
5266 5272 if (show and (mark or unmark)) or (mark and unmark):
5267 5273 raise util.Abort(_("too many options specified"))
5268 5274 if pats and all:
5269 5275 raise util.Abort(_("can't specify --all and patterns"))
5270 5276 if not (all or pats or show or mark or unmark):
5271 5277 raise util.Abort(_('no files or directories specified'),
5272 5278 hint=('use --all to remerge all files'))
5273 5279
5274 5280 wlock = repo.wlock()
5275 5281 try:
5276 5282 ms = mergemod.mergestate(repo)
5277 5283
5278 5284 if not (ms.active() or repo.dirstate.p2() != nullid) and not show:
5279 5285 raise util.Abort(
5280 5286 _('resolve command not applicable when not merging'))
5281 5287
5282 5288 m = scmutil.match(repo[None], pats, opts)
5283 5289 ret = 0
5284 5290 didwork = False
5285 5291
5286 5292 for f in ms:
5287 5293 if not m(f):
5288 5294 continue
5289 5295
5290 5296 didwork = True
5291 5297
5292 5298 if show:
5293 5299 if nostatus:
5294 5300 ui.write("%s\n" % f)
5295 5301 else:
5296 5302 ui.write("%s %s\n" % (ms[f].upper(), f),
5297 5303 label='resolve.' +
5298 5304 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5299 5305 elif mark:
5300 5306 ms.mark(f, "r")
5301 5307 elif unmark:
5302 5308 ms.mark(f, "u")
5303 5309 else:
5304 5310 wctx = repo[None]
5305 5311
5306 5312 # backup pre-resolve (merge uses .orig for its own purposes)
5307 5313 a = repo.wjoin(f)
5308 5314 util.copyfile(a, a + ".resolve")
5309 5315
5310 5316 try:
5311 5317 # resolve file
5312 5318 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5313 5319 'resolve')
5314 5320 if ms.resolve(f, wctx):
5315 5321 ret = 1
5316 5322 finally:
5317 5323 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5318 5324 ms.commit()
5319 5325
5320 5326 # replace filemerge's .orig file with our resolve file
5321 5327 util.rename(a + ".resolve", a + ".orig")
5322 5328
5323 5329 ms.commit()
5324 5330
5325 5331 if not didwork and pats:
5326 5332 ui.warn(_("arguments do not match paths that need resolving\n"))
5327 5333
5328 5334 finally:
5329 5335 wlock.release()
5330 5336
5331 5337 # Nudge users into finishing an unfinished operation. We don't print
5332 5338 # this with the list/show operation because we want list/show to remain
5333 5339 # machine readable.
5334 5340 if not list(ms.unresolved()) and not show:
5335 5341 ui.status(_('(no more unresolved files)\n'))
5336 5342
5337 5343 return ret
5338 5344
5339 5345 @command('revert',
5340 5346 [('a', 'all', None, _('revert all changes when no arguments given')),
5341 5347 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5342 5348 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5343 5349 ('C', 'no-backup', None, _('do not save backup copies of files')),
5344 5350 ] + walkopts + dryrunopts,
5345 5351 _('[OPTION]... [-r REV] [NAME]...'))
5346 5352 def revert(ui, repo, *pats, **opts):
5347 5353 """restore files to their checkout state
5348 5354
5349 5355 .. note::
5350 5356
5351 5357 To check out earlier revisions, you should use :hg:`update REV`.
5352 5358 To cancel an uncommitted merge (and lose your changes),
5353 5359 use :hg:`update --clean .`.
5354 5360
5355 5361 With no revision specified, revert the specified files or directories
5356 5362 to the contents they had in the parent of the working directory.
5357 5363 This restores the contents of files to an unmodified
5358 5364 state and unschedules adds, removes, copies, and renames. If the
5359 5365 working directory has two parents, you must explicitly specify a
5360 5366 revision.
5361 5367
5362 5368 Using the -r/--rev or -d/--date options, revert the given files or
5363 5369 directories to their states as of a specific revision. Because
5364 5370 revert does not change the working directory parents, this will
5365 5371 cause these files to appear modified. This can be helpful to "back
5366 5372 out" some or all of an earlier change. See :hg:`backout` for a
5367 5373 related method.
5368 5374
5369 5375 Modified files are saved with a .orig suffix before reverting.
5370 5376 To disable these backups, use --no-backup.
5371 5377
5372 5378 See :hg:`help dates` for a list of formats valid for -d/--date.
5373 5379
5374 5380 Returns 0 on success.
5375 5381 """
5376 5382
5377 5383 if opts.get("date"):
5378 5384 if opts.get("rev"):
5379 5385 raise util.Abort(_("you can't specify a revision and a date"))
5380 5386 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5381 5387
5382 5388 parent, p2 = repo.dirstate.parents()
5383 5389 if not opts.get('rev') and p2 != nullid:
5384 5390 # revert after merge is a trap for new users (issue2915)
5385 5391 raise util.Abort(_('uncommitted merge with no revision specified'),
5386 5392 hint=_('use "hg update" or see "hg help revert"'))
5387 5393
5388 5394 ctx = scmutil.revsingle(repo, opts.get('rev'))
5389 5395
5390 5396 if not pats and not opts.get('all'):
5391 5397 msg = _("no files or directories specified")
5392 5398 if p2 != nullid:
5393 5399 hint = _("uncommitted merge, use --all to discard all changes,"
5394 5400 " or 'hg update -C .' to abort the merge")
5395 5401 raise util.Abort(msg, hint=hint)
5396 5402 dirty = util.any(repo.status())
5397 5403 node = ctx.node()
5398 5404 if node != parent:
5399 5405 if dirty:
5400 5406 hint = _("uncommitted changes, use --all to discard all"
5401 5407 " changes, or 'hg update %s' to update") % ctx.rev()
5402 5408 else:
5403 5409 hint = _("use --all to revert all files,"
5404 5410 " or 'hg update %s' to update") % ctx.rev()
5405 5411 elif dirty:
5406 5412 hint = _("uncommitted changes, use --all to discard all changes")
5407 5413 else:
5408 5414 hint = _("use --all to revert all files")
5409 5415 raise util.Abort(msg, hint=hint)
5410 5416
5411 5417 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5412 5418
5413 5419 @command('rollback', dryrunopts +
5414 5420 [('f', 'force', False, _('ignore safety measures'))])
5415 5421 def rollback(ui, repo, **opts):
5416 5422 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5417 5423
5418 5424 Please use :hg:`commit --amend` instead of rollback to correct
5419 5425 mistakes in the last commit.
5420 5426
5421 5427 This command should be used with care. There is only one level of
5422 5428 rollback, and there is no way to undo a rollback. It will also
5423 5429 restore the dirstate at the time of the last transaction, losing
5424 5430 any dirstate changes since that time. This command does not alter
5425 5431 the working directory.
5426 5432
5427 5433 Transactions are used to encapsulate the effects of all commands
5428 5434 that create new changesets or propagate existing changesets into a
5429 5435 repository.
5430 5436
5431 5437 .. container:: verbose
5432 5438
5433 5439 For example, the following commands are transactional, and their
5434 5440 effects can be rolled back:
5435 5441
5436 5442 - commit
5437 5443 - import
5438 5444 - pull
5439 5445 - push (with this repository as the destination)
5440 5446 - unbundle
5441 5447
5442 5448 To avoid permanent data loss, rollback will refuse to rollback a
5443 5449 commit transaction if it isn't checked out. Use --force to
5444 5450 override this protection.
5445 5451
5446 5452 This command is not intended for use on public repositories. Once
5447 5453 changes are visible for pull by other users, rolling a transaction
5448 5454 back locally is ineffective (someone else may already have pulled
5449 5455 the changes). Furthermore, a race is possible with readers of the
5450 5456 repository; for example an in-progress pull from the repository
5451 5457 may fail if a rollback is performed.
5452 5458
5453 5459 Returns 0 on success, 1 if no rollback data is available.
5454 5460 """
5455 5461 return repo.rollback(dryrun=opts.get('dry_run'),
5456 5462 force=opts.get('force'))
5457 5463
5458 5464 @command('root', [])
5459 5465 def root(ui, repo):
5460 5466 """print the root (top) of the current working directory
5461 5467
5462 5468 Print the root directory of the current repository.
5463 5469
5464 5470 Returns 0 on success.
5465 5471 """
5466 5472 ui.write(repo.root + "\n")
5467 5473
5468 5474 @command('^serve',
5469 5475 [('A', 'accesslog', '', _('name of access log file to write to'),
5470 5476 _('FILE')),
5471 5477 ('d', 'daemon', None, _('run server in background')),
5472 5478 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5473 5479 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5474 5480 # use string type, then we can check if something was passed
5475 5481 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5476 5482 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5477 5483 _('ADDR')),
5478 5484 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5479 5485 _('PREFIX')),
5480 5486 ('n', 'name', '',
5481 5487 _('name to show in web pages (default: working directory)'), _('NAME')),
5482 5488 ('', 'web-conf', '',
5483 5489 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5484 5490 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5485 5491 _('FILE')),
5486 5492 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5487 5493 ('', 'stdio', None, _('for remote clients')),
5488 5494 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5489 5495 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5490 5496 ('', 'style', '', _('template style to use'), _('STYLE')),
5491 5497 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5492 5498 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5493 5499 _('[OPTION]...'),
5494 5500 optionalrepo=True)
5495 5501 def serve(ui, repo, **opts):
5496 5502 """start stand-alone webserver
5497 5503
5498 5504 Start a local HTTP repository browser and pull server. You can use
5499 5505 this for ad-hoc sharing and browsing of repositories. It is
5500 5506 recommended to use a real web server to serve a repository for
5501 5507 longer periods of time.
5502 5508
5503 5509 Please note that the server does not implement access control.
5504 5510 This means that, by default, anybody can read from the server and
5505 5511 nobody can write to it by default. Set the ``web.allow_push``
5506 5512 option to ``*`` to allow everybody to push to the server. You
5507 5513 should use a real web server if you need to authenticate users.
5508 5514
5509 5515 By default, the server logs accesses to stdout and errors to
5510 5516 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5511 5517 files.
5512 5518
5513 5519 To have the server choose a free port number to listen on, specify
5514 5520 a port number of 0; in this case, the server will print the port
5515 5521 number it uses.
5516 5522
5517 5523 Returns 0 on success.
5518 5524 """
5519 5525
5520 5526 if opts["stdio"] and opts["cmdserver"]:
5521 5527 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5522 5528
5523 5529 if opts["stdio"]:
5524 5530 if repo is None:
5525 5531 raise error.RepoError(_("there is no Mercurial repository here"
5526 5532 " (.hg not found)"))
5527 5533 s = sshserver.sshserver(ui, repo)
5528 5534 s.serve_forever()
5529 5535
5530 5536 if opts["cmdserver"]:
5531 5537 service = commandserver.createservice(ui, repo, opts)
5532 5538 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5533 5539
5534 5540 # this way we can check if something was given in the command-line
5535 5541 if opts.get('port'):
5536 5542 opts['port'] = util.getport(opts.get('port'))
5537 5543
5538 5544 baseui = repo and repo.baseui or ui
5539 5545 optlist = ("name templates style address port prefix ipv6"
5540 5546 " accesslog errorlog certificate encoding")
5541 5547 for o in optlist.split():
5542 5548 val = opts.get(o, '')
5543 5549 if val in (None, ''): # should check against default options instead
5544 5550 continue
5545 5551 baseui.setconfig("web", o, val, 'serve')
5546 5552 if repo and repo.ui != baseui:
5547 5553 repo.ui.setconfig("web", o, val, 'serve')
5548 5554
5549 5555 o = opts.get('web_conf') or opts.get('webdir_conf')
5550 5556 if not o:
5551 5557 if not repo:
5552 5558 raise error.RepoError(_("there is no Mercurial repository"
5553 5559 " here (.hg not found)"))
5554 5560 o = repo
5555 5561
5556 5562 app = hgweb.hgweb(o, baseui=baseui)
5557 5563 service = httpservice(ui, app, opts)
5558 5564 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5559 5565
5560 5566 class httpservice(object):
5561 5567 def __init__(self, ui, app, opts):
5562 5568 self.ui = ui
5563 5569 self.app = app
5564 5570 self.opts = opts
5565 5571
5566 5572 def init(self):
5567 5573 util.setsignalhandler()
5568 5574 self.httpd = hgweb_server.create_server(self.ui, self.app)
5569 5575
5570 5576 if self.opts['port'] and not self.ui.verbose:
5571 5577 return
5572 5578
5573 5579 if self.httpd.prefix:
5574 5580 prefix = self.httpd.prefix.strip('/') + '/'
5575 5581 else:
5576 5582 prefix = ''
5577 5583
5578 5584 port = ':%d' % self.httpd.port
5579 5585 if port == ':80':
5580 5586 port = ''
5581 5587
5582 5588 bindaddr = self.httpd.addr
5583 5589 if bindaddr == '0.0.0.0':
5584 5590 bindaddr = '*'
5585 5591 elif ':' in bindaddr: # IPv6
5586 5592 bindaddr = '[%s]' % bindaddr
5587 5593
5588 5594 fqaddr = self.httpd.fqaddr
5589 5595 if ':' in fqaddr:
5590 5596 fqaddr = '[%s]' % fqaddr
5591 5597 if self.opts['port']:
5592 5598 write = self.ui.status
5593 5599 else:
5594 5600 write = self.ui.write
5595 5601 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5596 5602 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5597 5603 self.ui.flush() # avoid buffering of status message
5598 5604
5599 5605 def run(self):
5600 5606 self.httpd.serve_forever()
5601 5607
5602 5608
5603 5609 @command('^status|st',
5604 5610 [('A', 'all', None, _('show status of all files')),
5605 5611 ('m', 'modified', None, _('show only modified files')),
5606 5612 ('a', 'added', None, _('show only added files')),
5607 5613 ('r', 'removed', None, _('show only removed files')),
5608 5614 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5609 5615 ('c', 'clean', None, _('show only files without changes')),
5610 5616 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5611 5617 ('i', 'ignored', None, _('show only ignored files')),
5612 5618 ('n', 'no-status', None, _('hide status prefix')),
5613 5619 ('C', 'copies', None, _('show source of copied files')),
5614 5620 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5615 5621 ('', 'rev', [], _('show difference from revision'), _('REV')),
5616 5622 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5617 5623 ] + walkopts + subrepoopts + formatteropts,
5618 5624 _('[OPTION]... [FILE]...'),
5619 5625 inferrepo=True)
5620 5626 def status(ui, repo, *pats, **opts):
5621 5627 """show changed files in the working directory
5622 5628
5623 5629 Show status of files in the repository. If names are given, only
5624 5630 files that match are shown. Files that are clean or ignored or
5625 5631 the source of a copy/move operation, are not listed unless
5626 5632 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5627 5633 Unless options described with "show only ..." are given, the
5628 5634 options -mardu are used.
5629 5635
5630 5636 Option -q/--quiet hides untracked (unknown and ignored) files
5631 5637 unless explicitly requested with -u/--unknown or -i/--ignored.
5632 5638
5633 5639 .. note::
5634 5640
5635 5641 status may appear to disagree with diff if permissions have
5636 5642 changed or a merge has occurred. The standard diff format does
5637 5643 not report permission changes and diff only reports changes
5638 5644 relative to one merge parent.
5639 5645
5640 5646 If one revision is given, it is used as the base revision.
5641 5647 If two revisions are given, the differences between them are
5642 5648 shown. The --change option can also be used as a shortcut to list
5643 5649 the changed files of a revision from its first parent.
5644 5650
5645 5651 The codes used to show the status of files are::
5646 5652
5647 5653 M = modified
5648 5654 A = added
5649 5655 R = removed
5650 5656 C = clean
5651 5657 ! = missing (deleted by non-hg command, but still tracked)
5652 5658 ? = not tracked
5653 5659 I = ignored
5654 5660 = origin of the previous file (with --copies)
5655 5661
5656 5662 .. container:: verbose
5657 5663
5658 5664 Examples:
5659 5665
5660 5666 - show changes in the working directory relative to a
5661 5667 changeset::
5662 5668
5663 5669 hg status --rev 9353
5664 5670
5665 5671 - show all changes including copies in an existing changeset::
5666 5672
5667 5673 hg status --copies --change 9353
5668 5674
5669 5675 - get a NUL separated list of added files, suitable for xargs::
5670 5676
5671 5677 hg status -an0
5672 5678
5673 5679 Returns 0 on success.
5674 5680 """
5675 5681
5676 5682 revs = opts.get('rev')
5677 5683 change = opts.get('change')
5678 5684
5679 5685 if revs and change:
5680 5686 msg = _('cannot specify --rev and --change at the same time')
5681 5687 raise util.Abort(msg)
5682 5688 elif change:
5683 5689 node2 = scmutil.revsingle(repo, change, None).node()
5684 5690 node1 = repo[node2].p1().node()
5685 5691 else:
5686 5692 node1, node2 = scmutil.revpair(repo, revs)
5687 5693
5688 5694 cwd = (pats and repo.getcwd()) or ''
5689 5695 end = opts.get('print0') and '\0' or '\n'
5690 5696 copy = {}
5691 5697 states = 'modified added removed deleted unknown ignored clean'.split()
5692 5698 show = [k for k in states if opts.get(k)]
5693 5699 if opts.get('all'):
5694 5700 show += ui.quiet and (states[:4] + ['clean']) or states
5695 5701 if not show:
5696 5702 show = ui.quiet and states[:4] or states[:5]
5697 5703
5698 5704 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5699 5705 'ignored' in show, 'clean' in show, 'unknown' in show,
5700 5706 opts.get('subrepos'))
5701 5707 changestates = zip(states, 'MAR!?IC', stat)
5702 5708
5703 5709 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5704 5710 copy = copies.pathcopies(repo[node1], repo[node2])
5705 5711
5706 5712 fm = ui.formatter('status', opts)
5707 5713 fmt = '%s' + end
5708 5714 showchar = not opts.get('no_status')
5709 5715
5710 5716 for state, char, files in changestates:
5711 5717 if state in show:
5712 5718 label = 'status.' + state
5713 5719 for f in files:
5714 5720 fm.startitem()
5715 5721 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5716 5722 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5717 5723 if f in copy:
5718 5724 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5719 5725 label='status.copied')
5720 5726 fm.end()
5721 5727
5722 5728 @command('^summary|sum',
5723 5729 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5724 5730 def summary(ui, repo, **opts):
5725 5731 """summarize working directory state
5726 5732
5727 5733 This generates a brief summary of the working directory state,
5728 5734 including parents, branch, commit status, and available updates.
5729 5735
5730 5736 With the --remote option, this will check the default paths for
5731 5737 incoming and outgoing changes. This can be time-consuming.
5732 5738
5733 5739 Returns 0 on success.
5734 5740 """
5735 5741
5736 5742 ctx = repo[None]
5737 5743 parents = ctx.parents()
5738 5744 pnode = parents[0].node()
5739 5745 marks = []
5740 5746
5741 5747 for p in parents:
5742 5748 # label with log.changeset (instead of log.parent) since this
5743 5749 # shows a working directory parent *changeset*:
5744 5750 # i18n: column positioning for "hg summary"
5745 5751 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5746 5752 label='log.changeset changeset.%s' % p.phasestr())
5747 5753 ui.write(' '.join(p.tags()), label='log.tag')
5748 5754 if p.bookmarks():
5749 5755 marks.extend(p.bookmarks())
5750 5756 if p.rev() == -1:
5751 5757 if not len(repo):
5752 5758 ui.write(_(' (empty repository)'))
5753 5759 else:
5754 5760 ui.write(_(' (no revision checked out)'))
5755 5761 ui.write('\n')
5756 5762 if p.description():
5757 5763 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5758 5764 label='log.summary')
5759 5765
5760 5766 branch = ctx.branch()
5761 5767 bheads = repo.branchheads(branch)
5762 5768 # i18n: column positioning for "hg summary"
5763 5769 m = _('branch: %s\n') % branch
5764 5770 if branch != 'default':
5765 5771 ui.write(m, label='log.branch')
5766 5772 else:
5767 5773 ui.status(m, label='log.branch')
5768 5774
5769 5775 if marks:
5770 5776 current = repo._bookmarkcurrent
5771 5777 # i18n: column positioning for "hg summary"
5772 5778 ui.write(_('bookmarks:'), label='log.bookmark')
5773 5779 if current is not None:
5774 5780 if current in marks:
5775 5781 ui.write(' *' + current, label='bookmarks.current')
5776 5782 marks.remove(current)
5777 5783 else:
5778 5784 ui.write(' [%s]' % current, label='bookmarks.current')
5779 5785 for m in marks:
5780 5786 ui.write(' ' + m, label='log.bookmark')
5781 5787 ui.write('\n', label='log.bookmark')
5782 5788
5783 5789 status = repo.status(unknown=True)
5784 5790
5785 5791 c = repo.dirstate.copies()
5786 5792 copied, renamed = [], []
5787 5793 for d, s in c.iteritems():
5788 5794 if s in status.removed:
5789 5795 status.removed.remove(s)
5790 5796 renamed.append(d)
5791 5797 else:
5792 5798 copied.append(d)
5793 5799 if d in status.added:
5794 5800 status.added.remove(d)
5795 5801
5796 5802 ms = mergemod.mergestate(repo)
5797 5803 unresolved = [f for f in ms if ms[f] == 'u']
5798 5804
5799 5805 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5800 5806
5801 5807 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5802 5808 (ui.label(_('%d added'), 'status.added'), status.added),
5803 5809 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5804 5810 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5805 5811 (ui.label(_('%d copied'), 'status.copied'), copied),
5806 5812 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5807 5813 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5808 5814 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5809 5815 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5810 5816 t = []
5811 5817 for l, s in labels:
5812 5818 if s:
5813 5819 t.append(l % len(s))
5814 5820
5815 5821 t = ', '.join(t)
5816 5822 cleanworkdir = False
5817 5823
5818 5824 if repo.vfs.exists('updatestate'):
5819 5825 t += _(' (interrupted update)')
5820 5826 elif len(parents) > 1:
5821 5827 t += _(' (merge)')
5822 5828 elif branch != parents[0].branch():
5823 5829 t += _(' (new branch)')
5824 5830 elif (parents[0].closesbranch() and
5825 5831 pnode in repo.branchheads(branch, closed=True)):
5826 5832 t += _(' (head closed)')
5827 5833 elif not (status.modified or status.added or status.removed or renamed or
5828 5834 copied or subs):
5829 5835 t += _(' (clean)')
5830 5836 cleanworkdir = True
5831 5837 elif pnode not in bheads:
5832 5838 t += _(' (new branch head)')
5833 5839
5834 5840 if cleanworkdir:
5835 5841 # i18n: column positioning for "hg summary"
5836 5842 ui.status(_('commit: %s\n') % t.strip())
5837 5843 else:
5838 5844 # i18n: column positioning for "hg summary"
5839 5845 ui.write(_('commit: %s\n') % t.strip())
5840 5846
5841 5847 # all ancestors of branch heads - all ancestors of parent = new csets
5842 5848 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5843 5849 bheads))
5844 5850
5845 5851 if new == 0:
5846 5852 # i18n: column positioning for "hg summary"
5847 5853 ui.status(_('update: (current)\n'))
5848 5854 elif pnode not in bheads:
5849 5855 # i18n: column positioning for "hg summary"
5850 5856 ui.write(_('update: %d new changesets (update)\n') % new)
5851 5857 else:
5852 5858 # i18n: column positioning for "hg summary"
5853 5859 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5854 5860 (new, len(bheads)))
5855 5861
5856 5862 cmdutil.summaryhooks(ui, repo)
5857 5863
5858 5864 if opts.get('remote'):
5859 5865 needsincoming, needsoutgoing = True, True
5860 5866 else:
5861 5867 needsincoming, needsoutgoing = False, False
5862 5868 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5863 5869 if i:
5864 5870 needsincoming = True
5865 5871 if o:
5866 5872 needsoutgoing = True
5867 5873 if not needsincoming and not needsoutgoing:
5868 5874 return
5869 5875
5870 5876 def getincoming():
5871 5877 source, branches = hg.parseurl(ui.expandpath('default'))
5872 5878 sbranch = branches[0]
5873 5879 try:
5874 5880 other = hg.peer(repo, {}, source)
5875 5881 except error.RepoError:
5876 5882 if opts.get('remote'):
5877 5883 raise
5878 5884 return source, sbranch, None, None, None
5879 5885 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5880 5886 if revs:
5881 5887 revs = [other.lookup(rev) for rev in revs]
5882 5888 ui.debug('comparing with %s\n' % util.hidepassword(source))
5883 5889 repo.ui.pushbuffer()
5884 5890 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5885 5891 repo.ui.popbuffer()
5886 5892 return source, sbranch, other, commoninc, commoninc[1]
5887 5893
5888 5894 if needsincoming:
5889 5895 source, sbranch, sother, commoninc, incoming = getincoming()
5890 5896 else:
5891 5897 source = sbranch = sother = commoninc = incoming = None
5892 5898
5893 5899 def getoutgoing():
5894 5900 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5895 5901 dbranch = branches[0]
5896 5902 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5897 5903 if source != dest:
5898 5904 try:
5899 5905 dother = hg.peer(repo, {}, dest)
5900 5906 except error.RepoError:
5901 5907 if opts.get('remote'):
5902 5908 raise
5903 5909 return dest, dbranch, None, None
5904 5910 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5905 5911 elif sother is None:
5906 5912 # there is no explicit destination peer, but source one is invalid
5907 5913 return dest, dbranch, None, None
5908 5914 else:
5909 5915 dother = sother
5910 5916 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5911 5917 common = None
5912 5918 else:
5913 5919 common = commoninc
5914 5920 if revs:
5915 5921 revs = [repo.lookup(rev) for rev in revs]
5916 5922 repo.ui.pushbuffer()
5917 5923 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5918 5924 commoninc=common)
5919 5925 repo.ui.popbuffer()
5920 5926 return dest, dbranch, dother, outgoing
5921 5927
5922 5928 if needsoutgoing:
5923 5929 dest, dbranch, dother, outgoing = getoutgoing()
5924 5930 else:
5925 5931 dest = dbranch = dother = outgoing = None
5926 5932
5927 5933 if opts.get('remote'):
5928 5934 t = []
5929 5935 if incoming:
5930 5936 t.append(_('1 or more incoming'))
5931 5937 o = outgoing.missing
5932 5938 if o:
5933 5939 t.append(_('%d outgoing') % len(o))
5934 5940 other = dother or sother
5935 5941 if 'bookmarks' in other.listkeys('namespaces'):
5936 5942 lmarks = repo.listkeys('bookmarks')
5937 5943 rmarks = other.listkeys('bookmarks')
5938 5944 diff = set(rmarks) - set(lmarks)
5939 5945 if len(diff) > 0:
5940 5946 t.append(_('%d incoming bookmarks') % len(diff))
5941 5947 diff = set(lmarks) - set(rmarks)
5942 5948 if len(diff) > 0:
5943 5949 t.append(_('%d outgoing bookmarks') % len(diff))
5944 5950
5945 5951 if t:
5946 5952 # i18n: column positioning for "hg summary"
5947 5953 ui.write(_('remote: %s\n') % (', '.join(t)))
5948 5954 else:
5949 5955 # i18n: column positioning for "hg summary"
5950 5956 ui.status(_('remote: (synced)\n'))
5951 5957
5952 5958 cmdutil.summaryremotehooks(ui, repo, opts,
5953 5959 ((source, sbranch, sother, commoninc),
5954 5960 (dest, dbranch, dother, outgoing)))
5955 5961
5956 5962 @command('tag',
5957 5963 [('f', 'force', None, _('force tag')),
5958 5964 ('l', 'local', None, _('make the tag local')),
5959 5965 ('r', 'rev', '', _('revision to tag'), _('REV')),
5960 5966 ('', 'remove', None, _('remove a tag')),
5961 5967 # -l/--local is already there, commitopts cannot be used
5962 5968 ('e', 'edit', None, _('invoke editor on commit messages')),
5963 5969 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5964 5970 ] + commitopts2,
5965 5971 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5966 5972 def tag(ui, repo, name1, *names, **opts):
5967 5973 """add one or more tags for the current or given revision
5968 5974
5969 5975 Name a particular revision using <name>.
5970 5976
5971 5977 Tags are used to name particular revisions of the repository and are
5972 5978 very useful to compare different revisions, to go back to significant
5973 5979 earlier versions or to mark branch points as releases, etc. Changing
5974 5980 an existing tag is normally disallowed; use -f/--force to override.
5975 5981
5976 5982 If no revision is given, the parent of the working directory is
5977 5983 used.
5978 5984
5979 5985 To facilitate version control, distribution, and merging of tags,
5980 5986 they are stored as a file named ".hgtags" which is managed similarly
5981 5987 to other project files and can be hand-edited if necessary. This
5982 5988 also means that tagging creates a new commit. The file
5983 5989 ".hg/localtags" is used for local tags (not shared among
5984 5990 repositories).
5985 5991
5986 5992 Tag commits are usually made at the head of a branch. If the parent
5987 5993 of the working directory is not a branch head, :hg:`tag` aborts; use
5988 5994 -f/--force to force the tag commit to be based on a non-head
5989 5995 changeset.
5990 5996
5991 5997 See :hg:`help dates` for a list of formats valid for -d/--date.
5992 5998
5993 5999 Since tag names have priority over branch names during revision
5994 6000 lookup, using an existing branch name as a tag name is discouraged.
5995 6001
5996 6002 Returns 0 on success.
5997 6003 """
5998 6004 wlock = lock = None
5999 6005 try:
6000 6006 wlock = repo.wlock()
6001 6007 lock = repo.lock()
6002 6008 rev_ = "."
6003 6009 names = [t.strip() for t in (name1,) + names]
6004 6010 if len(names) != len(set(names)):
6005 6011 raise util.Abort(_('tag names must be unique'))
6006 6012 for n in names:
6007 6013 scmutil.checknewlabel(repo, n, 'tag')
6008 6014 if not n:
6009 6015 raise util.Abort(_('tag names cannot consist entirely of '
6010 6016 'whitespace'))
6011 6017 if opts.get('rev') and opts.get('remove'):
6012 6018 raise util.Abort(_("--rev and --remove are incompatible"))
6013 6019 if opts.get('rev'):
6014 6020 rev_ = opts['rev']
6015 6021 message = opts.get('message')
6016 6022 if opts.get('remove'):
6017 6023 expectedtype = opts.get('local') and 'local' or 'global'
6018 6024 for n in names:
6019 6025 if not repo.tagtype(n):
6020 6026 raise util.Abort(_("tag '%s' does not exist") % n)
6021 6027 if repo.tagtype(n) != expectedtype:
6022 6028 if expectedtype == 'global':
6023 6029 raise util.Abort(_("tag '%s' is not a global tag") % n)
6024 6030 else:
6025 6031 raise util.Abort(_("tag '%s' is not a local tag") % n)
6026 6032 rev_ = nullid
6027 6033 if not message:
6028 6034 # we don't translate commit messages
6029 6035 message = 'Removed tag %s' % ', '.join(names)
6030 6036 elif not opts.get('force'):
6031 6037 for n in names:
6032 6038 if n in repo.tags():
6033 6039 raise util.Abort(_("tag '%s' already exists "
6034 6040 "(use -f to force)") % n)
6035 6041 if not opts.get('local'):
6036 6042 p1, p2 = repo.dirstate.parents()
6037 6043 if p2 != nullid:
6038 6044 raise util.Abort(_('uncommitted merge'))
6039 6045 bheads = repo.branchheads()
6040 6046 if not opts.get('force') and bheads and p1 not in bheads:
6041 6047 raise util.Abort(_('not at a branch head (use -f to force)'))
6042 6048 r = scmutil.revsingle(repo, rev_).node()
6043 6049
6044 6050 if not message:
6045 6051 # we don't translate commit messages
6046 6052 message = ('Added tag %s for changeset %s' %
6047 6053 (', '.join(names), short(r)))
6048 6054
6049 6055 date = opts.get('date')
6050 6056 if date:
6051 6057 date = util.parsedate(date)
6052 6058
6053 6059 if opts.get('remove'):
6054 6060 editform = 'tag.remove'
6055 6061 else:
6056 6062 editform = 'tag.add'
6057 6063 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6058 6064
6059 6065 # don't allow tagging the null rev
6060 6066 if (not opts.get('remove') and
6061 6067 scmutil.revsingle(repo, rev_).rev() == nullrev):
6062 6068 raise util.Abort(_("cannot tag null revision"))
6063 6069
6064 6070 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6065 6071 editor=editor)
6066 6072 finally:
6067 6073 release(lock, wlock)
6068 6074
6069 6075 @command('tags', formatteropts, '')
6070 6076 def tags(ui, repo, **opts):
6071 6077 """list repository tags
6072 6078
6073 6079 This lists both regular and local tags. When the -v/--verbose
6074 6080 switch is used, a third column "local" is printed for local tags.
6075 6081
6076 6082 Returns 0 on success.
6077 6083 """
6078 6084
6079 6085 fm = ui.formatter('tags', opts)
6080 6086 hexfunc = fm.hexfunc
6081 6087 tagtype = ""
6082 6088
6083 6089 for t, n in reversed(repo.tagslist()):
6084 6090 hn = hexfunc(n)
6085 6091 label = 'tags.normal'
6086 6092 tagtype = ''
6087 6093 if repo.tagtype(t) == 'local':
6088 6094 label = 'tags.local'
6089 6095 tagtype = 'local'
6090 6096
6091 6097 fm.startitem()
6092 6098 fm.write('tag', '%s', t, label=label)
6093 6099 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6094 6100 fm.condwrite(not ui.quiet, 'rev node', fmt,
6095 6101 repo.changelog.rev(n), hn, label=label)
6096 6102 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6097 6103 tagtype, label=label)
6098 6104 fm.plain('\n')
6099 6105 fm.end()
6100 6106
6101 6107 @command('tip',
6102 6108 [('p', 'patch', None, _('show patch')),
6103 6109 ('g', 'git', None, _('use git extended diff format')),
6104 6110 ] + templateopts,
6105 6111 _('[-p] [-g]'))
6106 6112 def tip(ui, repo, **opts):
6107 6113 """show the tip revision (DEPRECATED)
6108 6114
6109 6115 The tip revision (usually just called the tip) is the changeset
6110 6116 most recently added to the repository (and therefore the most
6111 6117 recently changed head).
6112 6118
6113 6119 If you have just made a commit, that commit will be the tip. If
6114 6120 you have just pulled changes from another repository, the tip of
6115 6121 that repository becomes the current tip. The "tip" tag is special
6116 6122 and cannot be renamed or assigned to a different changeset.
6117 6123
6118 6124 This command is deprecated, please use :hg:`heads` instead.
6119 6125
6120 6126 Returns 0 on success.
6121 6127 """
6122 6128 displayer = cmdutil.show_changeset(ui, repo, opts)
6123 6129 displayer.show(repo['tip'])
6124 6130 displayer.close()
6125 6131
6126 6132 @command('unbundle',
6127 6133 [('u', 'update', None,
6128 6134 _('update to new branch head if changesets were unbundled'))],
6129 6135 _('[-u] FILE...'))
6130 6136 def unbundle(ui, repo, fname1, *fnames, **opts):
6131 6137 """apply one or more changegroup files
6132 6138
6133 6139 Apply one or more compressed changegroup files generated by the
6134 6140 bundle command.
6135 6141
6136 6142 Returns 0 on success, 1 if an update has unresolved files.
6137 6143 """
6138 6144 fnames = (fname1,) + fnames
6139 6145
6140 6146 lock = repo.lock()
6141 6147 try:
6142 6148 for fname in fnames:
6143 6149 f = hg.openpath(ui, fname)
6144 6150 gen = exchange.readbundle(ui, f, fname)
6145 6151 if isinstance(gen, bundle2.unbundle20):
6146 6152 tr = repo.transaction('unbundle')
6147 6153 try:
6148 6154 op = bundle2.processbundle(repo, gen, lambda: tr)
6149 6155 tr.close()
6150 6156 finally:
6151 6157 if tr:
6152 6158 tr.release()
6153 6159 changes = [r.get('result', 0)
6154 6160 for r in op.records['changegroup']]
6155 6161 modheads = changegroup.combineresults(changes)
6156 6162 else:
6157 6163 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6158 6164 'bundle:' + fname)
6159 6165 finally:
6160 6166 lock.release()
6161 6167
6162 6168 return postincoming(ui, repo, modheads, opts.get('update'), None)
6163 6169
6164 6170 @command('^update|up|checkout|co',
6165 6171 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6166 6172 ('c', 'check', None,
6167 6173 _('update across branches if no uncommitted changes')),
6168 6174 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6169 6175 ('r', 'rev', '', _('revision'), _('REV'))
6170 6176 ] + mergetoolopts,
6171 6177 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6172 6178 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6173 6179 tool=None):
6174 6180 """update working directory (or switch revisions)
6175 6181
6176 6182 Update the repository's working directory to the specified
6177 6183 changeset. If no changeset is specified, update to the tip of the
6178 6184 current named branch and move the current bookmark (see :hg:`help
6179 6185 bookmarks`).
6180 6186
6181 6187 Update sets the working directory's parent revision to the specified
6182 6188 changeset (see :hg:`help parents`).
6183 6189
6184 6190 If the changeset is not a descendant or ancestor of the working
6185 6191 directory's parent, the update is aborted. With the -c/--check
6186 6192 option, the working directory is checked for uncommitted changes; if
6187 6193 none are found, the working directory is updated to the specified
6188 6194 changeset.
6189 6195
6190 6196 .. container:: verbose
6191 6197
6192 6198 The following rules apply when the working directory contains
6193 6199 uncommitted changes:
6194 6200
6195 6201 1. If neither -c/--check nor -C/--clean is specified, and if
6196 6202 the requested changeset is an ancestor or descendant of
6197 6203 the working directory's parent, the uncommitted changes
6198 6204 are merged into the requested changeset and the merged
6199 6205 result is left uncommitted. If the requested changeset is
6200 6206 not an ancestor or descendant (that is, it is on another
6201 6207 branch), the update is aborted and the uncommitted changes
6202 6208 are preserved.
6203 6209
6204 6210 2. With the -c/--check option, the update is aborted and the
6205 6211 uncommitted changes are preserved.
6206 6212
6207 6213 3. With the -C/--clean option, uncommitted changes are discarded and
6208 6214 the working directory is updated to the requested changeset.
6209 6215
6210 6216 To cancel an uncommitted merge (and lose your changes), use
6211 6217 :hg:`update --clean .`.
6212 6218
6213 6219 Use null as the changeset to remove the working directory (like
6214 6220 :hg:`clone -U`).
6215 6221
6216 6222 If you want to revert just one file to an older revision, use
6217 6223 :hg:`revert [-r REV] NAME`.
6218 6224
6219 6225 See :hg:`help dates` for a list of formats valid for -d/--date.
6220 6226
6221 6227 Returns 0 on success, 1 if there are unresolved files.
6222 6228 """
6223 6229 if rev and node:
6224 6230 raise util.Abort(_("please specify just one revision"))
6225 6231
6226 6232 if rev is None or rev == '':
6227 6233 rev = node
6228 6234
6229 6235 cmdutil.clearunfinished(repo)
6230 6236
6231 6237 # with no argument, we also move the current bookmark, if any
6232 6238 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6233 6239
6234 6240 # if we defined a bookmark, we have to remember the original bookmark name
6235 6241 brev = rev
6236 6242 rev = scmutil.revsingle(repo, rev, rev).rev()
6237 6243
6238 6244 if check and clean:
6239 6245 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6240 6246
6241 6247 if date:
6242 6248 if rev is not None:
6243 6249 raise util.Abort(_("you can't specify a revision and a date"))
6244 6250 rev = cmdutil.finddate(ui, repo, date)
6245 6251
6246 6252 if check:
6247 6253 c = repo[None]
6248 6254 if c.dirty(merge=False, branch=False, missing=True):
6249 6255 raise util.Abort(_("uncommitted changes"))
6250 6256 if rev is None:
6251 6257 rev = repo[repo[None].branch()].rev()
6252 6258
6253 6259 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6254 6260
6255 6261 if clean:
6256 6262 ret = hg.clean(repo, rev)
6257 6263 else:
6258 6264 ret = hg.update(repo, rev)
6259 6265
6260 6266 if not ret and movemarkfrom:
6261 6267 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6262 6268 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6263 6269 elif brev in repo._bookmarks:
6264 6270 bookmarks.setcurrent(repo, brev)
6265 6271 ui.status(_("(activating bookmark %s)\n") % brev)
6266 6272 elif brev:
6267 6273 if repo._bookmarkcurrent:
6268 6274 ui.status(_("(leaving bookmark %s)\n") %
6269 6275 repo._bookmarkcurrent)
6270 6276 bookmarks.unsetcurrent(repo)
6271 6277
6272 6278 return ret
6273 6279
6274 6280 @command('verify', [])
6275 6281 def verify(ui, repo):
6276 6282 """verify the integrity of the repository
6277 6283
6278 6284 Verify the integrity of the current repository.
6279 6285
6280 6286 This will perform an extensive check of the repository's
6281 6287 integrity, validating the hashes and checksums of each entry in
6282 6288 the changelog, manifest, and tracked files, as well as the
6283 6289 integrity of their crosslinks and indices.
6284 6290
6285 6291 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6286 6292 for more information about recovery from corruption of the
6287 6293 repository.
6288 6294
6289 6295 Returns 0 on success, 1 if errors are encountered.
6290 6296 """
6291 6297 return hg.verify(repo)
6292 6298
6293 6299 @command('version', [], norepo=True)
6294 6300 def version_(ui):
6295 6301 """output version and copyright information"""
6296 6302 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6297 6303 % util.version())
6298 6304 ui.status(_(
6299 6305 "(see http://mercurial.selenic.com for more information)\n"
6300 6306 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
6301 6307 "This is free software; see the source for copying conditions. "
6302 6308 "There is NO\nwarranty; "
6303 6309 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6304 6310 ))
6305 6311
6306 6312 ui.note(_("\nEnabled extensions:\n\n"))
6307 6313 if ui.verbose:
6308 6314 # format names and versions into columns
6309 6315 names = []
6310 6316 vers = []
6311 6317 for name, module in extensions.extensions():
6312 6318 names.append(name)
6313 6319 vers.append(extensions.moduleversion(module))
6314 6320 if names:
6315 6321 maxnamelen = max(len(n) for n in names)
6316 6322 for i, name in enumerate(names):
6317 6323 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,249 +1,272 b''
1 1 #require serve
2 2
3 3 = Test the getbundle() protocol function =
4 4
5 5 Create a test repository:
6 6
7 7 $ hg init repo
8 8 $ cd repo
9 9 $ hg debugbuilddag -n -m '+2 :fork +5 :p1 *fork +6 :p2 /p1 :m1 +3' > /dev/null
10 10 $ hg log -G --template '{node}\n'
11 11 o 10c14a2cc935e1d8c31f9e98587dcf27fb08a6da
12 12 |
13 13 o 4801a72e5d88cb515b0c7e40fae34180f3f837f2
14 14 |
15 15 o 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
16 16 |
17 17 o 8365676dbab05860ce0d9110f2af51368b961bbd
18 18 |\
19 19 | o 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
20 20 | |
21 21 | o 13c0170174366b441dc68e8e33757232fa744458
22 22 | |
23 23 | o 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
24 24 | |
25 25 | o 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
26 26 | |
27 27 | o 928b5f94cdb278bb536eba552de348a4e92ef24d
28 28 | |
29 29 | o f34414c64173e0ecb61b25dc55e116dbbcc89bee
30 30 | |
31 31 | o 8931463777131cd73923e560b760061f2aa8a4bc
32 32 | |
33 33 o | 6621d79f61b23ec74cf4b69464343d9e0980ec8b
34 34 | |
35 35 o | bac16991d12ff45f9dc43c52da1946dfadb83e80
36 36 | |
37 37 o | ff42371d57168345fdf1a3aac66a51f6a45d41d2
38 38 | |
39 39 o | d5f6e1ea452285324836a49d7d3c2a63cfed1d31
40 40 | |
41 41 o | 713346a995c363120712aed1aee7e04afd867638
42 42 |/
43 43 o 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
44 44 |
45 45 o 7704483d56b2a7b5db54dcee7c62378ac629b348
46 46
47 47 $ cd ..
48 48
49 49
50 50 = Test locally =
51 51
52 52 Get everything:
53 53
54 54 $ hg debuggetbundle repo bundle
55 55 $ hg debugbundle bundle
56 56 7704483d56b2a7b5db54dcee7c62378ac629b348
57 57 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
58 58 713346a995c363120712aed1aee7e04afd867638
59 59 d5f6e1ea452285324836a49d7d3c2a63cfed1d31
60 60 ff42371d57168345fdf1a3aac66a51f6a45d41d2
61 61 bac16991d12ff45f9dc43c52da1946dfadb83e80
62 62 6621d79f61b23ec74cf4b69464343d9e0980ec8b
63 63 8931463777131cd73923e560b760061f2aa8a4bc
64 64 f34414c64173e0ecb61b25dc55e116dbbcc89bee
65 65 928b5f94cdb278bb536eba552de348a4e92ef24d
66 66 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
67 67 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
68 68 13c0170174366b441dc68e8e33757232fa744458
69 69 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
70 70 8365676dbab05860ce0d9110f2af51368b961bbd
71 71 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
72 72 4801a72e5d88cb515b0c7e40fae34180f3f837f2
73 73 10c14a2cc935e1d8c31f9e98587dcf27fb08a6da
74 74
75 75 Get part of linear run:
76 76
77 77 $ hg debuggetbundle repo bundle -H 4801a72e5d88cb515b0c7e40fae34180f3f837f2 -C 8365676dbab05860ce0d9110f2af51368b961bbd
78 78 $ hg debugbundle bundle
79 79 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
80 80 4801a72e5d88cb515b0c7e40fae34180f3f837f2
81 81
82 82 Get missing branch and merge:
83 83
84 84 $ hg debuggetbundle repo bundle -H 4801a72e5d88cb515b0c7e40fae34180f3f837f2 -C 13c0170174366b441dc68e8e33757232fa744458
85 85 $ hg debugbundle bundle
86 86 713346a995c363120712aed1aee7e04afd867638
87 87 d5f6e1ea452285324836a49d7d3c2a63cfed1d31
88 88 ff42371d57168345fdf1a3aac66a51f6a45d41d2
89 89 bac16991d12ff45f9dc43c52da1946dfadb83e80
90 90 6621d79f61b23ec74cf4b69464343d9e0980ec8b
91 91 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
92 92 8365676dbab05860ce0d9110f2af51368b961bbd
93 93 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
94 94 4801a72e5d88cb515b0c7e40fae34180f3f837f2
95 95
96 96 Get from only one head:
97 97
98 98 $ hg debuggetbundle repo bundle -H 928b5f94cdb278bb536eba552de348a4e92ef24d -C 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
99 99 $ hg debugbundle bundle
100 100 8931463777131cd73923e560b760061f2aa8a4bc
101 101 f34414c64173e0ecb61b25dc55e116dbbcc89bee
102 102 928b5f94cdb278bb536eba552de348a4e92ef24d
103 103
104 104 Get parts of two branches:
105 105
106 106 $ hg debuggetbundle repo bundle -H 13c0170174366b441dc68e8e33757232fa744458 -C 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 -H bac16991d12ff45f9dc43c52da1946dfadb83e80 -C d5f6e1ea452285324836a49d7d3c2a63cfed1d31
107 107 $ hg debugbundle bundle
108 108 ff42371d57168345fdf1a3aac66a51f6a45d41d2
109 109 bac16991d12ff45f9dc43c52da1946dfadb83e80
110 110 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
111 111 13c0170174366b441dc68e8e33757232fa744458
112 112
113 113 Check that we get all needed file changes:
114 114
115 115 $ hg debugbundle bundle --all
116 116 format: id, p1, p2, cset, delta base, len(delta)
117 117
118 118 changelog
119 119 ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 99
120 120 bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 99
121 121 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 bac16991d12ff45f9dc43c52da1946dfadb83e80 102
122 122 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 102
123 123
124 124 manifest
125 125 dac7984588fc4eea7acbf39693a9c1b06f5b175d 591f732a3faf1fb903815273f3c199a514a61ccb 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 591f732a3faf1fb903815273f3c199a514a61ccb 113
126 126 0772616e6b48a76afb6c1458e193cbb3dae2e4ff dac7984588fc4eea7acbf39693a9c1b06f5b175d 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 dac7984588fc4eea7acbf39693a9c1b06f5b175d 113
127 127 eb498cd9af6c44108e43041e951ce829e29f6c80 bff2f4817ced57b386caf7c4e3e36a4bc9af7e93 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0772616e6b48a76afb6c1458e193cbb3dae2e4ff 295
128 128 b15709c071ddd2d93188508ba156196ab4f19620 eb498cd9af6c44108e43041e951ce829e29f6c80 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 eb498cd9af6c44108e43041e951ce829e29f6c80 114
129 129
130 130 mf
131 131 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 17
132 132 c7b583de053293870e145f45bd2d61643563fd06 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 18
133 133 266ee3c0302a5a18f1cf96817ac79a51836179e9 edc0f6b8db80d68ae6aff2b19f7e5347ab68fa63 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 c7b583de053293870e145f45bd2d61643563fd06 149
134 134 698c6a36220548cd3903ca7dada27c59aa500c52 266ee3c0302a5a18f1cf96817ac79a51836179e9 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 266ee3c0302a5a18f1cf96817ac79a51836179e9 19
135 135
136 136 nf11
137 137 33fbc651630ffa7ccbebfe4eb91320a873e7291c 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 16
138 138
139 139 nf12
140 140 ddce0544363f037e9fb889faca058f52dc01c0a5 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 0000000000000000000000000000000000000000 16
141 141
142 142 nf4
143 143 3c1407305701051cbed9f9cb9a68bdfb5997c235 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 15
144 144
145 145 nf5
146 146 0dbd89c185f53a1727c54cd1ce256482fa23968e 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 0000000000000000000000000000000000000000 15
147 147
148 148 Get branch and merge:
149 149
150 150 $ hg debuggetbundle repo bundle -C 7704483d56b2a7b5db54dcee7c62378ac629b348 -H 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
151 151 $ hg debugbundle bundle
152 152 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
153 153 713346a995c363120712aed1aee7e04afd867638
154 154 d5f6e1ea452285324836a49d7d3c2a63cfed1d31
155 155 ff42371d57168345fdf1a3aac66a51f6a45d41d2
156 156 bac16991d12ff45f9dc43c52da1946dfadb83e80
157 157 6621d79f61b23ec74cf4b69464343d9e0980ec8b
158 158 8931463777131cd73923e560b760061f2aa8a4bc
159 159 f34414c64173e0ecb61b25dc55e116dbbcc89bee
160 160 928b5f94cdb278bb536eba552de348a4e92ef24d
161 161 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
162 162 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
163 163 13c0170174366b441dc68e8e33757232fa744458
164 164 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
165 165 8365676dbab05860ce0d9110f2af51368b961bbd
166 166 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
167 167
168 = Test bundle2 =
168 169
170 $ hg debuggetbundle repo bundle -t bundle2
171 $ hg debugbundle bundle
172 Stream params: {}
173 b2x:changegroup -- "{'version': '01'}"
174 7704483d56b2a7b5db54dcee7c62378ac629b348
175 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
176 713346a995c363120712aed1aee7e04afd867638
177 d5f6e1ea452285324836a49d7d3c2a63cfed1d31
178 ff42371d57168345fdf1a3aac66a51f6a45d41d2
179 bac16991d12ff45f9dc43c52da1946dfadb83e80
180 6621d79f61b23ec74cf4b69464343d9e0980ec8b
181 8931463777131cd73923e560b760061f2aa8a4bc
182 f34414c64173e0ecb61b25dc55e116dbbcc89bee
183 928b5f94cdb278bb536eba552de348a4e92ef24d
184 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
185 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
186 13c0170174366b441dc68e8e33757232fa744458
187 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
188 8365676dbab05860ce0d9110f2af51368b961bbd
189 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
190 4801a72e5d88cb515b0c7e40fae34180f3f837f2
191 10c14a2cc935e1d8c31f9e98587dcf27fb08a6da
169 192 = Test via HTTP =
170 193
171 194 Get everything:
172 195
173 196 $ hg serve -R repo -p $HGPORT -d --pid-file=hg.pid -E error.log -A access.log
174 197 $ cat hg.pid >> $DAEMON_PIDS
175 198 $ hg debuggetbundle http://localhost:$HGPORT/ bundle
176 199 $ hg debugbundle bundle
177 200 7704483d56b2a7b5db54dcee7c62378ac629b348
178 201 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
179 202 713346a995c363120712aed1aee7e04afd867638
180 203 d5f6e1ea452285324836a49d7d3c2a63cfed1d31
181 204 ff42371d57168345fdf1a3aac66a51f6a45d41d2
182 205 bac16991d12ff45f9dc43c52da1946dfadb83e80
183 206 6621d79f61b23ec74cf4b69464343d9e0980ec8b
184 207 8931463777131cd73923e560b760061f2aa8a4bc
185 208 f34414c64173e0ecb61b25dc55e116dbbcc89bee
186 209 928b5f94cdb278bb536eba552de348a4e92ef24d
187 210 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
188 211 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
189 212 13c0170174366b441dc68e8e33757232fa744458
190 213 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
191 214 8365676dbab05860ce0d9110f2af51368b961bbd
192 215 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
193 216 4801a72e5d88cb515b0c7e40fae34180f3f837f2
194 217 10c14a2cc935e1d8c31f9e98587dcf27fb08a6da
195 218
196 219 Get parts of two branches:
197 220
198 221 $ hg debuggetbundle http://localhost:$HGPORT/ bundle -H 13c0170174366b441dc68e8e33757232fa744458 -C 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 -H bac16991d12ff45f9dc43c52da1946dfadb83e80 -C d5f6e1ea452285324836a49d7d3c2a63cfed1d31
199 222 $ hg debugbundle bundle
200 223 ff42371d57168345fdf1a3aac66a51f6a45d41d2
201 224 bac16991d12ff45f9dc43c52da1946dfadb83e80
202 225 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
203 226 13c0170174366b441dc68e8e33757232fa744458
204 227
205 228 Check that we get all needed file changes:
206 229
207 230 $ hg debugbundle bundle --all
208 231 format: id, p1, p2, cset, delta base, len(delta)
209 232
210 233 changelog
211 234 ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 99
212 235 bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 99
213 236 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 bac16991d12ff45f9dc43c52da1946dfadb83e80 102
214 237 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 102
215 238
216 239 manifest
217 240 dac7984588fc4eea7acbf39693a9c1b06f5b175d 591f732a3faf1fb903815273f3c199a514a61ccb 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 591f732a3faf1fb903815273f3c199a514a61ccb 113
218 241 0772616e6b48a76afb6c1458e193cbb3dae2e4ff dac7984588fc4eea7acbf39693a9c1b06f5b175d 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 dac7984588fc4eea7acbf39693a9c1b06f5b175d 113
219 242 eb498cd9af6c44108e43041e951ce829e29f6c80 bff2f4817ced57b386caf7c4e3e36a4bc9af7e93 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0772616e6b48a76afb6c1458e193cbb3dae2e4ff 295
220 243 b15709c071ddd2d93188508ba156196ab4f19620 eb498cd9af6c44108e43041e951ce829e29f6c80 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 eb498cd9af6c44108e43041e951ce829e29f6c80 114
221 244
222 245 mf
223 246 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 17
224 247 c7b583de053293870e145f45bd2d61643563fd06 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 18
225 248 266ee3c0302a5a18f1cf96817ac79a51836179e9 edc0f6b8db80d68ae6aff2b19f7e5347ab68fa63 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 c7b583de053293870e145f45bd2d61643563fd06 149
226 249 698c6a36220548cd3903ca7dada27c59aa500c52 266ee3c0302a5a18f1cf96817ac79a51836179e9 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 266ee3c0302a5a18f1cf96817ac79a51836179e9 19
227 250
228 251 nf11
229 252 33fbc651630ffa7ccbebfe4eb91320a873e7291c 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 16
230 253
231 254 nf12
232 255 ddce0544363f037e9fb889faca058f52dc01c0a5 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 0000000000000000000000000000000000000000 16
233 256
234 257 nf4
235 258 3c1407305701051cbed9f9cb9a68bdfb5997c235 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 15
236 259
237 260 nf5
238 261 0dbd89c185f53a1727c54cd1ce256482fa23968e 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 0000000000000000000000000000000000000000 15
239 262
240 263 Verify we hit the HTTP server:
241 264
242 265 $ cat access.log
243 266 * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
244 267 * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - (glob)
245 268 * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
246 269 * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=700b7e19db54103633c4bf4a6a6b6d55f4d50c03+d5f6e1ea452285324836a49d7d3c2a63cfed1d31&heads=13c0170174366b441dc68e8e33757232fa744458+bac16991d12ff45f9dc43c52da1946dfadb83e80 (glob)
247 270
248 271 $ cat error.log
249 272
General Comments 0
You need to be logged in to leave comments. Login now