##// END OF EJS Templates
scmutil: consistently return subrepos relative to ctx1 from itersubrepos()...
Matt Harbison -
r25418:c0995cd8 default
parent child Browse files
Show More
@@ -1,1147 +1,1162 b''
1 1 # scmutil.py - Mercurial core utility functions
2 2 #
3 3 # Copyright 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 i18n import _
9 9 from mercurial.node import nullrev
10 10 import util, error, osutil, revset, similar, encoding, phases
11 11 import pathutil
12 12 import match as matchmod
13 13 import os, errno, re, glob, tempfile, shutil, stat, inspect
14 14
15 15 if os.name == 'nt':
16 16 import scmwindows as scmplatform
17 17 else:
18 18 import scmposix as scmplatform
19 19
20 20 systemrcpath = scmplatform.systemrcpath
21 21 userrcpath = scmplatform.userrcpath
22 22
23 23 class status(tuple):
24 24 '''Named tuple with a list of files per status. The 'deleted', 'unknown'
25 25 and 'ignored' properties are only relevant to the working copy.
26 26 '''
27 27
28 28 __slots__ = ()
29 29
30 30 def __new__(cls, modified, added, removed, deleted, unknown, ignored,
31 31 clean):
32 32 return tuple.__new__(cls, (modified, added, removed, deleted, unknown,
33 33 ignored, clean))
34 34
35 35 @property
36 36 def modified(self):
37 37 '''files that have been modified'''
38 38 return self[0]
39 39
40 40 @property
41 41 def added(self):
42 42 '''files that have been added'''
43 43 return self[1]
44 44
45 45 @property
46 46 def removed(self):
47 47 '''files that have been removed'''
48 48 return self[2]
49 49
50 50 @property
51 51 def deleted(self):
52 52 '''files that are in the dirstate, but have been deleted from the
53 53 working copy (aka "missing")
54 54 '''
55 55 return self[3]
56 56
57 57 @property
58 58 def unknown(self):
59 59 '''files not in the dirstate that are not ignored'''
60 60 return self[4]
61 61
62 62 @property
63 63 def ignored(self):
64 64 '''files not in the dirstate that are ignored (by _dirignore())'''
65 65 return self[5]
66 66
67 67 @property
68 68 def clean(self):
69 69 '''files that have not been modified'''
70 70 return self[6]
71 71
72 72 def __repr__(self, *args, **kwargs):
73 73 return (('<status modified=%r, added=%r, removed=%r, deleted=%r, '
74 74 'unknown=%r, ignored=%r, clean=%r>') % self)
75 75
76 76 def itersubrepos(ctx1, ctx2):
77 77 """find subrepos in ctx1 or ctx2"""
78 78 # Create a (subpath, ctx) mapping where we prefer subpaths from
79 79 # ctx1. The subpaths from ctx2 are important when the .hgsub file
80 80 # has been modified (in ctx2) but not yet committed (in ctx1).
81 81 subpaths = dict.fromkeys(ctx2.substate, ctx2)
82 82 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
83
84 missing = set()
85
86 for subpath in ctx2.substate:
87 if subpath not in ctx1.substate:
88 del subpaths[subpath]
89 missing.add(subpath)
90
83 91 for subpath, ctx in sorted(subpaths.iteritems()):
84 92 yield subpath, ctx.sub(subpath)
85 93
94 # Yield an empty subrepo based on ctx1 for anything only in ctx2. That way,
95 # status and diff will have an accurate result when it does
96 # 'sub.{status|diff}(rev2)'. Otherwise, the ctx2 subrepo is compared
97 # against itself.
98 for subpath in missing:
99 yield subpath, ctx2.nullsub(subpath, ctx1)
100
86 101 def nochangesfound(ui, repo, excluded=None):
87 102 '''Report no changes for push/pull, excluded is None or a list of
88 103 nodes excluded from the push/pull.
89 104 '''
90 105 secretlist = []
91 106 if excluded:
92 107 for n in excluded:
93 108 if n not in repo:
94 109 # discovery should not have included the filtered revision,
95 110 # we have to explicitly exclude it until discovery is cleanup.
96 111 continue
97 112 ctx = repo[n]
98 113 if ctx.phase() >= phases.secret and not ctx.extinct():
99 114 secretlist.append(n)
100 115
101 116 if secretlist:
102 117 ui.status(_("no changes found (ignored %d secret changesets)\n")
103 118 % len(secretlist))
104 119 else:
105 120 ui.status(_("no changes found\n"))
106 121
107 122 def checknewlabel(repo, lbl, kind):
108 123 # Do not use the "kind" parameter in ui output.
109 124 # It makes strings difficult to translate.
110 125 if lbl in ['tip', '.', 'null']:
111 126 raise util.Abort(_("the name '%s' is reserved") % lbl)
112 127 for c in (':', '\0', '\n', '\r'):
113 128 if c in lbl:
114 129 raise util.Abort(_("%r cannot be used in a name") % c)
115 130 try:
116 131 int(lbl)
117 132 raise util.Abort(_("cannot use an integer as a name"))
118 133 except ValueError:
119 134 pass
120 135
121 136 def checkfilename(f):
122 137 '''Check that the filename f is an acceptable filename for a tracked file'''
123 138 if '\r' in f or '\n' in f:
124 139 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames: %r") % f)
125 140
126 141 def checkportable(ui, f):
127 142 '''Check if filename f is portable and warn or abort depending on config'''
128 143 checkfilename(f)
129 144 abort, warn = checkportabilityalert(ui)
130 145 if abort or warn:
131 146 msg = util.checkwinfilename(f)
132 147 if msg:
133 148 msg = "%s: %r" % (msg, f)
134 149 if abort:
135 150 raise util.Abort(msg)
136 151 ui.warn(_("warning: %s\n") % msg)
137 152
138 153 def checkportabilityalert(ui):
139 154 '''check if the user's config requests nothing, a warning, or abort for
140 155 non-portable filenames'''
141 156 val = ui.config('ui', 'portablefilenames', 'warn')
142 157 lval = val.lower()
143 158 bval = util.parsebool(val)
144 159 abort = os.name == 'nt' or lval == 'abort'
145 160 warn = bval or lval == 'warn'
146 161 if bval is None and not (warn or abort or lval == 'ignore'):
147 162 raise error.ConfigError(
148 163 _("ui.portablefilenames value is invalid ('%s')") % val)
149 164 return abort, warn
150 165
151 166 class casecollisionauditor(object):
152 167 def __init__(self, ui, abort, dirstate):
153 168 self._ui = ui
154 169 self._abort = abort
155 170 allfiles = '\0'.join(dirstate._map)
156 171 self._loweredfiles = set(encoding.lower(allfiles).split('\0'))
157 172 self._dirstate = dirstate
158 173 # The purpose of _newfiles is so that we don't complain about
159 174 # case collisions if someone were to call this object with the
160 175 # same filename twice.
161 176 self._newfiles = set()
162 177
163 178 def __call__(self, f):
164 179 if f in self._newfiles:
165 180 return
166 181 fl = encoding.lower(f)
167 182 if fl in self._loweredfiles and f not in self._dirstate:
168 183 msg = _('possible case-folding collision for %s') % f
169 184 if self._abort:
170 185 raise util.Abort(msg)
171 186 self._ui.warn(_("warning: %s\n") % msg)
172 187 self._loweredfiles.add(fl)
173 188 self._newfiles.add(f)
174 189
175 190 def develwarn(tui, msg):
176 191 """issue a developer warning message"""
177 192 msg = 'devel-warn: ' + msg
178 193 if tui.tracebackflag:
179 194 util.debugstacktrace(msg, 2)
180 195 else:
181 196 curframe = inspect.currentframe()
182 197 calframe = inspect.getouterframes(curframe, 2)
183 198 tui.write_err('%s at: %s:%s (%s)\n' % ((msg,) + calframe[2][1:4]))
184 199
185 200 def filteredhash(repo, maxrev):
186 201 """build hash of filtered revisions in the current repoview.
187 202
188 203 Multiple caches perform up-to-date validation by checking that the
189 204 tiprev and tipnode stored in the cache file match the current repository.
190 205 However, this is not sufficient for validating repoviews because the set
191 206 of revisions in the view may change without the repository tiprev and
192 207 tipnode changing.
193 208
194 209 This function hashes all the revs filtered from the view and returns
195 210 that SHA-1 digest.
196 211 """
197 212 cl = repo.changelog
198 213 if not cl.filteredrevs:
199 214 return None
200 215 key = None
201 216 revs = sorted(r for r in cl.filteredrevs if r <= maxrev)
202 217 if revs:
203 218 s = util.sha1()
204 219 for rev in revs:
205 220 s.update('%s;' % rev)
206 221 key = s.digest()
207 222 return key
208 223
209 224 class abstractvfs(object):
210 225 """Abstract base class; cannot be instantiated"""
211 226
212 227 def __init__(self, *args, **kwargs):
213 228 '''Prevent instantiation; don't call this from subclasses.'''
214 229 raise NotImplementedError('attempted instantiating ' + str(type(self)))
215 230
216 231 def tryread(self, path):
217 232 '''gracefully return an empty string for missing files'''
218 233 try:
219 234 return self.read(path)
220 235 except IOError, inst:
221 236 if inst.errno != errno.ENOENT:
222 237 raise
223 238 return ""
224 239
225 240 def tryreadlines(self, path, mode='rb'):
226 241 '''gracefully return an empty array for missing files'''
227 242 try:
228 243 return self.readlines(path, mode=mode)
229 244 except IOError, inst:
230 245 if inst.errno != errno.ENOENT:
231 246 raise
232 247 return []
233 248
234 249 def open(self, path, mode="r", text=False, atomictemp=False,
235 250 notindexed=False):
236 251 '''Open ``path`` file, which is relative to vfs root.
237 252
238 253 Newly created directories are marked as "not to be indexed by
239 254 the content indexing service", if ``notindexed`` is specified
240 255 for "write" mode access.
241 256 '''
242 257 self.open = self.__call__
243 258 return self.__call__(path, mode, text, atomictemp, notindexed)
244 259
245 260 def read(self, path):
246 261 fp = self(path, 'rb')
247 262 try:
248 263 return fp.read()
249 264 finally:
250 265 fp.close()
251 266
252 267 def readlines(self, path, mode='rb'):
253 268 fp = self(path, mode=mode)
254 269 try:
255 270 return fp.readlines()
256 271 finally:
257 272 fp.close()
258 273
259 274 def write(self, path, data):
260 275 fp = self(path, 'wb')
261 276 try:
262 277 return fp.write(data)
263 278 finally:
264 279 fp.close()
265 280
266 281 def writelines(self, path, data, mode='wb', notindexed=False):
267 282 fp = self(path, mode=mode, notindexed=notindexed)
268 283 try:
269 284 return fp.writelines(data)
270 285 finally:
271 286 fp.close()
272 287
273 288 def append(self, path, data):
274 289 fp = self(path, 'ab')
275 290 try:
276 291 return fp.write(data)
277 292 finally:
278 293 fp.close()
279 294
280 295 def chmod(self, path, mode):
281 296 return os.chmod(self.join(path), mode)
282 297
283 298 def exists(self, path=None):
284 299 return os.path.exists(self.join(path))
285 300
286 301 def fstat(self, fp):
287 302 return util.fstat(fp)
288 303
289 304 def isdir(self, path=None):
290 305 return os.path.isdir(self.join(path))
291 306
292 307 def isfile(self, path=None):
293 308 return os.path.isfile(self.join(path))
294 309
295 310 def islink(self, path=None):
296 311 return os.path.islink(self.join(path))
297 312
298 313 def reljoin(self, *paths):
299 314 """join various elements of a path together (as os.path.join would do)
300 315
301 316 The vfs base is not injected so that path stay relative. This exists
302 317 to allow handling of strange encoding if needed."""
303 318 return os.path.join(*paths)
304 319
305 320 def split(self, path):
306 321 """split top-most element of a path (as os.path.split would do)
307 322
308 323 This exists to allow handling of strange encoding if needed."""
309 324 return os.path.split(path)
310 325
311 326 def lexists(self, path=None):
312 327 return os.path.lexists(self.join(path))
313 328
314 329 def lstat(self, path=None):
315 330 return os.lstat(self.join(path))
316 331
317 332 def listdir(self, path=None):
318 333 return os.listdir(self.join(path))
319 334
320 335 def makedir(self, path=None, notindexed=True):
321 336 return util.makedir(self.join(path), notindexed)
322 337
323 338 def makedirs(self, path=None, mode=None):
324 339 return util.makedirs(self.join(path), mode)
325 340
326 341 def makelock(self, info, path):
327 342 return util.makelock(info, self.join(path))
328 343
329 344 def mkdir(self, path=None):
330 345 return os.mkdir(self.join(path))
331 346
332 347 def mkstemp(self, suffix='', prefix='tmp', dir=None, text=False):
333 348 fd, name = tempfile.mkstemp(suffix=suffix, prefix=prefix,
334 349 dir=self.join(dir), text=text)
335 350 dname, fname = util.split(name)
336 351 if dir:
337 352 return fd, os.path.join(dir, fname)
338 353 else:
339 354 return fd, fname
340 355
341 356 def readdir(self, path=None, stat=None, skip=None):
342 357 return osutil.listdir(self.join(path), stat, skip)
343 358
344 359 def readlock(self, path):
345 360 return util.readlock(self.join(path))
346 361
347 362 def rename(self, src, dst):
348 363 return util.rename(self.join(src), self.join(dst))
349 364
350 365 def readlink(self, path):
351 366 return os.readlink(self.join(path))
352 367
353 368 def removedirs(self, path=None):
354 369 """Remove a leaf directory and all empty intermediate ones
355 370 """
356 371 return util.removedirs(self.join(path))
357 372
358 373 def rmtree(self, path=None, ignore_errors=False, forcibly=False):
359 374 """Remove a directory tree recursively
360 375
361 376 If ``forcibly``, this tries to remove READ-ONLY files, too.
362 377 """
363 378 if forcibly:
364 379 def onerror(function, path, excinfo):
365 380 if function is not os.remove:
366 381 raise
367 382 # read-only files cannot be unlinked under Windows
368 383 s = os.stat(path)
369 384 if (s.st_mode & stat.S_IWRITE) != 0:
370 385 raise
371 386 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
372 387 os.remove(path)
373 388 else:
374 389 onerror = None
375 390 return shutil.rmtree(self.join(path),
376 391 ignore_errors=ignore_errors, onerror=onerror)
377 392
378 393 def setflags(self, path, l, x):
379 394 return util.setflags(self.join(path), l, x)
380 395
381 396 def stat(self, path=None):
382 397 return os.stat(self.join(path))
383 398
384 399 def unlink(self, path=None):
385 400 return util.unlink(self.join(path))
386 401
387 402 def unlinkpath(self, path=None, ignoremissing=False):
388 403 return util.unlinkpath(self.join(path), ignoremissing)
389 404
390 405 def utime(self, path=None, t=None):
391 406 return os.utime(self.join(path), t)
392 407
393 408 def walk(self, path=None, onerror=None):
394 409 """Yield (dirpath, dirs, files) tuple for each directories under path
395 410
396 411 ``dirpath`` is relative one from the root of this vfs. This
397 412 uses ``os.sep`` as path separator, even you specify POSIX
398 413 style ``path``.
399 414
400 415 "The root of this vfs" is represented as empty ``dirpath``.
401 416 """
402 417 root = os.path.normpath(self.join(None))
403 418 # when dirpath == root, dirpath[prefixlen:] becomes empty
404 419 # because len(dirpath) < prefixlen.
405 420 prefixlen = len(pathutil.normasprefix(root))
406 421 for dirpath, dirs, files in os.walk(self.join(path), onerror=onerror):
407 422 yield (dirpath[prefixlen:], dirs, files)
408 423
409 424 class vfs(abstractvfs):
410 425 '''Operate files relative to a base directory
411 426
412 427 This class is used to hide the details of COW semantics and
413 428 remote file access from higher level code.
414 429 '''
415 430 def __init__(self, base, audit=True, expandpath=False, realpath=False):
416 431 if expandpath:
417 432 base = util.expandpath(base)
418 433 if realpath:
419 434 base = os.path.realpath(base)
420 435 self.base = base
421 436 self._setmustaudit(audit)
422 437 self.createmode = None
423 438 self._trustnlink = None
424 439
425 440 def _getmustaudit(self):
426 441 return self._audit
427 442
428 443 def _setmustaudit(self, onoff):
429 444 self._audit = onoff
430 445 if onoff:
431 446 self.audit = pathutil.pathauditor(self.base)
432 447 else:
433 448 self.audit = util.always
434 449
435 450 mustaudit = property(_getmustaudit, _setmustaudit)
436 451
437 452 @util.propertycache
438 453 def _cansymlink(self):
439 454 return util.checklink(self.base)
440 455
441 456 @util.propertycache
442 457 def _chmod(self):
443 458 return util.checkexec(self.base)
444 459
445 460 def _fixfilemode(self, name):
446 461 if self.createmode is None or not self._chmod:
447 462 return
448 463 os.chmod(name, self.createmode & 0666)
449 464
450 465 def __call__(self, path, mode="r", text=False, atomictemp=False,
451 466 notindexed=False):
452 467 '''Open ``path`` file, which is relative to vfs root.
453 468
454 469 Newly created directories are marked as "not to be indexed by
455 470 the content indexing service", if ``notindexed`` is specified
456 471 for "write" mode access.
457 472 '''
458 473 if self._audit:
459 474 r = util.checkosfilename(path)
460 475 if r:
461 476 raise util.Abort("%s: %r" % (r, path))
462 477 self.audit(path)
463 478 f = self.join(path)
464 479
465 480 if not text and "b" not in mode:
466 481 mode += "b" # for that other OS
467 482
468 483 nlink = -1
469 484 if mode not in ('r', 'rb'):
470 485 dirname, basename = util.split(f)
471 486 # If basename is empty, then the path is malformed because it points
472 487 # to a directory. Let the posixfile() call below raise IOError.
473 488 if basename:
474 489 if atomictemp:
475 490 util.ensuredirs(dirname, self.createmode, notindexed)
476 491 return util.atomictempfile(f, mode, self.createmode)
477 492 try:
478 493 if 'w' in mode:
479 494 util.unlink(f)
480 495 nlink = 0
481 496 else:
482 497 # nlinks() may behave differently for files on Windows
483 498 # shares if the file is open.
484 499 fd = util.posixfile(f)
485 500 nlink = util.nlinks(f)
486 501 if nlink < 1:
487 502 nlink = 2 # force mktempcopy (issue1922)
488 503 fd.close()
489 504 except (OSError, IOError), e:
490 505 if e.errno != errno.ENOENT:
491 506 raise
492 507 nlink = 0
493 508 util.ensuredirs(dirname, self.createmode, notindexed)
494 509 if nlink > 0:
495 510 if self._trustnlink is None:
496 511 self._trustnlink = nlink > 1 or util.checknlink(f)
497 512 if nlink > 1 or not self._trustnlink:
498 513 util.rename(util.mktempcopy(f), f)
499 514 fp = util.posixfile(f, mode)
500 515 if nlink == 0:
501 516 self._fixfilemode(f)
502 517 return fp
503 518
504 519 def symlink(self, src, dst):
505 520 self.audit(dst)
506 521 linkname = self.join(dst)
507 522 try:
508 523 os.unlink(linkname)
509 524 except OSError:
510 525 pass
511 526
512 527 util.ensuredirs(os.path.dirname(linkname), self.createmode)
513 528
514 529 if self._cansymlink:
515 530 try:
516 531 os.symlink(src, linkname)
517 532 except OSError, err:
518 533 raise OSError(err.errno, _('could not symlink to %r: %s') %
519 534 (src, err.strerror), linkname)
520 535 else:
521 536 self.write(dst, src)
522 537
523 538 def join(self, path, *insidef):
524 539 if path:
525 540 return os.path.join(self.base, path, *insidef)
526 541 else:
527 542 return self.base
528 543
529 544 opener = vfs
530 545
531 546 class auditvfs(object):
532 547 def __init__(self, vfs):
533 548 self.vfs = vfs
534 549
535 550 def _getmustaudit(self):
536 551 return self.vfs.mustaudit
537 552
538 553 def _setmustaudit(self, onoff):
539 554 self.vfs.mustaudit = onoff
540 555
541 556 mustaudit = property(_getmustaudit, _setmustaudit)
542 557
543 558 class filtervfs(abstractvfs, auditvfs):
544 559 '''Wrapper vfs for filtering filenames with a function.'''
545 560
546 561 def __init__(self, vfs, filter):
547 562 auditvfs.__init__(self, vfs)
548 563 self._filter = filter
549 564
550 565 def __call__(self, path, *args, **kwargs):
551 566 return self.vfs(self._filter(path), *args, **kwargs)
552 567
553 568 def join(self, path, *insidef):
554 569 if path:
555 570 return self.vfs.join(self._filter(self.vfs.reljoin(path, *insidef)))
556 571 else:
557 572 return self.vfs.join(path)
558 573
559 574 filteropener = filtervfs
560 575
561 576 class readonlyvfs(abstractvfs, auditvfs):
562 577 '''Wrapper vfs preventing any writing.'''
563 578
564 579 def __init__(self, vfs):
565 580 auditvfs.__init__(self, vfs)
566 581
567 582 def __call__(self, path, mode='r', *args, **kw):
568 583 if mode not in ('r', 'rb'):
569 584 raise util.Abort('this vfs is read only')
570 585 return self.vfs(path, mode, *args, **kw)
571 586
572 587
573 588 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
574 589 '''yield every hg repository under path, always recursively.
575 590 The recurse flag will only control recursion into repo working dirs'''
576 591 def errhandler(err):
577 592 if err.filename == path:
578 593 raise err
579 594 samestat = getattr(os.path, 'samestat', None)
580 595 if followsym and samestat is not None:
581 596 def adddir(dirlst, dirname):
582 597 match = False
583 598 dirstat = os.stat(dirname)
584 599 for lstdirstat in dirlst:
585 600 if samestat(dirstat, lstdirstat):
586 601 match = True
587 602 break
588 603 if not match:
589 604 dirlst.append(dirstat)
590 605 return not match
591 606 else:
592 607 followsym = False
593 608
594 609 if (seen_dirs is None) and followsym:
595 610 seen_dirs = []
596 611 adddir(seen_dirs, path)
597 612 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
598 613 dirs.sort()
599 614 if '.hg' in dirs:
600 615 yield root # found a repository
601 616 qroot = os.path.join(root, '.hg', 'patches')
602 617 if os.path.isdir(os.path.join(qroot, '.hg')):
603 618 yield qroot # we have a patch queue repo here
604 619 if recurse:
605 620 # avoid recursing inside the .hg directory
606 621 dirs.remove('.hg')
607 622 else:
608 623 dirs[:] = [] # don't descend further
609 624 elif followsym:
610 625 newdirs = []
611 626 for d in dirs:
612 627 fname = os.path.join(root, d)
613 628 if adddir(seen_dirs, fname):
614 629 if os.path.islink(fname):
615 630 for hgname in walkrepos(fname, True, seen_dirs):
616 631 yield hgname
617 632 else:
618 633 newdirs.append(d)
619 634 dirs[:] = newdirs
620 635
621 636 def osrcpath():
622 637 '''return default os-specific hgrc search path'''
623 638 path = []
624 639 defaultpath = os.path.join(util.datapath, 'default.d')
625 640 if os.path.isdir(defaultpath):
626 641 for f, kind in osutil.listdir(defaultpath):
627 642 if f.endswith('.rc'):
628 643 path.append(os.path.join(defaultpath, f))
629 644 path.extend(systemrcpath())
630 645 path.extend(userrcpath())
631 646 path = [os.path.normpath(f) for f in path]
632 647 return path
633 648
634 649 _rcpath = None
635 650
636 651 def rcpath():
637 652 '''return hgrc search path. if env var HGRCPATH is set, use it.
638 653 for each item in path, if directory, use files ending in .rc,
639 654 else use item.
640 655 make HGRCPATH empty to only look in .hg/hgrc of current repo.
641 656 if no HGRCPATH, use default os-specific path.'''
642 657 global _rcpath
643 658 if _rcpath is None:
644 659 if 'HGRCPATH' in os.environ:
645 660 _rcpath = []
646 661 for p in os.environ['HGRCPATH'].split(os.pathsep):
647 662 if not p:
648 663 continue
649 664 p = util.expandpath(p)
650 665 if os.path.isdir(p):
651 666 for f, kind in osutil.listdir(p):
652 667 if f.endswith('.rc'):
653 668 _rcpath.append(os.path.join(p, f))
654 669 else:
655 670 _rcpath.append(p)
656 671 else:
657 672 _rcpath = osrcpath()
658 673 return _rcpath
659 674
660 675 def intrev(repo, rev):
661 676 """Return integer for a given revision that can be used in comparison or
662 677 arithmetic operation"""
663 678 if rev is None:
664 679 return len(repo)
665 680 return rev
666 681
667 682 def revsingle(repo, revspec, default='.'):
668 683 if not revspec and revspec != 0:
669 684 return repo[default]
670 685
671 686 l = revrange(repo, [revspec])
672 687 if not l:
673 688 raise util.Abort(_('empty revision set'))
674 689 return repo[l.last()]
675 690
676 691 def revpair(repo, revs):
677 692 if not revs:
678 693 return repo.dirstate.p1(), None
679 694
680 695 l = revrange(repo, revs)
681 696
682 697 if not l:
683 698 first = second = None
684 699 elif l.isascending():
685 700 first = l.min()
686 701 second = l.max()
687 702 elif l.isdescending():
688 703 first = l.max()
689 704 second = l.min()
690 705 else:
691 706 first = l.first()
692 707 second = l.last()
693 708
694 709 if first is None:
695 710 raise util.Abort(_('empty revision range'))
696 711
697 712 if first == second and len(revs) == 1 and _revrangesep not in revs[0]:
698 713 return repo.lookup(first), None
699 714
700 715 return repo.lookup(first), repo.lookup(second)
701 716
702 717 _revrangesep = ':'
703 718
704 719 def revrange(repo, revs):
705 720 """Yield revision as strings from a list of revision specifications."""
706 721
707 722 def revfix(repo, val, defval):
708 723 if not val and val != 0 and defval is not None:
709 724 return defval
710 725 return repo[val].rev()
711 726
712 727 subsets = []
713 728
714 729 revsetaliases = [alias for (alias, _) in
715 730 repo.ui.configitems("revsetalias")]
716 731
717 732 for spec in revs:
718 733 # attempt to parse old-style ranges first to deal with
719 734 # things like old-tag which contain query metacharacters
720 735 try:
721 736 # ... except for revset aliases without arguments. These
722 737 # should be parsed as soon as possible, because they might
723 738 # clash with a hash prefix.
724 739 if spec in revsetaliases:
725 740 raise error.RepoLookupError
726 741
727 742 if isinstance(spec, int):
728 743 subsets.append(revset.baseset([spec]))
729 744 continue
730 745
731 746 if _revrangesep in spec:
732 747 start, end = spec.split(_revrangesep, 1)
733 748 if start in revsetaliases or end in revsetaliases:
734 749 raise error.RepoLookupError
735 750
736 751 start = revfix(repo, start, 0)
737 752 end = revfix(repo, end, len(repo) - 1)
738 753 if end == nullrev and start < 0:
739 754 start = nullrev
740 755 if start < end:
741 756 l = revset.spanset(repo, start, end + 1)
742 757 else:
743 758 l = revset.spanset(repo, start, end - 1)
744 759 subsets.append(l)
745 760 continue
746 761 elif spec and spec in repo: # single unquoted rev
747 762 rev = revfix(repo, spec, None)
748 763 subsets.append(revset.baseset([rev]))
749 764 continue
750 765 except error.RepoLookupError:
751 766 pass
752 767
753 768 # fall through to new-style queries if old-style fails
754 769 m = revset.match(repo.ui, spec, repo)
755 770 subsets.append(m(repo))
756 771
757 772 return revset._combinesets(subsets)
758 773
759 774 def expandpats(pats):
760 775 '''Expand bare globs when running on windows.
761 776 On posix we assume it already has already been done by sh.'''
762 777 if not util.expandglobs:
763 778 return list(pats)
764 779 ret = []
765 780 for kindpat in pats:
766 781 kind, pat = matchmod._patsplit(kindpat, None)
767 782 if kind is None:
768 783 try:
769 784 globbed = glob.glob(pat)
770 785 except re.error:
771 786 globbed = [pat]
772 787 if globbed:
773 788 ret.extend(globbed)
774 789 continue
775 790 ret.append(kindpat)
776 791 return ret
777 792
778 793 def matchandpats(ctx, pats=[], opts={}, globbed=False, default='relpath'):
779 794 '''Return a matcher and the patterns that were used.
780 795 The matcher will warn about bad matches.'''
781 796 if pats == ("",):
782 797 pats = []
783 798 if not globbed and default == 'relpath':
784 799 pats = expandpats(pats or [])
785 800
786 801 m = ctx.match(pats, opts.get('include'), opts.get('exclude'),
787 802 default, listsubrepos=opts.get('subrepos'))
788 803 def badfn(f, msg):
789 804 ctx.repo().ui.warn("%s: %s\n" % (m.rel(f), msg))
790 805 m.bad = badfn
791 806 if m.always():
792 807 pats = []
793 808 return m, pats
794 809
795 810 def match(ctx, pats=[], opts={}, globbed=False, default='relpath'):
796 811 '''Return a matcher that will warn about bad matches.'''
797 812 return matchandpats(ctx, pats, opts, globbed, default)[0]
798 813
799 814 def matchall(repo):
800 815 '''Return a matcher that will efficiently match everything.'''
801 816 return matchmod.always(repo.root, repo.getcwd())
802 817
803 818 def matchfiles(repo, files):
804 819 '''Return a matcher that will efficiently match exactly these files.'''
805 820 return matchmod.exact(repo.root, repo.getcwd(), files)
806 821
807 822 def addremove(repo, matcher, prefix, opts={}, dry_run=None, similarity=None):
808 823 m = matcher
809 824 if dry_run is None:
810 825 dry_run = opts.get('dry_run')
811 826 if similarity is None:
812 827 similarity = float(opts.get('similarity') or 0)
813 828
814 829 ret = 0
815 830 join = lambda f: os.path.join(prefix, f)
816 831
817 832 def matchessubrepo(matcher, subpath):
818 833 if matcher.exact(subpath):
819 834 return True
820 835 for f in matcher.files():
821 836 if f.startswith(subpath):
822 837 return True
823 838 return False
824 839
825 840 wctx = repo[None]
826 841 for subpath in sorted(wctx.substate):
827 842 if opts.get('subrepos') or matchessubrepo(m, subpath):
828 843 sub = wctx.sub(subpath)
829 844 try:
830 845 submatch = matchmod.narrowmatcher(subpath, m)
831 846 if sub.addremove(submatch, prefix, opts, dry_run, similarity):
832 847 ret = 1
833 848 except error.LookupError:
834 849 repo.ui.status(_("skipping missing subrepository: %s\n")
835 850 % join(subpath))
836 851
837 852 rejected = []
838 853 origbad = m.bad
839 854 def badfn(f, msg):
840 855 if f in m.files():
841 856 origbad(f, msg)
842 857 rejected.append(f)
843 858
844 859 m.bad = badfn
845 860 added, unknown, deleted, removed, forgotten = _interestingfiles(repo, m)
846 861 m.bad = origbad
847 862
848 863 unknownset = set(unknown + forgotten)
849 864 toprint = unknownset.copy()
850 865 toprint.update(deleted)
851 866 for abs in sorted(toprint):
852 867 if repo.ui.verbose or not m.exact(abs):
853 868 if abs in unknownset:
854 869 status = _('adding %s\n') % m.uipath(abs)
855 870 else:
856 871 status = _('removing %s\n') % m.uipath(abs)
857 872 repo.ui.status(status)
858 873
859 874 renames = _findrenames(repo, m, added + unknown, removed + deleted,
860 875 similarity)
861 876
862 877 if not dry_run:
863 878 _markchanges(repo, unknown + forgotten, deleted, renames)
864 879
865 880 for f in rejected:
866 881 if f in m.files():
867 882 return 1
868 883 return ret
869 884
870 885 def marktouched(repo, files, similarity=0.0):
871 886 '''Assert that files have somehow been operated upon. files are relative to
872 887 the repo root.'''
873 888 m = matchfiles(repo, files)
874 889 rejected = []
875 890 m.bad = lambda x, y: rejected.append(x)
876 891
877 892 added, unknown, deleted, removed, forgotten = _interestingfiles(repo, m)
878 893
879 894 if repo.ui.verbose:
880 895 unknownset = set(unknown + forgotten)
881 896 toprint = unknownset.copy()
882 897 toprint.update(deleted)
883 898 for abs in sorted(toprint):
884 899 if abs in unknownset:
885 900 status = _('adding %s\n') % abs
886 901 else:
887 902 status = _('removing %s\n') % abs
888 903 repo.ui.status(status)
889 904
890 905 renames = _findrenames(repo, m, added + unknown, removed + deleted,
891 906 similarity)
892 907
893 908 _markchanges(repo, unknown + forgotten, deleted, renames)
894 909
895 910 for f in rejected:
896 911 if f in m.files():
897 912 return 1
898 913 return 0
899 914
900 915 def _interestingfiles(repo, matcher):
901 916 '''Walk dirstate with matcher, looking for files that addremove would care
902 917 about.
903 918
904 919 This is different from dirstate.status because it doesn't care about
905 920 whether files are modified or clean.'''
906 921 added, unknown, deleted, removed, forgotten = [], [], [], [], []
907 922 audit_path = pathutil.pathauditor(repo.root)
908 923
909 924 ctx = repo[None]
910 925 dirstate = repo.dirstate
911 926 walkresults = dirstate.walk(matcher, sorted(ctx.substate), True, False,
912 927 full=False)
913 928 for abs, st in walkresults.iteritems():
914 929 dstate = dirstate[abs]
915 930 if dstate == '?' and audit_path.check(abs):
916 931 unknown.append(abs)
917 932 elif dstate != 'r' and not st:
918 933 deleted.append(abs)
919 934 elif dstate == 'r' and st:
920 935 forgotten.append(abs)
921 936 # for finding renames
922 937 elif dstate == 'r' and not st:
923 938 removed.append(abs)
924 939 elif dstate == 'a':
925 940 added.append(abs)
926 941
927 942 return added, unknown, deleted, removed, forgotten
928 943
929 944 def _findrenames(repo, matcher, added, removed, similarity):
930 945 '''Find renames from removed files to added ones.'''
931 946 renames = {}
932 947 if similarity > 0:
933 948 for old, new, score in similar.findrenames(repo, added, removed,
934 949 similarity):
935 950 if (repo.ui.verbose or not matcher.exact(old)
936 951 or not matcher.exact(new)):
937 952 repo.ui.status(_('recording removal of %s as rename to %s '
938 953 '(%d%% similar)\n') %
939 954 (matcher.rel(old), matcher.rel(new),
940 955 score * 100))
941 956 renames[new] = old
942 957 return renames
943 958
944 959 def _markchanges(repo, unknown, deleted, renames):
945 960 '''Marks the files in unknown as added, the files in deleted as removed,
946 961 and the files in renames as copied.'''
947 962 wctx = repo[None]
948 963 wlock = repo.wlock()
949 964 try:
950 965 wctx.forget(deleted)
951 966 wctx.add(unknown)
952 967 for new, old in renames.iteritems():
953 968 wctx.copy(old, new)
954 969 finally:
955 970 wlock.release()
956 971
957 972 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
958 973 """Update the dirstate to reflect the intent of copying src to dst. For
959 974 different reasons it might not end with dst being marked as copied from src.
960 975 """
961 976 origsrc = repo.dirstate.copied(src) or src
962 977 if dst == origsrc: # copying back a copy?
963 978 if repo.dirstate[dst] not in 'mn' and not dryrun:
964 979 repo.dirstate.normallookup(dst)
965 980 else:
966 981 if repo.dirstate[origsrc] == 'a' and origsrc == src:
967 982 if not ui.quiet:
968 983 ui.warn(_("%s has not been committed yet, so no copy "
969 984 "data will be stored for %s.\n")
970 985 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd)))
971 986 if repo.dirstate[dst] in '?r' and not dryrun:
972 987 wctx.add([dst])
973 988 elif not dryrun:
974 989 wctx.copy(origsrc, dst)
975 990
976 991 def readrequires(opener, supported):
977 992 '''Reads and parses .hg/requires and checks if all entries found
978 993 are in the list of supported features.'''
979 994 requirements = set(opener.read("requires").splitlines())
980 995 missings = []
981 996 for r in requirements:
982 997 if r not in supported:
983 998 if not r or not r[0].isalnum():
984 999 raise error.RequirementError(_(".hg/requires file is corrupt"))
985 1000 missings.append(r)
986 1001 missings.sort()
987 1002 if missings:
988 1003 raise error.RequirementError(
989 1004 _("repository requires features unknown to this Mercurial: %s")
990 1005 % " ".join(missings),
991 1006 hint=_("see http://mercurial.selenic.com/wiki/MissingRequirement"
992 1007 " for more information"))
993 1008 return requirements
994 1009
995 1010 def writerequires(opener, requirements):
996 1011 reqfile = opener("requires", "w")
997 1012 for r in sorted(requirements):
998 1013 reqfile.write("%s\n" % r)
999 1014 reqfile.close()
1000 1015
1001 1016 class filecachesubentry(object):
1002 1017 def __init__(self, path, stat):
1003 1018 self.path = path
1004 1019 self.cachestat = None
1005 1020 self._cacheable = None
1006 1021
1007 1022 if stat:
1008 1023 self.cachestat = filecachesubentry.stat(self.path)
1009 1024
1010 1025 if self.cachestat:
1011 1026 self._cacheable = self.cachestat.cacheable()
1012 1027 else:
1013 1028 # None means we don't know yet
1014 1029 self._cacheable = None
1015 1030
1016 1031 def refresh(self):
1017 1032 if self.cacheable():
1018 1033 self.cachestat = filecachesubentry.stat(self.path)
1019 1034
1020 1035 def cacheable(self):
1021 1036 if self._cacheable is not None:
1022 1037 return self._cacheable
1023 1038
1024 1039 # we don't know yet, assume it is for now
1025 1040 return True
1026 1041
1027 1042 def changed(self):
1028 1043 # no point in going further if we can't cache it
1029 1044 if not self.cacheable():
1030 1045 return True
1031 1046
1032 1047 newstat = filecachesubentry.stat(self.path)
1033 1048
1034 1049 # we may not know if it's cacheable yet, check again now
1035 1050 if newstat and self._cacheable is None:
1036 1051 self._cacheable = newstat.cacheable()
1037 1052
1038 1053 # check again
1039 1054 if not self._cacheable:
1040 1055 return True
1041 1056
1042 1057 if self.cachestat != newstat:
1043 1058 self.cachestat = newstat
1044 1059 return True
1045 1060 else:
1046 1061 return False
1047 1062
1048 1063 @staticmethod
1049 1064 def stat(path):
1050 1065 try:
1051 1066 return util.cachestat(path)
1052 1067 except OSError, e:
1053 1068 if e.errno != errno.ENOENT:
1054 1069 raise
1055 1070
1056 1071 class filecacheentry(object):
1057 1072 def __init__(self, paths, stat=True):
1058 1073 self._entries = []
1059 1074 for path in paths:
1060 1075 self._entries.append(filecachesubentry(path, stat))
1061 1076
1062 1077 def changed(self):
1063 1078 '''true if any entry has changed'''
1064 1079 for entry in self._entries:
1065 1080 if entry.changed():
1066 1081 return True
1067 1082 return False
1068 1083
1069 1084 def refresh(self):
1070 1085 for entry in self._entries:
1071 1086 entry.refresh()
1072 1087
1073 1088 class filecache(object):
1074 1089 '''A property like decorator that tracks files under .hg/ for updates.
1075 1090
1076 1091 Records stat info when called in _filecache.
1077 1092
1078 1093 On subsequent calls, compares old stat info with new info, and recreates the
1079 1094 object when any of the files changes, updating the new stat info in
1080 1095 _filecache.
1081 1096
1082 1097 Mercurial either atomic renames or appends for files under .hg,
1083 1098 so to ensure the cache is reliable we need the filesystem to be able
1084 1099 to tell us if a file has been replaced. If it can't, we fallback to
1085 1100 recreating the object on every call (essentially the same behaviour as
1086 1101 propertycache).
1087 1102
1088 1103 '''
1089 1104 def __init__(self, *paths):
1090 1105 self.paths = paths
1091 1106
1092 1107 def join(self, obj, fname):
1093 1108 """Used to compute the runtime path of a cached file.
1094 1109
1095 1110 Users should subclass filecache and provide their own version of this
1096 1111 function to call the appropriate join function on 'obj' (an instance
1097 1112 of the class that its member function was decorated).
1098 1113 """
1099 1114 return obj.join(fname)
1100 1115
1101 1116 def __call__(self, func):
1102 1117 self.func = func
1103 1118 self.name = func.__name__
1104 1119 return self
1105 1120
1106 1121 def __get__(self, obj, type=None):
1107 1122 # do we need to check if the file changed?
1108 1123 if self.name in obj.__dict__:
1109 1124 assert self.name in obj._filecache, self.name
1110 1125 return obj.__dict__[self.name]
1111 1126
1112 1127 entry = obj._filecache.get(self.name)
1113 1128
1114 1129 if entry:
1115 1130 if entry.changed():
1116 1131 entry.obj = self.func(obj)
1117 1132 else:
1118 1133 paths = [self.join(obj, path) for path in self.paths]
1119 1134
1120 1135 # We stat -before- creating the object so our cache doesn't lie if
1121 1136 # a writer modified between the time we read and stat
1122 1137 entry = filecacheentry(paths, True)
1123 1138 entry.obj = self.func(obj)
1124 1139
1125 1140 obj._filecache[self.name] = entry
1126 1141
1127 1142 obj.__dict__[self.name] = entry.obj
1128 1143 return entry.obj
1129 1144
1130 1145 def __set__(self, obj, value):
1131 1146 if self.name not in obj._filecache:
1132 1147 # we add an entry for the missing value because X in __dict__
1133 1148 # implies X in _filecache
1134 1149 paths = [self.join(obj, path) for path in self.paths]
1135 1150 ce = filecacheentry(paths, False)
1136 1151 obj._filecache[self.name] = ce
1137 1152 else:
1138 1153 ce = obj._filecache[self.name]
1139 1154
1140 1155 ce.obj = value # update cached copy
1141 1156 obj.__dict__[self.name] = value # update copy returned by obj.x
1142 1157
1143 1158 def __delete__(self, obj):
1144 1159 try:
1145 1160 del obj.__dict__[self.name]
1146 1161 except KeyError:
1147 1162 raise AttributeError(self.name)
@@ -1,620 +1,626 b''
1 1 $ cat <<EOF >> $HGRCPATH
2 2 > [ui]
3 3 > commitsubrepos = Yes
4 4 > [extensions]
5 5 > mq =
6 6 > record =
7 7 > [diff]
8 8 > nodates = 1
9 9 > EOF
10 10
11 11 $ stdin=`pwd`/stdin.tmp
12 12
13 13 fn to create new repository w/dirty subrepo, and cd into it
14 14 $ mkrepo() {
15 15 > hg init $1
16 16 > cd $1
17 17 > hg qinit
18 18 > }
19 19
20 20 fn to create dirty subrepo
21 21 $ mksubrepo() {
22 22 > hg init $1
23 23 > cd $1
24 24 > echo a > a
25 25 > hg add
26 26 > cd ..
27 27 > }
28 28
29 29 $ testadd() {
30 30 > cat - > "$stdin"
31 31 > mksubrepo sub
32 32 > echo sub = sub >> .hgsub
33 33 > hg add .hgsub
34 34 > echo % abort when adding .hgsub w/dirty subrepo
35 35 > hg status -S
36 36 > echo '%' $*
37 37 > cat "$stdin" | hg $*
38 38 > echo [$?]
39 39 > hg -R sub ci -m0sub
40 40 > echo % update substate when adding .hgsub w/clean updated subrepo
41 41 > hg status -S
42 42 > echo '%' $*
43 43 > cat "$stdin" | hg $*
44 44 > hg debugsub
45 45 > }
46 46
47 47 $ testmod() {
48 48 > cat - > "$stdin"
49 49 > mksubrepo sub2
50 50 > echo sub2 = sub2 >> .hgsub
51 51 > echo % abort when modifying .hgsub w/dirty subrepo
52 52 > hg status -S
53 53 > echo '%' $*
54 54 > cat "$stdin" | hg $*
55 55 > echo [$?]
56 56 > hg -R sub2 ci -m0sub2
57 57 > echo % update substate when modifying .hgsub w/clean updated subrepo
58 58 > hg status -S
59 59 > echo '%' $*
60 60 > cat "$stdin" | hg $*
61 61 > hg debugsub
62 62 > }
63 63
64 64 $ testrm1() {
65 65 > cat - > "$stdin"
66 66 > mksubrepo sub3
67 67 > echo sub3 = sub3 >> .hgsub
68 68 > hg ci -Aqmsub3
69 69 > $EXTRA
70 70 > echo b >> sub3/a
71 71 > hg rm .hgsub
72 72 > echo % update substate when removing .hgsub w/dirty subrepo
73 73 > hg status -S
74 74 > echo '%' $*
75 75 > cat "$stdin" | hg $*
76 76 > echo % debugsub should be empty
77 77 > hg debugsub
78 78 > }
79 79
80 80 $ testrm2() {
81 81 > cat - > "$stdin"
82 82 > mksubrepo sub4
83 83 > echo sub4 = sub4 >> .hgsub
84 84 > hg ci -Aqmsub4
85 85 > $EXTRA
86 86 > hg rm .hgsub
87 87 > echo % update substate when removing .hgsub w/clean updated subrepo
88 88 > hg status -S
89 89 > echo '%' $*
90 90 > cat "$stdin" | hg $*
91 91 > echo % debugsub should be empty
92 92 > hg debugsub
93 93 > }
94 94
95 95
96 96 handle subrepos safely on qnew
97 97
98 98 $ mkrepo repo-2499-qnew
99 99 $ testadd qnew -X path:no-effect -m0 0.diff
100 100 adding a
101 101 % abort when adding .hgsub w/dirty subrepo
102 102 A .hgsub
103 103 A sub/a
104 104 % qnew -X path:no-effect -m0 0.diff
105 105 abort: uncommitted changes in subrepository 'sub'
106 106 [255]
107 107 % update substate when adding .hgsub w/clean updated subrepo
108 108 A .hgsub
109 A sub/a
109 110 % qnew -X path:no-effect -m0 0.diff
110 111 path sub
111 112 source sub
112 113 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
113 114
114 115 $ testmod qnew --cwd .. -R repo-2499-qnew -X path:no-effect -m1 1.diff
115 116 adding a
116 117 % abort when modifying .hgsub w/dirty subrepo
117 118 M .hgsub
118 119 A sub2/a
119 120 % qnew --cwd .. -R repo-2499-qnew -X path:no-effect -m1 1.diff
120 121 abort: uncommitted changes in subrepository 'sub2'
121 122 [255]
122 123 % update substate when modifying .hgsub w/clean updated subrepo
123 124 M .hgsub
125 A sub2/a
124 126 % qnew --cwd .. -R repo-2499-qnew -X path:no-effect -m1 1.diff
125 127 path sub
126 128 source sub
127 129 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
128 130 path sub2
129 131 source sub2
130 132 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
131 133
132 134 $ hg qpop -qa
133 135 patch queue now empty
134 136 $ testrm1 qnew -m2 2.diff
135 137 adding a
136 138 % update substate when removing .hgsub w/dirty subrepo
137 139 M sub3/a
138 140 R .hgsub
139 141 % qnew -m2 2.diff
140 142 % debugsub should be empty
141 143
142 144 $ hg qpop -qa
143 145 patch queue now empty
144 146 $ testrm2 qnew -m3 3.diff
145 147 adding a
146 148 % update substate when removing .hgsub w/clean updated subrepo
147 149 R .hgsub
148 150 % qnew -m3 3.diff
149 151 % debugsub should be empty
150 152
151 153 $ cd ..
152 154
153 155
154 156 handle subrepos safely on qrefresh
155 157
156 158 $ mkrepo repo-2499-qrefresh
157 159 $ hg qnew -m0 0.diff
158 160 $ testadd qrefresh
159 161 adding a
160 162 % abort when adding .hgsub w/dirty subrepo
161 163 A .hgsub
162 164 A sub/a
163 165 % qrefresh
164 166 abort: uncommitted changes in subrepository 'sub'
165 167 [255]
166 168 % update substate when adding .hgsub w/clean updated subrepo
167 169 A .hgsub
170 A sub/a
168 171 % qrefresh
169 172 path sub
170 173 source sub
171 174 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
172 175
173 176 $ hg qnew -m1 1.diff
174 177 $ testmod qrefresh
175 178 adding a
176 179 % abort when modifying .hgsub w/dirty subrepo
177 180 M .hgsub
178 181 A sub2/a
179 182 % qrefresh
180 183 abort: uncommitted changes in subrepository 'sub2'
181 184 [255]
182 185 % update substate when modifying .hgsub w/clean updated subrepo
183 186 M .hgsub
187 A sub2/a
184 188 % qrefresh
185 189 path sub
186 190 source sub
187 191 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
188 192 path sub2
189 193 source sub2
190 194 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
191 195
192 196 $ hg qpop -qa
193 197 patch queue now empty
194 198 $ EXTRA='hg qnew -m2 2.diff'
195 199 $ testrm1 qrefresh
196 200 adding a
197 201 % update substate when removing .hgsub w/dirty subrepo
198 202 M sub3/a
199 203 R .hgsub
200 204 % qrefresh
201 205 % debugsub should be empty
202 206
203 207 $ hg qpop -qa
204 208 patch queue now empty
205 209 $ EXTRA='hg qnew -m3 3.diff'
206 210 $ testrm2 qrefresh
207 211 adding a
208 212 % update substate when removing .hgsub w/clean updated subrepo
209 213 R .hgsub
210 214 % qrefresh
211 215 % debugsub should be empty
212 216 $ EXTRA=
213 217
214 218 $ cd ..
215 219
216 220
217 221 handle subrepos safely on qpush/qpop
218 222 (and we cannot qpop / qpush with a modified subrepo)
219 223
220 224 $ mkrepo repo-2499-qpush
221 225 $ mksubrepo sub
222 226 adding a
223 227 $ hg -R sub ci -m0sub
224 228 $ echo sub = sub > .hgsub
225 229 $ hg add .hgsub
226 230 $ hg commit -m0
227 231 $ hg debugsub
228 232 path sub
229 233 source sub
230 234 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
231 235 $ echo foo > ./sub/a
232 236 $ hg -R sub commit -m foo
233 237 $ hg commit -m1
234 238 $ hg qimport -r "0:tip"
235 239 $ hg -R sub id --id
236 240 aa037b301eba
237 241
238 242 qpop
239 243 $ hg -R sub update 0000
240 244 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
241 245 $ hg qpop
242 246 abort: local changed subrepos found, refresh first
243 247 [255]
244 248 $ hg revert sub
245 249 reverting subrepo sub
246 250 adding sub/a (glob)
247 251 $ hg qpop
248 252 popping 1.diff
249 253 now at: 0.diff
250 254 $ hg status -AS
251 255 C .hgsub
252 256 C .hgsubstate
253 257 C sub/a
254 258 $ hg -R sub id --id
255 259 b2fdb12cd82b
256 260
257 261 qpush
258 262 $ hg -R sub update 0000
259 263 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
260 264 $ hg qpush
261 265 abort: local changed subrepos found, refresh first
262 266 [255]
263 267 $ hg revert sub
264 268 reverting subrepo sub
265 269 adding sub/a (glob)
266 270 $ hg qpush
267 271 applying 1.diff
268 272 subrepository sub diverged (local revision: b2fdb12cd82b, remote revision: aa037b301eba)
269 273 (M)erge, keep (l)ocal or keep (r)emote? m
270 274 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
271 275 now at: 1.diff
272 276 $ hg status -AS
273 277 C .hgsub
274 278 C .hgsubstate
275 279 C sub/a
276 280 $ hg -R sub id --id
277 281 aa037b301eba
278 282
279 283 $ cd ..
280 284
281 285
282 286 handle subrepos safely on qrecord
283 287
284 288 $ mkrepo repo-2499-qrecord
285 289 $ testadd qrecord --config ui.interactive=1 -m0 0.diff <<EOF
286 290 > y
287 291 > y
288 292 > EOF
289 293 adding a
290 294 % abort when adding .hgsub w/dirty subrepo
291 295 A .hgsub
292 296 A sub/a
293 297 % qrecord --config ui.interactive=1 -m0 0.diff
294 298 diff --git a/.hgsub b/.hgsub
295 299 new file mode 100644
296 300 examine changes to '.hgsub'? [Ynesfdaq?] y
297 301
298 302 @@ -0,0 +1,1 @@
299 303 +sub = sub
300 304 record this change to '.hgsub'? [Ynesfdaq?] y
301 305
302 306 warning: subrepo spec file '.hgsub' not found
303 307 abort: uncommitted changes in subrepository 'sub'
304 308 [255]
305 309 % update substate when adding .hgsub w/clean updated subrepo
306 310 A .hgsub
311 A sub/a
307 312 % qrecord --config ui.interactive=1 -m0 0.diff
308 313 diff --git a/.hgsub b/.hgsub
309 314 new file mode 100644
310 315 examine changes to '.hgsub'? [Ynesfdaq?] y
311 316
312 317 @@ -0,0 +1,1 @@
313 318 +sub = sub
314 319 record this change to '.hgsub'? [Ynesfdaq?] y
315 320
316 321 warning: subrepo spec file '.hgsub' not found
317 322 path sub
318 323 source sub
319 324 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
320 325 $ testmod qrecord --config ui.interactive=1 -m1 1.diff <<EOF
321 326 > y
322 327 > y
323 328 > EOF
324 329 adding a
325 330 % abort when modifying .hgsub w/dirty subrepo
326 331 M .hgsub
327 332 A sub2/a
328 333 % qrecord --config ui.interactive=1 -m1 1.diff
329 334 diff --git a/.hgsub b/.hgsub
330 335 1 hunks, 1 lines changed
331 336 examine changes to '.hgsub'? [Ynesfdaq?] y
332 337
333 338 @@ -1,1 +1,2 @@
334 339 sub = sub
335 340 +sub2 = sub2
336 341 record this change to '.hgsub'? [Ynesfdaq?] y
337 342
338 343 abort: uncommitted changes in subrepository 'sub2'
339 344 [255]
340 345 % update substate when modifying .hgsub w/clean updated subrepo
341 346 M .hgsub
347 A sub2/a
342 348 % qrecord --config ui.interactive=1 -m1 1.diff
343 349 diff --git a/.hgsub b/.hgsub
344 350 1 hunks, 1 lines changed
345 351 examine changes to '.hgsub'? [Ynesfdaq?] y
346 352
347 353 @@ -1,1 +1,2 @@
348 354 sub = sub
349 355 +sub2 = sub2
350 356 record this change to '.hgsub'? [Ynesfdaq?] y
351 357
352 358 path sub
353 359 source sub
354 360 revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
355 361 path sub2
356 362 source sub2
357 363 revision 1f94c7611cc6b74f5a17b16121a1170d44776845
358 364
359 365 $ hg qpop -qa
360 366 patch queue now empty
361 367 $ testrm1 qrecord --config ui.interactive=1 -m2 2.diff <<EOF
362 368 > y
363 369 > y
364 370 > EOF
365 371 adding a
366 372 % update substate when removing .hgsub w/dirty subrepo
367 373 M sub3/a
368 374 R .hgsub
369 375 % qrecord --config ui.interactive=1 -m2 2.diff
370 376 diff --git a/.hgsub b/.hgsub
371 377 deleted file mode 100644
372 378 examine changes to '.hgsub'? [Ynesfdaq?] y
373 379
374 380 % debugsub should be empty
375 381
376 382 $ hg qpop -qa
377 383 patch queue now empty
378 384 $ testrm2 qrecord --config ui.interactive=1 -m3 3.diff <<EOF
379 385 > y
380 386 > y
381 387 > EOF
382 388 adding a
383 389 % update substate when removing .hgsub w/clean updated subrepo
384 390 R .hgsub
385 391 % qrecord --config ui.interactive=1 -m3 3.diff
386 392 diff --git a/.hgsub b/.hgsub
387 393 deleted file mode 100644
388 394 examine changes to '.hgsub'? [Ynesfdaq?] y
389 395
390 396 % debugsub should be empty
391 397
392 398 $ cd ..
393 399
394 400
395 401 correctly handle subrepos with patch queues
396 402 $ mkrepo repo-subrepo-with-queue
397 403 $ mksubrepo sub
398 404 adding a
399 405 $ hg -R sub qnew sub0.diff
400 406 $ echo sub = sub >> .hgsub
401 407 $ hg add .hgsub
402 408 $ hg qnew 0.diff
403 409
404 410 $ cd ..
405 411
406 412 check whether MQ operations can import updated .hgsubstate correctly
407 413 both into 'revision' and 'patch file under .hg/patches':
408 414
409 415 $ hg init importing-hgsubstate
410 416 $ cd importing-hgsubstate
411 417
412 418 $ echo a > a
413 419 $ hg commit -u test -d '0 0' -Am '#0 in parent'
414 420 adding a
415 421 $ hg init sub
416 422 $ echo sa > sub/sa
417 423 $ hg -R sub commit -u test -d '0 0' -Am '#0 in sub'
418 424 adding sa
419 425 $ echo 'sub = sub' > .hgsub
420 426 $ touch .hgsubstate
421 427 $ hg add .hgsub .hgsubstate
422 428
423 429 $ hg qnew -u test -d '0 0' import-at-qnew
424 430 $ hg -R sub parents --template '{node} sub\n'
425 431 b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
426 432 $ cat .hgsubstate
427 433 b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
428 434 $ hg diff -c tip
429 435 diff -r f499373e340c -r f69e96d86e75 .hgsub
430 436 --- /dev/null
431 437 +++ b/.hgsub
432 438 @@ -0,0 +1,1 @@
433 439 +sub = sub
434 440 diff -r f499373e340c -r f69e96d86e75 .hgsubstate
435 441 --- /dev/null
436 442 +++ b/.hgsubstate
437 443 @@ -0,0 +1,1 @@
438 444 +b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
439 445 $ cat .hg/patches/import-at-qnew
440 446 # HG changeset patch
441 447 # User test
442 448 # Date 0 0
443 449 # Parent f499373e340cdca5d01dee904aeb42dd2a325e71
444 450
445 451 diff -r f499373e340c -r f69e96d86e75 .hgsub
446 452 --- /dev/null
447 453 +++ b/.hgsub
448 454 @@ -0,0 +1,1 @@
449 455 +sub = sub
450 456 diff -r f499373e340c -r f69e96d86e75 .hgsubstate
451 457 --- /dev/null
452 458 +++ b/.hgsubstate
453 459 @@ -0,0 +1,1 @@
454 460 +b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
455 461 $ hg parents --template '{node}\n'
456 462 f69e96d86e75a6d4fd88285dc9697acb23951041
457 463 $ hg parents --template '{files}\n'
458 464 .hgsub .hgsubstate
459 465
460 466 check also whether qnew not including ".hgsubstate" explicitly causes
461 467 as same result (in node hash) as one including it.
462 468
463 469 $ hg qpop -a -q
464 470 patch queue now empty
465 471 $ hg qdelete import-at-qnew
466 472 $ echo 'sub = sub' > .hgsub
467 473 $ hg add .hgsub
468 474 $ rm -f .hgsubstate
469 475 $ hg qnew -u test -d '0 0' import-at-qnew
470 476 $ hg parents --template '{node}\n'
471 477 f69e96d86e75a6d4fd88285dc9697acb23951041
472 478 $ hg parents --template '{files}\n'
473 479 .hgsub .hgsubstate
474 480
475 481 check whether qrefresh imports updated .hgsubstate correctly
476 482
477 483 $ hg qpop
478 484 popping import-at-qnew
479 485 patch queue now empty
480 486 $ hg qpush
481 487 applying import-at-qnew
482 488 now at: import-at-qnew
483 489 $ hg parents --template '{files}\n'
484 490 .hgsub .hgsubstate
485 491
486 492 $ hg qnew import-at-qrefresh
487 493 $ echo sb > sub/sb
488 494 $ hg -R sub commit -u test -d '0 0' -Am '#1 in sub'
489 495 adding sb
490 496 $ hg qrefresh -u test -d '0 0'
491 497 $ hg -R sub parents --template '{node} sub\n'
492 498 88ac1bef5ed43b689d1d200b59886b675dec474b sub
493 499 $ cat .hgsubstate
494 500 88ac1bef5ed43b689d1d200b59886b675dec474b sub
495 501 $ hg diff -c tip
496 502 diff -r 05b056bb9c8c -r d987bec230f4 .hgsubstate
497 503 --- a/.hgsubstate
498 504 +++ b/.hgsubstate
499 505 @@ -1,1 +1,1 @@
500 506 -b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
501 507 +88ac1bef5ed43b689d1d200b59886b675dec474b sub
502 508 $ cat .hg/patches/import-at-qrefresh
503 509 # HG changeset patch
504 510 # User test
505 511 # Date 0 0
506 512 # Parent 05b056bb9c8c05ff15258b84fd42ab3527271033
507 513
508 514 diff -r 05b056bb9c8c .hgsubstate
509 515 --- a/.hgsubstate
510 516 +++ b/.hgsubstate
511 517 @@ -1,1 +1,1 @@
512 518 -b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
513 519 +88ac1bef5ed43b689d1d200b59886b675dec474b sub
514 520 $ hg parents --template '{files}\n'
515 521 .hgsubstate
516 522
517 523 $ hg qrefresh -u test -d '0 0'
518 524 $ cat .hgsubstate
519 525 88ac1bef5ed43b689d1d200b59886b675dec474b sub
520 526 $ hg diff -c tip
521 527 diff -r 05b056bb9c8c -r d987bec230f4 .hgsubstate
522 528 --- a/.hgsubstate
523 529 +++ b/.hgsubstate
524 530 @@ -1,1 +1,1 @@
525 531 -b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
526 532 +88ac1bef5ed43b689d1d200b59886b675dec474b sub
527 533 $ cat .hg/patches/import-at-qrefresh
528 534 # HG changeset patch
529 535 # User test
530 536 # Date 0 0
531 537 # Parent 05b056bb9c8c05ff15258b84fd42ab3527271033
532 538
533 539 diff -r 05b056bb9c8c .hgsubstate
534 540 --- a/.hgsubstate
535 541 +++ b/.hgsubstate
536 542 @@ -1,1 +1,1 @@
537 543 -b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
538 544 +88ac1bef5ed43b689d1d200b59886b675dec474b sub
539 545 $ hg parents --template '{files}\n'
540 546 .hgsubstate
541 547
542 548 $ hg update -C tip
543 549 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
544 550 $ hg qpop -a
545 551 popping import-at-qrefresh
546 552 popping import-at-qnew
547 553 patch queue now empty
548 554
549 555 $ hg -R sub update -C 0
550 556 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
551 557 $ echo 'sub = sub' > .hgsub
552 558 $ hg commit -Am '#1 in parent'
553 559 adding .hgsub
554 560 $ hg -R sub update -C 1
555 561 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
556 562 $ hg commit -Am '#2 in parent (but will be rolled back soon)'
557 563 $ hg rollback
558 564 repository tip rolled back to revision 1 (undo commit)
559 565 working directory now based on revision 1
560 566 $ hg status
561 567 M .hgsubstate
562 568 $ hg qnew -u test -d '0 0' checkstate-at-qnew
563 569 $ hg -R sub parents --template '{node} sub\n'
564 570 88ac1bef5ed43b689d1d200b59886b675dec474b sub
565 571 $ cat .hgsubstate
566 572 88ac1bef5ed43b689d1d200b59886b675dec474b sub
567 573 $ hg diff -c tip
568 574 diff -r 4d91eb2fa1d1 -r 1259c112d884 .hgsubstate
569 575 --- a/.hgsubstate
570 576 +++ b/.hgsubstate
571 577 @@ -1,1 +1,1 @@
572 578 -b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
573 579 +88ac1bef5ed43b689d1d200b59886b675dec474b sub
574 580 $ cat .hg/patches/checkstate-at-qnew
575 581 # HG changeset patch
576 582 # User test
577 583 # Date 0 0
578 584 # Parent 4d91eb2fa1d1b22ec513347b9cd06f6b49d470fa
579 585
580 586 diff -r 4d91eb2fa1d1 -r 1259c112d884 .hgsubstate
581 587 --- a/.hgsubstate
582 588 +++ b/.hgsubstate
583 589 @@ -1,1 +1,1 @@
584 590 -b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub
585 591 +88ac1bef5ed43b689d1d200b59886b675dec474b sub
586 592 $ hg parents --template '{files}\n'
587 593 .hgsubstate
588 594
589 595 check whether qrefresh not including ".hgsubstate" explicitly causes
590 596 as same result (in node hash) as one including it.
591 597
592 598 $ hg update -C -q 0
593 599 $ hg qpop -a -q
594 600 patch queue now empty
595 601 $ hg qnew -u test -d '0 0' add-hgsub-at-qrefresh
596 602 $ echo 'sub = sub' > .hgsub
597 603 $ echo > .hgsubstate
598 604 $ hg add .hgsub .hgsubstate
599 605 $ hg qrefresh -u test -d '0 0'
600 606 $ hg parents --template '{node}\n'
601 607 7c48c35501aae6770ed9c2517014628615821a8e
602 608 $ hg parents --template '{files}\n'
603 609 .hgsub .hgsubstate
604 610
605 611 $ hg qpop -a -q
606 612 patch queue now empty
607 613 $ hg qdelete add-hgsub-at-qrefresh
608 614 $ hg qnew -u test -d '0 0' add-hgsub-at-qrefresh
609 615 $ echo 'sub = sub' > .hgsub
610 616 $ hg add .hgsub
611 617 $ rm -f .hgsubstate
612 618 $ hg qrefresh -u test -d '0 0'
613 619 $ hg parents --template '{node}\n'
614 620 7c48c35501aae6770ed9c2517014628615821a8e
615 621 $ hg parents --template '{files}\n'
616 622 .hgsub .hgsubstate
617 623
618 624 $ cd ..
619 625
620 626 $ cd ..
@@ -1,1706 +1,1739 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 $ hg init t
7 7 $ cd t
8 8
9 9 first revision, no sub
10 10
11 11 $ echo a > a
12 12 $ hg ci -Am0
13 13 adding a
14 14
15 15 add first sub
16 16
17 17 $ echo s = s > .hgsub
18 18 $ hg add .hgsub
19 19 $ hg init s
20 20 $ echo a > s/a
21 21
22 22 Issue2232: committing a subrepo without .hgsub
23 23
24 24 $ hg ci -mbad s
25 25 abort: can't commit subrepos without .hgsub
26 26 [255]
27 27
28 28 $ hg -R s add s/a
29 29 $ hg files -S
30 30 .hgsub
31 31 a
32 32 s/a (glob)
33 33
34 34 $ hg -R s ci -Ams0
35 35 $ hg sum
36 36 parent: 0:f7b1eb17ad24 tip
37 37 0
38 38 branch: default
39 39 commit: 1 added, 1 subrepos
40 40 update: (current)
41 41 phases: 1 draft
42 42 $ hg ci -m1
43 43
44 44 test handling .hgsubstate "added" explicitly.
45 45
46 46 $ hg parents --template '{node}\n{files}\n'
47 47 7cf8cfea66e410e8e3336508dfeec07b3192de51
48 48 .hgsub .hgsubstate
49 49 $ hg rollback -q
50 50 $ hg add .hgsubstate
51 51 $ hg ci -m1
52 52 $ hg parents --template '{node}\n{files}\n'
53 53 7cf8cfea66e410e8e3336508dfeec07b3192de51
54 54 .hgsub .hgsubstate
55 55
56 56 Revert subrepo and test subrepo fileset keyword:
57 57
58 58 $ echo b > s/a
59 59 $ hg revert --dry-run "set:subrepo('glob:s*')"
60 60 reverting subrepo s
61 61 reverting s/a (glob)
62 62 $ cat s/a
63 63 b
64 64 $ hg revert "set:subrepo('glob:s*')"
65 65 reverting subrepo s
66 66 reverting s/a (glob)
67 67 $ cat s/a
68 68 a
69 69 $ rm s/a.orig
70 70
71 71 Revert subrepo with no backup. The "reverting s/a" line is gone since
72 72 we're really running 'hg update' in the subrepo:
73 73
74 74 $ echo b > s/a
75 75 $ hg revert --no-backup s
76 76 reverting subrepo s
77 77
78 78 Issue2022: update -C
79 79
80 80 $ echo b > s/a
81 81 $ hg sum
82 82 parent: 1:7cf8cfea66e4 tip
83 83 1
84 84 branch: default
85 85 commit: 1 subrepos
86 86 update: (current)
87 87 phases: 2 draft
88 88 $ hg co -C 1
89 89 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 90 $ hg sum
91 91 parent: 1:7cf8cfea66e4 tip
92 92 1
93 93 branch: default
94 94 commit: (clean)
95 95 update: (current)
96 96 phases: 2 draft
97 97
98 98 commands that require a clean repo should respect subrepos
99 99
100 100 $ echo b >> s/a
101 101 $ hg backout tip
102 102 abort: uncommitted changes in subrepository 's'
103 103 [255]
104 104 $ hg revert -C -R s s/a
105 105
106 106 add sub sub
107 107
108 108 $ echo ss = ss > s/.hgsub
109 109 $ hg init s/ss
110 110 $ echo a > s/ss/a
111 111 $ hg -R s add s/.hgsub
112 112 $ hg -R s/ss add s/ss/a
113 113 $ hg sum
114 114 parent: 1:7cf8cfea66e4 tip
115 115 1
116 116 branch: default
117 117 commit: 1 subrepos
118 118 update: (current)
119 119 phases: 2 draft
120 120 $ hg ci -m2
121 121 committing subrepository s
122 122 committing subrepository s/ss (glob)
123 123 $ hg sum
124 124 parent: 2:df30734270ae tip
125 125 2
126 126 branch: default
127 127 commit: (clean)
128 128 update: (current)
129 129 phases: 3 draft
130 130
131 131 test handling .hgsubstate "modified" explicitly.
132 132
133 133 $ hg parents --template '{node}\n{files}\n'
134 134 df30734270ae757feb35e643b7018e818e78a9aa
135 135 .hgsubstate
136 136 $ hg rollback -q
137 137 $ hg status -A .hgsubstate
138 138 M .hgsubstate
139 139 $ hg ci -m2
140 140 $ hg parents --template '{node}\n{files}\n'
141 141 df30734270ae757feb35e643b7018e818e78a9aa
142 142 .hgsubstate
143 143
144 144 bump sub rev (and check it is ignored by ui.commitsubrepos)
145 145
146 146 $ echo b > s/a
147 147 $ hg -R s ci -ms1
148 148 $ hg --config ui.commitsubrepos=no ci -m3
149 149
150 150 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
151 151
152 152 $ echo c > s/a
153 153 $ hg --config ui.commitsubrepos=no ci -m4
154 154 abort: uncommitted changes in subrepository 's'
155 155 (use --subrepos for recursive commit)
156 156 [255]
157 157 $ hg id
158 158 f6affe3fbfaa+ tip
159 159 $ hg -R s ci -mc
160 160 $ hg id
161 161 f6affe3fbfaa+ tip
162 162 $ echo d > s/a
163 163 $ hg ci -m4
164 164 committing subrepository s
165 165 $ hg tip -R s
166 166 changeset: 4:02dcf1d70411
167 167 tag: tip
168 168 user: test
169 169 date: Thu Jan 01 00:00:00 1970 +0000
170 170 summary: 4
171 171
172 172
173 173 check caching
174 174
175 175 $ hg co 0
176 176 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
177 177 $ hg debugsub
178 178
179 179 restore
180 180
181 181 $ hg co
182 182 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
183 183 $ hg debugsub
184 184 path s
185 185 source s
186 186 revision 02dcf1d704118aee3ee306ccfa1910850d5b05ef
187 187
188 188 new branch for merge tests
189 189
190 190 $ hg co 1
191 191 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
192 192 $ echo t = t >> .hgsub
193 193 $ hg init t
194 194 $ echo t > t/t
195 195 $ hg -R t add t
196 196 adding t/t (glob)
197 197
198 198 5
199 199
200 200 $ hg ci -m5 # add sub
201 201 committing subrepository t
202 202 created new head
203 203 $ echo t2 > t/t
204 204
205 205 6
206 206
207 207 $ hg st -R s
208 208 $ hg ci -m6 # change sub
209 209 committing subrepository t
210 210 $ hg debugsub
211 211 path s
212 212 source s
213 213 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
214 214 path t
215 215 source t
216 216 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
217 217 $ echo t3 > t/t
218 218
219 219 7
220 220
221 221 $ hg ci -m7 # change sub again for conflict test
222 222 committing subrepository t
223 223 $ hg rm .hgsub
224 224
225 225 8
226 226
227 227 $ hg ci -m8 # remove sub
228 228
229 229 test handling .hgsubstate "removed" explicitly.
230 230
231 231 $ hg parents --template '{node}\n{files}\n'
232 232 96615c1dad2dc8e3796d7332c77ce69156f7b78e
233 233 .hgsub .hgsubstate
234 234 $ hg rollback -q
235 235 $ hg remove .hgsubstate
236 236 $ hg ci -m8
237 237 $ hg parents --template '{node}\n{files}\n'
238 238 96615c1dad2dc8e3796d7332c77ce69156f7b78e
239 239 .hgsub .hgsubstate
240 240
241 241 merge tests
242 242
243 243 $ hg co -C 3
244 244 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
245 245 $ hg merge 5 # test adding
246 246 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
247 247 (branch merge, don't forget to commit)
248 248 $ hg debugsub
249 249 path s
250 250 source s
251 251 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
252 252 path t
253 253 source t
254 254 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
255 255 $ hg ci -m9
256 256 created new head
257 257 $ hg merge 6 --debug # test change
258 258 searching for copies back to rev 2
259 259 resolving manifests
260 260 branchmerge: True, force: False, partial: False
261 261 ancestor: 1f14a2e2d3ec, local: f0d2028bf86d+, remote: 1831e14459c4
262 262 .hgsubstate: versions differ -> m
263 263 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
264 264 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
265 265 getting subrepo t
266 266 resolving manifests
267 267 branchmerge: False, force: False, partial: False
268 268 ancestor: 60ca1237c194, local: 60ca1237c194+, remote: 6747d179aa9a
269 269 t: remote is newer -> g
270 270 getting t
271 271 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
272 272 (branch merge, don't forget to commit)
273 273 $ hg debugsub
274 274 path s
275 275 source s
276 276 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
277 277 path t
278 278 source t
279 279 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
280 280 $ echo conflict > t/t
281 281 $ hg ci -m10
282 282 committing subrepository t
283 283 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
284 284 searching for copies back to rev 2
285 285 resolving manifests
286 286 branchmerge: True, force: False, partial: False
287 287 ancestor: 1831e14459c4, local: e45c8b14af55+, remote: f94576341bcf
288 288 .hgsubstate: versions differ -> m
289 289 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
290 290 subrepo t: both sides changed
291 291 subrepository t diverged (local revision: 20a0db6fbf6c, remote revision: 7af322bc1198)
292 292 (M)erge, keep (l)ocal or keep (r)emote? m
293 293 merging subrepo t
294 294 searching for copies back to rev 2
295 295 resolving manifests
296 296 branchmerge: True, force: False, partial: False
297 297 ancestor: 6747d179aa9a, local: 20a0db6fbf6c+, remote: 7af322bc1198
298 298 preserving t for resolve of t
299 299 t: versions differ -> m
300 300 picked tool 'internal:merge' for t (binary False symlink False)
301 301 merging t
302 302 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
303 303 warning: conflicts during merge.
304 304 merging t incomplete! (edit conflicts, then use 'hg resolve --mark')
305 305 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
306 306 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
307 307 subrepo t: merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
308 308 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
309 309 (branch merge, don't forget to commit)
310 310
311 311 should conflict
312 312
313 313 $ cat t/t
314 314 <<<<<<< local: 20a0db6fbf6c - test: 10
315 315 conflict
316 316 =======
317 317 t3
318 318 >>>>>>> other: 7af322bc1198 - test: 7
319 319
320 320 11: remove subrepo t
321 321
322 322 $ hg co -C 5
323 323 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
324 324 $ hg revert -r 4 .hgsub # remove t
325 325 $ hg ci -m11
326 326 created new head
327 327 $ hg debugsub
328 328 path s
329 329 source s
330 330 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
331 331
332 332 local removed, remote changed, keep changed
333 333
334 334 $ hg merge 6
335 335 remote changed subrepository t which local removed
336 336 use (c)hanged version or (d)elete? c
337 337 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
338 338 (branch merge, don't forget to commit)
339 339 BROKEN: should include subrepo t
340 340 $ hg debugsub
341 341 path s
342 342 source s
343 343 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
344 344 $ cat .hgsubstate
345 345 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
346 346 6747d179aa9a688023c4b0cad32e4c92bb7f34ad t
347 347 $ hg ci -m 'local removed, remote changed, keep changed'
348 348 BROKEN: should include subrepo t
349 349 $ hg debugsub
350 350 path s
351 351 source s
352 352 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
353 353 BROKEN: should include subrepo t
354 354 $ cat .hgsubstate
355 355 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
356 356 $ cat t/t
357 357 t2
358 358
359 359 local removed, remote changed, keep removed
360 360
361 361 $ hg co -C 11
362 362 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
363 363 $ hg merge --config ui.interactive=true 6 <<EOF
364 364 > d
365 365 > EOF
366 366 remote changed subrepository t which local removed
367 367 use (c)hanged version or (d)elete? d
368 368 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
369 369 (branch merge, don't forget to commit)
370 370 $ hg debugsub
371 371 path s
372 372 source s
373 373 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
374 374 $ cat .hgsubstate
375 375 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
376 376 $ hg ci -m 'local removed, remote changed, keep removed'
377 377 created new head
378 378 $ hg debugsub
379 379 path s
380 380 source s
381 381 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
382 382 $ cat .hgsubstate
383 383 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
384 384
385 385 local changed, remote removed, keep changed
386 386
387 387 $ hg co -C 6
388 388 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
389 389 $ hg merge 11
390 390 local changed subrepository t which remote removed
391 391 use (c)hanged version or (d)elete? c
392 392 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
393 393 (branch merge, don't forget to commit)
394 394 BROKEN: should include subrepo t
395 395 $ hg debugsub
396 396 path s
397 397 source s
398 398 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
399 399 BROKEN: should include subrepo t
400 400 $ cat .hgsubstate
401 401 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
402 402 $ hg ci -m 'local changed, remote removed, keep changed'
403 403 created new head
404 404 BROKEN: should include subrepo t
405 405 $ hg debugsub
406 406 path s
407 407 source s
408 408 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
409 409 BROKEN: should include subrepo t
410 410 $ cat .hgsubstate
411 411 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
412 412 $ cat t/t
413 413 t2
414 414
415 415 local changed, remote removed, keep removed
416 416
417 417 $ hg co -C 6
418 418 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
419 419 $ hg merge --config ui.interactive=true 11 <<EOF
420 420 > d
421 421 > EOF
422 422 local changed subrepository t which remote removed
423 423 use (c)hanged version or (d)elete? d
424 424 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 425 (branch merge, don't forget to commit)
426 426 $ hg debugsub
427 427 path s
428 428 source s
429 429 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
430 430 $ cat .hgsubstate
431 431 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
432 432 $ hg ci -m 'local changed, remote removed, keep removed'
433 433 created new head
434 434 $ hg debugsub
435 435 path s
436 436 source s
437 437 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
438 438 $ cat .hgsubstate
439 439 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
440 440
441 441 clean up to avoid having to fix up the tests below
442 442
443 443 $ hg co -C 10
444 444 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
445 445 $ cat >> $HGRCPATH <<EOF
446 446 > [extensions]
447 447 > strip=
448 448 > EOF
449 449 $ hg strip -r 11:15
450 450 saved backup bundle to $TESTTMP/t/.hg/strip-backup/*-backup.hg (glob)
451 451
452 452 clone
453 453
454 454 $ cd ..
455 455 $ hg clone t tc
456 456 updating to branch default
457 457 cloning subrepo s from $TESTTMP/t/s
458 458 cloning subrepo s/ss from $TESTTMP/t/s/ss (glob)
459 459 cloning subrepo t from $TESTTMP/t/t
460 460 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
461 461 $ cd tc
462 462 $ hg debugsub
463 463 path s
464 464 source s
465 465 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
466 466 path t
467 467 source t
468 468 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
469 469
470 470 push
471 471
472 472 $ echo bah > t/t
473 473 $ hg ci -m11
474 474 committing subrepository t
475 475 $ hg push
476 476 pushing to $TESTTMP/t (glob)
477 477 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
478 478 no changes made to subrepo s since last push to $TESTTMP/t/s
479 479 pushing subrepo t to $TESTTMP/t/t
480 480 searching for changes
481 481 adding changesets
482 482 adding manifests
483 483 adding file changes
484 484 added 1 changesets with 1 changes to 1 files
485 485 searching for changes
486 486 adding changesets
487 487 adding manifests
488 488 adding file changes
489 489 added 1 changesets with 1 changes to 1 files
490 490
491 491 push -f
492 492
493 493 $ echo bah > s/a
494 494 $ hg ci -m12
495 495 committing subrepository s
496 496 $ hg push
497 497 pushing to $TESTTMP/t (glob)
498 498 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
499 499 pushing subrepo s to $TESTTMP/t/s
500 500 searching for changes
501 501 abort: push creates new remote head 12a213df6fa9! (in subrepo s)
502 502 (merge or see "hg help push" for details about pushing new heads)
503 503 [255]
504 504 $ hg push -f
505 505 pushing to $TESTTMP/t (glob)
506 506 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
507 507 searching for changes
508 508 no changes found
509 509 pushing subrepo s to $TESTTMP/t/s
510 510 searching for changes
511 511 adding changesets
512 512 adding manifests
513 513 adding file changes
514 514 added 1 changesets with 1 changes to 1 files (+1 heads)
515 515 pushing subrepo t to $TESTTMP/t/t
516 516 searching for changes
517 517 no changes found
518 518 searching for changes
519 519 adding changesets
520 520 adding manifests
521 521 adding file changes
522 522 added 1 changesets with 1 changes to 1 files
523 523
524 524 check that unmodified subrepos are not pushed
525 525
526 526 $ hg clone . ../tcc
527 527 updating to branch default
528 528 cloning subrepo s from $TESTTMP/tc/s
529 529 cloning subrepo s/ss from $TESTTMP/tc/s/ss (glob)
530 530 cloning subrepo t from $TESTTMP/tc/t
531 531 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
532 532
533 533 the subrepos on the new clone have nothing to push to its source
534 534
535 535 $ hg push -R ../tcc .
536 536 pushing to .
537 537 no changes made to subrepo s/ss since last push to s/ss (glob)
538 538 no changes made to subrepo s since last push to s
539 539 no changes made to subrepo t since last push to t
540 540 searching for changes
541 541 no changes found
542 542 [1]
543 543
544 544 the subrepos on the source do not have a clean store versus the clone target
545 545 because they were never explicitly pushed to the source
546 546
547 547 $ hg push ../tcc
548 548 pushing to ../tcc
549 549 pushing subrepo s/ss to ../tcc/s/ss (glob)
550 550 searching for changes
551 551 no changes found
552 552 pushing subrepo s to ../tcc/s
553 553 searching for changes
554 554 no changes found
555 555 pushing subrepo t to ../tcc/t
556 556 searching for changes
557 557 no changes found
558 558 searching for changes
559 559 no changes found
560 560 [1]
561 561
562 562 after push their stores become clean
563 563
564 564 $ hg push ../tcc
565 565 pushing to ../tcc
566 566 no changes made to subrepo s/ss since last push to ../tcc/s/ss (glob)
567 567 no changes made to subrepo s since last push to ../tcc/s
568 568 no changes made to subrepo t since last push to ../tcc/t
569 569 searching for changes
570 570 no changes found
571 571 [1]
572 572
573 573 updating a subrepo to a different revision or changing
574 574 its working directory does not make its store dirty
575 575
576 576 $ hg -R s update '.^'
577 577 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
578 578 $ hg push
579 579 pushing to $TESTTMP/t (glob)
580 580 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
581 581 no changes made to subrepo s since last push to $TESTTMP/t/s
582 582 no changes made to subrepo t since last push to $TESTTMP/t/t
583 583 searching for changes
584 584 no changes found
585 585 [1]
586 586 $ echo foo >> s/a
587 587 $ hg push
588 588 pushing to $TESTTMP/t (glob)
589 589 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
590 590 no changes made to subrepo s since last push to $TESTTMP/t/s
591 591 no changes made to subrepo t since last push to $TESTTMP/t/t
592 592 searching for changes
593 593 no changes found
594 594 [1]
595 595 $ hg -R s update -C tip
596 596 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
597 597
598 598 committing into a subrepo makes its store (but not its parent's store) dirty
599 599
600 600 $ echo foo >> s/ss/a
601 601 $ hg -R s/ss commit -m 'test dirty store detection'
602 602
603 603 $ hg out -S -r `hg log -r tip -T "{node|short}"`
604 604 comparing with $TESTTMP/t (glob)
605 605 searching for changes
606 606 no changes found
607 607 comparing with $TESTTMP/t/s
608 608 searching for changes
609 609 no changes found
610 610 comparing with $TESTTMP/t/s/ss
611 611 searching for changes
612 612 changeset: 1:79ea5566a333
613 613 tag: tip
614 614 user: test
615 615 date: Thu Jan 01 00:00:00 1970 +0000
616 616 summary: test dirty store detection
617 617
618 618 comparing with $TESTTMP/t/t
619 619 searching for changes
620 620 no changes found
621 621
622 622 $ hg push
623 623 pushing to $TESTTMP/t (glob)
624 624 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
625 625 searching for changes
626 626 adding changesets
627 627 adding manifests
628 628 adding file changes
629 629 added 1 changesets with 1 changes to 1 files
630 630 no changes made to subrepo s since last push to $TESTTMP/t/s
631 631 no changes made to subrepo t since last push to $TESTTMP/t/t
632 632 searching for changes
633 633 no changes found
634 634 [1]
635 635
636 636 a subrepo store may be clean versus one repo but not versus another
637 637
638 638 $ hg push
639 639 pushing to $TESTTMP/t (glob)
640 640 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
641 641 no changes made to subrepo s since last push to $TESTTMP/t/s
642 642 no changes made to subrepo t since last push to $TESTTMP/t/t
643 643 searching for changes
644 644 no changes found
645 645 [1]
646 646 $ hg push ../tcc
647 647 pushing to ../tcc
648 648 pushing subrepo s/ss to ../tcc/s/ss (glob)
649 649 searching for changes
650 650 adding changesets
651 651 adding manifests
652 652 adding file changes
653 653 added 1 changesets with 1 changes to 1 files
654 654 no changes made to subrepo s since last push to ../tcc/s
655 655 no changes made to subrepo t since last push to ../tcc/t
656 656 searching for changes
657 657 no changes found
658 658 [1]
659 659
660 660 update
661 661
662 662 $ cd ../t
663 663 $ hg up -C # discard our earlier merge
664 664 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
665 665 $ echo blah > t/t
666 666 $ hg ci -m13
667 667 committing subrepository t
668 668
669 669 backout calls revert internally with minimal opts, which should not raise
670 670 KeyError
671 671
672 672 $ hg backout ".^"
673 673 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
674 674 changeset c373c8102e68 backed out, don't forget to commit.
675 675
676 676 $ hg up -C # discard changes
677 677 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
678 678
679 679 pull
680 680
681 681 $ cd ../tc
682 682 $ hg pull
683 683 pulling from $TESTTMP/t (glob)
684 684 searching for changes
685 685 adding changesets
686 686 adding manifests
687 687 adding file changes
688 688 added 1 changesets with 1 changes to 1 files
689 689 (run 'hg update' to get a working copy)
690 690
691 691 should pull t
692 692
693 693 $ hg incoming -S -r `hg log -r tip -T "{node|short}"`
694 694 comparing with $TESTTMP/t (glob)
695 695 no changes found
696 696 comparing with $TESTTMP/t/s
697 697 searching for changes
698 698 no changes found
699 699 comparing with $TESTTMP/t/s/ss
700 700 searching for changes
701 701 no changes found
702 702 comparing with $TESTTMP/t/t
703 703 searching for changes
704 704 changeset: 5:52c0adc0515a
705 705 tag: tip
706 706 user: test
707 707 date: Thu Jan 01 00:00:00 1970 +0000
708 708 summary: 13
709 709
710 710
711 711 $ hg up
712 712 pulling subrepo t from $TESTTMP/t/t
713 713 searching for changes
714 714 adding changesets
715 715 adding manifests
716 716 adding file changes
717 717 added 1 changesets with 1 changes to 1 files
718 718 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
719 719 $ cat t/t
720 720 blah
721 721
722 722 bogus subrepo path aborts
723 723
724 724 $ echo 'bogus=[boguspath' >> .hgsub
725 725 $ hg ci -m 'bogus subrepo path'
726 726 abort: missing ] in subrepo source
727 727 [255]
728 728
729 729 Issue1986: merge aborts when trying to merge a subrepo that
730 730 shouldn't need merging
731 731
732 732 # subrepo layout
733 733 #
734 734 # o 5 br
735 735 # /|
736 736 # o | 4 default
737 737 # | |
738 738 # | o 3 br
739 739 # |/|
740 740 # o | 2 default
741 741 # | |
742 742 # | o 1 br
743 743 # |/
744 744 # o 0 default
745 745
746 746 $ cd ..
747 747 $ rm -rf sub
748 748 $ hg init main
749 749 $ cd main
750 750 $ hg init s
751 751 $ cd s
752 752 $ echo a > a
753 753 $ hg ci -Am1
754 754 adding a
755 755 $ hg branch br
756 756 marked working directory as branch br
757 757 (branches are permanent and global, did you want a bookmark?)
758 758 $ echo a >> a
759 759 $ hg ci -m1
760 760 $ hg up default
761 761 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
762 762 $ echo b > b
763 763 $ hg ci -Am1
764 764 adding b
765 765 $ hg up br
766 766 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
767 767 $ hg merge tip
768 768 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
769 769 (branch merge, don't forget to commit)
770 770 $ hg ci -m1
771 771 $ hg up 2
772 772 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
773 773 $ echo c > c
774 774 $ hg ci -Am1
775 775 adding c
776 776 $ hg up 3
777 777 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
778 778 $ hg merge 4
779 779 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
780 780 (branch merge, don't forget to commit)
781 781 $ hg ci -m1
782 782
783 783 # main repo layout:
784 784 #
785 785 # * <-- try to merge default into br again
786 786 # .`|
787 787 # . o 5 br --> substate = 5
788 788 # . |
789 789 # o | 4 default --> substate = 4
790 790 # | |
791 791 # | o 3 br --> substate = 2
792 792 # |/|
793 793 # o | 2 default --> substate = 2
794 794 # | |
795 795 # | o 1 br --> substate = 3
796 796 # |/
797 797 # o 0 default --> substate = 2
798 798
799 799 $ cd ..
800 800 $ echo 's = s' > .hgsub
801 801 $ hg -R s up 2
802 802 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
803 803 $ hg ci -Am1
804 804 adding .hgsub
805 805 $ hg branch br
806 806 marked working directory as branch br
807 807 (branches are permanent and global, did you want a bookmark?)
808 808 $ echo b > b
809 809 $ hg -R s up 3
810 810 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
811 811 $ hg ci -Am1
812 812 adding b
813 813 $ hg up default
814 814 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
815 815 $ echo c > c
816 816 $ hg ci -Am1
817 817 adding c
818 818 $ hg up 1
819 819 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
820 820 $ hg merge 2
821 821 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
822 822 (branch merge, don't forget to commit)
823 823 $ hg ci -m1
824 824 $ hg up 2
825 825 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
826 826 $ hg -R s up 4
827 827 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
828 828 $ echo d > d
829 829 $ hg ci -Am1
830 830 adding d
831 831 $ hg up 3
832 832 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
833 833 $ hg -R s up 5
834 834 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
835 835 $ echo e > e
836 836 $ hg ci -Am1
837 837 adding e
838 838
839 839 $ hg up 5
840 840 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
841 841 $ hg merge 4 # try to merge default into br again
842 842 subrepository s diverged (local revision: f8f13b33206e, remote revision: a3f9062a4f88)
843 843 (M)erge, keep (l)ocal or keep (r)emote? m
844 844 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
845 845 (branch merge, don't forget to commit)
846 846 $ cd ..
847 847
848 848 test subrepo delete from .hgsubstate
849 849
850 850 $ hg init testdelete
851 851 $ mkdir testdelete/nested testdelete/nested2
852 852 $ hg init testdelete/nested
853 853 $ hg init testdelete/nested2
854 854 $ echo test > testdelete/nested/foo
855 855 $ echo test > testdelete/nested2/foo
856 856 $ hg -R testdelete/nested add
857 857 adding testdelete/nested/foo (glob)
858 858 $ hg -R testdelete/nested2 add
859 859 adding testdelete/nested2/foo (glob)
860 860 $ hg -R testdelete/nested ci -m test
861 861 $ hg -R testdelete/nested2 ci -m test
862 862 $ echo nested = nested > testdelete/.hgsub
863 863 $ echo nested2 = nested2 >> testdelete/.hgsub
864 864 $ hg -R testdelete add
865 865 adding testdelete/.hgsub (glob)
866 866 $ hg -R testdelete ci -m "nested 1 & 2 added"
867 867 $ echo nested = nested > testdelete/.hgsub
868 868 $ hg -R testdelete ci -m "nested 2 deleted"
869 869 $ cat testdelete/.hgsubstate
870 870 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
871 871 $ hg -R testdelete remove testdelete/.hgsub
872 872 $ hg -R testdelete ci -m ".hgsub deleted"
873 873 $ cat testdelete/.hgsubstate
874 874 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
875 875
876 876 test repository cloning
877 877
878 878 $ mkdir mercurial mercurial2
879 879 $ hg init nested_absolute
880 880 $ echo test > nested_absolute/foo
881 881 $ hg -R nested_absolute add
882 882 adding nested_absolute/foo (glob)
883 883 $ hg -R nested_absolute ci -mtest
884 884 $ cd mercurial
885 885 $ hg init nested_relative
886 886 $ echo test2 > nested_relative/foo2
887 887 $ hg -R nested_relative add
888 888 adding nested_relative/foo2 (glob)
889 889 $ hg -R nested_relative ci -mtest2
890 890 $ hg init main
891 891 $ echo "nested_relative = ../nested_relative" > main/.hgsub
892 892 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
893 893 $ hg -R main add
894 894 adding main/.hgsub (glob)
895 895 $ hg -R main ci -m "add subrepos"
896 896 $ cd ..
897 897 $ hg clone mercurial/main mercurial2/main
898 898 updating to branch default
899 899 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
900 900 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
901 901 > mercurial2/main/nested_relative/.hg/hgrc
902 902 [paths]
903 903 default = $TESTTMP/mercurial/nested_absolute
904 904 [paths]
905 905 default = $TESTTMP/mercurial/nested_relative
906 906 $ rm -rf mercurial mercurial2
907 907
908 908 Issue1977: multirepo push should fail if subrepo push fails
909 909
910 910 $ hg init repo
911 911 $ hg init repo/s
912 912 $ echo a > repo/s/a
913 913 $ hg -R repo/s ci -Am0
914 914 adding a
915 915 $ echo s = s > repo/.hgsub
916 916 $ hg -R repo ci -Am1
917 917 adding .hgsub
918 918 $ hg clone repo repo2
919 919 updating to branch default
920 920 cloning subrepo s from $TESTTMP/repo/s
921 921 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
922 922 $ hg -q -R repo2 pull -u
923 923 $ echo 1 > repo2/s/a
924 924 $ hg -R repo2/s ci -m2
925 925 $ hg -q -R repo2/s push
926 926 $ hg -R repo2/s up -C 0
927 927 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
928 928 $ echo 2 > repo2/s/b
929 929 $ hg -R repo2/s ci -m3 -A
930 930 adding b
931 931 created new head
932 932 $ hg -R repo2 ci -m3
933 933 $ hg -q -R repo2 push
934 934 abort: push creates new remote head cc505f09a8b2! (in subrepo s)
935 935 (merge or see "hg help push" for details about pushing new heads)
936 936 [255]
937 937 $ hg -R repo update
938 938 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
939 939
940 940 test if untracked file is not overwritten
941 941
942 942 $ echo issue3276_ok > repo/s/b
943 943 $ hg -R repo2 push -f -q
944 944 $ touch -t 200001010000 repo/.hgsubstate
945 945 $ hg -R repo status --config debug.dirstate.delaywrite=2 repo/.hgsubstate
946 946 $ hg -R repo update
947 947 b: untracked file differs
948 948 abort: untracked files in working directory differ from files in requested revision (in subrepo s)
949 949 [255]
950 950
951 951 $ cat repo/s/b
952 952 issue3276_ok
953 953 $ rm repo/s/b
954 954 $ touch -t 200001010000 repo/.hgsubstate
955 955 $ hg -R repo revert --all
956 956 reverting repo/.hgsubstate (glob)
957 957 reverting subrepo s
958 958 $ hg -R repo update
959 959 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
960 960 $ cat repo/s/b
961 961 2
962 962 $ rm -rf repo2 repo
963 963
964 964
965 965 Issue1852 subrepos with relative paths always push/pull relative to default
966 966
967 967 Prepare a repo with subrepo
968 968
969 969 $ hg init issue1852a
970 970 $ cd issue1852a
971 971 $ hg init sub/repo
972 972 $ echo test > sub/repo/foo
973 973 $ hg -R sub/repo add sub/repo/foo
974 974 $ echo sub/repo = sub/repo > .hgsub
975 975 $ hg add .hgsub
976 976 $ hg ci -mtest
977 977 committing subrepository sub/repo (glob)
978 978 $ echo test >> sub/repo/foo
979 979 $ hg ci -mtest
980 980 committing subrepository sub/repo (glob)
981 981 $ hg cat sub/repo/foo
982 982 test
983 983 test
984 984 $ mkdir -p tmp/sub/repo
985 985 $ hg cat -r 0 --output tmp/%p_p sub/repo/foo
986 986 $ cat tmp/sub/repo/foo_p
987 987 test
988 988 $ mv sub/repo sub_
989 989 $ hg cat sub/repo/baz
990 990 skipping missing subrepository: sub/repo
991 991 [1]
992 992 $ rm -rf sub/repo
993 993 $ mv sub_ sub/repo
994 994 $ cd ..
995 995
996 996 Create repo without default path, pull top repo, and see what happens on update
997 997
998 998 $ hg init issue1852b
999 999 $ hg -R issue1852b pull issue1852a
1000 1000 pulling from issue1852a
1001 1001 requesting all changes
1002 1002 adding changesets
1003 1003 adding manifests
1004 1004 adding file changes
1005 1005 added 2 changesets with 3 changes to 2 files
1006 1006 (run 'hg update' to get a working copy)
1007 1007 $ hg -R issue1852b update
1008 1008 abort: default path for subrepository not found (in subrepo sub/repo) (glob)
1009 1009 [255]
1010 1010
1011 1011 Ensure a full traceback, not just the SubrepoAbort part
1012 1012
1013 1013 $ hg -R issue1852b update --traceback 2>&1 | grep 'raise util\.Abort'
1014 1014 raise util.Abort(_("default path for subrepository not found"))
1015 1015
1016 1016 Pull -u now doesn't help
1017 1017
1018 1018 $ hg -R issue1852b pull -u issue1852a
1019 1019 pulling from issue1852a
1020 1020 searching for changes
1021 1021 no changes found
1022 1022
1023 1023 Try the same, but with pull -u
1024 1024
1025 1025 $ hg init issue1852c
1026 1026 $ hg -R issue1852c pull -r0 -u issue1852a
1027 1027 pulling from issue1852a
1028 1028 adding changesets
1029 1029 adding manifests
1030 1030 adding file changes
1031 1031 added 1 changesets with 2 changes to 2 files
1032 1032 cloning subrepo sub/repo from issue1852a/sub/repo (glob)
1033 1033 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1034 1034
1035 1035 Try to push from the other side
1036 1036
1037 1037 $ hg -R issue1852a push `pwd`/issue1852c
1038 1038 pushing to $TESTTMP/issue1852c (glob)
1039 1039 pushing subrepo sub/repo to $TESTTMP/issue1852c/sub/repo (glob)
1040 1040 searching for changes
1041 1041 no changes found
1042 1042 searching for changes
1043 1043 adding changesets
1044 1044 adding manifests
1045 1045 adding file changes
1046 1046 added 1 changesets with 1 changes to 1 files
1047 1047
1048 1048 Incoming and outgoing should not use the default path:
1049 1049
1050 1050 $ hg clone -q issue1852a issue1852d
1051 1051 $ hg -R issue1852d outgoing --subrepos issue1852c
1052 1052 comparing with issue1852c
1053 1053 searching for changes
1054 1054 no changes found
1055 1055 comparing with issue1852c/sub/repo
1056 1056 searching for changes
1057 1057 no changes found
1058 1058 [1]
1059 1059 $ hg -R issue1852d incoming --subrepos issue1852c
1060 1060 comparing with issue1852c
1061 1061 searching for changes
1062 1062 no changes found
1063 1063 comparing with issue1852c/sub/repo
1064 1064 searching for changes
1065 1065 no changes found
1066 1066 [1]
1067 1067
1068 1068 Check that merge of a new subrepo doesn't write the uncommitted state to
1069 1069 .hgsubstate (issue4622)
1070 1070
1071 1071 $ hg init issue1852a/addedsub
1072 1072 $ echo zzz > issue1852a/addedsub/zz.txt
1073 1073 $ hg -R issue1852a/addedsub ci -Aqm "initial ZZ"
1074 1074
1075 1075 $ hg clone issue1852a/addedsub issue1852d/addedsub
1076 1076 updating to branch default
1077 1077 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1078 1078
1079 1079 $ echo def > issue1852a/sub/repo/foo
1080 1080 $ hg -R issue1852a ci -SAm 'tweaked subrepo'
1081 1081 adding tmp/sub/repo/foo_p
1082 1082 committing subrepository sub/repo (glob)
1083 1083
1084 1084 $ echo 'addedsub = addedsub' >> issue1852d/.hgsub
1085 1085 $ echo xyz > issue1852d/sub/repo/foo
1086 1086 $ hg -R issue1852d pull -u
1087 1087 pulling from $TESTTMP/issue1852a (glob)
1088 1088 searching for changes
1089 1089 adding changesets
1090 1090 adding manifests
1091 1091 adding file changes
1092 1092 added 1 changesets with 2 changes to 2 files
1093 1093 subrepository sub/repo diverged (local revision: f42d5c7504a8, remote revision: 46cd4aac504c)
1094 1094 (M)erge, keep (l)ocal or keep (r)emote? m
1095 1095 pulling subrepo sub/repo from $TESTTMP/issue1852a/sub/repo (glob)
1096 1096 searching for changes
1097 1097 adding changesets
1098 1098 adding manifests
1099 1099 adding file changes
1100 1100 added 1 changesets with 1 changes to 1 files
1101 1101 subrepository sources for sub/repo differ (glob)
1102 1102 use (l)ocal source (f42d5c7504a8) or (r)emote source (46cd4aac504c)? l
1103 1103 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1104 1104 $ cat issue1852d/.hgsubstate
1105 1105 f42d5c7504a811dda50f5cf3e5e16c3330b87172 sub/repo
1106 1106
1107 1107 Check status of files when none of them belong to the first
1108 1108 subrepository:
1109 1109
1110 1110 $ hg init subrepo-status
1111 1111 $ cd subrepo-status
1112 1112 $ hg init subrepo-1
1113 1113 $ hg init subrepo-2
1114 1114 $ cd subrepo-2
1115 1115 $ touch file
1116 1116 $ hg add file
1117 1117 $ cd ..
1118 1118 $ echo subrepo-1 = subrepo-1 > .hgsub
1119 1119 $ echo subrepo-2 = subrepo-2 >> .hgsub
1120 1120 $ hg add .hgsub
1121 1121 $ hg ci -m 'Added subrepos'
1122 1122 committing subrepository subrepo-2
1123 1123 $ hg st subrepo-2/file
1124 1124
1125 1125 Check that share works with subrepo
1126 1126 $ hg --config extensions.share= share . ../shared
1127 1127 updating working directory
1128 1128 cloning subrepo subrepo-2 from $TESTTMP/subrepo-status/subrepo-2
1129 1129 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1130 1130 $ test -f ../shared/subrepo-1/.hg/sharedpath
1131 1131 [1]
1132 1132 $ hg -R ../shared in
1133 1133 abort: repository default not found!
1134 1134 [255]
1135 1135 $ hg -R ../shared/subrepo-2 showconfig paths
1136 1136 paths.default=$TESTTMP/subrepo-status/subrepo-2
1137 1137 $ hg -R ../shared/subrepo-1 sum --remote
1138 1138 parent: -1:000000000000 tip (empty repository)
1139 1139 branch: default
1140 1140 commit: (clean)
1141 1141 update: (current)
1142 1142 remote: (synced)
1143 1143
1144 1144 Check hg update --clean
1145 1145 $ cd $TESTTMP/t
1146 1146 $ rm -r t/t.orig
1147 1147 $ hg status -S --all
1148 1148 C .hgsub
1149 1149 C .hgsubstate
1150 1150 C a
1151 1151 C s/.hgsub
1152 1152 C s/.hgsubstate
1153 1153 C s/a
1154 1154 C s/ss/a
1155 1155 C t/t
1156 1156 $ echo c1 > s/a
1157 1157 $ cd s
1158 1158 $ echo c1 > b
1159 1159 $ echo c1 > c
1160 1160 $ hg add b
1161 1161 $ cd ..
1162 1162 $ hg status -S
1163 1163 M s/a
1164 1164 A s/b
1165 1165 ? s/c
1166 1166 $ hg update -C
1167 1167 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1168 1168 $ hg status -S
1169 1169 ? s/b
1170 1170 ? s/c
1171 1171
1172 1172 Sticky subrepositories, no changes
1173 1173 $ cd $TESTTMP/t
1174 1174 $ hg id
1175 1175 925c17564ef8 tip
1176 1176 $ hg -R s id
1177 1177 12a213df6fa9 tip
1178 1178 $ hg -R t id
1179 1179 52c0adc0515a tip
1180 1180 $ hg update 11
1181 1181 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1182 1182 $ hg id
1183 1183 365661e5936a
1184 1184 $ hg -R s id
1185 1185 fc627a69481f
1186 1186 $ hg -R t id
1187 1187 e95bcfa18a35
1188 1188
1189 1189 Sticky subrepositories, file changes
1190 1190 $ touch s/f1
1191 1191 $ touch t/f1
1192 1192 $ hg add -S s/f1
1193 1193 $ hg add -S t/f1
1194 1194 $ hg id
1195 1195 365661e5936a+
1196 1196 $ hg -R s id
1197 1197 fc627a69481f+
1198 1198 $ hg -R t id
1199 1199 e95bcfa18a35+
1200 1200 $ hg update tip
1201 1201 subrepository s diverged (local revision: fc627a69481f, remote revision: 12a213df6fa9)
1202 1202 (M)erge, keep (l)ocal or keep (r)emote? m
1203 1203 subrepository sources for s differ
1204 1204 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)? l
1205 1205 subrepository t diverged (local revision: e95bcfa18a35, remote revision: 52c0adc0515a)
1206 1206 (M)erge, keep (l)ocal or keep (r)emote? m
1207 1207 subrepository sources for t differ
1208 1208 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)? l
1209 1209 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1210 1210 $ hg id
1211 1211 925c17564ef8+ tip
1212 1212 $ hg -R s id
1213 1213 fc627a69481f+
1214 1214 $ hg -R t id
1215 1215 e95bcfa18a35+
1216 1216 $ hg update --clean tip
1217 1217 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1218 1218
1219 1219 Sticky subrepository, revision updates
1220 1220 $ hg id
1221 1221 925c17564ef8 tip
1222 1222 $ hg -R s id
1223 1223 12a213df6fa9 tip
1224 1224 $ hg -R t id
1225 1225 52c0adc0515a tip
1226 1226 $ cd s
1227 1227 $ hg update -r -2
1228 1228 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1229 1229 $ cd ../t
1230 1230 $ hg update -r 2
1231 1231 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1232 1232 $ cd ..
1233 1233 $ hg update 10
1234 1234 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
1235 1235 (M)erge, keep (l)ocal or keep (r)emote? m
1236 1236 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 20a0db6fbf6c)
1237 1237 (M)erge, keep (l)ocal or keep (r)emote? m
1238 1238 subrepository sources for t differ (in checked out version)
1239 1239 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)? l
1240 1240 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1241 1241 $ hg id
1242 1242 e45c8b14af55+
1243 1243 $ hg -R s id
1244 1244 02dcf1d70411
1245 1245 $ hg -R t id
1246 1246 7af322bc1198
1247 1247
1248 1248 Sticky subrepository, file changes and revision updates
1249 1249 $ touch s/f1
1250 1250 $ touch t/f1
1251 1251 $ hg add -S s/f1
1252 1252 $ hg add -S t/f1
1253 1253 $ hg id
1254 1254 e45c8b14af55+
1255 1255 $ hg -R s id
1256 1256 02dcf1d70411+
1257 1257 $ hg -R t id
1258 1258 7af322bc1198+
1259 1259 $ hg update tip
1260 1260 subrepository s diverged (local revision: 12a213df6fa9, remote revision: 12a213df6fa9)
1261 1261 (M)erge, keep (l)ocal or keep (r)emote? m
1262 1262 subrepository sources for s differ
1263 1263 use (l)ocal source (02dcf1d70411) or (r)emote source (12a213df6fa9)? l
1264 1264 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 52c0adc0515a)
1265 1265 (M)erge, keep (l)ocal or keep (r)emote? m
1266 1266 subrepository sources for t differ
1267 1267 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)? l
1268 1268 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1269 1269 $ hg id
1270 1270 925c17564ef8+ tip
1271 1271 $ hg -R s id
1272 1272 02dcf1d70411+
1273 1273 $ hg -R t id
1274 1274 7af322bc1198+
1275 1275
1276 1276 Sticky repository, update --clean
1277 1277 $ hg update --clean tip
1278 1278 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1279 1279 $ hg id
1280 1280 925c17564ef8 tip
1281 1281 $ hg -R s id
1282 1282 12a213df6fa9 tip
1283 1283 $ hg -R t id
1284 1284 52c0adc0515a tip
1285 1285
1286 1286 Test subrepo already at intended revision:
1287 1287 $ cd s
1288 1288 $ hg update fc627a69481f
1289 1289 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1290 1290 $ cd ..
1291 1291 $ hg update 11
1292 1292 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
1293 1293 (M)erge, keep (l)ocal or keep (r)emote? m
1294 1294 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1295 1295 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1296 1296 $ hg id -n
1297 1297 11+
1298 1298 $ hg -R s id
1299 1299 fc627a69481f
1300 1300 $ hg -R t id
1301 1301 e95bcfa18a35
1302 1302
1303 1303 Test that removing .hgsubstate doesn't break anything:
1304 1304
1305 1305 $ hg rm -f .hgsubstate
1306 1306 $ hg ci -mrm
1307 1307 nothing changed
1308 1308 [1]
1309 1309 $ hg log -vr tip
1310 1310 changeset: 13:925c17564ef8
1311 1311 tag: tip
1312 1312 user: test
1313 1313 date: Thu Jan 01 00:00:00 1970 +0000
1314 1314 files: .hgsubstate
1315 1315 description:
1316 1316 13
1317 1317
1318 1318
1319 1319
1320 1320 Test that removing .hgsub removes .hgsubstate:
1321 1321
1322 1322 $ hg rm .hgsub
1323 1323 $ hg ci -mrm2
1324 1324 created new head
1325 1325 $ hg log -vr tip
1326 1326 changeset: 14:2400bccd50af
1327 1327 tag: tip
1328 1328 parent: 11:365661e5936a
1329 1329 user: test
1330 1330 date: Thu Jan 01 00:00:00 1970 +0000
1331 1331 files: .hgsub .hgsubstate
1332 1332 description:
1333 1333 rm2
1334 1334
1335 1335
1336 1336 Test issue3153: diff -S with deleted subrepos
1337 1337
1338 1338 $ hg diff --nodates -S -c .
1339 1339 diff -r 365661e5936a -r 2400bccd50af .hgsub
1340 1340 --- a/.hgsub
1341 1341 +++ /dev/null
1342 1342 @@ -1,2 +0,0 @@
1343 1343 -s = s
1344 1344 -t = t
1345 1345 diff -r 365661e5936a -r 2400bccd50af .hgsubstate
1346 1346 --- a/.hgsubstate
1347 1347 +++ /dev/null
1348 1348 @@ -1,2 +0,0 @@
1349 1349 -fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1350 1350 -e95bcfa18a358dc4936da981ebf4147b4cad1362 t
1351 1351
1352 1352 Test behavior of add for explicit path in subrepo:
1353 1353 $ cd ..
1354 1354 $ hg init explicit
1355 1355 $ cd explicit
1356 1356 $ echo s = s > .hgsub
1357 1357 $ hg add .hgsub
1358 1358 $ hg init s
1359 1359 $ hg ci -m0
1360 1360 Adding with an explicit path in a subrepo adds the file
1361 1361 $ echo c1 > f1
1362 1362 $ echo c2 > s/f2
1363 1363 $ hg st -S
1364 1364 ? f1
1365 1365 ? s/f2
1366 1366 $ hg add s/f2
1367 1367 $ hg st -S
1368 1368 A s/f2
1369 1369 ? f1
1370 1370 $ hg ci -R s -m0
1371 1371 $ hg ci -Am1
1372 1372 adding f1
1373 1373 Adding with an explicit path in a subrepo with -S has the same behavior
1374 1374 $ echo c3 > f3
1375 1375 $ echo c4 > s/f4
1376 1376 $ hg st -S
1377 1377 ? f3
1378 1378 ? s/f4
1379 1379 $ hg add -S s/f4
1380 1380 $ hg st -S
1381 1381 A s/f4
1382 1382 ? f3
1383 1383 $ hg ci -R s -m1
1384 1384 $ hg ci -Ama2
1385 1385 adding f3
1386 1386 Adding without a path or pattern silently ignores subrepos
1387 1387 $ echo c5 > f5
1388 1388 $ echo c6 > s/f6
1389 1389 $ echo c7 > s/f7
1390 1390 $ hg st -S
1391 1391 ? f5
1392 1392 ? s/f6
1393 1393 ? s/f7
1394 1394 $ hg add
1395 1395 adding f5
1396 1396 $ hg st -S
1397 1397 A f5
1398 1398 ? s/f6
1399 1399 ? s/f7
1400 1400 $ hg ci -R s -Am2
1401 1401 adding f6
1402 1402 adding f7
1403 1403 $ hg ci -m3
1404 1404 Adding without a path or pattern with -S also adds files in subrepos
1405 1405 $ echo c8 > f8
1406 1406 $ echo c9 > s/f9
1407 1407 $ echo c10 > s/f10
1408 1408 $ hg st -S
1409 1409 ? f8
1410 1410 ? s/f10
1411 1411 ? s/f9
1412 1412 $ hg add -S
1413 1413 adding f8
1414 1414 adding s/f10 (glob)
1415 1415 adding s/f9 (glob)
1416 1416 $ hg st -S
1417 1417 A f8
1418 1418 A s/f10
1419 1419 A s/f9
1420 1420 $ hg ci -R s -m3
1421 1421 $ hg ci -m4
1422 1422 Adding with a pattern silently ignores subrepos
1423 1423 $ echo c11 > fm11
1424 1424 $ echo c12 > fn12
1425 1425 $ echo c13 > s/fm13
1426 1426 $ echo c14 > s/fn14
1427 1427 $ hg st -S
1428 1428 ? fm11
1429 1429 ? fn12
1430 1430 ? s/fm13
1431 1431 ? s/fn14
1432 1432 $ hg add 'glob:**fm*'
1433 1433 adding fm11
1434 1434 $ hg st -S
1435 1435 A fm11
1436 1436 ? fn12
1437 1437 ? s/fm13
1438 1438 ? s/fn14
1439 1439 $ hg ci -R s -Am4
1440 1440 adding fm13
1441 1441 adding fn14
1442 1442 $ hg ci -Am5
1443 1443 adding fn12
1444 1444 Adding with a pattern with -S also adds matches in subrepos
1445 1445 $ echo c15 > fm15
1446 1446 $ echo c16 > fn16
1447 1447 $ echo c17 > s/fm17
1448 1448 $ echo c18 > s/fn18
1449 1449 $ hg st -S
1450 1450 ? fm15
1451 1451 ? fn16
1452 1452 ? s/fm17
1453 1453 ? s/fn18
1454 1454 $ hg add -S 'glob:**fm*'
1455 1455 adding fm15
1456 1456 adding s/fm17 (glob)
1457 1457 $ hg st -S
1458 1458 A fm15
1459 1459 A s/fm17
1460 1460 ? fn16
1461 1461 ? s/fn18
1462 1462 $ hg ci -R s -Am5
1463 1463 adding fn18
1464 1464 $ hg ci -Am6
1465 1465 adding fn16
1466 1466
1467 1467 Test behavior of forget for explicit path in subrepo:
1468 1468 Forgetting an explicit path in a subrepo untracks the file
1469 1469 $ echo c19 > s/f19
1470 1470 $ hg add s/f19
1471 1471 $ hg st -S
1472 1472 A s/f19
1473 1473 $ hg forget s/f19
1474 1474 $ hg st -S
1475 1475 ? s/f19
1476 1476 $ rm s/f19
1477 1477 $ cd ..
1478 1478
1479 1479 Courtesy phases synchronisation to publishing server does not block the push
1480 1480 (issue3781)
1481 1481
1482 1482 $ cp -r main issue3781
1483 1483 $ cp -r main issue3781-dest
1484 1484 $ cd issue3781-dest/s
1485 1485 $ hg phase tip # show we have draft changeset
1486 1486 5: draft
1487 1487 $ chmod a-w .hg/store/phaseroots # prevent phase push
1488 1488 $ cd ../../issue3781
1489 1489 $ cat >> .hg/hgrc << EOF
1490 1490 > [paths]
1491 1491 > default=../issue3781-dest/
1492 1492 > EOF
1493 1493 $ hg push --config experimental.bundle2-exp=False
1494 1494 pushing to $TESTTMP/issue3781-dest (glob)
1495 1495 pushing subrepo s to $TESTTMP/issue3781-dest/s
1496 1496 searching for changes
1497 1497 no changes found
1498 1498 searching for changes
1499 1499 no changes found
1500 1500 [1]
1501 1501 # clean the push cache
1502 1502 $ rm s/.hg/cache/storehash/*
1503 1503 $ hg push --config experimental.bundle2-exp=True
1504 1504 pushing to $TESTTMP/issue3781-dest (glob)
1505 1505 pushing subrepo s to $TESTTMP/issue3781-dest/s
1506 1506 searching for changes
1507 1507 no changes found
1508 1508 searching for changes
1509 1509 no changes found
1510 1510 [1]
1511 1511 $ cd ..
1512 1512
1513 1513 Test phase choice for newly created commit with "phases.subrepochecks"
1514 1514 configuration
1515 1515
1516 1516 $ cd t
1517 1517 $ hg update -q -r 12
1518 1518
1519 1519 $ cat >> s/ss/.hg/hgrc <<EOF
1520 1520 > [phases]
1521 1521 > new-commit = secret
1522 1522 > EOF
1523 1523 $ cat >> s/.hg/hgrc <<EOF
1524 1524 > [phases]
1525 1525 > new-commit = draft
1526 1526 > EOF
1527 1527 $ echo phasecheck1 >> s/ss/a
1528 1528 $ hg -R s commit -S --config phases.checksubrepos=abort -m phasecheck1
1529 1529 committing subrepository ss
1530 1530 transaction abort!
1531 1531 rollback completed
1532 1532 abort: can't commit in draft phase conflicting secret from subrepository ss
1533 1533 [255]
1534 1534 $ echo phasecheck2 >> s/ss/a
1535 1535 $ hg -R s commit -S --config phases.checksubrepos=ignore -m phasecheck2
1536 1536 committing subrepository ss
1537 1537 $ hg -R s/ss phase tip
1538 1538 3: secret
1539 1539 $ hg -R s phase tip
1540 1540 6: draft
1541 1541 $ echo phasecheck3 >> s/ss/a
1542 1542 $ hg -R s commit -S -m phasecheck3
1543 1543 committing subrepository ss
1544 1544 warning: changes are committed in secret phase from subrepository ss
1545 1545 $ hg -R s/ss phase tip
1546 1546 4: secret
1547 1547 $ hg -R s phase tip
1548 1548 7: secret
1549 1549
1550 1550 $ cat >> t/.hg/hgrc <<EOF
1551 1551 > [phases]
1552 1552 > new-commit = draft
1553 1553 > EOF
1554 1554 $ cat >> .hg/hgrc <<EOF
1555 1555 > [phases]
1556 1556 > new-commit = public
1557 1557 > EOF
1558 1558 $ echo phasecheck4 >> s/ss/a
1559 1559 $ echo phasecheck4 >> t/t
1560 1560 $ hg commit -S -m phasecheck4
1561 1561 committing subrepository s
1562 1562 committing subrepository s/ss (glob)
1563 1563 warning: changes are committed in secret phase from subrepository ss
1564 1564 committing subrepository t
1565 1565 warning: changes are committed in secret phase from subrepository s
1566 1566 created new head
1567 1567 $ hg -R s/ss phase tip
1568 1568 5: secret
1569 1569 $ hg -R s phase tip
1570 1570 8: secret
1571 1571 $ hg -R t phase tip
1572 1572 6: draft
1573 1573 $ hg phase tip
1574 1574 15: secret
1575 1575
1576 1576 $ cd ..
1577 1577
1578 1578
1579 1579 Test that commit --secret works on both repo and subrepo (issue4182)
1580 1580
1581 1581 $ cd main
1582 1582 $ echo secret >> b
1583 1583 $ echo secret >> s/b
1584 1584 $ hg commit --secret --subrepo -m "secret"
1585 1585 committing subrepository s
1586 1586 $ hg phase -r .
1587 1587 6: secret
1588 1588 $ cd s
1589 1589 $ hg phase -r .
1590 1590 6: secret
1591 1591 $ cd ../../
1592 1592
1593 1593 Test "subrepos" template keyword
1594 1594
1595 1595 $ cd t
1596 1596 $ hg update -q 15
1597 1597 $ cat > .hgsub <<EOF
1598 1598 > s = s
1599 1599 > EOF
1600 1600 $ hg commit -m "16"
1601 1601 warning: changes are committed in secret phase from subrepository s
1602 1602
1603 1603 (addition of ".hgsub" itself)
1604 1604
1605 1605 $ hg diff --nodates -c 1 .hgsubstate
1606 1606 diff -r f7b1eb17ad24 -r 7cf8cfea66e4 .hgsubstate
1607 1607 --- /dev/null
1608 1608 +++ b/.hgsubstate
1609 1609 @@ -0,0 +1,1 @@
1610 1610 +e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1611 1611 $ hg log -r 1 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1612 1612 f7b1eb17ad24 000000000000
1613 1613 s
1614 1614
1615 1615 (modification of existing entry)
1616 1616
1617 1617 $ hg diff --nodates -c 2 .hgsubstate
1618 1618 diff -r 7cf8cfea66e4 -r df30734270ae .hgsubstate
1619 1619 --- a/.hgsubstate
1620 1620 +++ b/.hgsubstate
1621 1621 @@ -1,1 +1,1 @@
1622 1622 -e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1623 1623 +dc73e2e6d2675eb2e41e33c205f4bdab4ea5111d s
1624 1624 $ hg log -r 2 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1625 1625 7cf8cfea66e4 000000000000
1626 1626 s
1627 1627
1628 1628 (addition of entry)
1629 1629
1630 1630 $ hg diff --nodates -c 5 .hgsubstate
1631 1631 diff -r 7cf8cfea66e4 -r 1f14a2e2d3ec .hgsubstate
1632 1632 --- a/.hgsubstate
1633 1633 +++ b/.hgsubstate
1634 1634 @@ -1,1 +1,2 @@
1635 1635 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1636 1636 +60ca1237c19474e7a3978b0dc1ca4e6f36d51382 t
1637 1637 $ hg log -r 5 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1638 1638 7cf8cfea66e4 000000000000
1639 1639 t
1640 1640
1641 1641 (removal of existing entry)
1642 1642
1643 1643 $ hg diff --nodates -c 16 .hgsubstate
1644 1644 diff -r 8bec38d2bd0b -r f2f70bc3d3c9 .hgsubstate
1645 1645 --- a/.hgsubstate
1646 1646 +++ b/.hgsubstate
1647 1647 @@ -1,2 +1,1 @@
1648 1648 0731af8ca9423976d3743119d0865097c07bdc1b s
1649 1649 -e202dc79b04c88a636ea8913d9182a1346d9b3dc t
1650 1650 $ hg log -r 16 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1651 1651 8bec38d2bd0b 000000000000
1652 1652 t
1653 1653
1654 1654 (merging)
1655 1655
1656 1656 $ hg diff --nodates -c 9 .hgsubstate
1657 1657 diff -r f6affe3fbfaa -r f0d2028bf86d .hgsubstate
1658 1658 --- a/.hgsubstate
1659 1659 +++ b/.hgsubstate
1660 1660 @@ -1,1 +1,2 @@
1661 1661 fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1662 1662 +60ca1237c19474e7a3978b0dc1ca4e6f36d51382 t
1663 1663 $ hg log -r 9 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1664 1664 f6affe3fbfaa 1f14a2e2d3ec
1665 1665 t
1666 1666
1667 1667 (removal of ".hgsub" itself)
1668 1668
1669 1669 $ hg diff --nodates -c 8 .hgsubstate
1670 1670 diff -r f94576341bcf -r 96615c1dad2d .hgsubstate
1671 1671 --- a/.hgsubstate
1672 1672 +++ /dev/null
1673 1673 @@ -1,2 +0,0 @@
1674 1674 -e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1675 1675 -7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4 t
1676 1676 $ hg log -r 8 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1677 1677 f94576341bcf 000000000000
1678 1678
1679 1679 Test that '[paths]' is configured correctly at subrepo creation
1680 1680
1681 1681 $ cd $TESTTMP/tc
1682 1682 $ cat > .hgsub <<EOF
1683 1683 > # to clear bogus subrepo path 'bogus=[boguspath'
1684 1684 > s = s
1685 1685 > t = t
1686 1686 > EOF
1687 1687 $ hg update -q --clean null
1688 1688 $ rm -rf s t
1689 1689 $ cat >> .hg/hgrc <<EOF
1690 1690 > [paths]
1691 1691 > default-push = /foo/bar
1692 1692 > EOF
1693 1693 $ hg update -q
1694 1694 $ cat s/.hg/hgrc
1695 1695 [paths]
1696 1696 default = $TESTTMP/t/s
1697 1697 default-push = /foo/bar/s
1698 1698 $ cat s/ss/.hg/hgrc
1699 1699 [paths]
1700 1700 default = $TESTTMP/t/s/ss
1701 1701 default-push = /foo/bar/s/ss
1702 1702 $ cat t/.hg/hgrc
1703 1703 [paths]
1704 1704 default = $TESTTMP/t/t
1705 1705 default-push = /foo/bar/t
1706
1707 $ cd $TESTTMP/t
1708 $ hg up -qC 0
1709 $ echo 'bar' > bar.txt
1710 $ hg ci -Am 'branch before subrepo add'
1711 adding bar.txt
1712 created new head
1713 $ hg merge -r "first(subrepo('s'))"
1714 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1715 (branch merge, don't forget to commit)
1716 $ hg status -S -X '.hgsub*'
1717 A s/a
1718 ? s/b
1719 ? s/c
1720 ? s/f1
1721 $ hg status -S --rev 'p2()'
1722 A bar.txt
1723 ? s/b
1724 ? s/c
1725 ? s/f1
1726 $ hg diff -S -X '.hgsub*' --nodates
1727 diff -r 000000000000 s/a
1728 --- /dev/null
1729 +++ b/s/a
1730 @@ -0,0 +1,1 @@
1731 +a
1732 $ hg diff -S --rev 'p2()' --nodates
1733 diff -r 7cf8cfea66e4 bar.txt
1734 --- /dev/null
1735 +++ b/bar.txt
1736 @@ -0,0 +1,1 @@
1737 +bar
1738
1706 1739 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now