##// END OF EJS Templates
subrepo: rewrite handling of subrepo state at commit (issue2403)...
Matt Mackall -
r16073:b254f827 default
parent child Browse files
Show More
@@ -1,2310 +1,2330 b''
1 1 # localrepo.py - read/write repository class 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 bin, hex, nullid, nullrev, short
9 9 from i18n import _
10 10 import repo, changegroup, subrepo, discovery, pushkey
11 11 import changelog, dirstate, filelog, manifest, context, bookmarks, phases
12 12 import lock, transaction, store, encoding
13 13 import scmutil, util, extensions, hook, error, revset
14 14 import match as matchmod
15 15 import merge as mergemod
16 16 import tags as tagsmod
17 17 from lock import release
18 18 import weakref, errno, os, time, inspect
19 19 propertycache = util.propertycache
20 20 filecache = scmutil.filecache
21 21
22 22 class localrepository(repo.repository):
23 23 capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey',
24 24 'known', 'getbundle'))
25 25 supportedformats = set(('revlogv1', 'generaldelta'))
26 26 supported = supportedformats | set(('store', 'fncache', 'shared',
27 27 'dotencode'))
28 28
29 29 def __init__(self, baseui, path=None, create=False):
30 30 repo.repository.__init__(self)
31 31 self.root = os.path.realpath(util.expandpath(path))
32 32 self.path = os.path.join(self.root, ".hg")
33 33 self.origroot = path
34 34 self.auditor = scmutil.pathauditor(self.root, self._checknested)
35 35 self.opener = scmutil.opener(self.path)
36 36 self.wopener = scmutil.opener(self.root)
37 37 self.baseui = baseui
38 38 self.ui = baseui.copy()
39 39 self._dirtyphases = False
40 40 # A list of callback to shape the phase if no data were found.
41 41 # Callback are in the form: func(repo, roots) --> processed root.
42 42 # This list it to be filled by extension during repo setup
43 43 self._phasedefaults = []
44 44
45 45 try:
46 46 self.ui.readconfig(self.join("hgrc"), self.root)
47 47 extensions.loadall(self.ui)
48 48 except IOError:
49 49 pass
50 50
51 51 if not os.path.isdir(self.path):
52 52 if create:
53 53 if not os.path.exists(path):
54 54 util.makedirs(path)
55 55 util.makedir(self.path, notindexed=True)
56 56 requirements = ["revlogv1"]
57 57 if self.ui.configbool('format', 'usestore', True):
58 58 os.mkdir(os.path.join(self.path, "store"))
59 59 requirements.append("store")
60 60 if self.ui.configbool('format', 'usefncache', True):
61 61 requirements.append("fncache")
62 62 if self.ui.configbool('format', 'dotencode', True):
63 63 requirements.append('dotencode')
64 64 # create an invalid changelog
65 65 self.opener.append(
66 66 "00changelog.i",
67 67 '\0\0\0\2' # represents revlogv2
68 68 ' dummy changelog to prevent using the old repo layout'
69 69 )
70 70 if self.ui.configbool('format', 'generaldelta', False):
71 71 requirements.append("generaldelta")
72 72 requirements = set(requirements)
73 73 else:
74 74 raise error.RepoError(_("repository %s not found") % path)
75 75 elif create:
76 76 raise error.RepoError(_("repository %s already exists") % path)
77 77 else:
78 78 try:
79 79 requirements = scmutil.readrequires(self.opener, self.supported)
80 80 except IOError, inst:
81 81 if inst.errno != errno.ENOENT:
82 82 raise
83 83 requirements = set()
84 84
85 85 self.sharedpath = self.path
86 86 try:
87 87 s = os.path.realpath(self.opener.read("sharedpath").rstrip('\n'))
88 88 if not os.path.exists(s):
89 89 raise error.RepoError(
90 90 _('.hg/sharedpath points to nonexistent directory %s') % s)
91 91 self.sharedpath = s
92 92 except IOError, inst:
93 93 if inst.errno != errno.ENOENT:
94 94 raise
95 95
96 96 self.store = store.store(requirements, self.sharedpath, scmutil.opener)
97 97 self.spath = self.store.path
98 98 self.sopener = self.store.opener
99 99 self.sjoin = self.store.join
100 100 self.opener.createmode = self.store.createmode
101 101 self._applyrequirements(requirements)
102 102 if create:
103 103 self._writerequirements()
104 104
105 105
106 106 self._branchcache = None
107 107 self._branchcachetip = None
108 108 self.filterpats = {}
109 109 self._datafilters = {}
110 110 self._transref = self._lockref = self._wlockref = None
111 111
112 112 # A cache for various files under .hg/ that tracks file changes,
113 113 # (used by the filecache decorator)
114 114 #
115 115 # Maps a property name to its util.filecacheentry
116 116 self._filecache = {}
117 117
118 118 def _applyrequirements(self, requirements):
119 119 self.requirements = requirements
120 120 openerreqs = set(('revlogv1', 'generaldelta'))
121 121 self.sopener.options = dict((r, 1) for r in requirements
122 122 if r in openerreqs)
123 123
124 124 def _writerequirements(self):
125 125 reqfile = self.opener("requires", "w")
126 126 for r in self.requirements:
127 127 reqfile.write("%s\n" % r)
128 128 reqfile.close()
129 129
130 130 def _checknested(self, path):
131 131 """Determine if path is a legal nested repository."""
132 132 if not path.startswith(self.root):
133 133 return False
134 134 subpath = path[len(self.root) + 1:]
135 135 normsubpath = util.pconvert(subpath)
136 136
137 137 # XXX: Checking against the current working copy is wrong in
138 138 # the sense that it can reject things like
139 139 #
140 140 # $ hg cat -r 10 sub/x.txt
141 141 #
142 142 # if sub/ is no longer a subrepository in the working copy
143 143 # parent revision.
144 144 #
145 145 # However, it can of course also allow things that would have
146 146 # been rejected before, such as the above cat command if sub/
147 147 # is a subrepository now, but was a normal directory before.
148 148 # The old path auditor would have rejected by mistake since it
149 149 # panics when it sees sub/.hg/.
150 150 #
151 151 # All in all, checking against the working copy seems sensible
152 152 # since we want to prevent access to nested repositories on
153 153 # the filesystem *now*.
154 154 ctx = self[None]
155 155 parts = util.splitpath(subpath)
156 156 while parts:
157 157 prefix = '/'.join(parts)
158 158 if prefix in ctx.substate:
159 159 if prefix == normsubpath:
160 160 return True
161 161 else:
162 162 sub = ctx.sub(prefix)
163 163 return sub.checknested(subpath[len(prefix) + 1:])
164 164 else:
165 165 parts.pop()
166 166 return False
167 167
168 168 @filecache('bookmarks')
169 169 def _bookmarks(self):
170 170 return bookmarks.read(self)
171 171
172 172 @filecache('bookmarks.current')
173 173 def _bookmarkcurrent(self):
174 174 return bookmarks.readcurrent(self)
175 175
176 176 def _writebookmarks(self, marks):
177 177 bookmarks.write(self)
178 178
179 179 @filecache('phaseroots', True)
180 180 def _phaseroots(self):
181 181 self._dirtyphases = False
182 182 phaseroots = phases.readroots(self)
183 183 phases.filterunknown(self, phaseroots)
184 184 return phaseroots
185 185
186 186 @propertycache
187 187 def _phaserev(self):
188 188 cache = [phases.public] * len(self)
189 189 for phase in phases.trackedphases:
190 190 roots = map(self.changelog.rev, self._phaseroots[phase])
191 191 if roots:
192 192 for rev in roots:
193 193 cache[rev] = phase
194 194 for rev in self.changelog.descendants(*roots):
195 195 cache[rev] = phase
196 196 return cache
197 197
198 198 @filecache('00changelog.i', True)
199 199 def changelog(self):
200 200 c = changelog.changelog(self.sopener)
201 201 if 'HG_PENDING' in os.environ:
202 202 p = os.environ['HG_PENDING']
203 203 if p.startswith(self.root):
204 204 c.readpending('00changelog.i.a')
205 205 return c
206 206
207 207 @filecache('00manifest.i', True)
208 208 def manifest(self):
209 209 return manifest.manifest(self.sopener)
210 210
211 211 @filecache('dirstate')
212 212 def dirstate(self):
213 213 warned = [0]
214 214 def validate(node):
215 215 try:
216 216 self.changelog.rev(node)
217 217 return node
218 218 except error.LookupError:
219 219 if not warned[0]:
220 220 warned[0] = True
221 221 self.ui.warn(_("warning: ignoring unknown"
222 222 " working parent %s!\n") % short(node))
223 223 return nullid
224 224
225 225 return dirstate.dirstate(self.opener, self.ui, self.root, validate)
226 226
227 227 def __getitem__(self, changeid):
228 228 if changeid is None:
229 229 return context.workingctx(self)
230 230 return context.changectx(self, changeid)
231 231
232 232 def __contains__(self, changeid):
233 233 try:
234 234 return bool(self.lookup(changeid))
235 235 except error.RepoLookupError:
236 236 return False
237 237
238 238 def __nonzero__(self):
239 239 return True
240 240
241 241 def __len__(self):
242 242 return len(self.changelog)
243 243
244 244 def __iter__(self):
245 245 for i in xrange(len(self)):
246 246 yield i
247 247
248 248 def revs(self, expr, *args):
249 249 '''Return a list of revisions matching the given revset'''
250 250 expr = revset.formatspec(expr, *args)
251 251 m = revset.match(None, expr)
252 252 return [r for r in m(self, range(len(self)))]
253 253
254 254 def set(self, expr, *args):
255 255 '''
256 256 Yield a context for each matching revision, after doing arg
257 257 replacement via revset.formatspec
258 258 '''
259 259 for r in self.revs(expr, *args):
260 260 yield self[r]
261 261
262 262 def url(self):
263 263 return 'file:' + self.root
264 264
265 265 def hook(self, name, throw=False, **args):
266 266 return hook.hook(self.ui, self, name, throw, **args)
267 267
268 268 tag_disallowed = ':\r\n'
269 269
270 270 def _tag(self, names, node, message, local, user, date, extra={}):
271 271 if isinstance(names, str):
272 272 allchars = names
273 273 names = (names,)
274 274 else:
275 275 allchars = ''.join(names)
276 276 for c in self.tag_disallowed:
277 277 if c in allchars:
278 278 raise util.Abort(_('%r cannot be used in a tag name') % c)
279 279
280 280 branches = self.branchmap()
281 281 for name in names:
282 282 self.hook('pretag', throw=True, node=hex(node), tag=name,
283 283 local=local)
284 284 if name in branches:
285 285 self.ui.warn(_("warning: tag %s conflicts with existing"
286 286 " branch name\n") % name)
287 287
288 288 def writetags(fp, names, munge, prevtags):
289 289 fp.seek(0, 2)
290 290 if prevtags and prevtags[-1] != '\n':
291 291 fp.write('\n')
292 292 for name in names:
293 293 m = munge and munge(name) or name
294 294 if self._tagscache.tagtypes and name in self._tagscache.tagtypes:
295 295 old = self.tags().get(name, nullid)
296 296 fp.write('%s %s\n' % (hex(old), m))
297 297 fp.write('%s %s\n' % (hex(node), m))
298 298 fp.close()
299 299
300 300 prevtags = ''
301 301 if local:
302 302 try:
303 303 fp = self.opener('localtags', 'r+')
304 304 except IOError:
305 305 fp = self.opener('localtags', 'a')
306 306 else:
307 307 prevtags = fp.read()
308 308
309 309 # local tags are stored in the current charset
310 310 writetags(fp, names, None, prevtags)
311 311 for name in names:
312 312 self.hook('tag', node=hex(node), tag=name, local=local)
313 313 return
314 314
315 315 try:
316 316 fp = self.wfile('.hgtags', 'rb+')
317 317 except IOError, e:
318 318 if e.errno != errno.ENOENT:
319 319 raise
320 320 fp = self.wfile('.hgtags', 'ab')
321 321 else:
322 322 prevtags = fp.read()
323 323
324 324 # committed tags are stored in UTF-8
325 325 writetags(fp, names, encoding.fromlocal, prevtags)
326 326
327 327 fp.close()
328 328
329 329 self.invalidatecaches()
330 330
331 331 if '.hgtags' not in self.dirstate:
332 332 self[None].add(['.hgtags'])
333 333
334 334 m = matchmod.exact(self.root, '', ['.hgtags'])
335 335 tagnode = self.commit(message, user, date, extra=extra, match=m)
336 336
337 337 for name in names:
338 338 self.hook('tag', node=hex(node), tag=name, local=local)
339 339
340 340 return tagnode
341 341
342 342 def tag(self, names, node, message, local, user, date):
343 343 '''tag a revision with one or more symbolic names.
344 344
345 345 names is a list of strings or, when adding a single tag, names may be a
346 346 string.
347 347
348 348 if local is True, the tags are stored in a per-repository file.
349 349 otherwise, they are stored in the .hgtags file, and a new
350 350 changeset is committed with the change.
351 351
352 352 keyword arguments:
353 353
354 354 local: whether to store tags in non-version-controlled file
355 355 (default False)
356 356
357 357 message: commit message to use if committing
358 358
359 359 user: name of user to use if committing
360 360
361 361 date: date tuple to use if committing'''
362 362
363 363 if not local:
364 364 for x in self.status()[:5]:
365 365 if '.hgtags' in x:
366 366 raise util.Abort(_('working copy of .hgtags is changed '
367 367 '(please commit .hgtags manually)'))
368 368
369 369 self.tags() # instantiate the cache
370 370 self._tag(names, node, message, local, user, date)
371 371
372 372 @propertycache
373 373 def _tagscache(self):
374 374 '''Returns a tagscache object that contains various tags related caches.'''
375 375
376 376 # This simplifies its cache management by having one decorated
377 377 # function (this one) and the rest simply fetch things from it.
378 378 class tagscache(object):
379 379 def __init__(self):
380 380 # These two define the set of tags for this repository. tags
381 381 # maps tag name to node; tagtypes maps tag name to 'global' or
382 382 # 'local'. (Global tags are defined by .hgtags across all
383 383 # heads, and local tags are defined in .hg/localtags.)
384 384 # They constitute the in-memory cache of tags.
385 385 self.tags = self.tagtypes = None
386 386
387 387 self.nodetagscache = self.tagslist = None
388 388
389 389 cache = tagscache()
390 390 cache.tags, cache.tagtypes = self._findtags()
391 391
392 392 return cache
393 393
394 394 def tags(self):
395 395 '''return a mapping of tag to node'''
396 396 return self._tagscache.tags
397 397
398 398 def _findtags(self):
399 399 '''Do the hard work of finding tags. Return a pair of dicts
400 400 (tags, tagtypes) where tags maps tag name to node, and tagtypes
401 401 maps tag name to a string like \'global\' or \'local\'.
402 402 Subclasses or extensions are free to add their own tags, but
403 403 should be aware that the returned dicts will be retained for the
404 404 duration of the localrepo object.'''
405 405
406 406 # XXX what tagtype should subclasses/extensions use? Currently
407 407 # mq and bookmarks add tags, but do not set the tagtype at all.
408 408 # Should each extension invent its own tag type? Should there
409 409 # be one tagtype for all such "virtual" tags? Or is the status
410 410 # quo fine?
411 411
412 412 alltags = {} # map tag name to (node, hist)
413 413 tagtypes = {}
414 414
415 415 tagsmod.findglobaltags(self.ui, self, alltags, tagtypes)
416 416 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
417 417
418 418 # Build the return dicts. Have to re-encode tag names because
419 419 # the tags module always uses UTF-8 (in order not to lose info
420 420 # writing to the cache), but the rest of Mercurial wants them in
421 421 # local encoding.
422 422 tags = {}
423 423 for (name, (node, hist)) in alltags.iteritems():
424 424 if node != nullid:
425 425 try:
426 426 # ignore tags to unknown nodes
427 427 self.changelog.lookup(node)
428 428 tags[encoding.tolocal(name)] = node
429 429 except error.LookupError:
430 430 pass
431 431 tags['tip'] = self.changelog.tip()
432 432 tagtypes = dict([(encoding.tolocal(name), value)
433 433 for (name, value) in tagtypes.iteritems()])
434 434 return (tags, tagtypes)
435 435
436 436 def tagtype(self, tagname):
437 437 '''
438 438 return the type of the given tag. result can be:
439 439
440 440 'local' : a local tag
441 441 'global' : a global tag
442 442 None : tag does not exist
443 443 '''
444 444
445 445 return self._tagscache.tagtypes.get(tagname)
446 446
447 447 def tagslist(self):
448 448 '''return a list of tags ordered by revision'''
449 449 if not self._tagscache.tagslist:
450 450 l = []
451 451 for t, n in self.tags().iteritems():
452 452 r = self.changelog.rev(n)
453 453 l.append((r, t, n))
454 454 self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
455 455
456 456 return self._tagscache.tagslist
457 457
458 458 def nodetags(self, node):
459 459 '''return the tags associated with a node'''
460 460 if not self._tagscache.nodetagscache:
461 461 nodetagscache = {}
462 462 for t, n in self.tags().iteritems():
463 463 nodetagscache.setdefault(n, []).append(t)
464 464 for tags in nodetagscache.itervalues():
465 465 tags.sort()
466 466 self._tagscache.nodetagscache = nodetagscache
467 467 return self._tagscache.nodetagscache.get(node, [])
468 468
469 469 def nodebookmarks(self, node):
470 470 marks = []
471 471 for bookmark, n in self._bookmarks.iteritems():
472 472 if n == node:
473 473 marks.append(bookmark)
474 474 return sorted(marks)
475 475
476 476 def _branchtags(self, partial, lrev):
477 477 # TODO: rename this function?
478 478 tiprev = len(self) - 1
479 479 if lrev != tiprev:
480 480 ctxgen = (self[r] for r in xrange(lrev + 1, tiprev + 1))
481 481 self._updatebranchcache(partial, ctxgen)
482 482 self._writebranchcache(partial, self.changelog.tip(), tiprev)
483 483
484 484 return partial
485 485
486 486 def updatebranchcache(self):
487 487 tip = self.changelog.tip()
488 488 if self._branchcache is not None and self._branchcachetip == tip:
489 489 return
490 490
491 491 oldtip = self._branchcachetip
492 492 self._branchcachetip = tip
493 493 if oldtip is None or oldtip not in self.changelog.nodemap:
494 494 partial, last, lrev = self._readbranchcache()
495 495 else:
496 496 lrev = self.changelog.rev(oldtip)
497 497 partial = self._branchcache
498 498
499 499 self._branchtags(partial, lrev)
500 500 # this private cache holds all heads (not just tips)
501 501 self._branchcache = partial
502 502
503 503 def branchmap(self):
504 504 '''returns a dictionary {branch: [branchheads]}'''
505 505 self.updatebranchcache()
506 506 return self._branchcache
507 507
508 508 def branchtags(self):
509 509 '''return a dict where branch names map to the tipmost head of
510 510 the branch, open heads come before closed'''
511 511 bt = {}
512 512 for bn, heads in self.branchmap().iteritems():
513 513 tip = heads[-1]
514 514 for h in reversed(heads):
515 515 if 'close' not in self.changelog.read(h)[5]:
516 516 tip = h
517 517 break
518 518 bt[bn] = tip
519 519 return bt
520 520
521 521 def _readbranchcache(self):
522 522 partial = {}
523 523 try:
524 524 f = self.opener("cache/branchheads")
525 525 lines = f.read().split('\n')
526 526 f.close()
527 527 except (IOError, OSError):
528 528 return {}, nullid, nullrev
529 529
530 530 try:
531 531 last, lrev = lines.pop(0).split(" ", 1)
532 532 last, lrev = bin(last), int(lrev)
533 533 if lrev >= len(self) or self[lrev].node() != last:
534 534 # invalidate the cache
535 535 raise ValueError('invalidating branch cache (tip differs)')
536 536 for l in lines:
537 537 if not l:
538 538 continue
539 539 node, label = l.split(" ", 1)
540 540 label = encoding.tolocal(label.strip())
541 541 partial.setdefault(label, []).append(bin(node))
542 542 except KeyboardInterrupt:
543 543 raise
544 544 except Exception, inst:
545 545 if self.ui.debugflag:
546 546 self.ui.warn(str(inst), '\n')
547 547 partial, last, lrev = {}, nullid, nullrev
548 548 return partial, last, lrev
549 549
550 550 def _writebranchcache(self, branches, tip, tiprev):
551 551 try:
552 552 f = self.opener("cache/branchheads", "w", atomictemp=True)
553 553 f.write("%s %s\n" % (hex(tip), tiprev))
554 554 for label, nodes in branches.iteritems():
555 555 for node in nodes:
556 556 f.write("%s %s\n" % (hex(node), encoding.fromlocal(label)))
557 557 f.close()
558 558 except (IOError, OSError):
559 559 pass
560 560
561 561 def _updatebranchcache(self, partial, ctxgen):
562 562 # collect new branch entries
563 563 newbranches = {}
564 564 for c in ctxgen:
565 565 newbranches.setdefault(c.branch(), []).append(c.node())
566 566 # if older branchheads are reachable from new ones, they aren't
567 567 # really branchheads. Note checking parents is insufficient:
568 568 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
569 569 for branch, newnodes in newbranches.iteritems():
570 570 bheads = partial.setdefault(branch, [])
571 571 bheads.extend(newnodes)
572 572 if len(bheads) <= 1:
573 573 continue
574 574 bheads = sorted(bheads, key=lambda x: self[x].rev())
575 575 # starting from tip means fewer passes over reachable
576 576 while newnodes:
577 577 latest = newnodes.pop()
578 578 if latest not in bheads:
579 579 continue
580 580 minbhrev = self[bheads[0]].node()
581 581 reachable = self.changelog.reachable(latest, minbhrev)
582 582 reachable.remove(latest)
583 583 if reachable:
584 584 bheads = [b for b in bheads if b not in reachable]
585 585 partial[branch] = bheads
586 586
587 587 def lookup(self, key):
588 588 if isinstance(key, int):
589 589 return self.changelog.node(key)
590 590 elif key == '.':
591 591 return self.dirstate.p1()
592 592 elif key == 'null':
593 593 return nullid
594 594 elif key == 'tip':
595 595 return self.changelog.tip()
596 596 n = self.changelog._match(key)
597 597 if n:
598 598 return n
599 599 if key in self._bookmarks:
600 600 return self._bookmarks[key]
601 601 if key in self.tags():
602 602 return self.tags()[key]
603 603 if key in self.branchtags():
604 604 return self.branchtags()[key]
605 605 n = self.changelog._partialmatch(key)
606 606 if n:
607 607 return n
608 608
609 609 # can't find key, check if it might have come from damaged dirstate
610 610 if key in self.dirstate.parents():
611 611 raise error.Abort(_("working directory has unknown parent '%s'!")
612 612 % short(key))
613 613 try:
614 614 if len(key) == 20:
615 615 key = hex(key)
616 616 except TypeError:
617 617 pass
618 618 raise error.RepoLookupError(_("unknown revision '%s'") % key)
619 619
620 620 def lookupbranch(self, key, remote=None):
621 621 repo = remote or self
622 622 if key in repo.branchmap():
623 623 return key
624 624
625 625 repo = (remote and remote.local()) and remote or self
626 626 return repo[key].branch()
627 627
628 628 def known(self, nodes):
629 629 nm = self.changelog.nodemap
630 630 result = []
631 631 for n in nodes:
632 632 r = nm.get(n)
633 633 resp = not (r is None or self._phaserev[r] >= phases.secret)
634 634 result.append(resp)
635 635 return result
636 636
637 637 def local(self):
638 638 return self
639 639
640 640 def join(self, f):
641 641 return os.path.join(self.path, f)
642 642
643 643 def wjoin(self, f):
644 644 return os.path.join(self.root, f)
645 645
646 646 def file(self, f):
647 647 if f[0] == '/':
648 648 f = f[1:]
649 649 return filelog.filelog(self.sopener, f)
650 650
651 651 def changectx(self, changeid):
652 652 return self[changeid]
653 653
654 654 def parents(self, changeid=None):
655 655 '''get list of changectxs for parents of changeid'''
656 656 return self[changeid].parents()
657 657
658 658 def filectx(self, path, changeid=None, fileid=None):
659 659 """changeid can be a changeset revision, node, or tag.
660 660 fileid can be a file revision or node."""
661 661 return context.filectx(self, path, changeid, fileid)
662 662
663 663 def getcwd(self):
664 664 return self.dirstate.getcwd()
665 665
666 666 def pathto(self, f, cwd=None):
667 667 return self.dirstate.pathto(f, cwd)
668 668
669 669 def wfile(self, f, mode='r'):
670 670 return self.wopener(f, mode)
671 671
672 672 def _link(self, f):
673 673 return os.path.islink(self.wjoin(f))
674 674
675 675 def _loadfilter(self, filter):
676 676 if filter not in self.filterpats:
677 677 l = []
678 678 for pat, cmd in self.ui.configitems(filter):
679 679 if cmd == '!':
680 680 continue
681 681 mf = matchmod.match(self.root, '', [pat])
682 682 fn = None
683 683 params = cmd
684 684 for name, filterfn in self._datafilters.iteritems():
685 685 if cmd.startswith(name):
686 686 fn = filterfn
687 687 params = cmd[len(name):].lstrip()
688 688 break
689 689 if not fn:
690 690 fn = lambda s, c, **kwargs: util.filter(s, c)
691 691 # Wrap old filters not supporting keyword arguments
692 692 if not inspect.getargspec(fn)[2]:
693 693 oldfn = fn
694 694 fn = lambda s, c, **kwargs: oldfn(s, c)
695 695 l.append((mf, fn, params))
696 696 self.filterpats[filter] = l
697 697 return self.filterpats[filter]
698 698
699 699 def _filter(self, filterpats, filename, data):
700 700 for mf, fn, cmd in filterpats:
701 701 if mf(filename):
702 702 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
703 703 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
704 704 break
705 705
706 706 return data
707 707
708 708 @propertycache
709 709 def _encodefilterpats(self):
710 710 return self._loadfilter('encode')
711 711
712 712 @propertycache
713 713 def _decodefilterpats(self):
714 714 return self._loadfilter('decode')
715 715
716 716 def adddatafilter(self, name, filter):
717 717 self._datafilters[name] = filter
718 718
719 719 def wread(self, filename):
720 720 if self._link(filename):
721 721 data = os.readlink(self.wjoin(filename))
722 722 else:
723 723 data = self.wopener.read(filename)
724 724 return self._filter(self._encodefilterpats, filename, data)
725 725
726 726 def wwrite(self, filename, data, flags):
727 727 data = self._filter(self._decodefilterpats, filename, data)
728 728 if 'l' in flags:
729 729 self.wopener.symlink(data, filename)
730 730 else:
731 731 self.wopener.write(filename, data)
732 732 if 'x' in flags:
733 733 util.setflags(self.wjoin(filename), False, True)
734 734
735 735 def wwritedata(self, filename, data):
736 736 return self._filter(self._decodefilterpats, filename, data)
737 737
738 738 def transaction(self, desc):
739 739 tr = self._transref and self._transref() or None
740 740 if tr and tr.running():
741 741 return tr.nest()
742 742
743 743 # abort here if the journal already exists
744 744 if os.path.exists(self.sjoin("journal")):
745 745 raise error.RepoError(
746 746 _("abandoned transaction found - run hg recover"))
747 747
748 748 journalfiles = self._writejournal(desc)
749 749 renames = [(x, undoname(x)) for x in journalfiles]
750 750
751 751 tr = transaction.transaction(self.ui.warn, self.sopener,
752 752 self.sjoin("journal"),
753 753 aftertrans(renames),
754 754 self.store.createmode)
755 755 self._transref = weakref.ref(tr)
756 756 return tr
757 757
758 758 def _writejournal(self, desc):
759 759 # save dirstate for rollback
760 760 try:
761 761 ds = self.opener.read("dirstate")
762 762 except IOError:
763 763 ds = ""
764 764 self.opener.write("journal.dirstate", ds)
765 765 self.opener.write("journal.branch",
766 766 encoding.fromlocal(self.dirstate.branch()))
767 767 self.opener.write("journal.desc",
768 768 "%d\n%s\n" % (len(self), desc))
769 769
770 770 bkname = self.join('bookmarks')
771 771 if os.path.exists(bkname):
772 772 util.copyfile(bkname, self.join('journal.bookmarks'))
773 773 else:
774 774 self.opener.write('journal.bookmarks', '')
775 775 phasesname = self.sjoin('phaseroots')
776 776 if os.path.exists(phasesname):
777 777 util.copyfile(phasesname, self.sjoin('journal.phaseroots'))
778 778 else:
779 779 self.sopener.write('journal.phaseroots', '')
780 780
781 781 return (self.sjoin('journal'), self.join('journal.dirstate'),
782 782 self.join('journal.branch'), self.join('journal.desc'),
783 783 self.join('journal.bookmarks'),
784 784 self.sjoin('journal.phaseroots'))
785 785
786 786 def recover(self):
787 787 lock = self.lock()
788 788 try:
789 789 if os.path.exists(self.sjoin("journal")):
790 790 self.ui.status(_("rolling back interrupted transaction\n"))
791 791 transaction.rollback(self.sopener, self.sjoin("journal"),
792 792 self.ui.warn)
793 793 self.invalidate()
794 794 return True
795 795 else:
796 796 self.ui.warn(_("no interrupted transaction available\n"))
797 797 return False
798 798 finally:
799 799 lock.release()
800 800
801 801 def rollback(self, dryrun=False, force=False):
802 802 wlock = lock = None
803 803 try:
804 804 wlock = self.wlock()
805 805 lock = self.lock()
806 806 if os.path.exists(self.sjoin("undo")):
807 807 return self._rollback(dryrun, force)
808 808 else:
809 809 self.ui.warn(_("no rollback information available\n"))
810 810 return 1
811 811 finally:
812 812 release(lock, wlock)
813 813
814 814 def _rollback(self, dryrun, force):
815 815 ui = self.ui
816 816 try:
817 817 args = self.opener.read('undo.desc').splitlines()
818 818 (oldlen, desc, detail) = (int(args[0]), args[1], None)
819 819 if len(args) >= 3:
820 820 detail = args[2]
821 821 oldtip = oldlen - 1
822 822
823 823 if detail and ui.verbose:
824 824 msg = (_('repository tip rolled back to revision %s'
825 825 ' (undo %s: %s)\n')
826 826 % (oldtip, desc, detail))
827 827 else:
828 828 msg = (_('repository tip rolled back to revision %s'
829 829 ' (undo %s)\n')
830 830 % (oldtip, desc))
831 831 except IOError:
832 832 msg = _('rolling back unknown transaction\n')
833 833 desc = None
834 834
835 835 if not force and self['.'] != self['tip'] and desc == 'commit':
836 836 raise util.Abort(
837 837 _('rollback of last commit while not checked out '
838 838 'may lose data'), hint=_('use -f to force'))
839 839
840 840 ui.status(msg)
841 841 if dryrun:
842 842 return 0
843 843
844 844 parents = self.dirstate.parents()
845 845 transaction.rollback(self.sopener, self.sjoin('undo'), ui.warn)
846 846 if os.path.exists(self.join('undo.bookmarks')):
847 847 util.rename(self.join('undo.bookmarks'),
848 848 self.join('bookmarks'))
849 849 if os.path.exists(self.sjoin('undo.phaseroots')):
850 850 util.rename(self.sjoin('undo.phaseroots'),
851 851 self.sjoin('phaseroots'))
852 852 self.invalidate()
853 853
854 854 parentgone = (parents[0] not in self.changelog.nodemap or
855 855 parents[1] not in self.changelog.nodemap)
856 856 if parentgone:
857 857 util.rename(self.join('undo.dirstate'), self.join('dirstate'))
858 858 try:
859 859 branch = self.opener.read('undo.branch')
860 860 self.dirstate.setbranch(branch)
861 861 except IOError:
862 862 ui.warn(_('named branch could not be reset: '
863 863 'current branch is still \'%s\'\n')
864 864 % self.dirstate.branch())
865 865
866 866 self.dirstate.invalidate()
867 867 parents = tuple([p.rev() for p in self.parents()])
868 868 if len(parents) > 1:
869 869 ui.status(_('working directory now based on '
870 870 'revisions %d and %d\n') % parents)
871 871 else:
872 872 ui.status(_('working directory now based on '
873 873 'revision %d\n') % parents)
874 874 self.destroyed()
875 875 return 0
876 876
877 877 def invalidatecaches(self):
878 878 def delcache(name):
879 879 try:
880 880 delattr(self, name)
881 881 except AttributeError:
882 882 pass
883 883
884 884 delcache('_tagscache')
885 885 delcache('_phaserev')
886 886
887 887 self._branchcache = None # in UTF-8
888 888 self._branchcachetip = None
889 889
890 890 def invalidatedirstate(self):
891 891 '''Invalidates the dirstate, causing the next call to dirstate
892 892 to check if it was modified since the last time it was read,
893 893 rereading it if it has.
894 894
895 895 This is different to dirstate.invalidate() that it doesn't always
896 896 rereads the dirstate. Use dirstate.invalidate() if you want to
897 897 explicitly read the dirstate again (i.e. restoring it to a previous
898 898 known good state).'''
899 899 try:
900 900 delattr(self, 'dirstate')
901 901 except AttributeError:
902 902 pass
903 903
904 904 def invalidate(self):
905 905 for k in self._filecache:
906 906 # dirstate is invalidated separately in invalidatedirstate()
907 907 if k == 'dirstate':
908 908 continue
909 909
910 910 try:
911 911 delattr(self, k)
912 912 except AttributeError:
913 913 pass
914 914 self.invalidatecaches()
915 915
916 916 def _lock(self, lockname, wait, releasefn, acquirefn, desc):
917 917 try:
918 918 l = lock.lock(lockname, 0, releasefn, desc=desc)
919 919 except error.LockHeld, inst:
920 920 if not wait:
921 921 raise
922 922 self.ui.warn(_("waiting for lock on %s held by %r\n") %
923 923 (desc, inst.locker))
924 924 # default to 600 seconds timeout
925 925 l = lock.lock(lockname, int(self.ui.config("ui", "timeout", "600")),
926 926 releasefn, desc=desc)
927 927 if acquirefn:
928 928 acquirefn()
929 929 return l
930 930
931 931 def _afterlock(self, callback):
932 932 """add a callback to the current repository lock.
933 933
934 934 The callback will be executed on lock release."""
935 935 l = self._lockref and self._lockref()
936 936 if l:
937 937 l.postrelease.append(callback)
938 938
939 939 def lock(self, wait=True):
940 940 '''Lock the repository store (.hg/store) and return a weak reference
941 941 to the lock. Use this before modifying the store (e.g. committing or
942 942 stripping). If you are opening a transaction, get a lock as well.)'''
943 943 l = self._lockref and self._lockref()
944 944 if l is not None and l.held:
945 945 l.lock()
946 946 return l
947 947
948 948 def unlock():
949 949 self.store.write()
950 950 if self._dirtyphases:
951 951 phases.writeroots(self)
952 952 for k, ce in self._filecache.items():
953 953 if k == 'dirstate':
954 954 continue
955 955 ce.refresh()
956 956
957 957 l = self._lock(self.sjoin("lock"), wait, unlock,
958 958 self.invalidate, _('repository %s') % self.origroot)
959 959 self._lockref = weakref.ref(l)
960 960 return l
961 961
962 962 def wlock(self, wait=True):
963 963 '''Lock the non-store parts of the repository (everything under
964 964 .hg except .hg/store) and return a weak reference to the lock.
965 965 Use this before modifying files in .hg.'''
966 966 l = self._wlockref and self._wlockref()
967 967 if l is not None and l.held:
968 968 l.lock()
969 969 return l
970 970
971 971 def unlock():
972 972 self.dirstate.write()
973 973 ce = self._filecache.get('dirstate')
974 974 if ce:
975 975 ce.refresh()
976 976
977 977 l = self._lock(self.join("wlock"), wait, unlock,
978 978 self.invalidatedirstate, _('working directory of %s') %
979 979 self.origroot)
980 980 self._wlockref = weakref.ref(l)
981 981 return l
982 982
983 983 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
984 984 """
985 985 commit an individual file as part of a larger transaction
986 986 """
987 987
988 988 fname = fctx.path()
989 989 text = fctx.data()
990 990 flog = self.file(fname)
991 991 fparent1 = manifest1.get(fname, nullid)
992 992 fparent2 = fparent2o = manifest2.get(fname, nullid)
993 993
994 994 meta = {}
995 995 copy = fctx.renamed()
996 996 if copy and copy[0] != fname:
997 997 # Mark the new revision of this file as a copy of another
998 998 # file. This copy data will effectively act as a parent
999 999 # of this new revision. If this is a merge, the first
1000 1000 # parent will be the nullid (meaning "look up the copy data")
1001 1001 # and the second one will be the other parent. For example:
1002 1002 #
1003 1003 # 0 --- 1 --- 3 rev1 changes file foo
1004 1004 # \ / rev2 renames foo to bar and changes it
1005 1005 # \- 2 -/ rev3 should have bar with all changes and
1006 1006 # should record that bar descends from
1007 1007 # bar in rev2 and foo in rev1
1008 1008 #
1009 1009 # this allows this merge to succeed:
1010 1010 #
1011 1011 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
1012 1012 # \ / merging rev3 and rev4 should use bar@rev2
1013 1013 # \- 2 --- 4 as the merge base
1014 1014 #
1015 1015
1016 1016 cfname = copy[0]
1017 1017 crev = manifest1.get(cfname)
1018 1018 newfparent = fparent2
1019 1019
1020 1020 if manifest2: # branch merge
1021 1021 if fparent2 == nullid or crev is None: # copied on remote side
1022 1022 if cfname in manifest2:
1023 1023 crev = manifest2[cfname]
1024 1024 newfparent = fparent1
1025 1025
1026 1026 # find source in nearest ancestor if we've lost track
1027 1027 if not crev:
1028 1028 self.ui.debug(" %s: searching for copy revision for %s\n" %
1029 1029 (fname, cfname))
1030 1030 for ancestor in self[None].ancestors():
1031 1031 if cfname in ancestor:
1032 1032 crev = ancestor[cfname].filenode()
1033 1033 break
1034 1034
1035 1035 if crev:
1036 1036 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
1037 1037 meta["copy"] = cfname
1038 1038 meta["copyrev"] = hex(crev)
1039 1039 fparent1, fparent2 = nullid, newfparent
1040 1040 else:
1041 1041 self.ui.warn(_("warning: can't find ancestor for '%s' "
1042 1042 "copied from '%s'!\n") % (fname, cfname))
1043 1043
1044 1044 elif fparent2 != nullid:
1045 1045 # is one parent an ancestor of the other?
1046 1046 fparentancestor = flog.ancestor(fparent1, fparent2)
1047 1047 if fparentancestor == fparent1:
1048 1048 fparent1, fparent2 = fparent2, nullid
1049 1049 elif fparentancestor == fparent2:
1050 1050 fparent2 = nullid
1051 1051
1052 1052 # is the file changed?
1053 1053 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
1054 1054 changelist.append(fname)
1055 1055 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
1056 1056
1057 1057 # are just the flags changed during merge?
1058 1058 if fparent1 != fparent2o and manifest1.flags(fname) != fctx.flags():
1059 1059 changelist.append(fname)
1060 1060
1061 1061 return fparent1
1062 1062
1063 1063 def commit(self, text="", user=None, date=None, match=None, force=False,
1064 1064 editor=False, extra={}):
1065 1065 """Add a new revision to current repository.
1066 1066
1067 1067 Revision information is gathered from the working directory,
1068 1068 match can be used to filter the committed files. If editor is
1069 1069 supplied, it is called to get a commit message.
1070 1070 """
1071 1071
1072 1072 def fail(f, msg):
1073 1073 raise util.Abort('%s: %s' % (f, msg))
1074 1074
1075 1075 if not match:
1076 1076 match = matchmod.always(self.root, '')
1077 1077
1078 1078 if not force:
1079 1079 vdirs = []
1080 1080 match.dir = vdirs.append
1081 1081 match.bad = fail
1082 1082
1083 1083 wlock = self.wlock()
1084 1084 try:
1085 1085 wctx = self[None]
1086 1086 merge = len(wctx.parents()) > 1
1087 1087
1088 1088 if (not force and merge and match and
1089 1089 (match.files() or match.anypats())):
1090 1090 raise util.Abort(_('cannot partially commit a merge '
1091 1091 '(do not specify files or patterns)'))
1092 1092
1093 1093 changes = self.status(match=match, clean=force)
1094 1094 if force:
1095 1095 changes[0].extend(changes[6]) # mq may commit unchanged files
1096 1096
1097 1097 # check subrepos
1098 1098 subs = []
1099 removedsubs = set()
1099 commitsubs = set()
1100 newstate = wctx.substate.copy()
1101 # only manage subrepos and .hgsubstate if .hgsub is present
1100 1102 if '.hgsub' in wctx:
1101 # only manage subrepos and .hgsubstate if .hgsub is present
1103 # we'll decide whether to track this ourselves, thanks
1104 if '.hgsubstate' in changes[0]:
1105 changes[0].remove('.hgsubstate')
1106 if '.hgsubstate' in changes[2]:
1107 changes[2].remove('.hgsubstate')
1108
1109 # compare current state to last committed state
1110 # build new substate based on last committed state
1111 oldstate = wctx.p1().substate
1112 for s in sorted(newstate.keys()):
1113 if not match(s):
1114 # ignore working copy, use old state if present
1115 if s in oldstate:
1116 newstate[s] = oldstate[s]
1117 continue
1118 if not force:
1119 raise util.Abort(
1120 _("commit with new subrepo %s excluded") % s)
1121 if wctx.sub(s).dirty(True):
1122 if not self.ui.configbool('ui', 'commitsubrepos'):
1123 raise util.Abort(
1124 _("uncommitted changes in subrepo %s") % s,
1125 hint=_("use --subrepos for recursive commit"))
1126 subs.append(s)
1127 commitsubs.add(s)
1128 else:
1129 bs = wctx.sub(s).basestate()
1130 newstate[s] = (newstate[s][0], bs, newstate[s][2])
1131 if oldstate.get(s, (None, None, None))[1] != bs:
1132 subs.append(s)
1133
1134 # check for removed subrepos
1102 1135 for p in wctx.parents():
1103 removedsubs.update(s for s in p.substate if match(s))
1104 for s in wctx.substate:
1105 removedsubs.discard(s)
1106 if match(s) and wctx.sub(s).dirty():
1107 subs.append(s)
1108 if (subs or removedsubs):
1136 r = [s for s in p.substate if s not in newstate]
1137 subs += [s for s in r if match(s)]
1138 if subs:
1109 1139 if (not match('.hgsub') and
1110 1140 '.hgsub' in (wctx.modified() + wctx.added())):
1111 1141 raise util.Abort(
1112 1142 _("can't commit subrepos without .hgsub"))
1113 if '.hgsubstate' not in changes[0]:
1114 changes[0].insert(0, '.hgsubstate')
1115 if '.hgsubstate' in changes[2]:
1116 changes[2].remove('.hgsubstate')
1143 changes[0].insert(0, '.hgsubstate')
1144
1117 1145 elif '.hgsub' in changes[2]:
1118 1146 # clean up .hgsubstate when .hgsub is removed
1119 1147 if ('.hgsubstate' in wctx and
1120 1148 '.hgsubstate' not in changes[0] + changes[1] + changes[2]):
1121 1149 changes[2].insert(0, '.hgsubstate')
1122 1150
1123 if subs and not self.ui.configbool('ui', 'commitsubrepos', False):
1124 changedsubs = [s for s in subs if wctx.sub(s).dirty(True)]
1125 if changedsubs:
1126 raise util.Abort(_("uncommitted changes in subrepo %s")
1127 % changedsubs[0],
1128 hint=_("use --subrepos for recursive commit"))
1129
1130 1151 # make sure all explicit patterns are matched
1131 1152 if not force and match.files():
1132 1153 matched = set(changes[0] + changes[1] + changes[2])
1133 1154
1134 1155 for f in match.files():
1135 1156 if f == '.' or f in matched or f in wctx.substate:
1136 1157 continue
1137 1158 if f in changes[3]: # missing
1138 1159 fail(f, _('file not found!'))
1139 1160 if f in vdirs: # visited directory
1140 1161 d = f + '/'
1141 1162 for mf in matched:
1142 1163 if mf.startswith(d):
1143 1164 break
1144 1165 else:
1145 1166 fail(f, _("no match under directory!"))
1146 1167 elif f not in self.dirstate:
1147 1168 fail(f, _("file not tracked!"))
1148 1169
1149 1170 if (not force and not extra.get("close") and not merge
1150 1171 and not (changes[0] or changes[1] or changes[2])
1151 1172 and wctx.branch() == wctx.p1().branch()):
1152 1173 return None
1153 1174
1154 1175 ms = mergemod.mergestate(self)
1155 1176 for f in changes[0]:
1156 1177 if f in ms and ms[f] == 'u':
1157 1178 raise util.Abort(_("unresolved merge conflicts "
1158 1179 "(see hg help resolve)"))
1159 1180
1160 1181 cctx = context.workingctx(self, text, user, date, extra, changes)
1161 1182 if editor:
1162 1183 cctx._text = editor(self, cctx, subs)
1163 1184 edited = (text != cctx._text)
1164 1185
1165 # commit subs
1166 if subs or removedsubs:
1167 state = wctx.substate.copy()
1168 for s in sorted(subs):
1186 # commit subs and write new state
1187 if subs:
1188 for s in sorted(commitsubs):
1169 1189 sub = wctx.sub(s)
1170 1190 self.ui.status(_('committing subrepository %s\n') %
1171 1191 subrepo.subrelpath(sub))
1172 1192 sr = sub.commit(cctx._text, user, date)
1173 state[s] = (state[s][0], sr)
1174 subrepo.writestate(self, state)
1193 newstate[s] = (newstate[s][0], sr)
1194 subrepo.writestate(self, newstate)
1175 1195
1176 1196 # Save commit message in case this transaction gets rolled back
1177 1197 # (e.g. by a pretxncommit hook). Leave the content alone on
1178 1198 # the assumption that the user will use the same editor again.
1179 1199 msgfn = self.savecommitmessage(cctx._text)
1180 1200
1181 1201 p1, p2 = self.dirstate.parents()
1182 1202 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
1183 1203 try:
1184 1204 self.hook("precommit", throw=True, parent1=hookp1, parent2=hookp2)
1185 1205 ret = self.commitctx(cctx, True)
1186 1206 except:
1187 1207 if edited:
1188 1208 self.ui.write(
1189 1209 _('note: commit message saved in %s\n') % msgfn)
1190 1210 raise
1191 1211
1192 1212 # update bookmarks, dirstate and mergestate
1193 1213 bookmarks.update(self, p1, ret)
1194 1214 for f in changes[0] + changes[1]:
1195 1215 self.dirstate.normal(f)
1196 1216 for f in changes[2]:
1197 1217 self.dirstate.drop(f)
1198 1218 self.dirstate.setparents(ret)
1199 1219 ms.reset()
1200 1220 finally:
1201 1221 wlock.release()
1202 1222
1203 1223 self.hook("commit", node=hex(ret), parent1=hookp1, parent2=hookp2)
1204 1224 return ret
1205 1225
1206 1226 def commitctx(self, ctx, error=False):
1207 1227 """Add a new revision to current repository.
1208 1228 Revision information is passed via the context argument.
1209 1229 """
1210 1230
1211 1231 tr = lock = None
1212 1232 removed = list(ctx.removed())
1213 1233 p1, p2 = ctx.p1(), ctx.p2()
1214 1234 user = ctx.user()
1215 1235
1216 1236 lock = self.lock()
1217 1237 try:
1218 1238 tr = self.transaction("commit")
1219 1239 trp = weakref.proxy(tr)
1220 1240
1221 1241 if ctx.files():
1222 1242 m1 = p1.manifest().copy()
1223 1243 m2 = p2.manifest()
1224 1244
1225 1245 # check in files
1226 1246 new = {}
1227 1247 changed = []
1228 1248 linkrev = len(self)
1229 1249 for f in sorted(ctx.modified() + ctx.added()):
1230 1250 self.ui.note(f + "\n")
1231 1251 try:
1232 1252 fctx = ctx[f]
1233 1253 new[f] = self._filecommit(fctx, m1, m2, linkrev, trp,
1234 1254 changed)
1235 1255 m1.set(f, fctx.flags())
1236 1256 except OSError, inst:
1237 1257 self.ui.warn(_("trouble committing %s!\n") % f)
1238 1258 raise
1239 1259 except IOError, inst:
1240 1260 errcode = getattr(inst, 'errno', errno.ENOENT)
1241 1261 if error or errcode and errcode != errno.ENOENT:
1242 1262 self.ui.warn(_("trouble committing %s!\n") % f)
1243 1263 raise
1244 1264 else:
1245 1265 removed.append(f)
1246 1266
1247 1267 # update manifest
1248 1268 m1.update(new)
1249 1269 removed = [f for f in sorted(removed) if f in m1 or f in m2]
1250 1270 drop = [f for f in removed if f in m1]
1251 1271 for f in drop:
1252 1272 del m1[f]
1253 1273 mn = self.manifest.add(m1, trp, linkrev, p1.manifestnode(),
1254 1274 p2.manifestnode(), (new, drop))
1255 1275 files = changed + removed
1256 1276 else:
1257 1277 mn = p1.manifestnode()
1258 1278 files = []
1259 1279
1260 1280 # update changelog
1261 1281 self.changelog.delayupdate()
1262 1282 n = self.changelog.add(mn, files, ctx.description(),
1263 1283 trp, p1.node(), p2.node(),
1264 1284 user, ctx.date(), ctx.extra().copy())
1265 1285 p = lambda: self.changelog.writepending() and self.root or ""
1266 1286 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
1267 1287 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
1268 1288 parent2=xp2, pending=p)
1269 1289 self.changelog.finalize(trp)
1270 1290 # set the new commit is proper phase
1271 1291 targetphase = phases.newcommitphase(self.ui)
1272 1292 if targetphase:
1273 1293 # retract boundary do not alter parent changeset.
1274 1294 # if a parent have higher the resulting phase will
1275 1295 # be compliant anyway
1276 1296 #
1277 1297 # if minimal phase was 0 we don't need to retract anything
1278 1298 phases.retractboundary(self, targetphase, [n])
1279 1299 tr.close()
1280 1300 self.updatebranchcache()
1281 1301 return n
1282 1302 finally:
1283 1303 if tr:
1284 1304 tr.release()
1285 1305 lock.release()
1286 1306
1287 1307 def destroyed(self):
1288 1308 '''Inform the repository that nodes have been destroyed.
1289 1309 Intended for use by strip and rollback, so there's a common
1290 1310 place for anything that has to be done after destroying history.'''
1291 1311 # XXX it might be nice if we could take the list of destroyed
1292 1312 # nodes, but I don't see an easy way for rollback() to do that
1293 1313
1294 1314 # Ensure the persistent tag cache is updated. Doing it now
1295 1315 # means that the tag cache only has to worry about destroyed
1296 1316 # heads immediately after a strip/rollback. That in turn
1297 1317 # guarantees that "cachetip == currenttip" (comparing both rev
1298 1318 # and node) always means no nodes have been added or destroyed.
1299 1319
1300 1320 # XXX this is suboptimal when qrefresh'ing: we strip the current
1301 1321 # head, refresh the tag cache, then immediately add a new head.
1302 1322 # But I think doing it this way is necessary for the "instant
1303 1323 # tag cache retrieval" case to work.
1304 1324 self.invalidatecaches()
1305 1325
1306 1326 def walk(self, match, node=None):
1307 1327 '''
1308 1328 walk recursively through the directory tree or a given
1309 1329 changeset, finding all files matched by the match
1310 1330 function
1311 1331 '''
1312 1332 return self[node].walk(match)
1313 1333
1314 1334 def status(self, node1='.', node2=None, match=None,
1315 1335 ignored=False, clean=False, unknown=False,
1316 1336 listsubrepos=False):
1317 1337 """return status of files between two nodes or node and working directory
1318 1338
1319 1339 If node1 is None, use the first dirstate parent instead.
1320 1340 If node2 is None, compare node1 with working directory.
1321 1341 """
1322 1342
1323 1343 def mfmatches(ctx):
1324 1344 mf = ctx.manifest().copy()
1325 1345 for fn in mf.keys():
1326 1346 if not match(fn):
1327 1347 del mf[fn]
1328 1348 return mf
1329 1349
1330 1350 if isinstance(node1, context.changectx):
1331 1351 ctx1 = node1
1332 1352 else:
1333 1353 ctx1 = self[node1]
1334 1354 if isinstance(node2, context.changectx):
1335 1355 ctx2 = node2
1336 1356 else:
1337 1357 ctx2 = self[node2]
1338 1358
1339 1359 working = ctx2.rev() is None
1340 1360 parentworking = working and ctx1 == self['.']
1341 1361 match = match or matchmod.always(self.root, self.getcwd())
1342 1362 listignored, listclean, listunknown = ignored, clean, unknown
1343 1363
1344 1364 # load earliest manifest first for caching reasons
1345 1365 if not working and ctx2.rev() < ctx1.rev():
1346 1366 ctx2.manifest()
1347 1367
1348 1368 if not parentworking:
1349 1369 def bad(f, msg):
1350 1370 if f not in ctx1:
1351 1371 self.ui.warn('%s: %s\n' % (self.dirstate.pathto(f), msg))
1352 1372 match.bad = bad
1353 1373
1354 1374 if working: # we need to scan the working dir
1355 1375 subrepos = []
1356 1376 if '.hgsub' in self.dirstate:
1357 1377 subrepos = ctx2.substate.keys()
1358 1378 s = self.dirstate.status(match, subrepos, listignored,
1359 1379 listclean, listunknown)
1360 1380 cmp, modified, added, removed, deleted, unknown, ignored, clean = s
1361 1381
1362 1382 # check for any possibly clean files
1363 1383 if parentworking and cmp:
1364 1384 fixup = []
1365 1385 # do a full compare of any files that might have changed
1366 1386 for f in sorted(cmp):
1367 1387 if (f not in ctx1 or ctx2.flags(f) != ctx1.flags(f)
1368 1388 or ctx1[f].cmp(ctx2[f])):
1369 1389 modified.append(f)
1370 1390 else:
1371 1391 fixup.append(f)
1372 1392
1373 1393 # update dirstate for files that are actually clean
1374 1394 if fixup:
1375 1395 if listclean:
1376 1396 clean += fixup
1377 1397
1378 1398 try:
1379 1399 # updating the dirstate is optional
1380 1400 # so we don't wait on the lock
1381 1401 wlock = self.wlock(False)
1382 1402 try:
1383 1403 for f in fixup:
1384 1404 self.dirstate.normal(f)
1385 1405 finally:
1386 1406 wlock.release()
1387 1407 except error.LockError:
1388 1408 pass
1389 1409
1390 1410 if not parentworking:
1391 1411 mf1 = mfmatches(ctx1)
1392 1412 if working:
1393 1413 # we are comparing working dir against non-parent
1394 1414 # generate a pseudo-manifest for the working dir
1395 1415 mf2 = mfmatches(self['.'])
1396 1416 for f in cmp + modified + added:
1397 1417 mf2[f] = None
1398 1418 mf2.set(f, ctx2.flags(f))
1399 1419 for f in removed:
1400 1420 if f in mf2:
1401 1421 del mf2[f]
1402 1422 else:
1403 1423 # we are comparing two revisions
1404 1424 deleted, unknown, ignored = [], [], []
1405 1425 mf2 = mfmatches(ctx2)
1406 1426
1407 1427 modified, added, clean = [], [], []
1408 1428 for fn in mf2:
1409 1429 if fn in mf1:
1410 1430 if (fn not in deleted and
1411 1431 (mf1.flags(fn) != mf2.flags(fn) or
1412 1432 (mf1[fn] != mf2[fn] and
1413 1433 (mf2[fn] or ctx1[fn].cmp(ctx2[fn]))))):
1414 1434 modified.append(fn)
1415 1435 elif listclean:
1416 1436 clean.append(fn)
1417 1437 del mf1[fn]
1418 1438 elif fn not in deleted:
1419 1439 added.append(fn)
1420 1440 removed = mf1.keys()
1421 1441
1422 1442 if working and modified and not self.dirstate._checklink:
1423 1443 # Symlink placeholders may get non-symlink-like contents
1424 1444 # via user error or dereferencing by NFS or Samba servers,
1425 1445 # so we filter out any placeholders that don't look like a
1426 1446 # symlink
1427 1447 sane = []
1428 1448 for f in modified:
1429 1449 if ctx2.flags(f) == 'l':
1430 1450 d = ctx2[f].data()
1431 1451 if len(d) >= 1024 or '\n' in d or util.binary(d):
1432 1452 self.ui.debug('ignoring suspect symlink placeholder'
1433 1453 ' "%s"\n' % f)
1434 1454 continue
1435 1455 sane.append(f)
1436 1456 modified = sane
1437 1457
1438 1458 r = modified, added, removed, deleted, unknown, ignored, clean
1439 1459
1440 1460 if listsubrepos:
1441 1461 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
1442 1462 if working:
1443 1463 rev2 = None
1444 1464 else:
1445 1465 rev2 = ctx2.substate[subpath][1]
1446 1466 try:
1447 1467 submatch = matchmod.narrowmatcher(subpath, match)
1448 1468 s = sub.status(rev2, match=submatch, ignored=listignored,
1449 1469 clean=listclean, unknown=listunknown,
1450 1470 listsubrepos=True)
1451 1471 for rfiles, sfiles in zip(r, s):
1452 1472 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
1453 1473 except error.LookupError:
1454 1474 self.ui.status(_("skipping missing subrepository: %s\n")
1455 1475 % subpath)
1456 1476
1457 1477 for l in r:
1458 1478 l.sort()
1459 1479 return r
1460 1480
1461 1481 def heads(self, start=None):
1462 1482 heads = self.changelog.heads(start)
1463 1483 # sort the output in rev descending order
1464 1484 return sorted(heads, key=self.changelog.rev, reverse=True)
1465 1485
1466 1486 def branchheads(self, branch=None, start=None, closed=False):
1467 1487 '''return a (possibly filtered) list of heads for the given branch
1468 1488
1469 1489 Heads are returned in topological order, from newest to oldest.
1470 1490 If branch is None, use the dirstate branch.
1471 1491 If start is not None, return only heads reachable from start.
1472 1492 If closed is True, return heads that are marked as closed as well.
1473 1493 '''
1474 1494 if branch is None:
1475 1495 branch = self[None].branch()
1476 1496 branches = self.branchmap()
1477 1497 if branch not in branches:
1478 1498 return []
1479 1499 # the cache returns heads ordered lowest to highest
1480 1500 bheads = list(reversed(branches[branch]))
1481 1501 if start is not None:
1482 1502 # filter out the heads that cannot be reached from startrev
1483 1503 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
1484 1504 bheads = [h for h in bheads if h in fbheads]
1485 1505 if not closed:
1486 1506 bheads = [h for h in bheads if
1487 1507 ('close' not in self.changelog.read(h)[5])]
1488 1508 return bheads
1489 1509
1490 1510 def branches(self, nodes):
1491 1511 if not nodes:
1492 1512 nodes = [self.changelog.tip()]
1493 1513 b = []
1494 1514 for n in nodes:
1495 1515 t = n
1496 1516 while True:
1497 1517 p = self.changelog.parents(n)
1498 1518 if p[1] != nullid or p[0] == nullid:
1499 1519 b.append((t, n, p[0], p[1]))
1500 1520 break
1501 1521 n = p[0]
1502 1522 return b
1503 1523
1504 1524 def between(self, pairs):
1505 1525 r = []
1506 1526
1507 1527 for top, bottom in pairs:
1508 1528 n, l, i = top, [], 0
1509 1529 f = 1
1510 1530
1511 1531 while n != bottom and n != nullid:
1512 1532 p = self.changelog.parents(n)[0]
1513 1533 if i == f:
1514 1534 l.append(n)
1515 1535 f = f * 2
1516 1536 n = p
1517 1537 i += 1
1518 1538
1519 1539 r.append(l)
1520 1540
1521 1541 return r
1522 1542
1523 1543 def pull(self, remote, heads=None, force=False):
1524 1544 lock = self.lock()
1525 1545 try:
1526 1546 tmp = discovery.findcommonincoming(self, remote, heads=heads,
1527 1547 force=force)
1528 1548 common, fetch, rheads = tmp
1529 1549 if not fetch:
1530 1550 self.ui.status(_("no changes found\n"))
1531 1551 added = []
1532 1552 result = 0
1533 1553 else:
1534 1554 if heads is None and list(common) == [nullid]:
1535 1555 self.ui.status(_("requesting all changes\n"))
1536 1556 elif heads is None and remote.capable('changegroupsubset'):
1537 1557 # issue1320, avoid a race if remote changed after discovery
1538 1558 heads = rheads
1539 1559
1540 1560 if remote.capable('getbundle'):
1541 1561 cg = remote.getbundle('pull', common=common,
1542 1562 heads=heads or rheads)
1543 1563 elif heads is None:
1544 1564 cg = remote.changegroup(fetch, 'pull')
1545 1565 elif not remote.capable('changegroupsubset'):
1546 1566 raise util.Abort(_("partial pull cannot be done because "
1547 1567 "other repository doesn't support "
1548 1568 "changegroupsubset."))
1549 1569 else:
1550 1570 cg = remote.changegroupsubset(fetch, heads, 'pull')
1551 1571 clstart = len(self.changelog)
1552 1572 result = self.addchangegroup(cg, 'pull', remote.url())
1553 1573 clend = len(self.changelog)
1554 1574 added = [self.changelog.node(r) for r in xrange(clstart, clend)]
1555 1575
1556 1576 # compute target subset
1557 1577 if heads is None:
1558 1578 # We pulled every thing possible
1559 1579 # sync on everything common
1560 1580 subset = common + added
1561 1581 else:
1562 1582 # We pulled a specific subset
1563 1583 # sync on this subset
1564 1584 subset = heads
1565 1585
1566 1586 # Get remote phases data from remote
1567 1587 remotephases = remote.listkeys('phases')
1568 1588 publishing = bool(remotephases.get('publishing', False))
1569 1589 if remotephases and not publishing:
1570 1590 # remote is new and unpublishing
1571 1591 pheads, _dr = phases.analyzeremotephases(self, subset,
1572 1592 remotephases)
1573 1593 phases.advanceboundary(self, phases.public, pheads)
1574 1594 phases.advanceboundary(self, phases.draft, subset)
1575 1595 else:
1576 1596 # Remote is old or publishing all common changesets
1577 1597 # should be seen as public
1578 1598 phases.advanceboundary(self, phases.public, subset)
1579 1599 finally:
1580 1600 lock.release()
1581 1601
1582 1602 return result
1583 1603
1584 1604 def checkpush(self, force, revs):
1585 1605 """Extensions can override this function if additional checks have
1586 1606 to be performed before pushing, or call it if they override push
1587 1607 command.
1588 1608 """
1589 1609 pass
1590 1610
1591 1611 def push(self, remote, force=False, revs=None, newbranch=False):
1592 1612 '''Push outgoing changesets (limited by revs) from the current
1593 1613 repository to remote. Return an integer:
1594 1614 - None means nothing to push
1595 1615 - 0 means HTTP error
1596 1616 - 1 means we pushed and remote head count is unchanged *or*
1597 1617 we have outgoing changesets but refused to push
1598 1618 - other values as described by addchangegroup()
1599 1619 '''
1600 1620 # there are two ways to push to remote repo:
1601 1621 #
1602 1622 # addchangegroup assumes local user can lock remote
1603 1623 # repo (local filesystem, old ssh servers).
1604 1624 #
1605 1625 # unbundle assumes local user cannot lock remote repo (new ssh
1606 1626 # servers, http servers).
1607 1627
1608 1628 # get local lock as we might write phase data
1609 1629 locallock = self.lock()
1610 1630 try:
1611 1631 self.checkpush(force, revs)
1612 1632 lock = None
1613 1633 unbundle = remote.capable('unbundle')
1614 1634 if not unbundle:
1615 1635 lock = remote.lock()
1616 1636 try:
1617 1637 # discovery
1618 1638 fci = discovery.findcommonincoming
1619 1639 commoninc = fci(self, remote, force=force)
1620 1640 common, inc, remoteheads = commoninc
1621 1641 fco = discovery.findcommonoutgoing
1622 1642 outgoing = fco(self, remote, onlyheads=revs,
1623 1643 commoninc=commoninc, force=force)
1624 1644
1625 1645
1626 1646 if not outgoing.missing:
1627 1647 # nothing to push
1628 1648 scmutil.nochangesfound(self.ui, outgoing.excluded)
1629 1649 ret = None
1630 1650 else:
1631 1651 # something to push
1632 1652 if not force:
1633 1653 discovery.checkheads(self, remote, outgoing,
1634 1654 remoteheads, newbranch,
1635 1655 bool(inc))
1636 1656
1637 1657 # create a changegroup from local
1638 1658 if revs is None and not outgoing.excluded:
1639 1659 # push everything,
1640 1660 # use the fast path, no race possible on push
1641 1661 cg = self._changegroup(outgoing.missing, 'push')
1642 1662 else:
1643 1663 cg = self.getlocalbundle('push', outgoing)
1644 1664
1645 1665 # apply changegroup to remote
1646 1666 if unbundle:
1647 1667 # local repo finds heads on server, finds out what
1648 1668 # revs it must push. once revs transferred, if server
1649 1669 # finds it has different heads (someone else won
1650 1670 # commit/push race), server aborts.
1651 1671 if force:
1652 1672 remoteheads = ['force']
1653 1673 # ssh: return remote's addchangegroup()
1654 1674 # http: return remote's addchangegroup() or 0 for error
1655 1675 ret = remote.unbundle(cg, remoteheads, 'push')
1656 1676 else:
1657 1677 # we return an integer indicating remote head count change
1658 1678 ret = remote.addchangegroup(cg, 'push', self.url())
1659 1679
1660 1680 if ret:
1661 1681 # push succeed, synchonize target of the push
1662 1682 cheads = outgoing.missingheads
1663 1683 elif revs is None:
1664 1684 # All out push fails. synchronize all common
1665 1685 cheads = outgoing.commonheads
1666 1686 else:
1667 1687 # I want cheads = heads(::missingheads and ::commonheads)
1668 1688 # (missingheads is revs with secret changeset filtered out)
1669 1689 #
1670 1690 # This can be expressed as:
1671 1691 # cheads = ( (missingheads and ::commonheads)
1672 1692 # + (commonheads and ::missingheads))"
1673 1693 # )
1674 1694 #
1675 1695 # while trying to push we already computed the following:
1676 1696 # common = (::commonheads)
1677 1697 # missing = ((commonheads::missingheads) - commonheads)
1678 1698 #
1679 1699 # We can pick:
1680 1700 # * missingheads part of comon (::commonheads)
1681 1701 common = set(outgoing.common)
1682 1702 cheads = [node for node in revs if node in common]
1683 1703 # and
1684 1704 # * commonheads parents on missing
1685 1705 revset = self.set('%ln and parents(roots(%ln))',
1686 1706 outgoing.commonheads,
1687 1707 outgoing.missing)
1688 1708 cheads.extend(c.node() for c in revset)
1689 1709 # even when we don't push, exchanging phase data is useful
1690 1710 remotephases = remote.listkeys('phases')
1691 1711 if not remotephases: # old server or public only repo
1692 1712 phases.advanceboundary(self, phases.public, cheads)
1693 1713 # don't push any phase data as there is nothing to push
1694 1714 else:
1695 1715 ana = phases.analyzeremotephases(self, cheads, remotephases)
1696 1716 pheads, droots = ana
1697 1717 ### Apply remote phase on local
1698 1718 if remotephases.get('publishing', False):
1699 1719 phases.advanceboundary(self, phases.public, cheads)
1700 1720 else: # publish = False
1701 1721 phases.advanceboundary(self, phases.public, pheads)
1702 1722 phases.advanceboundary(self, phases.draft, cheads)
1703 1723 ### Apply local phase on remote
1704 1724
1705 1725 # Get the list of all revs draft on remote by public here.
1706 1726 # XXX Beware that revset break if droots is not strictly
1707 1727 # XXX root we may want to ensure it is but it is costly
1708 1728 outdated = self.set('heads((%ln::%ln) and public())',
1709 1729 droots, cheads)
1710 1730 for newremotehead in outdated:
1711 1731 r = remote.pushkey('phases',
1712 1732 newremotehead.hex(),
1713 1733 str(phases.draft),
1714 1734 str(phases.public))
1715 1735 if not r:
1716 1736 self.ui.warn(_('updating %s to public failed!\n')
1717 1737 % newremotehead)
1718 1738 finally:
1719 1739 if lock is not None:
1720 1740 lock.release()
1721 1741 finally:
1722 1742 locallock.release()
1723 1743
1724 1744 self.ui.debug("checking for updated bookmarks\n")
1725 1745 rb = remote.listkeys('bookmarks')
1726 1746 for k in rb.keys():
1727 1747 if k in self._bookmarks:
1728 1748 nr, nl = rb[k], hex(self._bookmarks[k])
1729 1749 if nr in self:
1730 1750 cr = self[nr]
1731 1751 cl = self[nl]
1732 1752 if cl in cr.descendants():
1733 1753 r = remote.pushkey('bookmarks', k, nr, nl)
1734 1754 if r:
1735 1755 self.ui.status(_("updating bookmark %s\n") % k)
1736 1756 else:
1737 1757 self.ui.warn(_('updating bookmark %s'
1738 1758 ' failed!\n') % k)
1739 1759
1740 1760 return ret
1741 1761
1742 1762 def changegroupinfo(self, nodes, source):
1743 1763 if self.ui.verbose or source == 'bundle':
1744 1764 self.ui.status(_("%d changesets found\n") % len(nodes))
1745 1765 if self.ui.debugflag:
1746 1766 self.ui.debug("list of changesets:\n")
1747 1767 for node in nodes:
1748 1768 self.ui.debug("%s\n" % hex(node))
1749 1769
1750 1770 def changegroupsubset(self, bases, heads, source):
1751 1771 """Compute a changegroup consisting of all the nodes that are
1752 1772 descendants of any of the bases and ancestors of any of the heads.
1753 1773 Return a chunkbuffer object whose read() method will return
1754 1774 successive changegroup chunks.
1755 1775
1756 1776 It is fairly complex as determining which filenodes and which
1757 1777 manifest nodes need to be included for the changeset to be complete
1758 1778 is non-trivial.
1759 1779
1760 1780 Another wrinkle is doing the reverse, figuring out which changeset in
1761 1781 the changegroup a particular filenode or manifestnode belongs to.
1762 1782 """
1763 1783 cl = self.changelog
1764 1784 if not bases:
1765 1785 bases = [nullid]
1766 1786 csets, bases, heads = cl.nodesbetween(bases, heads)
1767 1787 # We assume that all ancestors of bases are known
1768 1788 common = set(cl.ancestors(*[cl.rev(n) for n in bases]))
1769 1789 return self._changegroupsubset(common, csets, heads, source)
1770 1790
1771 1791 def getlocalbundle(self, source, outgoing):
1772 1792 """Like getbundle, but taking a discovery.outgoing as an argument.
1773 1793
1774 1794 This is only implemented for local repos and reuses potentially
1775 1795 precomputed sets in outgoing."""
1776 1796 if not outgoing.missing:
1777 1797 return None
1778 1798 return self._changegroupsubset(outgoing.common,
1779 1799 outgoing.missing,
1780 1800 outgoing.missingheads,
1781 1801 source)
1782 1802
1783 1803 def getbundle(self, source, heads=None, common=None):
1784 1804 """Like changegroupsubset, but returns the set difference between the
1785 1805 ancestors of heads and the ancestors common.
1786 1806
1787 1807 If heads is None, use the local heads. If common is None, use [nullid].
1788 1808
1789 1809 The nodes in common might not all be known locally due to the way the
1790 1810 current discovery protocol works.
1791 1811 """
1792 1812 cl = self.changelog
1793 1813 if common:
1794 1814 nm = cl.nodemap
1795 1815 common = [n for n in common if n in nm]
1796 1816 else:
1797 1817 common = [nullid]
1798 1818 if not heads:
1799 1819 heads = cl.heads()
1800 1820 return self.getlocalbundle(source,
1801 1821 discovery.outgoing(cl, common, heads))
1802 1822
1803 1823 def _changegroupsubset(self, commonrevs, csets, heads, source):
1804 1824
1805 1825 cl = self.changelog
1806 1826 mf = self.manifest
1807 1827 mfs = {} # needed manifests
1808 1828 fnodes = {} # needed file nodes
1809 1829 changedfiles = set()
1810 1830 fstate = ['', {}]
1811 1831 count = [0]
1812 1832
1813 1833 # can we go through the fast path ?
1814 1834 heads.sort()
1815 1835 if heads == sorted(self.heads()):
1816 1836 return self._changegroup(csets, source)
1817 1837
1818 1838 # slow path
1819 1839 self.hook('preoutgoing', throw=True, source=source)
1820 1840 self.changegroupinfo(csets, source)
1821 1841
1822 1842 # filter any nodes that claim to be part of the known set
1823 1843 def prune(revlog, missing):
1824 1844 return [n for n in missing
1825 1845 if revlog.linkrev(revlog.rev(n)) not in commonrevs]
1826 1846
1827 1847 def lookup(revlog, x):
1828 1848 if revlog == cl:
1829 1849 c = cl.read(x)
1830 1850 changedfiles.update(c[3])
1831 1851 mfs.setdefault(c[0], x)
1832 1852 count[0] += 1
1833 1853 self.ui.progress(_('bundling'), count[0],
1834 1854 unit=_('changesets'), total=len(csets))
1835 1855 return x
1836 1856 elif revlog == mf:
1837 1857 clnode = mfs[x]
1838 1858 mdata = mf.readfast(x)
1839 1859 for f in changedfiles:
1840 1860 if f in mdata:
1841 1861 fnodes.setdefault(f, {}).setdefault(mdata[f], clnode)
1842 1862 count[0] += 1
1843 1863 self.ui.progress(_('bundling'), count[0],
1844 1864 unit=_('manifests'), total=len(mfs))
1845 1865 return mfs[x]
1846 1866 else:
1847 1867 self.ui.progress(
1848 1868 _('bundling'), count[0], item=fstate[0],
1849 1869 unit=_('files'), total=len(changedfiles))
1850 1870 return fstate[1][x]
1851 1871
1852 1872 bundler = changegroup.bundle10(lookup)
1853 1873 reorder = self.ui.config('bundle', 'reorder', 'auto')
1854 1874 if reorder == 'auto':
1855 1875 reorder = None
1856 1876 else:
1857 1877 reorder = util.parsebool(reorder)
1858 1878
1859 1879 def gengroup():
1860 1880 # Create a changenode group generator that will call our functions
1861 1881 # back to lookup the owning changenode and collect information.
1862 1882 for chunk in cl.group(csets, bundler, reorder=reorder):
1863 1883 yield chunk
1864 1884 self.ui.progress(_('bundling'), None)
1865 1885
1866 1886 # Create a generator for the manifestnodes that calls our lookup
1867 1887 # and data collection functions back.
1868 1888 count[0] = 0
1869 1889 for chunk in mf.group(prune(mf, mfs), bundler, reorder=reorder):
1870 1890 yield chunk
1871 1891 self.ui.progress(_('bundling'), None)
1872 1892
1873 1893 mfs.clear()
1874 1894
1875 1895 # Go through all our files in order sorted by name.
1876 1896 count[0] = 0
1877 1897 for fname in sorted(changedfiles):
1878 1898 filerevlog = self.file(fname)
1879 1899 if not len(filerevlog):
1880 1900 raise util.Abort(_("empty or missing revlog for %s") % fname)
1881 1901 fstate[0] = fname
1882 1902 fstate[1] = fnodes.pop(fname, {})
1883 1903
1884 1904 nodelist = prune(filerevlog, fstate[1])
1885 1905 if nodelist:
1886 1906 count[0] += 1
1887 1907 yield bundler.fileheader(fname)
1888 1908 for chunk in filerevlog.group(nodelist, bundler, reorder):
1889 1909 yield chunk
1890 1910
1891 1911 # Signal that no more groups are left.
1892 1912 yield bundler.close()
1893 1913 self.ui.progress(_('bundling'), None)
1894 1914
1895 1915 if csets:
1896 1916 self.hook('outgoing', node=hex(csets[0]), source=source)
1897 1917
1898 1918 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1899 1919
1900 1920 def changegroup(self, basenodes, source):
1901 1921 # to avoid a race we use changegroupsubset() (issue1320)
1902 1922 return self.changegroupsubset(basenodes, self.heads(), source)
1903 1923
1904 1924 def _changegroup(self, nodes, source):
1905 1925 """Compute the changegroup of all nodes that we have that a recipient
1906 1926 doesn't. Return a chunkbuffer object whose read() method will return
1907 1927 successive changegroup chunks.
1908 1928
1909 1929 This is much easier than the previous function as we can assume that
1910 1930 the recipient has any changenode we aren't sending them.
1911 1931
1912 1932 nodes is the set of nodes to send"""
1913 1933
1914 1934 cl = self.changelog
1915 1935 mf = self.manifest
1916 1936 mfs = {}
1917 1937 changedfiles = set()
1918 1938 fstate = ['']
1919 1939 count = [0]
1920 1940
1921 1941 self.hook('preoutgoing', throw=True, source=source)
1922 1942 self.changegroupinfo(nodes, source)
1923 1943
1924 1944 revset = set([cl.rev(n) for n in nodes])
1925 1945
1926 1946 def gennodelst(log):
1927 1947 return [log.node(r) for r in log if log.linkrev(r) in revset]
1928 1948
1929 1949 def lookup(revlog, x):
1930 1950 if revlog == cl:
1931 1951 c = cl.read(x)
1932 1952 changedfiles.update(c[3])
1933 1953 mfs.setdefault(c[0], x)
1934 1954 count[0] += 1
1935 1955 self.ui.progress(_('bundling'), count[0],
1936 1956 unit=_('changesets'), total=len(nodes))
1937 1957 return x
1938 1958 elif revlog == mf:
1939 1959 count[0] += 1
1940 1960 self.ui.progress(_('bundling'), count[0],
1941 1961 unit=_('manifests'), total=len(mfs))
1942 1962 return cl.node(revlog.linkrev(revlog.rev(x)))
1943 1963 else:
1944 1964 self.ui.progress(
1945 1965 _('bundling'), count[0], item=fstate[0],
1946 1966 total=len(changedfiles), unit=_('files'))
1947 1967 return cl.node(revlog.linkrev(revlog.rev(x)))
1948 1968
1949 1969 bundler = changegroup.bundle10(lookup)
1950 1970 reorder = self.ui.config('bundle', 'reorder', 'auto')
1951 1971 if reorder == 'auto':
1952 1972 reorder = None
1953 1973 else:
1954 1974 reorder = util.parsebool(reorder)
1955 1975
1956 1976 def gengroup():
1957 1977 '''yield a sequence of changegroup chunks (strings)'''
1958 1978 # construct a list of all changed files
1959 1979
1960 1980 for chunk in cl.group(nodes, bundler, reorder=reorder):
1961 1981 yield chunk
1962 1982 self.ui.progress(_('bundling'), None)
1963 1983
1964 1984 count[0] = 0
1965 1985 for chunk in mf.group(gennodelst(mf), bundler, reorder=reorder):
1966 1986 yield chunk
1967 1987 self.ui.progress(_('bundling'), None)
1968 1988
1969 1989 count[0] = 0
1970 1990 for fname in sorted(changedfiles):
1971 1991 filerevlog = self.file(fname)
1972 1992 if not len(filerevlog):
1973 1993 raise util.Abort(_("empty or missing revlog for %s") % fname)
1974 1994 fstate[0] = fname
1975 1995 nodelist = gennodelst(filerevlog)
1976 1996 if nodelist:
1977 1997 count[0] += 1
1978 1998 yield bundler.fileheader(fname)
1979 1999 for chunk in filerevlog.group(nodelist, bundler, reorder):
1980 2000 yield chunk
1981 2001 yield bundler.close()
1982 2002 self.ui.progress(_('bundling'), None)
1983 2003
1984 2004 if nodes:
1985 2005 self.hook('outgoing', node=hex(nodes[0]), source=source)
1986 2006
1987 2007 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1988 2008
1989 2009 def addchangegroup(self, source, srctype, url, emptyok=False):
1990 2010 """Add the changegroup returned by source.read() to this repo.
1991 2011 srctype is a string like 'push', 'pull', or 'unbundle'. url is
1992 2012 the URL of the repo where this changegroup is coming from.
1993 2013
1994 2014 Return an integer summarizing the change to this repo:
1995 2015 - nothing changed or no source: 0
1996 2016 - more heads than before: 1+added heads (2..n)
1997 2017 - fewer heads than before: -1-removed heads (-2..-n)
1998 2018 - number of heads stays the same: 1
1999 2019 """
2000 2020 def csmap(x):
2001 2021 self.ui.debug("add changeset %s\n" % short(x))
2002 2022 return len(cl)
2003 2023
2004 2024 def revmap(x):
2005 2025 return cl.rev(x)
2006 2026
2007 2027 if not source:
2008 2028 return 0
2009 2029
2010 2030 self.hook('prechangegroup', throw=True, source=srctype, url=url)
2011 2031
2012 2032 changesets = files = revisions = 0
2013 2033 efiles = set()
2014 2034
2015 2035 # write changelog data to temp files so concurrent readers will not see
2016 2036 # inconsistent view
2017 2037 cl = self.changelog
2018 2038 cl.delayupdate()
2019 2039 oldheads = cl.heads()
2020 2040
2021 2041 tr = self.transaction("\n".join([srctype, util.hidepassword(url)]))
2022 2042 try:
2023 2043 trp = weakref.proxy(tr)
2024 2044 # pull off the changeset group
2025 2045 self.ui.status(_("adding changesets\n"))
2026 2046 clstart = len(cl)
2027 2047 class prog(object):
2028 2048 step = _('changesets')
2029 2049 count = 1
2030 2050 ui = self.ui
2031 2051 total = None
2032 2052 def __call__(self):
2033 2053 self.ui.progress(self.step, self.count, unit=_('chunks'),
2034 2054 total=self.total)
2035 2055 self.count += 1
2036 2056 pr = prog()
2037 2057 source.callback = pr
2038 2058
2039 2059 source.changelogheader()
2040 2060 srccontent = cl.addgroup(source, csmap, trp)
2041 2061 if not (srccontent or emptyok):
2042 2062 raise util.Abort(_("received changelog group is empty"))
2043 2063 clend = len(cl)
2044 2064 changesets = clend - clstart
2045 2065 for c in xrange(clstart, clend):
2046 2066 efiles.update(self[c].files())
2047 2067 efiles = len(efiles)
2048 2068 self.ui.progress(_('changesets'), None)
2049 2069
2050 2070 # pull off the manifest group
2051 2071 self.ui.status(_("adding manifests\n"))
2052 2072 pr.step = _('manifests')
2053 2073 pr.count = 1
2054 2074 pr.total = changesets # manifests <= changesets
2055 2075 # no need to check for empty manifest group here:
2056 2076 # if the result of the merge of 1 and 2 is the same in 3 and 4,
2057 2077 # no new manifest will be created and the manifest group will
2058 2078 # be empty during the pull
2059 2079 source.manifestheader()
2060 2080 self.manifest.addgroup(source, revmap, trp)
2061 2081 self.ui.progress(_('manifests'), None)
2062 2082
2063 2083 needfiles = {}
2064 2084 if self.ui.configbool('server', 'validate', default=False):
2065 2085 # validate incoming csets have their manifests
2066 2086 for cset in xrange(clstart, clend):
2067 2087 mfest = self.changelog.read(self.changelog.node(cset))[0]
2068 2088 mfest = self.manifest.readdelta(mfest)
2069 2089 # store file nodes we must see
2070 2090 for f, n in mfest.iteritems():
2071 2091 needfiles.setdefault(f, set()).add(n)
2072 2092
2073 2093 # process the files
2074 2094 self.ui.status(_("adding file changes\n"))
2075 2095 pr.step = _('files')
2076 2096 pr.count = 1
2077 2097 pr.total = efiles
2078 2098 source.callback = None
2079 2099
2080 2100 while True:
2081 2101 chunkdata = source.filelogheader()
2082 2102 if not chunkdata:
2083 2103 break
2084 2104 f = chunkdata["filename"]
2085 2105 self.ui.debug("adding %s revisions\n" % f)
2086 2106 pr()
2087 2107 fl = self.file(f)
2088 2108 o = len(fl)
2089 2109 if not fl.addgroup(source, revmap, trp):
2090 2110 raise util.Abort(_("received file revlog group is empty"))
2091 2111 revisions += len(fl) - o
2092 2112 files += 1
2093 2113 if f in needfiles:
2094 2114 needs = needfiles[f]
2095 2115 for new in xrange(o, len(fl)):
2096 2116 n = fl.node(new)
2097 2117 if n in needs:
2098 2118 needs.remove(n)
2099 2119 if not needs:
2100 2120 del needfiles[f]
2101 2121 self.ui.progress(_('files'), None)
2102 2122
2103 2123 for f, needs in needfiles.iteritems():
2104 2124 fl = self.file(f)
2105 2125 for n in needs:
2106 2126 try:
2107 2127 fl.rev(n)
2108 2128 except error.LookupError:
2109 2129 raise util.Abort(
2110 2130 _('missing file data for %s:%s - run hg verify') %
2111 2131 (f, hex(n)))
2112 2132
2113 2133 dh = 0
2114 2134 if oldheads:
2115 2135 heads = cl.heads()
2116 2136 dh = len(heads) - len(oldheads)
2117 2137 for h in heads:
2118 2138 if h not in oldheads and 'close' in self[h].extra():
2119 2139 dh -= 1
2120 2140 htext = ""
2121 2141 if dh:
2122 2142 htext = _(" (%+d heads)") % dh
2123 2143
2124 2144 self.ui.status(_("added %d changesets"
2125 2145 " with %d changes to %d files%s\n")
2126 2146 % (changesets, revisions, files, htext))
2127 2147
2128 2148 if changesets > 0:
2129 2149 p = lambda: cl.writepending() and self.root or ""
2130 2150 self.hook('pretxnchangegroup', throw=True,
2131 2151 node=hex(cl.node(clstart)), source=srctype,
2132 2152 url=url, pending=p)
2133 2153
2134 2154 added = [cl.node(r) for r in xrange(clstart, clend)]
2135 2155 publishing = self.ui.configbool('phases', 'publish', True)
2136 2156 if srctype == 'push':
2137 2157 # Old server can not push the boundary themself.
2138 2158 # New server won't push the boundary if changeset already
2139 2159 # existed locally as secrete
2140 2160 #
2141 2161 # We should not use added here but the list of all change in
2142 2162 # the bundle
2143 2163 if publishing:
2144 2164 phases.advanceboundary(self, phases.public, srccontent)
2145 2165 else:
2146 2166 phases.advanceboundary(self, phases.draft, srccontent)
2147 2167 phases.retractboundary(self, phases.draft, added)
2148 2168 elif srctype != 'strip':
2149 2169 # publishing only alter behavior during push
2150 2170 #
2151 2171 # strip should not touch boundary at all
2152 2172 phases.retractboundary(self, phases.draft, added)
2153 2173
2154 2174 # make changelog see real files again
2155 2175 cl.finalize(trp)
2156 2176
2157 2177 tr.close()
2158 2178
2159 2179 if changesets > 0:
2160 2180 def runhooks():
2161 2181 # forcefully update the on-disk branch cache
2162 2182 self.ui.debug("updating the branch cache\n")
2163 2183 self.updatebranchcache()
2164 2184 self.hook("changegroup", node=hex(cl.node(clstart)),
2165 2185 source=srctype, url=url)
2166 2186
2167 2187 for n in added:
2168 2188 self.hook("incoming", node=hex(n), source=srctype,
2169 2189 url=url)
2170 2190 self._afterlock(runhooks)
2171 2191
2172 2192 finally:
2173 2193 tr.release()
2174 2194 # never return 0 here:
2175 2195 if dh < 0:
2176 2196 return dh - 1
2177 2197 else:
2178 2198 return dh + 1
2179 2199
2180 2200 def stream_in(self, remote, requirements):
2181 2201 lock = self.lock()
2182 2202 try:
2183 2203 fp = remote.stream_out()
2184 2204 l = fp.readline()
2185 2205 try:
2186 2206 resp = int(l)
2187 2207 except ValueError:
2188 2208 raise error.ResponseError(
2189 2209 _('Unexpected response from remote server:'), l)
2190 2210 if resp == 1:
2191 2211 raise util.Abort(_('operation forbidden by server'))
2192 2212 elif resp == 2:
2193 2213 raise util.Abort(_('locking the remote repository failed'))
2194 2214 elif resp != 0:
2195 2215 raise util.Abort(_('the server sent an unknown error code'))
2196 2216 self.ui.status(_('streaming all changes\n'))
2197 2217 l = fp.readline()
2198 2218 try:
2199 2219 total_files, total_bytes = map(int, l.split(' ', 1))
2200 2220 except (ValueError, TypeError):
2201 2221 raise error.ResponseError(
2202 2222 _('Unexpected response from remote server:'), l)
2203 2223 self.ui.status(_('%d files to transfer, %s of data\n') %
2204 2224 (total_files, util.bytecount(total_bytes)))
2205 2225 start = time.time()
2206 2226 for i in xrange(total_files):
2207 2227 # XXX doesn't support '\n' or '\r' in filenames
2208 2228 l = fp.readline()
2209 2229 try:
2210 2230 name, size = l.split('\0', 1)
2211 2231 size = int(size)
2212 2232 except (ValueError, TypeError):
2213 2233 raise error.ResponseError(
2214 2234 _('Unexpected response from remote server:'), l)
2215 2235 self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
2216 2236 # for backwards compat, name was partially encoded
2217 2237 ofp = self.sopener(store.decodedir(name), 'w')
2218 2238 for chunk in util.filechunkiter(fp, limit=size):
2219 2239 ofp.write(chunk)
2220 2240 ofp.close()
2221 2241 elapsed = time.time() - start
2222 2242 if elapsed <= 0:
2223 2243 elapsed = 0.001
2224 2244 self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
2225 2245 (util.bytecount(total_bytes), elapsed,
2226 2246 util.bytecount(total_bytes / elapsed)))
2227 2247
2228 2248 # new requirements = old non-format requirements + new format-related
2229 2249 # requirements from the streamed-in repository
2230 2250 requirements.update(set(self.requirements) - self.supportedformats)
2231 2251 self._applyrequirements(requirements)
2232 2252 self._writerequirements()
2233 2253
2234 2254 self.invalidate()
2235 2255 return len(self.heads()) + 1
2236 2256 finally:
2237 2257 lock.release()
2238 2258
2239 2259 def clone(self, remote, heads=[], stream=False):
2240 2260 '''clone remote repository.
2241 2261
2242 2262 keyword arguments:
2243 2263 heads: list of revs to clone (forces use of pull)
2244 2264 stream: use streaming clone if possible'''
2245 2265
2246 2266 # now, all clients that can request uncompressed clones can
2247 2267 # read repo formats supported by all servers that can serve
2248 2268 # them.
2249 2269
2250 2270 # if revlog format changes, client will have to check version
2251 2271 # and format flags on "stream" capability, and use
2252 2272 # uncompressed only if compatible.
2253 2273
2254 2274 if stream and not heads:
2255 2275 # 'stream' means remote revlog format is revlogv1 only
2256 2276 if remote.capable('stream'):
2257 2277 return self.stream_in(remote, set(('revlogv1',)))
2258 2278 # otherwise, 'streamreqs' contains the remote revlog format
2259 2279 streamreqs = remote.capable('streamreqs')
2260 2280 if streamreqs:
2261 2281 streamreqs = set(streamreqs.split(','))
2262 2282 # if we support it, stream in and adjust our requirements
2263 2283 if not streamreqs - self.supportedformats:
2264 2284 return self.stream_in(remote, streamreqs)
2265 2285 return self.pull(remote, heads)
2266 2286
2267 2287 def pushkey(self, namespace, key, old, new):
2268 2288 self.hook('prepushkey', throw=True, namespace=namespace, key=key,
2269 2289 old=old, new=new)
2270 2290 ret = pushkey.push(self, namespace, key, old, new)
2271 2291 self.hook('pushkey', namespace=namespace, key=key, old=old, new=new,
2272 2292 ret=ret)
2273 2293 return ret
2274 2294
2275 2295 def listkeys(self, namespace):
2276 2296 self.hook('prelistkeys', throw=True, namespace=namespace)
2277 2297 values = pushkey.list(self, namespace)
2278 2298 self.hook('listkeys', namespace=namespace, values=values)
2279 2299 return values
2280 2300
2281 2301 def debugwireargs(self, one, two, three=None, four=None, five=None):
2282 2302 '''used to test argument passing over the wire'''
2283 2303 return "%s %s %s %s %s" % (one, two, three, four, five)
2284 2304
2285 2305 def savecommitmessage(self, text):
2286 2306 fp = self.opener('last-message.txt', 'wb')
2287 2307 try:
2288 2308 fp.write(text)
2289 2309 finally:
2290 2310 fp.close()
2291 2311 return self.pathto(fp.name[len(self.root)+1:])
2292 2312
2293 2313 # used to avoid circular references so destructors work
2294 2314 def aftertrans(files):
2295 2315 renamefiles = [tuple(t) for t in files]
2296 2316 def a():
2297 2317 for src, dest in renamefiles:
2298 2318 util.rename(src, dest)
2299 2319 return a
2300 2320
2301 2321 def undoname(fn):
2302 2322 base, name = os.path.split(fn)
2303 2323 assert name.startswith('journal')
2304 2324 return os.path.join(base, name.replace('journal', 'undo', 1))
2305 2325
2306 2326 def instance(ui, path, create):
2307 2327 return localrepository(ui, util.urllocalpath(path), create)
2308 2328
2309 2329 def islocal(path):
2310 2330 return True
@@ -1,660 +1,657 b''
1 1 $ check_code="$TESTDIR"/../contrib/check-code.py
2 2 $ cd "$TESTDIR"/..
3 3
4 4 $ "$check_code" `hg manifest` || echo 'FAILURE IS NOT AN OPTION!!!'
5 5
6 6 $ "$check_code" --warnings --nolineno --per-file=0 `hg manifest`
7 7 contrib/check-code.py:0:
8 8 > # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=', "don't use underbars in identifiers"),
9 9 warning: line over 80 characters
10 10 contrib/perf.py:0:
11 11 > except:
12 12 warning: naked except clause
13 13 contrib/perf.py:0:
14 14 > #timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False, False))))
15 15 warning: line over 80 characters
16 16 contrib/perf.py:0:
17 17 > except:
18 18 warning: naked except clause
19 19 contrib/setup3k.py:0:
20 20 > except:
21 21 warning: naked except clause
22 22 contrib/setup3k.py:0:
23 23 > except:
24 24 warning: naked except clause
25 25 contrib/setup3k.py:0:
26 26 > except:
27 27 warning: naked except clause
28 28 warning: naked except clause
29 29 warning: naked except clause
30 30 contrib/shrink-revlog.py:0:
31 31 > '(You can delete those files when you are satisfied that your\n'
32 32 warning: line over 80 characters
33 33 contrib/shrink-revlog.py:0:
34 34 > ('', 'sort', 'reversepostorder', 'name of sort algorithm to use'),
35 35 warning: line over 80 characters
36 36 contrib/shrink-revlog.py:0:
37 37 > [('', 'revlog', '', _('index (.i) file of the revlog to shrink')),
38 38 warning: line over 80 characters
39 39 contrib/shrink-revlog.py:0:
40 40 > except:
41 41 warning: naked except clause
42 42 doc/gendoc.py:0:
43 43 > "together with Mercurial. Help for other extensions is available "
44 44 warning: line over 80 characters
45 45 hgext/bugzilla.py:0:
46 46 > raise util.Abort(_('cannot find bugzilla user id for %s or %s') %
47 47 warning: line over 80 characters
48 48 hgext/bugzilla.py:0:
49 49 > bzdir = self.ui.config('bugzilla', 'bzdir', '/var/www/html/bugzilla')
50 50 warning: line over 80 characters
51 51 hgext/convert/__init__.py:0:
52 52 > ('', 'ancestors', '', _('show current changeset in ancestor branches')),
53 53 warning: line over 80 characters
54 54 hgext/convert/bzr.py:0:
55 55 > except:
56 56 warning: naked except clause
57 57 hgext/convert/common.py:0:
58 58 > except:
59 59 warning: naked except clause
60 60 hgext/convert/common.py:0:
61 61 > except:
62 62 warning: naked except clause
63 63 warning: naked except clause
64 64 hgext/convert/convcmd.py:0:
65 65 > except:
66 66 warning: naked except clause
67 67 hgext/convert/cvs.py:0:
68 68 > # /1 :pserver:user@example.com:2401/cvsroot/foo Ah<Z
69 69 warning: line over 80 characters
70 70 hgext/convert/cvsps.py:0:
71 71 > assert len(branches) == 1, 'unknown branch: %s' % e.mergepoint
72 72 warning: line over 80 characters
73 73 hgext/convert/cvsps.py:0:
74 74 > ui.write('Ancestors: %s\n' % (','.join(r)))
75 75 warning: unwrapped ui message
76 76 hgext/convert/cvsps.py:0:
77 77 > ui.write('Parent: %d\n' % cs.parents[0].id)
78 78 warning: unwrapped ui message
79 79 hgext/convert/cvsps.py:0:
80 80 > ui.write('Parents: %s\n' %
81 81 warning: unwrapped ui message
82 82 hgext/convert/cvsps.py:0:
83 83 > except:
84 84 warning: naked except clause
85 85 hgext/convert/cvsps.py:0:
86 86 > ui.write('Branchpoints: %s \n' % ', '.join(branchpoints))
87 87 warning: unwrapped ui message
88 88 hgext/convert/cvsps.py:0:
89 89 > ui.write('Author: %s\n' % cs.author)
90 90 warning: unwrapped ui message
91 91 hgext/convert/cvsps.py:0:
92 92 > ui.write('Branch: %s\n' % (cs.branch or 'HEAD'))
93 93 warning: unwrapped ui message
94 94 hgext/convert/cvsps.py:0:
95 95 > ui.write('Date: %s\n' % util.datestr(cs.date,
96 96 warning: unwrapped ui message
97 97 hgext/convert/cvsps.py:0:
98 98 > ui.write('Log:\n')
99 99 warning: unwrapped ui message
100 100 hgext/convert/cvsps.py:0:
101 101 > ui.write('Members: \n')
102 102 warning: unwrapped ui message
103 103 hgext/convert/cvsps.py:0:
104 104 > ui.write('PatchSet %d \n' % cs.id)
105 105 warning: unwrapped ui message
106 106 hgext/convert/cvsps.py:0:
107 107 > ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags) > 1],
108 108 warning: unwrapped ui message
109 109 hgext/convert/git.py:0:
110 110 > except:
111 111 warning: naked except clause
112 112 hgext/convert/git.py:0:
113 113 > fh = self.gitopen('git diff-tree --name-only --root -r %s "%s^%s" --'
114 114 warning: line over 80 characters
115 115 hgext/convert/hg.py:0:
116 116 > # detect missing revlogs and abort on errors or populate self.ignored
117 117 warning: line over 80 characters
118 118 hgext/convert/hg.py:0:
119 119 > except:
120 120 warning: naked except clause
121 121 warning: naked except clause
122 122 hgext/convert/hg.py:0:
123 123 > except:
124 124 warning: naked except clause
125 125 hgext/convert/monotone.py:0:
126 126 > except:
127 127 warning: naked except clause
128 128 hgext/convert/monotone.py:0:
129 129 > except:
130 130 warning: naked except clause
131 131 hgext/convert/subversion.py:0:
132 132 > raise util.Abort(_('svn: branch has no revision %s') % to_revnum)
133 133 warning: line over 80 characters
134 134 hgext/convert/subversion.py:0:
135 135 > except:
136 136 warning: naked except clause
137 137 hgext/convert/subversion.py:0:
138 138 > args = [self.baseurl, relpaths, start, end, limit, discover_changed_paths,
139 139 warning: line over 80 characters
140 140 hgext/convert/subversion.py:0:
141 141 > self.trunkname = self.ui.config('convert', 'svn.trunk', 'trunk').strip('/')
142 142 warning: line over 80 characters
143 143 hgext/convert/subversion.py:0:
144 144 > except:
145 145 warning: naked except clause
146 146 hgext/convert/subversion.py:0:
147 147 > def get_log_child(fp, url, paths, start, end, limit=0, discover_changed_paths=True,
148 148 warning: line over 80 characters
149 149 hgext/eol.py:0:
150 150 > if ui.configbool('eol', 'fix-trailing-newline', False) and s and s[-1] != '\n':
151 151 warning: line over 80 characters
152 152 warning: line over 80 characters
153 153 hgext/gpg.py:0:
154 154 > except:
155 155 warning: naked except clause
156 156 hgext/hgcia.py:0:
157 157 > except:
158 158 warning: naked except clause
159 159 hgext/hgk.py:0:
160 160 > ui.write("%s%s\n" % (prefix, description.replace('\n', nlprefix).strip()))
161 161 warning: line over 80 characters
162 162 hgext/hgk.py:0:
163 163 > ui.write("parent %s\n" % p)
164 164 warning: unwrapped ui message
165 165 hgext/hgk.py:0:
166 166 > ui.write('k=%s\nv=%s\n' % (name, value))
167 167 warning: unwrapped ui message
168 168 hgext/hgk.py:0:
169 169 > ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
170 170 warning: unwrapped ui message
171 171 hgext/hgk.py:0:
172 172 > ui.write("branch %s\n\n" % ctx.branch())
173 173 warning: unwrapped ui message
174 174 hgext/hgk.py:0:
175 175 > ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
176 176 warning: unwrapped ui message
177 177 hgext/hgk.py:0:
178 178 > ui.write("revision %d\n" % ctx.rev())
179 179 warning: unwrapped ui message
180 180 hgext/hgk.py:0:
181 181 > ui.write("tree %s\n" % short(ctx.changeset()[0])) # use ctx.node() instead ??
182 182 warning: line over 80 characters
183 183 warning: unwrapped ui message
184 184 hgext/highlight/__init__.py:0:
185 185 > extensions.wrapfunction(webcommands, '_filerevision', filerevision_highlight)
186 186 warning: line over 80 characters
187 187 hgext/highlight/__init__.py:0:
188 188 > return ['/* pygments_style = %s */\n\n' % pg_style, fmter.get_style_defs('')]
189 189 warning: line over 80 characters
190 190 hgext/inotify/__init__.py:0:
191 191 > if self._inotifyon and not ignored and not subrepos and not self._dirty:
192 192 warning: line over 80 characters
193 193 hgext/inotify/server.py:0:
194 194 > except:
195 195 warning: naked except clause
196 196 hgext/inotify/server.py:0:
197 197 > except:
198 198 warning: naked except clause
199 199 hgext/keyword.py:0:
200 200 > ui.note("hg ci -m '%s'\n" % msg)
201 201 warning: unwrapped ui message
202 202 hgext/largefiles/overrides.py:0:
203 203 > # When we call orig below it creates the standins but we don't add them
204 204 warning: line over 80 characters
205 205 hgext/largefiles/reposetup.py:0:
206 206 > if os.path.exists(self.wjoin(lfutil.standin(lfile))):
207 207 warning: line over 80 characters
208 208 hgext/mq.py:0:
209 209 > raise util.Abort(_("%s does not have a parent recorded" % root))
210 210 warning: line over 80 characters
211 211 hgext/mq.py:0:
212 212 > raise util.Abort(_("cannot push --exact with applied patches"))
213 213 warning: line over 80 characters
214 214 hgext/mq.py:0:
215 215 > raise util.Abort(_("cannot use --exact and --move together"))
216 216 warning: line over 80 characters
217 217 hgext/mq.py:0:
218 218 > self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
219 219 warning: line over 80 characters
220 220 hgext/mq.py:0:
221 221 > except:
222 222 warning: naked except clause
223 223 warning: naked except clause
224 224 hgext/mq.py:0:
225 225 > except:
226 226 warning: naked except clause
227 227 warning: naked except clause
228 228 warning: naked except clause
229 229 warning: naked except clause
230 230 hgext/mq.py:0:
231 231 > raise util.Abort(_('cannot mix -l/--list with options or arguments'))
232 232 warning: line over 80 characters
233 233 hgext/mq.py:0:
234 234 > raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
235 235 warning: line over 80 characters
236 236 hgext/mq.py:0:
237 237 > ('', 'move', None, _('reorder patch series and apply only the patch'))],
238 238 warning: line over 80 characters
239 239 hgext/mq.py:0:
240 240 > ('U', 'noupdate', None, _('do not update the new working directories')),
241 241 warning: line over 80 characters
242 242 hgext/mq.py:0:
243 243 > ('e', 'exact', None, _('apply the target patch to its recorded parent')),
244 244 warning: line over 80 characters
245 245 hgext/mq.py:0:
246 246 > except:
247 247 warning: naked except clause
248 248 hgext/mq.py:0:
249 249 > ui.write("mq: %s\n" % ', '.join(m))
250 250 warning: unwrapped ui message
251 251 hgext/mq.py:0:
252 252 > repo.mq.qseries(repo, missing=opts.get('missing'), summary=opts.get('summary'))
253 253 warning: line over 80 characters
254 254 hgext/notify.py:0:
255 255 > ui.note(_('notify: suppressing notification for merge %d:%s\n') %
256 256 warning: line over 80 characters
257 257 hgext/patchbomb.py:0:
258 258 > binnode, seqno=idx, total=total)
259 259 warning: line over 80 characters
260 260 hgext/patchbomb.py:0:
261 261 > except:
262 262 warning: naked except clause
263 263 hgext/patchbomb.py:0:
264 264 > ui.write('Subject: %s\n' % subj)
265 265 warning: unwrapped ui message
266 266 hgext/patchbomb.py:0:
267 267 > p = mail.mimetextpatch('\n'.join(patchlines), 'x-patch', opts.get('test'))
268 268 warning: line over 80 characters
269 269 hgext/patchbomb.py:0:
270 270 > ui.write('From: %s\n' % sender)
271 271 warning: unwrapped ui message
272 272 hgext/record.py:0:
273 273 > ignoreblanklines=opts.get('ignore_blank_lines'))
274 274 warning: line over 80 characters
275 275 hgext/record.py:0:
276 276 > ignorewsamount=opts.get('ignore_space_change'),
277 277 warning: line over 80 characters
278 278 hgext/zeroconf/__init__.py:0:
279 279 > publish(name, desc, path, util.getport(u.config("web", "port", 8000)))
280 280 warning: line over 80 characters
281 281 hgext/zeroconf/__init__.py:0:
282 282 > except:
283 283 warning: naked except clause
284 284 warning: naked except clause
285 285 mercurial/bundlerepo.py:0:
286 286 > is a bundlerepo for the obtained bundle when the original "other" is remote.
287 287 warning: line over 80 characters
288 288 mercurial/bundlerepo.py:0:
289 289 > "local" is a local repo from which to obtain the actual incoming changesets; it
290 290 warning: line over 80 characters
291 291 mercurial/bundlerepo.py:0:
292 292 > tmp = discovery.findcommonincoming(repo, other, heads=onlyheads, force=force)
293 293 warning: line over 80 characters
294 294 mercurial/commands.py:0:
295 295 > " size " + basehdr + " link p1 p2 nodeid\n")
296 296 warning: line over 80 characters
297 297 mercurial/commands.py:0:
298 298 > raise util.Abort('cannot use localheads with old style discovery')
299 299 warning: line over 80 characters
300 300 mercurial/commands.py:0:
301 301 > ui.note('branch %s\n' % data)
302 302 warning: unwrapped ui message
303 303 mercurial/commands.py:0:
304 304 > ui.note('node %s\n' % str(data))
305 305 warning: unwrapped ui message
306 306 mercurial/commands.py:0:
307 307 > ui.note('tag %s\n' % name)
308 308 warning: unwrapped ui message
309 309 mercurial/commands.py:0:
310 310 > ui.write("unpruned common: %s\n" % " ".join([short(n)
311 311 warning: unwrapped ui message
312 312 mercurial/commands.py:0:
313 313 > yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
314 314 warning: line over 80 characters
315 315 mercurial/commands.py:0:
316 316 > yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
317 317 warning: line over 80 characters
318 318 mercurial/commands.py:0:
319 319 > except:
320 320 warning: naked except clause
321 321 mercurial/commands.py:0:
322 322 > ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
323 323 warning: line over 80 characters
324 324 mercurial/commands.py:0:
325 325 > ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
326 326 warning: unwrapped ui message
327 327 mercurial/commands.py:0:
328 328 > ui.write("local is subset\n")
329 329 warning: unwrapped ui message
330 330 mercurial/commands.py:0:
331 331 > ui.write("remote is subset\n")
332 332 warning: unwrapped ui message
333 333 mercurial/commands.py:0:
334 334 > ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
335 335 warning: line over 80 characters
336 336 mercurial/commands.py:0:
337 337 > ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
338 338 warning: line over 80 characters
339 339 mercurial/commands.py:0:
340 340 > ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
341 341 warning: line over 80 characters
342 342 mercurial/commands.py:0:
343 343 > ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
344 344 warning: line over 80 characters
345 345 warning: unwrapped ui message
346 346 mercurial/commands.py:0:
347 347 > ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
348 348 warning: unwrapped ui message
349 349 mercurial/commands.py:0:
350 350 > ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
351 351 warning: unwrapped ui message
352 352 mercurial/commands.py:0:
353 353 > cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
354 354 warning: line over 80 characters
355 355 mercurial/commands.py:0:
356 356 > except:
357 357 warning: naked except clause
358 358 mercurial/commands.py:0:
359 359 > revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
360 360 warning: line over 80 characters
361 361 mercurial/commands.py:0:
362 362 > ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
363 363 warning: unwrapped ui message
364 364 mercurial/commands.py:0:
365 365 > ui.write("match: %s\n" % m(d[0]))
366 366 warning: unwrapped ui message
367 367 mercurial/commands.py:0:
368 368 > ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
369 369 warning: unwrapped ui message
370 370 mercurial/commands.py:0:
371 371 > ui.write('path %s\n' % k)
372 372 warning: unwrapped ui message
373 373 mercurial/commands.py:0:
374 374 > ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
375 375 warning: unwrapped ui message
376 376 mercurial/commands.py:0:
377 377 > Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
378 378 warning: line over 80 characters
379 379 mercurial/commands.py:0:
380 380 > remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
381 381 warning: line over 80 characters
382 382 mercurial/commands.py:0:
383 383 > ui.write("digraph G {\n")
384 384 warning: unwrapped ui message
385 385 mercurial/commands.py:0:
386 386 > ui.write("internal: %s %s\n" % d)
387 387 warning: unwrapped ui message
388 388 mercurial/commands.py:0:
389 389 > ui.write("standard: %s\n" % util.datestr(d))
390 390 warning: unwrapped ui message
391 391 mercurial/commands.py:0:
392 392 > ui.write('avg chain length : ' + fmt % avgchainlen)
393 393 warning: unwrapped ui message
394 394 mercurial/commands.py:0:
395 395 > ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
396 396 warning: unwrapped ui message
397 397 mercurial/commands.py:0:
398 398 > ui.write('compression ratio : ' + fmt % compratio)
399 399 warning: unwrapped ui message
400 400 mercurial/commands.py:0:
401 401 > ui.write('delta size (min/max/avg) : %d / %d / %d\n'
402 402 warning: unwrapped ui message
403 403 mercurial/commands.py:0:
404 404 > ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
405 405 warning: unwrapped ui message
406 406 mercurial/commands.py:0:
407 407 > ui.write('flags : %s\n' % ', '.join(flags))
408 408 warning: unwrapped ui message
409 409 mercurial/commands.py:0:
410 410 > ui.write('format : %d\n' % format)
411 411 warning: unwrapped ui message
412 412 mercurial/commands.py:0:
413 413 > ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
414 414 warning: unwrapped ui message
415 415 mercurial/commands.py:0:
416 416 > ui.write('revision size : ' + fmt2 % totalsize)
417 417 warning: unwrapped ui message
418 418 mercurial/commands.py:0:
419 419 > ui.write('revisions : ' + fmt2 % numrevs)
420 420 warning: unwrapped ui message
421 421 warning: unwrapped ui message
422 422 mercurial/commands.py:0:
423 423 > ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
424 424 warning: unwrapped ui message
425 425 mercurial/commandserver.py:0:
426 426 > # the ui here is really the repo ui so take its baseui so we don't end up
427 427 warning: line over 80 characters
428 428 mercurial/context.py:0:
429 429 > return self._manifestdelta[path], self._manifestdelta.flags(path)
430 430 warning: line over 80 characters
431 431 mercurial/dagparser.py:0:
432 432 > raise util.Abort(_("invalid character in dag description: %s...") % s)
433 433 warning: line over 80 characters
434 434 mercurial/dagparser.py:0:
435 435 > >>> dagtext([('n', (0, [-1])), ('C', 'my command line'), ('n', (1, [0]))])
436 436 warning: line over 80 characters
437 437 mercurial/dirstate.py:0:
438 438 > if not st is None and not getkind(st.st_mode) in (regkind, lnkkind):
439 439 warning: line over 80 characters
440 440 mercurial/discovery.py:0:
441 441 > If onlyheads is given, only nodes ancestral to nodes in onlyheads (inclusive)
442 442 warning: line over 80 characters
443 443 mercurial/discovery.py:0:
444 444 > def findcommonoutgoing(repo, other, onlyheads=None, force=False, commoninc=None):
445 445 warning: line over 80 characters
446 446 mercurial/dispatch.py:0:
447 447 > " (.hg not found)") % os.getcwd())
448 448 warning: line over 80 characters
449 449 mercurial/dispatch.py:0:
450 450 > aliases, entry = cmdutil.findcmd(cmd, cmdtable, lui.config("ui", "strict"))
451 451 warning: line over 80 characters
452 452 mercurial/dispatch.py:0:
453 453 > except:
454 454 warning: naked except clause
455 455 mercurial/dispatch.py:0:
456 456 > return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {})
457 457 warning: line over 80 characters
458 458 mercurial/dispatch.py:0:
459 459 > def __init__(self, args, ui=None, repo=None, fin=None, fout=None, ferr=None):
460 460 warning: line over 80 characters
461 461 mercurial/dispatch.py:0:
462 462 > except:
463 463 warning: naked except clause
464 464 mercurial/hg.py:0:
465 465 > except:
466 466 warning: naked except clause
467 467 mercurial/hgweb/hgweb_mod.py:0:
468 468 > self.maxshortchanges = int(self.config("web", "maxshortchanges", 60))
469 469 warning: line over 80 characters
470 470 mercurial/keepalive.py:0:
471 471 > except:
472 472 warning: naked except clause
473 473 mercurial/keepalive.py:0:
474 474 > except:
475 475 warning: naked except clause
476 476 mercurial/localrepo.py:0:
477 > hint=_("use --subrepos for recursive commit"))
478 warning: line over 80 characters
479 mercurial/localrepo.py:0:
480 477 > # we return an integer indicating remote head count change
481 478 warning: line over 80 characters
482 479 mercurial/localrepo.py:0:
483 480 > raise util.Abort(_("empty or missing revlog for %s") % fname)
484 481 warning: line over 80 characters
485 482 warning: line over 80 characters
486 483 mercurial/localrepo.py:0:
487 484 > if self._tagscache.tagtypes and name in self._tagscache.tagtypes:
488 485 warning: line over 80 characters
489 486 mercurial/localrepo.py:0:
490 487 > self.hook("precommit", throw=True, parent1=hookp1, parent2=hookp2)
491 488 warning: line over 80 characters
492 489 mercurial/localrepo.py:0:
493 490 > # new requirements = old non-format requirements + new format-related
494 491 warning: line over 80 characters
495 492 mercurial/localrepo.py:0:
496 493 > except:
497 494 warning: naked except clause
498 495 mercurial/localrepo.py:0:
499 496 > """return status of files between two nodes or node and working directory
500 497 warning: line over 80 characters
501 498 mercurial/localrepo.py:0:
502 499 > '''Returns a tagscache object that contains various tags related caches.'''
503 500 warning: line over 80 characters
504 501 mercurial/manifest.py:0:
505 502 > return "".join(struct.pack(">lll", start, end, len(content)) + content
506 503 warning: line over 80 characters
507 504 mercurial/merge.py:0:
508 505 > subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx), overwrite)
509 506 warning: line over 80 characters
510 507 mercurial/patch.py:0:
511 508 > modified, added, removed, copy, getfilectx, opts, losedata, prefix)
512 509 warning: line over 80 characters
513 510 mercurial/patch.py:0:
514 511 > diffhelpers.addlines(lr, self.hunk, self.lena, self.lenb, self.a, self.b)
515 512 warning: line over 80 characters
516 513 mercurial/patch.py:0:
517 514 > output.append(_(' %d files changed, %d insertions(+), %d deletions(-)\n')
518 515 warning: line over 80 characters
519 516 mercurial/patch.py:0:
520 517 > except:
521 518 warning: naked except clause
522 519 mercurial/pure/base85.py:0:
523 520 > raise OverflowError('Base85 overflow in hunk starting at byte %d' % i)
524 521 warning: line over 80 characters
525 522 mercurial/pure/mpatch.py:0:
526 523 > frags.extend(reversed(new)) # what was left at the end
527 524 warning: line over 80 characters
528 525 mercurial/repair.py:0:
529 526 > except:
530 527 warning: naked except clause
531 528 mercurial/repair.py:0:
532 529 > except:
533 530 warning: naked except clause
534 531 mercurial/revset.py:0:
535 532 > elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
536 533 warning: line over 80 characters
537 534 mercurial/revset.py:0:
538 535 > Changesets that are the Nth ancestor (first parents only) of a changeset in set.
539 536 warning: line over 80 characters
540 537 mercurial/scmutil.py:0:
541 538 > raise util.Abort(_("path '%s' is inside nested repo %r") %
542 539 warning: line over 80 characters
543 540 mercurial/scmutil.py:0:
544 541 > "requires features '%s' (upgrade Mercurial)") % "', '".join(missings))
545 542 warning: line over 80 characters
546 543 mercurial/scmutil.py:0:
547 544 > elif repo.dirstate[abs] != 'r' and (not good or not os.path.lexists(target)
548 545 warning: line over 80 characters
549 546 mercurial/setdiscovery.py:0:
550 547 > # treat remote heads (and maybe own heads) as a first implicit sample response
551 548 warning: line over 80 characters
552 549 mercurial/setdiscovery.py:0:
553 550 > undecided = dag.nodeset() # own nodes where I don't know if remote knows them
554 551 warning: line over 80 characters
555 552 mercurial/similar.py:0:
556 553 > repo.ui.progress(_('searching for similar files'), i, total=len(removed))
557 554 warning: line over 80 characters
558 555 mercurial/simplemerge.py:0:
559 556 > for zmatch, zend, amatch, aend, bmatch, bend in self.find_sync_regions():
560 557 warning: line over 80 characters
561 558 mercurial/sshrepo.py:0:
562 559 > self._abort(error.RepoError(_("no suitable response from remote hg")))
563 560 warning: line over 80 characters
564 561 mercurial/sshrepo.py:0:
565 562 > except:
566 563 warning: naked except clause
567 564 mercurial/subrepo.py:0:
568 565 > other, self._repo = hg.clone(self._repo._subparent.ui, {}, other,
569 566 warning: line over 80 characters
570 567 mercurial/subrepo.py:0:
571 568 > msg = (_(' subrepository sources for %s differ (in checked out version)\n'
572 569 warning: line over 80 characters
573 570 mercurial/transaction.py:0:
574 571 > except:
575 572 warning: naked except clause
576 573 mercurial/ui.py:0:
577 574 > traceback.print_exception(exc[0], exc[1], exc[2], file=self.ferr)
578 575 warning: line over 80 characters
579 576 mercurial/url.py:0:
580 577 > conn = httpsconnection(host, port, keyfile, certfile, *args, **kwargs)
581 578 warning: line over 80 characters
582 579 mercurial/util.py:0:
583 580 > except:
584 581 warning: naked except clause
585 582 mercurial/util.py:0:
586 583 > except:
587 584 warning: naked except clause
588 585 mercurial/verify.py:0:
589 586 > except:
590 587 warning: naked except clause
591 588 mercurial/verify.py:0:
592 589 > except:
593 590 warning: naked except clause
594 591 mercurial/wireproto.py:0:
595 592 > # Assuming the future to be filled with the result from the batched request
596 593 warning: line over 80 characters
597 594 mercurial/wireproto.py:0:
598 595 > '''remote must support _submitbatch(encbatch) and _submitone(op, encargs)'''
599 596 warning: line over 80 characters
600 597 mercurial/wireproto.py:0:
601 598 > All methods invoked on instances of this class are simply queued and return a
602 599 warning: line over 80 characters
603 600 mercurial/wireproto.py:0:
604 601 > The decorator returns a function which wraps this coroutine as a plain method,
605 602 warning: line over 80 characters
606 603 setup.py:0:
607 604 > raise SystemExit("Python headers are required to build Mercurial")
608 605 warning: line over 80 characters
609 606 setup.py:0:
610 607 > except:
611 608 warning: naked except clause
612 609 setup.py:0:
613 610 > # build_py), it will not find osutil & friends, thinking that those modules are
614 611 warning: line over 80 characters
615 612 setup.py:0:
616 613 > except:
617 614 warning: naked except clause
618 615 warning: naked except clause
619 616 setup.py:0:
620 617 > isironpython = platform.python_implementation().lower().find("ironpython") != -1
621 618 warning: line over 80 characters
622 619 setup.py:0:
623 620 > except:
624 621 warning: naked except clause
625 622 warning: naked except clause
626 623 warning: naked except clause
627 624 tests/autodiff.py:0:
628 625 > ui.write('data lost for: %s\n' % fn)
629 626 warning: unwrapped ui message
630 627 tests/run-tests.py:0:
631 628 > except:
632 629 warning: naked except clause
633 630 tests/test-commandserver.py:0:
634 631 > 'hooks.pre-identify=python:test-commandserver.hook', 'id'],
635 632 warning: line over 80 characters
636 633 tests/test-commandserver.py:0:
637 634 > # the cached repo local hgrc contains ui.foo=bar, so showconfig should show it
638 635 warning: line over 80 characters
639 636 tests/test-commandserver.py:0:
640 637 > print '%c, %r' % (ch, re.sub('encoding: [a-zA-Z0-9-]+', 'encoding: ***', data))
641 638 warning: line over 80 characters
642 639 tests/test-filecache.py:0:
643 640 > except:
644 641 warning: naked except clause
645 642 tests/test-filecache.py:0:
646 643 > if subprocess.call(['python', '%s/hghave' % os.environ['TESTDIR'], 'cacheable']):
647 644 warning: line over 80 characters
648 645 tests/test-ui-color.py:0:
649 646 > testui.warn('warning\n')
650 647 warning: unwrapped ui message
651 648 tests/test-ui-color.py:0:
652 649 > testui.write('buffered\n')
653 650 warning: unwrapped ui message
654 651 tests/test-walkrepo.py:0:
655 652 > print "Found %d repositories when I should have found 2" % (len(reposet),)
656 653 warning: line over 80 characters
657 654 tests/test-walkrepo.py:0:
658 655 > print "Found %d repositories when I should have found 3" % (len(reposet),)
659 656 warning: line over 80 characters
660 657 [1]
@@ -1,51 +1,50 b''
1 1 $ "$TESTDIR/hghave" svn13 || exit 80
2 2
3 3 $ echo "[extensions]" >> $HGRCPATH
4 4 $ echo "mq=" >> $HGRCPATH
5 5 $ echo "[diff]" >> $HGRCPATH
6 6 $ echo "nodates=1" >> $HGRCPATH
7 7
8 8 fn to create new repository, and cd into it
9 9 $ mkrepo() {
10 10 > hg init $1
11 11 > cd $1
12 12 > hg qinit
13 13 > }
14 14
15 15
16 16 handle svn subrepos safely
17 17
18 18 $ svnadmin create svn-repo-2499
19 19 $ curpath=`pwd | tr '\\\\' /`
20 20 $ expr "$svnpath" : "\/" > /dev/null
21 21 > if [ $? -ne 0 ]; then
22 22 > curpath="/$curpath"
23 23 > fi
24 24 $ svnurl="file://$curpath/svn-repo-2499/project"
25 25 $ mkdir -p svn-project-2499/trunk
26 26 $ svn import -m 'init project' svn-project-2499 "$svnurl"
27 27 Adding svn-project-2499/trunk
28 28
29 29 Committed revision 1.
30 30
31 31 qnew on repo w/svn subrepo
32 32 $ mkrepo repo-2499-svn-subrepo
33 33 $ svn co "$svnurl"/trunk sub
34 34 Checked out revision 1.
35 35 $ echo 'sub = [svn]sub' >> .hgsub
36 36 $ hg add .hgsub
37 37 $ hg status -S -X '**/format'
38 38 A .hgsub
39 39 $ hg qnew -m0 0.diff
40 committing subrepository sub
41 40 $ cd sub
42 41 $ echo a > a
43 42 $ svn add a
44 43 A a
45 44 $ svn st
46 45 A* a (glob)
47 46 $ cd ..
48 47 $ hg status -S # doesn't show status for svn subrepos (yet)
49 48 $ hg qnew -m1 1.diff
50 49 abort: uncommitted changes in subrepository sub
51 50 [255]
@@ -1,363 +1,355 b''
1 1 $ echo "[ui]" >> $HGRCPATH
2 2 $ echo "commitsubrepos = Yes" >> $HGRCPATH
3 3 $ echo "[extensions]" >> $HGRCPATH
4 4 $ echo "mq=" >> $HGRCPATH
5 5 $ echo "record=" >> $HGRCPATH
6 6 $ echo "[diff]" >> $HGRCPATH
7 7 $ echo "nodates=1" >> $HGRCPATH
8 8
9 9 $ stdin=`pwd`/stdin.tmp
10 10
11 11 fn to create new repository w/dirty subrepo, and cd into it
12 12 $ mkrepo() {
13 13 > hg init $1
14 14 > cd $1
15 15 > hg qinit
16 16 > }
17 17
18 18 fn to create dirty subrepo
19 19 $ mksubrepo() {
20 20 > hg init $1
21 21 > cd $1
22 22 > echo a > a
23 23 > hg add
24 24 > cd ..
25 25 > }
26 26
27 27 $ testadd() {
28 28 > cat - > "$stdin"
29 29 > mksubrepo sub
30 30 > echo sub = sub >> .hgsub
31 31 > hg add .hgsub
32 32 > echo % abort when adding .hgsub w/dirty subrepo
33 33 > hg status -S
34 34 > echo '%' $*
35 35 > cat "$stdin" | hg $*
36 36 > echo [$?]
37 37 > hg -R sub ci -m0sub
38 38 > echo % update substate when adding .hgsub w/clean updated subrepo
39 39 > hg status -S
40 40 > echo '%' $*
41 41 > cat "$stdin" | hg $*
42 42 > hg debugsub
43 43 > }
44 44
45 45 $ testmod() {
46 46 > cat - > "$stdin"
47 47 > mksubrepo sub2
48 48 > echo sub2 = sub2 >> .hgsub
49 49 > echo % abort when modifying .hgsub w/dirty subrepo
50 50 > hg status -S
51 51 > echo '%' $*
52 52 > cat "$stdin" | hg $*
53 53 > echo [$?]
54 54 > hg -R sub2 ci -m0sub2
55 55 > echo % update substate when modifying .hgsub w/clean updated subrepo
56 56 > hg status -S
57 57 > echo '%' $*
58 58 > cat "$stdin" | hg $*
59 59 > hg debugsub
60 60 > }
61 61
62 62 $ testrm1() {
63 63 > cat - > "$stdin"
64 64 > mksubrepo sub3
65 65 > echo sub3 = sub3 >> .hgsub
66 66 > hg ci -Aqmsub3
67 67 > $EXTRA
68 68 > echo b >> sub3/a
69 69 > hg rm .hgsub
70 70 > echo % update substate when removing .hgsub w/dirty subrepo
71 71 > hg status -S
72 72 > echo '%' $*
73 73 > cat "$stdin" | hg $*
74 74 > echo % debugsub should be empty
75 75 > hg debugsub
76 76 > }
77 77
78 78 $ testrm2() {
79 79 > cat - > "$stdin"
80 80 > mksubrepo sub4
81 81 > echo sub4 = sub4 >> .hgsub
82 82 > hg ci -Aqmsub4
83 83 > $EXTRA
84 84 > hg rm .hgsub
85 85 > echo % update substate when removing .hgsub w/clean updated subrepo
86 86 > hg status -S
87 87 > echo '%' $*
88 88 > cat "$stdin" | hg $*
89 89 > echo % debugsub should be empty
90 90 > hg debugsub
91 91 > }
92 92
93 93
94 94 handle subrepos safely on qnew
95 95
96 96 $ mkrepo repo-2499-qnew
97 97 $ testadd qnew -m0 0.diff
98 98 adding a
99 99 % abort when adding .hgsub w/dirty subrepo
100 100 A .hgsub
101 101 A sub/a
102 102 % qnew -m0 0.diff
103 103 abort: uncommitted changes in subrepository sub
104 104 [255]
105 105 % update substate when adding .hgsub w/clean updated subrepo
106 106 A .hgsub
107 107 % qnew -m0 0.diff
108 committing subrepository sub
109 108 path sub
110 109 source sub
111 110 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
112 111
113 112 $ testmod qnew -m1 1.diff
114 113 adding a
115 114 % abort when modifying .hgsub w/dirty subrepo
116 115 M .hgsub
117 116 A sub2/a
118 117 % qnew -m1 1.diff
119 118 abort: uncommitted changes in subrepository sub2
120 119 [255]
121 120 % update substate when modifying .hgsub w/clean updated subrepo
122 121 M .hgsub
123 122 % qnew -m1 1.diff
124 committing subrepository sub2
125 123 path sub
126 124 source sub
127 125 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
128 126 path sub2
129 127 source sub2
130 128 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
131 129
132 130 $ hg qpop -qa
133 131 patch queue now empty
134 132 $ testrm1 qnew -m2 2.diff
135 133 adding a
136 134 % update substate when removing .hgsub w/dirty subrepo
137 135 M sub3/a
138 136 R .hgsub
139 137 % qnew -m2 2.diff
140 138 % debugsub should be empty
141 139
142 140 $ hg qpop -qa
143 141 patch queue now empty
144 142 $ testrm2 qnew -m3 3.diff
145 143 adding a
146 144 % update substate when removing .hgsub w/clean updated subrepo
147 145 R .hgsub
148 146 % qnew -m3 3.diff
149 147 % debugsub should be empty
150 148
151 149 $ cd ..
152 150
153 151
154 152 handle subrepos safely on qrefresh
155 153
156 154 $ mkrepo repo-2499-qrefresh
157 155 $ hg qnew -m0 0.diff
158 156 $ testadd qrefresh
159 157 adding a
160 158 % abort when adding .hgsub w/dirty subrepo
161 159 A .hgsub
162 160 A sub/a
163 161 % qrefresh
164 162 abort: uncommitted changes in subrepository sub
165 163 [255]
166 164 % update substate when adding .hgsub w/clean updated subrepo
167 165 A .hgsub
168 166 % qrefresh
169 committing subrepository sub
170 167 path sub
171 168 source sub
172 169 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
173 170
174 171 $ hg qnew -m1 1.diff
175 172 $ testmod qrefresh
176 173 adding a
177 174 % abort when modifying .hgsub w/dirty subrepo
178 175 M .hgsub
179 176 A sub2/a
180 177 % qrefresh
181 178 abort: uncommitted changes in subrepository sub2
182 179 [255]
183 180 % update substate when modifying .hgsub w/clean updated subrepo
184 181 M .hgsub
185 182 % qrefresh
186 committing subrepository sub2
187 183 path sub
188 184 source sub
189 185 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
190 186 path sub2
191 187 source sub2
192 188 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
193 189
194 190 $ hg qpop -qa
195 191 patch queue now empty
196 192 $ EXTRA='hg qnew -m2 2.diff'
197 193 $ testrm1 qrefresh
198 194 adding a
199 195 % update substate when removing .hgsub w/dirty subrepo
200 196 M sub3/a
201 197 R .hgsub
202 198 % qrefresh
203 199 % debugsub should be empty
204 200
205 201 $ hg qpop -qa
206 202 patch queue now empty
207 203 $ EXTRA='hg qnew -m3 3.diff'
208 204 $ testrm2 qrefresh
209 205 adding a
210 206 % update substate when removing .hgsub w/clean updated subrepo
211 207 R .hgsub
212 208 % qrefresh
213 209 % debugsub should be empty
214 210 $ EXTRA=
215 211
216 212 $ cd ..
217 213
218 214
219 215 handle subrepos safely on qpush/qpop
220 216
221 217 $ mkrepo repo-2499-qpush
222 218 $ mksubrepo sub
223 219 adding a
224 220 $ hg -R sub ci -m0sub
225 221 $ echo sub = sub > .hgsub
226 222 $ hg add .hgsub
227 223 $ hg qnew -m0 0.diff
228 committing subrepository sub
229 224 $ hg debugsub
230 225 path sub
231 226 source sub
232 227 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
233 228
234 229 qpop
235 230 $ hg qpop
236 231 popping 0.diff
237 232 patch queue now empty
238 233 $ hg status -AS
239 234 $ hg debugsub
240 235
241 236 qpush
242 237 $ hg qpush
243 238 applying 0.diff
244 239 now at: 0.diff
245 240 $ hg status -AS
246 241 C .hgsub
247 242 C .hgsubstate
248 243 C sub/a
249 244 $ hg debugsub
250 245 path sub
251 246 source sub
252 247 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
253 248
254 249 $ cd ..
255 250
256 251
257 252 handle subrepos safely on qrecord
258 253
259 254 $ mkrepo repo-2499-qrecord
260 255 $ testadd qrecord --config ui.interactive=1 -m0 0.diff <<EOF
261 256 > y
262 257 > y
263 258 > EOF
264 259 adding a
265 260 % abort when adding .hgsub w/dirty subrepo
266 261 A .hgsub
267 262 A sub/a
268 263 % qrecord --config ui.interactive=1 -m0 0.diff
269 264 diff --git a/.hgsub b/.hgsub
270 265 new file mode 100644
271 266 examine changes to '.hgsub'? [Ynsfdaq?]
272 267 abort: uncommitted changes in subrepository sub
273 268 [255]
274 269 % update substate when adding .hgsub w/clean updated subrepo
275 270 A .hgsub
276 271 % qrecord --config ui.interactive=1 -m0 0.diff
277 272 diff --git a/.hgsub b/.hgsub
278 273 new file mode 100644
279 274 examine changes to '.hgsub'? [Ynsfdaq?]
280 committing subrepository sub
281 275 path sub
282 276 source sub
283 277 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
284 278
285 279 $ testmod qrecord --config ui.interactive=1 -m1 1.diff <<EOF
286 280 > y
287 281 > y
288 282 > EOF
289 283 adding a
290 284 % abort when modifying .hgsub w/dirty subrepo
291 285 M .hgsub
292 286 A sub2/a
293 287 % qrecord --config ui.interactive=1 -m1 1.diff
294 288 diff --git a/.hgsub b/.hgsub
295 289 1 hunks, 1 lines changed
296 290 examine changes to '.hgsub'? [Ynsfdaq?]
297 291 @@ -1,1 +1,2 @@
298 292 sub = sub
299 293 +sub2 = sub2
300 294 record this change to '.hgsub'? [Ynsfdaq?]
301 295 abort: uncommitted changes in subrepository sub2
302 296 [255]
303 297 % update substate when modifying .hgsub w/clean updated subrepo
304 298 M .hgsub
305 299 % qrecord --config ui.interactive=1 -m1 1.diff
306 300 diff --git a/.hgsub b/.hgsub
307 301 1 hunks, 1 lines changed
308 302 examine changes to '.hgsub'? [Ynsfdaq?]
309 303 @@ -1,1 +1,2 @@
310 304 sub = sub
311 305 +sub2 = sub2
312 306 record this change to '.hgsub'? [Ynsfdaq?]
313 committing subrepository sub2
314 307 path sub
315 308 source sub
316 309 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
317 310 path sub2
318 311 source sub2
319 312 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
320 313
321 314 $ hg qpop -qa
322 315 patch queue now empty
323 316 $ testrm1 qrecord --config ui.interactive=1 -m2 2.diff <<EOF
324 317 > y
325 318 > y
326 319 > EOF
327 320 adding a
328 321 % update substate when removing .hgsub w/dirty subrepo
329 322 M sub3/a
330 323 R .hgsub
331 324 % qrecord --config ui.interactive=1 -m2 2.diff
332 325 diff --git a/.hgsub b/.hgsub
333 326 deleted file mode 100644
334 327 examine changes to '.hgsub'? [Ynsfdaq?]
335 328 % debugsub should be empty
336 329
337 330 $ hg qpop -qa
338 331 patch queue now empty
339 332 $ testrm2 qrecord --config ui.interactive=1 -m3 3.diff <<EOF
340 333 > y
341 334 > y
342 335 > EOF
343 336 adding a
344 337 % update substate when removing .hgsub w/clean updated subrepo
345 338 R .hgsub
346 339 % qrecord --config ui.interactive=1 -m3 3.diff
347 340 diff --git a/.hgsub b/.hgsub
348 341 deleted file mode 100644
349 342 examine changes to '.hgsub'? [Ynsfdaq?]
350 343 % debugsub should be empty
351 344
352 345 $ cd ..
353 346
354 347
355 348 correctly handle subrepos with patch queues
356 349 $ mkrepo repo-subrepo-with-queue
357 350 $ mksubrepo sub
358 351 adding a
359 352 $ hg -R sub qnew sub0.diff
360 353 $ echo sub = sub >> .hgsub
361 354 $ hg add .hgsub
362 355 $ hg qnew 0.diff
363 committing subrepository sub
@@ -1,102 +1,100 b''
1 1 Preparing the subrepository 'sub2'
2 2
3 3 $ hg init sub2
4 4 $ echo sub2 > sub2/sub2
5 5 $ hg add -R sub2
6 6 adding sub2/sub2 (glob)
7 7 $ hg commit -R sub2 -m "sub2 import"
8 8
9 9 Preparing the 'sub1' repo which depends on the subrepo 'sub2'
10 10
11 11 $ hg init sub1
12 12 $ echo sub1 > sub1/sub1
13 13 $ echo "sub2 = ../sub2" > sub1/.hgsub
14 14 $ hg clone sub2 sub1/sub2
15 15 updating to branch default
16 16 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
17 17 $ hg add -R sub1
18 18 adding sub1/.hgsub (glob)
19 19 adding sub1/sub1 (glob)
20 20 $ hg commit -R sub1 -m "sub1 import"
21 committing subrepository sub2
22 21
23 22 Preparing the 'main' repo which depends on the subrepo 'sub1'
24 23
25 24 $ hg init main
26 25 $ echo main > main/main
27 26 $ echo "sub1 = ../sub1" > main/.hgsub
28 27 $ hg clone sub1 main/sub1
29 28 updating to branch default
30 29 cloning subrepo sub2 from $TESTTMP/sub2
31 30 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
32 31 $ hg add -R main
33 32 adding main/.hgsub (glob)
34 33 adding main/main (glob)
35 34 $ hg commit -R main -m "main import"
36 committing subrepository sub1
37 35
38 36 Cleaning both repositories, just as a clone -U
39 37
40 38 $ hg up -C -R sub2 null
41 39 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
42 40 $ hg up -C -R sub1 null
43 41 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
44 42 $ hg up -C -R main null
45 43 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
46 44 $ rm -rf main/sub1
47 45 $ rm -rf sub1/sub2
48 46
49 47 Clone main
50 48
51 49 $ hg clone main cloned
52 50 updating to branch default
53 51 cloning subrepo sub1 from $TESTTMP/sub1
54 52 cloning subrepo sub1/sub2 from $TESTTMP/sub2 (glob)
55 53 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
56 54
57 55 Checking cloned repo ids
58 56
59 57 $ printf "cloned " ; hg id -R cloned
60 58 cloned 7f491f53a367 tip
61 59 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
62 60 cloned/sub1 fc3b4ce2696f tip
63 61 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
64 62 cloned/sub1/sub2 c57a0840e3ba tip
65 63
66 64 debugsub output for main and sub1
67 65
68 66 $ hg debugsub -R cloned
69 67 path sub1
70 68 source ../sub1
71 69 revision fc3b4ce2696f7741438c79207583768f2ce6b0dd
72 70 $ hg debugsub -R cloned/sub1
73 71 path sub2
74 72 source ../sub2
75 73 revision c57a0840e3badd667ef3c3ef65471609acb2ba3c
76 74
77 75 Modifying deeply nested 'sub2'
78 76
79 77 $ echo modified > cloned/sub1/sub2/sub2
80 78 $ hg commit --subrepos -m "deep nested modif should trigger a commit" -R cloned
81 79 committing subrepository sub1
82 80 committing subrepository sub1/sub2 (glob)
83 81
84 82 Checking modified node ids
85 83
86 84 $ printf "cloned " ; hg id -R cloned
87 85 cloned ffe6649062fe tip
88 86 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
89 87 cloned/sub1 2ecb03bf44a9 tip
90 88 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
91 89 cloned/sub1/sub2 53dd3430bcaf tip
92 90
93 91 debugsub output for main and sub1
94 92
95 93 $ hg debugsub -R cloned
96 94 path sub1
97 95 source ../sub1
98 96 revision 2ecb03bf44a94e749e8669481dd9069526ce7cb9
99 97 $ hg debugsub -R cloned/sub1
100 98 path sub2
101 99 source ../sub2
102 100 revision 53dd3430bcaf5ab4a7c48262bcad6d441f510487
@@ -1,510 +1,511 b''
1 1 $ "$TESTDIR/hghave" git || exit 80
2 2
3 3 make git commits repeatable
4 4
5 5 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
6 6 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
7 7 $ GIT_AUTHOR_DATE='1234567891 +0000'; export GIT_AUTHOR_DATE
8 8 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
9 9 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
10 10 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
11 11
12 12 root hg repo
13 13
14 14 $ hg init t
15 15 $ cd t
16 16 $ echo a > a
17 17 $ hg add a
18 18 $ hg commit -m a
19 19 $ cd ..
20 20
21 21 new external git repo
22 22
23 23 $ mkdir gitroot
24 24 $ cd gitroot
25 25 $ git init -q
26 26 $ echo g > g
27 27 $ git add g
28 28 $ git commit -q -m g
29 29
30 30 add subrepo clone
31 31
32 32 $ cd ../t
33 33 $ echo 's = [git]../gitroot' > .hgsub
34 34 $ git clone -q ../gitroot s
35 35 $ hg add .hgsub
36 36 $ hg commit -m 'new git subrepo'
37 committing subrepository s
38 37 $ hg debugsub
39 38 path s
40 39 source ../gitroot
41 40 revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
42 41
43 42 record a new commit from upstream from a different branch
44 43
45 44 $ cd ../gitroot
46 45 $ git checkout -q -b testing
47 46 $ echo gg >> g
48 47 $ git commit -q -a -m gg
49 48
50 49 $ cd ../t/s
51 50 $ git pull -q >/dev/null 2>/dev/null
52 51 $ git checkout -q -b testing origin/testing >/dev/null
53 52
54 53 $ cd ..
55 54 $ hg status --subrepos
56 55 M s/g
57 56 $ hg commit -m 'update git subrepo'
58 committing subrepository s
59 57 $ hg debugsub
60 58 path s
61 59 source ../gitroot
62 60 revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
63 61
64 62 make $GITROOT pushable, by replacing it with a clone with nothing checked out
65 63
66 64 $ cd ..
67 65 $ git clone gitroot gitrootbare --bare -q
68 66 $ rm -rf gitroot
69 67 $ mv gitrootbare gitroot
70 68
71 69 clone root
72 70
73 71 $ cd t
74 72 $ hg clone . ../tc
75 73 updating to branch default
76 74 cloning subrepo s from $TESTTMP/gitroot
77 75 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 76 $ cd ../tc
79 77 $ hg debugsub
80 78 path s
81 79 source ../gitroot
82 80 revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
83 81
84 82 update to previous substate
85 83
86 84 $ hg update 1 -q
87 85 $ cat s/g
88 86 g
89 87 $ hg debugsub
90 88 path s
91 89 source ../gitroot
92 90 revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
93 91
94 92 clone root, make local change
95 93
96 94 $ cd ../t
97 95 $ hg clone . ../ta
98 96 updating to branch default
99 97 cloning subrepo s from $TESTTMP/gitroot
100 98 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
101 99
102 100 $ cd ../ta
103 101 $ echo ggg >> s/g
104 102 $ hg status --subrepos
105 103 M s/g
106 104 $ hg commit --subrepos -m ggg
107 105 committing subrepository s
108 106 $ hg debugsub
109 107 path s
110 108 source ../gitroot
111 109 revision 79695940086840c99328513acbe35f90fcd55e57
112 110
113 111 clone root separately, make different local change
114 112
115 113 $ cd ../t
116 114 $ hg clone . ../tb
117 115 updating to branch default
118 116 cloning subrepo s from $TESTTMP/gitroot
119 117 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 118
121 119 $ cd ../tb/s
122 120 $ echo f > f
123 121 $ git add f
124 122 $ cd ..
125 123
126 124 $ hg status --subrepos
127 125 A s/f
128 126 $ hg commit --subrepos -m f
129 127 committing subrepository s
130 128 $ hg debugsub
131 129 path s
132 130 source ../gitroot
133 131 revision aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
134 132
135 133 user b push changes
136 134
137 135 $ hg push 2>/dev/null
138 136 pushing to $TESTTMP/t
139 137 pushing branch testing of subrepo s
140 138 searching for changes
141 139 adding changesets
142 140 adding manifests
143 141 adding file changes
144 142 added 1 changesets with 1 changes to 1 files
145 143
146 144 user a pulls, merges, commits
147 145
148 146 $ cd ../ta
149 147 $ hg pull
150 148 pulling from $TESTTMP/t
151 149 searching for changes
152 150 adding changesets
153 151 adding manifests
154 152 adding file changes
155 153 added 1 changesets with 1 changes to 1 files (+1 heads)
156 154 (run 'hg heads' to see heads, 'hg merge' to merge)
157 155 $ hg merge 2>/dev/null
158 156 pulling subrepo s from $TESTTMP/gitroot
159 157 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 158 (branch merge, don't forget to commit)
161 159 $ cat s/f
162 160 f
163 161 $ cat s/g
164 162 g
165 163 gg
166 164 ggg
167 165 $ hg commit --subrepos -m 'merge'
168 166 committing subrepository s
169 167 $ hg status --subrepos --rev 1:5
170 168 M .hgsubstate
171 169 M s/g
172 170 A s/f
173 171 $ hg debugsub
174 172 path s
175 173 source ../gitroot
176 174 revision f47b465e1bce645dbf37232a00574aa1546ca8d3
177 175 $ hg push 2>/dev/null
178 176 pushing to $TESTTMP/t
179 177 pushing branch testing of subrepo s
180 178 searching for changes
181 179 adding changesets
182 180 adding manifests
183 181 adding file changes
184 182 added 2 changesets with 2 changes to 1 files
185 183
186 184 make upstream git changes
187 185
188 186 $ cd ..
189 187 $ git clone -q gitroot gitclone
190 188 $ cd gitclone
191 189 $ echo ff >> f
192 190 $ git commit -q -a -m ff
193 191 $ echo fff >> f
194 192 $ git commit -q -a -m fff
195 193 $ git push origin testing 2>/dev/null
196 194
197 195 make and push changes to hg without updating the subrepo
198 196
199 197 $ cd ../t
200 198 $ hg clone . ../td
201 199 updating to branch default
202 200 cloning subrepo s from $TESTTMP/gitroot
203 201 checking out detached HEAD in subrepo s
204 202 check out a git branch if you intend to make changes
205 203 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
206 204 $ cd ../td
207 205 $ echo aa >> a
208 206 $ hg commit -m aa
209 207 $ hg push
210 208 pushing to $TESTTMP/t
211 209 searching for changes
212 210 adding changesets
213 211 adding manifests
214 212 adding file changes
215 213 added 1 changesets with 1 changes to 1 files
216 214
217 215 sync to upstream git, distribute changes
218 216
219 217 $ cd ../ta
220 218 $ hg pull -u -q
221 219 $ cd s
222 220 $ git pull -q >/dev/null 2>/dev/null
223 221 $ cd ..
224 222 $ hg commit -m 'git upstream sync'
225 committing subrepository s
226 223 $ hg debugsub
227 224 path s
228 225 source ../gitroot
229 226 revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
230 227 $ hg push -q
231 228
232 229 $ cd ../tb
233 230 $ hg pull -q
234 231 $ hg update 2>/dev/null
235 232 pulling subrepo s from $TESTTMP/gitroot
236 233 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
237 234 $ hg debugsub
238 235 path s
239 236 source ../gitroot
240 237 revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
241 238
242 239 update to a revision without the subrepo, keeping the local git repository
243 240
244 241 $ cd ../t
245 242 $ hg up 0
246 243 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
247 244 $ ls -a s
248 245 .
249 246 ..
250 247 .git
251 248
252 249 $ hg up 2
253 250 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
254 251 $ ls -a s
255 252 .
256 253 ..
257 254 .git
258 255 g
259 256
260 257 archive subrepos
261 258
262 259 $ cd ../tc
263 260 $ hg pull -q
264 261 $ hg archive --subrepos -r 5 ../archive 2>/dev/null
265 262 pulling subrepo s from $TESTTMP/gitroot
266 263 $ cd ../archive
267 264 $ cat s/f
268 265 f
269 266 $ cat s/g
270 267 g
271 268 gg
272 269 ggg
273 270
274 271 create nested repo
275 272
276 273 $ cd ..
277 274 $ hg init outer
278 275 $ cd outer
279 276 $ echo b>b
280 277 $ hg add b
281 278 $ hg commit -m b
282 279
283 280 $ hg clone ../t inner
284 281 updating to branch default
285 282 cloning subrepo s from $TESTTMP/gitroot
286 283 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
287 284 $ echo inner = inner > .hgsub
288 285 $ hg add .hgsub
289 286 $ hg commit -m 'nested sub'
290 committing subrepository inner
291 287
292 288 nested commit
293 289
294 290 $ echo ffff >> inner/s/f
295 291 $ hg status --subrepos
296 292 M inner/s/f
297 293 $ hg commit --subrepos -m nested
298 294 committing subrepository inner
299 295 committing subrepository inner/s
300 296
301 297 nested archive
302 298
303 299 $ hg archive --subrepos ../narchive
304 300 $ ls ../narchive/inner/s | grep -v pax_global_header
305 301 f
306 302 g
307 303
308 304 relative source expansion
309 305
310 306 $ cd ..
311 307 $ mkdir d
312 308 $ hg clone t d/t
313 309 updating to branch default
314 310 cloning subrepo s from $TESTTMP/gitroot
315 311 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
316 312
317 313 Don't crash if the subrepo is missing
318 314
319 315 $ hg clone t missing -q
320 316 $ cd missing
321 317 $ rm -rf s
322 318 $ hg status -S
323 319 $ hg sum | grep commit
324 320 commit: 1 subrepos
325 321 $ hg push -q
326 322 abort: subrepo s is missing
327 323 [255]
328 324 $ hg commit --subrepos -qm missing
329 325 abort: subrepo s is missing
330 326 [255]
331 327 $ hg update -C
332 328 cloning subrepo s from $TESTTMP/gitroot
333 329 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 330 $ hg sum | grep commit
335 331 commit: (clean)
336 332
337 333 Don't crash if the .hgsubstate entry is missing
338 334
339 335 $ hg update 1 -q
340 336 $ hg rm .hgsubstate
341 337 $ hg commit .hgsubstate -m 'no substate'
342 created new head
338 nothing changed
339 [1]
343 340 $ hg tag -l nosubstate
344 341 $ hg manifest
345 342 .hgsub
343 .hgsubstate
346 344 a
347 345
348 346 $ hg status -S
347 R .hgsubstate
349 348 $ hg sum | grep commit
350 commit: 1 subrepos
349 commit: 1 removed, 1 subrepos (new branch head)
351 350
352 351 $ hg commit -m 'restore substate'
353 committing subrepository s
352 nothing changed
353 [1]
354 354 $ hg manifest
355 355 .hgsub
356 356 .hgsubstate
357 357 a
358 358 $ hg sum | grep commit
359 commit: (clean)
359 commit: 1 removed, 1 subrepos (new branch head)
360 360
361 361 $ hg update -qC nosubstate
362 362 $ ls s
363 g
363 364
364 365 issue3109: false positives in git diff-index
365 366
366 367 $ hg update -q
367 368 $ touch -t 200001010000 s/g
368 369 $ hg status --subrepos
369 370 $ touch -t 200001010000 s/g
370 371 $ hg sum | grep commit
371 372 commit: (clean)
372 373
373 374 Check hg update --clean
374 375 $ cd $TESTTMP/ta
375 376 $ echo > s/g
376 377 $ cd s
377 378 $ echo c1 > f1
378 379 $ echo c1 > f2
379 380 $ git add f1
380 381 $ cd ..
381 382 $ hg status -S
382 383 M s/g
383 384 A s/f1
384 385 $ ls s
385 386 f
386 387 f1
387 388 f2
388 389 g
389 390 $ hg update --clean
390 391 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
391 392 $ hg status -S
392 393 $ ls s
393 394 f
394 395 f1
395 396 f2
396 397 g
397 398
398 399 Sticky subrepositories, no changes
399 400 $ cd $TESTTMP/ta
400 401 $ hg id -n
401 402 7
402 403 $ cd s
403 404 $ git rev-parse HEAD
404 405 32a343883b74769118bb1d3b4b1fbf9156f4dddc
405 406 $ cd ..
406 407 $ hg update 1 > /dev/null 2>&1
407 408 $ hg id -n
408 409 1
409 410 $ cd s
410 411 $ git rev-parse HEAD
411 412 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
412 413 $ cd ..
413 414
414 415 Sticky subrepositorys, file changes
415 416 $ touch s/f1
416 417 $ cd s
417 418 $ git add f1
418 419 $ cd ..
419 420 $ hg id -n
420 421 1
421 422 $ cd s
422 423 $ git rev-parse HEAD
423 424 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
424 425 $ cd ..
425 426 $ hg update 4
426 427 subrepository sources for s differ
427 428 use (l)ocal source (da5f5b1) or (r)emote source (aa84837)?
428 429 l
429 430 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
430 431 $ hg id -n
431 432 4+
432 433 $ cd s
433 434 $ git rev-parse HEAD
434 435 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
435 436 $ cd ..
436 437 $ hg update --clean tip > /dev/null 2>&1
437 438
438 439 Sticky subrepository, revision updates
439 440 $ hg id -n
440 441 7
441 442 $ cd s
442 443 $ git rev-parse HEAD
443 444 32a343883b74769118bb1d3b4b1fbf9156f4dddc
444 445 $ cd ..
445 446 $ cd s
446 447 $ git checkout aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
447 448 Previous HEAD position was 32a3438... fff
448 449 HEAD is now at aa84837... f
449 450 $ cd ..
450 451 $ hg update 1
451 452 subrepository sources for s differ (in checked out version)
452 453 use (l)ocal source (32a3438) or (r)emote source (da5f5b1)?
453 454 l
454 455 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
455 456 $ hg id -n
456 457 1+
457 458 $ cd s
458 459 $ git rev-parse HEAD
459 460 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
460 461 $ cd ..
461 462
462 463 Sticky subrepository, file changes and revision updates
463 464 $ touch s/f1
464 465 $ cd s
465 466 $ git add f1
466 467 $ git rev-parse HEAD
467 468 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
468 469 $ cd ..
469 470 $ hg id -n
470 471 1+
471 472 $ hg update 7
472 473 subrepository sources for s differ
473 474 use (l)ocal source (32a3438) or (r)emote source (32a3438)?
474 475 l
475 476 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
476 477 $ hg id -n
477 478 7
478 479 $ cd s
479 480 $ git rev-parse HEAD
480 481 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
481 482 $ cd ..
482 483
483 484 Sticky repository, update --clean
484 485 $ hg update --clean tip
485 486 Previous HEAD position was aa84837... f
486 487 HEAD is now at 32a3438... fff
487 488 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
488 489 $ hg id -n
489 490 7
490 491 $ cd s
491 492 $ git rev-parse HEAD
492 493 32a343883b74769118bb1d3b4b1fbf9156f4dddc
493 494 $ cd ..
494 495
495 496 Test subrepo already at intended revision:
496 497 $ cd s
497 498 $ git checkout 32a343883b74769118bb1d3b4b1fbf9156f4dddc
498 499 HEAD is now at 32a3438... fff
499 500 $ cd ..
500 501 $ hg update 1
501 502 Previous HEAD position was 32a3438... fff
502 503 HEAD is now at da5f5b1... g
503 504 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
504 505 $ hg id -n
505 506 1
506 507 $ cd s
507 508 $ git rev-parse HEAD
508 509 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
509 510 $ cd ..
510 511
@@ -1,55 +1,53 b''
1 1 $ hg init repo
2 2 $ cd repo
3 3 $ hg init subrepo
4 4 $ echo a > subrepo/a
5 5 $ hg -R subrepo ci -Am adda
6 6 adding a
7 7 $ echo 'subrepo = subrepo' > .hgsub
8 8 $ hg ci -Am addsubrepo
9 9 adding .hgsub
10 committing subrepository subrepo
11 10 $ echo b > subrepo/b
12 11 $ hg -R subrepo ci -Am addb
13 12 adding b
14 13 $ hg ci -m updatedsub
15 committing subrepository subrepo
16 14
17 15 delete .hgsub and revert it
18 16
19 17 $ rm .hgsub
20 18 $ hg revert .hgsub
21 19 warning: subrepo spec file .hgsub not found
22 20 warning: subrepo spec file .hgsub not found
23 21
24 22 delete .hgsubstate and revert it
25 23
26 24 $ rm .hgsubstate
27 25 $ hg revert .hgsubstate
28 26
29 27 delete .hgsub and update
30 28
31 29 $ rm .hgsub
32 30 $ hg up 0
33 31 warning: subrepo spec file .hgsub not found
34 32 warning: subrepo spec file .hgsub not found
35 33 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
36 34 $ hg st
37 35 warning: subrepo spec file .hgsub not found
38 36 ! .hgsub
39 37 $ ls subrepo
40 38 a
41 39
42 40 delete .hgsubstate and update
43 41
44 42 $ hg up -C
45 43 warning: subrepo spec file .hgsub not found
46 44 warning: subrepo spec file .hgsub not found
47 45 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
48 46 $ rm .hgsubstate
49 47 $ hg up 0
50 48 remote changed .hgsubstate which local deleted
51 49 use (c)hanged version or leave (d)eleted? c
52 50 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
53 51 $ hg st
54 52 $ ls subrepo
55 53 a
@@ -1,490 +1,488 b''
1 1 Create test repository:
2 2
3 3 $ hg init repo
4 4 $ cd repo
5 5 $ echo x1 > x.txt
6 6
7 7 $ hg init foo
8 8 $ cd foo
9 9 $ echo y1 > y.txt
10 10
11 11 $ hg init bar
12 12 $ cd bar
13 13 $ echo z1 > z.txt
14 14
15 15 $ cd ..
16 16 $ echo 'bar = bar' > .hgsub
17 17
18 18 $ cd ..
19 19 $ echo 'foo = foo' > .hgsub
20 20
21 21 Add files --- .hgsub files must go first to trigger subrepos:
22 22
23 23 $ hg add -S .hgsub
24 24 $ hg add -S foo/.hgsub
25 25 $ hg add -S foo/bar
26 26 adding foo/bar/z.txt (glob)
27 27 $ hg add -S
28 28 adding x.txt
29 29 adding foo/y.txt (glob)
30 30
31 31 Test recursive status without committing anything:
32 32
33 33 $ hg status -S
34 34 A .hgsub
35 35 A foo/.hgsub
36 36 A foo/bar/z.txt
37 37 A foo/y.txt
38 38 A x.txt
39 39
40 40 Test recursive diff without committing anything:
41 41
42 42 $ hg diff --nodates -S foo
43 43 diff -r 000000000000 foo/.hgsub
44 44 --- /dev/null
45 45 +++ b/foo/.hgsub
46 46 @@ -0,0 +1,1 @@
47 47 +bar = bar
48 48 diff -r 000000000000 foo/y.txt
49 49 --- /dev/null
50 50 +++ b/foo/y.txt
51 51 @@ -0,0 +1,1 @@
52 52 +y1
53 53 diff -r 000000000000 foo/bar/z.txt
54 54 --- /dev/null
55 55 +++ b/foo/bar/z.txt
56 56 @@ -0,0 +1,1 @@
57 57 +z1
58 58
59 59 Commits:
60 60
61 61 $ hg commit -m fails
62 62 abort: uncommitted changes in subrepo foo
63 63 (use --subrepos for recursive commit)
64 64 [255]
65 65
66 66 The --subrepos flag overwrite the config setting:
67 67
68 68 $ hg commit -m 0-0-0 --config ui.commitsubrepos=No --subrepos
69 69 committing subrepository foo
70 70 committing subrepository foo/bar (glob)
71 71
72 72 $ cd foo
73 73 $ echo y2 >> y.txt
74 74 $ hg commit -m 0-1-0
75 75
76 76 $ cd bar
77 77 $ echo z2 >> z.txt
78 78 $ hg commit -m 0-1-1
79 79
80 80 $ cd ..
81 81 $ hg commit -m 0-2-1
82 committing subrepository bar
83 82
84 83 $ cd ..
85 84 $ hg commit -m 1-2-1
86 committing subrepository foo
87 85
88 86 Change working directory:
89 87
90 88 $ echo y3 >> foo/y.txt
91 89 $ echo z3 >> foo/bar/z.txt
92 90 $ hg status -S
93 91 M foo/bar/z.txt
94 92 M foo/y.txt
95 93 $ hg diff --nodates -S
96 94 diff -r d254738c5f5e foo/y.txt
97 95 --- a/foo/y.txt
98 96 +++ b/foo/y.txt
99 97 @@ -1,2 +1,3 @@
100 98 y1
101 99 y2
102 100 +y3
103 101 diff -r 9647f22de499 foo/bar/z.txt
104 102 --- a/foo/bar/z.txt
105 103 +++ b/foo/bar/z.txt
106 104 @@ -1,2 +1,3 @@
107 105 z1
108 106 z2
109 107 +z3
110 108
111 109 Status call crossing repository boundaries:
112 110
113 111 $ hg status -S foo/bar/z.txt
114 112 M foo/bar/z.txt
115 113 $ hg status -S -I 'foo/?.txt'
116 114 M foo/y.txt
117 115 $ hg status -S -I '**/?.txt'
118 116 M foo/bar/z.txt
119 117 M foo/y.txt
120 118 $ hg diff --nodates -S -I '**/?.txt'
121 119 diff -r d254738c5f5e foo/y.txt
122 120 --- a/foo/y.txt
123 121 +++ b/foo/y.txt
124 122 @@ -1,2 +1,3 @@
125 123 y1
126 124 y2
127 125 +y3
128 126 diff -r 9647f22de499 foo/bar/z.txt
129 127 --- a/foo/bar/z.txt
130 128 +++ b/foo/bar/z.txt
131 129 @@ -1,2 +1,3 @@
132 130 z1
133 131 z2
134 132 +z3
135 133
136 134 Status from within a subdirectory:
137 135
138 136 $ mkdir dir
139 137 $ cd dir
140 138 $ echo a1 > a.txt
141 139 $ hg status -S
142 140 M foo/bar/z.txt
143 141 M foo/y.txt
144 142 ? dir/a.txt
145 143 $ hg diff --nodates -S
146 144 diff -r d254738c5f5e foo/y.txt
147 145 --- a/foo/y.txt
148 146 +++ b/foo/y.txt
149 147 @@ -1,2 +1,3 @@
150 148 y1
151 149 y2
152 150 +y3
153 151 diff -r 9647f22de499 foo/bar/z.txt
154 152 --- a/foo/bar/z.txt
155 153 +++ b/foo/bar/z.txt
156 154 @@ -1,2 +1,3 @@
157 155 z1
158 156 z2
159 157 +z3
160 158
161 159 Status with relative path:
162 160
163 161 $ hg status -S ..
164 162 M ../foo/bar/z.txt
165 163 M ../foo/y.txt
166 164 ? a.txt
167 165 $ hg diff --nodates -S ..
168 166 diff -r d254738c5f5e foo/y.txt
169 167 --- a/foo/y.txt
170 168 +++ b/foo/y.txt
171 169 @@ -1,2 +1,3 @@
172 170 y1
173 171 y2
174 172 +y3
175 173 diff -r 9647f22de499 foo/bar/z.txt
176 174 --- a/foo/bar/z.txt
177 175 +++ b/foo/bar/z.txt
178 176 @@ -1,2 +1,3 @@
179 177 z1
180 178 z2
181 179 +z3
182 180 $ cd ..
183 181
184 182 Cleanup and final commit:
185 183
186 184 $ rm -r dir
187 185 $ hg commit --subrepos -m 2-3-2
188 186 committing subrepository foo
189 187 committing subrepository foo/bar (glob)
190 188
191 189 Test explicit path commands within subrepos: add/forget
192 190 $ echo z1 > foo/bar/z2.txt
193 191 $ hg status -S
194 192 ? foo/bar/z2.txt
195 193 $ hg add foo/bar/z2.txt
196 194 $ hg status -S
197 195 A foo/bar/z2.txt
198 196 This is expected to forget the file, but is currently broken
199 197 $ hg forget foo/bar/z2.txt
200 198 $ hg status -S
201 199 ? foo/bar/z2.txt
202 200 $ rm foo/bar/z2.txt
203 201
204 202 Log with the relationships between repo and its subrepo:
205 203
206 204 $ hg log --template '{rev}:{node|short} {desc}\n'
207 205 2:1326fa26d0c0 2-3-2
208 206 1:4b3c9ff4f66b 1-2-1
209 207 0:23376cbba0d8 0-0-0
210 208
211 209 $ hg -R foo log --template '{rev}:{node|short} {desc}\n'
212 210 3:65903cebad86 2-3-2
213 211 2:d254738c5f5e 0-2-1
214 212 1:8629ce7dcc39 0-1-0
215 213 0:af048e97ade2 0-0-0
216 214
217 215 $ hg -R foo/bar log --template '{rev}:{node|short} {desc}\n'
218 216 2:31ecbdafd357 2-3-2
219 217 1:9647f22de499 0-1-1
220 218 0:4904098473f9 0-0-0
221 219
222 220 Status between revisions:
223 221
224 222 $ hg status -S
225 223 $ hg status -S --rev 0:1
226 224 M .hgsubstate
227 225 M foo/.hgsubstate
228 226 M foo/bar/z.txt
229 227 M foo/y.txt
230 228 $ hg diff --nodates -S -I '**/?.txt' --rev 0:1
231 229 diff -r af048e97ade2 -r d254738c5f5e foo/y.txt
232 230 --- a/foo/y.txt
233 231 +++ b/foo/y.txt
234 232 @@ -1,1 +1,2 @@
235 233 y1
236 234 +y2
237 235 diff -r 4904098473f9 -r 9647f22de499 foo/bar/z.txt
238 236 --- a/foo/bar/z.txt
239 237 +++ b/foo/bar/z.txt
240 238 @@ -1,1 +1,2 @@
241 239 z1
242 240 +z2
243 241
244 242 Enable progress extension for archive tests:
245 243
246 244 $ cp $HGRCPATH $HGRCPATH.no-progress
247 245 $ cat >> $HGRCPATH <<EOF
248 246 > [extensions]
249 247 > progress =
250 248 > [progress]
251 249 > assume-tty = 1
252 250 > delay = 0
253 251 > format = topic bar number
254 252 > refresh = 0
255 253 > width = 60
256 254 > EOF
257 255
258 256 Test archiving to a directory tree (the doubled lines in the output
259 257 only show up in the test output, not in real usage):
260 258
261 259 $ hg archive --subrepos ../archive 2>&1 | $TESTDIR/filtercr.py
262 260
263 261 archiving [ ] 0/3
264 262 archiving [ ] 0/3
265 263 archiving [=============> ] 1/3
266 264 archiving [=============> ] 1/3
267 265 archiving [===========================> ] 2/3
268 266 archiving [===========================> ] 2/3
269 267 archiving [==========================================>] 3/3
270 268 archiving [==========================================>] 3/3
271 269
272 270 archiving (foo) [ ] 0/3
273 271 archiving (foo) [ ] 0/3
274 272 archiving (foo) [===========> ] 1/3
275 273 archiving (foo) [===========> ] 1/3
276 274 archiving (foo) [=======================> ] 2/3
277 275 archiving (foo) [=======================> ] 2/3
278 276 archiving (foo) [====================================>] 3/3
279 277 archiving (foo) [====================================>] 3/3
280 278
281 279 archiving (foo/bar) [ ] 0/1 (glob)
282 280 archiving (foo/bar) [ ] 0/1 (glob)
283 281 archiving (foo/bar) [================================>] 1/1 (glob)
284 282 archiving (foo/bar) [================================>] 1/1 (glob)
285 283 \r (esc)
286 284 $ find ../archive | sort
287 285 ../archive
288 286 ../archive/.hg_archival.txt
289 287 ../archive/.hgsub
290 288 ../archive/.hgsubstate
291 289 ../archive/foo
292 290 ../archive/foo/.hgsub
293 291 ../archive/foo/.hgsubstate
294 292 ../archive/foo/bar
295 293 ../archive/foo/bar/z.txt
296 294 ../archive/foo/y.txt
297 295 ../archive/x.txt
298 296
299 297 Test archiving to zip file (unzip output is unstable):
300 298
301 299 $ hg archive --subrepos ../archive.zip 2>&1 | $TESTDIR/filtercr.py
302 300
303 301 archiving [ ] 0/3
304 302 archiving [ ] 0/3
305 303 archiving [=============> ] 1/3
306 304 archiving [=============> ] 1/3
307 305 archiving [===========================> ] 2/3
308 306 archiving [===========================> ] 2/3
309 307 archiving [==========================================>] 3/3
310 308 archiving [==========================================>] 3/3
311 309
312 310 archiving (foo) [ ] 0/3
313 311 archiving (foo) [ ] 0/3
314 312 archiving (foo) [===========> ] 1/3
315 313 archiving (foo) [===========> ] 1/3
316 314 archiving (foo) [=======================> ] 2/3
317 315 archiving (foo) [=======================> ] 2/3
318 316 archiving (foo) [====================================>] 3/3
319 317 archiving (foo) [====================================>] 3/3
320 318
321 319 archiving (foo/bar) [ ] 0/1 (glob)
322 320 archiving (foo/bar) [ ] 0/1 (glob)
323 321 archiving (foo/bar) [================================>] 1/1 (glob)
324 322 archiving (foo/bar) [================================>] 1/1 (glob)
325 323 \r (esc)
326 324
327 325 Test archiving a revision that references a subrepo that is not yet
328 326 cloned:
329 327
330 328 $ hg clone -U . ../empty
331 329 $ cd ../empty
332 330 $ hg archive --subrepos -r tip ../archive.tar.gz 2>&1 | $TESTDIR/filtercr.py
333 331
334 332 archiving [ ] 0/3
335 333 archiving [ ] 0/3
336 334 archiving [=============> ] 1/3
337 335 archiving [=============> ] 1/3
338 336 archiving [===========================> ] 2/3
339 337 archiving [===========================> ] 2/3
340 338 archiving [==========================================>] 3/3
341 339 archiving [==========================================>] 3/3
342 340
343 341 archiving (foo) [ ] 0/3
344 342 archiving (foo) [ ] 0/3
345 343 archiving (foo) [===========> ] 1/3
346 344 archiving (foo) [===========> ] 1/3
347 345 archiving (foo) [=======================> ] 2/3
348 346 archiving (foo) [=======================> ] 2/3
349 347 archiving (foo) [====================================>] 3/3
350 348 archiving (foo) [====================================>] 3/3
351 349
352 350 archiving (foo/bar) [ ] 0/1 (glob)
353 351 archiving (foo/bar) [ ] 0/1 (glob)
354 352 archiving (foo/bar) [================================>] 1/1 (glob)
355 353 archiving (foo/bar) [================================>] 1/1 (glob)
356 354
357 355 cloning subrepo foo from $TESTTMP/repo/foo
358 356 cloning subrepo foo/bar from $TESTTMP/repo/foo/bar (glob)
359 357
360 358 The newly cloned subrepos contain no working copy:
361 359
362 360 $ hg -R foo summary
363 361 parent: -1:000000000000 (no revision checked out)
364 362 branch: default
365 363 commit: (clean)
366 364 update: 4 new changesets (update)
367 365
368 366 Disable progress extension and cleanup:
369 367
370 368 $ mv $HGRCPATH.no-progress $HGRCPATH
371 369
372 370 Test archiving when there is a directory in the way for a subrepo
373 371 created by archive:
374 372
375 373 $ hg clone -U . ../almost-empty
376 374 $ cd ../almost-empty
377 375 $ mkdir foo
378 376 $ echo f > foo/f
379 377 $ hg archive --subrepos -r tip archive
380 378 cloning subrepo foo from $TESTTMP/empty/foo
381 379 abort: destination '$TESTTMP/almost-empty/foo' is not empty (glob)
382 380 [255]
383 381
384 382 Clone and test outgoing:
385 383
386 384 $ cd ..
387 385 $ hg clone repo repo2
388 386 updating to branch default
389 387 cloning subrepo foo from $TESTTMP/repo/foo
390 388 cloning subrepo foo/bar from $TESTTMP/repo/foo/bar (glob)
391 389 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
392 390 $ cd repo2
393 391 $ hg outgoing -S
394 392 comparing with $TESTTMP/repo (glob)
395 393 searching for changes
396 394 no changes found
397 395 comparing with $TESTTMP/repo/foo
398 396 searching for changes
399 397 no changes found
400 398 comparing with $TESTTMP/repo/foo/bar
401 399 searching for changes
402 400 no changes found
403 401 [1]
404 402
405 403 Make nested change:
406 404
407 405 $ echo y4 >> foo/y.txt
408 406 $ hg diff --nodates -S
409 407 diff -r 65903cebad86 foo/y.txt
410 408 --- a/foo/y.txt
411 409 +++ b/foo/y.txt
412 410 @@ -1,3 +1,4 @@
413 411 y1
414 412 y2
415 413 y3
416 414 +y4
417 415 $ hg commit --subrepos -m 3-4-2
418 416 committing subrepository foo
419 417 $ hg outgoing -S
420 418 comparing with $TESTTMP/repo (glob)
421 419 searching for changes
422 420 changeset: 3:2655b8ecc4ee
423 421 tag: tip
424 422 user: test
425 423 date: Thu Jan 01 00:00:00 1970 +0000
426 424 summary: 3-4-2
427 425
428 426 comparing with $TESTTMP/repo/foo
429 427 searching for changes
430 428 changeset: 4:e96193d6cb36
431 429 tag: tip
432 430 user: test
433 431 date: Thu Jan 01 00:00:00 1970 +0000
434 432 summary: 3-4-2
435 433
436 434 comparing with $TESTTMP/repo/foo/bar
437 435 searching for changes
438 436 no changes found
439 437
440 438
441 439 Switch to original repo and setup default path:
442 440
443 441 $ cd ../repo
444 442 $ echo '[paths]' >> .hg/hgrc
445 443 $ echo 'default = ../repo2' >> .hg/hgrc
446 444
447 445 Test incoming:
448 446
449 447 $ hg incoming -S
450 448 comparing with $TESTTMP/repo2 (glob)
451 449 searching for changes
452 450 changeset: 3:2655b8ecc4ee
453 451 tag: tip
454 452 user: test
455 453 date: Thu Jan 01 00:00:00 1970 +0000
456 454 summary: 3-4-2
457 455
458 456 comparing with $TESTTMP/repo2/foo
459 457 searching for changes
460 458 changeset: 4:e96193d6cb36
461 459 tag: tip
462 460 user: test
463 461 date: Thu Jan 01 00:00:00 1970 +0000
464 462 summary: 3-4-2
465 463
466 464 comparing with $TESTTMP/repo2/foo/bar
467 465 searching for changes
468 466 no changes found
469 467
470 468 $ hg incoming -S --bundle incoming.hg
471 469 abort: cannot combine --bundle and --subrepos
472 470 [255]
473 471
474 472 Test missing subrepo:
475 473
476 474 $ rm -r foo
477 475 $ hg status -S
478 476 warning: error "unknown revision '65903cebad86f1a84bd4f1134f62fa7dcb7a1c98'" in subrepository "foo"
479 477
480 478 Issue2619: IndexError: list index out of range on hg add with subrepos
481 479 The subrepo must sorts after the explicit filename.
482 480
483 481 $ cd ..
484 482 $ hg init test
485 483 $ cd test
486 484 $ hg init x
487 485 $ echo "x = x" >> .hgsub
488 486 $ hg add .hgsub
489 487 $ touch a x/a
490 488 $ hg add a x/a
@@ -1,106 +1,105 b''
1 1 $ "$TESTDIR/hghave" serve || exit 80
2 2
3 3 Preparing the subrepository 'sub'
4 4
5 5 $ hg init sub
6 6 $ echo sub > sub/sub
7 7 $ hg add -R sub
8 8 adding sub/sub (glob)
9 9 $ hg commit -R sub -m "sub import"
10 10
11 11 Preparing the 'main' repo which depends on the subrepo 'sub'
12 12
13 13 $ hg init main
14 14 $ echo main > main/main
15 15 $ echo "sub = ../sub" > main/.hgsub
16 16 $ hg clone sub main/sub
17 17 updating to branch default
18 18 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
19 19 $ hg add -R main
20 20 adding main/.hgsub (glob)
21 21 adding main/main (glob)
22 22 $ hg commit -R main -m "main import"
23 committing subrepository sub
24 23
25 24 Cleaning both repositories, just as a clone -U
26 25
27 26 $ hg up -C -R sub null
28 27 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
29 28 $ hg up -C -R main null
30 29 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
31 30 $ rm -rf main/sub
32 31
33 32 Serving them both using hgweb
34 33
35 34 $ printf '[paths]\n/main = main\nsub = sub\n' > webdir.conf
36 35 $ hg serve --webdir-conf webdir.conf -a localhost -p $HGPORT \
37 36 > -A /dev/null -E /dev/null --pid-file hg.pid -d
38 37 $ cat hg.pid >> $DAEMON_PIDS
39 38
40 39 Clone main from hgweb
41 40
42 41 $ hg clone "http://localhost:$HGPORT/main" cloned
43 42 requesting all changes
44 43 adding changesets
45 44 adding manifests
46 45 adding file changes
47 46 added 1 changesets with 3 changes to 3 files
48 47 updating to branch default
49 48 cloning subrepo sub from http://localhost:$HGPORT/sub
50 49 requesting all changes
51 50 adding changesets
52 51 adding manifests
53 52 adding file changes
54 53 added 1 changesets with 1 changes to 1 files
55 54 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
56 55
57 56 Checking cloned repo ids
58 57
59 58 $ hg id -R cloned
60 59 fdfeeb3e979e tip
61 60 $ hg id -R cloned/sub
62 61 863c1745b441 tip
63 62
64 63 subrepo debug for 'main' clone
65 64
66 65 $ hg debugsub -R cloned
67 66 path sub
68 67 source ../sub
69 68 revision 863c1745b441bd97a8c4a096e87793073f4fb215
70 69
71 70 $ "$TESTDIR/killdaemons.py"
72 71
73 72 subrepo paths with ssh urls
74 73
75 74 $ cp $TESTDIR/dummyssh $BINDIR/ssh
76 75
77 76 $ hg clone ssh://user@dummy/cloned sshclone
78 77 requesting all changes
79 78 adding changesets
80 79 adding manifests
81 80 adding file changes
82 81 added 1 changesets with 3 changes to 3 files
83 82 updating to branch default
84 83 cloning subrepo sub from ssh://user@dummy/sub
85 84 requesting all changes
86 85 adding changesets
87 86 adding manifests
88 87 adding file changes
89 88 added 1 changesets with 1 changes to 1 files
90 89 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 90
92 91 $ hg -R sshclone push ssh://user@dummy/$TESTTMP/cloned
93 92 pushing to ssh://user@dummy/$TESTTMP/cloned
94 93 pushing subrepo sub to ssh://user@dummy/$TESTTMP/sub
95 94 searching for changes
96 95 no changes found
97 96 searching for changes
98 97 no changes found
99 98 [1]
100 99
101 100 $ cat dummylog
102 101 Got arguments 1:user@dummy 2:hg -R cloned serve --stdio
103 102 Got arguments 1:user@dummy 2:hg -R sub serve --stdio
104 103 Got arguments 1:user@dummy 2:hg -R $TESTTMP/cloned serve --stdio
105 104 Got arguments 1:user@dummy 2:hg -R $TESTTMP/sub serve --stdio
106 105 $ rm $BINDIR/ssh
@@ -1,545 +1,537 b''
1 1 $ "$TESTDIR/hghave" svn15 || exit 80
2 2
3 3 $ fix_path()
4 4 > {
5 5 > tr '\\' /
6 6 > }
7 7
8 8 SVN wants all paths to start with a slash. Unfortunately, Windows ones
9 9 don't. Handle that.
10 10
11 11 $ escapedwd=`pwd | fix_path`
12 12 $ expr "$escapedwd" : '\/' > /dev/null || escapedwd="/$escapedwd"
13 13 $ escapedwd=`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$escapedwd"`
14 14
15 15 create subversion repo
16 16
17 17 $ SVNREPO="file://$escapedwd/svn-repo"
18 18 $ WCROOT="`pwd`/svn-wc"
19 19 $ svnadmin create svn-repo
20 20 $ svn co "$SVNREPO" svn-wc
21 21 Checked out revision 0.
22 22 $ cd svn-wc
23 23 $ mkdir src
24 24 $ echo alpha > src/alpha
25 25 $ svn add src
26 26 A src
27 27 A src/alpha
28 28 $ mkdir externals
29 29 $ echo other > externals/other
30 30 $ svn add externals
31 31 A externals
32 32 A externals/other
33 33 $ svn ci -m 'Add alpha'
34 34 Adding externals
35 35 Adding externals/other
36 36 Adding src
37 37 Adding src/alpha
38 38 Transmitting file data ..
39 39 Committed revision 1.
40 40 $ svn up -q
41 41 $ echo "externals -r1 $SVNREPO/externals" > extdef
42 42 $ svn propset -F extdef svn:externals src
43 43 property 'svn:externals' set on 'src'
44 44 $ svn ci -m 'Setting externals'
45 45 Sending src
46 46
47 47 Committed revision 2.
48 48 $ cd ..
49 49
50 50 create hg repo
51 51
52 52 $ mkdir sub
53 53 $ cd sub
54 54 $ hg init t
55 55 $ cd t
56 56
57 57 first revision, no sub
58 58
59 59 $ echo a > a
60 60 $ hg ci -Am0
61 61 adding a
62 62
63 63 add first svn sub with leading whitespaces
64 64
65 65 $ echo "s = [svn] $SVNREPO/src" >> .hgsub
66 66 $ echo "subdir/s = [svn] $SVNREPO/src" >> .hgsub
67 67 $ svn co --quiet "$SVNREPO"/src s
68 68 $ mkdir subdir
69 69 $ svn co --quiet "$SVNREPO"/src subdir/s
70 70 $ hg add .hgsub
71 71 $ hg ci -m1
72 committing subrepository s
73 committing subrepository subdir/s
74 72
75 73 make sure we avoid empty commits (issue2445)
76 74
77 75 $ hg sum
78 76 parent: 1:* tip (glob)
79 77 1
80 78 branch: default
81 79 commit: (clean)
82 80 update: (current)
83 81 $ hg ci -moops
84 82 nothing changed
85 83 [1]
86 84
87 85 debugsub
88 86
89 87 $ hg debugsub
90 88 path s
91 89 source file://*/svn-repo/src (glob)
92 90 revision 2
93 91 path subdir/s
94 92 source file://*/svn-repo/src (glob)
95 93 revision 2
96 94
97 95 change file in svn and hg, commit
98 96
99 97 $ echo a >> a
100 98 $ echo alpha >> s/alpha
101 99 $ hg sum
102 100 parent: 1:* tip (glob)
103 101 1
104 102 branch: default
105 103 commit: 1 modified, 1 subrepos
106 104 update: (current)
107 105 $ hg commit --subrepos -m 'Message!' | grep -v Updating
108 106 committing subrepository s
109 107 Sending*s/alpha (glob)
110 108 Transmitting file data .
111 109 Committed revision 3.
112 110
113 111 Fetching external item into '*s/externals'* (glob)
114 112 External at revision 1.
115 113
116 114 At revision 3.
117 115 $ hg debugsub
118 116 path s
119 117 source file://*/svn-repo/src (glob)
120 118 revision 3
121 119 path subdir/s
122 120 source file://*/svn-repo/src (glob)
123 121 revision 2
124 122
125 123 add an unrelated revision in svn and update the subrepo to without
126 124 bringing any changes.
127 125
128 126 $ svn mkdir "$SVNREPO/unrelated" -m 'create unrelated'
129 127
130 128 Committed revision 4.
131 129 $ svn up -q s
132 130 $ hg sum
133 131 parent: 2:* tip (glob)
134 132 Message!
135 133 branch: default
136 134 commit: (clean)
137 135 update: (current)
138 136
139 137 $ echo a > s/a
140 138
141 139 should be empty despite change to s/a
142 140
143 141 $ hg st
144 142
145 143 add a commit from svn
146 144
147 145 $ cd "$WCROOT"/src
148 146 $ svn up -q
149 147 $ echo xyz >> alpha
150 148 $ svn propset svn:mime-type 'text/xml' alpha
151 149 property 'svn:mime-type' set on 'alpha'
152 150 $ svn ci -m 'amend a from svn'
153 151 Sending *alpha (glob)
154 152 Transmitting file data .
155 153 Committed revision 5.
156 154 $ cd ../../sub/t
157 155
158 156 this commit from hg will fail
159 157
160 158 $ echo zzz >> s/alpha
161 159 $ (hg ci --subrepos -m 'amend alpha from hg' 2>&1; echo "[$?]") | grep -vi 'out of date'
162 160 committing subrepository s
163 161 abort: svn:*Commit failed (details follow): (glob)
164 162 [255]
165 163 $ svn revert -q s/alpha
166 164
167 165 this commit fails because of meta changes
168 166
169 167 $ svn propset svn:mime-type 'text/html' s/alpha
170 168 property 'svn:mime-type' set on 's/alpha'
171 169 $ (hg ci --subrepos -m 'amend alpha from hg' 2>&1; echo "[$?]") | grep -vi 'out of date'
172 170 committing subrepository s
173 171 abort: svn:*Commit failed (details follow): (glob)
174 172 [255]
175 173 $ svn revert -q s/alpha
176 174
177 175 this commit fails because of externals changes
178 176
179 177 $ echo zzz > s/externals/other
180 178 $ hg ci --subrepos -m 'amend externals from hg'
181 179 committing subrepository s
182 180 abort: cannot commit svn externals
183 181 [255]
184 182 $ hg diff --subrepos -r 1:2 | grep -v diff
185 183 --- a/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
186 184 +++ b/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
187 185 @@ -1,2 +1,2 @@
188 186 -2 s
189 187 +3 s
190 188 2 subdir/s
191 189 --- a/a Thu Jan 01 00:00:00 1970 +0000
192 190 +++ b/a Thu Jan 01 00:00:00 1970 +0000
193 191 @@ -1,1 +1,2 @@
194 192 a
195 193 +a
196 194 $ svn revert -q s/externals/other
197 195
198 196 this commit fails because of externals meta changes
199 197
200 198 $ svn propset svn:mime-type 'text/html' s/externals/other
201 199 property 'svn:mime-type' set on 's/externals/other'
202 200 $ hg ci --subrepos -m 'amend externals from hg'
203 201 committing subrepository s
204 202 abort: cannot commit svn externals
205 203 [255]
206 204 $ svn revert -q s/externals/other
207 205
208 206 clone
209 207
210 208 $ cd ..
211 209 $ hg clone t tc | fix_path
212 210 updating to branch default
213 211 A tc/s/alpha
214 212 U tc/s
215 213
216 214 Fetching external item into 'tc/s/externals'* (glob)
217 215 A tc/s/externals/other
218 216 Checked out external at revision 1.
219 217
220 218 Checked out revision 3.
221 219 A tc/subdir/s/alpha
222 220 U tc/subdir/s
223 221
224 222 Fetching external item into 'tc/subdir/s/externals'* (glob)
225 223 A tc/subdir/s/externals/other
226 224 Checked out external at revision 1.
227 225
228 226 Checked out revision 2.
229 227 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
230 228 $ cd tc
231 229
232 230 debugsub in clone
233 231
234 232 $ hg debugsub
235 233 path s
236 234 source file://*/svn-repo/src (glob)
237 235 revision 3
238 236 path subdir/s
239 237 source file://*/svn-repo/src (glob)
240 238 revision 2
241 239
242 240 verify subrepo is contained within the repo directory
243 241
244 242 $ python -c "import os.path; print os.path.exists('s')"
245 243 True
246 244
247 245 update to nullrev (must delete the subrepo)
248 246
249 247 $ hg up null
250 248 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
251 249 $ ls
252 250
253 251 Check hg update --clean
254 252 $ cd $TESTTMP/sub/t
255 253 $ cd s
256 254 $ echo c0 > alpha
257 255 $ echo c1 > f1
258 256 $ echo c1 > f2
259 257 $ svn add f1 -q
260 258 $ svn status | sort
261 259
262 260 ? * a (glob)
263 261 ? * f2 (glob)
264 262 A * f1 (glob)
265 263 M * alpha (glob)
266 264 Performing status on external item at 'externals'* (glob)
267 265 X * externals (glob)
268 266 $ cd ../..
269 267 $ hg -R t update -C
270 268
271 269 Fetching external item into 't/s/externals'* (glob)
272 270 Checked out external at revision 1.
273 271
274 272 Checked out revision 3.
275 273 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
276 274 $ cd t/s
277 275 $ svn status
278 276 ? * a (glob)
279 277 X * externals (glob)
280 278 ? * f1 (glob)
281 279 ? * f2 (glob)
282 280
283 281 Performing status on external item at 'externals'* (glob)
284 282
285 283 Sticky subrepositories, no changes
286 284 $ cd $TESTTMP/sub/t
287 285 $ hg id -n
288 286 2
289 287 $ cd s
290 288 $ svnversion
291 289 3
292 290 $ cd ..
293 291 $ hg update 1
294 292 U *s/alpha (glob)
295 293
296 294 Fetching external item into '*s/externals'* (glob)
297 295 Checked out external at revision 1.
298 296
299 297 Checked out revision 2.
300 298 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
301 299 $ hg id -n
302 300 1
303 301 $ cd s
304 302 $ svnversion
305 303 2
306 304 $ cd ..
307 305
308 306 Sticky subrepositorys, file changes
309 307 $ touch s/f1
310 308 $ cd s
311 309 $ svn add f1
312 310 A f1
313 311 $ cd ..
314 312 $ hg id -n
315 313 1
316 314 $ cd s
317 315 $ svnversion
318 316 2M
319 317 $ cd ..
320 318 $ hg update tip
321 319 subrepository sources for s differ
322 320 use (l)ocal source (2) or (r)emote source (3)?
323 321 l
324 322 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
325 323 $ hg id -n
326 324 2+
327 325 $ cd s
328 326 $ svnversion
329 327 2M
330 328 $ cd ..
331 329 $ hg update --clean tip
332 330 U *s/alpha (glob)
333 331
334 332 Fetching external item into '*s/externals'* (glob)
335 333 Checked out external at revision 1.
336 334
337 335 Checked out revision 3.
338 336 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
339 337
340 338 Sticky subrepository, revision updates
341 339 $ hg id -n
342 340 2
343 341 $ cd s
344 342 $ svnversion
345 343 3
346 344 $ cd ..
347 345 $ cd s
348 346 $ svn update -qr 1
349 347 $ cd ..
350 348 $ hg update 1
351 349 subrepository sources for s differ (in checked out version)
352 350 use (l)ocal source (1) or (r)emote source (2)?
353 351 l
354 352 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
355 353 $ hg id -n
356 354 1+
357 355 $ cd s
358 356 $ svnversion
359 357 1
360 358 $ cd ..
361 359
362 360 Sticky subrepository, file changes and revision updates
363 361 $ touch s/f1
364 362 $ cd s
365 363 $ svn add f1
366 364 A f1
367 365 $ svnversion
368 366 1M
369 367 $ cd ..
370 368 $ hg id -n
371 369 1+
372 370 $ hg update tip
373 371 subrepository sources for s differ
374 372 use (l)ocal source (1) or (r)emote source (3)?
375 373 l
376 374 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
377 375 $ hg id -n
378 376 2
379 377 $ cd s
380 378 $ svnversion
381 379 1M
382 380 $ cd ..
383 381
384 382 Sticky repository, update --clean
385 383 $ hg update --clean tip | grep -v s/externals/other
386 384 U *s/alpha (glob)
387 385 U *s (glob)
388 386
389 387 Fetching external item into '*s/externals'* (glob)
390 388 Checked out external at revision 1.
391 389
392 390 Checked out revision 3.
393 391 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
394 392 $ hg id -n
395 393 2
396 394 $ cd s
397 395 $ svnversion
398 396 3
399 397 $ cd ..
400 398
401 399 Test subrepo already at intended revision:
402 400 $ cd s
403 401 $ svn update -qr 2
404 402 $ cd ..
405 403 $ hg update 1
406 404 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
407 405 $ hg id -n
408 406 1+
409 407 $ cd s
410 408 $ svnversion
411 409 2
412 410 $ cd ..
413 411
414 412 Test case where subversion would fail to update the subrepo because there
415 413 are unknown directories being replaced by tracked ones (happens with rebase).
416 414
417 415 $ cd $WCROOT/src
418 416 $ mkdir dir
419 417 $ echo epsilon.py > dir/epsilon.py
420 418 $ svn add dir
421 419 A dir
422 420 A dir/epsilon.py
423 421 $ svn ci -m 'Add dir/epsilon.py'
424 422 Adding *dir (glob)
425 423 Adding *dir/epsilon.py (glob)
426 424 Transmitting file data .
427 425 Committed revision 6.
428 426 $ cd ../..
429 427 $ hg init rebaserepo
430 428 $ cd rebaserepo
431 429 $ svn co -r5 --quiet "$SVNREPO"/src s
432 430 $ echo "s = [svn] $SVNREPO/src" >> .hgsub
433 431 $ hg add .hgsub
434 432 $ hg ci -m addsub
435 committing subrepository s
436 433 $ echo a > a
437 434 $ hg ci -Am adda
438 435 adding a
439 436 $ hg up 0
440 437 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
441 438 $ svn up -qr6 s
442 439 $ hg ci -m updatesub
443 committing subrepository s
444 440 created new head
445 441 $ echo pyc > s/dir/epsilon.pyc
446 442 $ hg up 1
447 443 D *s/dir (glob)
448 444
449 445 Fetching external item into '*s/externals'* (glob)
450 446 Checked out external at revision 1.
451 447
452 448 Checked out revision 5.
453 449 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
454 450 $ if "$TESTDIR/hghave" -q svn15; then
455 451 > hg up 2 >/dev/null 2>&1 || echo update failed
456 452 > fi
457 453
458 454 Modify one of the externals to point to a different path so we can
459 455 test having obstructions when switching branches on checkout:
460 456 $ hg checkout tip
461 457 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
462 458 $ echo "obstruct = [svn] $SVNREPO/externals" >> .hgsub
463 459 $ svn co -r5 --quiet "$SVNREPO"/externals obstruct
464 460 $ hg commit -m 'Start making obstructed working copy'
465 committing subrepository obstruct
466 461 $ hg book other
467 462 $ hg co -r 'p1(tip)'
468 463 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
469 464 $ echo "obstruct = [svn] $SVNREPO/src" >> .hgsub
470 465 $ svn co -r5 --quiet "$SVNREPO"/src obstruct
471 466 $ hg commit -m 'Other branch which will be obstructed'
472 committing subrepository obstruct
473 467 created new head
474 468
475 469 Switching back to the head where we have another path mapped to the
476 470 same subrepo should work if the subrepo is clean.
477 471 $ hg co other
478 472 A *obstruct/other (glob)
479 473 Checked out revision 1.
480 474 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
481 475
482 476 This is surprising, but is also correct based on the current code:
483 477 $ echo "updating should (maybe) fail" > obstruct/other
484 478 $ hg co tip
485 479 abort: crosses branches (merge branches or use --clean to discard changes)
486 480 [255]
487 481
488 482 Point to a Subversion branch which has since been deleted and recreated
489 483 First, create that condition in the repository.
490 484
491 485 $ hg ci --subrepos -m cleanup | grep -v Updating
492 486 committing subrepository obstruct
493 487 Sending obstruct/other
494 488 Transmitting file data .
495 489 Committed revision 7.
496 490 At revision 7.
497 491 $ svn mkdir -m "baseline" $SVNREPO/trunk
498 492
499 493 Committed revision 8.
500 494 $ svn copy -m "initial branch" $SVNREPO/trunk $SVNREPO/branch
501 495
502 496 Committed revision 9.
503 497 $ svn co --quiet "$SVNREPO"/branch tempwc
504 498 $ cd tempwc
505 499 $ echo "something old" > somethingold
506 500 $ svn add somethingold
507 501 A somethingold
508 502 $ svn ci -m 'Something old'
509 503 Adding somethingold
510 504 Transmitting file data .
511 505 Committed revision 10.
512 506 $ svn rm -m "remove branch" $SVNREPO/branch
513 507
514 508 Committed revision 11.
515 509 $ svn copy -m "recreate branch" $SVNREPO/trunk $SVNREPO/branch
516 510
517 511 Committed revision 12.
518 512 $ svn up -q
519 513 $ echo "something new" > somethingnew
520 514 $ svn add somethingnew
521 515 A somethingnew
522 516 $ svn ci -m 'Something new'
523 517 Adding somethingnew
524 518 Transmitting file data .
525 519 Committed revision 13.
526 520 $ cd ..
527 521 $ rm -rf tempwc
528 522 $ svn co "$SVNREPO/branch"@10 recreated
529 523 A recreated/somethingold
530 524 Checked out revision 10.
531 525 $ echo "recreated = [svn] $SVNREPO/branch" >> .hgsub
532 526 $ hg ci -m addsub
533 committing subrepository recreated
534 527 $ cd recreated
535 528 $ svn up -q
536 529 $ cd ..
537 530 $ hg ci -m updatesub
538 committing subrepository recreated
539 531 $ hg up -r-2
540 532 D *recreated/somethingnew (glob)
541 533 A *recreated/somethingold (glob)
542 534 Checked out revision 10.
543 535 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
544 536 $ test -f recreated/somethingold
545 537
@@ -1,1037 +1,1018 b''
1 1 Let commit recurse into subrepos by default to match pre-2.0 behavior:
2 2
3 3 $ echo "[ui]" >> $HGRCPATH
4 4 $ echo "commitsubrepos = Yes" >> $HGRCPATH
5 5
6 6 $ rm -rf sub
7 7 $ mkdir sub
8 8 $ cd sub
9 9 $ hg init t
10 10 $ cd t
11 11
12 12 first revision, no sub
13 13
14 14 $ echo a > a
15 15 $ hg ci -Am0
16 16 adding a
17 17
18 18 add first sub
19 19
20 20 $ echo s = s > .hgsub
21 21 $ hg add .hgsub
22 22 $ hg init s
23 23 $ echo a > s/a
24 24
25 25 Issue2232: committing a subrepo without .hgsub
26 26
27 27 $ hg ci -mbad s
28 28 abort: can't commit subrepos without .hgsub
29 29 [255]
30 30
31 31 $ hg -R s ci -Ams0
32 32 adding a
33 33 $ hg sum
34 34 parent: 0:f7b1eb17ad24 tip
35 35 0
36 36 branch: default
37 37 commit: 1 added, 1 subrepos
38 38 update: (current)
39 39 $ hg ci -m1
40 committing subrepository s
41 40
42 41 Revert can't (yet) revert subrepos:
43 42
44 43 $ echo b > s/a
45 44 $ hg revert s
46 45 s: reverting subrepos is unsupported
47 46
48 47 Revert currently ignores subrepos by default
49 48
50 49 $ hg revert -a
51 50 $ hg revert -R s -a -C
52 51 reverting s/a (glob)
53 52
54 53 Issue2022: update -C
55 54
56 55 $ echo b > s/a
57 56 $ hg sum
58 57 parent: 1:7cf8cfea66e4 tip
59 58 1
60 59 branch: default
61 60 commit: 1 subrepos
62 61 update: (current)
63 62 $ hg co -C 1
64 63 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 64 $ hg sum
66 65 parent: 1:7cf8cfea66e4 tip
67 66 1
68 67 branch: default
69 68 commit: (clean)
70 69 update: (current)
71 70
72 71 commands that require a clean repo should respect subrepos
73 72
74 73 $ echo b >> s/a
75 74 $ hg backout tip
76 75 abort: uncommitted changes in subrepo s
77 76 [255]
78 77 $ hg revert -C -R s s/a
79 78
80 79 add sub sub
81 80
82 81 $ echo ss = ss > s/.hgsub
83 82 $ hg init s/ss
84 83 $ echo a > s/ss/a
85 84 $ hg -R s add s/.hgsub
86 85 $ hg -R s/ss add s/ss/a
87 86 $ hg sum
88 87 parent: 1:7cf8cfea66e4 tip
89 88 1
90 89 branch: default
91 90 commit: 1 subrepos
92 91 update: (current)
93 92 $ hg ci -m2
94 93 committing subrepository s
95 94 committing subrepository s/ss (glob)
96 95 $ hg sum
97 96 parent: 2:df30734270ae tip
98 97 2
99 98 branch: default
100 99 commit: (clean)
101 100 update: (current)
102 101
103 102 bump sub rev (and check it is ignored by ui.commitsubrepos)
104 103
105 104 $ echo b > s/a
106 105 $ hg -R s ci -ms1
107 106 $ hg --config ui.commitsubrepos=no ci -m3
108 committing subrepository s
109 107
110 108 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
111 109
112 110 $ echo c > s/a
113 111 $ hg --config ui.commitsubrepos=no ci -m4
114 112 abort: uncommitted changes in subrepo s
115 113 (use --subrepos for recursive commit)
116 114 [255]
117 115 $ hg ci -m4
118 116 committing subrepository s
119 117 $ hg tip -R s
120 118 changeset: 3:1c833a7a9e3a
121 119 tag: tip
122 120 user: test
123 121 date: Thu Jan 01 00:00:00 1970 +0000
124 122 summary: 4
125 123
126 124
127 125 check caching
128 126
129 127 $ hg co 0
130 128 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
131 129 $ hg debugsub
132 130
133 131 restore
134 132
135 133 $ hg co
136 134 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
137 135 $ hg debugsub
138 136 path s
139 137 source s
140 138 revision 1c833a7a9e3a4445c711aaf0f012379cd0d4034e
141 139
142 140 new branch for merge tests
143 141
144 142 $ hg co 1
145 143 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
146 144 $ echo t = t >> .hgsub
147 145 $ hg init t
148 146 $ echo t > t/t
149 147 $ hg -R t add t
150 148 adding t/t (glob)
151 149
152 150 5
153 151
154 152 $ hg ci -m5 # add sub
155 153 committing subrepository t
156 154 created new head
157 155 $ echo t2 > t/t
158 156
159 157 6
160 158
161 159 $ hg st -R s
162 160 $ hg ci -m6 # change sub
163 161 committing subrepository t
164 162 $ hg debugsub
165 163 path s
166 164 source s
167 165 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
168 166 path t
169 167 source t
170 168 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
171 169 $ echo t3 > t/t
172 170
173 171 7
174 172
175 173 $ hg ci -m7 # change sub again for conflict test
176 174 committing subrepository t
177 175 $ hg rm .hgsub
178 176
179 177 8
180 178
181 179 $ hg ci -m8 # remove sub
182 180
183 181 merge tests
184 182
185 183 $ hg co -C 3
186 184 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
187 185 $ hg merge 5 # test adding
188 186 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 187 (branch merge, don't forget to commit)
190 188 $ hg debugsub
191 189 path s
192 190 source s
193 191 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
194 192 path t
195 193 source t
196 194 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
197 195 $ hg ci -m9
198 196 created new head
199 197 $ hg merge 6 --debug # test change
200 198 searching for copies back to rev 2
201 199 resolving manifests
202 200 overwrite: False, partial: False
203 201 ancestor: 1f14a2e2d3ec, local: f0d2028bf86d+, remote: 1831e14459c4
204 202 .hgsubstate: versions differ -> m
205 203 updating: .hgsubstate 1/1 files (100.00%)
206 204 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
207 205 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
208 206 getting subrepo t
209 207 resolving manifests
210 208 overwrite: True, partial: False
211 209 ancestor: 60ca1237c194+, local: 60ca1237c194+, remote: 6747d179aa9a
212 210 t: remote is newer -> g
213 211 updating: t 1/1 files (100.00%)
214 212 getting t
215 213 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
216 214 (branch merge, don't forget to commit)
217 215 $ hg debugsub
218 216 path s
219 217 source s
220 218 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
221 219 path t
222 220 source t
223 221 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
224 222 $ echo conflict > t/t
225 223 $ hg ci -m10
226 224 committing subrepository t
227 225 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
228 226 searching for copies back to rev 2
229 227 resolving manifests
230 228 overwrite: False, partial: False
231 229 ancestor: 1831e14459c4, local: e45c8b14af55+, remote: f94576341bcf
232 230 .hgsubstate: versions differ -> m
233 231 updating: .hgsubstate 1/1 files (100.00%)
234 232 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
235 233 subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
236 234 merging subrepo t
237 235 searching for copies back to rev 2
238 236 resolving manifests
239 237 overwrite: False, partial: False
240 238 ancestor: 6747d179aa9a, local: 20a0db6fbf6c+, remote: 7af322bc1198
241 239 t: versions differ -> m
242 240 preserving t for resolve of t
243 241 updating: t 1/1 files (100.00%)
244 242 picked tool 'internal:merge' for t (binary False symlink False)
245 243 merging t
246 244 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
247 245 warning: conflicts during merge.
248 246 merging t incomplete! (edit conflicts, then use 'hg resolve --mark')
249 247 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
250 248 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
251 249 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
252 250 (branch merge, don't forget to commit)
253 251
254 252 should conflict
255 253
256 254 $ cat t/t
257 255 <<<<<<< local
258 256 conflict
259 257 =======
260 258 t3
261 259 >>>>>>> other
262 260
263 261 clone
264 262
265 263 $ cd ..
266 264 $ hg clone t tc
267 265 updating to branch default
268 266 cloning subrepo s from $TESTTMP/sub/t/s (glob)
269 267 cloning subrepo s/ss from $TESTTMP/sub/t/s/ss (glob)
270 268 cloning subrepo t from $TESTTMP/sub/t/t (glob)
271 269 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
272 270 $ cd tc
273 271 $ hg debugsub
274 272 path s
275 273 source s
276 274 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
277 275 path t
278 276 source t
279 277 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
280 278
281 279 push
282 280
283 281 $ echo bah > t/t
284 282 $ hg ci -m11
285 283 committing subrepository t
286 284 $ hg push
287 285 pushing to $TESTTMP/sub/t (glob)
288 286 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss (glob)
289 287 searching for changes
290 288 no changes found
291 289 pushing subrepo s to $TESTTMP/sub/t/s (glob)
292 290 searching for changes
293 291 no changes found
294 292 pushing subrepo t to $TESTTMP/sub/t/t (glob)
295 293 searching for changes
296 294 adding changesets
297 295 adding manifests
298 296 adding file changes
299 297 added 1 changesets with 1 changes to 1 files
300 298 searching for changes
301 299 adding changesets
302 300 adding manifests
303 301 adding file changes
304 302 added 1 changesets with 1 changes to 1 files
305 303
306 304 push -f
307 305
308 306 $ echo bah > s/a
309 307 $ hg ci -m12
310 308 committing subrepository s
311 309 $ hg push
312 310 pushing to $TESTTMP/sub/t (glob)
313 311 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss (glob)
314 312 searching for changes
315 313 no changes found
316 314 pushing subrepo s to $TESTTMP/sub/t/s (glob)
317 315 searching for changes
318 316 abort: push creates new remote head 12a213df6fa9!
319 317 (did you forget to merge? use push -f to force)
320 318 [255]
321 319 $ hg push -f
322 320 pushing to $TESTTMP/sub/t (glob)
323 321 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss (glob)
324 322 searching for changes
325 323 no changes found
326 324 pushing subrepo s to $TESTTMP/sub/t/s (glob)
327 325 searching for changes
328 326 adding changesets
329 327 adding manifests
330 328 adding file changes
331 329 added 1 changesets with 1 changes to 1 files (+1 heads)
332 330 pushing subrepo t to $TESTTMP/sub/t/t (glob)
333 331 searching for changes
334 332 no changes found
335 333 searching for changes
336 334 adding changesets
337 335 adding manifests
338 336 adding file changes
339 337 added 1 changesets with 1 changes to 1 files
340 338
341 339 update
342 340
343 341 $ cd ../t
344 342 $ hg up -C # discard our earlier merge
345 343 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
346 344 $ echo blah > t/t
347 345 $ hg ci -m13
348 346 committing subrepository t
349 347
350 348 pull
351 349
352 350 $ cd ../tc
353 351 $ hg pull
354 352 pulling from $TESTTMP/sub/t (glob)
355 353 searching for changes
356 354 adding changesets
357 355 adding manifests
358 356 adding file changes
359 357 added 1 changesets with 1 changes to 1 files
360 358 (run 'hg update' to get a working copy)
361 359
362 360 should pull t
363 361
364 362 $ hg up
365 363 pulling subrepo t from $TESTTMP/sub/t/t (glob)
366 364 searching for changes
367 365 adding changesets
368 366 adding manifests
369 367 adding file changes
370 368 added 1 changesets with 1 changes to 1 files
371 369 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
372 370 $ cat t/t
373 371 blah
374 372
375 373 bogus subrepo path aborts
376 374
377 375 $ echo 'bogus=[boguspath' >> .hgsub
378 376 $ hg ci -m 'bogus subrepo path'
379 377 abort: missing ] in subrepo source
380 378 [255]
381 379
382 380 Issue1986: merge aborts when trying to merge a subrepo that
383 381 shouldn't need merging
384 382
385 383 # subrepo layout
386 384 #
387 385 # o 5 br
388 386 # /|
389 387 # o | 4 default
390 388 # | |
391 389 # | o 3 br
392 390 # |/|
393 391 # o | 2 default
394 392 # | |
395 393 # | o 1 br
396 394 # |/
397 395 # o 0 default
398 396
399 397 $ cd ..
400 398 $ rm -rf sub
401 399 $ hg init main
402 400 $ cd main
403 401 $ hg init s
404 402 $ cd s
405 403 $ echo a > a
406 404 $ hg ci -Am1
407 405 adding a
408 406 $ hg branch br
409 407 marked working directory as branch br
410 408 (branches are permanent and global, did you want a bookmark?)
411 409 $ echo a >> a
412 410 $ hg ci -m1
413 411 $ hg up default
414 412 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
415 413 $ echo b > b
416 414 $ hg ci -Am1
417 415 adding b
418 416 $ hg up br
419 417 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
420 418 $ hg merge tip
421 419 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
422 420 (branch merge, don't forget to commit)
423 421 $ hg ci -m1
424 422 $ hg up 2
425 423 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
426 424 $ echo c > c
427 425 $ hg ci -Am1
428 426 adding c
429 427 $ hg up 3
430 428 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
431 429 $ hg merge 4
432 430 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
433 431 (branch merge, don't forget to commit)
434 432 $ hg ci -m1
435 433
436 434 # main repo layout:
437 435 #
438 436 # * <-- try to merge default into br again
439 437 # .`|
440 438 # . o 5 br --> substate = 5
441 439 # . |
442 440 # o | 4 default --> substate = 4
443 441 # | |
444 442 # | o 3 br --> substate = 2
445 443 # |/|
446 444 # o | 2 default --> substate = 2
447 445 # | |
448 446 # | o 1 br --> substate = 3
449 447 # |/
450 448 # o 0 default --> substate = 2
451 449
452 450 $ cd ..
453 451 $ echo 's = s' > .hgsub
454 452 $ hg -R s up 2
455 453 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
456 454 $ hg ci -Am1
457 455 adding .hgsub
458 committing subrepository s
459 456 $ hg branch br
460 457 marked working directory as branch br
461 458 (branches are permanent and global, did you want a bookmark?)
462 459 $ echo b > b
463 460 $ hg -R s up 3
464 461 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
465 462 $ hg ci -Am1
466 463 adding b
467 committing subrepository s
468 464 $ hg up default
469 465 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
470 466 $ echo c > c
471 467 $ hg ci -Am1
472 468 adding c
473 469 $ hg up 1
474 470 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
475 471 $ hg merge 2
476 472 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
477 473 (branch merge, don't forget to commit)
478 474 $ hg ci -m1
479 475 $ hg up 2
480 476 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
481 477 $ hg -R s up 4
482 478 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
483 479 $ echo d > d
484 480 $ hg ci -Am1
485 481 adding d
486 committing subrepository s
487 482 $ hg up 3
488 483 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
489 484 $ hg -R s up 5
490 485 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
491 486 $ echo e > e
492 487 $ hg ci -Am1
493 488 adding e
494 committing subrepository s
495 489
496 490 $ hg up 5
497 491 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
498 492 $ hg merge 4 # try to merge default into br again
499 493 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
500 494 (branch merge, don't forget to commit)
501 495 $ cd ..
502 496
503 497 test subrepo delete from .hgsubstate
504 498
505 499 $ hg init testdelete
506 500 $ mkdir testdelete/nested testdelete/nested2
507 501 $ hg init testdelete/nested
508 502 $ hg init testdelete/nested2
509 503 $ echo test > testdelete/nested/foo
510 504 $ echo test > testdelete/nested2/foo
511 505 $ hg -R testdelete/nested add
512 506 adding testdelete/nested/foo (glob)
513 507 $ hg -R testdelete/nested2 add
514 508 adding testdelete/nested2/foo (glob)
515 509 $ hg -R testdelete/nested ci -m test
516 510 $ hg -R testdelete/nested2 ci -m test
517 511 $ echo nested = nested > testdelete/.hgsub
518 512 $ echo nested2 = nested2 >> testdelete/.hgsub
519 513 $ hg -R testdelete add
520 514 adding testdelete/.hgsub (glob)
521 515 $ hg -R testdelete ci -m "nested 1 & 2 added"
522 committing subrepository nested
523 committing subrepository nested2
524 516 $ echo nested = nested > testdelete/.hgsub
525 517 $ hg -R testdelete ci -m "nested 2 deleted"
526 518 $ cat testdelete/.hgsubstate
527 519 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
528 520 $ hg -R testdelete remove testdelete/.hgsub
529 521 $ hg -R testdelete ci -m ".hgsub deleted"
530 522 $ cat testdelete/.hgsubstate
531 523 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
532 524
533 525 test repository cloning
534 526
535 527 $ mkdir mercurial mercurial2
536 528 $ hg init nested_absolute
537 529 $ echo test > nested_absolute/foo
538 530 $ hg -R nested_absolute add
539 531 adding nested_absolute/foo (glob)
540 532 $ hg -R nested_absolute ci -mtest
541 533 $ cd mercurial
542 534 $ hg init nested_relative
543 535 $ echo test2 > nested_relative/foo2
544 536 $ hg -R nested_relative add
545 537 adding nested_relative/foo2 (glob)
546 538 $ hg -R nested_relative ci -mtest2
547 539 $ hg init main
548 540 $ echo "nested_relative = ../nested_relative" > main/.hgsub
549 541 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
550 542 $ hg -R main add
551 543 adding main/.hgsub (glob)
552 544 $ hg -R main ci -m "add subrepos"
553 committing subrepository nested_absolute
554 committing subrepository nested_relative
555 545 $ cd ..
556 546 $ hg clone mercurial/main mercurial2/main
557 547 updating to branch default
558 548 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
559 549 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
560 550 > mercurial2/main/nested_relative/.hg/hgrc
561 551 [paths]
562 552 default = $TESTTMP/sub/mercurial/nested_absolute
563 553 [paths]
564 554 default = $TESTTMP/sub/mercurial/nested_relative
565 555 $ rm -rf mercurial mercurial2
566 556
567 557 Issue1977: multirepo push should fail if subrepo push fails
568 558
569 559 $ hg init repo
570 560 $ hg init repo/s
571 561 $ echo a > repo/s/a
572 562 $ hg -R repo/s ci -Am0
573 563 adding a
574 564 $ echo s = s > repo/.hgsub
575 565 $ hg -R repo ci -Am1
576 566 adding .hgsub
577 committing subrepository s
578 567 $ hg clone repo repo2
579 568 updating to branch default
580 569 cloning subrepo s from $TESTTMP/sub/repo/s (glob)
581 570 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
582 571 $ hg -q -R repo2 pull -u
583 572 [1]
584 573 $ echo 1 > repo2/s/a
585 574 $ hg -R repo2/s ci -m2
586 575 $ hg -q -R repo2/s push
587 576 $ hg -R repo2/s up -C 0
588 577 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
589 578 $ echo 2 > repo2/s/a
590 579 $ hg -R repo2/s ci -m3
591 580 created new head
592 581 $ hg -R repo2 ci -m3
593 committing subrepository s
594 582 $ hg -q -R repo2 push
595 583 abort: push creates new remote head 9d66565e64e1!
596 584 (did you forget to merge? use push -f to force)
597 585 [255]
598 586 $ hg -R repo update
599 587 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
600 588 $ rm -rf repo2 repo
601 589
602 590
603 591 Issue1852 subrepos with relative paths always push/pull relative to default
604 592
605 593 Prepare a repo with subrepo
606 594
607 595 $ hg init issue1852a
608 596 $ cd issue1852a
609 597 $ hg init sub/repo
610 598 $ echo test > sub/repo/foo
611 599 $ hg -R sub/repo add sub/repo/foo
612 600 $ echo sub/repo = sub/repo > .hgsub
613 601 $ hg add .hgsub
614 602 $ hg ci -mtest
615 603 committing subrepository sub/repo (glob)
616 604 $ echo test >> sub/repo/foo
617 605 $ hg ci -mtest
618 606 committing subrepository sub/repo (glob)
619 607 $ cd ..
620 608
621 609 Create repo without default path, pull top repo, and see what happens on update
622 610
623 611 $ hg init issue1852b
624 612 $ hg -R issue1852b pull issue1852a
625 613 pulling from issue1852a
626 614 requesting all changes
627 615 adding changesets
628 616 adding manifests
629 617 adding file changes
630 618 added 2 changesets with 3 changes to 2 files
631 619 (run 'hg update' to get a working copy)
632 620 $ hg -R issue1852b update
633 621 abort: default path for subrepository sub/repo not found (glob)
634 622 [255]
635 623
636 624 Pull -u now doesn't help
637 625
638 626 $ hg -R issue1852b pull -u issue1852a
639 627 pulling from issue1852a
640 628 searching for changes
641 629 no changes found
642 630 [1]
643 631
644 632 Try the same, but with pull -u
645 633
646 634 $ hg init issue1852c
647 635 $ hg -R issue1852c pull -r0 -u issue1852a
648 636 pulling from issue1852a
649 637 adding changesets
650 638 adding manifests
651 639 adding file changes
652 640 added 1 changesets with 2 changes to 2 files
653 641 cloning subrepo sub/repo from issue1852a/sub/repo (glob)
654 642 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
655 643
656 644 Try to push from the other side
657 645
658 646 $ hg -R issue1852a push `pwd`/issue1852c
659 647 pushing to $TESTTMP/sub/issue1852c
660 648 pushing subrepo sub/repo to $TESTTMP/sub/issue1852c/sub/repo (glob)
661 649 searching for changes
662 650 no changes found
663 651 searching for changes
664 652 adding changesets
665 653 adding manifests
666 654 adding file changes
667 655 added 1 changesets with 1 changes to 1 files
668 656
669 657 Incoming and outgoing should not use the default path:
670 658
671 659 $ hg clone -q issue1852a issue1852d
672 660 $ hg -R issue1852d outgoing --subrepos issue1852c
673 661 comparing with issue1852c
674 662 searching for changes
675 663 no changes found
676 664 comparing with issue1852c/sub/repo
677 665 searching for changes
678 666 no changes found
679 667 [1]
680 668 $ hg -R issue1852d incoming --subrepos issue1852c
681 669 comparing with issue1852c
682 670 searching for changes
683 671 no changes found
684 672 comparing with issue1852c/sub/repo
685 673 searching for changes
686 674 no changes found
687 675 [1]
688 676
689 677 Check status of files when none of them belong to the first
690 678 subrepository:
691 679
692 680 $ hg init subrepo-status
693 681 $ cd subrepo-status
694 682 $ hg init subrepo-1
695 683 $ hg init subrepo-2
696 684 $ cd subrepo-2
697 685 $ touch file
698 686 $ hg add file
699 687 $ cd ..
700 688 $ echo subrepo-1 = subrepo-1 > .hgsub
701 689 $ echo subrepo-2 = subrepo-2 >> .hgsub
702 690 $ hg add .hgsub
703 691 $ hg ci -m 'Added subrepos'
704 committing subrepository subrepo-1
705 692 committing subrepository subrepo-2
706 693 $ hg st subrepo-2/file
707 694
708 695 Check hg update --clean
709 696 $ cd $TESTTMP/sub/t
710 697 $ rm -r t/t.orig
711 698 $ hg status -S --all
712 699 C .hgsub
713 700 C .hgsubstate
714 701 C a
715 702 C s/.hgsub
716 703 C s/.hgsubstate
717 704 C s/a
718 705 C s/ss/a
719 706 C t/t
720 707 $ echo c1 > s/a
721 708 $ cd s
722 709 $ echo c1 > b
723 710 $ echo c1 > c
724 711 $ hg add b
725 712 $ cd ..
726 713 $ hg status -S
727 714 M s/a
728 715 A s/b
729 716 ? s/c
730 717 $ hg update -C
731 718 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
732 719 $ hg status -S
733 720 ? s/b
734 721 ? s/c
735 722
736 723 Sticky subrepositories, no changes
737 724 $ cd $TESTTMP/sub/t
738 725 $ hg id
739 726 925c17564ef8 tip
740 727 $ hg -R s id
741 728 12a213df6fa9 tip
742 729 $ hg -R t id
743 730 52c0adc0515a tip
744 731 $ hg update 11
745 732 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
746 733 $ hg id
747 734 365661e5936a
748 735 $ hg -R s id
749 736 fc627a69481f
750 737 $ hg -R t id
751 738 e95bcfa18a35
752 739
753 740 Sticky subrepositorys, file changes
754 741 $ touch s/f1
755 742 $ touch t/f1
756 743 $ hg add -S s/f1
757 744 $ hg add -S t/f1
758 745 $ hg id
759 746 365661e5936a
760 747 $ hg -R s id
761 748 fc627a69481f+
762 749 $ hg -R t id
763 750 e95bcfa18a35+
764 751 $ hg update tip
765 752 subrepository sources for s differ
766 753 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
767 754 l
768 755 subrepository sources for t differ
769 756 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
770 757 l
771 758 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
772 759 $ hg id
773 760 925c17564ef8+ tip
774 761 $ hg -R s id
775 762 fc627a69481f+
776 763 $ hg -R t id
777 764 e95bcfa18a35+
778 765 $ hg update --clean tip
779 766 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
780 767
781 768 Sticky subrepository, revision updates
782 769 $ hg id
783 770 925c17564ef8 tip
784 771 $ hg -R s id
785 772 12a213df6fa9 tip
786 773 $ hg -R t id
787 774 52c0adc0515a tip
788 775 $ cd s
789 776 $ hg update -r -2
790 777 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
791 778 $ cd ../t
792 779 $ hg update -r 2
793 780 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
794 781 $ cd ..
795 782 $ hg update 10
796 783 subrepository sources for t differ (in checked out version)
797 784 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
798 785 l
799 786 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
800 787 $ hg id
801 788 e45c8b14af55+
802 789 $ hg -R s id
803 790 1c833a7a9e3a
804 791 $ hg -R t id
805 792 7af322bc1198
806 793
807 794 Sticky subrepository, file changes and revision updates
808 795 $ touch s/f1
809 796 $ touch t/f1
810 797 $ hg add -S s/f1
811 798 $ hg add -S t/f1
812 799 $ hg id
813 800 e45c8b14af55+
814 801 $ hg -R s id
815 802 1c833a7a9e3a+
816 803 $ hg -R t id
817 804 7af322bc1198+
818 805 $ hg update tip
819 806 subrepository sources for s differ
820 807 use (l)ocal source (1c833a7a9e3a) or (r)emote source (12a213df6fa9)?
821 808 l
822 809 subrepository sources for t differ
823 810 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
824 811 l
825 812 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
826 813 $ hg id
827 814 925c17564ef8 tip
828 815 $ hg -R s id
829 816 1c833a7a9e3a+
830 817 $ hg -R t id
831 818 7af322bc1198+
832 819
833 820 Sticky repository, update --clean
834 821 $ hg update --clean tip
835 822 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
836 823 $ hg id
837 824 925c17564ef8 tip
838 825 $ hg -R s id
839 826 12a213df6fa9 tip
840 827 $ hg -R t id
841 828 52c0adc0515a tip
842 829
843 830 Test subrepo already at intended revision:
844 831 $ cd s
845 832 $ hg update fc627a69481f
846 833 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
847 834 $ cd ..
848 835 $ hg update 11
849 836 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
850 837 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
851 838 $ hg id -n
852 839 11+
853 840 $ hg -R s id
854 841 fc627a69481f
855 842 $ hg -R t id
856 843 e95bcfa18a35
857 844
858 845 Test that removing .hgsubstate doesn't break anything:
859 846
860 847 $ hg rm -f .hgsubstate
861 848 $ hg ci -mrm
862 committing subrepository s
863 committing subrepository t
864 created new head
849 nothing changed
850 [1]
865 851 $ hg log -vr tip
866 changeset: 14:3941e0aa5236
852 changeset: 13:925c17564ef8
867 853 tag: tip
868 parent: 11:365661e5936a
869 854 user: test
870 855 date: Thu Jan 01 00:00:00 1970 +0000
856 files: .hgsubstate
871 857 description:
872 rm
858 13
873 859
874 860
875 861
876 862 Test that removing .hgsub removes .hgsubstate:
877 863
878 864 $ hg rm .hgsub
879 865 $ hg ci -mrm2
866 created new head
880 867 $ hg log -vr tip
881 changeset: 15:8b31de9d13d1
868 changeset: 14:2400bccd50af
882 869 tag: tip
870 parent: 11:365661e5936a
883 871 user: test
884 872 date: Thu Jan 01 00:00:00 1970 +0000
885 873 files: .hgsub .hgsubstate
886 874 description:
887 875 rm2
888 876
889 877
890 878 Test issue3153: diff -S with deleted subrepos
891 879
892 880 $ hg diff --nodates -S -c .
893 diff -r 3941e0aa5236 -r 8b31de9d13d1 .hgsub
881 diff -r 365661e5936a -r 2400bccd50af .hgsub
894 882 --- a/.hgsub
895 883 +++ /dev/null
896 884 @@ -1,2 +0,0 @@
897 885 -s = s
898 886 -t = t
899 diff -r 3941e0aa5236 -r 8b31de9d13d1 .hgsubstate
887 diff -r 365661e5936a -r 2400bccd50af .hgsubstate
900 888 --- a/.hgsubstate
901 889 +++ /dev/null
902 890 @@ -1,2 +0,0 @@
903 891 -fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
904 892 -e95bcfa18a358dc4936da981ebf4147b4cad1362 t
905 893
906 894 Test behavior of add for explicit path in subrepo:
907 895 $ cd ..
908 896 $ hg init explicit
909 897 $ cd explicit
910 898 $ echo s = s > .hgsub
911 899 $ hg add .hgsub
912 900 $ hg init s
913 901 $ hg ci -m0
914 committing subrepository s
915 902 Adding with an explicit path in a subrepo adds the file
916 903 $ echo c1 > f1
917 904 $ echo c2 > s/f2
918 905 $ hg st -S
919 906 ? f1
920 907 ? s/f2
921 908 $ hg add s/f2
922 909 $ hg st -S
923 910 A s/f2
924 911 ? f1
925 912 $ hg ci -R s -m0
926 913 $ hg ci -Am1
927 914 adding f1
928 committing subrepository s
929 915 Adding with an explicit path in a subrepo with -S has the same behavior
930 916 $ echo c3 > f3
931 917 $ echo c4 > s/f4
932 918 $ hg st -S
933 919 ? f3
934 920 ? s/f4
935 921 $ hg add -S s/f4
936 922 $ hg st -S
937 923 A s/f4
938 924 ? f3
939 925 $ hg ci -R s -m1
940 926 $ hg ci -Ama2
941 927 adding f3
942 committing subrepository s
943 928 Adding without a path or pattern silently ignores subrepos
944 929 $ echo c5 > f5
945 930 $ echo c6 > s/f6
946 931 $ echo c7 > s/f7
947 932 $ hg st -S
948 933 ? f5
949 934 ? s/f6
950 935 ? s/f7
951 936 $ hg add
952 937 adding f5
953 938 $ hg st -S
954 939 A f5
955 940 ? s/f6
956 941 ? s/f7
957 942 $ hg ci -R s -Am2
958 943 adding f6
959 944 adding f7
960 945 $ hg ci -m3
961 committing subrepository s
962 946 Adding without a path or pattern with -S also adds files in subrepos
963 947 $ echo c8 > f8
964 948 $ echo c9 > s/f9
965 949 $ echo c10 > s/f10
966 950 $ hg st -S
967 951 ? f8
968 952 ? s/f10
969 953 ? s/f9
970 954 $ hg add -S
971 955 adding f8
972 956 adding s/f10 (glob)
973 957 adding s/f9 (glob)
974 958 $ hg st -S
975 959 A f8
976 960 A s/f10
977 961 A s/f9
978 962 $ hg ci -R s -m3
979 963 $ hg ci -m4
980 committing subrepository s
981 964 Adding with a pattern silently ignores subrepos
982 965 $ echo c11 > fm11
983 966 $ echo c12 > fn12
984 967 $ echo c13 > s/fm13
985 968 $ echo c14 > s/fn14
986 969 $ hg st -S
987 970 ? fm11
988 971 ? fn12
989 972 ? s/fm13
990 973 ? s/fn14
991 974 $ hg add 'glob:**fm*'
992 975 adding fm11
993 976 $ hg st -S
994 977 A fm11
995 978 ? fn12
996 979 ? s/fm13
997 980 ? s/fn14
998 981 $ hg ci -R s -Am4
999 982 adding fm13
1000 983 adding fn14
1001 984 $ hg ci -Am5
1002 985 adding fn12
1003 committing subrepository s
1004 986 Adding with a pattern with -S also adds matches in subrepos
1005 987 $ echo c15 > fm15
1006 988 $ echo c16 > fn16
1007 989 $ echo c17 > s/fm17
1008 990 $ echo c18 > s/fn18
1009 991 $ hg st -S
1010 992 ? fm15
1011 993 ? fn16
1012 994 ? s/fm17
1013 995 ? s/fn18
1014 996 $ hg add -S 'glob:**fm*'
1015 997 adding fm15
1016 998 adding s/fm17 (glob)
1017 999 $ hg st -S
1018 1000 A fm15
1019 1001 A s/fm17
1020 1002 ? fn16
1021 1003 ? s/fn18
1022 1004 $ hg ci -R s -Am5
1023 1005 adding fn18
1024 1006 $ hg ci -Am6
1025 1007 adding fn16
1026 committing subrepository s
1027 1008
1028 1009 Test behavior of forget for explicit path in subrepo:
1029 1010 Forgetting an explicit path in a subrepo untracks the file
1030 1011 $ echo c19 > s/f19
1031 1012 $ hg add s/f19
1032 1013 $ hg st -S
1033 1014 A s/f19
1034 1015 $ hg forget s/f19
1035 1016 $ hg st -S
1036 1017 ? s/f19
1037 1018 $ rm s/f19
General Comments 0
You need to be logged in to leave comments. Login now