##// END OF EJS Templates
subrepo: append subrepo path to subrepo error messages...
Angel Ezquerra -
r18109:9e3910db default
parent child Browse files
Show More
@@ -1,1281 +1,1325 b''
1 1 # subrepo.py - sub-repository handling for Mercurial
2 2 #
3 3 # Copyright 2009-2010 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 import errno, os, re, xml.dom.minidom, shutil, posixpath
9 9 import stat, subprocess, tarfile
10 10 from i18n import _
11 11 import config, scmutil, util, node, error, cmdutil, bookmarks, match as matchmod
12 12 hg = None
13 13 propertycache = util.propertycache
14 14
15 15 nullstate = ('', '', 'empty')
16 16
17 class SubrepoAbort(error.Abort):
18 """Exception class used to avoid handling a subrepo error more than once"""
19
20 def annotatesubrepoerror(func):
21 def decoratedmethod(self, *args, **kargs):
22 try:
23 res = func(self, *args, **kargs)
24 except SubrepoAbort, ex:
25 # This exception has already been handled
26 raise ex
27 except error.Abort, ex:
28 errormsg = _('%s (in subrepo %s)') % (str(ex), subrelpath(self))
29 # avoid handling this exception by raising a SubrepoAbort exception
30 raise SubrepoAbort(errormsg, hint=ex.hint)
31 return res
32 return decoratedmethod
33
17 34 def state(ctx, ui):
18 35 """return a state dict, mapping subrepo paths configured in .hgsub
19 36 to tuple: (source from .hgsub, revision from .hgsubstate, kind
20 37 (key in types dict))
21 38 """
22 39 p = config.config()
23 40 def read(f, sections=None, remap=None):
24 41 if f in ctx:
25 42 try:
26 43 data = ctx[f].data()
27 44 except IOError, err:
28 45 if err.errno != errno.ENOENT:
29 46 raise
30 47 # handle missing subrepo spec files as removed
31 48 ui.warn(_("warning: subrepo spec file %s not found\n") % f)
32 49 return
33 50 p.parse(f, data, sections, remap, read)
34 51 else:
35 52 raise util.Abort(_("subrepo spec file %s not found") % f)
36 53
37 54 if '.hgsub' in ctx:
38 55 read('.hgsub')
39 56
40 57 for path, src in ui.configitems('subpaths'):
41 58 p.set('subpaths', path, src, ui.configsource('subpaths', path))
42 59
43 60 rev = {}
44 61 if '.hgsubstate' in ctx:
45 62 try:
46 63 for i, l in enumerate(ctx['.hgsubstate'].data().splitlines()):
47 64 l = l.lstrip()
48 65 if not l:
49 66 continue
50 67 try:
51 68 revision, path = l.split(" ", 1)
52 69 except ValueError:
53 70 raise util.Abort(_("invalid subrepository revision "
54 71 "specifier in .hgsubstate line %d")
55 72 % (i + 1))
56 73 rev[path] = revision
57 74 except IOError, err:
58 75 if err.errno != errno.ENOENT:
59 76 raise
60 77
61 78 def remap(src):
62 79 for pattern, repl in p.items('subpaths'):
63 80 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
64 81 # does a string decode.
65 82 repl = repl.encode('string-escape')
66 83 # However, we still want to allow back references to go
67 84 # through unharmed, so we turn r'\\1' into r'\1'. Again,
68 85 # extra escapes are needed because re.sub string decodes.
69 86 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
70 87 try:
71 88 src = re.sub(pattern, repl, src, 1)
72 89 except re.error, e:
73 90 raise util.Abort(_("bad subrepository pattern in %s: %s")
74 91 % (p.source('subpaths', pattern), e))
75 92 return src
76 93
77 94 state = {}
78 95 for path, src in p[''].items():
79 96 kind = 'hg'
80 97 if src.startswith('['):
81 98 if ']' not in src:
82 99 raise util.Abort(_('missing ] in subrepo source'))
83 100 kind, src = src.split(']', 1)
84 101 kind = kind[1:]
85 102 src = src.lstrip() # strip any extra whitespace after ']'
86 103
87 104 if not util.url(src).isabs():
88 105 parent = _abssource(ctx._repo, abort=False)
89 106 if parent:
90 107 parent = util.url(parent)
91 108 parent.path = posixpath.join(parent.path or '', src)
92 109 parent.path = posixpath.normpath(parent.path)
93 110 joined = str(parent)
94 111 # Remap the full joined path and use it if it changes,
95 112 # else remap the original source.
96 113 remapped = remap(joined)
97 114 if remapped == joined:
98 115 src = remap(src)
99 116 else:
100 117 src = remapped
101 118
102 119 src = remap(src)
103 120 state[util.pconvert(path)] = (src.strip(), rev.get(path, ''), kind)
104 121
105 122 return state
106 123
107 124 def writestate(repo, state):
108 125 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
109 126 lines = ['%s %s\n' % (state[s][1], s) for s in sorted(state)]
110 127 repo.wwrite('.hgsubstate', ''.join(lines), '')
111 128
112 129 def submerge(repo, wctx, mctx, actx, overwrite):
113 130 """delegated from merge.applyupdates: merging of .hgsubstate file
114 131 in working context, merging context and ancestor context"""
115 132 if mctx == actx: # backwards?
116 133 actx = wctx.p1()
117 134 s1 = wctx.substate
118 135 s2 = mctx.substate
119 136 sa = actx.substate
120 137 sm = {}
121 138
122 139 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
123 140
124 141 def debug(s, msg, r=""):
125 142 if r:
126 143 r = "%s:%s:%s" % r
127 144 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
128 145
129 146 for s, l in s1.items():
130 147 a = sa.get(s, nullstate)
131 148 ld = l # local state with possible dirty flag for compares
132 149 if wctx.sub(s).dirty():
133 150 ld = (l[0], l[1] + "+")
134 151 if wctx == actx: # overwrite
135 152 a = ld
136 153
137 154 if s in s2:
138 155 r = s2[s]
139 156 if ld == r or r == a: # no change or local is newer
140 157 sm[s] = l
141 158 continue
142 159 elif ld == a: # other side changed
143 160 debug(s, "other changed, get", r)
144 161 wctx.sub(s).get(r, overwrite)
145 162 sm[s] = r
146 163 elif ld[0] != r[0]: # sources differ
147 164 if repo.ui.promptchoice(
148 165 _(' subrepository sources for %s differ\n'
149 166 'use (l)ocal source (%s) or (r)emote source (%s)?')
150 167 % (s, l[0], r[0]),
151 168 (_('&Local'), _('&Remote')), 0):
152 169 debug(s, "prompt changed, get", r)
153 170 wctx.sub(s).get(r, overwrite)
154 171 sm[s] = r
155 172 elif ld[1] == a[1]: # local side is unchanged
156 173 debug(s, "other side changed, get", r)
157 174 wctx.sub(s).get(r, overwrite)
158 175 sm[s] = r
159 176 else:
160 177 debug(s, "both sides changed, merge with", r)
161 178 wctx.sub(s).merge(r)
162 179 sm[s] = l
163 180 elif ld == a: # remote removed, local unchanged
164 181 debug(s, "remote removed, remove")
165 182 wctx.sub(s).remove()
166 183 elif a == nullstate: # not present in remote or ancestor
167 184 debug(s, "local added, keep")
168 185 sm[s] = l
169 186 continue
170 187 else:
171 188 if repo.ui.promptchoice(
172 189 _(' local changed subrepository %s which remote removed\n'
173 190 'use (c)hanged version or (d)elete?') % s,
174 191 (_('&Changed'), _('&Delete')), 0):
175 192 debug(s, "prompt remove")
176 193 wctx.sub(s).remove()
177 194
178 195 for s, r in sorted(s2.items()):
179 196 if s in s1:
180 197 continue
181 198 elif s not in sa:
182 199 debug(s, "remote added, get", r)
183 200 mctx.sub(s).get(r)
184 201 sm[s] = r
185 202 elif r != sa[s]:
186 203 if repo.ui.promptchoice(
187 204 _(' remote changed subrepository %s which local removed\n'
188 205 'use (c)hanged version or (d)elete?') % s,
189 206 (_('&Changed'), _('&Delete')), 0) == 0:
190 207 debug(s, "prompt recreate", r)
191 208 wctx.sub(s).get(r)
192 209 sm[s] = r
193 210
194 211 # record merged .hgsubstate
195 212 writestate(repo, sm)
196 213
197 214 def _updateprompt(ui, sub, dirty, local, remote):
198 215 if dirty:
199 216 msg = (_(' subrepository sources for %s differ\n'
200 217 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
201 218 % (subrelpath(sub), local, remote))
202 219 else:
203 220 msg = (_(' subrepository sources for %s differ (in checked out '
204 221 'version)\n'
205 222 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
206 223 % (subrelpath(sub), local, remote))
207 224 return ui.promptchoice(msg, (_('&Local'), _('&Remote')), 0)
208 225
209 226 def reporelpath(repo):
210 227 """return path to this (sub)repo as seen from outermost repo"""
211 228 parent = repo
212 229 while util.safehasattr(parent, '_subparent'):
213 230 parent = parent._subparent
214 231 p = parent.root.rstrip(os.sep)
215 232 return repo.root[len(p) + 1:]
216 233
217 234 def subrelpath(sub):
218 235 """return path to this subrepo as seen from outermost repo"""
219 236 if util.safehasattr(sub, '_relpath'):
220 237 return sub._relpath
221 238 if not util.safehasattr(sub, '_repo'):
222 239 return sub._path
223 240 return reporelpath(sub._repo)
224 241
225 242 def _abssource(repo, push=False, abort=True):
226 243 """return pull/push path of repo - either based on parent repo .hgsub info
227 244 or on the top repo config. Abort or return None if no source found."""
228 245 if util.safehasattr(repo, '_subparent'):
229 246 source = util.url(repo._subsource)
230 247 if source.isabs():
231 248 return str(source)
232 249 source.path = posixpath.normpath(source.path)
233 250 parent = _abssource(repo._subparent, push, abort=False)
234 251 if parent:
235 252 parent = util.url(util.pconvert(parent))
236 253 parent.path = posixpath.join(parent.path or '', source.path)
237 254 parent.path = posixpath.normpath(parent.path)
238 255 return str(parent)
239 256 else: # recursion reached top repo
240 257 if util.safehasattr(repo, '_subtoppath'):
241 258 return repo._subtoppath
242 259 if push and repo.ui.config('paths', 'default-push'):
243 260 return repo.ui.config('paths', 'default-push')
244 261 if repo.ui.config('paths', 'default'):
245 262 return repo.ui.config('paths', 'default')
246 263 if abort:
247 raise util.Abort(_("default path for subrepository %s not found") %
248 reporelpath(repo))
264 raise util.Abort(_("default path for subrepository not found"))
249 265
250 266 def itersubrepos(ctx1, ctx2):
251 267 """find subrepos in ctx1 or ctx2"""
252 268 # Create a (subpath, ctx) mapping where we prefer subpaths from
253 269 # ctx1. The subpaths from ctx2 are important when the .hgsub file
254 270 # has been modified (in ctx2) but not yet committed (in ctx1).
255 271 subpaths = dict.fromkeys(ctx2.substate, ctx2)
256 272 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
257 273 for subpath, ctx in sorted(subpaths.iteritems()):
258 274 yield subpath, ctx.sub(subpath)
259 275
260 276 def subrepo(ctx, path):
261 277 """return instance of the right subrepo class for subrepo in path"""
262 278 # subrepo inherently violates our import layering rules
263 279 # because it wants to make repo objects from deep inside the stack
264 280 # so we manually delay the circular imports to not break
265 281 # scripts that don't use our demand-loading
266 282 global hg
267 283 import hg as h
268 284 hg = h
269 285
270 286 scmutil.pathauditor(ctx._repo.root)(path)
271 287 state = ctx.substate[path]
272 288 if state[2] not in types:
273 289 raise util.Abort(_('unknown subrepo type %s') % state[2])
274 290 return types[state[2]](ctx, path, state[:2])
275 291
276 292 # subrepo classes need to implement the following abstract class:
277 293
278 294 class abstractsubrepo(object):
279 295
280 296 def dirty(self, ignoreupdate=False):
281 297 """returns true if the dirstate of the subrepo is dirty or does not
282 298 match current stored state. If ignoreupdate is true, only check
283 299 whether the subrepo has uncommitted changes in its dirstate.
284 300 """
285 301 raise NotImplementedError
286 302
287 303 def basestate(self):
288 304 """current working directory base state, disregarding .hgsubstate
289 305 state and working directory modifications"""
290 306 raise NotImplementedError
291 307
292 308 def checknested(self, path):
293 309 """check if path is a subrepository within this repository"""
294 310 return False
295 311
296 312 def commit(self, text, user, date):
297 313 """commit the current changes to the subrepo with the given
298 314 log message. Use given user and date if possible. Return the
299 315 new state of the subrepo.
300 316 """
301 317 raise NotImplementedError
302 318
303 319 def remove(self):
304 320 """remove the subrepo
305 321
306 322 (should verify the dirstate is not dirty first)
307 323 """
308 324 raise NotImplementedError
309 325
310 326 def get(self, state, overwrite=False):
311 327 """run whatever commands are needed to put the subrepo into
312 328 this state
313 329 """
314 330 raise NotImplementedError
315 331
316 332 def merge(self, state):
317 333 """merge currently-saved state with the new state."""
318 334 raise NotImplementedError
319 335
320 336 def push(self, opts):
321 337 """perform whatever action is analogous to 'hg push'
322 338
323 339 This may be a no-op on some systems.
324 340 """
325 341 raise NotImplementedError
326 342
327 343 def add(self, ui, match, dryrun, listsubrepos, prefix, explicitonly):
328 344 return []
329 345
330 346 def status(self, rev2, **opts):
331 347 return [], [], [], [], [], [], []
332 348
333 349 def diff(self, ui, diffopts, node2, match, prefix, **opts):
334 350 pass
335 351
336 352 def outgoing(self, ui, dest, opts):
337 353 return 1
338 354
339 355 def incoming(self, ui, source, opts):
340 356 return 1
341 357
342 358 def files(self):
343 359 """return filename iterator"""
344 360 raise NotImplementedError
345 361
346 362 def filedata(self, name):
347 363 """return file data"""
348 364 raise NotImplementedError
349 365
350 366 def fileflags(self, name):
351 367 """return file flags"""
352 368 return ''
353 369
354 370 def archive(self, ui, archiver, prefix, match=None):
355 371 if match is not None:
356 372 files = [f for f in self.files() if match(f)]
357 373 else:
358 374 files = self.files()
359 375 total = len(files)
360 376 relpath = subrelpath(self)
361 377 ui.progress(_('archiving (%s)') % relpath, 0,
362 378 unit=_('files'), total=total)
363 379 for i, name in enumerate(files):
364 380 flags = self.fileflags(name)
365 381 mode = 'x' in flags and 0755 or 0644
366 382 symlink = 'l' in flags
367 383 archiver.addfile(os.path.join(prefix, self._path, name),
368 384 mode, symlink, self.filedata(name))
369 385 ui.progress(_('archiving (%s)') % relpath, i + 1,
370 386 unit=_('files'), total=total)
371 387 ui.progress(_('archiving (%s)') % relpath, None)
372 388
373 389 def walk(self, match):
374 390 '''
375 391 walk recursively through the directory tree, finding all files
376 392 matched by the match function
377 393 '''
378 394 pass
379 395
380 396 def forget(self, ui, match, prefix):
381 397 return ([], [])
382 398
383 399 def revert(self, ui, substate, *pats, **opts):
384 400 ui.warn('%s: reverting %s subrepos is unsupported\n' \
385 401 % (substate[0], substate[2]))
386 402 return []
387 403
388 404 class hgsubrepo(abstractsubrepo):
389 405 def __init__(self, ctx, path, state):
390 406 self._path = path
391 407 self._state = state
392 408 r = ctx._repo
393 409 root = r.wjoin(path)
394 410 create = False
395 411 if not os.path.exists(os.path.join(root, '.hg')):
396 412 create = True
397 413 util.makedirs(root)
398 414 self._repo = hg.repository(r.baseui, root, create=create)
399 415 for s, k in [('ui', 'commitsubrepos')]:
400 416 v = r.ui.config(s, k)
401 417 if v:
402 418 self._repo.ui.setconfig(s, k, v)
403 419 self._initrepo(r, state[0], create)
404 420
421 @annotatesubrepoerror
405 422 def _initrepo(self, parentrepo, source, create):
406 423 self._repo._subparent = parentrepo
407 424 self._repo._subsource = source
408 425
409 426 if create:
410 427 fp = self._repo.opener("hgrc", "w", text=True)
411 428 fp.write('[paths]\n')
412 429
413 430 def addpathconfig(key, value):
414 431 if value:
415 432 fp.write('%s = %s\n' % (key, value))
416 433 self._repo.ui.setconfig('paths', key, value)
417 434
418 435 defpath = _abssource(self._repo, abort=False)
419 436 defpushpath = _abssource(self._repo, True, abort=False)
420 437 addpathconfig('default', defpath)
421 438 if defpath != defpushpath:
422 439 addpathconfig('default-push', defpushpath)
423 440 fp.close()
424 441
442 @annotatesubrepoerror
425 443 def add(self, ui, match, dryrun, listsubrepos, prefix, explicitonly):
426 444 return cmdutil.add(ui, self._repo, match, dryrun, listsubrepos,
427 445 os.path.join(prefix, self._path), explicitonly)
428 446
447 @annotatesubrepoerror
429 448 def status(self, rev2, **opts):
430 449 try:
431 450 rev1 = self._state[1]
432 451 ctx1 = self._repo[rev1]
433 452 ctx2 = self._repo[rev2]
434 453 return self._repo.status(ctx1, ctx2, **opts)
435 454 except error.RepoLookupError, inst:
436 455 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
437 456 % (inst, subrelpath(self)))
438 457 return [], [], [], [], [], [], []
439 458
459 @annotatesubrepoerror
440 460 def diff(self, ui, diffopts, node2, match, prefix, **opts):
441 461 try:
442 462 node1 = node.bin(self._state[1])
443 463 # We currently expect node2 to come from substate and be
444 464 # in hex format
445 465 if node2 is not None:
446 466 node2 = node.bin(node2)
447 467 cmdutil.diffordiffstat(ui, self._repo, diffopts,
448 468 node1, node2, match,
449 469 prefix=posixpath.join(prefix, self._path),
450 470 listsubrepos=True, **opts)
451 471 except error.RepoLookupError, inst:
452 472 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
453 473 % (inst, subrelpath(self)))
454 474
475 @annotatesubrepoerror
455 476 def archive(self, ui, archiver, prefix, match=None):
456 477 self._get(self._state + ('hg',))
457 478 abstractsubrepo.archive(self, ui, archiver, prefix, match)
458 479
459 480 rev = self._state[1]
460 481 ctx = self._repo[rev]
461 482 for subpath in ctx.substate:
462 483 s = subrepo(ctx, subpath)
463 484 submatch = matchmod.narrowmatcher(subpath, match)
464 485 s.archive(ui, archiver, os.path.join(prefix, self._path), submatch)
465 486
487 @annotatesubrepoerror
466 488 def dirty(self, ignoreupdate=False):
467 489 r = self._state[1]
468 490 if r == '' and not ignoreupdate: # no state recorded
469 491 return True
470 492 w = self._repo[None]
471 493 if r != w.p1().hex() and not ignoreupdate:
472 494 # different version checked out
473 495 return True
474 496 return w.dirty() # working directory changed
475 497
476 498 def basestate(self):
477 499 return self._repo['.'].hex()
478 500
479 501 def checknested(self, path):
480 502 return self._repo._checknested(self._repo.wjoin(path))
481 503
504 @annotatesubrepoerror
482 505 def commit(self, text, user, date):
483 506 # don't bother committing in the subrepo if it's only been
484 507 # updated
485 508 if not self.dirty(True):
486 509 return self._repo['.'].hex()
487 510 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self))
488 511 n = self._repo.commit(text, user, date)
489 512 if not n:
490 513 return self._repo['.'].hex() # different version checked out
491 514 return node.hex(n)
492 515
516 @annotatesubrepoerror
493 517 def remove(self):
494 518 # we can't fully delete the repository as it may contain
495 519 # local-only history
496 520 self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
497 521 hg.clean(self._repo, node.nullid, False)
498 522
499 523 def _get(self, state):
500 524 source, revision, kind = state
501 525 if revision not in self._repo:
502 526 self._repo._subsource = source
503 527 srcurl = _abssource(self._repo)
504 528 other = hg.peer(self._repo, {}, srcurl)
505 529 if len(self._repo) == 0:
506 530 self._repo.ui.status(_('cloning subrepo %s from %s\n')
507 531 % (subrelpath(self), srcurl))
508 532 parentrepo = self._repo._subparent
509 533 shutil.rmtree(self._repo.path)
510 534 other, cloned = hg.clone(self._repo._subparent.baseui, {},
511 535 other, self._repo.root,
512 536 update=False)
513 537 self._repo = cloned.local()
514 538 self._initrepo(parentrepo, source, create=True)
515 539 else:
516 540 self._repo.ui.status(_('pulling subrepo %s from %s\n')
517 541 % (subrelpath(self), srcurl))
518 542 self._repo.pull(other)
519 543 bookmarks.updatefromremote(self._repo.ui, self._repo, other,
520 544 srcurl)
521 545
546 @annotatesubrepoerror
522 547 def get(self, state, overwrite=False):
523 548 self._get(state)
524 549 source, revision, kind = state
525 550 self._repo.ui.debug("getting subrepo %s\n" % self._path)
526 551 hg.updaterepo(self._repo, revision, overwrite)
527 552
553 @annotatesubrepoerror
528 554 def merge(self, state):
529 555 self._get(state)
530 556 cur = self._repo['.']
531 557 dst = self._repo[state[1]]
532 558 anc = dst.ancestor(cur)
533 559
534 560 def mergefunc():
535 561 if anc == cur and dst.branch() == cur.branch():
536 562 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
537 563 hg.update(self._repo, state[1])
538 564 elif anc == dst:
539 565 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
540 566 else:
541 567 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
542 568 hg.merge(self._repo, state[1], remind=False)
543 569
544 570 wctx = self._repo[None]
545 571 if self.dirty():
546 572 if anc != dst:
547 573 if _updateprompt(self._repo.ui, self, wctx.dirty(), cur, dst):
548 574 mergefunc()
549 575 else:
550 576 mergefunc()
551 577 else:
552 578 mergefunc()
553 579
580 @annotatesubrepoerror
554 581 def push(self, opts):
555 582 force = opts.get('force')
556 583 newbranch = opts.get('new_branch')
557 584 ssh = opts.get('ssh')
558 585
559 586 # push subrepos depth-first for coherent ordering
560 587 c = self._repo['']
561 588 subs = c.substate # only repos that are committed
562 589 for s in sorted(subs):
563 590 if c.sub(s).push(opts) == 0:
564 591 return False
565 592
566 593 dsturl = _abssource(self._repo, True)
567 594 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
568 595 (subrelpath(self), dsturl))
569 596 other = hg.peer(self._repo, {'ssh': ssh}, dsturl)
570 597 return self._repo.push(other, force, newbranch=newbranch)
571 598
599 @annotatesubrepoerror
572 600 def outgoing(self, ui, dest, opts):
573 601 return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
574 602
603 @annotatesubrepoerror
575 604 def incoming(self, ui, source, opts):
576 605 return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
577 606
607 @annotatesubrepoerror
578 608 def files(self):
579 609 rev = self._state[1]
580 610 ctx = self._repo[rev]
581 611 return ctx.manifest()
582 612
583 613 def filedata(self, name):
584 614 rev = self._state[1]
585 615 return self._repo[rev][name].data()
586 616
587 617 def fileflags(self, name):
588 618 rev = self._state[1]
589 619 ctx = self._repo[rev]
590 620 return ctx.flags(name)
591 621
592 622 def walk(self, match):
593 623 ctx = self._repo[None]
594 624 return ctx.walk(match)
595 625
626 @annotatesubrepoerror
596 627 def forget(self, ui, match, prefix):
597 628 return cmdutil.forget(ui, self._repo, match,
598 629 os.path.join(prefix, self._path), True)
599 630
631 @annotatesubrepoerror
600 632 def revert(self, ui, substate, *pats, **opts):
601 633 # reverting a subrepo is a 2 step process:
602 634 # 1. if the no_backup is not set, revert all modified
603 635 # files inside the subrepo
604 636 # 2. update the subrepo to the revision specified in
605 637 # the corresponding substate dictionary
606 638 ui.status(_('reverting subrepo %s\n') % substate[0])
607 639 if not opts.get('no_backup'):
608 640 # Revert all files on the subrepo, creating backups
609 641 # Note that this will not recursively revert subrepos
610 642 # We could do it if there was a set:subrepos() predicate
611 643 opts = opts.copy()
612 644 opts['date'] = None
613 645 opts['rev'] = substate[1]
614 646
615 647 pats = []
616 648 if not opts['all']:
617 649 pats = ['set:modified()']
618 650 self.filerevert(ui, *pats, **opts)
619 651
620 652 # Update the repo to the revision specified in the given substate
621 653 self.get(substate, overwrite=True)
622 654
623 655 def filerevert(self, ui, *pats, **opts):
624 656 ctx = self._repo[opts['rev']]
625 657 parents = self._repo.dirstate.parents()
626 658 if opts['all']:
627 659 pats = ['set:modified()']
628 660 else:
629 661 pats = []
630 662 cmdutil.revert(ui, self._repo, ctx, parents, *pats, **opts)
631 663
632 664 class svnsubrepo(abstractsubrepo):
633 665 def __init__(self, ctx, path, state):
634 666 self._path = path
635 667 self._state = state
636 668 self._ctx = ctx
637 669 self._ui = ctx._repo.ui
638 670 self._exe = util.findexe('svn')
639 671 if not self._exe:
640 672 raise util.Abort(_("'svn' executable not found for subrepo '%s'")
641 673 % self._path)
642 674
643 675 def _svncommand(self, commands, filename='', failok=False):
644 676 cmd = [self._exe]
645 677 extrakw = {}
646 678 if not self._ui.interactive():
647 679 # Making stdin be a pipe should prevent svn from behaving
648 680 # interactively even if we can't pass --non-interactive.
649 681 extrakw['stdin'] = subprocess.PIPE
650 682 # Starting in svn 1.5 --non-interactive is a global flag
651 683 # instead of being per-command, but we need to support 1.4 so
652 684 # we have to be intelligent about what commands take
653 685 # --non-interactive.
654 686 if commands[0] in ('update', 'checkout', 'commit'):
655 687 cmd.append('--non-interactive')
656 688 cmd.extend(commands)
657 689 if filename is not None:
658 690 path = os.path.join(self._ctx._repo.origroot, self._path, filename)
659 691 cmd.append(path)
660 692 env = dict(os.environ)
661 693 # Avoid localized output, preserve current locale for everything else.
662 694 lc_all = env.get('LC_ALL')
663 695 if lc_all:
664 696 env['LANG'] = lc_all
665 697 del env['LC_ALL']
666 698 env['LC_MESSAGES'] = 'C'
667 699 p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
668 700 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
669 701 universal_newlines=True, env=env, **extrakw)
670 702 stdout, stderr = p.communicate()
671 703 stderr = stderr.strip()
672 704 if not failok:
673 705 if p.returncode:
674 706 raise util.Abort(stderr or 'exited with code %d' % p.returncode)
675 707 if stderr:
676 708 self._ui.warn(stderr + '\n')
677 709 return stdout, stderr
678 710
679 711 @propertycache
680 712 def _svnversion(self):
681 713 output, err = self._svncommand(['--version', '--quiet'], filename=None)
682 714 m = re.search(r'^(\d+)\.(\d+)', output)
683 715 if not m:
684 716 raise util.Abort(_('cannot retrieve svn tool version'))
685 717 return (int(m.group(1)), int(m.group(2)))
686 718
687 719 def _wcrevs(self):
688 720 # Get the working directory revision as well as the last
689 721 # commit revision so we can compare the subrepo state with
690 722 # both. We used to store the working directory one.
691 723 output, err = self._svncommand(['info', '--xml'])
692 724 doc = xml.dom.minidom.parseString(output)
693 725 entries = doc.getElementsByTagName('entry')
694 726 lastrev, rev = '0', '0'
695 727 if entries:
696 728 rev = str(entries[0].getAttribute('revision')) or '0'
697 729 commits = entries[0].getElementsByTagName('commit')
698 730 if commits:
699 731 lastrev = str(commits[0].getAttribute('revision')) or '0'
700 732 return (lastrev, rev)
701 733
702 734 def _wcrev(self):
703 735 return self._wcrevs()[0]
704 736
705 737 def _wcchanged(self):
706 738 """Return (changes, extchanges, missing) where changes is True
707 739 if the working directory was changed, extchanges is
708 740 True if any of these changes concern an external entry and missing
709 741 is True if any change is a missing entry.
710 742 """
711 743 output, err = self._svncommand(['status', '--xml'])
712 744 externals, changes, missing = [], [], []
713 745 doc = xml.dom.minidom.parseString(output)
714 746 for e in doc.getElementsByTagName('entry'):
715 747 s = e.getElementsByTagName('wc-status')
716 748 if not s:
717 749 continue
718 750 item = s[0].getAttribute('item')
719 751 props = s[0].getAttribute('props')
720 752 path = e.getAttribute('path')
721 753 if item == 'external':
722 754 externals.append(path)
723 755 elif item == 'missing':
724 756 missing.append(path)
725 757 if (item not in ('', 'normal', 'unversioned', 'external')
726 758 or props not in ('', 'none', 'normal')):
727 759 changes.append(path)
728 760 for path in changes:
729 761 for ext in externals:
730 762 if path == ext or path.startswith(ext + os.sep):
731 763 return True, True, bool(missing)
732 764 return bool(changes), False, bool(missing)
733 765
734 766 def dirty(self, ignoreupdate=False):
735 767 if not self._wcchanged()[0]:
736 768 if self._state[1] in self._wcrevs() or ignoreupdate:
737 769 return False
738 770 return True
739 771
740 772 def basestate(self):
741 773 lastrev, rev = self._wcrevs()
742 774 if lastrev != rev:
743 775 # Last committed rev is not the same than rev. We would
744 776 # like to take lastrev but we do not know if the subrepo
745 777 # URL exists at lastrev. Test it and fallback to rev it
746 778 # is not there.
747 779 try:
748 780 self._svncommand(['list', '%s@%s' % (self._state[0], lastrev)])
749 781 return lastrev
750 782 except error.Abort:
751 783 pass
752 784 return rev
753 785
786 @annotatesubrepoerror
754 787 def commit(self, text, user, date):
755 788 # user and date are out of our hands since svn is centralized
756 789 changed, extchanged, missing = self._wcchanged()
757 790 if not changed:
758 791 return self.basestate()
759 792 if extchanged:
760 793 # Do not try to commit externals
761 794 raise util.Abort(_('cannot commit svn externals'))
762 795 if missing:
763 796 # svn can commit with missing entries but aborting like hg
764 797 # seems a better approach.
765 798 raise util.Abort(_('cannot commit missing svn entries'))
766 799 commitinfo, err = self._svncommand(['commit', '-m', text])
767 800 self._ui.status(commitinfo)
768 801 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
769 802 if not newrev:
770 803 if not commitinfo.strip():
771 804 # Sometimes, our definition of "changed" differs from
772 805 # svn one. For instance, svn ignores missing files
773 806 # when committing. If there are only missing files, no
774 807 # commit is made, no output and no error code.
775 808 raise util.Abort(_('failed to commit svn changes'))
776 809 raise util.Abort(commitinfo.splitlines()[-1])
777 810 newrev = newrev.groups()[0]
778 811 self._ui.status(self._svncommand(['update', '-r', newrev])[0])
779 812 return newrev
780 813
814 @annotatesubrepoerror
781 815 def remove(self):
782 816 if self.dirty():
783 817 self._ui.warn(_('not removing repo %s because '
784 818 'it has changes.\n' % self._path))
785 819 return
786 820 self._ui.note(_('removing subrepo %s\n') % self._path)
787 821
788 822 def onerror(function, path, excinfo):
789 823 if function is not os.remove:
790 824 raise
791 825 # read-only files cannot be unlinked under Windows
792 826 s = os.stat(path)
793 827 if (s.st_mode & stat.S_IWRITE) != 0:
794 828 raise
795 829 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
796 830 os.remove(path)
797 831
798 832 path = self._ctx._repo.wjoin(self._path)
799 833 shutil.rmtree(path, onerror=onerror)
800 834 try:
801 835 os.removedirs(os.path.dirname(path))
802 836 except OSError:
803 837 pass
804 838
839 @annotatesubrepoerror
805 840 def get(self, state, overwrite=False):
806 841 if overwrite:
807 842 self._svncommand(['revert', '--recursive'])
808 843 args = ['checkout']
809 844 if self._svnversion >= (1, 5):
810 845 args.append('--force')
811 846 # The revision must be specified at the end of the URL to properly
812 847 # update to a directory which has since been deleted and recreated.
813 848 args.append('%s@%s' % (state[0], state[1]))
814 849 status, err = self._svncommand(args, failok=True)
815 850 if not re.search('Checked out revision [0-9]+.', status):
816 851 if ('is already a working copy for a different URL' in err
817 852 and (self._wcchanged()[:2] == (False, False))):
818 853 # obstructed but clean working copy, so just blow it away.
819 854 self.remove()
820 855 self.get(state, overwrite=False)
821 856 return
822 857 raise util.Abort((status or err).splitlines()[-1])
823 858 self._ui.status(status)
824 859
860 @annotatesubrepoerror
825 861 def merge(self, state):
826 862 old = self._state[1]
827 863 new = state[1]
828 864 wcrev = self._wcrev()
829 865 if new != wcrev:
830 866 dirty = old == wcrev or self._wcchanged()[0]
831 867 if _updateprompt(self._ui, self, dirty, wcrev, new):
832 868 self.get(state, False)
833 869
834 870 def push(self, opts):
835 871 # push is a no-op for SVN
836 872 return True
837 873
874 @annotatesubrepoerror
838 875 def files(self):
839 876 output = self._svncommand(['list', '--recursive', '--xml'])[0]
840 877 doc = xml.dom.minidom.parseString(output)
841 878 paths = []
842 879 for e in doc.getElementsByTagName('entry'):
843 880 kind = str(e.getAttribute('kind'))
844 881 if kind != 'file':
845 882 continue
846 883 name = ''.join(c.data for c
847 884 in e.getElementsByTagName('name')[0].childNodes
848 885 if c.nodeType == c.TEXT_NODE)
849 886 paths.append(name.encode('utf-8'))
850 887 return paths
851 888
852 889 def filedata(self, name):
853 890 return self._svncommand(['cat'], name)[0]
854 891
855 892
856 893 class gitsubrepo(abstractsubrepo):
857 894 def __init__(self, ctx, path, state):
858 895 self._state = state
859 896 self._ctx = ctx
860 897 self._path = path
861 898 self._relpath = os.path.join(reporelpath(ctx._repo), path)
862 899 self._abspath = ctx._repo.wjoin(path)
863 900 self._subparent = ctx._repo
864 901 self._ui = ctx._repo.ui
865 902 self._ensuregit()
866 903
867 904 def _ensuregit(self):
868 905 try:
869 906 self._gitexecutable = 'git'
870 907 out, err = self._gitnodir(['--version'])
871 908 except OSError, e:
872 909 if e.errno != 2 or os.name != 'nt':
873 910 raise
874 911 self._gitexecutable = 'git.cmd'
875 912 out, err = self._gitnodir(['--version'])
876 913 m = re.search(r'^git version (\d+)\.(\d+)\.(\d+)', out)
877 914 if not m:
878 915 self._ui.warn(_('cannot retrieve git version'))
879 916 return
880 917 version = (int(m.group(1)), m.group(2), m.group(3))
881 918 # git 1.4.0 can't work at all, but 1.5.X can in at least some cases,
882 919 # despite the docstring comment. For now, error on 1.4.0, warn on
883 920 # 1.5.0 but attempt to continue.
884 921 if version < (1, 5, 0):
885 922 raise util.Abort(_('git subrepo requires at least 1.6.0 or later'))
886 923 elif version < (1, 6, 0):
887 924 self._ui.warn(_('git subrepo requires at least 1.6.0 or later'))
888 925
889 926 def _gitcommand(self, commands, env=None, stream=False):
890 927 return self._gitdir(commands, env=env, stream=stream)[0]
891 928
892 929 def _gitdir(self, commands, env=None, stream=False):
893 930 return self._gitnodir(commands, env=env, stream=stream,
894 931 cwd=self._abspath)
895 932
896 933 def _gitnodir(self, commands, env=None, stream=False, cwd=None):
897 934 """Calls the git command
898 935
899 936 The methods tries to call the git command. versions prior to 1.6.0
900 937 are not supported and very probably fail.
901 938 """
902 939 self._ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
903 940 # unless ui.quiet is set, print git's stderr,
904 941 # which is mostly progress and useful info
905 942 errpipe = None
906 943 if self._ui.quiet:
907 944 errpipe = open(os.devnull, 'w')
908 945 p = subprocess.Popen([self._gitexecutable] + commands, bufsize=-1,
909 946 cwd=cwd, env=env, close_fds=util.closefds,
910 947 stdout=subprocess.PIPE, stderr=errpipe)
911 948 if stream:
912 949 return p.stdout, None
913 950
914 951 retdata = p.stdout.read().strip()
915 952 # wait for the child to exit to avoid race condition.
916 953 p.wait()
917 954
918 955 if p.returncode != 0 and p.returncode != 1:
919 956 # there are certain error codes that are ok
920 957 command = commands[0]
921 958 if command in ('cat-file', 'symbolic-ref'):
922 959 return retdata, p.returncode
923 960 # for all others, abort
924 961 raise util.Abort('git %s error %d in %s' %
925 962 (command, p.returncode, self._relpath))
926 963
927 964 return retdata, p.returncode
928 965
929 966 def _gitmissing(self):
930 967 return not os.path.exists(os.path.join(self._abspath, '.git'))
931 968
932 969 def _gitstate(self):
933 970 return self._gitcommand(['rev-parse', 'HEAD'])
934 971
935 972 def _gitcurrentbranch(self):
936 973 current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
937 974 if err:
938 975 current = None
939 976 return current
940 977
941 978 def _gitremote(self, remote):
942 979 out = self._gitcommand(['remote', 'show', '-n', remote])
943 980 line = out.split('\n')[1]
944 981 i = line.index('URL: ') + len('URL: ')
945 982 return line[i:]
946 983
947 984 def _githavelocally(self, revision):
948 985 out, code = self._gitdir(['cat-file', '-e', revision])
949 986 return code == 0
950 987
951 988 def _gitisancestor(self, r1, r2):
952 989 base = self._gitcommand(['merge-base', r1, r2])
953 990 return base == r1
954 991
955 992 def _gitisbare(self):
956 993 return self._gitcommand(['config', '--bool', 'core.bare']) == 'true'
957 994
958 995 def _gitupdatestat(self):
959 996 """This must be run before git diff-index.
960 997 diff-index only looks at changes to file stat;
961 998 this command looks at file contents and updates the stat."""
962 999 self._gitcommand(['update-index', '-q', '--refresh'])
963 1000
964 1001 def _gitbranchmap(self):
965 1002 '''returns 2 things:
966 1003 a map from git branch to revision
967 1004 a map from revision to branches'''
968 1005 branch2rev = {}
969 1006 rev2branch = {}
970 1007
971 1008 out = self._gitcommand(['for-each-ref', '--format',
972 1009 '%(objectname) %(refname)'])
973 1010 for line in out.split('\n'):
974 1011 revision, ref = line.split(' ')
975 1012 if (not ref.startswith('refs/heads/') and
976 1013 not ref.startswith('refs/remotes/')):
977 1014 continue
978 1015 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
979 1016 continue # ignore remote/HEAD redirects
980 1017 branch2rev[ref] = revision
981 1018 rev2branch.setdefault(revision, []).append(ref)
982 1019 return branch2rev, rev2branch
983 1020
984 1021 def _gittracking(self, branches):
985 1022 'return map of remote branch to local tracking branch'
986 1023 # assumes no more than one local tracking branch for each remote
987 1024 tracking = {}
988 1025 for b in branches:
989 1026 if b.startswith('refs/remotes/'):
990 1027 continue
991 1028 bname = b.split('/', 2)[2]
992 1029 remote = self._gitcommand(['config', 'branch.%s.remote' % bname])
993 1030 if remote:
994 1031 ref = self._gitcommand(['config', 'branch.%s.merge' % bname])
995 1032 tracking['refs/remotes/%s/%s' %
996 1033 (remote, ref.split('/', 2)[2])] = b
997 1034 return tracking
998 1035
999 1036 def _abssource(self, source):
1000 1037 if '://' not in source:
1001 1038 # recognize the scp syntax as an absolute source
1002 1039 colon = source.find(':')
1003 1040 if colon != -1 and '/' not in source[:colon]:
1004 1041 return source
1005 1042 self._subsource = source
1006 1043 return _abssource(self)
1007 1044
1008 1045 def _fetch(self, source, revision):
1009 1046 if self._gitmissing():
1010 1047 source = self._abssource(source)
1011 1048 self._ui.status(_('cloning subrepo %s from %s\n') %
1012 1049 (self._relpath, source))
1013 1050 self._gitnodir(['clone', source, self._abspath])
1014 1051 if self._githavelocally(revision):
1015 1052 return
1016 1053 self._ui.status(_('pulling subrepo %s from %s\n') %
1017 1054 (self._relpath, self._gitremote('origin')))
1018 1055 # try only origin: the originally cloned repo
1019 1056 self._gitcommand(['fetch'])
1020 1057 if not self._githavelocally(revision):
1021 1058 raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
1022 1059 (revision, self._relpath))
1023 1060
1061 @annotatesubrepoerror
1024 1062 def dirty(self, ignoreupdate=False):
1025 1063 if self._gitmissing():
1026 1064 return self._state[1] != ''
1027 1065 if self._gitisbare():
1028 1066 return True
1029 1067 if not ignoreupdate and self._state[1] != self._gitstate():
1030 1068 # different version checked out
1031 1069 return True
1032 1070 # check for staged changes or modified files; ignore untracked files
1033 1071 self._gitupdatestat()
1034 1072 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1035 1073 return code == 1
1036 1074
1037 1075 def basestate(self):
1038 1076 return self._gitstate()
1039 1077
1078 @annotatesubrepoerror
1040 1079 def get(self, state, overwrite=False):
1041 1080 source, revision, kind = state
1042 1081 if not revision:
1043 1082 self.remove()
1044 1083 return
1045 1084 self._fetch(source, revision)
1046 1085 # if the repo was set to be bare, unbare it
1047 1086 if self._gitisbare():
1048 1087 self._gitcommand(['config', 'core.bare', 'false'])
1049 1088 if self._gitstate() == revision:
1050 1089 self._gitcommand(['reset', '--hard', 'HEAD'])
1051 1090 return
1052 1091 elif self._gitstate() == revision:
1053 1092 if overwrite:
1054 1093 # first reset the index to unmark new files for commit, because
1055 1094 # reset --hard will otherwise throw away files added for commit,
1056 1095 # not just unmark them.
1057 1096 self._gitcommand(['reset', 'HEAD'])
1058 1097 self._gitcommand(['reset', '--hard', 'HEAD'])
1059 1098 return
1060 1099 branch2rev, rev2branch = self._gitbranchmap()
1061 1100
1062 1101 def checkout(args):
1063 1102 cmd = ['checkout']
1064 1103 if overwrite:
1065 1104 # first reset the index to unmark new files for commit, because
1066 1105 # the -f option will otherwise throw away files added for
1067 1106 # commit, not just unmark them.
1068 1107 self._gitcommand(['reset', 'HEAD'])
1069 1108 cmd.append('-f')
1070 1109 self._gitcommand(cmd + args)
1071 1110
1072 1111 def rawcheckout():
1073 1112 # no branch to checkout, check it out with no branch
1074 1113 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
1075 1114 self._relpath)
1076 1115 self._ui.warn(_('check out a git branch if you intend '
1077 1116 'to make changes\n'))
1078 1117 checkout(['-q', revision])
1079 1118
1080 1119 if revision not in rev2branch:
1081 1120 rawcheckout()
1082 1121 return
1083 1122 branches = rev2branch[revision]
1084 1123 firstlocalbranch = None
1085 1124 for b in branches:
1086 1125 if b == 'refs/heads/master':
1087 1126 # master trumps all other branches
1088 1127 checkout(['refs/heads/master'])
1089 1128 return
1090 1129 if not firstlocalbranch and not b.startswith('refs/remotes/'):
1091 1130 firstlocalbranch = b
1092 1131 if firstlocalbranch:
1093 1132 checkout([firstlocalbranch])
1094 1133 return
1095 1134
1096 1135 tracking = self._gittracking(branch2rev.keys())
1097 1136 # choose a remote branch already tracked if possible
1098 1137 remote = branches[0]
1099 1138 if remote not in tracking:
1100 1139 for b in branches:
1101 1140 if b in tracking:
1102 1141 remote = b
1103 1142 break
1104 1143
1105 1144 if remote not in tracking:
1106 1145 # create a new local tracking branch
1107 1146 local = remote.split('/', 2)[2]
1108 1147 checkout(['-b', local, remote])
1109 1148 elif self._gitisancestor(branch2rev[tracking[remote]], remote):
1110 1149 # When updating to a tracked remote branch,
1111 1150 # if the local tracking branch is downstream of it,
1112 1151 # a normal `git pull` would have performed a "fast-forward merge"
1113 1152 # which is equivalent to updating the local branch to the remote.
1114 1153 # Since we are only looking at branching at update, we need to
1115 1154 # detect this situation and perform this action lazily.
1116 1155 if tracking[remote] != self._gitcurrentbranch():
1117 1156 checkout([tracking[remote]])
1118 1157 self._gitcommand(['merge', '--ff', remote])
1119 1158 else:
1120 1159 # a real merge would be required, just checkout the revision
1121 1160 rawcheckout()
1122 1161
1162 @annotatesubrepoerror
1123 1163 def commit(self, text, user, date):
1124 1164 if self._gitmissing():
1125 1165 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1126 1166 cmd = ['commit', '-a', '-m', text]
1127 1167 env = os.environ.copy()
1128 1168 if user:
1129 1169 cmd += ['--author', user]
1130 1170 if date:
1131 1171 # git's date parser silently ignores when seconds < 1e9
1132 1172 # convert to ISO8601
1133 1173 env['GIT_AUTHOR_DATE'] = util.datestr(date,
1134 1174 '%Y-%m-%dT%H:%M:%S %1%2')
1135 1175 self._gitcommand(cmd, env=env)
1136 1176 # make sure commit works otherwise HEAD might not exist under certain
1137 1177 # circumstances
1138 1178 return self._gitstate()
1139 1179
1180 @annotatesubrepoerror
1140 1181 def merge(self, state):
1141 1182 source, revision, kind = state
1142 1183 self._fetch(source, revision)
1143 1184 base = self._gitcommand(['merge-base', revision, self._state[1]])
1144 1185 self._gitupdatestat()
1145 1186 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1146 1187
1147 1188 def mergefunc():
1148 1189 if base == revision:
1149 1190 self.get(state) # fast forward merge
1150 1191 elif base != self._state[1]:
1151 1192 self._gitcommand(['merge', '--no-commit', revision])
1152 1193
1153 1194 if self.dirty():
1154 1195 if self._gitstate() != revision:
1155 1196 dirty = self._gitstate() == self._state[1] or code != 0
1156 1197 if _updateprompt(self._ui, self, dirty,
1157 1198 self._state[1][:7], revision[:7]):
1158 1199 mergefunc()
1159 1200 else:
1160 1201 mergefunc()
1161 1202
1203 @annotatesubrepoerror
1162 1204 def push(self, opts):
1163 1205 force = opts.get('force')
1164 1206
1165 1207 if not self._state[1]:
1166 1208 return True
1167 1209 if self._gitmissing():
1168 1210 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1169 1211 # if a branch in origin contains the revision, nothing to do
1170 1212 branch2rev, rev2branch = self._gitbranchmap()
1171 1213 if self._state[1] in rev2branch:
1172 1214 for b in rev2branch[self._state[1]]:
1173 1215 if b.startswith('refs/remotes/origin/'):
1174 1216 return True
1175 1217 for b, revision in branch2rev.iteritems():
1176 1218 if b.startswith('refs/remotes/origin/'):
1177 1219 if self._gitisancestor(self._state[1], revision):
1178 1220 return True
1179 1221 # otherwise, try to push the currently checked out branch
1180 1222 cmd = ['push']
1181 1223 if force:
1182 1224 cmd.append('--force')
1183 1225
1184 1226 current = self._gitcurrentbranch()
1185 1227 if current:
1186 1228 # determine if the current branch is even useful
1187 1229 if not self._gitisancestor(self._state[1], current):
1188 1230 self._ui.warn(_('unrelated git branch checked out '
1189 1231 'in subrepo %s\n') % self._relpath)
1190 1232 return False
1191 1233 self._ui.status(_('pushing branch %s of subrepo %s\n') %
1192 1234 (current.split('/', 2)[2], self._relpath))
1193 1235 self._gitcommand(cmd + ['origin', current])
1194 1236 return True
1195 1237 else:
1196 1238 self._ui.warn(_('no branch checked out in subrepo %s\n'
1197 1239 'cannot push revision %s\n') %
1198 1240 (self._relpath, self._state[1]))
1199 1241 return False
1200 1242
1243 @annotatesubrepoerror
1201 1244 def remove(self):
1202 1245 if self._gitmissing():
1203 1246 return
1204 1247 if self.dirty():
1205 1248 self._ui.warn(_('not removing repo %s because '
1206 1249 'it has changes.\n') % self._relpath)
1207 1250 return
1208 1251 # we can't fully delete the repository as it may contain
1209 1252 # local-only history
1210 1253 self._ui.note(_('removing subrepo %s\n') % self._relpath)
1211 1254 self._gitcommand(['config', 'core.bare', 'true'])
1212 1255 for f in os.listdir(self._abspath):
1213 1256 if f == '.git':
1214 1257 continue
1215 1258 path = os.path.join(self._abspath, f)
1216 1259 if os.path.isdir(path) and not os.path.islink(path):
1217 1260 shutil.rmtree(path)
1218 1261 else:
1219 1262 os.remove(path)
1220 1263
1221 1264 def archive(self, ui, archiver, prefix, match=None):
1222 1265 source, revision = self._state
1223 1266 if not revision:
1224 1267 return
1225 1268 self._fetch(source, revision)
1226 1269
1227 1270 # Parse git's native archive command.
1228 1271 # This should be much faster than manually traversing the trees
1229 1272 # and objects with many subprocess calls.
1230 1273 tarstream = self._gitcommand(['archive', revision], stream=True)
1231 1274 tar = tarfile.open(fileobj=tarstream, mode='r|')
1232 1275 relpath = subrelpath(self)
1233 1276 ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
1234 1277 for i, info in enumerate(tar):
1235 1278 if info.isdir():
1236 1279 continue
1237 1280 if match and not match(info.name):
1238 1281 continue
1239 1282 if info.issym():
1240 1283 data = info.linkname
1241 1284 else:
1242 1285 data = tar.extractfile(info).read()
1243 1286 archiver.addfile(os.path.join(prefix, self._path, info.name),
1244 1287 info.mode, info.issym(), data)
1245 1288 ui.progress(_('archiving (%s)') % relpath, i + 1,
1246 1289 unit=_('files'))
1247 1290 ui.progress(_('archiving (%s)') % relpath, None)
1248 1291
1249 1292
1293 @annotatesubrepoerror
1250 1294 def status(self, rev2, **opts):
1251 1295 rev1 = self._state[1]
1252 1296 if self._gitmissing() or not rev1:
1253 1297 # if the repo is missing, return no results
1254 1298 return [], [], [], [], [], [], []
1255 1299 modified, added, removed = [], [], []
1256 1300 self._gitupdatestat()
1257 1301 if rev2:
1258 1302 command = ['diff-tree', rev1, rev2]
1259 1303 else:
1260 1304 command = ['diff-index', rev1]
1261 1305 out = self._gitcommand(command)
1262 1306 for line in out.split('\n'):
1263 1307 tab = line.find('\t')
1264 1308 if tab == -1:
1265 1309 continue
1266 1310 status, f = line[tab - 1], line[tab + 1:]
1267 1311 if status == 'M':
1268 1312 modified.append(f)
1269 1313 elif status == 'A':
1270 1314 added.append(f)
1271 1315 elif status == 'D':
1272 1316 removed.append(f)
1273 1317
1274 1318 deleted = unknown = ignored = clean = []
1275 1319 return modified, added, removed, deleted, unknown, ignored, clean
1276 1320
1277 1321 types = {
1278 1322 'hg': hgsubrepo,
1279 1323 'svn': svnsubrepo,
1280 1324 'git': gitsubrepo,
1281 1325 }
@@ -1,534 +1,534 b''
1 1 $ "$TESTDIR/hghave" git || exit 80
2 2
3 3 make git commits repeatable
4 4
5 5 $ echo "[core]" >> $HOME/.gitconfig
6 6 $ echo "autocrlf = false" >> $HOME/.gitconfig
7 7 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
8 8 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
9 9 $ GIT_AUTHOR_DATE='1234567891 +0000'; export GIT_AUTHOR_DATE
10 10 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
11 11 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
12 12 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
13 13
14 14 root hg repo
15 15
16 16 $ hg init t
17 17 $ cd t
18 18 $ echo a > a
19 19 $ hg add a
20 20 $ hg commit -m a
21 21 $ cd ..
22 22
23 23 new external git repo
24 24
25 25 $ mkdir gitroot
26 26 $ cd gitroot
27 27 $ git init -q
28 28 $ echo g > g
29 29 $ git add g
30 30 $ git commit -q -m g
31 31
32 32 add subrepo clone
33 33
34 34 $ cd ../t
35 35 $ echo 's = [git]../gitroot' > .hgsub
36 36 $ git clone -q ../gitroot s
37 37 $ hg add .hgsub
38 38 $ hg commit -m 'new git subrepo'
39 39 $ hg debugsub
40 40 path s
41 41 source ../gitroot
42 42 revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
43 43
44 44 record a new commit from upstream from a different branch
45 45
46 46 $ cd ../gitroot
47 47 $ git checkout -q -b testing
48 48 $ echo gg >> g
49 49 $ git commit -q -a -m gg
50 50
51 51 $ cd ../t/s
52 52 $ git pull -q >/dev/null 2>/dev/null
53 53 $ git checkout -q -b testing origin/testing >/dev/null
54 54
55 55 $ cd ..
56 56 $ hg status --subrepos
57 57 M s/g
58 58 $ hg commit -m 'update git subrepo'
59 59 $ hg debugsub
60 60 path s
61 61 source ../gitroot
62 62 revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
63 63
64 64 make $GITROOT pushable, by replacing it with a clone with nothing checked out
65 65
66 66 $ cd ..
67 67 $ git clone gitroot gitrootbare --bare -q
68 68 $ rm -rf gitroot
69 69 $ mv gitrootbare gitroot
70 70
71 71 clone root
72 72
73 73 $ cd t
74 74 $ hg clone . ../tc
75 75 updating to branch default
76 76 cloning subrepo s from $TESTTMP/gitroot
77 77 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 78 $ cd ../tc
79 79 $ hg debugsub
80 80 path s
81 81 source ../gitroot
82 82 revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
83 83
84 84 update to previous substate
85 85
86 86 $ hg update 1 -q
87 87 $ cat s/g
88 88 g
89 89 $ hg debugsub
90 90 path s
91 91 source ../gitroot
92 92 revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
93 93
94 94 clone root, make local change
95 95
96 96 $ cd ../t
97 97 $ hg clone . ../ta
98 98 updating to branch default
99 99 cloning subrepo s from $TESTTMP/gitroot
100 100 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
101 101
102 102 $ cd ../ta
103 103 $ echo ggg >> s/g
104 104 $ hg status --subrepos
105 105 M s/g
106 106 $ hg commit --subrepos -m ggg
107 107 committing subrepository s
108 108 $ hg debugsub
109 109 path s
110 110 source ../gitroot
111 111 revision 79695940086840c99328513acbe35f90fcd55e57
112 112
113 113 clone root separately, make different local change
114 114
115 115 $ cd ../t
116 116 $ hg clone . ../tb
117 117 updating to branch default
118 118 cloning subrepo s from $TESTTMP/gitroot
119 119 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 120
121 121 $ cd ../tb/s
122 122 $ echo f > f
123 123 $ git add f
124 124 $ cd ..
125 125
126 126 $ hg status --subrepos
127 127 A s/f
128 128 $ hg commit --subrepos -m f
129 129 committing subrepository s
130 130 $ hg debugsub
131 131 path s
132 132 source ../gitroot
133 133 revision aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
134 134
135 135 user b push changes
136 136
137 137 $ hg push 2>/dev/null
138 138 pushing to $TESTTMP/t (glob)
139 139 pushing branch testing of subrepo s
140 140 searching for changes
141 141 adding changesets
142 142 adding manifests
143 143 adding file changes
144 144 added 1 changesets with 1 changes to 1 files
145 145
146 146 user a pulls, merges, commits
147 147
148 148 $ cd ../ta
149 149 $ hg pull
150 150 pulling from $TESTTMP/t (glob)
151 151 searching for changes
152 152 adding changesets
153 153 adding manifests
154 154 adding file changes
155 155 added 1 changesets with 1 changes to 1 files (+1 heads)
156 156 (run 'hg heads' to see heads, 'hg merge' to merge)
157 157 $ hg merge 2>/dev/null
158 158 pulling subrepo s from $TESTTMP/gitroot
159 159 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 160 (branch merge, don't forget to commit)
161 161 $ cat s/f
162 162 f
163 163 $ cat s/g
164 164 g
165 165 gg
166 166 ggg
167 167 $ hg commit --subrepos -m 'merge'
168 168 committing subrepository s
169 169 $ hg status --subrepos --rev 1:5
170 170 M .hgsubstate
171 171 M s/g
172 172 A s/f
173 173 $ hg debugsub
174 174 path s
175 175 source ../gitroot
176 176 revision f47b465e1bce645dbf37232a00574aa1546ca8d3
177 177 $ hg push 2>/dev/null
178 178 pushing to $TESTTMP/t (glob)
179 179 pushing branch testing of subrepo s
180 180 searching for changes
181 181 adding changesets
182 182 adding manifests
183 183 adding file changes
184 184 added 2 changesets with 2 changes to 1 files
185 185
186 186 make upstream git changes
187 187
188 188 $ cd ..
189 189 $ git clone -q gitroot gitclone
190 190 $ cd gitclone
191 191 $ echo ff >> f
192 192 $ git commit -q -a -m ff
193 193 $ echo fff >> f
194 194 $ git commit -q -a -m fff
195 195 $ git push origin testing 2>/dev/null
196 196
197 197 make and push changes to hg without updating the subrepo
198 198
199 199 $ cd ../t
200 200 $ hg clone . ../td
201 201 updating to branch default
202 202 cloning subrepo s from $TESTTMP/gitroot
203 203 checking out detached HEAD in subrepo s
204 204 check out a git branch if you intend to make changes
205 205 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
206 206 $ cd ../td
207 207 $ echo aa >> a
208 208 $ hg commit -m aa
209 209 $ hg push
210 210 pushing to $TESTTMP/t (glob)
211 211 searching for changes
212 212 adding changesets
213 213 adding manifests
214 214 adding file changes
215 215 added 1 changesets with 1 changes to 1 files
216 216
217 217 sync to upstream git, distribute changes
218 218
219 219 $ cd ../ta
220 220 $ hg pull -u -q
221 221 $ cd s
222 222 $ git pull -q >/dev/null 2>/dev/null
223 223 $ cd ..
224 224 $ hg commit -m 'git upstream sync'
225 225 $ hg debugsub
226 226 path s
227 227 source ../gitroot
228 228 revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
229 229 $ hg push -q
230 230
231 231 $ cd ../tb
232 232 $ hg pull -q
233 233 $ hg update 2>/dev/null
234 234 pulling subrepo s from $TESTTMP/gitroot
235 235 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
236 236 $ hg debugsub
237 237 path s
238 238 source ../gitroot
239 239 revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
240 240
241 241 update to a revision without the subrepo, keeping the local git repository
242 242
243 243 $ cd ../t
244 244 $ hg up 0
245 245 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
246 246 $ ls -a s
247 247 .
248 248 ..
249 249 .git
250 250
251 251 $ hg up 2
252 252 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
253 253 $ ls -a s
254 254 .
255 255 ..
256 256 .git
257 257 g
258 258
259 259 archive subrepos
260 260
261 261 $ cd ../tc
262 262 $ hg pull -q
263 263 $ hg archive --subrepos -r 5 ../archive 2>/dev/null
264 264 pulling subrepo s from $TESTTMP/gitroot
265 265 $ cd ../archive
266 266 $ cat s/f
267 267 f
268 268 $ cat s/g
269 269 g
270 270 gg
271 271 ggg
272 272
273 273 $ hg -R ../tc archive --subrepo -r 5 -X ../tc/**f ../archive_x 2>/dev/null
274 274 $ find ../archive_x | sort | grep -v pax_global_header
275 275 ../archive_x
276 276 ../archive_x/.hg_archival.txt
277 277 ../archive_x/.hgsub
278 278 ../archive_x/.hgsubstate
279 279 ../archive_x/a
280 280 ../archive_x/s
281 281 ../archive_x/s/g
282 282
283 283 create nested repo
284 284
285 285 $ cd ..
286 286 $ hg init outer
287 287 $ cd outer
288 288 $ echo b>b
289 289 $ hg add b
290 290 $ hg commit -m b
291 291
292 292 $ hg clone ../t inner
293 293 updating to branch default
294 294 cloning subrepo s from $TESTTMP/gitroot
295 295 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
296 296 $ echo inner = inner > .hgsub
297 297 $ hg add .hgsub
298 298 $ hg commit -m 'nested sub'
299 299
300 300 nested commit
301 301
302 302 $ echo ffff >> inner/s/f
303 303 $ hg status --subrepos
304 304 M inner/s/f
305 305 $ hg commit --subrepos -m nested
306 306 committing subrepository inner
307 307 committing subrepository inner/s (glob)
308 308
309 309 nested archive
310 310
311 311 $ hg archive --subrepos ../narchive
312 312 $ ls ../narchive/inner/s | grep -v pax_global_header
313 313 f
314 314 g
315 315
316 316 relative source expansion
317 317
318 318 $ cd ..
319 319 $ mkdir d
320 320 $ hg clone t d/t
321 321 updating to branch default
322 322 cloning subrepo s from $TESTTMP/gitroot
323 323 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
324 324
325 325 Don't crash if the subrepo is missing
326 326
327 327 $ hg clone t missing -q
328 328 $ cd missing
329 329 $ rm -rf s
330 330 $ hg status -S
331 331 $ hg sum | grep commit
332 332 commit: 1 subrepos
333 333 $ hg push -q
334 abort: subrepo s is missing
334 abort: subrepo s is missing (in subrepo s)
335 335 [255]
336 336 $ hg commit --subrepos -qm missing
337 abort: subrepo s is missing
337 abort: subrepo s is missing (in subrepo s)
338 338 [255]
339 339 $ hg update -C
340 340 cloning subrepo s from $TESTTMP/gitroot
341 341 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
342 342 $ hg sum | grep commit
343 343 commit: (clean)
344 344
345 345 Don't crash if the .hgsubstate entry is missing
346 346
347 347 $ hg update 1 -q
348 348 $ hg rm .hgsubstate
349 349 $ hg commit .hgsubstate -m 'no substate'
350 350 nothing changed
351 351 [1]
352 352 $ hg tag -l nosubstate
353 353 $ hg manifest
354 354 .hgsub
355 355 .hgsubstate
356 356 a
357 357
358 358 $ hg status -S
359 359 R .hgsubstate
360 360 $ hg sum | grep commit
361 361 commit: 1 removed, 1 subrepos (new branch head)
362 362
363 363 $ hg commit -m 'restore substate'
364 364 nothing changed
365 365 [1]
366 366 $ hg manifest
367 367 .hgsub
368 368 .hgsubstate
369 369 a
370 370 $ hg sum | grep commit
371 371 commit: 1 removed, 1 subrepos (new branch head)
372 372
373 373 $ hg update -qC nosubstate
374 374 $ ls s
375 375 g
376 376
377 377 issue3109: false positives in git diff-index
378 378
379 379 $ hg update -q
380 380 $ touch -t 200001010000 s/g
381 381 $ hg status --subrepos
382 382 $ touch -t 200001010000 s/g
383 383 $ hg sum | grep commit
384 384 commit: (clean)
385 385
386 386 Check hg update --clean
387 387 $ cd $TESTTMP/ta
388 388 $ echo > s/g
389 389 $ cd s
390 390 $ echo c1 > f1
391 391 $ echo c1 > f2
392 392 $ git add f1
393 393 $ cd ..
394 394 $ hg status -S
395 395 M s/g
396 396 A s/f1
397 397 $ ls s
398 398 f
399 399 f1
400 400 f2
401 401 g
402 402 $ hg update --clean
403 403 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
404 404 $ hg status -S
405 405 $ ls s
406 406 f
407 407 f1
408 408 f2
409 409 g
410 410
411 411 Sticky subrepositories, no changes
412 412 $ cd $TESTTMP/ta
413 413 $ hg id -n
414 414 7
415 415 $ cd s
416 416 $ git rev-parse HEAD
417 417 32a343883b74769118bb1d3b4b1fbf9156f4dddc
418 418 $ cd ..
419 419 $ hg update 1 > /dev/null 2>&1
420 420 $ hg id -n
421 421 1
422 422 $ cd s
423 423 $ git rev-parse HEAD
424 424 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
425 425 $ cd ..
426 426
427 427 Sticky subrepositorys, file changes
428 428 $ touch s/f1
429 429 $ cd s
430 430 $ git add f1
431 431 $ cd ..
432 432 $ hg id -n
433 433 1+
434 434 $ cd s
435 435 $ git rev-parse HEAD
436 436 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
437 437 $ cd ..
438 438 $ hg update 4
439 439 subrepository sources for s differ
440 440 use (l)ocal source (da5f5b1) or (r)emote source (aa84837)?
441 441 l
442 442 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
443 443 $ hg id -n
444 444 4+
445 445 $ cd s
446 446 $ git rev-parse HEAD
447 447 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
448 448 $ cd ..
449 449 $ hg update --clean tip > /dev/null 2>&1
450 450
451 451 Sticky subrepository, revision updates
452 452 $ hg id -n
453 453 7
454 454 $ cd s
455 455 $ git rev-parse HEAD
456 456 32a343883b74769118bb1d3b4b1fbf9156f4dddc
457 457 $ cd ..
458 458 $ cd s
459 459 $ git checkout aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
460 460 Previous HEAD position was 32a3438... fff
461 461 HEAD is now at aa84837... f
462 462 $ cd ..
463 463 $ hg update 1
464 464 subrepository sources for s differ (in checked out version)
465 465 use (l)ocal source (32a3438) or (r)emote source (da5f5b1)?
466 466 l
467 467 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
468 468 $ hg id -n
469 469 1+
470 470 $ cd s
471 471 $ git rev-parse HEAD
472 472 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
473 473 $ cd ..
474 474
475 475 Sticky subrepository, file changes and revision updates
476 476 $ touch s/f1
477 477 $ cd s
478 478 $ git add f1
479 479 $ git rev-parse HEAD
480 480 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
481 481 $ cd ..
482 482 $ hg id -n
483 483 1+
484 484 $ hg update 7
485 485 subrepository sources for s differ
486 486 use (l)ocal source (32a3438) or (r)emote source (32a3438)?
487 487 l
488 488 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
489 489 $ hg id -n
490 490 7+
491 491 $ cd s
492 492 $ git rev-parse HEAD
493 493 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
494 494 $ cd ..
495 495
496 496 Sticky repository, update --clean
497 497 $ hg update --clean tip 2>/dev/null
498 498 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
499 499 $ hg id -n
500 500 7
501 501 $ cd s
502 502 $ git rev-parse HEAD
503 503 32a343883b74769118bb1d3b4b1fbf9156f4dddc
504 504 $ cd ..
505 505
506 506 Test subrepo already at intended revision:
507 507 $ cd s
508 508 $ git checkout 32a343883b74769118bb1d3b4b1fbf9156f4dddc
509 509 HEAD is now at 32a3438... fff
510 510 $ cd ..
511 511 $ hg update 1
512 512 Previous HEAD position was 32a3438... fff
513 513 HEAD is now at da5f5b1... g
514 514 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
515 515 $ hg id -n
516 516 1
517 517 $ cd s
518 518 $ git rev-parse HEAD
519 519 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
520 520 $ cd ..
521 521
522 522 Test forgetting files, not implemented in git subrepo, used to
523 523 traceback
524 524 #if no-windows
525 525 $ hg forget 'notafile*'
526 526 notafile*: No such file or directory
527 527 [1]
528 528 #else
529 529 $ hg forget 'notafile'
530 530 notafile: * (glob)
531 531 [1]
532 532 #endif
533 533
534 534 $ cd ..
@@ -1,500 +1,500 b''
1 1 Create test repository:
2 2
3 3 $ hg init repo
4 4 $ cd repo
5 5 $ echo x1 > x.txt
6 6
7 7 $ hg init foo
8 8 $ cd foo
9 9 $ echo y1 > y.txt
10 10
11 11 $ hg init bar
12 12 $ cd bar
13 13 $ echo z1 > z.txt
14 14
15 15 $ cd ..
16 16 $ echo 'bar = bar' > .hgsub
17 17
18 18 $ cd ..
19 19 $ echo 'foo = foo' > .hgsub
20 20
21 21 Add files --- .hgsub files must go first to trigger subrepos:
22 22
23 23 $ hg add -S .hgsub
24 24 $ hg add -S foo/.hgsub
25 25 $ hg add -S foo/bar
26 26 adding foo/bar/z.txt (glob)
27 27 $ hg add -S
28 28 adding x.txt
29 29 adding foo/y.txt (glob)
30 30
31 31 Test recursive status without committing anything:
32 32
33 33 $ hg status -S
34 34 A .hgsub
35 35 A foo/.hgsub
36 36 A foo/bar/z.txt
37 37 A foo/y.txt
38 38 A x.txt
39 39
40 40 Test recursive diff without committing anything:
41 41
42 42 $ hg diff --nodates -S foo
43 43 diff -r 000000000000 foo/.hgsub
44 44 --- /dev/null
45 45 +++ b/foo/.hgsub
46 46 @@ -0,0 +1,1 @@
47 47 +bar = bar
48 48 diff -r 000000000000 foo/y.txt
49 49 --- /dev/null
50 50 +++ b/foo/y.txt
51 51 @@ -0,0 +1,1 @@
52 52 +y1
53 53 diff -r 000000000000 foo/bar/z.txt
54 54 --- /dev/null
55 55 +++ b/foo/bar/z.txt
56 56 @@ -0,0 +1,1 @@
57 57 +z1
58 58
59 59 Commits:
60 60
61 61 $ hg commit -m fails
62 62 abort: uncommitted changes in subrepo foo
63 63 (use --subrepos for recursive commit)
64 64 [255]
65 65
66 66 The --subrepos flag overwrite the config setting:
67 67
68 68 $ hg commit -m 0-0-0 --config ui.commitsubrepos=No --subrepos
69 69 committing subrepository foo
70 70 committing subrepository foo/bar (glob)
71 71
72 72 $ cd foo
73 73 $ echo y2 >> y.txt
74 74 $ hg commit -m 0-1-0
75 75
76 76 $ cd bar
77 77 $ echo z2 >> z.txt
78 78 $ hg commit -m 0-1-1
79 79
80 80 $ cd ..
81 81 $ hg commit -m 0-2-1
82 82
83 83 $ cd ..
84 84 $ hg commit -m 1-2-1
85 85
86 86 Change working directory:
87 87
88 88 $ echo y3 >> foo/y.txt
89 89 $ echo z3 >> foo/bar/z.txt
90 90 $ hg status -S
91 91 M foo/bar/z.txt
92 92 M foo/y.txt
93 93 $ hg diff --nodates -S
94 94 diff -r d254738c5f5e foo/y.txt
95 95 --- a/foo/y.txt
96 96 +++ b/foo/y.txt
97 97 @@ -1,2 +1,3 @@
98 98 y1
99 99 y2
100 100 +y3
101 101 diff -r 9647f22de499 foo/bar/z.txt
102 102 --- a/foo/bar/z.txt
103 103 +++ b/foo/bar/z.txt
104 104 @@ -1,2 +1,3 @@
105 105 z1
106 106 z2
107 107 +z3
108 108
109 109 Status call crossing repository boundaries:
110 110
111 111 $ hg status -S foo/bar/z.txt
112 112 M foo/bar/z.txt
113 113 $ hg status -S -I 'foo/?.txt'
114 114 M foo/y.txt
115 115 $ hg status -S -I '**/?.txt'
116 116 M foo/bar/z.txt
117 117 M foo/y.txt
118 118 $ hg diff --nodates -S -I '**/?.txt'
119 119 diff -r d254738c5f5e foo/y.txt
120 120 --- a/foo/y.txt
121 121 +++ b/foo/y.txt
122 122 @@ -1,2 +1,3 @@
123 123 y1
124 124 y2
125 125 +y3
126 126 diff -r 9647f22de499 foo/bar/z.txt
127 127 --- a/foo/bar/z.txt
128 128 +++ b/foo/bar/z.txt
129 129 @@ -1,2 +1,3 @@
130 130 z1
131 131 z2
132 132 +z3
133 133
134 134 Status from within a subdirectory:
135 135
136 136 $ mkdir dir
137 137 $ cd dir
138 138 $ echo a1 > a.txt
139 139 $ hg status -S
140 140 M foo/bar/z.txt
141 141 M foo/y.txt
142 142 ? dir/a.txt
143 143 $ hg diff --nodates -S
144 144 diff -r d254738c5f5e foo/y.txt
145 145 --- a/foo/y.txt
146 146 +++ b/foo/y.txt
147 147 @@ -1,2 +1,3 @@
148 148 y1
149 149 y2
150 150 +y3
151 151 diff -r 9647f22de499 foo/bar/z.txt
152 152 --- a/foo/bar/z.txt
153 153 +++ b/foo/bar/z.txt
154 154 @@ -1,2 +1,3 @@
155 155 z1
156 156 z2
157 157 +z3
158 158
159 159 Status with relative path:
160 160
161 161 $ hg status -S ..
162 162 M ../foo/bar/z.txt
163 163 M ../foo/y.txt
164 164 ? a.txt
165 165 $ hg diff --nodates -S ..
166 166 diff -r d254738c5f5e foo/y.txt
167 167 --- a/foo/y.txt
168 168 +++ b/foo/y.txt
169 169 @@ -1,2 +1,3 @@
170 170 y1
171 171 y2
172 172 +y3
173 173 diff -r 9647f22de499 foo/bar/z.txt
174 174 --- a/foo/bar/z.txt
175 175 +++ b/foo/bar/z.txt
176 176 @@ -1,2 +1,3 @@
177 177 z1
178 178 z2
179 179 +z3
180 180 $ cd ..
181 181
182 182 Cleanup and final commit:
183 183
184 184 $ rm -r dir
185 185 $ hg commit --subrepos -m 2-3-2
186 186 committing subrepository foo
187 187 committing subrepository foo/bar (glob)
188 188
189 189 Test explicit path commands within subrepos: add/forget
190 190 $ echo z1 > foo/bar/z2.txt
191 191 $ hg status -S
192 192 ? foo/bar/z2.txt
193 193 $ hg add foo/bar/z2.txt
194 194 $ hg status -S
195 195 A foo/bar/z2.txt
196 196 $ hg forget foo/bar/z2.txt
197 197 $ hg status -S
198 198 ? foo/bar/z2.txt
199 199 $ hg forget foo/bar/z2.txt
200 200 not removing foo/bar/z2.txt: file is already untracked (glob)
201 201 [1]
202 202 $ hg status -S
203 203 ? foo/bar/z2.txt
204 204 $ rm foo/bar/z2.txt
205 205
206 206 Log with the relationships between repo and its subrepo:
207 207
208 208 $ hg log --template '{rev}:{node|short} {desc}\n'
209 209 2:1326fa26d0c0 2-3-2
210 210 1:4b3c9ff4f66b 1-2-1
211 211 0:23376cbba0d8 0-0-0
212 212
213 213 $ hg -R foo log --template '{rev}:{node|short} {desc}\n'
214 214 3:65903cebad86 2-3-2
215 215 2:d254738c5f5e 0-2-1
216 216 1:8629ce7dcc39 0-1-0
217 217 0:af048e97ade2 0-0-0
218 218
219 219 $ hg -R foo/bar log --template '{rev}:{node|short} {desc}\n'
220 220 2:31ecbdafd357 2-3-2
221 221 1:9647f22de499 0-1-1
222 222 0:4904098473f9 0-0-0
223 223
224 224 Status between revisions:
225 225
226 226 $ hg status -S
227 227 $ hg status -S --rev 0:1
228 228 M .hgsubstate
229 229 M foo/.hgsubstate
230 230 M foo/bar/z.txt
231 231 M foo/y.txt
232 232 $ hg diff --nodates -S -I '**/?.txt' --rev 0:1
233 233 diff -r af048e97ade2 -r d254738c5f5e foo/y.txt
234 234 --- a/foo/y.txt
235 235 +++ b/foo/y.txt
236 236 @@ -1,1 +1,2 @@
237 237 y1
238 238 +y2
239 239 diff -r 4904098473f9 -r 9647f22de499 foo/bar/z.txt
240 240 --- a/foo/bar/z.txt
241 241 +++ b/foo/bar/z.txt
242 242 @@ -1,1 +1,2 @@
243 243 z1
244 244 +z2
245 245
246 246 Enable progress extension for archive tests:
247 247
248 248 $ cp $HGRCPATH $HGRCPATH.no-progress
249 249 $ cat >> $HGRCPATH <<EOF
250 250 > [extensions]
251 251 > progress =
252 252 > [progress]
253 253 > assume-tty = 1
254 254 > delay = 0
255 255 > format = topic bar number
256 256 > refresh = 0
257 257 > width = 60
258 258 > EOF
259 259
260 260 Test archiving to a directory tree (the doubled lines in the output
261 261 only show up in the test output, not in real usage):
262 262
263 263 $ hg archive --subrepos ../archive
264 264 \r (no-eol) (esc)
265 265 archiving [ ] 0/3\r (no-eol) (esc)
266 266 archiving [ ] 0/3\r (no-eol) (esc)
267 267 archiving [=============> ] 1/3\r (no-eol) (esc)
268 268 archiving [=============> ] 1/3\r (no-eol) (esc)
269 269 archiving [===========================> ] 2/3\r (no-eol) (esc)
270 270 archiving [===========================> ] 2/3\r (no-eol) (esc)
271 271 archiving [==========================================>] 3/3\r (no-eol) (esc)
272 272 archiving [==========================================>] 3/3\r (no-eol) (esc)
273 273 \r (no-eol) (esc)
274 274 \r (no-eol) (esc)
275 275 archiving (foo) [ ] 0/3\r (no-eol) (esc)
276 276 archiving (foo) [ ] 0/3\r (no-eol) (esc)
277 277 archiving (foo) [===========> ] 1/3\r (no-eol) (esc)
278 278 archiving (foo) [===========> ] 1/3\r (no-eol) (esc)
279 279 archiving (foo) [=======================> ] 2/3\r (no-eol) (esc)
280 280 archiving (foo) [=======================> ] 2/3\r (no-eol) (esc)
281 281 archiving (foo) [====================================>] 3/3\r (no-eol) (esc)
282 282 archiving (foo) [====================================>] 3/3\r (no-eol) (esc)
283 283 \r (no-eol) (esc)
284 284 \r (no-eol) (esc)
285 285 archiving (foo/bar) [ ] 0/1\r (no-eol) (glob) (esc)
286 286 archiving (foo/bar) [ ] 0/1\r (no-eol) (glob) (esc)
287 287 archiving (foo/bar) [================================>] 1/1\r (no-eol) (glob) (esc)
288 288 archiving (foo/bar) [================================>] 1/1\r (no-eol) (glob) (esc)
289 289 \r (no-eol) (esc)
290 290 $ find ../archive | sort
291 291 ../archive
292 292 ../archive/.hg_archival.txt
293 293 ../archive/.hgsub
294 294 ../archive/.hgsubstate
295 295 ../archive/foo
296 296 ../archive/foo/.hgsub
297 297 ../archive/foo/.hgsubstate
298 298 ../archive/foo/bar
299 299 ../archive/foo/bar/z.txt
300 300 ../archive/foo/y.txt
301 301 ../archive/x.txt
302 302
303 303 Test archiving to zip file (unzip output is unstable):
304 304
305 305 $ hg archive --subrepos ../archive.zip
306 306 \r (no-eol) (esc)
307 307 archiving [ ] 0/3\r (no-eol) (esc)
308 308 archiving [ ] 0/3\r (no-eol) (esc)
309 309 archiving [=============> ] 1/3\r (no-eol) (esc)
310 310 archiving [=============> ] 1/3\r (no-eol) (esc)
311 311 archiving [===========================> ] 2/3\r (no-eol) (esc)
312 312 archiving [===========================> ] 2/3\r (no-eol) (esc)
313 313 archiving [==========================================>] 3/3\r (no-eol) (esc)
314 314 archiving [==========================================>] 3/3\r (no-eol) (esc)
315 315 \r (no-eol) (esc)
316 316 \r (no-eol) (esc)
317 317 archiving (foo) [ ] 0/3\r (no-eol) (esc)
318 318 archiving (foo) [ ] 0/3\r (no-eol) (esc)
319 319 archiving (foo) [===========> ] 1/3\r (no-eol) (esc)
320 320 archiving (foo) [===========> ] 1/3\r (no-eol) (esc)
321 321 archiving (foo) [=======================> ] 2/3\r (no-eol) (esc)
322 322 archiving (foo) [=======================> ] 2/3\r (no-eol) (esc)
323 323 archiving (foo) [====================================>] 3/3\r (no-eol) (esc)
324 324 archiving (foo) [====================================>] 3/3\r (no-eol) (esc)
325 325 \r (no-eol) (esc)
326 326 \r (no-eol) (esc)
327 327 archiving (foo/bar) [ ] 0/1\r (no-eol) (glob) (esc)
328 328 archiving (foo/bar) [ ] 0/1\r (no-eol) (glob) (esc)
329 329 archiving (foo/bar) [================================>] 1/1\r (no-eol) (glob) (esc)
330 330 archiving (foo/bar) [================================>] 1/1\r (no-eol) (glob) (esc)
331 331 \r (no-eol) (esc)
332 332
333 333 Test archiving a revision that references a subrepo that is not yet
334 334 cloned:
335 335
336 336 $ hg clone -U . ../empty
337 337 $ cd ../empty
338 338 $ hg archive --subrepos -r tip ../archive.tar.gz
339 339 \r (no-eol) (esc)
340 340 archiving [ ] 0/3\r (no-eol) (esc)
341 341 archiving [ ] 0/3\r (no-eol) (esc)
342 342 archiving [=============> ] 1/3\r (no-eol) (esc)
343 343 archiving [=============> ] 1/3\r (no-eol) (esc)
344 344 archiving [===========================> ] 2/3\r (no-eol) (esc)
345 345 archiving [===========================> ] 2/3\r (no-eol) (esc)
346 346 archiving [==========================================>] 3/3\r (no-eol) (esc)
347 347 archiving [==========================================>] 3/3\r (no-eol) (esc)
348 348 \r (no-eol) (esc)
349 349 \r (no-eol) (esc)
350 350 archiving (foo) [ ] 0/3\r (no-eol) (esc)
351 351 archiving (foo) [ ] 0/3\r (no-eol) (esc)
352 352 archiving (foo) [===========> ] 1/3\r (no-eol) (esc)
353 353 archiving (foo) [===========> ] 1/3\r (no-eol) (esc)
354 354 archiving (foo) [=======================> ] 2/3\r (no-eol) (esc)
355 355 archiving (foo) [=======================> ] 2/3\r (no-eol) (esc)
356 356 archiving (foo) [====================================>] 3/3\r (no-eol) (esc)
357 357 archiving (foo) [====================================>] 3/3\r (no-eol) (esc)
358 358 \r (no-eol) (esc)
359 359 \r (no-eol) (esc)
360 360 archiving (foo/bar) [ ] 0/1\r (no-eol) (glob) (esc)
361 361 archiving (foo/bar) [ ] 0/1\r (no-eol) (glob) (esc)
362 362 archiving (foo/bar) [================================>] 1/1\r (no-eol) (glob) (esc)
363 363 archiving (foo/bar) [================================>] 1/1\r (no-eol) (glob) (esc)
364 364 \r (no-eol) (esc)
365 365 cloning subrepo foo from $TESTTMP/repo/foo
366 366 cloning subrepo foo/bar from $TESTTMP/repo/foo/bar (glob)
367 367
368 368 The newly cloned subrepos contain no working copy:
369 369
370 370 $ hg -R foo summary
371 371 parent: -1:000000000000 (no revision checked out)
372 372 branch: default
373 373 commit: (clean)
374 374 update: 4 new changesets (update)
375 375
376 376 Disable progress extension and cleanup:
377 377
378 378 $ mv $HGRCPATH.no-progress $HGRCPATH
379 379
380 380 Test archiving when there is a directory in the way for a subrepo
381 381 created by archive:
382 382
383 383 $ hg clone -U . ../almost-empty
384 384 $ cd ../almost-empty
385 385 $ mkdir foo
386 386 $ echo f > foo/f
387 387 $ hg archive --subrepos -r tip archive
388 388 cloning subrepo foo from $TESTTMP/empty/foo
389 abort: destination '$TESTTMP/almost-empty/foo' is not empty (glob)
389 abort: destination '$TESTTMP/almost-empty/foo' is not empty (in subrepo foo) (glob)
390 390 [255]
391 391
392 392 Clone and test outgoing:
393 393
394 394 $ cd ..
395 395 $ hg clone repo repo2
396 396 updating to branch default
397 397 cloning subrepo foo from $TESTTMP/repo/foo
398 398 cloning subrepo foo/bar from $TESTTMP/repo/foo/bar (glob)
399 399 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
400 400 $ cd repo2
401 401 $ hg outgoing -S
402 402 comparing with $TESTTMP/repo (glob)
403 403 searching for changes
404 404 no changes found
405 405 comparing with $TESTTMP/repo/foo
406 406 searching for changes
407 407 no changes found
408 408 comparing with $TESTTMP/repo/foo/bar
409 409 searching for changes
410 410 no changes found
411 411 [1]
412 412
413 413 Make nested change:
414 414
415 415 $ echo y4 >> foo/y.txt
416 416 $ hg diff --nodates -S
417 417 diff -r 65903cebad86 foo/y.txt
418 418 --- a/foo/y.txt
419 419 +++ b/foo/y.txt
420 420 @@ -1,3 +1,4 @@
421 421 y1
422 422 y2
423 423 y3
424 424 +y4
425 425 $ hg commit --subrepos -m 3-4-2
426 426 committing subrepository foo
427 427 $ hg outgoing -S
428 428 comparing with $TESTTMP/repo (glob)
429 429 searching for changes
430 430 changeset: 3:2655b8ecc4ee
431 431 tag: tip
432 432 user: test
433 433 date: Thu Jan 01 00:00:00 1970 +0000
434 434 summary: 3-4-2
435 435
436 436 comparing with $TESTTMP/repo/foo
437 437 searching for changes
438 438 changeset: 4:e96193d6cb36
439 439 tag: tip
440 440 user: test
441 441 date: Thu Jan 01 00:00:00 1970 +0000
442 442 summary: 3-4-2
443 443
444 444 comparing with $TESTTMP/repo/foo/bar
445 445 searching for changes
446 446 no changes found
447 447
448 448
449 449 Switch to original repo and setup default path:
450 450
451 451 $ cd ../repo
452 452 $ echo '[paths]' >> .hg/hgrc
453 453 $ echo 'default = ../repo2' >> .hg/hgrc
454 454
455 455 Test incoming:
456 456
457 457 $ hg incoming -S
458 458 comparing with $TESTTMP/repo2 (glob)
459 459 searching for changes
460 460 changeset: 3:2655b8ecc4ee
461 461 tag: tip
462 462 user: test
463 463 date: Thu Jan 01 00:00:00 1970 +0000
464 464 summary: 3-4-2
465 465
466 466 comparing with $TESTTMP/repo2/foo
467 467 searching for changes
468 468 changeset: 4:e96193d6cb36
469 469 tag: tip
470 470 user: test
471 471 date: Thu Jan 01 00:00:00 1970 +0000
472 472 summary: 3-4-2
473 473
474 474 comparing with $TESTTMP/repo2/foo/bar
475 475 searching for changes
476 476 no changes found
477 477
478 478 $ hg incoming -S --bundle incoming.hg
479 479 abort: cannot combine --bundle and --subrepos
480 480 [255]
481 481
482 482 Test missing subrepo:
483 483
484 484 $ rm -r foo
485 485 $ hg status -S
486 486 warning: error "unknown revision '65903cebad86f1a84bd4f1134f62fa7dcb7a1c98'" in subrepository "foo"
487 487
488 488 Issue2619: IndexError: list index out of range on hg add with subrepos
489 489 The subrepo must sorts after the explicit filename.
490 490
491 491 $ cd ..
492 492 $ hg init test
493 493 $ cd test
494 494 $ hg init x
495 495 $ echo "x = x" >> .hgsub
496 496 $ hg add .hgsub
497 497 $ touch a x/a
498 498 $ hg add a x/a
499 499
500 500 $ cd ..
@@ -1,625 +1,625 b''
1 1 $ "$TESTDIR/hghave" svn15 || exit 80
2 2
3 3 $ SVNREPOPATH=`pwd`/svn-repo
4 4 #if windows
5 5 $ SVNREPOURL=file:///`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$SVNREPOPATH"`
6 6 #else
7 7 $ SVNREPOURL=file://`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$SVNREPOPATH"`
8 8 #endif
9 9
10 10 create subversion repo
11 11
12 12 $ WCROOT="`pwd`/svn-wc"
13 13 $ svnadmin create svn-repo
14 14 $ svn co "$SVNREPOURL" svn-wc
15 15 Checked out revision 0.
16 16 $ cd svn-wc
17 17 $ mkdir src
18 18 $ echo alpha > src/alpha
19 19 $ svn add src
20 20 A src
21 21 A src/alpha (glob)
22 22 $ mkdir externals
23 23 $ echo other > externals/other
24 24 $ svn add externals
25 25 A externals
26 26 A externals/other (glob)
27 27 $ svn ci -m 'Add alpha'
28 28 Adding externals
29 29 Adding externals/other (glob)
30 30 Adding src
31 31 Adding src/alpha (glob)
32 32 Transmitting file data ..
33 33 Committed revision 1.
34 34 $ svn up -q
35 35 $ echo "externals -r1 $SVNREPOURL/externals" > extdef
36 36 $ svn propset -F extdef svn:externals src
37 37 property 'svn:externals' set on 'src'
38 38 $ svn ci -m 'Setting externals'
39 39 Sending src
40 40
41 41 Committed revision 2.
42 42 $ cd ..
43 43
44 44 create hg repo
45 45
46 46 $ mkdir sub
47 47 $ cd sub
48 48 $ hg init t
49 49 $ cd t
50 50
51 51 first revision, no sub
52 52
53 53 $ echo a > a
54 54 $ hg ci -Am0
55 55 adding a
56 56
57 57 add first svn sub with leading whitespaces
58 58
59 59 $ echo "s = [svn] $SVNREPOURL/src" >> .hgsub
60 60 $ echo "subdir/s = [svn] $SVNREPOURL/src" >> .hgsub
61 61 $ svn co --quiet "$SVNREPOURL"/src s
62 62 $ mkdir subdir
63 63 $ svn co --quiet "$SVNREPOURL"/src subdir/s
64 64 $ hg add .hgsub
65 65 $ hg ci -m1
66 66
67 67 make sure we avoid empty commits (issue2445)
68 68
69 69 $ hg sum
70 70 parent: 1:* tip (glob)
71 71 1
72 72 branch: default
73 73 commit: (clean)
74 74 update: (current)
75 75 $ hg ci -moops
76 76 nothing changed
77 77 [1]
78 78
79 79 debugsub
80 80
81 81 $ hg debugsub
82 82 path s
83 83 source file://*/svn-repo/src (glob)
84 84 revision 2
85 85 path subdir/s
86 86 source file://*/svn-repo/src (glob)
87 87 revision 2
88 88
89 89 change file in svn and hg, commit
90 90
91 91 $ echo a >> a
92 92 $ echo alpha >> s/alpha
93 93 $ hg sum
94 94 parent: 1:* tip (glob)
95 95 1
96 96 branch: default
97 97 commit: 1 modified, 1 subrepos
98 98 update: (current)
99 99 $ hg commit --subrepos -m 'Message!' | grep -v Updating
100 100 committing subrepository s
101 101 Sending*s/alpha (glob)
102 102 Transmitting file data .
103 103 Committed revision 3.
104 104
105 105 Fetching external item into '*s/externals'* (glob)
106 106 External at revision 1.
107 107
108 108 At revision 3.
109 109 $ hg debugsub
110 110 path s
111 111 source file://*/svn-repo/src (glob)
112 112 revision 3
113 113 path subdir/s
114 114 source file://*/svn-repo/src (glob)
115 115 revision 2
116 116
117 117 missing svn file, commit should fail
118 118
119 119 $ rm s/alpha
120 120 $ hg commit --subrepos -m 'abort on missing file'
121 121 committing subrepository s
122 abort: cannot commit missing svn entries
122 abort: cannot commit missing svn entries (in subrepo s)
123 123 [255]
124 124 $ svn revert s/alpha > /dev/null
125 125
126 126 add an unrelated revision in svn and update the subrepo to without
127 127 bringing any changes.
128 128
129 129 $ svn mkdir "$SVNREPOURL/unrelated" -m 'create unrelated'
130 130
131 131 Committed revision 4.
132 132 $ svn up -q s
133 133 $ hg sum
134 134 parent: 2:* tip (glob)
135 135 Message!
136 136 branch: default
137 137 commit: (clean)
138 138 update: (current)
139 139
140 140 $ echo a > s/a
141 141
142 142 should be empty despite change to s/a
143 143
144 144 $ hg st
145 145
146 146 add a commit from svn
147 147
148 148 $ cd "$WCROOT/src"
149 149 $ svn up -q
150 150 $ echo xyz >> alpha
151 151 $ svn propset svn:mime-type 'text/xml' alpha
152 152 property 'svn:mime-type' set on 'alpha'
153 153 $ svn ci -m 'amend a from svn'
154 154 Sending *alpha (glob)
155 155 Transmitting file data .
156 156 Committed revision 5.
157 157 $ cd ../../sub/t
158 158
159 159 this commit from hg will fail
160 160
161 161 $ echo zzz >> s/alpha
162 162 $ (hg ci --subrepos -m 'amend alpha from hg' 2>&1; echo "[$?]") | grep -vi 'out of date'
163 163 committing subrepository s
164 164 abort: svn:*Commit failed (details follow): (glob)
165 165 [255]
166 166 $ svn revert -q s/alpha
167 167
168 168 this commit fails because of meta changes
169 169
170 170 $ svn propset svn:mime-type 'text/html' s/alpha
171 171 property 'svn:mime-type' set on 's/alpha' (glob)
172 172 $ (hg ci --subrepos -m 'amend alpha from hg' 2>&1; echo "[$?]") | grep -vi 'out of date'
173 173 committing subrepository s
174 174 abort: svn:*Commit failed (details follow): (glob)
175 175 [255]
176 176 $ svn revert -q s/alpha
177 177
178 178 this commit fails because of externals changes
179 179
180 180 $ echo zzz > s/externals/other
181 181 $ hg ci --subrepos -m 'amend externals from hg'
182 182 committing subrepository s
183 abort: cannot commit svn externals
183 abort: cannot commit svn externals (in subrepo s)
184 184 [255]
185 185 $ hg diff --subrepos -r 1:2 | grep -v diff
186 186 --- a/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
187 187 +++ b/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
188 188 @@ -1,2 +1,2 @@
189 189 -2 s
190 190 +3 s
191 191 2 subdir/s
192 192 --- a/a Thu Jan 01 00:00:00 1970 +0000
193 193 +++ b/a Thu Jan 01 00:00:00 1970 +0000
194 194 @@ -1,1 +1,2 @@
195 195 a
196 196 +a
197 197 $ svn revert -q s/externals/other
198 198
199 199 this commit fails because of externals meta changes
200 200
201 201 $ svn propset svn:mime-type 'text/html' s/externals/other
202 202 property 'svn:mime-type' set on 's/externals/other' (glob)
203 203 $ hg ci --subrepos -m 'amend externals from hg'
204 204 committing subrepository s
205 abort: cannot commit svn externals
205 abort: cannot commit svn externals (in subrepo s)
206 206 [255]
207 207 $ svn revert -q s/externals/other
208 208
209 209 clone
210 210
211 211 $ cd ..
212 212 $ hg clone t tc
213 213 updating to branch default
214 214 A tc/s/alpha (glob)
215 215 U tc/s (glob)
216 216
217 217 Fetching external item into 'tc/s/externals'* (glob)
218 218 A tc/s/externals/other (glob)
219 219 Checked out external at revision 1.
220 220
221 221 Checked out revision 3.
222 222 A tc/subdir/s/alpha (glob)
223 223 U tc/subdir/s (glob)
224 224
225 225 Fetching external item into 'tc/subdir/s/externals'* (glob)
226 226 A tc/subdir/s/externals/other (glob)
227 227 Checked out external at revision 1.
228 228
229 229 Checked out revision 2.
230 230 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
231 231 $ cd tc
232 232
233 233 debugsub in clone
234 234
235 235 $ hg debugsub
236 236 path s
237 237 source file://*/svn-repo/src (glob)
238 238 revision 3
239 239 path subdir/s
240 240 source file://*/svn-repo/src (glob)
241 241 revision 2
242 242
243 243 verify subrepo is contained within the repo directory
244 244
245 245 $ python -c "import os.path; print os.path.exists('s')"
246 246 True
247 247
248 248 update to nullrev (must delete the subrepo)
249 249
250 250 $ hg up null
251 251 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
252 252 $ ls
253 253
254 254 Check hg update --clean
255 255 $ cd "$TESTTMP/sub/t"
256 256 $ cd s
257 257 $ echo c0 > alpha
258 258 $ echo c1 > f1
259 259 $ echo c1 > f2
260 260 $ svn add f1 -q
261 261 $ svn status | sort
262 262
263 263 ? * a (glob)
264 264 ? * f2 (glob)
265 265 A * f1 (glob)
266 266 M * alpha (glob)
267 267 Performing status on external item at 'externals'* (glob)
268 268 X * externals (glob)
269 269 $ cd ../..
270 270 $ hg -R t update -C
271 271
272 272 Fetching external item into 't/s/externals'* (glob)
273 273 Checked out external at revision 1.
274 274
275 275 Checked out revision 3.
276 276 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
277 277 $ cd t/s
278 278 $ svn status | sort
279 279
280 280 ? * a (glob)
281 281 ? * f1 (glob)
282 282 ? * f2 (glob)
283 283 Performing status on external item at 'externals'* (glob)
284 284 X * externals (glob)
285 285
286 286 Sticky subrepositories, no changes
287 287 $ cd "$TESTTMP/sub/t"
288 288 $ hg id -n
289 289 2
290 290 $ cd s
291 291 $ svnversion
292 292 3
293 293 $ cd ..
294 294 $ hg update 1
295 295 U *s/alpha (glob)
296 296
297 297 Fetching external item into '*s/externals'* (glob)
298 298 Checked out external at revision 1.
299 299
300 300 Checked out revision 2.
301 301 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
302 302 $ hg id -n
303 303 1
304 304 $ cd s
305 305 $ svnversion
306 306 2
307 307 $ cd ..
308 308
309 309 Sticky subrepositorys, file changes
310 310 $ touch s/f1
311 311 $ cd s
312 312 $ svn add f1
313 313 A f1
314 314 $ cd ..
315 315 $ hg id -n
316 316 1+
317 317 $ cd s
318 318 $ svnversion
319 319 2M
320 320 $ cd ..
321 321 $ hg update tip
322 322 subrepository sources for s differ
323 323 use (l)ocal source (2) or (r)emote source (3)?
324 324 l
325 325 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
326 326 $ hg id -n
327 327 2+
328 328 $ cd s
329 329 $ svnversion
330 330 2M
331 331 $ cd ..
332 332 $ hg update --clean tip
333 333 U *s/alpha (glob)
334 334
335 335 Fetching external item into '*s/externals'* (glob)
336 336 Checked out external at revision 1.
337 337
338 338 Checked out revision 3.
339 339 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
340 340
341 341 Sticky subrepository, revision updates
342 342 $ hg id -n
343 343 2
344 344 $ cd s
345 345 $ svnversion
346 346 3
347 347 $ cd ..
348 348 $ cd s
349 349 $ svn update -qr 1
350 350 $ cd ..
351 351 $ hg update 1
352 352 subrepository sources for s differ (in checked out version)
353 353 use (l)ocal source (1) or (r)emote source (2)?
354 354 l
355 355 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
356 356 $ hg id -n
357 357 1+
358 358 $ cd s
359 359 $ svnversion
360 360 1
361 361 $ cd ..
362 362
363 363 Sticky subrepository, file changes and revision updates
364 364 $ touch s/f1
365 365 $ cd s
366 366 $ svn add f1
367 367 A f1
368 368 $ svnversion
369 369 1M
370 370 $ cd ..
371 371 $ hg id -n
372 372 1+
373 373 $ hg update tip
374 374 subrepository sources for s differ
375 375 use (l)ocal source (1) or (r)emote source (3)?
376 376 l
377 377 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
378 378 $ hg id -n
379 379 2+
380 380 $ cd s
381 381 $ svnversion
382 382 1M
383 383 $ cd ..
384 384
385 385 Sticky repository, update --clean
386 386 $ hg update --clean tip | grep -v 's[/\]externals[/\]other'
387 387 U *s/alpha (glob)
388 388 U *s (glob)
389 389
390 390 Fetching external item into '*s/externals'* (glob)
391 391 Checked out external at revision 1.
392 392
393 393 Checked out revision 3.
394 394 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
395 395 $ hg id -n
396 396 2
397 397 $ cd s
398 398 $ svnversion
399 399 3
400 400 $ cd ..
401 401
402 402 Test subrepo already at intended revision:
403 403 $ cd s
404 404 $ svn update -qr 2
405 405 $ cd ..
406 406 $ hg update 1
407 407 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
408 408 $ hg id -n
409 409 1+
410 410 $ cd s
411 411 $ svnversion
412 412 2
413 413 $ cd ..
414 414
415 415 Test case where subversion would fail to update the subrepo because there
416 416 are unknown directories being replaced by tracked ones (happens with rebase).
417 417
418 418 $ cd "$WCROOT/src"
419 419 $ mkdir dir
420 420 $ echo epsilon.py > dir/epsilon.py
421 421 $ svn add dir
422 422 A dir
423 423 A dir/epsilon.py (glob)
424 424 $ svn ci -m 'Add dir/epsilon.py'
425 425 Adding *dir (glob)
426 426 Adding *dir/epsilon.py (glob)
427 427 Transmitting file data .
428 428 Committed revision 6.
429 429 $ cd ../..
430 430 $ hg init rebaserepo
431 431 $ cd rebaserepo
432 432 $ svn co -r5 --quiet "$SVNREPOURL"/src s
433 433 $ echo "s = [svn] $SVNREPOURL/src" >> .hgsub
434 434 $ hg add .hgsub
435 435 $ hg ci -m addsub
436 436 $ echo a > a
437 437 $ hg ci -Am adda
438 438 adding a
439 439 $ hg up 0
440 440 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
441 441 $ svn up -qr6 s
442 442 $ hg ci -m updatesub
443 443 created new head
444 444 $ echo pyc > s/dir/epsilon.pyc
445 445 $ hg up 1
446 446 D *s/dir (glob)
447 447
448 448 Fetching external item into '*s/externals'* (glob)
449 449 Checked out external at revision 1.
450 450
451 451 Checked out revision 5.
452 452 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
453 453 $ hg up -q 2
454 454
455 455 Modify one of the externals to point to a different path so we can
456 456 test having obstructions when switching branches on checkout:
457 457 $ hg checkout tip
458 458 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
459 459 $ echo "obstruct = [svn] $SVNREPOURL/externals" >> .hgsub
460 460 $ svn co -r5 --quiet "$SVNREPOURL"/externals obstruct
461 461 $ hg commit -m 'Start making obstructed working copy'
462 462 $ hg book other
463 463 $ hg co -r 'p1(tip)'
464 464 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
465 465 $ echo "obstruct = [svn] $SVNREPOURL/src" >> .hgsub
466 466 $ svn co -r5 --quiet "$SVNREPOURL"/src obstruct
467 467 $ hg commit -m 'Other branch which will be obstructed'
468 468 created new head
469 469
470 470 Switching back to the head where we have another path mapped to the
471 471 same subrepo should work if the subrepo is clean.
472 472 $ hg co other
473 473 A *obstruct/other (glob)
474 474 Checked out revision 1.
475 475 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
476 476
477 477 This is surprising, but is also correct based on the current code:
478 478 $ echo "updating should (maybe) fail" > obstruct/other
479 479 $ hg co tip
480 480 abort: crosses branches (merge branches or use --clean to discard changes)
481 481 [255]
482 482
483 483 Point to a Subversion branch which has since been deleted and recreated
484 484 First, create that condition in the repository.
485 485
486 486 $ hg ci --subrepos -m cleanup | grep -v Updating
487 487 committing subrepository obstruct
488 488 Sending obstruct/other (glob)
489 489 Transmitting file data .
490 490 Committed revision 7.
491 491 At revision 7.
492 492 $ svn mkdir -m "baseline" $SVNREPOURL/trunk
493 493
494 494 Committed revision 8.
495 495 $ svn copy -m "initial branch" $SVNREPOURL/trunk $SVNREPOURL/branch
496 496
497 497 Committed revision 9.
498 498 $ svn co --quiet "$SVNREPOURL"/branch tempwc
499 499 $ cd tempwc
500 500 $ echo "something old" > somethingold
501 501 $ svn add somethingold
502 502 A somethingold
503 503 $ svn ci -m 'Something old'
504 504 Adding somethingold
505 505 Transmitting file data .
506 506 Committed revision 10.
507 507 $ svn rm -m "remove branch" $SVNREPOURL/branch
508 508
509 509 Committed revision 11.
510 510 $ svn copy -m "recreate branch" $SVNREPOURL/trunk $SVNREPOURL/branch
511 511
512 512 Committed revision 12.
513 513 $ svn up -q
514 514 $ echo "something new" > somethingnew
515 515 $ svn add somethingnew
516 516 A somethingnew
517 517 $ svn ci -m 'Something new'
518 518 Adding somethingnew
519 519 Transmitting file data .
520 520 Committed revision 13.
521 521 $ cd ..
522 522 $ rm -rf tempwc
523 523 $ svn co "$SVNREPOURL/branch"@10 recreated
524 524 A recreated/somethingold (glob)
525 525 Checked out revision 10.
526 526 $ echo "recreated = [svn] $SVNREPOURL/branch" >> .hgsub
527 527 $ hg ci -m addsub
528 528 $ cd recreated
529 529 $ svn up -q
530 530 $ cd ..
531 531 $ hg ci -m updatesub
532 532 $ hg up -r-2
533 533 D *recreated/somethingnew (glob)
534 534 A *recreated/somethingold (glob)
535 535 Checked out revision 10.
536 536 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
537 537 $ test -f recreated/somethingold
538 538
539 539 Test archive
540 540
541 541 $ hg archive -S ../archive-all --debug
542 542 archiving: 0/2 files (0.00%)
543 543 archiving: .hgsub 1/2 files (50.00%)
544 544 archiving: .hgsubstate 2/2 files (100.00%)
545 545 archiving (obstruct): 0/1 files (0.00%)
546 546 archiving (obstruct): 1/1 files (100.00%)
547 547 archiving (s): 0/2 files (0.00%)
548 548 archiving (s): 1/2 files (50.00%)
549 549 archiving (s): 2/2 files (100.00%)
550 550 archiving (recreated): 0/1 files (0.00%)
551 551 archiving (recreated): 1/1 files (100.00%)
552 552
553 553 $ hg archive -S ../archive-exclude --debug -X **old
554 554 archiving: 0/2 files (0.00%)
555 555 archiving: .hgsub 1/2 files (50.00%)
556 556 archiving: .hgsubstate 2/2 files (100.00%)
557 557 archiving (obstruct): 0/1 files (0.00%)
558 558 archiving (obstruct): 1/1 files (100.00%)
559 559 archiving (s): 0/2 files (0.00%)
560 560 archiving (s): 1/2 files (50.00%)
561 561 archiving (s): 2/2 files (100.00%)
562 562 archiving (recreated): 0 files
563 563 $ find ../archive-exclude | sort
564 564 ../archive-exclude
565 565 ../archive-exclude/.hg_archival.txt
566 566 ../archive-exclude/.hgsub
567 567 ../archive-exclude/.hgsubstate
568 568 ../archive-exclude/obstruct
569 569 ../archive-exclude/obstruct/other
570 570 ../archive-exclude/s
571 571 ../archive-exclude/s/alpha
572 572 ../archive-exclude/s/dir
573 573 ../archive-exclude/s/dir/epsilon.py
574 574
575 575 Test forgetting files, not implemented in svn subrepo, used to
576 576 traceback
577 577
578 578 #if no-windows
579 579 $ hg forget 'notafile*'
580 580 notafile*: No such file or directory
581 581 [1]
582 582 #else
583 583 $ hg forget 'notafile'
584 584 notafile: * (glob)
585 585 [1]
586 586 #endif
587 587
588 588 Test a subrepo referencing a just moved svn path. Last commit rev will
589 589 be different from the revision, and the path will be different as
590 590 well.
591 591
592 592 $ cd "$WCROOT"
593 593 $ svn up > /dev/null
594 594 $ mkdir trunk/subdir branches
595 595 $ echo a > trunk/subdir/a
596 596 $ svn add trunk/subdir branches
597 597 A trunk/subdir (glob)
598 598 A trunk/subdir/a (glob)
599 599 A branches
600 600 $ svn ci -m addsubdir
601 601 Adding branches
602 602 Adding trunk/subdir (glob)
603 603 Adding trunk/subdir/a (glob)
604 604 Transmitting file data .
605 605 Committed revision 14.
606 606 $ svn cp -m branchtrunk $SVNREPOURL/trunk $SVNREPOURL/branches/somebranch
607 607
608 608 Committed revision 15.
609 609 $ cd ..
610 610
611 611 $ hg init repo2
612 612 $ cd repo2
613 613 $ svn co $SVNREPOURL/branches/somebranch/subdir
614 614 A subdir/a (glob)
615 615 Checked out revision 15.
616 616 $ echo "subdir = [svn] $SVNREPOURL/branches/somebranch/subdir" > .hgsub
617 617 $ hg add .hgsub
618 618 $ hg ci -m addsub
619 619 $ hg up null
620 620 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
621 621 $ hg up
622 622 A *subdir/a (glob)
623 623 Checked out revision 15.
624 624 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
625 625 $ cd ..
@@ -1,1053 +1,1053 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 ci -Ams0
29 29 adding a
30 30 $ hg sum
31 31 parent: 0:f7b1eb17ad24 tip
32 32 0
33 33 branch: default
34 34 commit: 1 added, 1 subrepos
35 35 update: (current)
36 36 $ hg ci -m1
37 37
38 38 Revert subrepo and test subrepo fileset keyword:
39 39
40 40 $ echo b > s/a
41 41 $ hg revert "set:subrepo('glob:s*')"
42 42 reverting subrepo s
43 43 reverting s/a (glob)
44 44 $ rm s/a.orig
45 45
46 46 Revert subrepo with no backup. The "reverting s/a" line is gone since
47 47 we're really running 'hg update' in the subrepo:
48 48
49 49 $ echo b > s/a
50 50 $ hg revert --no-backup s
51 51 reverting subrepo s
52 52
53 53 Issue2022: update -C
54 54
55 55 $ echo b > s/a
56 56 $ hg sum
57 57 parent: 1:7cf8cfea66e4 tip
58 58 1
59 59 branch: default
60 60 commit: 1 subrepos
61 61 update: (current)
62 62 $ hg co -C 1
63 63 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 64 $ hg sum
65 65 parent: 1:7cf8cfea66e4 tip
66 66 1
67 67 branch: default
68 68 commit: (clean)
69 69 update: (current)
70 70
71 71 commands that require a clean repo should respect subrepos
72 72
73 73 $ echo b >> s/a
74 74 $ hg backout tip
75 75 abort: uncommitted changes in subrepo s
76 76 [255]
77 77 $ hg revert -C -R s s/a
78 78
79 79 add sub sub
80 80
81 81 $ echo ss = ss > s/.hgsub
82 82 $ hg init s/ss
83 83 $ echo a > s/ss/a
84 84 $ hg -R s add s/.hgsub
85 85 $ hg -R s/ss add s/ss/a
86 86 $ hg sum
87 87 parent: 1:7cf8cfea66e4 tip
88 88 1
89 89 branch: default
90 90 commit: 1 subrepos
91 91 update: (current)
92 92 $ hg ci -m2
93 93 committing subrepository s
94 94 committing subrepository s/ss (glob)
95 95 $ hg sum
96 96 parent: 2:df30734270ae tip
97 97 2
98 98 branch: default
99 99 commit: (clean)
100 100 update: (current)
101 101
102 102 bump sub rev (and check it is ignored by ui.commitsubrepos)
103 103
104 104 $ echo b > s/a
105 105 $ hg -R s ci -ms1
106 106 $ hg --config ui.commitsubrepos=no ci -m3
107 107
108 108 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
109 109
110 110 $ echo c > s/a
111 111 $ hg --config ui.commitsubrepos=no ci -m4
112 112 abort: uncommitted changes in subrepo s
113 113 (use --subrepos for recursive commit)
114 114 [255]
115 115 $ hg id
116 116 f6affe3fbfaa+ tip
117 117 $ hg -R s ci -mc
118 118 $ hg id
119 119 f6affe3fbfaa+ tip
120 120 $ echo d > s/a
121 121 $ hg ci -m4
122 122 committing subrepository s
123 123 $ hg tip -R s
124 124 changeset: 4:02dcf1d70411
125 125 tag: tip
126 126 user: test
127 127 date: Thu Jan 01 00:00:00 1970 +0000
128 128 summary: 4
129 129
130 130
131 131 check caching
132 132
133 133 $ hg co 0
134 134 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
135 135 $ hg debugsub
136 136
137 137 restore
138 138
139 139 $ hg co
140 140 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 141 $ hg debugsub
142 142 path s
143 143 source s
144 144 revision 02dcf1d704118aee3ee306ccfa1910850d5b05ef
145 145
146 146 new branch for merge tests
147 147
148 148 $ hg co 1
149 149 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
150 150 $ echo t = t >> .hgsub
151 151 $ hg init t
152 152 $ echo t > t/t
153 153 $ hg -R t add t
154 154 adding t/t (glob)
155 155
156 156 5
157 157
158 158 $ hg ci -m5 # add sub
159 159 committing subrepository t
160 160 created new head
161 161 $ echo t2 > t/t
162 162
163 163 6
164 164
165 165 $ hg st -R s
166 166 $ hg ci -m6 # change sub
167 167 committing subrepository t
168 168 $ hg debugsub
169 169 path s
170 170 source s
171 171 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
172 172 path t
173 173 source t
174 174 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
175 175 $ echo t3 > t/t
176 176
177 177 7
178 178
179 179 $ hg ci -m7 # change sub again for conflict test
180 180 committing subrepository t
181 181 $ hg rm .hgsub
182 182
183 183 8
184 184
185 185 $ hg ci -m8 # remove sub
186 186
187 187 merge tests
188 188
189 189 $ hg co -C 3
190 190 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 191 $ hg merge 5 # test adding
192 192 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
193 193 (branch merge, don't forget to commit)
194 194 $ hg debugsub
195 195 path s
196 196 source s
197 197 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
198 198 path t
199 199 source t
200 200 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
201 201 $ hg ci -m9
202 202 created new head
203 203 $ hg merge 6 --debug # test change
204 204 searching for copies back to rev 2
205 205 resolving manifests
206 206 overwrite: False, partial: False
207 207 ancestor: 1f14a2e2d3ec, local: f0d2028bf86d+, remote: 1831e14459c4
208 208 .hgsubstate: versions differ -> m
209 209 updating: .hgsubstate 1/1 files (100.00%)
210 210 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
211 211 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
212 212 getting subrepo t
213 213 searching for copies back to rev 1
214 214 resolving manifests
215 215 overwrite: False, partial: False
216 216 ancestor: 60ca1237c194, local: 60ca1237c194+, remote: 6747d179aa9a
217 217 t: remote is newer -> g
218 218 updating: t 1/1 files (100.00%)
219 219 getting t
220 220 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
221 221 (branch merge, don't forget to commit)
222 222 $ hg debugsub
223 223 path s
224 224 source s
225 225 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
226 226 path t
227 227 source t
228 228 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
229 229 $ echo conflict > t/t
230 230 $ hg ci -m10
231 231 committing subrepository t
232 232 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
233 233 searching for copies back to rev 2
234 234 resolving manifests
235 235 overwrite: False, partial: False
236 236 ancestor: 1831e14459c4, local: e45c8b14af55+, remote: f94576341bcf
237 237 .hgsubstate: versions differ -> m
238 238 updating: .hgsubstate 1/1 files (100.00%)
239 239 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
240 240 subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
241 241 merging subrepo t
242 242 searching for copies back to rev 2
243 243 resolving manifests
244 244 overwrite: False, partial: False
245 245 ancestor: 6747d179aa9a, local: 20a0db6fbf6c+, remote: 7af322bc1198
246 246 t: versions differ -> m
247 247 preserving t for resolve of t
248 248 updating: t 1/1 files (100.00%)
249 249 picked tool 'internal:merge' for t (binary False symlink False)
250 250 merging t
251 251 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
252 252 warning: conflicts during merge.
253 253 merging t incomplete! (edit conflicts, then use 'hg resolve --mark')
254 254 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
255 255 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
256 256 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
257 257 (branch merge, don't forget to commit)
258 258
259 259 should conflict
260 260
261 261 $ cat t/t
262 262 <<<<<<< local
263 263 conflict
264 264 =======
265 265 t3
266 266 >>>>>>> other
267 267
268 268 clone
269 269
270 270 $ cd ..
271 271 $ hg clone t tc
272 272 updating to branch default
273 273 cloning subrepo s from $TESTTMP/t/s (glob)
274 274 cloning subrepo s/ss from $TESTTMP/t/s/ss (glob)
275 275 cloning subrepo t from $TESTTMP/t/t (glob)
276 276 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
277 277 $ cd tc
278 278 $ hg debugsub
279 279 path s
280 280 source s
281 281 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
282 282 path t
283 283 source t
284 284 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
285 285
286 286 push
287 287
288 288 $ echo bah > t/t
289 289 $ hg ci -m11
290 290 committing subrepository t
291 291 $ hg push
292 292 pushing to $TESTTMP/t (glob)
293 293 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
294 294 searching for changes
295 295 no changes found
296 296 pushing subrepo s to $TESTTMP/t/s (glob)
297 297 searching for changes
298 298 no changes found
299 299 pushing subrepo t to $TESTTMP/t/t (glob)
300 300 searching for changes
301 301 adding changesets
302 302 adding manifests
303 303 adding file changes
304 304 added 1 changesets with 1 changes to 1 files
305 305 searching for changes
306 306 adding changesets
307 307 adding manifests
308 308 adding file changes
309 309 added 1 changesets with 1 changes to 1 files
310 310
311 311 push -f
312 312
313 313 $ echo bah > s/a
314 314 $ hg ci -m12
315 315 committing subrepository s
316 316 $ hg push
317 317 pushing to $TESTTMP/t (glob)
318 318 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
319 319 searching for changes
320 320 no changes found
321 321 pushing subrepo s to $TESTTMP/t/s (glob)
322 322 searching for changes
323 abort: push creates new remote head 12a213df6fa9!
323 abort: push creates new remote head 12a213df6fa9! (in subrepo s)
324 324 (did you forget to merge? use push -f to force)
325 325 [255]
326 326 $ hg push -f
327 327 pushing to $TESTTMP/t (glob)
328 328 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
329 329 searching for changes
330 330 no changes found
331 331 pushing subrepo s to $TESTTMP/t/s (glob)
332 332 searching for changes
333 333 adding changesets
334 334 adding manifests
335 335 adding file changes
336 336 added 1 changesets with 1 changes to 1 files (+1 heads)
337 337 pushing subrepo t to $TESTTMP/t/t (glob)
338 338 searching for changes
339 339 no changes found
340 340 searching for changes
341 341 adding changesets
342 342 adding manifests
343 343 adding file changes
344 344 added 1 changesets with 1 changes to 1 files
345 345
346 346 update
347 347
348 348 $ cd ../t
349 349 $ hg up -C # discard our earlier merge
350 350 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
351 351 $ echo blah > t/t
352 352 $ hg ci -m13
353 353 committing subrepository t
354 354
355 355 pull
356 356
357 357 $ cd ../tc
358 358 $ hg pull
359 359 pulling from $TESTTMP/t (glob)
360 360 searching for changes
361 361 adding changesets
362 362 adding manifests
363 363 adding file changes
364 364 added 1 changesets with 1 changes to 1 files
365 365 (run 'hg update' to get a working copy)
366 366
367 367 should pull t
368 368
369 369 $ hg up
370 370 pulling subrepo t from $TESTTMP/t/t (glob)
371 371 searching for changes
372 372 adding changesets
373 373 adding manifests
374 374 adding file changes
375 375 added 1 changesets with 1 changes to 1 files
376 376 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
377 377 $ cat t/t
378 378 blah
379 379
380 380 bogus subrepo path aborts
381 381
382 382 $ echo 'bogus=[boguspath' >> .hgsub
383 383 $ hg ci -m 'bogus subrepo path'
384 384 abort: missing ] in subrepo source
385 385 [255]
386 386
387 387 Issue1986: merge aborts when trying to merge a subrepo that
388 388 shouldn't need merging
389 389
390 390 # subrepo layout
391 391 #
392 392 # o 5 br
393 393 # /|
394 394 # o | 4 default
395 395 # | |
396 396 # | o 3 br
397 397 # |/|
398 398 # o | 2 default
399 399 # | |
400 400 # | o 1 br
401 401 # |/
402 402 # o 0 default
403 403
404 404 $ cd ..
405 405 $ rm -rf sub
406 406 $ hg init main
407 407 $ cd main
408 408 $ hg init s
409 409 $ cd s
410 410 $ echo a > a
411 411 $ hg ci -Am1
412 412 adding a
413 413 $ hg branch br
414 414 marked working directory as branch br
415 415 (branches are permanent and global, did you want a bookmark?)
416 416 $ echo a >> a
417 417 $ hg ci -m1
418 418 $ hg up default
419 419 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
420 420 $ echo b > b
421 421 $ hg ci -Am1
422 422 adding b
423 423 $ hg up br
424 424 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
425 425 $ hg merge tip
426 426 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
427 427 (branch merge, don't forget to commit)
428 428 $ hg ci -m1
429 429 $ hg up 2
430 430 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
431 431 $ echo c > c
432 432 $ hg ci -Am1
433 433 adding c
434 434 $ hg up 3
435 435 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
436 436 $ hg merge 4
437 437 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
438 438 (branch merge, don't forget to commit)
439 439 $ hg ci -m1
440 440
441 441 # main repo layout:
442 442 #
443 443 # * <-- try to merge default into br again
444 444 # .`|
445 445 # . o 5 br --> substate = 5
446 446 # . |
447 447 # o | 4 default --> substate = 4
448 448 # | |
449 449 # | o 3 br --> substate = 2
450 450 # |/|
451 451 # o | 2 default --> substate = 2
452 452 # | |
453 453 # | o 1 br --> substate = 3
454 454 # |/
455 455 # o 0 default --> substate = 2
456 456
457 457 $ cd ..
458 458 $ echo 's = s' > .hgsub
459 459 $ hg -R s up 2
460 460 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
461 461 $ hg ci -Am1
462 462 adding .hgsub
463 463 $ hg branch br
464 464 marked working directory as branch br
465 465 (branches are permanent and global, did you want a bookmark?)
466 466 $ echo b > b
467 467 $ hg -R s up 3
468 468 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
469 469 $ hg ci -Am1
470 470 adding b
471 471 $ hg up default
472 472 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
473 473 $ echo c > c
474 474 $ hg ci -Am1
475 475 adding c
476 476 $ hg up 1
477 477 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
478 478 $ hg merge 2
479 479 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
480 480 (branch merge, don't forget to commit)
481 481 $ hg ci -m1
482 482 $ hg up 2
483 483 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
484 484 $ hg -R s up 4
485 485 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
486 486 $ echo d > d
487 487 $ hg ci -Am1
488 488 adding d
489 489 $ hg up 3
490 490 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
491 491 $ hg -R s up 5
492 492 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
493 493 $ echo e > e
494 494 $ hg ci -Am1
495 495 adding e
496 496
497 497 $ hg up 5
498 498 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
499 499 $ hg merge 4 # try to merge default into br again
500 500 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
501 501 (branch merge, don't forget to commit)
502 502 $ cd ..
503 503
504 504 test subrepo delete from .hgsubstate
505 505
506 506 $ hg init testdelete
507 507 $ mkdir testdelete/nested testdelete/nested2
508 508 $ hg init testdelete/nested
509 509 $ hg init testdelete/nested2
510 510 $ echo test > testdelete/nested/foo
511 511 $ echo test > testdelete/nested2/foo
512 512 $ hg -R testdelete/nested add
513 513 adding testdelete/nested/foo (glob)
514 514 $ hg -R testdelete/nested2 add
515 515 adding testdelete/nested2/foo (glob)
516 516 $ hg -R testdelete/nested ci -m test
517 517 $ hg -R testdelete/nested2 ci -m test
518 518 $ echo nested = nested > testdelete/.hgsub
519 519 $ echo nested2 = nested2 >> testdelete/.hgsub
520 520 $ hg -R testdelete add
521 521 adding testdelete/.hgsub (glob)
522 522 $ hg -R testdelete ci -m "nested 1 & 2 added"
523 523 $ echo nested = nested > testdelete/.hgsub
524 524 $ hg -R testdelete ci -m "nested 2 deleted"
525 525 $ cat testdelete/.hgsubstate
526 526 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
527 527 $ hg -R testdelete remove testdelete/.hgsub
528 528 $ hg -R testdelete ci -m ".hgsub deleted"
529 529 $ cat testdelete/.hgsubstate
530 530 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
531 531
532 532 test repository cloning
533 533
534 534 $ mkdir mercurial mercurial2
535 535 $ hg init nested_absolute
536 536 $ echo test > nested_absolute/foo
537 537 $ hg -R nested_absolute add
538 538 adding nested_absolute/foo (glob)
539 539 $ hg -R nested_absolute ci -mtest
540 540 $ cd mercurial
541 541 $ hg init nested_relative
542 542 $ echo test2 > nested_relative/foo2
543 543 $ hg -R nested_relative add
544 544 adding nested_relative/foo2 (glob)
545 545 $ hg -R nested_relative ci -mtest2
546 546 $ hg init main
547 547 $ echo "nested_relative = ../nested_relative" > main/.hgsub
548 548 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
549 549 $ hg -R main add
550 550 adding main/.hgsub (glob)
551 551 $ hg -R main ci -m "add subrepos"
552 552 $ cd ..
553 553 $ hg clone mercurial/main mercurial2/main
554 554 updating to branch default
555 555 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
556 556 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
557 557 > mercurial2/main/nested_relative/.hg/hgrc
558 558 [paths]
559 559 default = $TESTTMP/mercurial/nested_absolute
560 560 [paths]
561 561 default = $TESTTMP/mercurial/nested_relative
562 562 $ rm -rf mercurial mercurial2
563 563
564 564 Issue1977: multirepo push should fail if subrepo push fails
565 565
566 566 $ hg init repo
567 567 $ hg init repo/s
568 568 $ echo a > repo/s/a
569 569 $ hg -R repo/s ci -Am0
570 570 adding a
571 571 $ echo s = s > repo/.hgsub
572 572 $ hg -R repo ci -Am1
573 573 adding .hgsub
574 574 $ hg clone repo repo2
575 575 updating to branch default
576 576 cloning subrepo s from $TESTTMP/repo/s (glob)
577 577 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
578 578 $ hg -q -R repo2 pull -u
579 579 $ echo 1 > repo2/s/a
580 580 $ hg -R repo2/s ci -m2
581 581 $ hg -q -R repo2/s push
582 582 $ hg -R repo2/s up -C 0
583 583 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
584 584 $ echo 2 > repo2/s/b
585 585 $ hg -R repo2/s ci -m3 -A
586 586 adding b
587 587 created new head
588 588 $ hg -R repo2 ci -m3
589 589 $ hg -q -R repo2 push
590 abort: push creates new remote head cc505f09a8b2!
590 abort: push creates new remote head cc505f09a8b2! (in subrepo s)
591 591 (did you forget to merge? use push -f to force)
592 592 [255]
593 593 $ hg -R repo update
594 594 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
595 595
596 596 test if untracked file is not overwritten
597 597
598 598 $ echo issue3276_ok > repo/s/b
599 599 $ hg -R repo2 push -f -q
600 600 $ hg -R repo update
601 601 b: untracked file differs
602 abort: untracked files in working directory differ from files in requested revision
602 abort: untracked files in working directory differ from files in requested revision (in subrepo s)
603 603 [255]
604 604
605 605 $ cat repo/s/b
606 606 issue3276_ok
607 607 $ rm repo/s/b
608 608 $ hg -R repo revert --all
609 609 reverting repo/.hgsubstate (glob)
610 610 reverting subrepo s
611 611 $ hg -R repo update
612 612 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
613 613 $ cat repo/s/b
614 614 2
615 615 $ rm -rf repo2 repo
616 616
617 617
618 618 Issue1852 subrepos with relative paths always push/pull relative to default
619 619
620 620 Prepare a repo with subrepo
621 621
622 622 $ hg init issue1852a
623 623 $ cd issue1852a
624 624 $ hg init sub/repo
625 625 $ echo test > sub/repo/foo
626 626 $ hg -R sub/repo add sub/repo/foo
627 627 $ echo sub/repo = sub/repo > .hgsub
628 628 $ hg add .hgsub
629 629 $ hg ci -mtest
630 630 committing subrepository sub/repo (glob)
631 631 $ echo test >> sub/repo/foo
632 632 $ hg ci -mtest
633 633 committing subrepository sub/repo (glob)
634 634 $ cd ..
635 635
636 636 Create repo without default path, pull top repo, and see what happens on update
637 637
638 638 $ hg init issue1852b
639 639 $ hg -R issue1852b pull issue1852a
640 640 pulling from issue1852a
641 641 requesting all changes
642 642 adding changesets
643 643 adding manifests
644 644 adding file changes
645 645 added 2 changesets with 3 changes to 2 files
646 646 (run 'hg update' to get a working copy)
647 647 $ hg -R issue1852b update
648 abort: default path for subrepository sub/repo not found (glob)
648 abort: default path for subrepository not found (in subrepo sub/repo) (glob)
649 649 [255]
650 650
651 651 Pull -u now doesn't help
652 652
653 653 $ hg -R issue1852b pull -u issue1852a
654 654 pulling from issue1852a
655 655 searching for changes
656 656 no changes found
657 657
658 658 Try the same, but with pull -u
659 659
660 660 $ hg init issue1852c
661 661 $ hg -R issue1852c pull -r0 -u issue1852a
662 662 pulling from issue1852a
663 663 adding changesets
664 664 adding manifests
665 665 adding file changes
666 666 added 1 changesets with 2 changes to 2 files
667 667 cloning subrepo sub/repo from issue1852a/sub/repo (glob)
668 668 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
669 669
670 670 Try to push from the other side
671 671
672 672 $ hg -R issue1852a push `pwd`/issue1852c
673 673 pushing to $TESTTMP/issue1852c
674 674 pushing subrepo sub/repo to $TESTTMP/issue1852c/sub/repo (glob)
675 675 searching for changes
676 676 no changes found
677 677 searching for changes
678 678 adding changesets
679 679 adding manifests
680 680 adding file changes
681 681 added 1 changesets with 1 changes to 1 files
682 682
683 683 Incoming and outgoing should not use the default path:
684 684
685 685 $ hg clone -q issue1852a issue1852d
686 686 $ hg -R issue1852d outgoing --subrepos issue1852c
687 687 comparing with issue1852c
688 688 searching for changes
689 689 no changes found
690 690 comparing with issue1852c/sub/repo
691 691 searching for changes
692 692 no changes found
693 693 [1]
694 694 $ hg -R issue1852d incoming --subrepos issue1852c
695 695 comparing with issue1852c
696 696 searching for changes
697 697 no changes found
698 698 comparing with issue1852c/sub/repo
699 699 searching for changes
700 700 no changes found
701 701 [1]
702 702
703 703 Check status of files when none of them belong to the first
704 704 subrepository:
705 705
706 706 $ hg init subrepo-status
707 707 $ cd subrepo-status
708 708 $ hg init subrepo-1
709 709 $ hg init subrepo-2
710 710 $ cd subrepo-2
711 711 $ touch file
712 712 $ hg add file
713 713 $ cd ..
714 714 $ echo subrepo-1 = subrepo-1 > .hgsub
715 715 $ echo subrepo-2 = subrepo-2 >> .hgsub
716 716 $ hg add .hgsub
717 717 $ hg ci -m 'Added subrepos'
718 718 committing subrepository subrepo-2
719 719 $ hg st subrepo-2/file
720 720
721 721 Check that share works with subrepo
722 722 $ hg --config extensions.share= share . ../shared
723 723 updating working directory
724 724 cloning subrepo subrepo-2 from $TESTTMP/subrepo-status/subrepo-2
725 725 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
726 726 $ test -f ../shared/subrepo-1/.hg/sharedpath
727 727 [1]
728 728
729 729 Check hg update --clean
730 730 $ cd $TESTTMP/t
731 731 $ rm -r t/t.orig
732 732 $ hg status -S --all
733 733 C .hgsub
734 734 C .hgsubstate
735 735 C a
736 736 C s/.hgsub
737 737 C s/.hgsubstate
738 738 C s/a
739 739 C s/ss/a
740 740 C t/t
741 741 $ echo c1 > s/a
742 742 $ cd s
743 743 $ echo c1 > b
744 744 $ echo c1 > c
745 745 $ hg add b
746 746 $ cd ..
747 747 $ hg status -S
748 748 M s/a
749 749 A s/b
750 750 ? s/c
751 751 $ hg update -C
752 752 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
753 753 $ hg status -S
754 754 ? s/b
755 755 ? s/c
756 756
757 757 Sticky subrepositories, no changes
758 758 $ cd $TESTTMP/t
759 759 $ hg id
760 760 925c17564ef8 tip
761 761 $ hg -R s id
762 762 12a213df6fa9 tip
763 763 $ hg -R t id
764 764 52c0adc0515a tip
765 765 $ hg update 11
766 766 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
767 767 $ hg id
768 768 365661e5936a
769 769 $ hg -R s id
770 770 fc627a69481f
771 771 $ hg -R t id
772 772 e95bcfa18a35
773 773
774 774 Sticky subrepositorys, file changes
775 775 $ touch s/f1
776 776 $ touch t/f1
777 777 $ hg add -S s/f1
778 778 $ hg add -S t/f1
779 779 $ hg id
780 780 365661e5936a+
781 781 $ hg -R s id
782 782 fc627a69481f+
783 783 $ hg -R t id
784 784 e95bcfa18a35+
785 785 $ hg update tip
786 786 subrepository sources for s differ
787 787 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
788 788 l
789 789 subrepository sources for t differ
790 790 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
791 791 l
792 792 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
793 793 $ hg id
794 794 925c17564ef8+ tip
795 795 $ hg -R s id
796 796 fc627a69481f+
797 797 $ hg -R t id
798 798 e95bcfa18a35+
799 799 $ hg update --clean tip
800 800 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
801 801
802 802 Sticky subrepository, revision updates
803 803 $ hg id
804 804 925c17564ef8 tip
805 805 $ hg -R s id
806 806 12a213df6fa9 tip
807 807 $ hg -R t id
808 808 52c0adc0515a tip
809 809 $ cd s
810 810 $ hg update -r -2
811 811 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
812 812 $ cd ../t
813 813 $ hg update -r 2
814 814 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
815 815 $ cd ..
816 816 $ hg update 10
817 817 subrepository sources for t differ (in checked out version)
818 818 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
819 819 l
820 820 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
821 821 $ hg id
822 822 e45c8b14af55+
823 823 $ hg -R s id
824 824 02dcf1d70411
825 825 $ hg -R t id
826 826 7af322bc1198
827 827
828 828 Sticky subrepository, file changes and revision updates
829 829 $ touch s/f1
830 830 $ touch t/f1
831 831 $ hg add -S s/f1
832 832 $ hg add -S t/f1
833 833 $ hg id
834 834 e45c8b14af55+
835 835 $ hg -R s id
836 836 02dcf1d70411+
837 837 $ hg -R t id
838 838 7af322bc1198+
839 839 $ hg update tip
840 840 subrepository sources for s differ
841 841 use (l)ocal source (02dcf1d70411) or (r)emote source (12a213df6fa9)?
842 842 l
843 843 subrepository sources for t differ
844 844 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
845 845 l
846 846 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
847 847 $ hg id
848 848 925c17564ef8+ tip
849 849 $ hg -R s id
850 850 02dcf1d70411+
851 851 $ hg -R t id
852 852 7af322bc1198+
853 853
854 854 Sticky repository, update --clean
855 855 $ hg update --clean tip
856 856 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
857 857 $ hg id
858 858 925c17564ef8 tip
859 859 $ hg -R s id
860 860 12a213df6fa9 tip
861 861 $ hg -R t id
862 862 52c0adc0515a tip
863 863
864 864 Test subrepo already at intended revision:
865 865 $ cd s
866 866 $ hg update fc627a69481f
867 867 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
868 868 $ cd ..
869 869 $ hg update 11
870 870 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
871 871 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
872 872 $ hg id -n
873 873 11+
874 874 $ hg -R s id
875 875 fc627a69481f
876 876 $ hg -R t id
877 877 e95bcfa18a35
878 878
879 879 Test that removing .hgsubstate doesn't break anything:
880 880
881 881 $ hg rm -f .hgsubstate
882 882 $ hg ci -mrm
883 883 nothing changed
884 884 [1]
885 885 $ hg log -vr tip
886 886 changeset: 13:925c17564ef8
887 887 tag: tip
888 888 user: test
889 889 date: Thu Jan 01 00:00:00 1970 +0000
890 890 files: .hgsubstate
891 891 description:
892 892 13
893 893
894 894
895 895
896 896 Test that removing .hgsub removes .hgsubstate:
897 897
898 898 $ hg rm .hgsub
899 899 $ hg ci -mrm2
900 900 created new head
901 901 $ hg log -vr tip
902 902 changeset: 14:2400bccd50af
903 903 tag: tip
904 904 parent: 11:365661e5936a
905 905 user: test
906 906 date: Thu Jan 01 00:00:00 1970 +0000
907 907 files: .hgsub .hgsubstate
908 908 description:
909 909 rm2
910 910
911 911
912 912 Test issue3153: diff -S with deleted subrepos
913 913
914 914 $ hg diff --nodates -S -c .
915 915 diff -r 365661e5936a -r 2400bccd50af .hgsub
916 916 --- a/.hgsub
917 917 +++ /dev/null
918 918 @@ -1,2 +0,0 @@
919 919 -s = s
920 920 -t = t
921 921 diff -r 365661e5936a -r 2400bccd50af .hgsubstate
922 922 --- a/.hgsubstate
923 923 +++ /dev/null
924 924 @@ -1,2 +0,0 @@
925 925 -fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
926 926 -e95bcfa18a358dc4936da981ebf4147b4cad1362 t
927 927
928 928 Test behavior of add for explicit path in subrepo:
929 929 $ cd ..
930 930 $ hg init explicit
931 931 $ cd explicit
932 932 $ echo s = s > .hgsub
933 933 $ hg add .hgsub
934 934 $ hg init s
935 935 $ hg ci -m0
936 936 Adding with an explicit path in a subrepo adds the file
937 937 $ echo c1 > f1
938 938 $ echo c2 > s/f2
939 939 $ hg st -S
940 940 ? f1
941 941 ? s/f2
942 942 $ hg add s/f2
943 943 $ hg st -S
944 944 A s/f2
945 945 ? f1
946 946 $ hg ci -R s -m0
947 947 $ hg ci -Am1
948 948 adding f1
949 949 Adding with an explicit path in a subrepo with -S has the same behavior
950 950 $ echo c3 > f3
951 951 $ echo c4 > s/f4
952 952 $ hg st -S
953 953 ? f3
954 954 ? s/f4
955 955 $ hg add -S s/f4
956 956 $ hg st -S
957 957 A s/f4
958 958 ? f3
959 959 $ hg ci -R s -m1
960 960 $ hg ci -Ama2
961 961 adding f3
962 962 Adding without a path or pattern silently ignores subrepos
963 963 $ echo c5 > f5
964 964 $ echo c6 > s/f6
965 965 $ echo c7 > s/f7
966 966 $ hg st -S
967 967 ? f5
968 968 ? s/f6
969 969 ? s/f7
970 970 $ hg add
971 971 adding f5
972 972 $ hg st -S
973 973 A f5
974 974 ? s/f6
975 975 ? s/f7
976 976 $ hg ci -R s -Am2
977 977 adding f6
978 978 adding f7
979 979 $ hg ci -m3
980 980 Adding without a path or pattern with -S also adds files in subrepos
981 981 $ echo c8 > f8
982 982 $ echo c9 > s/f9
983 983 $ echo c10 > s/f10
984 984 $ hg st -S
985 985 ? f8
986 986 ? s/f10
987 987 ? s/f9
988 988 $ hg add -S
989 989 adding f8
990 990 adding s/f10 (glob)
991 991 adding s/f9 (glob)
992 992 $ hg st -S
993 993 A f8
994 994 A s/f10
995 995 A s/f9
996 996 $ hg ci -R s -m3
997 997 $ hg ci -m4
998 998 Adding with a pattern silently ignores subrepos
999 999 $ echo c11 > fm11
1000 1000 $ echo c12 > fn12
1001 1001 $ echo c13 > s/fm13
1002 1002 $ echo c14 > s/fn14
1003 1003 $ hg st -S
1004 1004 ? fm11
1005 1005 ? fn12
1006 1006 ? s/fm13
1007 1007 ? s/fn14
1008 1008 $ hg add 'glob:**fm*'
1009 1009 adding fm11
1010 1010 $ hg st -S
1011 1011 A fm11
1012 1012 ? fn12
1013 1013 ? s/fm13
1014 1014 ? s/fn14
1015 1015 $ hg ci -R s -Am4
1016 1016 adding fm13
1017 1017 adding fn14
1018 1018 $ hg ci -Am5
1019 1019 adding fn12
1020 1020 Adding with a pattern with -S also adds matches in subrepos
1021 1021 $ echo c15 > fm15
1022 1022 $ echo c16 > fn16
1023 1023 $ echo c17 > s/fm17
1024 1024 $ echo c18 > s/fn18
1025 1025 $ hg st -S
1026 1026 ? fm15
1027 1027 ? fn16
1028 1028 ? s/fm17
1029 1029 ? s/fn18
1030 1030 $ hg add -S 'glob:**fm*'
1031 1031 adding fm15
1032 1032 adding s/fm17 (glob)
1033 1033 $ hg st -S
1034 1034 A fm15
1035 1035 A s/fm17
1036 1036 ? fn16
1037 1037 ? s/fn18
1038 1038 $ hg ci -R s -Am5
1039 1039 adding fn18
1040 1040 $ hg ci -Am6
1041 1041 adding fn16
1042 1042
1043 1043 Test behavior of forget for explicit path in subrepo:
1044 1044 Forgetting an explicit path in a subrepo untracks the file
1045 1045 $ echo c19 > s/f19
1046 1046 $ hg add s/f19
1047 1047 $ hg st -S
1048 1048 A s/f19
1049 1049 $ hg forget s/f19
1050 1050 $ hg st -S
1051 1051 ? s/f19
1052 1052 $ rm s/f19
1053 1053 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now