##// END OF EJS Templates
subrepo: create subrepos using clone instead of pull...
Martin Geisler -
r14281:ccb7240a default
parent child Browse files
Show More
@@ -1,1045 +1,1057 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
12 12 hg = None
13 13 propertycache = util.propertycache
14 14
15 15 nullstate = ('', '', 'empty')
16 16
17 17 def state(ctx, ui):
18 18 """return a state dict, mapping subrepo paths configured in .hgsub
19 19 to tuple: (source from .hgsub, revision from .hgsubstate, kind
20 20 (key in types dict))
21 21 """
22 22 p = config.config()
23 23 def read(f, sections=None, remap=None):
24 24 if f in ctx:
25 25 try:
26 26 data = ctx[f].data()
27 27 except IOError, err:
28 28 if err.errno != errno.ENOENT:
29 29 raise
30 30 # handle missing subrepo spec files as removed
31 31 ui.warn(_("warning: subrepo spec file %s not found\n") % f)
32 32 return
33 33 p.parse(f, data, sections, remap, read)
34 34 else:
35 35 raise util.Abort(_("subrepo spec file %s not found") % f)
36 36
37 37 if '.hgsub' in ctx:
38 38 read('.hgsub')
39 39
40 40 for path, src in ui.configitems('subpaths'):
41 41 p.set('subpaths', path, src, ui.configsource('subpaths', path))
42 42
43 43 rev = {}
44 44 if '.hgsubstate' in ctx:
45 45 try:
46 46 for l in ctx['.hgsubstate'].data().splitlines():
47 47 revision, path = l.split(" ", 1)
48 48 rev[path] = revision
49 49 except IOError, err:
50 50 if err.errno != errno.ENOENT:
51 51 raise
52 52
53 53 state = {}
54 54 for path, src in p[''].items():
55 55 kind = 'hg'
56 56 if src.startswith('['):
57 57 if ']' not in src:
58 58 raise util.Abort(_('missing ] in subrepo source'))
59 59 kind, src = src.split(']', 1)
60 60 kind = kind[1:]
61 61
62 62 for pattern, repl in p.items('subpaths'):
63 63 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
64 64 # does a string decode.
65 65 repl = repl.encode('string-escape')
66 66 # However, we still want to allow back references to go
67 67 # through unharmed, so we turn r'\\1' into r'\1'. Again,
68 68 # extra escapes are needed because re.sub string decodes.
69 69 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
70 70 try:
71 71 src = re.sub(pattern, repl, src, 1)
72 72 except re.error, e:
73 73 raise util.Abort(_("bad subrepository pattern in %s: %s")
74 74 % (p.source('subpaths', pattern), e))
75 75
76 76 state[path] = (src.strip(), rev.get(path, ''), kind)
77 77
78 78 return state
79 79
80 80 def writestate(repo, state):
81 81 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
82 82 repo.wwrite('.hgsubstate',
83 83 ''.join(['%s %s\n' % (state[s][1], s)
84 84 for s in sorted(state)]), '')
85 85
86 86 def submerge(repo, wctx, mctx, actx, overwrite):
87 87 """delegated from merge.applyupdates: merging of .hgsubstate file
88 88 in working context, merging context and ancestor context"""
89 89 if mctx == actx: # backwards?
90 90 actx = wctx.p1()
91 91 s1 = wctx.substate
92 92 s2 = mctx.substate
93 93 sa = actx.substate
94 94 sm = {}
95 95
96 96 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
97 97
98 98 def debug(s, msg, r=""):
99 99 if r:
100 100 r = "%s:%s:%s" % r
101 101 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
102 102
103 103 for s, l in s1.items():
104 104 a = sa.get(s, nullstate)
105 105 ld = l # local state with possible dirty flag for compares
106 106 if wctx.sub(s).dirty():
107 107 ld = (l[0], l[1] + "+")
108 108 if wctx == actx: # overwrite
109 109 a = ld
110 110
111 111 if s in s2:
112 112 r = s2[s]
113 113 if ld == r or r == a: # no change or local is newer
114 114 sm[s] = l
115 115 continue
116 116 elif ld == a: # other side changed
117 117 debug(s, "other changed, get", r)
118 118 wctx.sub(s).get(r, overwrite)
119 119 sm[s] = r
120 120 elif ld[0] != r[0]: # sources differ
121 121 if repo.ui.promptchoice(
122 122 _(' subrepository sources for %s differ\n'
123 123 'use (l)ocal source (%s) or (r)emote source (%s)?')
124 124 % (s, l[0], r[0]),
125 125 (_('&Local'), _('&Remote')), 0):
126 126 debug(s, "prompt changed, get", r)
127 127 wctx.sub(s).get(r, overwrite)
128 128 sm[s] = r
129 129 elif ld[1] == a[1]: # local side is unchanged
130 130 debug(s, "other side changed, get", r)
131 131 wctx.sub(s).get(r, overwrite)
132 132 sm[s] = r
133 133 else:
134 134 debug(s, "both sides changed, merge with", r)
135 135 wctx.sub(s).merge(r)
136 136 sm[s] = l
137 137 elif ld == a: # remote removed, local unchanged
138 138 debug(s, "remote removed, remove")
139 139 wctx.sub(s).remove()
140 140 else:
141 141 if repo.ui.promptchoice(
142 142 _(' local changed subrepository %s which remote removed\n'
143 143 'use (c)hanged version or (d)elete?') % s,
144 144 (_('&Changed'), _('&Delete')), 0):
145 145 debug(s, "prompt remove")
146 146 wctx.sub(s).remove()
147 147
148 148 for s, r in sorted(s2.items()):
149 149 if s in s1:
150 150 continue
151 151 elif s not in sa:
152 152 debug(s, "remote added, get", r)
153 153 mctx.sub(s).get(r)
154 154 sm[s] = r
155 155 elif r != sa[s]:
156 156 if repo.ui.promptchoice(
157 157 _(' remote changed subrepository %s which local removed\n'
158 158 'use (c)hanged version or (d)elete?') % s,
159 159 (_('&Changed'), _('&Delete')), 0) == 0:
160 160 debug(s, "prompt recreate", r)
161 161 wctx.sub(s).get(r)
162 162 sm[s] = r
163 163
164 164 # record merged .hgsubstate
165 165 writestate(repo, sm)
166 166
167 167 def _updateprompt(ui, sub, dirty, local, remote):
168 168 if dirty:
169 169 msg = (_(' subrepository sources for %s differ\n'
170 170 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
171 171 % (subrelpath(sub), local, remote))
172 172 else:
173 173 msg = (_(' subrepository sources for %s differ (in checked out version)\n'
174 174 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
175 175 % (subrelpath(sub), local, remote))
176 176 return ui.promptchoice(msg, (_('&Local'), _('&Remote')), 0)
177 177
178 178 def reporelpath(repo):
179 179 """return path to this (sub)repo as seen from outermost repo"""
180 180 parent = repo
181 181 while hasattr(parent, '_subparent'):
182 182 parent = parent._subparent
183 183 return repo.root[len(parent.root)+1:]
184 184
185 185 def subrelpath(sub):
186 186 """return path to this subrepo as seen from outermost repo"""
187 187 if hasattr(sub, '_relpath'):
188 188 return sub._relpath
189 189 if not hasattr(sub, '_repo'):
190 190 return sub._path
191 191 return reporelpath(sub._repo)
192 192
193 193 def _abssource(repo, push=False, abort=True):
194 194 """return pull/push path of repo - either based on parent repo .hgsub info
195 195 or on the top repo config. Abort or return None if no source found."""
196 196 if hasattr(repo, '_subparent'):
197 197 source = util.url(repo._subsource)
198 198 source.path = posixpath.normpath(source.path)
199 199 if posixpath.isabs(source.path) or source.scheme:
200 200 return str(source)
201 201 parent = _abssource(repo._subparent, push, abort=False)
202 202 if parent:
203 203 parent = util.url(parent)
204 204 parent.path = posixpath.join(parent.path, source.path)
205 205 parent.path = posixpath.normpath(parent.path)
206 206 return str(parent)
207 207 else: # recursion reached top repo
208 208 if hasattr(repo, '_subtoppath'):
209 209 return repo._subtoppath
210 210 if push and repo.ui.config('paths', 'default-push'):
211 211 return repo.ui.config('paths', 'default-push')
212 212 if repo.ui.config('paths', 'default'):
213 213 return repo.ui.config('paths', 'default')
214 214 if abort:
215 215 raise util.Abort(_("default path for subrepository %s not found") %
216 216 reporelpath(repo))
217 217
218 218 def itersubrepos(ctx1, ctx2):
219 219 """find subrepos in ctx1 or ctx2"""
220 220 # Create a (subpath, ctx) mapping where we prefer subpaths from
221 221 # ctx1. The subpaths from ctx2 are important when the .hgsub file
222 222 # has been modified (in ctx2) but not yet committed (in ctx1).
223 223 subpaths = dict.fromkeys(ctx2.substate, ctx2)
224 224 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
225 225 for subpath, ctx in sorted(subpaths.iteritems()):
226 226 yield subpath, ctx.sub(subpath)
227 227
228 228 def subrepo(ctx, path):
229 229 """return instance of the right subrepo class for subrepo in path"""
230 230 # subrepo inherently violates our import layering rules
231 231 # because it wants to make repo objects from deep inside the stack
232 232 # so we manually delay the circular imports to not break
233 233 # scripts that don't use our demand-loading
234 234 global hg
235 235 import hg as h
236 236 hg = h
237 237
238 238 scmutil.pathauditor(ctx._repo.root)(path)
239 239 state = ctx.substate.get(path, nullstate)
240 240 if state[2] not in types:
241 241 raise util.Abort(_('unknown subrepo type %s') % state[2])
242 242 return types[state[2]](ctx, path, state[:2])
243 243
244 244 # subrepo classes need to implement the following abstract class:
245 245
246 246 class abstractsubrepo(object):
247 247
248 248 def dirty(self, ignoreupdate=False):
249 249 """returns true if the dirstate of the subrepo is dirty or does not
250 250 match current stored state. If ignoreupdate is true, only check
251 251 whether the subrepo has uncommitted changes in its dirstate.
252 252 """
253 253 raise NotImplementedError
254 254
255 255 def checknested(self, path):
256 256 """check if path is a subrepository within this repository"""
257 257 return False
258 258
259 259 def commit(self, text, user, date):
260 260 """commit the current changes to the subrepo with the given
261 261 log message. Use given user and date if possible. Return the
262 262 new state of the subrepo.
263 263 """
264 264 raise NotImplementedError
265 265
266 266 def remove(self):
267 267 """remove the subrepo
268 268
269 269 (should verify the dirstate is not dirty first)
270 270 """
271 271 raise NotImplementedError
272 272
273 273 def get(self, state, overwrite=False):
274 274 """run whatever commands are needed to put the subrepo into
275 275 this state
276 276 """
277 277 raise NotImplementedError
278 278
279 279 def merge(self, state):
280 280 """merge currently-saved state with the new state."""
281 281 raise NotImplementedError
282 282
283 283 def push(self, force):
284 284 """perform whatever action is analogous to 'hg push'
285 285
286 286 This may be a no-op on some systems.
287 287 """
288 288 raise NotImplementedError
289 289
290 290 def add(self, ui, match, dryrun, prefix):
291 291 return []
292 292
293 293 def status(self, rev2, **opts):
294 294 return [], [], [], [], [], [], []
295 295
296 296 def diff(self, diffopts, node2, match, prefix, **opts):
297 297 pass
298 298
299 299 def outgoing(self, ui, dest, opts):
300 300 return 1
301 301
302 302 def incoming(self, ui, source, opts):
303 303 return 1
304 304
305 305 def files(self):
306 306 """return filename iterator"""
307 307 raise NotImplementedError
308 308
309 309 def filedata(self, name):
310 310 """return file data"""
311 311 raise NotImplementedError
312 312
313 313 def fileflags(self, name):
314 314 """return file flags"""
315 315 return ''
316 316
317 317 def archive(self, ui, archiver, prefix):
318 318 files = self.files()
319 319 total = len(files)
320 320 relpath = subrelpath(self)
321 321 ui.progress(_('archiving (%s)') % relpath, 0,
322 322 unit=_('files'), total=total)
323 323 for i, name in enumerate(files):
324 324 flags = self.fileflags(name)
325 325 mode = 'x' in flags and 0755 or 0644
326 326 symlink = 'l' in flags
327 327 archiver.addfile(os.path.join(prefix, self._path, name),
328 328 mode, symlink, self.filedata(name))
329 329 ui.progress(_('archiving (%s)') % relpath, i + 1,
330 330 unit=_('files'), total=total)
331 331 ui.progress(_('archiving (%s)') % relpath, None)
332 332
333 333
334 334 class hgsubrepo(abstractsubrepo):
335 335 def __init__(self, ctx, path, state):
336 336 self._path = path
337 337 self._state = state
338 338 r = ctx._repo
339 339 root = r.wjoin(path)
340 340 create = False
341 341 if not os.path.exists(os.path.join(root, '.hg')):
342 342 create = True
343 343 util.makedirs(root)
344 344 self._repo = hg.repository(r.ui, root, create=create)
345 self._repo._subparent = r
346 self._repo._subsource = state[0]
345 self._initrepo(r, state[0], create)
346
347 def _initrepo(self, parentrepo, source, create):
348 self._repo._subparent = parentrepo
349 self._repo._subsource = source
347 350
348 351 if create:
349 352 fp = self._repo.opener("hgrc", "w", text=True)
350 353 fp.write('[paths]\n')
351 354
352 355 def addpathconfig(key, value):
353 356 if value:
354 357 fp.write('%s = %s\n' % (key, value))
355 358 self._repo.ui.setconfig('paths', key, value)
356 359
357 360 defpath = _abssource(self._repo, abort=False)
358 361 defpushpath = _abssource(self._repo, True, abort=False)
359 362 addpathconfig('default', defpath)
360 363 if defpath != defpushpath:
361 364 addpathconfig('default-push', defpushpath)
362 365 fp.close()
363 366
364 367 def add(self, ui, match, dryrun, prefix):
365 368 return cmdutil.add(ui, self._repo, match, dryrun, True,
366 369 os.path.join(prefix, self._path))
367 370
368 371 def status(self, rev2, **opts):
369 372 try:
370 373 rev1 = self._state[1]
371 374 ctx1 = self._repo[rev1]
372 375 ctx2 = self._repo[rev2]
373 376 return self._repo.status(ctx1, ctx2, **opts)
374 377 except error.RepoLookupError, inst:
375 378 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
376 379 % (inst, subrelpath(self)))
377 380 return [], [], [], [], [], [], []
378 381
379 382 def diff(self, diffopts, node2, match, prefix, **opts):
380 383 try:
381 384 node1 = node.bin(self._state[1])
382 385 # We currently expect node2 to come from substate and be
383 386 # in hex format
384 387 if node2 is not None:
385 388 node2 = node.bin(node2)
386 389 cmdutil.diffordiffstat(self._repo.ui, self._repo, diffopts,
387 390 node1, node2, match,
388 391 prefix=os.path.join(prefix, self._path),
389 392 listsubrepos=True, **opts)
390 393 except error.RepoLookupError, inst:
391 394 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
392 395 % (inst, subrelpath(self)))
393 396
394 397 def archive(self, ui, archiver, prefix):
395 398 abstractsubrepo.archive(self, ui, archiver, prefix)
396 399
397 400 rev = self._state[1]
398 401 ctx = self._repo[rev]
399 402 for subpath in ctx.substate:
400 403 s = subrepo(ctx, subpath)
401 404 s.archive(ui, archiver, os.path.join(prefix, self._path))
402 405
403 406 def dirty(self, ignoreupdate=False):
404 407 r = self._state[1]
405 408 if r == '' and not ignoreupdate: # no state recorded
406 409 return True
407 410 w = self._repo[None]
408 411 if w.p1() != self._repo[r] and not ignoreupdate:
409 412 # different version checked out
410 413 return True
411 414 return w.dirty() # working directory changed
412 415
413 416 def checknested(self, path):
414 417 return self._repo._checknested(self._repo.wjoin(path))
415 418
416 419 def commit(self, text, user, date):
417 420 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self))
418 421 n = self._repo.commit(text, user, date)
419 422 if not n:
420 423 return self._repo['.'].hex() # different version checked out
421 424 return node.hex(n)
422 425
423 426 def remove(self):
424 427 # we can't fully delete the repository as it may contain
425 428 # local-only history
426 429 self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
427 430 hg.clean(self._repo, node.nullid, False)
428 431
429 432 def _get(self, state):
430 433 source, revision, kind = state
431 434 if revision not in self._repo:
432 435 self._repo._subsource = source
433 436 srcurl = _abssource(self._repo)
434 self._repo.ui.status(_('pulling subrepo %s from %s\n')
435 % (subrelpath(self), srcurl))
436 437 other = hg.repository(self._repo.ui, srcurl)
437 self._repo.pull(other)
438 if len(self._repo) == 0:
439 self._repo.ui.status(_('cloning subrepo %s from %s\n')
440 % (subrelpath(self), srcurl))
441 parentrepo = self._repo._subparent
442 shutil.rmtree(self._repo.root)
443 other, self._repo = hg.clone(self._repo._subparent.ui, other,
444 self._repo.root, update=False)
445 self._initrepo(parentrepo, source, create=True)
446 else:
447 self._repo.ui.status(_('pulling subrepo %s from %s\n')
448 % (subrelpath(self), srcurl))
449 self._repo.pull(other)
438 450 bookmarks.updatefromremote(self._repo.ui, self._repo, other)
439 451
440 452 def get(self, state, overwrite=False):
441 453 self._get(state)
442 454 source, revision, kind = state
443 455 self._repo.ui.debug("getting subrepo %s\n" % self._path)
444 456 hg.clean(self._repo, revision, False)
445 457
446 458 def merge(self, state):
447 459 self._get(state)
448 460 cur = self._repo['.']
449 461 dst = self._repo[state[1]]
450 462 anc = dst.ancestor(cur)
451 463
452 464 def mergefunc():
453 465 if anc == cur:
454 466 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
455 467 hg.update(self._repo, state[1])
456 468 elif anc == dst:
457 469 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
458 470 else:
459 471 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
460 472 hg.merge(self._repo, state[1], remind=False)
461 473
462 474 wctx = self._repo[None]
463 475 if self.dirty():
464 476 if anc != dst:
465 477 if _updateprompt(self._repo.ui, self, wctx.dirty(), cur, dst):
466 478 mergefunc()
467 479 else:
468 480 mergefunc()
469 481 else:
470 482 mergefunc()
471 483
472 484 def push(self, force):
473 485 # push subrepos depth-first for coherent ordering
474 486 c = self._repo['']
475 487 subs = c.substate # only repos that are committed
476 488 for s in sorted(subs):
477 489 if not c.sub(s).push(force):
478 490 return False
479 491
480 492 dsturl = _abssource(self._repo, True)
481 493 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
482 494 (subrelpath(self), dsturl))
483 495 other = hg.repository(self._repo.ui, dsturl)
484 496 return self._repo.push(other, force)
485 497
486 498 def outgoing(self, ui, dest, opts):
487 499 return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
488 500
489 501 def incoming(self, ui, source, opts):
490 502 return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
491 503
492 504 def files(self):
493 505 rev = self._state[1]
494 506 ctx = self._repo[rev]
495 507 return ctx.manifest()
496 508
497 509 def filedata(self, name):
498 510 rev = self._state[1]
499 511 return self._repo[rev][name].data()
500 512
501 513 def fileflags(self, name):
502 514 rev = self._state[1]
503 515 ctx = self._repo[rev]
504 516 return ctx.flags(name)
505 517
506 518
507 519 class svnsubrepo(abstractsubrepo):
508 520 def __init__(self, ctx, path, state):
509 521 self._path = path
510 522 self._state = state
511 523 self._ctx = ctx
512 524 self._ui = ctx._repo.ui
513 525
514 526 def _svncommand(self, commands, filename=''):
515 527 cmd = ['svn']
516 528 # Starting in svn 1.5 --non-interactive is a global flag
517 529 # instead of being per-command, but we need to support 1.4 so
518 530 # we have to be intelligent about what commands take
519 531 # --non-interactive.
520 532 if (not self._ui.interactive() and
521 533 commands[0] in ('update', 'checkout', 'commit')):
522 534 cmd.append('--non-interactive')
523 535 cmd.extend(commands)
524 536 if filename is not None:
525 537 path = os.path.join(self._ctx._repo.origroot, self._path, filename)
526 538 cmd.append(path)
527 539 env = dict(os.environ)
528 540 # Avoid localized output, preserve current locale for everything else.
529 541 env['LC_MESSAGES'] = 'C'
530 542 p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
531 543 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
532 544 universal_newlines=True, env=env)
533 545 stdout, stderr = p.communicate()
534 546 stderr = stderr.strip()
535 547 if stderr:
536 548 raise util.Abort(stderr)
537 549 return stdout
538 550
539 551 @propertycache
540 552 def _svnversion(self):
541 553 output = self._svncommand(['--version'], filename=None)
542 554 m = re.search(r'^svn,\s+version\s+(\d+)\.(\d+)', output)
543 555 if not m:
544 556 raise util.Abort(_('cannot retrieve svn tool version'))
545 557 return (int(m.group(1)), int(m.group(2)))
546 558
547 559 def _wcrevs(self):
548 560 # Get the working directory revision as well as the last
549 561 # commit revision so we can compare the subrepo state with
550 562 # both. We used to store the working directory one.
551 563 output = self._svncommand(['info', '--xml'])
552 564 doc = xml.dom.minidom.parseString(output)
553 565 entries = doc.getElementsByTagName('entry')
554 566 lastrev, rev = '0', '0'
555 567 if entries:
556 568 rev = str(entries[0].getAttribute('revision')) or '0'
557 569 commits = entries[0].getElementsByTagName('commit')
558 570 if commits:
559 571 lastrev = str(commits[0].getAttribute('revision')) or '0'
560 572 return (lastrev, rev)
561 573
562 574 def _wcrev(self):
563 575 return self._wcrevs()[0]
564 576
565 577 def _wcchanged(self):
566 578 """Return (changes, extchanges) where changes is True
567 579 if the working directory was changed, and extchanges is
568 580 True if any of these changes concern an external entry.
569 581 """
570 582 output = self._svncommand(['status', '--xml'])
571 583 externals, changes = [], []
572 584 doc = xml.dom.minidom.parseString(output)
573 585 for e in doc.getElementsByTagName('entry'):
574 586 s = e.getElementsByTagName('wc-status')
575 587 if not s:
576 588 continue
577 589 item = s[0].getAttribute('item')
578 590 props = s[0].getAttribute('props')
579 591 path = e.getAttribute('path')
580 592 if item == 'external':
581 593 externals.append(path)
582 594 if (item not in ('', 'normal', 'unversioned', 'external')
583 595 or props not in ('', 'none')):
584 596 changes.append(path)
585 597 for path in changes:
586 598 for ext in externals:
587 599 if path == ext or path.startswith(ext + os.sep):
588 600 return True, True
589 601 return bool(changes), False
590 602
591 603 def dirty(self, ignoreupdate=False):
592 604 if not self._wcchanged()[0]:
593 605 if self._state[1] in self._wcrevs() or ignoreupdate:
594 606 return False
595 607 return True
596 608
597 609 def commit(self, text, user, date):
598 610 # user and date are out of our hands since svn is centralized
599 611 changed, extchanged = self._wcchanged()
600 612 if not changed:
601 613 return self._wcrev()
602 614 if extchanged:
603 615 # Do not try to commit externals
604 616 raise util.Abort(_('cannot commit svn externals'))
605 617 commitinfo = self._svncommand(['commit', '-m', text])
606 618 self._ui.status(commitinfo)
607 619 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
608 620 if not newrev:
609 621 raise util.Abort(commitinfo.splitlines()[-1])
610 622 newrev = newrev.groups()[0]
611 623 self._ui.status(self._svncommand(['update', '-r', newrev]))
612 624 return newrev
613 625
614 626 def remove(self):
615 627 if self.dirty():
616 628 self._ui.warn(_('not removing repo %s because '
617 629 'it has changes.\n' % self._path))
618 630 return
619 631 self._ui.note(_('removing subrepo %s\n') % self._path)
620 632
621 633 def onerror(function, path, excinfo):
622 634 if function is not os.remove:
623 635 raise
624 636 # read-only files cannot be unlinked under Windows
625 637 s = os.stat(path)
626 638 if (s.st_mode & stat.S_IWRITE) != 0:
627 639 raise
628 640 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
629 641 os.remove(path)
630 642
631 643 path = self._ctx._repo.wjoin(self._path)
632 644 shutil.rmtree(path, onerror=onerror)
633 645 try:
634 646 os.removedirs(os.path.dirname(path))
635 647 except OSError:
636 648 pass
637 649
638 650 def get(self, state, overwrite=False):
639 651 if overwrite:
640 652 self._svncommand(['revert', '--recursive'])
641 653 args = ['checkout']
642 654 if self._svnversion >= (1, 5):
643 655 args.append('--force')
644 656 args.extend([state[0], '--revision', state[1]])
645 657 status = self._svncommand(args)
646 658 if not re.search('Checked out revision [0-9]+.', status):
647 659 raise util.Abort(status.splitlines()[-1])
648 660 self._ui.status(status)
649 661
650 662 def merge(self, state):
651 663 old = self._state[1]
652 664 new = state[1]
653 665 if new != self._wcrev():
654 666 dirty = old == self._wcrev() or self._wcchanged()[0]
655 667 if _updateprompt(self._ui, self, dirty, self._wcrev(), new):
656 668 self.get(state, False)
657 669
658 670 def push(self, force):
659 671 # push is a no-op for SVN
660 672 return True
661 673
662 674 def files(self):
663 675 output = self._svncommand(['list'])
664 676 # This works because svn forbids \n in filenames.
665 677 return output.splitlines()
666 678
667 679 def filedata(self, name):
668 680 return self._svncommand(['cat'], name)
669 681
670 682
671 683 class gitsubrepo(abstractsubrepo):
672 684 def __init__(self, ctx, path, state):
673 685 # TODO add git version check.
674 686 self._state = state
675 687 self._ctx = ctx
676 688 self._path = path
677 689 self._relpath = os.path.join(reporelpath(ctx._repo), path)
678 690 self._abspath = ctx._repo.wjoin(path)
679 691 self._subparent = ctx._repo
680 692 self._ui = ctx._repo.ui
681 693
682 694 def _gitcommand(self, commands, env=None, stream=False):
683 695 return self._gitdir(commands, env=env, stream=stream)[0]
684 696
685 697 def _gitdir(self, commands, env=None, stream=False):
686 698 return self._gitnodir(commands, env=env, stream=stream,
687 699 cwd=self._abspath)
688 700
689 701 def _gitnodir(self, commands, env=None, stream=False, cwd=None):
690 702 """Calls the git command
691 703
692 704 The methods tries to call the git command. versions previor to 1.6.0
693 705 are not supported and very probably fail.
694 706 """
695 707 self._ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
696 708 # unless ui.quiet is set, print git's stderr,
697 709 # which is mostly progress and useful info
698 710 errpipe = None
699 711 if self._ui.quiet:
700 712 errpipe = open(os.devnull, 'w')
701 713 p = subprocess.Popen(['git'] + commands, bufsize=-1, cwd=cwd, env=env,
702 714 close_fds=util.closefds,
703 715 stdout=subprocess.PIPE, stderr=errpipe)
704 716 if stream:
705 717 return p.stdout, None
706 718
707 719 retdata = p.stdout.read().strip()
708 720 # wait for the child to exit to avoid race condition.
709 721 p.wait()
710 722
711 723 if p.returncode != 0 and p.returncode != 1:
712 724 # there are certain error codes that are ok
713 725 command = commands[0]
714 726 if command in ('cat-file', 'symbolic-ref'):
715 727 return retdata, p.returncode
716 728 # for all others, abort
717 729 raise util.Abort('git %s error %d in %s' %
718 730 (command, p.returncode, self._relpath))
719 731
720 732 return retdata, p.returncode
721 733
722 734 def _gitmissing(self):
723 735 return not os.path.exists(os.path.join(self._abspath, '.git'))
724 736
725 737 def _gitstate(self):
726 738 return self._gitcommand(['rev-parse', 'HEAD'])
727 739
728 740 def _gitcurrentbranch(self):
729 741 current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
730 742 if err:
731 743 current = None
732 744 return current
733 745
734 746 def _gitremote(self, remote):
735 747 out = self._gitcommand(['remote', 'show', '-n', remote])
736 748 line = out.split('\n')[1]
737 749 i = line.index('URL: ') + len('URL: ')
738 750 return line[i:]
739 751
740 752 def _githavelocally(self, revision):
741 753 out, code = self._gitdir(['cat-file', '-e', revision])
742 754 return code == 0
743 755
744 756 def _gitisancestor(self, r1, r2):
745 757 base = self._gitcommand(['merge-base', r1, r2])
746 758 return base == r1
747 759
748 760 def _gitbranchmap(self):
749 761 '''returns 2 things:
750 762 a map from git branch to revision
751 763 a map from revision to branches'''
752 764 branch2rev = {}
753 765 rev2branch = {}
754 766
755 767 out = self._gitcommand(['for-each-ref', '--format',
756 768 '%(objectname) %(refname)'])
757 769 for line in out.split('\n'):
758 770 revision, ref = line.split(' ')
759 771 if (not ref.startswith('refs/heads/') and
760 772 not ref.startswith('refs/remotes/')):
761 773 continue
762 774 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
763 775 continue # ignore remote/HEAD redirects
764 776 branch2rev[ref] = revision
765 777 rev2branch.setdefault(revision, []).append(ref)
766 778 return branch2rev, rev2branch
767 779
768 780 def _gittracking(self, branches):
769 781 'return map of remote branch to local tracking branch'
770 782 # assumes no more than one local tracking branch for each remote
771 783 tracking = {}
772 784 for b in branches:
773 785 if b.startswith('refs/remotes/'):
774 786 continue
775 787 remote = self._gitcommand(['config', 'branch.%s.remote' % b])
776 788 if remote:
777 789 ref = self._gitcommand(['config', 'branch.%s.merge' % b])
778 790 tracking['refs/remotes/%s/%s' %
779 791 (remote, ref.split('/', 2)[2])] = b
780 792 return tracking
781 793
782 794 def _abssource(self, source):
783 795 if '://' not in source:
784 796 # recognize the scp syntax as an absolute source
785 797 colon = source.find(':')
786 798 if colon != -1 and '/' not in source[:colon]:
787 799 return source
788 800 self._subsource = source
789 801 return _abssource(self)
790 802
791 803 def _fetch(self, source, revision):
792 804 if self._gitmissing():
793 805 source = self._abssource(source)
794 806 self._ui.status(_('cloning subrepo %s from %s\n') %
795 807 (self._relpath, source))
796 808 self._gitnodir(['clone', source, self._abspath])
797 809 if self._githavelocally(revision):
798 810 return
799 811 self._ui.status(_('pulling subrepo %s from %s\n') %
800 812 (self._relpath, self._gitremote('origin')))
801 813 # try only origin: the originally cloned repo
802 814 self._gitcommand(['fetch'])
803 815 if not self._githavelocally(revision):
804 816 raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
805 817 (revision, self._relpath))
806 818
807 819 def dirty(self, ignoreupdate=False):
808 820 if self._gitmissing():
809 821 return True
810 822 if not ignoreupdate and self._state[1] != self._gitstate():
811 823 # different version checked out
812 824 return True
813 825 # check for staged changes or modified files; ignore untracked files
814 826 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
815 827 return code == 1
816 828
817 829 def get(self, state, overwrite=False):
818 830 source, revision, kind = state
819 831 self._fetch(source, revision)
820 832 # if the repo was set to be bare, unbare it
821 833 if self._gitcommand(['config', '--bool', 'core.bare']) == 'true':
822 834 self._gitcommand(['config', 'core.bare', 'false'])
823 835 if self._gitstate() == revision:
824 836 self._gitcommand(['reset', '--hard', 'HEAD'])
825 837 return
826 838 elif self._gitstate() == revision:
827 839 if overwrite:
828 840 # first reset the index to unmark new files for commit, because
829 841 # reset --hard will otherwise throw away files added for commit,
830 842 # not just unmark them.
831 843 self._gitcommand(['reset', 'HEAD'])
832 844 self._gitcommand(['reset', '--hard', 'HEAD'])
833 845 return
834 846 branch2rev, rev2branch = self._gitbranchmap()
835 847
836 848 def checkout(args):
837 849 cmd = ['checkout']
838 850 if overwrite:
839 851 # first reset the index to unmark new files for commit, because
840 852 # the -f option will otherwise throw away files added for
841 853 # commit, not just unmark them.
842 854 self._gitcommand(['reset', 'HEAD'])
843 855 cmd.append('-f')
844 856 self._gitcommand(cmd + args)
845 857
846 858 def rawcheckout():
847 859 # no branch to checkout, check it out with no branch
848 860 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
849 861 self._relpath)
850 862 self._ui.warn(_('check out a git branch if you intend '
851 863 'to make changes\n'))
852 864 checkout(['-q', revision])
853 865
854 866 if revision not in rev2branch:
855 867 rawcheckout()
856 868 return
857 869 branches = rev2branch[revision]
858 870 firstlocalbranch = None
859 871 for b in branches:
860 872 if b == 'refs/heads/master':
861 873 # master trumps all other branches
862 874 checkout(['refs/heads/master'])
863 875 return
864 876 if not firstlocalbranch and not b.startswith('refs/remotes/'):
865 877 firstlocalbranch = b
866 878 if firstlocalbranch:
867 879 checkout([firstlocalbranch])
868 880 return
869 881
870 882 tracking = self._gittracking(branch2rev.keys())
871 883 # choose a remote branch already tracked if possible
872 884 remote = branches[0]
873 885 if remote not in tracking:
874 886 for b in branches:
875 887 if b in tracking:
876 888 remote = b
877 889 break
878 890
879 891 if remote not in tracking:
880 892 # create a new local tracking branch
881 893 local = remote.split('/', 2)[2]
882 894 checkout(['-b', local, remote])
883 895 elif self._gitisancestor(branch2rev[tracking[remote]], remote):
884 896 # When updating to a tracked remote branch,
885 897 # if the local tracking branch is downstream of it,
886 898 # a normal `git pull` would have performed a "fast-forward merge"
887 899 # which is equivalent to updating the local branch to the remote.
888 900 # Since we are only looking at branching at update, we need to
889 901 # detect this situation and perform this action lazily.
890 902 if tracking[remote] != self._gitcurrentbranch():
891 903 checkout([tracking[remote]])
892 904 self._gitcommand(['merge', '--ff', remote])
893 905 else:
894 906 # a real merge would be required, just checkout the revision
895 907 rawcheckout()
896 908
897 909 def commit(self, text, user, date):
898 910 if self._gitmissing():
899 911 raise util.Abort(_("subrepo %s is missing") % self._relpath)
900 912 cmd = ['commit', '-a', '-m', text]
901 913 env = os.environ.copy()
902 914 if user:
903 915 cmd += ['--author', user]
904 916 if date:
905 917 # git's date parser silently ignores when seconds < 1e9
906 918 # convert to ISO8601
907 919 env['GIT_AUTHOR_DATE'] = util.datestr(date,
908 920 '%Y-%m-%dT%H:%M:%S %1%2')
909 921 self._gitcommand(cmd, env=env)
910 922 # make sure commit works otherwise HEAD might not exist under certain
911 923 # circumstances
912 924 return self._gitstate()
913 925
914 926 def merge(self, state):
915 927 source, revision, kind = state
916 928 self._fetch(source, revision)
917 929 base = self._gitcommand(['merge-base', revision, self._state[1]])
918 930 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
919 931
920 932 def mergefunc():
921 933 if base == revision:
922 934 self.get(state) # fast forward merge
923 935 elif base != self._state[1]:
924 936 self._gitcommand(['merge', '--no-commit', revision])
925 937
926 938 if self.dirty():
927 939 if self._gitstate() != revision:
928 940 dirty = self._gitstate() == self._state[1] or code != 0
929 941 if _updateprompt(self._ui, self, dirty,
930 942 self._state[1][:7], revision[:7]):
931 943 mergefunc()
932 944 else:
933 945 mergefunc()
934 946
935 947 def push(self, force):
936 948 if self._gitmissing():
937 949 raise util.Abort(_("subrepo %s is missing") % self._relpath)
938 950 # if a branch in origin contains the revision, nothing to do
939 951 branch2rev, rev2branch = self._gitbranchmap()
940 952 if self._state[1] in rev2branch:
941 953 for b in rev2branch[self._state[1]]:
942 954 if b.startswith('refs/remotes/origin/'):
943 955 return True
944 956 for b, revision in branch2rev.iteritems():
945 957 if b.startswith('refs/remotes/origin/'):
946 958 if self._gitisancestor(self._state[1], revision):
947 959 return True
948 960 # otherwise, try to push the currently checked out branch
949 961 cmd = ['push']
950 962 if force:
951 963 cmd.append('--force')
952 964
953 965 current = self._gitcurrentbranch()
954 966 if current:
955 967 # determine if the current branch is even useful
956 968 if not self._gitisancestor(self._state[1], current):
957 969 self._ui.warn(_('unrelated git branch checked out '
958 970 'in subrepo %s\n') % self._relpath)
959 971 return False
960 972 self._ui.status(_('pushing branch %s of subrepo %s\n') %
961 973 (current.split('/', 2)[2], self._relpath))
962 974 self._gitcommand(cmd + ['origin', current])
963 975 return True
964 976 else:
965 977 self._ui.warn(_('no branch checked out in subrepo %s\n'
966 978 'cannot push revision %s') %
967 979 (self._relpath, self._state[1]))
968 980 return False
969 981
970 982 def remove(self):
971 983 if self._gitmissing():
972 984 return
973 985 if self.dirty():
974 986 self._ui.warn(_('not removing repo %s because '
975 987 'it has changes.\n') % self._relpath)
976 988 return
977 989 # we can't fully delete the repository as it may contain
978 990 # local-only history
979 991 self._ui.note(_('removing subrepo %s\n') % self._relpath)
980 992 self._gitcommand(['config', 'core.bare', 'true'])
981 993 for f in os.listdir(self._abspath):
982 994 if f == '.git':
983 995 continue
984 996 path = os.path.join(self._abspath, f)
985 997 if os.path.isdir(path) and not os.path.islink(path):
986 998 shutil.rmtree(path)
987 999 else:
988 1000 os.remove(path)
989 1001
990 1002 def archive(self, ui, archiver, prefix):
991 1003 source, revision = self._state
992 1004 self._fetch(source, revision)
993 1005
994 1006 # Parse git's native archive command.
995 1007 # This should be much faster than manually traversing the trees
996 1008 # and objects with many subprocess calls.
997 1009 tarstream = self._gitcommand(['archive', revision], stream=True)
998 1010 tar = tarfile.open(fileobj=tarstream, mode='r|')
999 1011 relpath = subrelpath(self)
1000 1012 ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
1001 1013 for i, info in enumerate(tar):
1002 1014 if info.isdir():
1003 1015 continue
1004 1016 if info.issym():
1005 1017 data = info.linkname
1006 1018 else:
1007 1019 data = tar.extractfile(info).read()
1008 1020 archiver.addfile(os.path.join(prefix, self._path, info.name),
1009 1021 info.mode, info.issym(), data)
1010 1022 ui.progress(_('archiving (%s)') % relpath, i + 1,
1011 1023 unit=_('files'))
1012 1024 ui.progress(_('archiving (%s)') % relpath, None)
1013 1025
1014 1026
1015 1027 def status(self, rev2, **opts):
1016 1028 if self._gitmissing():
1017 1029 # if the repo is missing, return no results
1018 1030 return [], [], [], [], [], [], []
1019 1031 rev1 = self._state[1]
1020 1032 modified, added, removed = [], [], []
1021 1033 if rev2:
1022 1034 command = ['diff-tree', rev1, rev2]
1023 1035 else:
1024 1036 command = ['diff-index', rev1]
1025 1037 out = self._gitcommand(command)
1026 1038 for line in out.split('\n'):
1027 1039 tab = line.find('\t')
1028 1040 if tab == -1:
1029 1041 continue
1030 1042 status, f = line[tab - 1], line[tab + 1:]
1031 1043 if status == 'M':
1032 1044 modified.append(f)
1033 1045 elif status == 'A':
1034 1046 added.append(f)
1035 1047 elif status == 'D':
1036 1048 removed.append(f)
1037 1049
1038 1050 deleted = unknown = ignored = clean = []
1039 1051 return modified, added, removed, deleted, unknown, ignored, clean
1040 1052
1041 1053 types = {
1042 1054 'hg': hgsubrepo,
1043 1055 'svn': svnsubrepo,
1044 1056 'git': gitsubrepo,
1045 1057 }
@@ -1,164 +1,164 b''
1 1
2 2 $ hg clone http://localhost:$HGPORT/ copy
3 3 abort: error: Connection refused
4 4 [255]
5 5 $ test -d copy
6 6 [1]
7 7
8 8 This server doesn't do range requests so it's basically only good for
9 9 one pull
10 10
11 11 $ cat > dumb.py <<EOF
12 12 > import BaseHTTPServer, SimpleHTTPServer, os, signal, sys
13 13 >
14 14 > def run(server_class=BaseHTTPServer.HTTPServer,
15 15 > handler_class=SimpleHTTPServer.SimpleHTTPRequestHandler):
16 16 > server_address = ('localhost', int(os.environ['HGPORT']))
17 17 > httpd = server_class(server_address, handler_class)
18 18 > httpd.serve_forever()
19 19 >
20 20 > signal.signal(signal.SIGTERM, lambda x, y: sys.exit(0))
21 21 > run()
22 22 > EOF
23 23 $ python dumb.py 2>/dev/null &
24 24 $ echo $! >> $DAEMON_PIDS
25 25 $ hg init remote
26 26 $ cd remote
27 27 $ echo foo > bar
28 28 $ echo c2 > '.dotfile with spaces'
29 29 $ hg add
30 30 adding .dotfile with spaces
31 31 adding bar
32 32 $ hg commit -m"test"
33 33 $ hg tip
34 34 changeset: 0:02770d679fb8
35 35 tag: tip
36 36 user: test
37 37 date: Thu Jan 01 00:00:00 1970 +0000
38 38 summary: test
39 39
40 40 $ cd ..
41 41 $ hg clone static-http://localhost:$HGPORT/remote local
42 42 requesting all changes
43 43 adding changesets
44 44 adding manifests
45 45 adding file changes
46 46 added 1 changesets with 2 changes to 2 files
47 47 updating to branch default
48 48 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 49 $ cd local
50 50 $ hg verify
51 51 checking changesets
52 52 checking manifests
53 53 crosschecking files in changesets and manifests
54 54 checking files
55 55 2 files, 1 changesets, 2 total revisions
56 56 $ cat bar
57 57 foo
58 58 $ cd ../remote
59 59 $ echo baz > quux
60 60 $ hg commit -A -mtest2
61 61 adding quux
62 62
63 63 check for HTTP opener failures when cachefile does not exist
64 64
65 65 $ rm .hg/cache/*
66 66 $ cd ../local
67 67 $ echo '[hooks]' >> .hg/hgrc
68 68 $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup' >> .hg/hgrc
69 69 $ hg pull
70 70 pulling from static-http://localhost:$HGPORT/remote
71 71 searching for changes
72 72 adding changesets
73 73 adding manifests
74 74 adding file changes
75 75 added 1 changesets with 1 changes to 1 files
76 76 changegroup hook: HG_NODE=4ac2e3648604439c580c69b09ec9d93a88d93432 HG_SOURCE=pull HG_URL=http://localhost:$HGPORT/remote
77 77 (run 'hg update' to get a working copy)
78 78
79 79 trying to push
80 80
81 81 $ hg update
82 82 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
83 83 $ echo more foo >> bar
84 84 $ hg commit -m"test"
85 85 $ hg push
86 86 pushing to static-http://localhost:$HGPORT/remote
87 87 abort: cannot lock static-http repository
88 88 [255]
89 89
90 90 trying clone -r
91 91
92 92 $ cd ..
93 93 $ hg clone -r donotexist static-http://localhost:$HGPORT/remote local0
94 94 abort: unknown revision 'donotexist'!
95 95 [255]
96 96 $ hg clone -r 0 static-http://localhost:$HGPORT/remote local0
97 97 adding changesets
98 98 adding manifests
99 99 adding file changes
100 100 added 1 changesets with 2 changes to 2 files
101 101 updating to branch default
102 102 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
103 103
104 104 test with "/" URI (issue 747) and subrepo
105 105
106 106 $ hg init
107 107 $ hg init sub
108 108 $ hg -R sub tag not-empty
109 109 $ echo sub=sub > .hgsub
110 110 $ echo a > a
111 111 $ hg add a .hgsub
112 112 $ hg -q ci -ma
113 113 $ hg clone static-http://localhost:$HGPORT/ local2
114 114 requesting all changes
115 115 adding changesets
116 116 adding manifests
117 117 adding file changes
118 118 added 1 changesets with 3 changes to 3 files
119 119 updating to branch default
120 pulling subrepo sub from static-http://localhost:$HGPORT/sub
120 cloning subrepo sub from static-http://localhost:$HGPORT/sub
121 121 requesting all changes
122 122 adding changesets
123 123 adding manifests
124 124 adding file changes
125 125 added 1 changesets with 1 changes to 1 files
126 126 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 127 $ cd local2
128 128 $ hg verify
129 129 checking changesets
130 130 checking manifests
131 131 crosschecking files in changesets and manifests
132 132 checking files
133 133 3 files, 1 changesets, 3 total revisions
134 134 $ cat a
135 135 a
136 136 $ hg paths
137 137 default = static-http://localhost:$HGPORT/
138 138
139 139 test with empty repo (issue965)
140 140
141 141 $ cd ..
142 142 $ hg init remotempty
143 143 $ hg clone static-http://localhost:$HGPORT/remotempty local3
144 144 no changes found
145 145 updating to branch default
146 146 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
147 147 $ cd local3
148 148 $ hg verify
149 149 checking changesets
150 150 checking manifests
151 151 crosschecking files in changesets and manifests
152 152 checking files
153 153 0 files, 0 changesets, 0 total revisions
154 154 $ hg paths
155 155 default = static-http://localhost:$HGPORT/remotempty
156 156
157 157 test with non-repo
158 158
159 159 $ cd ..
160 160 $ mkdir notarepo
161 161 $ hg clone static-http://localhost:$HGPORT/notarepo local3
162 162 abort: 'http://localhost:$HGPORT/notarepo' does not appear to be an hg repository!
163 163 [255]
164 164 $ kill $!
@@ -1,117 +1,102 b''
1 1 Preparing the subrepository 'sub2'
2 2
3 3 $ hg init sub2
4 4 $ echo sub2 > sub2/sub2
5 5 $ hg add -R sub2
6 6 adding sub2/sub2
7 7 $ hg commit -R sub2 -m "sub2 import"
8 8
9 9 Preparing the 'sub1' repo which depends on the subrepo 'sub2'
10 10
11 11 $ hg init sub1
12 12 $ echo sub1 > sub1/sub1
13 13 $ echo "sub2 = ../sub2" > sub1/.hgsub
14 14 $ hg clone sub2 sub1/sub2
15 15 updating to branch default
16 16 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
17 17 $ hg add -R sub1
18 18 adding sub1/.hgsub
19 19 adding sub1/sub1
20 20 $ hg commit -R sub1 -m "sub1 import"
21 21 committing subrepository sub2
22 22
23 23 Preparing the 'main' repo which depends on the subrepo 'sub1'
24 24
25 25 $ hg init main
26 26 $ echo main > main/main
27 27 $ echo "sub1 = ../sub1" > main/.hgsub
28 28 $ hg clone sub1 main/sub1
29 29 updating to branch default
30 pulling subrepo sub2 from $TESTTMP/sub2
31 requesting all changes
32 adding changesets
33 adding manifests
34 adding file changes
35 added 1 changesets with 1 changes to 1 files
30 cloning subrepo sub2 from $TESTTMP/sub2
36 31 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
37 32 $ hg add -R main
38 33 adding main/.hgsub
39 34 adding main/main
40 35 $ hg commit -R main -m "main import"
41 36 committing subrepository sub1
42 37
43 38 Cleaning both repositories, just as a clone -U
44 39
45 40 $ hg up -C -R sub2 null
46 41 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
47 42 $ hg up -C -R sub1 null
48 43 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
49 44 $ hg up -C -R main null
50 45 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
51 46 $ rm -rf main/sub1
52 47 $ rm -rf sub1/sub2
53 48
54 49 Clone main
55 50
56 51 $ hg clone main cloned
57 52 updating to branch default
58 pulling subrepo sub1 from $TESTTMP/sub1
59 requesting all changes
60 adding changesets
61 adding manifests
62 adding file changes
63 added 1 changesets with 3 changes to 3 files
64 pulling subrepo sub1/sub2 from $TESTTMP/sub2
65 requesting all changes
66 adding changesets
67 adding manifests
68 adding file changes
69 added 1 changesets with 1 changes to 1 files
53 cloning subrepo sub1 from $TESTTMP/sub1
54 cloning subrepo sub1/sub2 from $TESTTMP/sub2
70 55 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
71 56
72 57 Checking cloned repo ids
73 58
74 59 $ printf "cloned " ; hg id -R cloned
75 60 cloned 7f491f53a367 tip
76 61 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
77 62 cloned/sub1 fc3b4ce2696f tip
78 63 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
79 64 cloned/sub1/sub2 c57a0840e3ba tip
80 65
81 66 debugsub output for main and sub1
82 67
83 68 $ hg debugsub -R cloned
84 69 path sub1
85 70 source ../sub1
86 71 revision fc3b4ce2696f7741438c79207583768f2ce6b0dd
87 72 $ hg debugsub -R cloned/sub1
88 73 path sub2
89 74 source ../sub2
90 75 revision c57a0840e3badd667ef3c3ef65471609acb2ba3c
91 76
92 77 Modifying deeply nested 'sub2'
93 78
94 79 $ echo modified > cloned/sub1/sub2/sub2
95 80 $ hg commit -m "deep nested modif should trigger a commit" -R cloned
96 81 committing subrepository sub1
97 82 committing subrepository sub1/sub2
98 83
99 84 Checking modified node ids
100 85
101 86 $ printf "cloned " ; hg id -R cloned
102 87 cloned ffe6649062fe tip
103 88 $ printf "cloned/sub1 " ; hg id -R cloned/sub1
104 89 cloned/sub1 2ecb03bf44a9 tip
105 90 $ printf "cloned/sub1/sub2 " ; hg id -R cloned/sub1/sub2
106 91 cloned/sub1/sub2 53dd3430bcaf tip
107 92
108 93 debugsub output for main and sub1
109 94
110 95 $ hg debugsub -R cloned
111 96 path sub1
112 97 source ../sub1
113 98 revision 2ecb03bf44a94e749e8669481dd9069526ce7cb9
114 99 $ hg debugsub -R cloned/sub1
115 100 path sub2
116 101 source ../sub2
117 102 revision 53dd3430bcaf5ab4a7c48262bcad6d441f510487
@@ -1,427 +1,417 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
27 27 $ hg add -S
28 28 adding x.txt
29 29 adding foo/y.txt
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 0-0-0
62 62 committing subrepository foo
63 63 committing subrepository foo/bar
64 64
65 65 $ cd foo
66 66 $ echo y2 >> y.txt
67 67 $ hg commit -m 0-1-0
68 68
69 69 $ cd bar
70 70 $ echo z2 >> z.txt
71 71 $ hg commit -m 0-1-1
72 72
73 73 $ cd ..
74 74 $ hg commit -m 0-2-1
75 75 committing subrepository bar
76 76
77 77 $ cd ..
78 78 $ hg commit -m 1-2-1
79 79 committing subrepository foo
80 80
81 81 Change working directory:
82 82
83 83 $ echo y3 >> foo/y.txt
84 84 $ echo z3 >> foo/bar/z.txt
85 85 $ hg status -S
86 86 M foo/bar/z.txt
87 87 M foo/y.txt
88 88 $ hg diff --nodates -S
89 89 diff -r d254738c5f5e foo/y.txt
90 90 --- a/foo/y.txt
91 91 +++ b/foo/y.txt
92 92 @@ -1,2 +1,3 @@
93 93 y1
94 94 y2
95 95 +y3
96 96 diff -r 9647f22de499 foo/bar/z.txt
97 97 --- a/foo/bar/z.txt
98 98 +++ b/foo/bar/z.txt
99 99 @@ -1,2 +1,3 @@
100 100 z1
101 101 z2
102 102 +z3
103 103
104 104 Status call crossing repository boundaries:
105 105
106 106 $ hg status -S foo/bar/z.txt
107 107 M foo/bar/z.txt
108 108 $ hg status -S -I 'foo/?.txt'
109 109 M foo/y.txt
110 110 $ hg status -S -I '**/?.txt'
111 111 M foo/bar/z.txt
112 112 M foo/y.txt
113 113 $ hg diff --nodates -S -I '**/?.txt'
114 114 diff -r d254738c5f5e foo/y.txt
115 115 --- a/foo/y.txt
116 116 +++ b/foo/y.txt
117 117 @@ -1,2 +1,3 @@
118 118 y1
119 119 y2
120 120 +y3
121 121 diff -r 9647f22de499 foo/bar/z.txt
122 122 --- a/foo/bar/z.txt
123 123 +++ b/foo/bar/z.txt
124 124 @@ -1,2 +1,3 @@
125 125 z1
126 126 z2
127 127 +z3
128 128
129 129 Status from within a subdirectory:
130 130
131 131 $ mkdir dir
132 132 $ cd dir
133 133 $ echo a1 > a.txt
134 134 $ hg status -S
135 135 M foo/bar/z.txt
136 136 M foo/y.txt
137 137 ? dir/a.txt
138 138 $ hg diff --nodates -S
139 139 diff -r d254738c5f5e foo/y.txt
140 140 --- a/foo/y.txt
141 141 +++ b/foo/y.txt
142 142 @@ -1,2 +1,3 @@
143 143 y1
144 144 y2
145 145 +y3
146 146 diff -r 9647f22de499 foo/bar/z.txt
147 147 --- a/foo/bar/z.txt
148 148 +++ b/foo/bar/z.txt
149 149 @@ -1,2 +1,3 @@
150 150 z1
151 151 z2
152 152 +z3
153 153
154 154 Status with relative path:
155 155
156 156 $ hg status -S ..
157 157 M ../foo/bar/z.txt
158 158 M ../foo/y.txt
159 159 ? a.txt
160 160 $ hg diff --nodates -S ..
161 161 diff -r d254738c5f5e foo/y.txt
162 162 --- a/foo/y.txt
163 163 +++ b/foo/y.txt
164 164 @@ -1,2 +1,3 @@
165 165 y1
166 166 y2
167 167 +y3
168 168 diff -r 9647f22de499 foo/bar/z.txt
169 169 --- a/foo/bar/z.txt
170 170 +++ b/foo/bar/z.txt
171 171 @@ -1,2 +1,3 @@
172 172 z1
173 173 z2
174 174 +z3
175 175 $ cd ..
176 176
177 177 Cleanup and final commit:
178 178
179 179 $ rm -r dir
180 180 $ hg commit -m 2-3-2
181 181 committing subrepository foo
182 182 committing subrepository foo/bar
183 183
184 184 Log with the relationships between repo and its subrepo:
185 185
186 186 $ hg log --template '{rev}:{node|short} {desc}\n'
187 187 2:1326fa26d0c0 2-3-2
188 188 1:4b3c9ff4f66b 1-2-1
189 189 0:23376cbba0d8 0-0-0
190 190
191 191 $ hg -R foo log --template '{rev}:{node|short} {desc}\n'
192 192 3:65903cebad86 2-3-2
193 193 2:d254738c5f5e 0-2-1
194 194 1:8629ce7dcc39 0-1-0
195 195 0:af048e97ade2 0-0-0
196 196
197 197 $ hg -R foo/bar log --template '{rev}:{node|short} {desc}\n'
198 198 2:31ecbdafd357 2-3-2
199 199 1:9647f22de499 0-1-1
200 200 0:4904098473f9 0-0-0
201 201
202 202 Status between revisions:
203 203
204 204 $ hg status -S
205 205 $ hg status -S --rev 0:1
206 206 M .hgsubstate
207 207 M foo/.hgsubstate
208 208 M foo/bar/z.txt
209 209 M foo/y.txt
210 210 $ hg diff --nodates -S -I '**/?.txt' --rev 0:1
211 211 diff -r af048e97ade2 -r d254738c5f5e foo/y.txt
212 212 --- a/foo/y.txt
213 213 +++ b/foo/y.txt
214 214 @@ -1,1 +1,2 @@
215 215 y1
216 216 +y2
217 217 diff -r 4904098473f9 -r 9647f22de499 foo/bar/z.txt
218 218 --- a/foo/bar/z.txt
219 219 +++ b/foo/bar/z.txt
220 220 @@ -1,1 +1,2 @@
221 221 z1
222 222 +z2
223 223
224 224 Enable progress extension for archive tests:
225 225
226 226 $ cp $HGRCPATH $HGRCPATH.no-progress
227 227 $ cat >> $HGRCPATH <<EOF
228 228 > [extensions]
229 229 > progress =
230 230 > [progress]
231 231 > assume-tty = 1
232 232 > delay = 0
233 233 > format = topic bar number
234 234 > refresh = 0
235 235 > width = 60
236 236 > EOF
237 237
238 238 Test archiving to a directory tree (the doubled lines in the output
239 239 only show up in the test output, not in real usage):
240 240
241 241 $ hg archive --subrepos ../archive 2>&1 | $TESTDIR/filtercr.py
242 242
243 243 archiving [ ] 0/3
244 244 archiving [ ] 0/3
245 245 archiving [=============> ] 1/3
246 246 archiving [=============> ] 1/3
247 247 archiving [===========================> ] 2/3
248 248 archiving [===========================> ] 2/3
249 249 archiving [==========================================>] 3/3
250 250 archiving [==========================================>] 3/3
251 251
252 252 archiving (foo) [ ] 0/3
253 253 archiving (foo) [ ] 0/3
254 254 archiving (foo) [===========> ] 1/3
255 255 archiving (foo) [===========> ] 1/3
256 256 archiving (foo) [=======================> ] 2/3
257 257 archiving (foo) [=======================> ] 2/3
258 258 archiving (foo) [====================================>] 3/3
259 259 archiving (foo) [====================================>] 3/3
260 260
261 261 archiving (foo/bar) [ ] 0/1
262 262 archiving (foo/bar) [ ] 0/1
263 263 archiving (foo/bar) [================================>] 1/1
264 264 archiving (foo/bar) [================================>] 1/1
265 265 \r (esc)
266 266 $ find ../archive | sort
267 267 ../archive
268 268 ../archive/.hg_archival.txt
269 269 ../archive/.hgsub
270 270 ../archive/.hgsubstate
271 271 ../archive/foo
272 272 ../archive/foo/.hgsub
273 273 ../archive/foo/.hgsubstate
274 274 ../archive/foo/bar
275 275 ../archive/foo/bar/z.txt
276 276 ../archive/foo/y.txt
277 277 ../archive/x.txt
278 278
279 279 Test archiving to zip file (unzip output is unstable):
280 280
281 281 $ hg archive --subrepos ../archive.zip 2>&1 | $TESTDIR/filtercr.py
282 282
283 283 archiving [ ] 0/3
284 284 archiving [ ] 0/3
285 285 archiving [=============> ] 1/3
286 286 archiving [=============> ] 1/3
287 287 archiving [===========================> ] 2/3
288 288 archiving [===========================> ] 2/3
289 289 archiving [==========================================>] 3/3
290 290 archiving [==========================================>] 3/3
291 291
292 292 archiving (foo) [ ] 0/3
293 293 archiving (foo) [ ] 0/3
294 294 archiving (foo) [===========> ] 1/3
295 295 archiving (foo) [===========> ] 1/3
296 296 archiving (foo) [=======================> ] 2/3
297 297 archiving (foo) [=======================> ] 2/3
298 298 archiving (foo) [====================================>] 3/3
299 299 archiving (foo) [====================================>] 3/3
300 300
301 301 archiving (foo/bar) [ ] 0/1
302 302 archiving (foo/bar) [ ] 0/1
303 303 archiving (foo/bar) [================================>] 1/1
304 304 archiving (foo/bar) [================================>] 1/1
305 305 \r (esc)
306 306
307 307 Disable progress extension and cleanup:
308 308
309 309 $ mv $HGRCPATH.no-progress $HGRCPATH
310 310
311 311 Clone and test outgoing:
312 312
313 313 $ cd ..
314 314 $ hg clone repo repo2
315 315 updating to branch default
316 pulling subrepo foo from $TESTTMP/repo/foo
317 requesting all changes
318 adding changesets
319 adding manifests
320 adding file changes
321 added 4 changesets with 7 changes to 3 files
322 pulling subrepo foo/bar from $TESTTMP/repo/foo/bar
323 requesting all changes
324 adding changesets
325 adding manifests
326 adding file changes
327 added 3 changesets with 3 changes to 1 files
316 cloning subrepo foo from $TESTTMP/repo/foo
317 cloning subrepo foo/bar from $TESTTMP/repo/foo/bar
328 318 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
329 319 $ cd repo2
330 320 $ hg outgoing -S
331 321 comparing with $TESTTMP/repo
332 322 searching for changes
333 323 no changes found
334 324 comparing with $TESTTMP/repo/foo
335 325 searching for changes
336 326 no changes found
337 327 comparing with $TESTTMP/repo/foo/bar
338 328 searching for changes
339 329 no changes found
340 330 [1]
341 331
342 332 Make nested change:
343 333
344 334 $ echo y4 >> foo/y.txt
345 335 $ hg diff --nodates -S
346 336 diff -r 65903cebad86 foo/y.txt
347 337 --- a/foo/y.txt
348 338 +++ b/foo/y.txt
349 339 @@ -1,3 +1,4 @@
350 340 y1
351 341 y2
352 342 y3
353 343 +y4
354 344 $ hg commit -m 3-4-2
355 345 committing subrepository foo
356 346 $ hg outgoing -S
357 347 comparing with $TESTTMP/repo
358 348 searching for changes
359 349 changeset: 3:2655b8ecc4ee
360 350 tag: tip
361 351 user: test
362 352 date: Thu Jan 01 00:00:00 1970 +0000
363 353 summary: 3-4-2
364 354
365 355 comparing with $TESTTMP/repo/foo
366 356 searching for changes
367 357 changeset: 4:e96193d6cb36
368 358 tag: tip
369 359 user: test
370 360 date: Thu Jan 01 00:00:00 1970 +0000
371 361 summary: 3-4-2
372 362
373 363 comparing with $TESTTMP/repo/foo/bar
374 364 searching for changes
375 365 no changes found
376 366
377 367
378 368 Switch to original repo and setup default path:
379 369
380 370 $ cd ../repo
381 371 $ echo '[paths]' >> .hg/hgrc
382 372 $ echo 'default = ../repo2' >> .hg/hgrc
383 373
384 374 Test incoming:
385 375
386 376 $ hg incoming -S
387 377 comparing with $TESTTMP/repo2
388 378 searching for changes
389 379 changeset: 3:2655b8ecc4ee
390 380 tag: tip
391 381 user: test
392 382 date: Thu Jan 01 00:00:00 1970 +0000
393 383 summary: 3-4-2
394 384
395 385 comparing with $TESTTMP/repo2/foo
396 386 searching for changes
397 387 changeset: 4:e96193d6cb36
398 388 tag: tip
399 389 user: test
400 390 date: Thu Jan 01 00:00:00 1970 +0000
401 391 summary: 3-4-2
402 392
403 393 comparing with $TESTTMP/repo2/foo/bar
404 394 searching for changes
405 395 no changes found
406 396
407 397 $ hg incoming -S --bundle incoming.hg
408 398 abort: cannot combine --bundle and --subrepos
409 399 [255]
410 400
411 401 Test missing subrepo:
412 402
413 403 $ rm -r foo
414 404 $ hg status -S
415 405 warning: error "unknown revision '65903cebad86f1a84bd4f1134f62fa7dcb7a1c98'" in subrepository "foo"
416 406
417 407 Issue2619: IndexError: list index out of range on hg add with subrepos
418 408 The subrepo must sorts after the explicit filename.
419 409
420 410 $ cd ..
421 411 $ hg init test
422 412 $ cd test
423 413 $ hg init x
424 414 $ echo "x = x" >> .hgsub
425 415 $ hg add .hgsub
426 416 $ touch a x/a
427 417 $ hg add a x/a
@@ -1,103 +1,103 b''
1 1 Preparing the subrepository 'sub'
2 2
3 3 $ hg init sub
4 4 $ echo sub > sub/sub
5 5 $ hg add -R sub
6 6 adding sub/sub
7 7 $ hg commit -R sub -m "sub import"
8 8
9 9 Preparing the 'main' repo which depends on the subrepo 'sub'
10 10
11 11 $ hg init main
12 12 $ echo main > main/main
13 13 $ echo "sub = ../sub" > main/.hgsub
14 14 $ hg clone sub main/sub
15 15 updating to branch default
16 16 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
17 17 $ hg add -R main
18 18 adding main/.hgsub
19 19 adding main/main
20 20 $ hg commit -R main -m "main import"
21 21 committing subrepository sub
22 22
23 23 Cleaning both repositories, just as a clone -U
24 24
25 25 $ hg up -C -R sub null
26 26 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
27 27 $ hg up -C -R main null
28 28 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
29 29 $ rm -rf main/sub
30 30
31 31 Serving them both using hgweb
32 32
33 33 $ printf '[paths]\n/main = main\nsub = sub\n' > webdir.conf
34 34 $ hg serve --webdir-conf webdir.conf -a localhost -p $HGPORT \
35 35 > -A /dev/null -E /dev/null --pid-file hg.pid -d
36 36 $ cat hg.pid >> $DAEMON_PIDS
37 37
38 38 Clone main from hgweb
39 39
40 40 $ hg clone "http://localhost:$HGPORT/main" cloned
41 41 requesting all changes
42 42 adding changesets
43 43 adding manifests
44 44 adding file changes
45 45 added 1 changesets with 3 changes to 3 files
46 46 updating to branch default
47 pulling subrepo sub from http://localhost:$HGPORT/sub
47 cloning subrepo sub from http://localhost:$HGPORT/sub
48 48 requesting all changes
49 49 adding changesets
50 50 adding manifests
51 51 adding file changes
52 52 added 1 changesets with 1 changes to 1 files
53 53 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
54 54
55 55 Checking cloned repo ids
56 56
57 57 $ hg id -R cloned
58 58 fdfeeb3e979e tip
59 59 $ hg id -R cloned/sub
60 60 863c1745b441 tip
61 61
62 62 subrepo debug for 'main' clone
63 63
64 64 $ hg debugsub -R cloned
65 65 path sub
66 66 source ../sub
67 67 revision 863c1745b441bd97a8c4a096e87793073f4fb215
68 68
69 69 $ "$TESTDIR/killdaemons.py"
70 70
71 71 subrepo paths with ssh urls
72 72
73 73 $ cp $TESTDIR/dummyssh $BINDIR/ssh
74 74
75 75 $ hg clone ssh://user@dummy/cloned sshclone
76 76 requesting all changes
77 77 adding changesets
78 78 adding manifests
79 79 adding file changes
80 80 added 1 changesets with 3 changes to 3 files
81 81 updating to branch default
82 pulling subrepo sub from ssh://user@dummy/sub
82 cloning subrepo sub from ssh://user@dummy/sub
83 83 requesting all changes
84 84 adding changesets
85 85 adding manifests
86 86 adding file changes
87 87 added 1 changesets with 1 changes to 1 files
88 88 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 89
90 90 $ hg -R sshclone push ssh://user@dummy/$TESTTMP/cloned
91 91 pushing to ssh://user@dummy/$TESTTMP/cloned
92 92 pushing subrepo sub to ssh://user@dummy/$TESTTMP/sub
93 93 searching for changes
94 94 no changes found
95 95 searching for changes
96 96 no changes found
97 97
98 98 $ cat dummylog
99 99 Got arguments 1:user@dummy 2:hg -R cloned serve --stdio
100 100 Got arguments 1:user@dummy 2:hg -R sub serve --stdio
101 101 Got arguments 1:user@dummy 2:hg -R $TESTTMP/cloned serve --stdio
102 102 Got arguments 1:user@dummy 2:hg -R $TESTTMP/sub serve --stdio
103 103 $ rm $BINDIR/ssh
@@ -1,830 +1,805 b''
1 1 $ rm -rf sub
2 2 $ mkdir sub
3 3 $ cd sub
4 4 $ hg init t
5 5 $ cd t
6 6
7 7 first revision, no sub
8 8
9 9 $ echo a > a
10 10 $ hg ci -Am0
11 11 adding a
12 12
13 13 add first sub
14 14
15 15 $ echo s = s > .hgsub
16 16 $ hg add .hgsub
17 17 $ hg init s
18 18 $ echo a > s/a
19 19
20 20 Issue2232: committing a subrepo without .hgsub
21 21
22 22 $ hg ci -mbad s
23 23 abort: can't commit subrepos without .hgsub
24 24 [255]
25 25
26 26 $ hg -R s ci -Ams0
27 27 adding a
28 28 $ hg sum
29 29 parent: 0:f7b1eb17ad24 tip
30 30 0
31 31 branch: default
32 32 commit: 1 added, 1 subrepos
33 33 update: (current)
34 34 $ hg ci -m1
35 35 committing subrepository s
36 36
37 37 Issue2022: update -C
38 38
39 39 $ echo b > s/a
40 40 $ hg sum
41 41 parent: 1:7cf8cfea66e4 tip
42 42 1
43 43 branch: default
44 44 commit: 1 subrepos
45 45 update: (current)
46 46 $ hg co -C 1
47 47 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
48 48 $ hg sum
49 49 parent: 1:7cf8cfea66e4 tip
50 50 1
51 51 branch: default
52 52 commit: (clean)
53 53 update: (current)
54 54
55 55 add sub sub
56 56
57 57 $ echo ss = ss > s/.hgsub
58 58 $ hg init s/ss
59 59 $ echo a > s/ss/a
60 60 $ hg -R s add s/.hgsub
61 61 $ hg -R s/ss add s/ss/a
62 62 $ hg sum
63 63 parent: 1:7cf8cfea66e4 tip
64 64 1
65 65 branch: default
66 66 commit: 1 subrepos
67 67 update: (current)
68 68 $ hg ci -m2
69 69 committing subrepository s
70 70 committing subrepository s/ss
71 71 $ hg sum
72 72 parent: 2:df30734270ae tip
73 73 2
74 74 branch: default
75 75 commit: (clean)
76 76 update: (current)
77 77
78 78 bump sub rev (and check it is ignored by ui.commitsubrepos)
79 79
80 80 $ echo b > s/a
81 81 $ hg -R s ci -ms1
82 82 $ hg --config ui.commitsubrepos=no ci -m3
83 83 committing subrepository s
84 84
85 85 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
86 86
87 87 $ echo c > s/a
88 88 $ hg --config ui.commitsubrepos=no ci -m4
89 89 abort: uncommitted changes in subrepo s
90 90 [255]
91 91 $ hg ci -m4
92 92 committing subrepository s
93 93 $ hg tip -R s
94 94 changeset: 3:1c833a7a9e3a
95 95 tag: tip
96 96 user: test
97 97 date: Thu Jan 01 00:00:00 1970 +0000
98 98 summary: 4
99 99
100 100
101 101 check caching
102 102
103 103 $ hg co 0
104 104 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
105 105 $ hg debugsub
106 106
107 107 restore
108 108
109 109 $ hg co
110 110 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
111 111 $ hg debugsub
112 112 path s
113 113 source s
114 114 revision 1c833a7a9e3a4445c711aaf0f012379cd0d4034e
115 115
116 116 new branch for merge tests
117 117
118 118 $ hg co 1
119 119 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 120 $ echo t = t >> .hgsub
121 121 $ hg init t
122 122 $ echo t > t/t
123 123 $ hg -R t add t
124 124 adding t/t
125 125
126 126 5
127 127
128 128 $ hg ci -m5 # add sub
129 129 committing subrepository t
130 130 created new head
131 131 $ echo t2 > t/t
132 132
133 133 6
134 134
135 135 $ hg st -R s
136 136 $ hg ci -m6 # change sub
137 137 committing subrepository t
138 138 $ hg debugsub
139 139 path s
140 140 source s
141 141 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
142 142 path t
143 143 source t
144 144 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
145 145 $ echo t3 > t/t
146 146
147 147 7
148 148
149 149 $ hg ci -m7 # change sub again for conflict test
150 150 committing subrepository t
151 151 $ hg rm .hgsub
152 152
153 153 8
154 154
155 155 $ hg ci -m8 # remove sub
156 156
157 157 merge tests
158 158
159 159 $ hg co -C 3
160 160 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
161 161 $ hg merge 5 # test adding
162 162 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
163 163 (branch merge, don't forget to commit)
164 164 $ hg debugsub
165 165 path s
166 166 source s
167 167 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
168 168 path t
169 169 source t
170 170 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
171 171 $ hg ci -m9
172 172 created new head
173 173 $ hg merge 6 --debug # test change
174 174 searching for copies back to rev 2
175 175 resolving manifests
176 176 overwrite None partial False
177 177 ancestor 1f14a2e2d3ec local f0d2028bf86d+ remote 1831e14459c4
178 178 .hgsubstate: versions differ -> m
179 179 updating: .hgsubstate 1/1 files (100.00%)
180 180 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
181 181 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
182 182 getting subrepo t
183 183 resolving manifests
184 184 overwrite True partial False
185 185 ancestor 60ca1237c194+ local 60ca1237c194+ remote 6747d179aa9a
186 186 t: remote is newer -> g
187 187 updating: t 1/1 files (100.00%)
188 188 getting t
189 189 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 190 (branch merge, don't forget to commit)
191 191 $ hg debugsub
192 192 path s
193 193 source s
194 194 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
195 195 path t
196 196 source t
197 197 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
198 198 $ echo conflict > t/t
199 199 $ hg ci -m10
200 200 committing subrepository t
201 201 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
202 202 searching for copies back to rev 2
203 203 resolving manifests
204 204 overwrite None partial False
205 205 ancestor 1831e14459c4 local e45c8b14af55+ remote f94576341bcf
206 206 .hgsubstate: versions differ -> m
207 207 updating: .hgsubstate 1/1 files (100.00%)
208 208 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
209 209 subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
210 210 merging subrepo t
211 211 searching for copies back to rev 2
212 212 resolving manifests
213 213 overwrite None partial False
214 214 ancestor 6747d179aa9a local 20a0db6fbf6c+ remote 7af322bc1198
215 215 t: versions differ -> m
216 216 preserving t for resolve of t
217 217 updating: t 1/1 files (100.00%)
218 218 picked tool 'internal:merge' for t (binary False symlink False)
219 219 merging t
220 220 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
221 221 warning: conflicts during merge.
222 222 merging t failed!
223 223 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
224 224 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
225 225 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
226 226 (branch merge, don't forget to commit)
227 227
228 228 should conflict
229 229
230 230 $ cat t/t
231 231 <<<<<<< local
232 232 conflict
233 233 =======
234 234 t3
235 235 >>>>>>> other
236 236
237 237 clone
238 238
239 239 $ cd ..
240 240 $ hg clone t tc
241 241 updating to branch default
242 pulling subrepo s from $TESTTMP/sub/t/s
243 requesting all changes
244 adding changesets
245 adding manifests
246 adding file changes
247 added 4 changesets with 5 changes to 3 files
248 pulling subrepo s/ss from $TESTTMP/sub/t/s/ss
249 requesting all changes
250 adding changesets
251 adding manifests
252 adding file changes
253 added 1 changesets with 1 changes to 1 files
254 pulling subrepo t from $TESTTMP/sub/t/t
255 requesting all changes
256 adding changesets
257 adding manifests
258 adding file changes
259 added 4 changesets with 4 changes to 1 files (+1 heads)
242 cloning subrepo s from $TESTTMP/sub/t/s
243 cloning subrepo s/ss from $TESTTMP/sub/t/s/ss
244 cloning subrepo t from $TESTTMP/sub/t/t
260 245 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
261 246 $ cd tc
262 247 $ hg debugsub
263 248 path s
264 249 source s
265 250 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
266 251 path t
267 252 source t
268 253 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
269 254
270 255 push
271 256
272 257 $ echo bah > t/t
273 258 $ hg ci -m11
274 259 committing subrepository t
275 260 $ hg push
276 261 pushing to $TESTTMP/sub/t
277 262 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
278 263 searching for changes
279 264 no changes found
280 265 pushing subrepo s to $TESTTMP/sub/t/s
281 266 searching for changes
282 267 no changes found
283 268 pushing subrepo t to $TESTTMP/sub/t/t
284 269 searching for changes
285 270 adding changesets
286 271 adding manifests
287 272 adding file changes
288 273 added 1 changesets with 1 changes to 1 files
289 274 searching for changes
290 275 adding changesets
291 276 adding manifests
292 277 adding file changes
293 278 added 1 changesets with 1 changes to 1 files
294 279
295 280 push -f
296 281
297 282 $ echo bah > s/a
298 283 $ hg ci -m12
299 284 committing subrepository s
300 285 $ hg push
301 286 pushing to $TESTTMP/sub/t
302 287 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
303 288 searching for changes
304 289 no changes found
305 290 pushing subrepo s to $TESTTMP/sub/t/s
306 291 searching for changes
307 292 abort: push creates new remote heads on branch 'default'!
308 293 (did you forget to merge? use push -f to force)
309 294 [255]
310 295 $ hg push -f
311 296 pushing to $TESTTMP/sub/t
312 297 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
313 298 searching for changes
314 299 no changes found
315 300 pushing subrepo s to $TESTTMP/sub/t/s
316 301 searching for changes
317 302 adding changesets
318 303 adding manifests
319 304 adding file changes
320 305 added 1 changesets with 1 changes to 1 files (+1 heads)
321 306 pushing subrepo t to $TESTTMP/sub/t/t
322 307 searching for changes
323 308 no changes found
324 309 searching for changes
325 310 adding changesets
326 311 adding manifests
327 312 adding file changes
328 313 added 1 changesets with 1 changes to 1 files
329 314
330 315 update
331 316
332 317 $ cd ../t
333 318 $ hg up -C # discard our earlier merge
334 319 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
335 320 $ echo blah > t/t
336 321 $ hg ci -m13
337 322 committing subrepository t
338 323
339 324 pull
340 325
341 326 $ cd ../tc
342 327 $ hg pull
343 328 pulling from $TESTTMP/sub/t
344 329 searching for changes
345 330 adding changesets
346 331 adding manifests
347 332 adding file changes
348 333 added 1 changesets with 1 changes to 1 files
349 334 (run 'hg update' to get a working copy)
350 335
351 336 should pull t
352 337
353 338 $ hg up
354 339 pulling subrepo t from $TESTTMP/sub/t/t
355 340 searching for changes
356 341 adding changesets
357 342 adding manifests
358 343 adding file changes
359 344 added 1 changesets with 1 changes to 1 files
360 345 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
361 346 $ cat t/t
362 347 blah
363 348
364 349 bogus subrepo path aborts
365 350
366 351 $ echo 'bogus=[boguspath' >> .hgsub
367 352 $ hg ci -m 'bogus subrepo path'
368 353 abort: missing ] in subrepo source
369 354 [255]
370 355
371 356 Issue1986: merge aborts when trying to merge a subrepo that
372 357 shouldn't need merging
373 358
374 359 # subrepo layout
375 360 #
376 361 # o 5 br
377 362 # /|
378 363 # o | 4 default
379 364 # | |
380 365 # | o 3 br
381 366 # |/|
382 367 # o | 2 default
383 368 # | |
384 369 # | o 1 br
385 370 # |/
386 371 # o 0 default
387 372
388 373 $ cd ..
389 374 $ rm -rf sub
390 375 $ hg init main
391 376 $ cd main
392 377 $ hg init s
393 378 $ cd s
394 379 $ echo a > a
395 380 $ hg ci -Am1
396 381 adding a
397 382 $ hg branch br
398 383 marked working directory as branch br
399 384 $ echo a >> a
400 385 $ hg ci -m1
401 386 $ hg up default
402 387 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
403 388 $ echo b > b
404 389 $ hg ci -Am1
405 390 adding b
406 391 $ hg up br
407 392 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
408 393 $ hg merge tip
409 394 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
410 395 (branch merge, don't forget to commit)
411 396 $ hg ci -m1
412 397 $ hg up 2
413 398 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
414 399 $ echo c > c
415 400 $ hg ci -Am1
416 401 adding c
417 402 $ hg up 3
418 403 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
419 404 $ hg merge 4
420 405 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
421 406 (branch merge, don't forget to commit)
422 407 $ hg ci -m1
423 408
424 409 # main repo layout:
425 410 #
426 411 # * <-- try to merge default into br again
427 412 # .`|
428 413 # . o 5 br --> substate = 5
429 414 # . |
430 415 # o | 4 default --> substate = 4
431 416 # | |
432 417 # | o 3 br --> substate = 2
433 418 # |/|
434 419 # o | 2 default --> substate = 2
435 420 # | |
436 421 # | o 1 br --> substate = 3
437 422 # |/
438 423 # o 0 default --> substate = 2
439 424
440 425 $ cd ..
441 426 $ echo 's = s' > .hgsub
442 427 $ hg -R s up 2
443 428 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
444 429 $ hg ci -Am1
445 430 adding .hgsub
446 431 committing subrepository s
447 432 $ hg branch br
448 433 marked working directory as branch br
449 434 $ echo b > b
450 435 $ hg -R s up 3
451 436 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
452 437 $ hg ci -Am1
453 438 adding b
454 439 committing subrepository s
455 440 $ hg up default
456 441 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
457 442 $ echo c > c
458 443 $ hg ci -Am1
459 444 adding c
460 445 $ hg up 1
461 446 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
462 447 $ hg merge 2
463 448 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
464 449 (branch merge, don't forget to commit)
465 450 $ hg ci -m1
466 451 $ hg up 2
467 452 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
468 453 $ hg -R s up 4
469 454 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
470 455 $ echo d > d
471 456 $ hg ci -Am1
472 457 adding d
473 458 committing subrepository s
474 459 $ hg up 3
475 460 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
476 461 $ hg -R s up 5
477 462 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
478 463 $ echo e > e
479 464 $ hg ci -Am1
480 465 adding e
481 466 committing subrepository s
482 467
483 468 $ hg up 5
484 469 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
485 470 $ hg merge 4 # try to merge default into br again
486 471 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
487 472 (branch merge, don't forget to commit)
488 473 $ cd ..
489 474
490 475 test subrepo delete from .hgsubstate
491 476
492 477 $ hg init testdelete
493 478 $ mkdir testdelete/nested testdelete/nested2
494 479 $ hg init testdelete/nested
495 480 $ hg init testdelete/nested2
496 481 $ echo test > testdelete/nested/foo
497 482 $ echo test > testdelete/nested2/foo
498 483 $ hg -R testdelete/nested add
499 484 adding testdelete/nested/foo
500 485 $ hg -R testdelete/nested2 add
501 486 adding testdelete/nested2/foo
502 487 $ hg -R testdelete/nested ci -m test
503 488 $ hg -R testdelete/nested2 ci -m test
504 489 $ echo nested = nested > testdelete/.hgsub
505 490 $ echo nested2 = nested2 >> testdelete/.hgsub
506 491 $ hg -R testdelete add
507 492 adding testdelete/.hgsub
508 493 $ hg -R testdelete ci -m "nested 1 & 2 added"
509 494 committing subrepository nested
510 495 committing subrepository nested2
511 496 $ echo nested = nested > testdelete/.hgsub
512 497 $ hg -R testdelete ci -m "nested 2 deleted"
513 498 $ cat testdelete/.hgsubstate
514 499 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
515 500 $ hg -R testdelete remove testdelete/.hgsub
516 501 $ hg -R testdelete ci -m ".hgsub deleted"
517 502 $ cat testdelete/.hgsubstate
518 503
519 504 test repository cloning
520 505
521 506 $ mkdir mercurial mercurial2
522 507 $ hg init nested_absolute
523 508 $ echo test > nested_absolute/foo
524 509 $ hg -R nested_absolute add
525 510 adding nested_absolute/foo
526 511 $ hg -R nested_absolute ci -mtest
527 512 $ cd mercurial
528 513 $ hg init nested_relative
529 514 $ echo test2 > nested_relative/foo2
530 515 $ hg -R nested_relative add
531 516 adding nested_relative/foo2
532 517 $ hg -R nested_relative ci -mtest2
533 518 $ hg init main
534 519 $ echo "nested_relative = ../nested_relative" > main/.hgsub
535 520 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
536 521 $ hg -R main add
537 522 adding main/.hgsub
538 523 $ hg -R main ci -m "add subrepos"
539 524 committing subrepository nested_absolute
540 525 committing subrepository nested_relative
541 526 $ cd ..
542 527 $ hg clone mercurial/main mercurial2/main
543 528 updating to branch default
544 529 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
545 530 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
546 531 > mercurial2/main/nested_relative/.hg/hgrc
547 532 [paths]
548 533 default = $TESTTMP/sub/mercurial/nested_absolute
549 534 [paths]
550 535 default = $TESTTMP/sub/mercurial/nested_relative
551 536 $ rm -rf mercurial mercurial2
552 537
553 538 Issue1977: multirepo push should fail if subrepo push fails
554 539
555 540 $ hg init repo
556 541 $ hg init repo/s
557 542 $ echo a > repo/s/a
558 543 $ hg -R repo/s ci -Am0
559 544 adding a
560 545 $ echo s = s > repo/.hgsub
561 546 $ hg -R repo ci -Am1
562 547 adding .hgsub
563 548 committing subrepository s
564 549 $ hg clone repo repo2
565 550 updating to branch default
566 pulling subrepo s from $TESTTMP/sub/repo/s
567 requesting all changes
568 adding changesets
569 adding manifests
570 adding file changes
571 added 1 changesets with 1 changes to 1 files
551 cloning subrepo s from $TESTTMP/sub/repo/s
572 552 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
573 553 $ hg -q -R repo2 pull -u
574 554 $ echo 1 > repo2/s/a
575 555 $ hg -R repo2/s ci -m2
576 556 $ hg -q -R repo2/s push
577 557 $ hg -R repo2/s up -C 0
578 558 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
579 559 $ echo 2 > repo2/s/a
580 560 $ hg -R repo2/s ci -m3
581 561 created new head
582 562 $ hg -R repo2 ci -m3
583 563 committing subrepository s
584 564 $ hg -q -R repo2 push
585 565 abort: push creates new remote heads on branch 'default'!
586 566 (did you forget to merge? use push -f to force)
587 567 [255]
588 568 $ hg -R repo update
589 569 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
590 570 $ rm -rf repo2 repo
591 571
592 572
593 573 Issue1852 subrepos with relative paths always push/pull relative to default
594 574
595 575 Prepare a repo with subrepo
596 576
597 577 $ hg init issue1852a
598 578 $ cd issue1852a
599 579 $ hg init sub/repo
600 580 $ echo test > sub/repo/foo
601 581 $ hg -R sub/repo add sub/repo/foo
602 582 $ echo sub/repo = sub/repo > .hgsub
603 583 $ hg add .hgsub
604 584 $ hg ci -mtest
605 585 committing subrepository sub/repo
606 586 $ echo test >> sub/repo/foo
607 587 $ hg ci -mtest
608 588 committing subrepository sub/repo
609 589 $ cd ..
610 590
611 591 Create repo without default path, pull top repo, and see what happens on update
612 592
613 593 $ hg init issue1852b
614 594 $ hg -R issue1852b pull issue1852a
615 595 pulling from issue1852a
616 596 requesting all changes
617 597 adding changesets
618 598 adding manifests
619 599 adding file changes
620 600 added 2 changesets with 3 changes to 2 files
621 601 (run 'hg update' to get a working copy)
622 602 $ hg -R issue1852b update
623 603 abort: default path for subrepository sub/repo not found
624 604 [255]
625 605
626 606 Pull -u now doesn't help
627 607
628 608 $ hg -R issue1852b pull -u issue1852a
629 609 pulling from issue1852a
630 610 searching for changes
631 611 no changes found
632 612
633 613 Try the same, but with pull -u
634 614
635 615 $ hg init issue1852c
636 616 $ hg -R issue1852c pull -r0 -u issue1852a
637 617 pulling from issue1852a
638 618 adding changesets
639 619 adding manifests
640 620 adding file changes
641 621 added 1 changesets with 2 changes to 2 files
642 pulling subrepo sub/repo from issue1852a/sub/repo
643 requesting all changes
644 adding changesets
645 adding manifests
646 adding file changes
647 added 2 changesets with 2 changes to 1 files
622 cloning subrepo sub/repo from issue1852a/sub/repo
648 623 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
649 624
650 625 Try to push from the other side
651 626
652 627 $ hg -R issue1852a push `pwd`/issue1852c
653 628 pushing to $TESTTMP/sub/issue1852c
654 629 pushing subrepo sub/repo to $TESTTMP/sub/issue1852c/sub/repo
655 630 searching for changes
656 631 no changes found
657 632 searching for changes
658 633 adding changesets
659 634 adding manifests
660 635 adding file changes
661 636 added 1 changesets with 1 changes to 1 files
662 637
663 638 Check status of files when none of them belong to the first
664 639 subrepository:
665 640
666 641 $ hg init subrepo-status
667 642 $ cd subrepo-status
668 643 $ hg init subrepo-1
669 644 $ hg init subrepo-2
670 645 $ cd subrepo-2
671 646 $ touch file
672 647 $ hg add file
673 648 $ cd ..
674 649 $ echo subrepo-1 = subrepo-1 > .hgsub
675 650 $ echo subrepo-2 = subrepo-2 >> .hgsub
676 651 $ hg add .hgsub
677 652 $ hg ci -m 'Added subrepos'
678 653 committing subrepository subrepo-1
679 654 committing subrepository subrepo-2
680 655 $ hg st subrepo-2/file
681 656
682 657 Check hg update --clean
683 658 $ cd $TESTTMP/sub/t
684 659 $ rm -r t/t.orig
685 660 $ hg status -S --all
686 661 C .hgsub
687 662 C .hgsubstate
688 663 C a
689 664 C s/.hgsub
690 665 C s/.hgsubstate
691 666 C s/a
692 667 C s/ss/a
693 668 C t/t
694 669 $ echo c1 > s/a
695 670 $ cd s
696 671 $ echo c1 > b
697 672 $ echo c1 > c
698 673 $ hg add b
699 674 $ cd ..
700 675 $ hg status -S
701 676 M s/a
702 677 A s/b
703 678 ? s/c
704 679 $ hg update -C
705 680 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
706 681 $ hg status -S
707 682 ? s/b
708 683 ? s/c
709 684
710 685 Sticky subrepositories, no changes
711 686 $ cd $TESTTMP/sub/t
712 687 $ hg id
713 688 925c17564ef8 tip
714 689 $ hg -R s id
715 690 12a213df6fa9 tip
716 691 $ hg -R t id
717 692 52c0adc0515a tip
718 693 $ hg update 11
719 694 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
720 695 $ hg id
721 696 365661e5936a
722 697 $ hg -R s id
723 698 fc627a69481f
724 699 $ hg -R t id
725 700 e95bcfa18a35
726 701
727 702 Sticky subrepositorys, file changes
728 703 $ touch s/f1
729 704 $ touch t/f1
730 705 $ hg add -S s/f1
731 706 $ hg add -S t/f1
732 707 $ hg id
733 708 365661e5936a
734 709 $ hg -R s id
735 710 fc627a69481f+
736 711 $ hg -R t id
737 712 e95bcfa18a35+
738 713 $ hg update tip
739 714 subrepository sources for s differ
740 715 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
741 716 l
742 717 subrepository sources for t differ
743 718 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
744 719 l
745 720 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
746 721 $ hg id
747 722 925c17564ef8+ tip
748 723 $ hg -R s id
749 724 fc627a69481f+
750 725 $ hg -R t id
751 726 e95bcfa18a35+
752 727 $ hg update --clean tip
753 728 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
754 729
755 730 Sticky subrepository, revision updates
756 731 $ hg id
757 732 925c17564ef8 tip
758 733 $ hg -R s id
759 734 12a213df6fa9 tip
760 735 $ hg -R t id
761 736 52c0adc0515a tip
762 737 $ cd s
763 738 $ hg update -r -2
764 739 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
765 740 $ cd ../t
766 741 $ hg update -r 2
767 742 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
768 743 $ cd ..
769 744 $ hg update 10
770 745 subrepository sources for t differ (in checked out version)
771 746 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
772 747 l
773 748 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
774 749 $ hg id
775 750 e45c8b14af55+
776 751 $ hg -R s id
777 752 1c833a7a9e3a
778 753 $ hg -R t id
779 754 7af322bc1198
780 755
781 756 Sticky subrepository, file changes and revision updates
782 757 $ touch s/f1
783 758 $ touch t/f1
784 759 $ hg add -S s/f1
785 760 $ hg add -S t/f1
786 761 $ hg id
787 762 e45c8b14af55+
788 763 $ hg -R s id
789 764 1c833a7a9e3a+
790 765 $ hg -R t id
791 766 7af322bc1198+
792 767 $ hg update tip
793 768 subrepository sources for s differ
794 769 use (l)ocal source (1c833a7a9e3a) or (r)emote source (12a213df6fa9)?
795 770 l
796 771 subrepository sources for t differ
797 772 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
798 773 l
799 774 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
800 775 $ hg id
801 776 925c17564ef8 tip
802 777 $ hg -R s id
803 778 1c833a7a9e3a+
804 779 $ hg -R t id
805 780 7af322bc1198+
806 781
807 782 Sticky repository, update --clean
808 783 $ hg update --clean tip
809 784 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
810 785 $ hg id
811 786 925c17564ef8 tip
812 787 $ hg -R s id
813 788 12a213df6fa9 tip
814 789 $ hg -R t id
815 790 52c0adc0515a tip
816 791
817 792 Test subrepo already at intended revision:
818 793 $ cd s
819 794 $ hg update fc627a69481f
820 795 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
821 796 $ cd ..
822 797 $ hg update 11
823 798 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
824 799 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
825 800 $ hg id -n
826 801 11+
827 802 $ hg -R s id
828 803 fc627a69481f
829 804 $ hg -R t id
830 805 e95bcfa18a35
General Comments 0
You need to be logged in to leave comments. Login now