##// END OF EJS Templates
filemerge: break overall filemerge into separate premerge and merge steps...
Siddharth Agarwal -
r26611:a5ff66e6 default
parent child Browse files
Show More
@@ -1,583 +1,583 b''
1 1 # filemerge.py - file-level merge handling for Mercurial
2 2 #
3 3 # Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import filecmp
11 11 import os
12 12 import re
13 13 import tempfile
14 14
15 15 from .i18n import _
16 16 from .node import short
17 17
18 18 from . import (
19 19 error,
20 20 match,
21 21 simplemerge,
22 22 tagmerge,
23 23 templatekw,
24 24 templater,
25 25 util,
26 26 )
27 27
28 28 def _toolstr(ui, tool, part, default=""):
29 29 return ui.config("merge-tools", tool + "." + part, default)
30 30
31 31 def _toolbool(ui, tool, part, default=False):
32 32 return ui.configbool("merge-tools", tool + "." + part, default)
33 33
34 34 def _toollist(ui, tool, part, default=[]):
35 35 return ui.configlist("merge-tools", tool + "." + part, default)
36 36
37 37 internals = {}
38 38 # Merge tools to document.
39 39 internalsdoc = {}
40 40
41 41 # internal tool merge types
42 42 nomerge = None
43 43 mergeonly = 'mergeonly' # just the full merge, no premerge
44 44 fullmerge = 'fullmerge' # both premerge and merge
45 45
46 46 def internaltool(name, mergetype, onfailure=None, precheck=None):
47 47 '''return a decorator for populating internal merge tool table'''
48 48 def decorator(func):
49 49 fullname = ':' + name
50 50 func.__doc__ = "``%s``\n" % fullname + func.__doc__.strip()
51 51 internals[fullname] = func
52 52 internals['internal:' + name] = func
53 53 internalsdoc[fullname] = func
54 54 func.mergetype = mergetype
55 55 func.onfailure = onfailure
56 56 func.precheck = precheck
57 57 return func
58 58 return decorator
59 59
60 60 def _findtool(ui, tool):
61 61 if tool in internals:
62 62 return tool
63 63 return findexternaltool(ui, tool)
64 64
65 65 def findexternaltool(ui, tool):
66 66 for kn in ("regkey", "regkeyalt"):
67 67 k = _toolstr(ui, tool, kn)
68 68 if not k:
69 69 continue
70 70 p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
71 71 if p:
72 72 p = util.findexe(p + _toolstr(ui, tool, "regappend"))
73 73 if p:
74 74 return p
75 75 exe = _toolstr(ui, tool, "executable", tool)
76 76 return util.findexe(util.expandpath(exe))
77 77
78 78 def _picktool(repo, ui, path, binary, symlink):
79 79 def check(tool, pat, symlink, binary):
80 80 tmsg = tool
81 81 if pat:
82 82 tmsg += " specified for " + pat
83 83 if not _findtool(ui, tool):
84 84 if pat: # explicitly requested tool deserves a warning
85 85 ui.warn(_("couldn't find merge tool %s\n") % tmsg)
86 86 else: # configured but non-existing tools are more silent
87 87 ui.note(_("couldn't find merge tool %s\n") % tmsg)
88 88 elif symlink and not _toolbool(ui, tool, "symlink"):
89 89 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
90 90 elif binary and not _toolbool(ui, tool, "binary"):
91 91 ui.warn(_("tool %s can't handle binary\n") % tmsg)
92 92 elif not util.gui() and _toolbool(ui, tool, "gui"):
93 93 ui.warn(_("tool %s requires a GUI\n") % tmsg)
94 94 else:
95 95 return True
96 96 return False
97 97
98 98 # internal config: ui.forcemerge
99 99 # forcemerge comes from command line arguments, highest priority
100 100 force = ui.config('ui', 'forcemerge')
101 101 if force:
102 102 toolpath = _findtool(ui, force)
103 103 if toolpath:
104 104 return (force, util.shellquote(toolpath))
105 105 else:
106 106 # mimic HGMERGE if given tool not found
107 107 return (force, force)
108 108
109 109 # HGMERGE takes next precedence
110 110 hgmerge = os.environ.get("HGMERGE")
111 111 if hgmerge:
112 112 return (hgmerge, hgmerge)
113 113
114 114 # then patterns
115 115 for pat, tool in ui.configitems("merge-patterns"):
116 116 mf = match.match(repo.root, '', [pat])
117 117 if mf(path) and check(tool, pat, symlink, False):
118 118 toolpath = _findtool(ui, tool)
119 119 return (tool, util.shellquote(toolpath))
120 120
121 121 # then merge tools
122 122 tools = {}
123 123 for k, v in ui.configitems("merge-tools"):
124 124 t = k.split('.')[0]
125 125 if t not in tools:
126 126 tools[t] = int(_toolstr(ui, t, "priority", "0"))
127 127 names = tools.keys()
128 128 tools = sorted([(-p, t) for t, p in tools.items()])
129 129 uimerge = ui.config("ui", "merge")
130 130 if uimerge:
131 131 if uimerge not in names:
132 132 return (uimerge, uimerge)
133 133 tools.insert(0, (None, uimerge)) # highest priority
134 134 tools.append((None, "hgmerge")) # the old default, if found
135 135 for p, t in tools:
136 136 if check(t, None, symlink, binary):
137 137 toolpath = _findtool(ui, t)
138 138 return (t, util.shellquote(toolpath))
139 139
140 140 # internal merge or prompt as last resort
141 141 if symlink or binary:
142 142 return ":prompt", None
143 143 return ":merge", None
144 144
145 145 def _eoltype(data):
146 146 "Guess the EOL type of a file"
147 147 if '\0' in data: # binary
148 148 return None
149 149 if '\r\n' in data: # Windows
150 150 return '\r\n'
151 151 if '\r' in data: # Old Mac
152 152 return '\r'
153 153 if '\n' in data: # UNIX
154 154 return '\n'
155 155 return None # unknown
156 156
157 157 def _matcheol(file, origfile):
158 158 "Convert EOL markers in a file to match origfile"
159 159 tostyle = _eoltype(util.readfile(origfile))
160 160 if tostyle:
161 161 data = util.readfile(file)
162 162 style = _eoltype(data)
163 163 if style:
164 164 newdata = data.replace(style, tostyle)
165 165 if newdata != data:
166 166 util.writefile(file, newdata)
167 167
168 168 @internaltool('prompt', nomerge)
169 169 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf):
170 170 """Asks the user which of the local or the other version to keep as
171 171 the merged version."""
172 172 ui = repo.ui
173 173 fd = fcd.path()
174 174
175 175 if ui.promptchoice(_(" no tool found to merge %s\n"
176 176 "keep (l)ocal or take (o)ther?"
177 177 "$$ &Local $$ &Other") % fd, 0):
178 178 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf)
179 179 else:
180 180 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf)
181 181
182 182 @internaltool('local', nomerge)
183 183 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf):
184 184 """Uses the local version of files as the merged version."""
185 185 return 0
186 186
187 187 @internaltool('other', nomerge)
188 188 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf):
189 189 """Uses the other version of files as the merged version."""
190 190 repo.wwrite(fcd.path(), fco.data(), fco.flags())
191 191 return 0
192 192
193 193 @internaltool('fail', nomerge)
194 194 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf):
195 195 """
196 196 Rather than attempting to merge files that were modified on both
197 197 branches, it marks them as unresolved. The resolve command must be
198 198 used to resolve these conflicts."""
199 199 return 1
200 200
201 201 def _premerge(repo, toolconf, files, labels=None):
202 202 tool, toolpath, binary, symlink = toolconf
203 203 if symlink:
204 204 return 1
205 205 a, b, c, back = files
206 206
207 207 ui = repo.ui
208 208
209 209 validkeep = ['keep', 'keep-merge3']
210 210
211 211 # do we attempt to simplemerge first?
212 212 try:
213 213 premerge = _toolbool(ui, tool, "premerge", not binary)
214 214 except error.ConfigError:
215 215 premerge = _toolstr(ui, tool, "premerge").lower()
216 216 if premerge not in validkeep:
217 217 _valid = ', '.join(["'" + v + "'" for v in validkeep])
218 218 raise error.ConfigError(_("%s.premerge not valid "
219 219 "('%s' is neither boolean nor %s)") %
220 220 (tool, premerge, _valid))
221 221
222 222 if premerge:
223 223 if premerge == 'keep-merge3':
224 224 if not labels:
225 225 labels = _defaultconflictlabels
226 226 if len(labels) < 3:
227 227 labels.append('base')
228 228 r = simplemerge.simplemerge(ui, a, b, c, quiet=True, label=labels)
229 229 if not r:
230 230 ui.debug(" premerge successful\n")
231 231 return 0
232 232 if premerge not in validkeep:
233 233 util.copyfile(back, a) # restore from backup and try again
234 234 return 1 # continue merging
235 235
236 236 def _symlinkcheck(repo, mynode, orig, fcd, fco, fca, toolconf):
237 237 tool, toolpath, binary, symlink = toolconf
238 238 if symlink:
239 239 repo.ui.warn(_('warning: internal %s cannot merge symlinks '
240 240 'for %s\n') % (tool, fcd.path()))
241 241 return False
242 242 return True
243 243
244 244 def _merge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels, mode):
245 245 """
246 246 Uses the internal non-interactive simple merge algorithm for merging
247 247 files. It will fail if there are any conflicts and leave markers in
248 248 the partially merged file. Markers will have two sections, one for each side
249 249 of merge, unless mode equals 'union' which suppresses the markers."""
250 250 a, b, c, back = files
251 251
252 252 ui = repo.ui
253 253
254 254 r = simplemerge.simplemerge(ui, a, b, c, label=labels, mode=mode)
255 255 return True, r
256 256
257 257 @internaltool('union', fullmerge,
258 258 _("merging %s incomplete! "
259 259 "(edit conflicts, then use 'hg resolve --mark')\n"),
260 260 precheck=_symlinkcheck)
261 261 def _iunion(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
262 262 """
263 263 Uses the internal non-interactive simple merge algorithm for merging
264 264 files. It will use both left and right sides for conflict regions.
265 265 No markers are inserted."""
266 266 return _merge(repo, mynode, orig, fcd, fco, fca, toolconf,
267 267 files, labels, 'union')
268 268
269 269 @internaltool('merge', fullmerge,
270 270 _("merging %s incomplete! "
271 271 "(edit conflicts, then use 'hg resolve --mark')\n"),
272 272 precheck=_symlinkcheck)
273 273 def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
274 274 """
275 275 Uses the internal non-interactive simple merge algorithm for merging
276 276 files. It will fail if there are any conflicts and leave markers in
277 277 the partially merged file. Markers will have two sections, one for each side
278 278 of merge."""
279 279 return _merge(repo, mynode, orig, fcd, fco, fca, toolconf,
280 280 files, labels, 'merge')
281 281
282 282 @internaltool('merge3', fullmerge,
283 283 _("merging %s incomplete! "
284 284 "(edit conflicts, then use 'hg resolve --mark')\n"),
285 285 precheck=_symlinkcheck)
286 286 def _imerge3(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
287 287 """
288 288 Uses the internal non-interactive simple merge algorithm for merging
289 289 files. It will fail if there are any conflicts and leave markers in
290 290 the partially merged file. Marker will have three sections, one from each
291 291 side of the merge and one for the base content."""
292 292 if not labels:
293 293 labels = _defaultconflictlabels
294 294 if len(labels) < 3:
295 295 labels.append('base')
296 296 return _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels)
297 297
298 298 def _imergeauto(repo, mynode, orig, fcd, fco, fca, toolconf, files,
299 299 labels=None, localorother=None):
300 300 """
301 301 Generic driver for _imergelocal and _imergeother
302 302 """
303 303 assert localorother is not None
304 304 tool, toolpath, binary, symlink = toolconf
305 305 if symlink:
306 306 repo.ui.warn(_('warning: :merge-%s cannot merge symlinks '
307 307 'for %s\n') % (localorother, fcd.path()))
308 308 return False, 1
309 309 a, b, c, back = files
310 310 r = simplemerge.simplemerge(repo.ui, a, b, c, label=labels,
311 311 localorother=localorother)
312 312 return True, r
313 313
314 314 @internaltool('merge-local', mergeonly)
315 315 def _imergelocal(*args, **kwargs):
316 316 """
317 317 Like :merge, but resolve all conflicts non-interactively in favor
318 318 of the local changes."""
319 319 success, status = _imergeauto(localorother='local', *args, **kwargs)
320 320 return success, status
321 321
322 322 @internaltool('merge-other', mergeonly)
323 323 def _imergeother(*args, **kwargs):
324 324 """
325 325 Like :merge, but resolve all conflicts non-interactively in favor
326 326 of the other changes."""
327 327 success, status = _imergeauto(localorother='other', *args, **kwargs)
328 328 return success, status
329 329
330 330 @internaltool('tagmerge', mergeonly,
331 331 _("automatic tag merging of %s failed! "
332 332 "(use 'hg resolve --tool :merge' or another merge "
333 333 "tool of your choice)\n"))
334 334 def _itagmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
335 335 """
336 336 Uses the internal tag merge algorithm (experimental).
337 337 """
338 338 return tagmerge.merge(repo, fcd, fco, fca)
339 339
340 340 @internaltool('dump', fullmerge)
341 341 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
342 342 """
343 343 Creates three versions of the files to merge, containing the
344 344 contents of local, other and base. These files can then be used to
345 345 perform a merge manually. If the file to be merged is named
346 346 ``a.txt``, these files will accordingly be named ``a.txt.local``,
347 347 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
348 348 same directory as ``a.txt``."""
349 349 a, b, c, back = files
350 350
351 351 fd = fcd.path()
352 352
353 353 util.copyfile(a, a + ".local")
354 354 repo.wwrite(fd + ".other", fco.data(), fco.flags())
355 355 repo.wwrite(fd + ".base", fca.data(), fca.flags())
356 356 return False, 1
357 357
358 358 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
359 359 tool, toolpath, binary, symlink = toolconf
360 360 a, b, c, back = files
361 361 out = ""
362 362 env = {'HG_FILE': fcd.path(),
363 363 'HG_MY_NODE': short(mynode),
364 364 'HG_OTHER_NODE': str(fco.changectx()),
365 365 'HG_BASE_NODE': str(fca.changectx()),
366 366 'HG_MY_ISLINK': 'l' in fcd.flags(),
367 367 'HG_OTHER_ISLINK': 'l' in fco.flags(),
368 368 'HG_BASE_ISLINK': 'l' in fca.flags(),
369 369 }
370 370
371 371 ui = repo.ui
372 372
373 373 args = _toolstr(ui, tool, "args", '$local $base $other')
374 374 if "$output" in args:
375 375 out, a = a, back # read input from backup, write to original
376 376 replace = {'local': a, 'base': b, 'other': c, 'output': out}
377 377 args = util.interpolate(r'\$', replace, args,
378 378 lambda s: util.shellquote(util.localpath(s)))
379 379 cmd = toolpath + ' ' + args
380 380 repo.ui.debug('launching merge tool: %s\n' % cmd)
381 381 r = ui.system(cmd, cwd=repo.root, environ=env)
382 382 repo.ui.debug('merge tool returned: %s\n' % r)
383 383 return True, r
384 384
385 385 def _formatconflictmarker(repo, ctx, template, label, pad):
386 386 """Applies the given template to the ctx, prefixed by the label.
387 387
388 388 Pad is the minimum width of the label prefix, so that multiple markers
389 389 can have aligned templated parts.
390 390 """
391 391 if ctx.node() is None:
392 392 ctx = ctx.p1()
393 393
394 394 props = templatekw.keywords.copy()
395 395 props['templ'] = template
396 396 props['ctx'] = ctx
397 397 props['repo'] = repo
398 398 templateresult = template('conflictmarker', **props)
399 399
400 400 label = ('%s:' % label).ljust(pad + 1)
401 401 mark = '%s %s' % (label, templater.stringify(templateresult))
402 402
403 403 if mark:
404 404 mark = mark.splitlines()[0] # split for safety
405 405
406 406 # 8 for the prefix of conflict marker lines (e.g. '<<<<<<< ')
407 407 return util.ellipsis(mark, 80 - 8)
408 408
409 409 _defaultconflictmarker = ('{node|short} ' +
410 410 '{ifeq(tags, "tip", "", "{tags} ")}' +
411 411 '{if(bookmarks, "{bookmarks} ")}' +
412 412 '{ifeq(branch, "default", "", "{branch} ")}' +
413 413 '- {author|user}: {desc|firstline}')
414 414
415 415 _defaultconflictlabels = ['local', 'other']
416 416
417 417 def _formatlabels(repo, fcd, fco, fca, labels):
418 418 """Formats the given labels using the conflict marker template.
419 419
420 420 Returns a list of formatted labels.
421 421 """
422 422 cd = fcd.changectx()
423 423 co = fco.changectx()
424 424 ca = fca.changectx()
425 425
426 426 ui = repo.ui
427 427 template = ui.config('ui', 'mergemarkertemplate', _defaultconflictmarker)
428 428 tmpl = templater.templater(None, cache={'conflictmarker': template})
429 429
430 430 pad = max(len(l) for l in labels)
431 431
432 432 newlabels = [_formatconflictmarker(repo, cd, tmpl, labels[0], pad),
433 433 _formatconflictmarker(repo, co, tmpl, labels[1], pad)]
434 434 if len(labels) > 2:
435 435 newlabels.append(_formatconflictmarker(repo, ca, tmpl, labels[2], pad))
436 436 return newlabels
437 437
438 438 def _filemerge(premerge, repo, mynode, orig, fcd, fco, fca, labels=None):
439 439 """perform a 3-way merge in the working directory
440 440
441 441 premerge = whether this is a premerge
442 442 mynode = parent node before merge
443 443 orig = original local filename before merge
444 444 fco = other file context
445 445 fca = ancestor file context
446 446 fcd = local file context for current/destination file
447 447
448 448 Returns whether the merge is complete, and the return value of the merge.
449 449 """
450 450
451 451 def temp(prefix, ctx):
452 452 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
453 453 (fd, name) = tempfile.mkstemp(prefix=pre)
454 454 data = repo.wwritedata(ctx.path(), ctx.data())
455 455 f = os.fdopen(fd, "wb")
456 456 f.write(data)
457 457 f.close()
458 458 return name
459 459
460 460 if not fco.cmp(fcd): # files identical?
461 461 return True, None
462 462
463 463 ui = repo.ui
464 464 fd = fcd.path()
465 465 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
466 466 symlink = 'l' in fcd.flags() + fco.flags()
467 467 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
468 468 if tool in internals and tool.startswith('internal:'):
469 469 # normalize to new-style names (':merge' etc)
470 470 tool = tool[len('internal'):]
471 471 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
472 472 (tool, fd, binary, symlink))
473 473
474 474 if tool in internals:
475 475 func = internals[tool]
476 476 mergetype = func.mergetype
477 477 onfailure = func.onfailure
478 478 precheck = func.precheck
479 479 else:
480 480 func = _xmerge
481 481 mergetype = fullmerge
482 482 onfailure = _("merging %s failed!\n")
483 483 precheck = None
484 484
485 485 toolconf = tool, toolpath, binary, symlink
486 486
487 487 if mergetype == nomerge:
488 488 return True, func(repo, mynode, orig, fcd, fco, fca, toolconf)
489 489
490 490 if premerge:
491 491 if orig != fco.path():
492 492 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
493 493 else:
494 494 ui.status(_("merging %s\n") % fd)
495 495
496 496 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
497 497
498 498 if precheck and not precheck(repo, mynode, orig, fcd, fco, fca,
499 499 toolconf):
500 500 if onfailure:
501 501 ui.warn(onfailure % fd)
502 502 return True, 1
503 503
504 504 a = repo.wjoin(fd)
505 505 b = temp("base", fca)
506 506 c = temp("other", fco)
507 507 back = a + ".orig"
508 508 if premerge:
509 509 util.copyfile(a, back)
510 510 files = (a, b, c, back)
511 511
512 512 r = 1
513 513 try:
514 514 markerstyle = ui.config('ui', 'mergemarkers', 'basic')
515 515 if not labels:
516 516 labels = _defaultconflictlabels
517 517 if markerstyle != 'basic':
518 518 labels = _formatlabels(repo, fcd, fco, fca, labels)
519 519
520 520 if premerge and mergetype == fullmerge:
521 521 r = _premerge(repo, toolconf, files, labels=labels)
522 # complete if premerge successful (r is 0)
523 return not r, r
522 524
523 525 if not r: # premerge successfully merged the file
524 526 needcheck = False
525 527 else:
526 528 needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf,
527 529 files, labels=labels)
528 530
529 531 if needcheck:
530 532 r = _check(r, ui, tool, fcd, files)
531 533
532 534 if r:
533 535 if onfailure:
534 536 ui.warn(onfailure % fd)
535 537
536 538 return True, r
537 539 finally:
538 540 if not r:
539 541 util.unlink(back)
540 542 util.unlink(b)
541 543 util.unlink(c)
542 544
543 545 def _check(r, ui, tool, fcd, files):
544 546 fd = fcd.path()
545 547 a, b, c, back = files
546 548
547 549 if not r and (_toolbool(ui, tool, "checkconflicts") or
548 550 'conflicts' in _toollist(ui, tool, "check")):
549 551 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
550 552 re.MULTILINE):
551 553 r = 1
552 554
553 555 checked = False
554 556 if 'prompt' in _toollist(ui, tool, "check"):
555 557 checked = True
556 558 if ui.promptchoice(_("was merge of '%s' successful (yn)?"
557 559 "$$ &Yes $$ &No") % fd, 1):
558 560 r = 1
559 561
560 562 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
561 563 'changed' in
562 564 _toollist(ui, tool, "check")):
563 565 if filecmp.cmp(a, back):
564 566 if ui.promptchoice(_(" output file %s appears unchanged\n"
565 567 "was merge successful (yn)?"
566 568 "$$ &Yes $$ &No") % fd, 1):
567 569 r = 1
568 570
569 571 if _toolbool(ui, tool, "fixeol"):
570 572 _matcheol(a, back)
571 573
572 574 return r
573 575
574 576 def premerge(repo, mynode, orig, fcd, fco, fca, labels=None):
575 577 return _filemerge(True, repo, mynode, orig, fcd, fco, fca, labels=labels)
576 578
577 579 def filemerge(repo, mynode, orig, fcd, fco, fca, labels=None):
578 # premerge = True is temporary -- will be changed to False once premerge
579 # function above is ready
580 return _filemerge(True, repo, mynode, orig, fcd, fco, fca, labels=labels)
580 return _filemerge(False, repo, mynode, orig, fcd, fco, fca, labels=labels)
581 581
582 582 # tell hggettext to extract docstrings from these functions:
583 583 i18nfunctions = internals.values()
@@ -1,1189 +1,1192 b''
1 1 # merge.py - directory-level update/merge handling for Mercurial
2 2 #
3 3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import errno
11 11 import os
12 12 import shutil
13 13 import struct
14 14
15 15 from .i18n import _
16 16 from .node import (
17 17 bin,
18 18 hex,
19 19 nullid,
20 20 nullrev,
21 21 )
22 22 from . import (
23 23 copies,
24 24 destutil,
25 25 error,
26 26 filemerge,
27 27 obsolete,
28 28 subrepo,
29 29 util,
30 30 worker,
31 31 )
32 32
33 33 _pack = struct.pack
34 34 _unpack = struct.unpack
35 35
36 36 def _droponode(data):
37 37 # used for compatibility for v1
38 38 bits = data.split('\0')
39 39 bits = bits[:-2] + bits[-1:]
40 40 return '\0'.join(bits)
41 41
42 42 class mergestate(object):
43 43 '''track 3-way merge state of individual files
44 44
45 45 it is stored on disk when needed. Two file are used, one with an old
46 46 format, one with a new format. Both contains similar data, but the new
47 47 format can store new kinds of field.
48 48
49 49 Current new format is a list of arbitrary record of the form:
50 50
51 51 [type][length][content]
52 52
53 53 Type is a single character, length is a 4 bytes integer, content is an
54 54 arbitrary suites of bytes of length `length`.
55 55
56 56 Type should be a letter. Capital letter are mandatory record, Mercurial
57 57 should abort if they are unknown. lower case record can be safely ignored.
58 58
59 59 Currently known record:
60 60
61 61 L: the node of the "local" part of the merge (hexified version)
62 62 O: the node of the "other" part of the merge (hexified version)
63 63 F: a file to be merged entry
64 64 '''
65 65 statepathv1 = 'merge/state'
66 66 statepathv2 = 'merge/state2'
67 67
68 68 def __init__(self, repo):
69 69 self._repo = repo
70 70 self._dirty = False
71 71 self._read()
72 72
73 73 def reset(self, node=None, other=None):
74 74 self._state = {}
75 75 self._local = None
76 76 self._other = None
77 77 if node:
78 78 self._local = node
79 79 self._other = other
80 80 shutil.rmtree(self._repo.join('merge'), True)
81 81 self._dirty = False
82 82
83 83 def _read(self):
84 84 """Analyse each record content to restore a serialized state from disk
85 85
86 86 This function process "record" entry produced by the de-serialization
87 87 of on disk file.
88 88 """
89 89 self._state = {}
90 90 self._local = None
91 91 self._other = None
92 92 records = self._readrecords()
93 93 for rtype, record in records:
94 94 if rtype == 'L':
95 95 self._local = bin(record)
96 96 elif rtype == 'O':
97 97 self._other = bin(record)
98 98 elif rtype == 'F':
99 99 bits = record.split('\0')
100 100 self._state[bits[0]] = bits[1:]
101 101 elif not rtype.islower():
102 102 raise error.Abort(_('unsupported merge state record: %s')
103 103 % rtype)
104 104 self._dirty = False
105 105
106 106 def _readrecords(self):
107 107 """Read merge state from disk and return a list of record (TYPE, data)
108 108
109 109 We read data from both v1 and v2 files and decide which one to use.
110 110
111 111 V1 has been used by version prior to 2.9.1 and contains less data than
112 112 v2. We read both versions and check if no data in v2 contradicts
113 113 v1. If there is not contradiction we can safely assume that both v1
114 114 and v2 were written at the same time and use the extract data in v2. If
115 115 there is contradiction we ignore v2 content as we assume an old version
116 116 of Mercurial has overwritten the mergestate file and left an old v2
117 117 file around.
118 118
119 119 returns list of record [(TYPE, data), ...]"""
120 120 v1records = self._readrecordsv1()
121 121 v2records = self._readrecordsv2()
122 122 if self._v1v2match(v1records, v2records):
123 123 return v2records
124 124 else:
125 125 # v1 file is newer than v2 file, use it
126 126 # we have to infer the "other" changeset of the merge
127 127 # we cannot do better than that with v1 of the format
128 128 mctx = self._repo[None].parents()[-1]
129 129 v1records.append(('O', mctx.hex()))
130 130 # add place holder "other" file node information
131 131 # nobody is using it yet so we do no need to fetch the data
132 132 # if mctx was wrong `mctx[bits[-2]]` may fails.
133 133 for idx, r in enumerate(v1records):
134 134 if r[0] == 'F':
135 135 bits = r[1].split('\0')
136 136 bits.insert(-2, '')
137 137 v1records[idx] = (r[0], '\0'.join(bits))
138 138 return v1records
139 139
140 140 def _v1v2match(self, v1records, v2records):
141 141 oldv2 = set() # old format version of v2 record
142 142 for rec in v2records:
143 143 if rec[0] == 'L':
144 144 oldv2.add(rec)
145 145 elif rec[0] == 'F':
146 146 # drop the onode data (not contained in v1)
147 147 oldv2.add(('F', _droponode(rec[1])))
148 148 for rec in v1records:
149 149 if rec not in oldv2:
150 150 return False
151 151 else:
152 152 return True
153 153
154 154 def _readrecordsv1(self):
155 155 """read on disk merge state for version 1 file
156 156
157 157 returns list of record [(TYPE, data), ...]
158 158
159 159 Note: the "F" data from this file are one entry short
160 160 (no "other file node" entry)
161 161 """
162 162 records = []
163 163 try:
164 164 f = self._repo.vfs(self.statepathv1)
165 165 for i, l in enumerate(f):
166 166 if i == 0:
167 167 records.append(('L', l[:-1]))
168 168 else:
169 169 records.append(('F', l[:-1]))
170 170 f.close()
171 171 except IOError as err:
172 172 if err.errno != errno.ENOENT:
173 173 raise
174 174 return records
175 175
176 176 def _readrecordsv2(self):
177 177 """read on disk merge state for version 2 file
178 178
179 179 returns list of record [(TYPE, data), ...]
180 180 """
181 181 records = []
182 182 try:
183 183 f = self._repo.vfs(self.statepathv2)
184 184 data = f.read()
185 185 off = 0
186 186 end = len(data)
187 187 while off < end:
188 188 rtype = data[off]
189 189 off += 1
190 190 length = _unpack('>I', data[off:(off + 4)])[0]
191 191 off += 4
192 192 record = data[off:(off + length)]
193 193 off += length
194 194 records.append((rtype, record))
195 195 f.close()
196 196 except IOError as err:
197 197 if err.errno != errno.ENOENT:
198 198 raise
199 199 return records
200 200
201 201 def active(self):
202 202 """Whether mergestate is active.
203 203
204 204 Returns True if there appears to be mergestate. This is a rough proxy
205 205 for "is a merge in progress."
206 206 """
207 207 # Check local variables before looking at filesystem for performance
208 208 # reasons.
209 209 return bool(self._local) or bool(self._state) or \
210 210 self._repo.vfs.exists(self.statepathv1) or \
211 211 self._repo.vfs.exists(self.statepathv2)
212 212
213 213 def commit(self):
214 214 """Write current state on disk (if necessary)"""
215 215 if self._dirty:
216 216 records = []
217 217 records.append(('L', hex(self._local)))
218 218 records.append(('O', hex(self._other)))
219 219 for d, v in self._state.iteritems():
220 220 records.append(('F', '\0'.join([d] + v)))
221 221 self._writerecords(records)
222 222 self._dirty = False
223 223
224 224 def _writerecords(self, records):
225 225 """Write current state on disk (both v1 and v2)"""
226 226 self._writerecordsv1(records)
227 227 self._writerecordsv2(records)
228 228
229 229 def _writerecordsv1(self, records):
230 230 """Write current state on disk in a version 1 file"""
231 231 f = self._repo.vfs(self.statepathv1, 'w')
232 232 irecords = iter(records)
233 233 lrecords = irecords.next()
234 234 assert lrecords[0] == 'L'
235 235 f.write(hex(self._local) + '\n')
236 236 for rtype, data in irecords:
237 237 if rtype == 'F':
238 238 f.write('%s\n' % _droponode(data))
239 239 f.close()
240 240
241 241 def _writerecordsv2(self, records):
242 242 """Write current state on disk in a version 2 file"""
243 243 f = self._repo.vfs(self.statepathv2, 'w')
244 244 for key, data in records:
245 245 assert len(key) == 1
246 246 format = '>sI%is' % len(data)
247 247 f.write(_pack(format, key, len(data), data))
248 248 f.close()
249 249
250 250 def add(self, fcl, fco, fca, fd):
251 251 """add a new (potentially?) conflicting file the merge state
252 252 fcl: file context for local,
253 253 fco: file context for remote,
254 254 fca: file context for ancestors,
255 255 fd: file path of the resulting merge.
256 256
257 257 note: also write the local version to the `.hg/merge` directory.
258 258 """
259 259 hash = util.sha1(fcl.path()).hexdigest()
260 260 self._repo.vfs.write('merge/' + hash, fcl.data())
261 261 self._state[fd] = ['u', hash, fcl.path(),
262 262 fca.path(), hex(fca.filenode()),
263 263 fco.path(), hex(fco.filenode()),
264 264 fcl.flags()]
265 265 self._dirty = True
266 266
267 267 def __contains__(self, dfile):
268 268 return dfile in self._state
269 269
270 270 def __getitem__(self, dfile):
271 271 return self._state[dfile][0]
272 272
273 273 def __iter__(self):
274 274 return iter(sorted(self._state))
275 275
276 276 def files(self):
277 277 return self._state.keys()
278 278
279 279 def mark(self, dfile, state):
280 280 self._state[dfile][0] = state
281 281 self._dirty = True
282 282
283 283 def unresolved(self):
284 284 """Obtain the paths of unresolved files."""
285 285
286 286 for f, entry in self._state.items():
287 287 if entry[0] == 'u':
288 288 yield f
289 289
290 290 def resolve(self, dfile, wctx, labels=None):
291 291 """rerun merge process for file path `dfile`"""
292 292 if self[dfile] == 'r':
293 293 return 0
294 294 stateentry = self._state[dfile]
295 295 state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
296 296 octx = self._repo[self._other]
297 297 fcd = wctx[dfile]
298 298 fco = octx[ofile]
299 299 fca = self._repo.filectx(afile, fileid=anode)
300 300 # "premerge" x flags
301 301 flo = fco.flags()
302 302 fla = fca.flags()
303 303 if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
304 304 if fca.node() == nullid:
305 305 self._repo.ui.warn(_('warning: cannot merge flags for %s\n') %
306 306 afile)
307 307 elif flags == fla:
308 308 flags = flo
309 309 # restore local
310 310 f = self._repo.vfs('merge/' + hash)
311 311 self._repo.wwrite(dfile, f.read(), flags)
312 312 f.close()
313 complete, r = filemerge.filemerge(self._repo, self._local, lfile, fcd,
314 fco, fca, labels=labels)
313 complete, r = filemerge.premerge(self._repo, self._local, lfile, fcd,
314 fco, fca, labels=labels)
315 if not complete:
316 complete, r = filemerge.filemerge(self._repo, self._local, lfile,
317 fcd, fco, fca, labels=labels)
315 318 if r is None:
316 319 # no real conflict
317 320 del self._state[dfile]
318 321 self._dirty = True
319 322 elif not r:
320 323 self.mark(dfile, 'r')
321 324 return r
322 325
323 326 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
324 327 if f2 is None:
325 328 f2 = f
326 329 return (os.path.isfile(repo.wjoin(f))
327 330 and repo.wvfs.audit.check(f)
328 331 and repo.dirstate.normalize(f) not in repo.dirstate
329 332 and mctx[f2].cmp(wctx[f]))
330 333
331 334 def _checkunknownfiles(repo, wctx, mctx, force, actions):
332 335 """
333 336 Considers any actions that care about the presence of conflicting unknown
334 337 files. For some actions, the result is to abort; for others, it is to
335 338 choose a different action.
336 339 """
337 340 aborts = []
338 341 if not force:
339 342 for f, (m, args, msg) in actions.iteritems():
340 343 if m in ('c', 'dc'):
341 344 if _checkunknownfile(repo, wctx, mctx, f):
342 345 aborts.append(f)
343 346 elif m == 'dg':
344 347 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
345 348 aborts.append(f)
346 349
347 350 for f in sorted(aborts):
348 351 repo.ui.warn(_("%s: untracked file differs\n") % f)
349 352 if aborts:
350 353 raise error.Abort(_("untracked files in working directory differ "
351 354 "from files in requested revision"))
352 355
353 356 for f, (m, args, msg) in actions.iteritems():
354 357 if m == 'c':
355 358 actions[f] = ('g', args, msg)
356 359 elif m == 'cm':
357 360 fl2, anc = args
358 361 different = _checkunknownfile(repo, wctx, mctx, f)
359 362 if different:
360 363 actions[f] = ('m', (f, f, None, False, anc),
361 364 "remote differs from untracked local")
362 365 else:
363 366 actions[f] = ('g', (fl2,), "remote created")
364 367
365 368 def _forgetremoved(wctx, mctx, branchmerge):
366 369 """
367 370 Forget removed files
368 371
369 372 If we're jumping between revisions (as opposed to merging), and if
370 373 neither the working directory nor the target rev has the file,
371 374 then we need to remove it from the dirstate, to prevent the
372 375 dirstate from listing the file when it is no longer in the
373 376 manifest.
374 377
375 378 If we're merging, and the other revision has removed a file
376 379 that is not present in the working directory, we need to mark it
377 380 as removed.
378 381 """
379 382
380 383 actions = {}
381 384 m = 'f'
382 385 if branchmerge:
383 386 m = 'r'
384 387 for f in wctx.deleted():
385 388 if f not in mctx:
386 389 actions[f] = m, None, "forget deleted"
387 390
388 391 if not branchmerge:
389 392 for f in wctx.removed():
390 393 if f not in mctx:
391 394 actions[f] = 'f', None, "forget removed"
392 395
393 396 return actions
394 397
395 398 def _checkcollision(repo, wmf, actions):
396 399 # build provisional merged manifest up
397 400 pmmf = set(wmf)
398 401
399 402 if actions:
400 403 # k, dr, e and rd are no-op
401 404 for m in 'a', 'f', 'g', 'cd', 'dc':
402 405 for f, args, msg in actions[m]:
403 406 pmmf.add(f)
404 407 for f, args, msg in actions['r']:
405 408 pmmf.discard(f)
406 409 for f, args, msg in actions['dm']:
407 410 f2, flags = args
408 411 pmmf.discard(f2)
409 412 pmmf.add(f)
410 413 for f, args, msg in actions['dg']:
411 414 pmmf.add(f)
412 415 for f, args, msg in actions['m']:
413 416 f1, f2, fa, move, anc = args
414 417 if move:
415 418 pmmf.discard(f1)
416 419 pmmf.add(f)
417 420
418 421 # check case-folding collision in provisional merged manifest
419 422 foldmap = {}
420 423 for f in sorted(pmmf):
421 424 fold = util.normcase(f)
422 425 if fold in foldmap:
423 426 raise error.Abort(_("case-folding collision between %s and %s")
424 427 % (f, foldmap[fold]))
425 428 foldmap[fold] = f
426 429
427 430 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
428 431 acceptremote, followcopies):
429 432 """
430 433 Merge p1 and p2 with ancestor pa and generate merge action list
431 434
432 435 branchmerge and force are as passed in to update
433 436 partial = function to filter file lists
434 437 acceptremote = accept the incoming changes without prompting
435 438 """
436 439
437 440 copy, movewithdir, diverge, renamedelete = {}, {}, {}, {}
438 441
439 442 # manifests fetched in order are going to be faster, so prime the caches
440 443 [x.manifest() for x in
441 444 sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
442 445
443 446 if followcopies:
444 447 ret = copies.mergecopies(repo, wctx, p2, pa)
445 448 copy, movewithdir, diverge, renamedelete = ret
446 449
447 450 repo.ui.note(_("resolving manifests\n"))
448 451 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
449 452 % (bool(branchmerge), bool(force), bool(partial)))
450 453 repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
451 454
452 455 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
453 456 copied = set(copy.values())
454 457 copied.update(movewithdir.values())
455 458
456 459 if '.hgsubstate' in m1:
457 460 # check whether sub state is modified
458 461 for s in sorted(wctx.substate):
459 462 if wctx.sub(s).dirty():
460 463 m1['.hgsubstate'] += '+'
461 464 break
462 465
463 466 # Compare manifests
464 467 diff = m1.diff(m2)
465 468
466 469 actions = {}
467 470 for f, ((n1, fl1), (n2, fl2)) in diff.iteritems():
468 471 if partial and not partial(f):
469 472 continue
470 473 if n1 and n2: # file exists on both local and remote side
471 474 if f not in ma:
472 475 fa = copy.get(f, None)
473 476 if fa is not None:
474 477 actions[f] = ('m', (f, f, fa, False, pa.node()),
475 478 "both renamed from " + fa)
476 479 else:
477 480 actions[f] = ('m', (f, f, None, False, pa.node()),
478 481 "both created")
479 482 else:
480 483 a = ma[f]
481 484 fla = ma.flags(f)
482 485 nol = 'l' not in fl1 + fl2 + fla
483 486 if n2 == a and fl2 == fla:
484 487 actions[f] = ('k' , (), "remote unchanged")
485 488 elif n1 == a and fl1 == fla: # local unchanged - use remote
486 489 if n1 == n2: # optimization: keep local content
487 490 actions[f] = ('e', (fl2,), "update permissions")
488 491 else:
489 492 actions[f] = ('g', (fl2,), "remote is newer")
490 493 elif nol and n2 == a: # remote only changed 'x'
491 494 actions[f] = ('e', (fl2,), "update permissions")
492 495 elif nol and n1 == a: # local only changed 'x'
493 496 actions[f] = ('g', (fl1,), "remote is newer")
494 497 else: # both changed something
495 498 actions[f] = ('m', (f, f, f, False, pa.node()),
496 499 "versions differ")
497 500 elif n1: # file exists only on local side
498 501 if f in copied:
499 502 pass # we'll deal with it on m2 side
500 503 elif f in movewithdir: # directory rename, move local
501 504 f2 = movewithdir[f]
502 505 if f2 in m2:
503 506 actions[f2] = ('m', (f, f2, None, True, pa.node()),
504 507 "remote directory rename, both created")
505 508 else:
506 509 actions[f2] = ('dm', (f, fl1),
507 510 "remote directory rename - move from " + f)
508 511 elif f in copy:
509 512 f2 = copy[f]
510 513 actions[f] = ('m', (f, f2, f2, False, pa.node()),
511 514 "local copied/moved from " + f2)
512 515 elif f in ma: # clean, a different, no remote
513 516 if n1 != ma[f]:
514 517 if acceptremote:
515 518 actions[f] = ('r', None, "remote delete")
516 519 else:
517 520 actions[f] = ('cd', None, "prompt changed/deleted")
518 521 elif n1[20:] == 'a':
519 522 # This extra 'a' is added by working copy manifest to mark
520 523 # the file as locally added. We should forget it instead of
521 524 # deleting it.
522 525 actions[f] = ('f', None, "remote deleted")
523 526 else:
524 527 actions[f] = ('r', None, "other deleted")
525 528 elif n2: # file exists only on remote side
526 529 if f in copied:
527 530 pass # we'll deal with it on m1 side
528 531 elif f in movewithdir:
529 532 f2 = movewithdir[f]
530 533 if f2 in m1:
531 534 actions[f2] = ('m', (f2, f, None, False, pa.node()),
532 535 "local directory rename, both created")
533 536 else:
534 537 actions[f2] = ('dg', (f, fl2),
535 538 "local directory rename - get from " + f)
536 539 elif f in copy:
537 540 f2 = copy[f]
538 541 if f2 in m2:
539 542 actions[f] = ('m', (f2, f, f2, False, pa.node()),
540 543 "remote copied from " + f2)
541 544 else:
542 545 actions[f] = ('m', (f2, f, f2, True, pa.node()),
543 546 "remote moved from " + f2)
544 547 elif f not in ma:
545 548 # local unknown, remote created: the logic is described by the
546 549 # following table:
547 550 #
548 551 # force branchmerge different | action
549 552 # n * * | create
550 553 # y n * | create
551 554 # y y n | create
552 555 # y y y | merge
553 556 #
554 557 # Checking whether the files are different is expensive, so we
555 558 # don't do that when we can avoid it.
556 559 if not force:
557 560 actions[f] = ('c', (fl2,), "remote created")
558 561 elif not branchmerge:
559 562 actions[f] = ('c', (fl2,), "remote created")
560 563 else:
561 564 actions[f] = ('cm', (fl2, pa.node()),
562 565 "remote created, get or merge")
563 566 elif n2 != ma[f]:
564 567 if acceptremote:
565 568 actions[f] = ('c', (fl2,), "remote recreating")
566 569 else:
567 570 actions[f] = ('dc', (fl2,), "prompt deleted/changed")
568 571
569 572 return actions, diverge, renamedelete
570 573
571 574 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
572 575 """Resolves false conflicts where the nodeid changed but the content
573 576 remained the same."""
574 577
575 578 for f, (m, args, msg) in actions.items():
576 579 if m == 'cd' and f in ancestor and not wctx[f].cmp(ancestor[f]):
577 580 # local did change but ended up with same content
578 581 actions[f] = 'r', None, "prompt same"
579 582 elif m == 'dc' and f in ancestor and not mctx[f].cmp(ancestor[f]):
580 583 # remote did change but ended up with same content
581 584 del actions[f] # don't get = keep local deleted
582 585
583 586 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force, partial,
584 587 acceptremote, followcopies):
585 588 "Calculate the actions needed to merge mctx into wctx using ancestors"
586 589
587 590 if len(ancestors) == 1: # default
588 591 actions, diverge, renamedelete = manifestmerge(
589 592 repo, wctx, mctx, ancestors[0], branchmerge, force, partial,
590 593 acceptremote, followcopies)
591 594 _checkunknownfiles(repo, wctx, mctx, force, actions)
592 595
593 596 else: # only when merge.preferancestor=* - the default
594 597 repo.ui.note(
595 598 _("note: merging %s and %s using bids from ancestors %s\n") %
596 599 (wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
597 600
598 601 # Call for bids
599 602 fbids = {} # mapping filename to bids (action method to list af actions)
600 603 diverge, renamedelete = None, None
601 604 for ancestor in ancestors:
602 605 repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
603 606 actions, diverge1, renamedelete1 = manifestmerge(
604 607 repo, wctx, mctx, ancestor, branchmerge, force, partial,
605 608 acceptremote, followcopies)
606 609 _checkunknownfiles(repo, wctx, mctx, force, actions)
607 610
608 611 # Track the shortest set of warning on the theory that bid
609 612 # merge will correctly incorporate more information
610 613 if diverge is None or len(diverge1) < len(diverge):
611 614 diverge = diverge1
612 615 if renamedelete is None or len(renamedelete) < len(renamedelete1):
613 616 renamedelete = renamedelete1
614 617
615 618 for f, a in sorted(actions.iteritems()):
616 619 m, args, msg = a
617 620 repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
618 621 if f in fbids:
619 622 d = fbids[f]
620 623 if m in d:
621 624 d[m].append(a)
622 625 else:
623 626 d[m] = [a]
624 627 else:
625 628 fbids[f] = {m: [a]}
626 629
627 630 # Pick the best bid for each file
628 631 repo.ui.note(_('\nauction for merging merge bids\n'))
629 632 actions = {}
630 633 for f, bids in sorted(fbids.items()):
631 634 # bids is a mapping from action method to list af actions
632 635 # Consensus?
633 636 if len(bids) == 1: # all bids are the same kind of method
634 637 m, l = bids.items()[0]
635 638 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
636 639 repo.ui.note(" %s: consensus for %s\n" % (f, m))
637 640 actions[f] = l[0]
638 641 continue
639 642 # If keep is an option, just do it.
640 643 if 'k' in bids:
641 644 repo.ui.note(" %s: picking 'keep' action\n" % f)
642 645 actions[f] = bids['k'][0]
643 646 continue
644 647 # If there are gets and they all agree [how could they not?], do it.
645 648 if 'g' in bids:
646 649 ga0 = bids['g'][0]
647 650 if all(a == ga0 for a in bids['g'][1:]):
648 651 repo.ui.note(" %s: picking 'get' action\n" % f)
649 652 actions[f] = ga0
650 653 continue
651 654 # TODO: Consider other simple actions such as mode changes
652 655 # Handle inefficient democrazy.
653 656 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
654 657 for m, l in sorted(bids.items()):
655 658 for _f, args, msg in l:
656 659 repo.ui.note(' %s -> %s\n' % (msg, m))
657 660 # Pick random action. TODO: Instead, prompt user when resolving
658 661 m, l = bids.items()[0]
659 662 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
660 663 (f, m))
661 664 actions[f] = l[0]
662 665 continue
663 666 repo.ui.note(_('end of auction\n\n'))
664 667
665 668 _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
666 669
667 670 if wctx.rev() is None:
668 671 fractions = _forgetremoved(wctx, mctx, branchmerge)
669 672 actions.update(fractions)
670 673
671 674 return actions, diverge, renamedelete
672 675
673 676 def batchremove(repo, actions):
674 677 """apply removes to the working directory
675 678
676 679 yields tuples for progress updates
677 680 """
678 681 verbose = repo.ui.verbose
679 682 unlink = util.unlinkpath
680 683 wjoin = repo.wjoin
681 684 audit = repo.wvfs.audit
682 685 i = 0
683 686 for f, args, msg in actions:
684 687 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
685 688 if verbose:
686 689 repo.ui.note(_("removing %s\n") % f)
687 690 audit(f)
688 691 try:
689 692 unlink(wjoin(f), ignoremissing=True)
690 693 except OSError as inst:
691 694 repo.ui.warn(_("update failed to remove %s: %s!\n") %
692 695 (f, inst.strerror))
693 696 if i == 100:
694 697 yield i, f
695 698 i = 0
696 699 i += 1
697 700 if i > 0:
698 701 yield i, f
699 702
700 703 def batchget(repo, mctx, actions):
701 704 """apply gets to the working directory
702 705
703 706 mctx is the context to get from
704 707
705 708 yields tuples for progress updates
706 709 """
707 710 verbose = repo.ui.verbose
708 711 fctx = mctx.filectx
709 712 wwrite = repo.wwrite
710 713 i = 0
711 714 for f, args, msg in actions:
712 715 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
713 716 if verbose:
714 717 repo.ui.note(_("getting %s\n") % f)
715 718 wwrite(f, fctx(f).data(), args[0])
716 719 if i == 100:
717 720 yield i, f
718 721 i = 0
719 722 i += 1
720 723 if i > 0:
721 724 yield i, f
722 725
723 726 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
724 727 """apply the merge action list to the working directory
725 728
726 729 wctx is the working copy context
727 730 mctx is the context to be merged into the working copy
728 731
729 732 Return a tuple of counts (updated, merged, removed, unresolved) that
730 733 describes how many files were affected by the update.
731 734 """
732 735
733 736 updated, merged, removed, unresolved = 0, 0, 0, 0
734 737 ms = mergestate(repo)
735 738 ms.reset(wctx.p1().node(), mctx.node())
736 739 moves = []
737 740 for m, l in actions.items():
738 741 l.sort()
739 742
740 743 # prescan for merges
741 744 for f, args, msg in actions['m']:
742 745 f1, f2, fa, move, anc = args
743 746 if f == '.hgsubstate': # merged internally
744 747 continue
745 748 repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
746 749 fcl = wctx[f1]
747 750 fco = mctx[f2]
748 751 actx = repo[anc]
749 752 if fa in actx:
750 753 fca = actx[fa]
751 754 else:
752 755 fca = repo.filectx(f1, fileid=nullrev)
753 756 ms.add(fcl, fco, fca, f)
754 757 if f1 != f and move:
755 758 moves.append(f1)
756 759
757 760 audit = repo.wvfs.audit
758 761 _updating = _('updating')
759 762 _files = _('files')
760 763 progress = repo.ui.progress
761 764
762 765 # remove renamed files after safely stored
763 766 for f in moves:
764 767 if os.path.lexists(repo.wjoin(f)):
765 768 repo.ui.debug("removing %s\n" % f)
766 769 audit(f)
767 770 util.unlinkpath(repo.wjoin(f))
768 771
769 772 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
770 773
771 774 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
772 775 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
773 776
774 777 # remove in parallel (must come first)
775 778 z = 0
776 779 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
777 780 for i, item in prog:
778 781 z += i
779 782 progress(_updating, z, item=item, total=numupdates, unit=_files)
780 783 removed = len(actions['r'])
781 784
782 785 # get in parallel
783 786 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
784 787 for i, item in prog:
785 788 z += i
786 789 progress(_updating, z, item=item, total=numupdates, unit=_files)
787 790 updated = len(actions['g'])
788 791
789 792 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
790 793 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
791 794
792 795 # forget (manifest only, just log it) (must come first)
793 796 for f, args, msg in actions['f']:
794 797 repo.ui.debug(" %s: %s -> f\n" % (f, msg))
795 798 z += 1
796 799 progress(_updating, z, item=f, total=numupdates, unit=_files)
797 800
798 801 # re-add (manifest only, just log it)
799 802 for f, args, msg in actions['a']:
800 803 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
801 804 z += 1
802 805 progress(_updating, z, item=f, total=numupdates, unit=_files)
803 806
804 807 # keep (noop, just log it)
805 808 for f, args, msg in actions['k']:
806 809 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
807 810 # no progress
808 811
809 812 # directory rename, move local
810 813 for f, args, msg in actions['dm']:
811 814 repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
812 815 z += 1
813 816 progress(_updating, z, item=f, total=numupdates, unit=_files)
814 817 f0, flags = args
815 818 repo.ui.note(_("moving %s to %s\n") % (f0, f))
816 819 audit(f)
817 820 repo.wwrite(f, wctx.filectx(f0).data(), flags)
818 821 util.unlinkpath(repo.wjoin(f0))
819 822 updated += 1
820 823
821 824 # local directory rename, get
822 825 for f, args, msg in actions['dg']:
823 826 repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
824 827 z += 1
825 828 progress(_updating, z, item=f, total=numupdates, unit=_files)
826 829 f0, flags = args
827 830 repo.ui.note(_("getting %s to %s\n") % (f0, f))
828 831 repo.wwrite(f, mctx.filectx(f0).data(), flags)
829 832 updated += 1
830 833
831 834 # exec
832 835 for f, args, msg in actions['e']:
833 836 repo.ui.debug(" %s: %s -> e\n" % (f, msg))
834 837 z += 1
835 838 progress(_updating, z, item=f, total=numupdates, unit=_files)
836 839 flags, = args
837 840 audit(f)
838 841 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
839 842 updated += 1
840 843
841 844 # merge
842 845 for f, args, msg in actions['m']:
843 846 repo.ui.debug(" %s: %s -> m\n" % (f, msg))
844 847 z += 1
845 848 progress(_updating, z, item=f, total=numupdates, unit=_files)
846 849 if f == '.hgsubstate': # subrepo states need updating
847 850 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
848 851 overwrite)
849 852 continue
850 853 audit(f)
851 854 r = ms.resolve(f, wctx, labels=labels)
852 855 if r is not None and r > 0:
853 856 unresolved += 1
854 857 else:
855 858 if r is None:
856 859 updated += 1
857 860 else:
858 861 merged += 1
859 862
860 863 ms.commit()
861 864 progress(_updating, None, total=numupdates, unit=_files)
862 865
863 866 return updated, merged, removed, unresolved
864 867
865 868 def recordupdates(repo, actions, branchmerge):
866 869 "record merge actions to the dirstate"
867 870 # remove (must come first)
868 871 for f, args, msg in actions['r']:
869 872 if branchmerge:
870 873 repo.dirstate.remove(f)
871 874 else:
872 875 repo.dirstate.drop(f)
873 876
874 877 # forget (must come first)
875 878 for f, args, msg in actions['f']:
876 879 repo.dirstate.drop(f)
877 880
878 881 # re-add
879 882 for f, args, msg in actions['a']:
880 883 if not branchmerge:
881 884 repo.dirstate.add(f)
882 885
883 886 # exec change
884 887 for f, args, msg in actions['e']:
885 888 repo.dirstate.normallookup(f)
886 889
887 890 # keep
888 891 for f, args, msg in actions['k']:
889 892 pass
890 893
891 894 # get
892 895 for f, args, msg in actions['g']:
893 896 if branchmerge:
894 897 repo.dirstate.otherparent(f)
895 898 else:
896 899 repo.dirstate.normal(f)
897 900
898 901 # merge
899 902 for f, args, msg in actions['m']:
900 903 f1, f2, fa, move, anc = args
901 904 if branchmerge:
902 905 # We've done a branch merge, mark this file as merged
903 906 # so that we properly record the merger later
904 907 repo.dirstate.merge(f)
905 908 if f1 != f2: # copy/rename
906 909 if move:
907 910 repo.dirstate.remove(f1)
908 911 if f1 != f:
909 912 repo.dirstate.copy(f1, f)
910 913 else:
911 914 repo.dirstate.copy(f2, f)
912 915 else:
913 916 # We've update-merged a locally modified file, so
914 917 # we set the dirstate to emulate a normal checkout
915 918 # of that file some time in the past. Thus our
916 919 # merge will appear as a normal local file
917 920 # modification.
918 921 if f2 == f: # file not locally copied/moved
919 922 repo.dirstate.normallookup(f)
920 923 if move:
921 924 repo.dirstate.drop(f1)
922 925
923 926 # directory rename, move local
924 927 for f, args, msg in actions['dm']:
925 928 f0, flag = args
926 929 if branchmerge:
927 930 repo.dirstate.add(f)
928 931 repo.dirstate.remove(f0)
929 932 repo.dirstate.copy(f0, f)
930 933 else:
931 934 repo.dirstate.normal(f)
932 935 repo.dirstate.drop(f0)
933 936
934 937 # directory rename, get
935 938 for f, args, msg in actions['dg']:
936 939 f0, flag = args
937 940 if branchmerge:
938 941 repo.dirstate.add(f)
939 942 repo.dirstate.copy(f0, f)
940 943 else:
941 944 repo.dirstate.normal(f)
942 945
943 946 def update(repo, node, branchmerge, force, partial, ancestor=None,
944 947 mergeancestor=False, labels=None):
945 948 """
946 949 Perform a merge between the working directory and the given node
947 950
948 951 node = the node to update to, or None if unspecified
949 952 branchmerge = whether to merge between branches
950 953 force = whether to force branch merging or file overwriting
951 954 partial = a function to filter file lists (dirstate not updated)
952 955 mergeancestor = whether it is merging with an ancestor. If true,
953 956 we should accept the incoming changes for any prompts that occur.
954 957 If false, merging with an ancestor (fast-forward) is only allowed
955 958 between different named branches. This flag is used by rebase extension
956 959 as a temporary fix and should be avoided in general.
957 960
958 961 The table below shows all the behaviors of the update command
959 962 given the -c and -C or no options, whether the working directory
960 963 is dirty, whether a revision is specified, and the relationship of
961 964 the parent rev to the target rev (linear, on the same named
962 965 branch, or on another named branch).
963 966
964 967 This logic is tested by test-update-branches.t.
965 968
966 969 -c -C dirty rev | linear same cross
967 970 n n n n | ok (1) x
968 971 n n n y | ok ok ok
969 972 n n y n | merge (2) (2)
970 973 n n y y | merge (3) (3)
971 974 n y * * | --- discard ---
972 975 y n y * | --- (4) ---
973 976 y n n * | --- ok ---
974 977 y y * * | --- (5) ---
975 978
976 979 x = can't happen
977 980 * = don't-care
978 981 1 = abort: not a linear update (merge or update --check to force update)
979 982 2 = abort: uncommitted changes (commit and merge, or update --clean to
980 983 discard changes)
981 984 3 = abort: uncommitted changes (commit or update --clean to discard changes)
982 985 4 = abort: uncommitted changes (checked in commands.py)
983 986 5 = incompatible options (checked in commands.py)
984 987
985 988 Return the same tuple as applyupdates().
986 989 """
987 990
988 991 onode = node
989 992 wlock = repo.wlock()
990 993 try:
991 994 wc = repo[None]
992 995 pl = wc.parents()
993 996 p1 = pl[0]
994 997 pas = [None]
995 998 if ancestor is not None:
996 999 pas = [repo[ancestor]]
997 1000
998 1001 if node is None:
999 1002 node = repo[destutil.destupdate(repo)].node()
1000 1003
1001 1004 overwrite = force and not branchmerge
1002 1005
1003 1006 p2 = repo[node]
1004 1007 if pas[0] is None:
1005 1008 if repo.ui.configlist('merge', 'preferancestor', ['*']) == ['*']:
1006 1009 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
1007 1010 pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
1008 1011 else:
1009 1012 pas = [p1.ancestor(p2, warn=branchmerge)]
1010 1013
1011 1014 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
1012 1015
1013 1016 ### check phase
1014 1017 if not overwrite and len(pl) > 1:
1015 1018 raise error.Abort(_("outstanding uncommitted merge"))
1016 1019 if branchmerge:
1017 1020 if pas == [p2]:
1018 1021 raise error.Abort(_("merging with a working directory ancestor"
1019 1022 " has no effect"))
1020 1023 elif pas == [p1]:
1021 1024 if not mergeancestor and p1.branch() == p2.branch():
1022 1025 raise error.Abort(_("nothing to merge"),
1023 1026 hint=_("use 'hg update' "
1024 1027 "or check 'hg heads'"))
1025 1028 if not force and (wc.files() or wc.deleted()):
1026 1029 raise error.Abort(_("uncommitted changes"),
1027 1030 hint=_("use 'hg status' to list changes"))
1028 1031 for s in sorted(wc.substate):
1029 1032 wc.sub(s).bailifchanged()
1030 1033
1031 1034 elif not overwrite:
1032 1035 if p1 == p2: # no-op update
1033 1036 # call the hooks and exit early
1034 1037 repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
1035 1038 repo.hook('update', parent1=xp2, parent2='', error=0)
1036 1039 return 0, 0, 0, 0
1037 1040
1038 1041 if pas not in ([p1], [p2]): # nonlinear
1039 1042 dirty = wc.dirty(missing=True)
1040 1043 if dirty or onode is None:
1041 1044 # Branching is a bit strange to ensure we do the minimal
1042 1045 # amount of call to obsolete.background.
1043 1046 foreground = obsolete.foreground(repo, [p1.node()])
1044 1047 # note: the <node> variable contains a random identifier
1045 1048 if repo[node].node() in foreground:
1046 1049 pas = [p1] # allow updating to successors
1047 1050 elif dirty:
1048 1051 msg = _("uncommitted changes")
1049 1052 if onode is None:
1050 1053 hint = _("commit and merge, or update --clean to"
1051 1054 " discard changes")
1052 1055 else:
1053 1056 hint = _("commit or update --clean to discard"
1054 1057 " changes")
1055 1058 raise error.Abort(msg, hint=hint)
1056 1059 else: # node is none
1057 1060 msg = _("not a linear update")
1058 1061 hint = _("merge or update --check to force update")
1059 1062 raise error.Abort(msg, hint=hint)
1060 1063 else:
1061 1064 # Allow jumping branches if clean and specific rev given
1062 1065 pas = [p1]
1063 1066
1064 1067 # deprecated config: merge.followcopies
1065 1068 followcopies = False
1066 1069 if overwrite:
1067 1070 pas = [wc]
1068 1071 elif pas == [p2]: # backwards
1069 1072 pas = [wc.p1()]
1070 1073 elif not branchmerge and not wc.dirty(missing=True):
1071 1074 pass
1072 1075 elif pas[0] and repo.ui.configbool('merge', 'followcopies', True):
1073 1076 followcopies = True
1074 1077
1075 1078 ### calculate phase
1076 1079 actionbyfile, diverge, renamedelete = calculateupdates(
1077 1080 repo, wc, p2, pas, branchmerge, force, partial, mergeancestor,
1078 1081 followcopies)
1079 1082 # Convert to dictionary-of-lists format
1080 1083 actions = dict((m, []) for m in 'a f g cd dc r dm dg m e k'.split())
1081 1084 for f, (m, args, msg) in actionbyfile.iteritems():
1082 1085 if m not in actions:
1083 1086 actions[m] = []
1084 1087 actions[m].append((f, args, msg))
1085 1088
1086 1089 if not util.checkcase(repo.path):
1087 1090 # check collision between files only in p2 for clean update
1088 1091 if (not branchmerge and
1089 1092 (force or not wc.dirty(missing=True, branch=False))):
1090 1093 _checkcollision(repo, p2.manifest(), None)
1091 1094 else:
1092 1095 _checkcollision(repo, wc.manifest(), actions)
1093 1096
1094 1097 # Prompt and create actions. TODO: Move this towards resolve phase.
1095 1098 for f, args, msg in sorted(actions['cd']):
1096 1099 if repo.ui.promptchoice(
1097 1100 _("local changed %s which remote deleted\n"
1098 1101 "use (c)hanged version or (d)elete?"
1099 1102 "$$ &Changed $$ &Delete") % f, 0):
1100 1103 actions['r'].append((f, None, "prompt delete"))
1101 1104 else:
1102 1105 actions['a'].append((f, None, "prompt keep"))
1103 1106 del actions['cd'][:]
1104 1107
1105 1108 for f, args, msg in sorted(actions['dc']):
1106 1109 flags, = args
1107 1110 if repo.ui.promptchoice(
1108 1111 _("remote changed %s which local deleted\n"
1109 1112 "use (c)hanged version or leave (d)eleted?"
1110 1113 "$$ &Changed $$ &Deleted") % f, 0) == 0:
1111 1114 actions['g'].append((f, (flags,), "prompt recreating"))
1112 1115 del actions['dc'][:]
1113 1116
1114 1117 ### apply phase
1115 1118 if not branchmerge: # just jump to the new rev
1116 1119 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
1117 1120 if not partial:
1118 1121 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
1119 1122 # note that we're in the middle of an update
1120 1123 repo.vfs.write('updatestate', p2.hex())
1121 1124
1122 1125 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
1123 1126
1124 1127 # divergent renames
1125 1128 for f, fl in sorted(diverge.iteritems()):
1126 1129 repo.ui.warn(_("note: possible conflict - %s was renamed "
1127 1130 "multiple times to:\n") % f)
1128 1131 for nf in fl:
1129 1132 repo.ui.warn(" %s\n" % nf)
1130 1133
1131 1134 # rename and delete
1132 1135 for f, fl in sorted(renamedelete.iteritems()):
1133 1136 repo.ui.warn(_("note: possible conflict - %s was deleted "
1134 1137 "and renamed to:\n") % f)
1135 1138 for nf in fl:
1136 1139 repo.ui.warn(" %s\n" % nf)
1137 1140
1138 1141 if not partial:
1139 1142 repo.dirstate.beginparentchange()
1140 1143 repo.setparents(fp1, fp2)
1141 1144 recordupdates(repo, actions, branchmerge)
1142 1145 # update completed, clear state
1143 1146 util.unlink(repo.join('updatestate'))
1144 1147
1145 1148 if not branchmerge:
1146 1149 repo.dirstate.setbranch(p2.branch())
1147 1150 repo.dirstate.endparentchange()
1148 1151 finally:
1149 1152 wlock.release()
1150 1153
1151 1154 if not partial:
1152 1155 def updatehook(parent1=xp1, parent2=xp2, error=stats[3]):
1153 1156 repo.hook('update', parent1=parent1, parent2=parent2, error=error)
1154 1157 repo._afterlock(updatehook)
1155 1158 return stats
1156 1159
1157 1160 def graft(repo, ctx, pctx, labels):
1158 1161 """Do a graft-like merge.
1159 1162
1160 1163 This is a merge where the merge ancestor is chosen such that one
1161 1164 or more changesets are grafted onto the current changeset. In
1162 1165 addition to the merge, this fixes up the dirstate to include only
1163 1166 a single parent and tries to duplicate any renames/copies
1164 1167 appropriately.
1165 1168
1166 1169 ctx - changeset to rebase
1167 1170 pctx - merge base, usually ctx.p1()
1168 1171 labels - merge labels eg ['local', 'graft']
1169 1172
1170 1173 """
1171 1174 # If we're grafting a descendant onto an ancestor, be sure to pass
1172 1175 # mergeancestor=True to update. This does two things: 1) allows the merge if
1173 1176 # the destination is the same as the parent of the ctx (so we can use graft
1174 1177 # to copy commits), and 2) informs update that the incoming changes are
1175 1178 # newer than the destination so it doesn't prompt about "remote changed foo
1176 1179 # which local deleted".
1177 1180 mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
1178 1181
1179 1182 stats = update(repo, ctx.node(), True, True, False, pctx.node(),
1180 1183 mergeancestor=mergeancestor, labels=labels)
1181 1184
1182 1185 # drop the second merge parent
1183 1186 repo.dirstate.beginparentchange()
1184 1187 repo.setparents(repo['.'].node(), nullid)
1185 1188 repo.dirstate.write()
1186 1189 # fix up dirstate for copies and renames
1187 1190 copies.duplicatecopies(repo, ctx.rev(), pctx.rev())
1188 1191 repo.dirstate.endparentchange()
1189 1192 return stats
@@ -1,819 +1,821 b''
1 1 Create a repo with some stuff in it:
2 2
3 3 $ hg init a
4 4 $ cd a
5 5 $ echo a > a
6 6 $ echo a > d
7 7 $ echo a > e
8 8 $ hg ci -qAm0
9 9 $ echo b > a
10 10 $ hg ci -m1 -u bar
11 11 $ hg mv a b
12 12 $ hg ci -m2
13 13 $ hg cp b c
14 14 $ hg ci -m3 -u baz
15 15 $ echo b > d
16 16 $ echo f > e
17 17 $ hg ci -m4
18 18 $ hg up -q 3
19 19 $ echo b > e
20 20 $ hg branch -q stable
21 21 $ hg ci -m5
22 22 $ hg merge -q default --tool internal:local
23 23 $ hg branch -q default
24 24 $ hg ci -m6
25 25 $ hg phase --public 3
26 26 $ hg phase --force --secret 6
27 27
28 28 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
29 29 @ test@6.secret: 6
30 30 |\
31 31 | o test@5.draft: 5
32 32 | |
33 33 o | test@4.draft: 4
34 34 |/
35 35 o baz@3.public: 3
36 36 |
37 37 o test@2.public: 2
38 38 |
39 39 o bar@1.public: 1
40 40 |
41 41 o test@0.public: 0
42 42
43 43
44 44 Need to specify a rev:
45 45
46 46 $ hg graft
47 47 abort: no revisions specified
48 48 [255]
49 49
50 50 Can't graft ancestor:
51 51
52 52 $ hg graft 1 2
53 53 skipping ancestor revision 1:5d205f8b35b6
54 54 skipping ancestor revision 2:5c095ad7e90f
55 55 [255]
56 56
57 57 Specify revisions with -r:
58 58
59 59 $ hg graft -r 1 -r 2
60 60 skipping ancestor revision 1:5d205f8b35b6
61 61 skipping ancestor revision 2:5c095ad7e90f
62 62 [255]
63 63
64 64 $ hg graft -r 1 2
65 65 skipping ancestor revision 2:5c095ad7e90f
66 66 skipping ancestor revision 1:5d205f8b35b6
67 67 [255]
68 68
69 69 Can't graft with dirty wd:
70 70
71 71 $ hg up -q 0
72 72 $ echo foo > a
73 73 $ hg graft 1
74 74 abort: uncommitted changes
75 75 [255]
76 76 $ hg revert a
77 77
78 78 Graft a rename:
79 79 (this also tests that editor is invoked if '--edit' is specified)
80 80
81 81 $ hg status --rev "2^1" --rev 2
82 82 A b
83 83 R a
84 84 $ HGEDITOR=cat hg graft 2 -u foo --edit
85 85 grafting 2:5c095ad7e90f "2"
86 86 merging a and b to b
87 87 2
88 88
89 89
90 90 HG: Enter commit message. Lines beginning with 'HG:' are removed.
91 91 HG: Leave message empty to abort commit.
92 92 HG: --
93 93 HG: user: foo
94 94 HG: branch 'default'
95 95 HG: added b
96 96 HG: removed a
97 97 $ hg export tip --git
98 98 # HG changeset patch
99 99 # User foo
100 100 # Date 0 0
101 101 # Thu Jan 01 00:00:00 1970 +0000
102 102 # Node ID ef0ef43d49e79e81ddafdc7997401ba0041efc82
103 103 # Parent 68795b066622ca79a25816a662041d8f78f3cd9e
104 104 2
105 105
106 106 diff --git a/a b/b
107 107 rename from a
108 108 rename to b
109 109
110 110 Look for extra:source
111 111
112 112 $ hg log --debug -r tip
113 113 changeset: 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
114 114 tag: tip
115 115 phase: draft
116 116 parent: 0:68795b066622ca79a25816a662041d8f78f3cd9e
117 117 parent: -1:0000000000000000000000000000000000000000
118 118 manifest: 7:e59b6b228f9cbf9903d5e9abf996e083a1f533eb
119 119 user: foo
120 120 date: Thu Jan 01 00:00:00 1970 +0000
121 121 files+: b
122 122 files-: a
123 123 extra: branch=default
124 124 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
125 125 description:
126 126 2
127 127
128 128
129 129
130 130 Graft out of order, skipping a merge and a duplicate
131 131 (this also tests that editor is not invoked if '--edit' is not specified)
132 132
133 133 $ hg graft 1 5 4 3 'merge()' 2 -n
134 134 skipping ungraftable merge revision 6
135 135 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
136 136 grafting 1:5d205f8b35b6 "1"
137 137 grafting 5:97f8bfe72746 "5"
138 138 grafting 4:9c233e8e184d "4"
139 139 grafting 3:4c60f11aa304 "3"
140 140
141 141 $ HGEDITOR=cat hg graft 1 5 4 3 'merge()' 2 --debug
142 142 skipping ungraftable merge revision 6
143 143 scanning for duplicate grafts
144 144 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
145 145 grafting 1:5d205f8b35b6 "1"
146 146 searching for copies back to rev 1
147 147 unmatched files in local:
148 148 b
149 149 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
150 150 src: 'a' -> dst: 'b' *
151 151 checking for directory renames
152 152 resolving manifests
153 153 branchmerge: True, force: True, partial: False
154 154 ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
155 155 preserving b for resolve of b
156 156 b: local copied/moved from a -> m
157 157 picked tool ':merge' for b (binary False symlink False)
158 158 merging b and a to b
159 159 my b@ef0ef43d49e7+ other a@5d205f8b35b6 ancestor a@68795b066622
160 160 premerge successful
161 161 committing files:
162 162 b
163 163 committing manifest
164 164 committing changelog
165 165 grafting 5:97f8bfe72746 "5"
166 166 searching for copies back to rev 1
167 167 resolving manifests
168 168 branchmerge: True, force: True, partial: False
169 169 ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
170 170 e: remote is newer -> g
171 171 getting e
172 172 b: remote unchanged -> k
173 173 committing files:
174 174 e
175 175 committing manifest
176 176 committing changelog
177 177 grafting 4:9c233e8e184d "4"
178 178 searching for copies back to rev 1
179 179 resolving manifests
180 180 branchmerge: True, force: True, partial: False
181 181 ancestor: 4c60f11aa304, local: 1905859650ec+, remote: 9c233e8e184d
182 182 preserving e for resolve of e
183 183 d: remote is newer -> g
184 184 getting d
185 185 b: remote unchanged -> k
186 186 e: versions differ -> m
187 187 picked tool ':merge' for e (binary False symlink False)
188 188 merging e
189 189 my e@1905859650ec+ other e@9c233e8e184d ancestor e@68795b066622
190 picked tool ':merge' for e (binary False symlink False)
191 my e@1905859650ec+ other e@9c233e8e184d ancestor e@68795b066622
190 192 warning: conflicts during merge.
191 193 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
192 194 abort: unresolved conflicts, can't continue
193 195 (use hg resolve and hg graft --continue)
194 196 [255]
195 197
196 198 Commit while interrupted should fail:
197 199
198 200 $ hg ci -m 'commit interrupted graft'
199 201 abort: graft in progress
200 202 (use 'hg graft --continue' or 'hg update' to abort)
201 203 [255]
202 204
203 205 Abort the graft and try committing:
204 206
205 207 $ hg up -C .
206 208 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 209 $ echo c >> e
208 210 $ hg ci -mtest
209 211
210 212 $ hg strip . --config extensions.strip=
211 213 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
212 214 saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
213 215
214 216 Graft again:
215 217
216 218 $ hg graft 1 5 4 3 'merge()' 2
217 219 skipping ungraftable merge revision 6
218 220 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
219 221 skipping revision 1:5d205f8b35b6 (already grafted to 8:6b9e5368ca4e)
220 222 skipping revision 5:97f8bfe72746 (already grafted to 9:1905859650ec)
221 223 grafting 4:9c233e8e184d "4"
222 224 merging e
223 225 warning: conflicts during merge.
224 226 merging e incomplete! (edit conflicts, then use 'hg resolve --mark')
225 227 abort: unresolved conflicts, can't continue
226 228 (use hg resolve and hg graft --continue)
227 229 [255]
228 230
229 231 Continue without resolve should fail:
230 232
231 233 $ hg graft -c
232 234 grafting 4:9c233e8e184d "4"
233 235 abort: unresolved merge conflicts (see "hg help resolve")
234 236 [255]
235 237
236 238 Fix up:
237 239
238 240 $ echo b > e
239 241 $ hg resolve -m e
240 242 (no more unresolved files)
241 243
242 244 Continue with a revision should fail:
243 245
244 246 $ hg graft -c 6
245 247 abort: can't specify --continue and revisions
246 248 [255]
247 249
248 250 $ hg graft -c -r 6
249 251 abort: can't specify --continue and revisions
250 252 [255]
251 253
252 254 Continue for real, clobber usernames
253 255
254 256 $ hg graft -c -U
255 257 grafting 4:9c233e8e184d "4"
256 258 grafting 3:4c60f11aa304 "3"
257 259
258 260 Compare with original:
259 261
260 262 $ hg diff -r 6
261 263 $ hg status --rev 0:. -C
262 264 M d
263 265 M e
264 266 A b
265 267 a
266 268 A c
267 269 a
268 270 R a
269 271
270 272 View graph:
271 273
272 274 $ hg log -G --template '{author}@{rev}.{phase}: {desc}\n'
273 275 @ test@11.draft: 3
274 276 |
275 277 o test@10.draft: 4
276 278 |
277 279 o test@9.draft: 5
278 280 |
279 281 o bar@8.draft: 1
280 282 |
281 283 o foo@7.draft: 2
282 284 |
283 285 | o test@6.secret: 6
284 286 | |\
285 287 | | o test@5.draft: 5
286 288 | | |
287 289 | o | test@4.draft: 4
288 290 | |/
289 291 | o baz@3.public: 3
290 292 | |
291 293 | o test@2.public: 2
292 294 | |
293 295 | o bar@1.public: 1
294 296 |/
295 297 o test@0.public: 0
296 298
297 299 Graft again onto another branch should preserve the original source
298 300 $ hg up -q 0
299 301 $ echo 'g'>g
300 302 $ hg add g
301 303 $ hg ci -m 7
302 304 created new head
303 305 $ hg graft 7
304 306 grafting 7:ef0ef43d49e7 "2"
305 307
306 308 $ hg log -r 7 --template '{rev}:{node}\n'
307 309 7:ef0ef43d49e79e81ddafdc7997401ba0041efc82
308 310 $ hg log -r 2 --template '{rev}:{node}\n'
309 311 2:5c095ad7e90f871700f02dd1fa5012cb4498a2d4
310 312
311 313 $ hg log --debug -r tip
312 314 changeset: 13:7a4785234d87ec1aa420ed6b11afe40fa73e12a9
313 315 tag: tip
314 316 phase: draft
315 317 parent: 12:b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
316 318 parent: -1:0000000000000000000000000000000000000000
317 319 manifest: 13:dc313617b8c32457c0d589e0dbbedfe71f3cd637
318 320 user: foo
319 321 date: Thu Jan 01 00:00:00 1970 +0000
320 322 files+: b
321 323 files-: a
322 324 extra: branch=default
323 325 extra: intermediate-source=ef0ef43d49e79e81ddafdc7997401ba0041efc82
324 326 extra: source=5c095ad7e90f871700f02dd1fa5012cb4498a2d4
325 327 description:
326 328 2
327 329
328 330
329 331 Disallow grafting an already grafted cset onto its original branch
330 332 $ hg up -q 6
331 333 $ hg graft 7
332 334 skipping already grafted revision 7:ef0ef43d49e7 (was grafted from 2:5c095ad7e90f)
333 335 [255]
334 336
335 337 $ hg extdiff --config extensions.extdiff= --patch -r 2 -r 13
336 338 --- */hg-5c095ad7e90f.patch * +0000 (glob)
337 339 +++ */hg-7a4785234d87.patch * +0000 (glob)
338 340 @@ -1,18 +1,18 @@
339 341 # HG changeset patch
340 342 -# User test
341 343 +# User foo
342 344 # Date 0 0
343 345 # Thu Jan 01 00:00:00 1970 +0000
344 346 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
345 347 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
346 348 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
347 349 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
348 350 2
349 351
350 352 -diff -r 5d205f8b35b6 -r 5c095ad7e90f a
351 353 +diff -r b592ea63bb0c -r 7a4785234d87 a
352 354 --- a/a Thu Jan 01 00:00:00 1970 +0000
353 355 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
354 356 @@ -1,1 +0,0 @@
355 357 --b
356 358 -diff -r 5d205f8b35b6 -r 5c095ad7e90f b
357 359 +-a
358 360 +diff -r b592ea63bb0c -r 7a4785234d87 b
359 361 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
360 362 +++ b/b Thu Jan 01 00:00:00 1970 +0000
361 363 @@ -0,0 +1,1 @@
362 364 -+b
363 365 ++a
364 366 [1]
365 367
366 368 $ hg extdiff --config extensions.extdiff= --patch -r 2 -r 13 -X .
367 369 --- */hg-5c095ad7e90f.patch * +0000 (glob)
368 370 +++ */hg-7a4785234d87.patch * +0000 (glob)
369 371 @@ -1,8 +1,8 @@
370 372 # HG changeset patch
371 373 -# User test
372 374 +# User foo
373 375 # Date 0 0
374 376 # Thu Jan 01 00:00:00 1970 +0000
375 377 -# Node ID 5c095ad7e90f871700f02dd1fa5012cb4498a2d4
376 378 -# Parent 5d205f8b35b66bc36375c9534ffd3237730e8f04
377 379 +# Node ID 7a4785234d87ec1aa420ed6b11afe40fa73e12a9
378 380 +# Parent b592ea63bb0c19a6c5c44685ee29a2284f9f1b8f
379 381 2
380 382
381 383 [1]
382 384
383 385 Disallow grafting already grafted csets with the same origin onto each other
384 386 $ hg up -q 13
385 387 $ hg graft 2
386 388 skipping revision 2:5c095ad7e90f (already grafted to 13:7a4785234d87)
387 389 [255]
388 390 $ hg graft 7
389 391 skipping already grafted revision 7:ef0ef43d49e7 (13:7a4785234d87 also has origin 2:5c095ad7e90f)
390 392 [255]
391 393
392 394 $ hg up -q 7
393 395 $ hg graft 2
394 396 skipping revision 2:5c095ad7e90f (already grafted to 7:ef0ef43d49e7)
395 397 [255]
396 398 $ hg graft tip
397 399 skipping already grafted revision 13:7a4785234d87 (7:ef0ef43d49e7 also has origin 2:5c095ad7e90f)
398 400 [255]
399 401
400 402 Graft with --log
401 403
402 404 $ hg up -Cq 1
403 405 $ hg graft 3 --log -u foo
404 406 grafting 3:4c60f11aa304 "3"
405 407 warning: can't find ancestor for 'c' copied from 'b'!
406 408 $ hg log --template '{rev} {parents} {desc}\n' -r tip
407 409 14 1:5d205f8b35b6 3
408 410 (grafted from 4c60f11aa304a54ae1c199feb94e7fc771e51ed8)
409 411
410 412 Resolve conflicted graft
411 413 $ hg up -q 0
412 414 $ echo b > a
413 415 $ hg ci -m 8
414 416 created new head
415 417 $ echo c > a
416 418 $ hg ci -m 9
417 419 $ hg graft 1 --tool internal:fail
418 420 grafting 1:5d205f8b35b6 "1"
419 421 abort: unresolved conflicts, can't continue
420 422 (use hg resolve and hg graft --continue)
421 423 [255]
422 424 $ hg resolve --all
423 425 merging a
424 426 warning: conflicts during merge.
425 427 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
426 428 [1]
427 429 $ cat a
428 430 <<<<<<< local: aaa4406d4f0a - test: 9
429 431 c
430 432 =======
431 433 b
432 434 >>>>>>> other: 5d205f8b35b6 - bar: 1
433 435 $ echo b > a
434 436 $ hg resolve -m a
435 437 (no more unresolved files)
436 438 $ hg graft -c
437 439 grafting 1:5d205f8b35b6 "1"
438 440 $ hg export tip --git
439 441 # HG changeset patch
440 442 # User bar
441 443 # Date 0 0
442 444 # Thu Jan 01 00:00:00 1970 +0000
443 445 # Node ID f67661df0c4804d301f064f332b57e7d5ddaf2be
444 446 # Parent aaa4406d4f0ae9befd6e58c82ec63706460cbca6
445 447 1
446 448
447 449 diff --git a/a b/a
448 450 --- a/a
449 451 +++ b/a
450 452 @@ -1,1 +1,1 @@
451 453 -c
452 454 +b
453 455
454 456 Resolve conflicted graft with rename
455 457 $ echo c > a
456 458 $ hg ci -m 10
457 459 $ hg graft 2 --tool internal:fail
458 460 grafting 2:5c095ad7e90f "2"
459 461 abort: unresolved conflicts, can't continue
460 462 (use hg resolve and hg graft --continue)
461 463 [255]
462 464 $ hg resolve --all
463 465 merging a and b to b
464 466 (no more unresolved files)
465 467 $ hg graft -c
466 468 grafting 2:5c095ad7e90f "2"
467 469 $ hg export tip --git
468 470 # HG changeset patch
469 471 # User test
470 472 # Date 0 0
471 473 # Thu Jan 01 00:00:00 1970 +0000
472 474 # Node ID 9627f653b421c61fc1ea4c4e366745070fa3d2bc
473 475 # Parent ee295f490a40b97f3d18dd4c4f1c8936c233b612
474 476 2
475 477
476 478 diff --git a/a b/b
477 479 rename from a
478 480 rename to b
479 481
480 482 Test simple origin(), with and without args
481 483 $ hg log -r 'origin()'
482 484 changeset: 1:5d205f8b35b6
483 485 user: bar
484 486 date: Thu Jan 01 00:00:00 1970 +0000
485 487 summary: 1
486 488
487 489 changeset: 2:5c095ad7e90f
488 490 user: test
489 491 date: Thu Jan 01 00:00:00 1970 +0000
490 492 summary: 2
491 493
492 494 changeset: 3:4c60f11aa304
493 495 user: baz
494 496 date: Thu Jan 01 00:00:00 1970 +0000
495 497 summary: 3
496 498
497 499 changeset: 4:9c233e8e184d
498 500 user: test
499 501 date: Thu Jan 01 00:00:00 1970 +0000
500 502 summary: 4
501 503
502 504 changeset: 5:97f8bfe72746
503 505 branch: stable
504 506 parent: 3:4c60f11aa304
505 507 user: test
506 508 date: Thu Jan 01 00:00:00 1970 +0000
507 509 summary: 5
508 510
509 511 $ hg log -r 'origin(7)'
510 512 changeset: 2:5c095ad7e90f
511 513 user: test
512 514 date: Thu Jan 01 00:00:00 1970 +0000
513 515 summary: 2
514 516
515 517 Now transplant a graft to test following through copies
516 518 $ hg up -q 0
517 519 $ hg branch -q dev
518 520 $ hg ci -qm "dev branch"
519 521 $ hg --config extensions.transplant= transplant -q 7
520 522 $ hg log -r 'origin(.)'
521 523 changeset: 2:5c095ad7e90f
522 524 user: test
523 525 date: Thu Jan 01 00:00:00 1970 +0000
524 526 summary: 2
525 527
526 528 Test that the graft and transplant markers in extra are converted, allowing
527 529 origin() to still work. Note that these recheck the immediately preceeding two
528 530 tests.
529 531 $ hg --quiet --config extensions.convert= --config convert.hg.saverev=True convert . ../converted
530 532
531 533 The graft case
532 534 $ hg -R ../converted log -r 7 --template "{rev}: {node}\n{join(extras, '\n')}\n"
533 535 7: 7ae846e9111fc8f57745634250c7b9ac0a60689b
534 536 branch=default
535 537 convert_revision=ef0ef43d49e79e81ddafdc7997401ba0041efc82
536 538 source=e0213322b2c1a5d5d236c74e79666441bee67a7d
537 539 $ hg -R ../converted log -r 'origin(7)'
538 540 changeset: 2:e0213322b2c1
539 541 user: test
540 542 date: Thu Jan 01 00:00:00 1970 +0000
541 543 summary: 2
542 544
543 545 Test that template correctly expands more than one 'extra' (issue4362), and that
544 546 'intermediate-source' is converted.
545 547 $ hg -R ../converted log -r 13 --template "{extras % ' Extra: {extra}\n'}"
546 548 Extra: branch=default
547 549 Extra: convert_revision=7a4785234d87ec1aa420ed6b11afe40fa73e12a9
548 550 Extra: intermediate-source=7ae846e9111fc8f57745634250c7b9ac0a60689b
549 551 Extra: source=e0213322b2c1a5d5d236c74e79666441bee67a7d
550 552
551 553 The transplant case
552 554 $ hg -R ../converted log -r tip --template "{rev}: {node}\n{join(extras, '\n')}\n"
553 555 21: fbb6c5cc81002f2b4b49c9d731404688bcae5ade
554 556 branch=dev
555 557 convert_revision=7e61b508e709a11d28194a5359bc3532d910af21
556 558 transplant_source=z\xe8F\xe9\x11\x1f\xc8\xf5wEcBP\xc7\xb9\xac (esc)
557 559 `h\x9b (esc)
558 560 $ hg -R ../converted log -r 'origin(tip)'
559 561 changeset: 2:e0213322b2c1
560 562 user: test
561 563 date: Thu Jan 01 00:00:00 1970 +0000
562 564 summary: 2
563 565
564 566
565 567 Test simple destination
566 568 $ hg log -r 'destination()'
567 569 changeset: 7:ef0ef43d49e7
568 570 parent: 0:68795b066622
569 571 user: foo
570 572 date: Thu Jan 01 00:00:00 1970 +0000
571 573 summary: 2
572 574
573 575 changeset: 8:6b9e5368ca4e
574 576 user: bar
575 577 date: Thu Jan 01 00:00:00 1970 +0000
576 578 summary: 1
577 579
578 580 changeset: 9:1905859650ec
579 581 user: test
580 582 date: Thu Jan 01 00:00:00 1970 +0000
581 583 summary: 5
582 584
583 585 changeset: 10:52dc0b4c6907
584 586 user: test
585 587 date: Thu Jan 01 00:00:00 1970 +0000
586 588 summary: 4
587 589
588 590 changeset: 11:882b35362a6b
589 591 user: test
590 592 date: Thu Jan 01 00:00:00 1970 +0000
591 593 summary: 3
592 594
593 595 changeset: 13:7a4785234d87
594 596 user: foo
595 597 date: Thu Jan 01 00:00:00 1970 +0000
596 598 summary: 2
597 599
598 600 changeset: 14:f64defefacee
599 601 parent: 1:5d205f8b35b6
600 602 user: foo
601 603 date: Thu Jan 01 00:00:00 1970 +0000
602 604 summary: 3
603 605
604 606 changeset: 17:f67661df0c48
605 607 user: bar
606 608 date: Thu Jan 01 00:00:00 1970 +0000
607 609 summary: 1
608 610
609 611 changeset: 19:9627f653b421
610 612 user: test
611 613 date: Thu Jan 01 00:00:00 1970 +0000
612 614 summary: 2
613 615
614 616 changeset: 21:7e61b508e709
615 617 branch: dev
616 618 tag: tip
617 619 user: foo
618 620 date: Thu Jan 01 00:00:00 1970 +0000
619 621 summary: 2
620 622
621 623 $ hg log -r 'destination(2)'
622 624 changeset: 7:ef0ef43d49e7
623 625 parent: 0:68795b066622
624 626 user: foo
625 627 date: Thu Jan 01 00:00:00 1970 +0000
626 628 summary: 2
627 629
628 630 changeset: 13:7a4785234d87
629 631 user: foo
630 632 date: Thu Jan 01 00:00:00 1970 +0000
631 633 summary: 2
632 634
633 635 changeset: 19:9627f653b421
634 636 user: test
635 637 date: Thu Jan 01 00:00:00 1970 +0000
636 638 summary: 2
637 639
638 640 changeset: 21:7e61b508e709
639 641 branch: dev
640 642 tag: tip
641 643 user: foo
642 644 date: Thu Jan 01 00:00:00 1970 +0000
643 645 summary: 2
644 646
645 647 Transplants of grafts can find a destination...
646 648 $ hg log -r 'destination(7)'
647 649 changeset: 21:7e61b508e709
648 650 branch: dev
649 651 tag: tip
650 652 user: foo
651 653 date: Thu Jan 01 00:00:00 1970 +0000
652 654 summary: 2
653 655
654 656 ... grafts of grafts unfortunately can't
655 657 $ hg graft -q 13
656 658 warning: can't find ancestor for 'b' copied from 'a'!
657 659 $ hg log -r 'destination(13)'
658 660 All copies of a cset
659 661 $ hg log -r 'origin(13) or destination(origin(13))'
660 662 changeset: 2:5c095ad7e90f
661 663 user: test
662 664 date: Thu Jan 01 00:00:00 1970 +0000
663 665 summary: 2
664 666
665 667 changeset: 7:ef0ef43d49e7
666 668 parent: 0:68795b066622
667 669 user: foo
668 670 date: Thu Jan 01 00:00:00 1970 +0000
669 671 summary: 2
670 672
671 673 changeset: 13:7a4785234d87
672 674 user: foo
673 675 date: Thu Jan 01 00:00:00 1970 +0000
674 676 summary: 2
675 677
676 678 changeset: 19:9627f653b421
677 679 user: test
678 680 date: Thu Jan 01 00:00:00 1970 +0000
679 681 summary: 2
680 682
681 683 changeset: 21:7e61b508e709
682 684 branch: dev
683 685 user: foo
684 686 date: Thu Jan 01 00:00:00 1970 +0000
685 687 summary: 2
686 688
687 689 changeset: 22:d1cb6591fa4b
688 690 branch: dev
689 691 tag: tip
690 692 user: foo
691 693 date: Thu Jan 01 00:00:00 1970 +0000
692 694 summary: 2
693 695
694 696
695 697 graft works on complex revset
696 698
697 699 $ hg graft 'origin(13) or destination(origin(13))'
698 700 skipping ancestor revision 21:7e61b508e709
699 701 skipping ancestor revision 22:d1cb6591fa4b
700 702 skipping revision 2:5c095ad7e90f (already grafted to 22:d1cb6591fa4b)
701 703 grafting 7:ef0ef43d49e7 "2"
702 704 warning: can't find ancestor for 'b' copied from 'a'!
703 705 grafting 13:7a4785234d87 "2"
704 706 warning: can't find ancestor for 'b' copied from 'a'!
705 707 grafting 19:9627f653b421 "2"
706 708 merging b
707 709 warning: can't find ancestor for 'b' copied from 'a'!
708 710
709 711 graft with --force (still doesn't graft merges)
710 712
711 713 $ hg graft 19 0 6
712 714 skipping ungraftable merge revision 6
713 715 skipping ancestor revision 0:68795b066622
714 716 skipping already grafted revision 19:9627f653b421 (22:d1cb6591fa4b also has origin 2:5c095ad7e90f)
715 717 [255]
716 718 $ hg graft 19 0 6 --force
717 719 skipping ungraftable merge revision 6
718 720 grafting 19:9627f653b421 "2"
719 721 merging b
720 722 warning: can't find ancestor for 'b' copied from 'a'!
721 723 grafting 0:68795b066622 "0"
722 724
723 725 graft --force after backout
724 726
725 727 $ echo abc > a
726 728 $ hg ci -m 28
727 729 $ hg backout 28
728 730 reverting a
729 731 changeset 29:53177ba928f6 backs out changeset 28:50a516bb8b57
730 732 $ hg graft 28
731 733 skipping ancestor revision 28:50a516bb8b57
732 734 [255]
733 735 $ hg graft 28 --force
734 736 grafting 28:50a516bb8b57 "28"
735 737 merging a
736 738 $ cat a
737 739 abc
738 740
739 741 graft --continue after --force
740 742
741 743 $ echo def > a
742 744 $ hg ci -m 31
743 745 $ hg graft 28 --force --tool internal:fail
744 746 grafting 28:50a516bb8b57 "28"
745 747 abort: unresolved conflicts, can't continue
746 748 (use hg resolve and hg graft --continue)
747 749 [255]
748 750 $ hg resolve --all
749 751 merging a
750 752 warning: conflicts during merge.
751 753 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
752 754 [1]
753 755 $ echo abc > a
754 756 $ hg resolve -m a
755 757 (no more unresolved files)
756 758 $ hg graft -c
757 759 grafting 28:50a516bb8b57 "28"
758 760 $ cat a
759 761 abc
760 762
761 763 Continue testing same origin policy, using revision numbers from test above
762 764 but do some destructive editing of the repo:
763 765
764 766 $ hg up -qC 7
765 767 $ hg tag -l -r 13 tmp
766 768 $ hg --config extensions.strip= strip 2
767 769 saved backup bundle to $TESTTMP/a/.hg/strip-backup/5c095ad7e90f-d323a1e4-backup.hg (glob)
768 770 $ hg graft tmp
769 771 skipping already grafted revision 8:7a4785234d87 (2:ef0ef43d49e7 also has unknown origin 5c095ad7e90f)
770 772 [255]
771 773
772 774 Empty graft
773 775
774 776 $ hg up -qr 26
775 777 $ hg tag -f something
776 778 $ hg graft -qr 27
777 779 $ hg graft -f 27
778 780 grafting 27:ed6c7e54e319 "28"
779 781 note: graft of 27:ed6c7e54e319 created no changes to commit
780 782
781 783 $ cd ..
782 784
783 785 Graft to duplicate a commit
784 786
785 787 $ hg init graftsibling
786 788 $ cd graftsibling
787 789 $ touch a
788 790 $ hg commit -qAm a
789 791 $ touch b
790 792 $ hg commit -qAm b
791 793 $ hg log -G -T '{rev}\n'
792 794 @ 1
793 795 |
794 796 o 0
795 797
796 798 $ hg up -q 0
797 799 $ hg graft -r 1
798 800 grafting 1:0e067c57feba "b" (tip)
799 801 $ hg log -G -T '{rev}\n'
800 802 @ 2
801 803 |
802 804 | o 1
803 805 |/
804 806 o 0
805 807
806 808 Graft to duplicate a commit twice
807 809
808 810 $ hg up -q 0
809 811 $ hg graft -r 2
810 812 grafting 2:044ec77f6389 "b" (tip)
811 813 $ hg log -G -T '{rev}\n'
812 814 @ 3
813 815 |
814 816 | o 2
815 817 |/
816 818 | o 1
817 819 |/
818 820 o 0
819 821
@@ -1,349 +1,351 b''
1 1 Criss cross merging
2 2
3 3 $ hg init criss-cross
4 4 $ cd criss-cross
5 5 $ echo '0 base' > f1
6 6 $ echo '0 base' > f2
7 7 $ hg ci -Aqm '0 base'
8 8
9 9 $ echo '1 first change' > f1
10 10 $ hg ci -m '1 first change f1'
11 11
12 12 $ hg up -qr0
13 13 $ echo '2 first change' > f2
14 14 $ hg ci -qm '2 first change f2'
15 15
16 16 $ hg merge -qr 1
17 17 $ hg ci -m '3 merge'
18 18
19 19 $ hg up -qr2
20 20 $ hg merge -qr1
21 21 $ hg ci -qm '4 merge'
22 22
23 23 $ echo '5 second change' > f1
24 24 $ hg ci -m '5 second change f1'
25 25
26 26 $ hg up -r3
27 27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 28 $ echo '6 second change' > f2
29 29 $ hg ci -m '6 second change f2'
30 30
31 31 $ hg log -G
32 32 @ changeset: 6:3b08d01b0ab5
33 33 | tag: tip
34 34 | parent: 3:cf89f02107e5
35 35 | user: test
36 36 | date: Thu Jan 01 00:00:00 1970 +0000
37 37 | summary: 6 second change f2
38 38 |
39 39 | o changeset: 5:adfe50279922
40 40 | | user: test
41 41 | | date: Thu Jan 01 00:00:00 1970 +0000
42 42 | | summary: 5 second change f1
43 43 | |
44 44 | o changeset: 4:7d3e55501ae6
45 45 | |\ parent: 2:40663881a6dd
46 46 | | | parent: 1:0f6b37dbe527
47 47 | | | user: test
48 48 | | | date: Thu Jan 01 00:00:00 1970 +0000
49 49 | | | summary: 4 merge
50 50 | | |
51 51 o---+ changeset: 3:cf89f02107e5
52 52 | | | parent: 2:40663881a6dd
53 53 |/ / parent: 1:0f6b37dbe527
54 54 | | user: test
55 55 | | date: Thu Jan 01 00:00:00 1970 +0000
56 56 | | summary: 3 merge
57 57 | |
58 58 | o changeset: 2:40663881a6dd
59 59 | | parent: 0:40494bf2444c
60 60 | | user: test
61 61 | | date: Thu Jan 01 00:00:00 1970 +0000
62 62 | | summary: 2 first change f2
63 63 | |
64 64 o | changeset: 1:0f6b37dbe527
65 65 |/ user: test
66 66 | date: Thu Jan 01 00:00:00 1970 +0000
67 67 | summary: 1 first change f1
68 68 |
69 69 o changeset: 0:40494bf2444c
70 70 user: test
71 71 date: Thu Jan 01 00:00:00 1970 +0000
72 72 summary: 0 base
73 73
74 74
75 75 $ hg merge -v --debug --tool internal:dump 5 --config merge.preferancestor='!'
76 76 note: using 0f6b37dbe527 as ancestor of 3b08d01b0ab5 and adfe50279922
77 77 alternatively, use --config merge.preferancestor=40663881a6dd
78 78 searching for copies back to rev 3
79 79 resolving manifests
80 80 branchmerge: True, force: False, partial: False
81 81 ancestor: 0f6b37dbe527, local: 3b08d01b0ab5+, remote: adfe50279922
82 82 preserving f2 for resolve of f2
83 83 f1: remote is newer -> g
84 84 getting f1
85 85 f2: versions differ -> m
86 86 picked tool ':dump' for f2 (binary False symlink False)
87 87 merging f2
88 88 my f2@3b08d01b0ab5+ other f2@adfe50279922 ancestor f2@40494bf2444c
89 picked tool ':dump' for f2 (binary False symlink False)
90 my f2@3b08d01b0ab5+ other f2@adfe50279922 ancestor f2@40494bf2444c
89 91 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
90 92 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
91 93 [1]
92 94
93 95 $ head *
94 96 ==> f1 <==
95 97 5 second change
96 98
97 99 ==> f2 <==
98 100 6 second change
99 101
100 102 ==> f2.base <==
101 103 0 base
102 104
103 105 ==> f2.local <==
104 106 6 second change
105 107
106 108 ==> f2.orig <==
107 109 6 second change
108 110
109 111 ==> f2.other <==
110 112 2 first change
111 113
112 114 $ hg up -qC .
113 115 $ hg merge -v --tool internal:dump 5 --config merge.preferancestor="null 40663881 3b08d"
114 116 note: using 40663881a6dd as ancestor of 3b08d01b0ab5 and adfe50279922
115 117 alternatively, use --config merge.preferancestor=0f6b37dbe527
116 118 resolving manifests
117 119 merging f1
118 120 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
119 121 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
120 122 [1]
121 123
122 124 Redo merge with merge.preferancestor="*" to enable bid merge
123 125
124 126 $ rm f*
125 127 $ hg up -qC .
126 128 $ hg merge -v --debug --tool internal:dump 5 --config merge.preferancestor="*"
127 129 note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
128 130
129 131 calculating bids for ancestor 0f6b37dbe527
130 132 searching for copies back to rev 3
131 133 resolving manifests
132 134 branchmerge: True, force: False, partial: False
133 135 ancestor: 0f6b37dbe527, local: 3b08d01b0ab5+, remote: adfe50279922
134 136 f1: remote is newer -> g
135 137 f2: versions differ -> m
136 138
137 139 calculating bids for ancestor 40663881a6dd
138 140 searching for copies back to rev 3
139 141 resolving manifests
140 142 branchmerge: True, force: False, partial: False
141 143 ancestor: 40663881a6dd, local: 3b08d01b0ab5+, remote: adfe50279922
142 144 f1: versions differ -> m
143 145 f2: remote unchanged -> k
144 146
145 147 auction for merging merge bids
146 148 f1: picking 'get' action
147 149 f2: picking 'keep' action
148 150 end of auction
149 151
150 152 f1: remote is newer -> g
151 153 getting f1
152 154 f2: remote unchanged -> k
153 155 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
154 156 (branch merge, don't forget to commit)
155 157
156 158 $ head *
157 159 ==> f1 <==
158 160 5 second change
159 161
160 162 ==> f2 <==
161 163 6 second change
162 164
163 165
164 166 The other way around:
165 167
166 168 $ hg up -C -r5
167 169 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
168 170 $ hg merge -v --debug --config merge.preferancestor="*"
169 171 note: merging adfe50279922+ and 3b08d01b0ab5 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
170 172
171 173 calculating bids for ancestor 0f6b37dbe527
172 174 searching for copies back to rev 3
173 175 resolving manifests
174 176 branchmerge: True, force: False, partial: False
175 177 ancestor: 0f6b37dbe527, local: adfe50279922+, remote: 3b08d01b0ab5
176 178 f1: remote unchanged -> k
177 179 f2: versions differ -> m
178 180
179 181 calculating bids for ancestor 40663881a6dd
180 182 searching for copies back to rev 3
181 183 resolving manifests
182 184 branchmerge: True, force: False, partial: False
183 185 ancestor: 40663881a6dd, local: adfe50279922+, remote: 3b08d01b0ab5
184 186 f1: versions differ -> m
185 187 f2: remote is newer -> g
186 188
187 189 auction for merging merge bids
188 190 f1: picking 'keep' action
189 191 f2: picking 'get' action
190 192 end of auction
191 193
192 194 f2: remote is newer -> g
193 195 getting f2
194 196 f1: remote unchanged -> k
195 197 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
196 198 (branch merge, don't forget to commit)
197 199
198 200 $ head *
199 201 ==> f1 <==
200 202 5 second change
201 203
202 204 ==> f2 <==
203 205 6 second change
204 206
205 207 Verify how the output looks and and how verbose it is:
206 208
207 209 $ hg up -qC
208 210 $ hg merge
209 211 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
210 212 (branch merge, don't forget to commit)
211 213
212 214 $ hg up -qC
213 215 $ hg merge -v
214 216 note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
215 217
216 218 calculating bids for ancestor 0f6b37dbe527
217 219 resolving manifests
218 220
219 221 calculating bids for ancestor 40663881a6dd
220 222 resolving manifests
221 223
222 224 auction for merging merge bids
223 225 f1: picking 'get' action
224 226 f2: picking 'keep' action
225 227 end of auction
226 228
227 229 getting f1
228 230 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
229 231 (branch merge, don't forget to commit)
230 232
231 233 $ hg up -qC
232 234 $ hg merge -v --debug --config merge.preferancestor="*"
233 235 note: merging 3b08d01b0ab5+ and adfe50279922 using bids from ancestors 0f6b37dbe527 and 40663881a6dd
234 236
235 237 calculating bids for ancestor 0f6b37dbe527
236 238 searching for copies back to rev 3
237 239 resolving manifests
238 240 branchmerge: True, force: False, partial: False
239 241 ancestor: 0f6b37dbe527, local: 3b08d01b0ab5+, remote: adfe50279922
240 242 f1: remote is newer -> g
241 243 f2: versions differ -> m
242 244
243 245 calculating bids for ancestor 40663881a6dd
244 246 searching for copies back to rev 3
245 247 resolving manifests
246 248 branchmerge: True, force: False, partial: False
247 249 ancestor: 40663881a6dd, local: 3b08d01b0ab5+, remote: adfe50279922
248 250 f1: versions differ -> m
249 251 f2: remote unchanged -> k
250 252
251 253 auction for merging merge bids
252 254 f1: picking 'get' action
253 255 f2: picking 'keep' action
254 256 end of auction
255 257
256 258 f1: remote is newer -> g
257 259 getting f1
258 260 f2: remote unchanged -> k
259 261 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
260 262 (branch merge, don't forget to commit)
261 263
262 264 $ cd ..
263 265
264 266 http://stackoverflow.com/questions/9350005/how-do-i-specify-a-merge-base-to-use-in-a-hg-merge/9430810
265 267
266 268 $ hg init ancestor-merging
267 269 $ cd ancestor-merging
268 270 $ echo a > x
269 271 $ hg commit -A -m a x
270 272 $ hg update -q 0
271 273 $ echo b >> x
272 274 $ hg commit -m b
273 275 $ hg update -q 0
274 276 $ echo c >> x
275 277 $ hg commit -qm c
276 278 $ hg update -q 1
277 279 $ hg merge -q --tool internal:local 2
278 280 $ echo c >> x
279 281 $ hg commit -m bc
280 282 $ hg update -q 2
281 283 $ hg merge -q --tool internal:local 1
282 284 $ echo b >> x
283 285 $ hg commit -qm cb
284 286
285 287 $ hg merge --config merge.preferancestor='!'
286 288 note: using 70008a2163f6 as ancestor of 0d355fdef312 and 4b8b546a3eef
287 289 alternatively, use --config merge.preferancestor=b211bbc6eb3c
288 290 merging x
289 291 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
290 292 (branch merge, don't forget to commit)
291 293 $ cat x
292 294 a
293 295 c
294 296 b
295 297 c
296 298
297 299 $ hg up -qC .
298 300
299 301 $ hg merge --config merge.preferancestor=b211bbc6eb3c
300 302 note: using b211bbc6eb3c as ancestor of 0d355fdef312 and 4b8b546a3eef
301 303 alternatively, use --config merge.preferancestor=70008a2163f6
302 304 merging x
303 305 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
304 306 (branch merge, don't forget to commit)
305 307 $ cat x
306 308 a
307 309 b
308 310 c
309 311 b
310 312
311 313 $ hg up -qC .
312 314
313 315 $ hg merge -v --config merge.preferancestor="*"
314 316 note: merging 0d355fdef312+ and 4b8b546a3eef using bids from ancestors 70008a2163f6 and b211bbc6eb3c
315 317
316 318 calculating bids for ancestor 70008a2163f6
317 319 resolving manifests
318 320
319 321 calculating bids for ancestor b211bbc6eb3c
320 322 resolving manifests
321 323
322 324 auction for merging merge bids
323 325 x: multiple bids for merge action:
324 326 versions differ -> m
325 327 versions differ -> m
326 328 x: ambiguous merge - picked m action
327 329 end of auction
328 330
329 331 merging x
330 332 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
331 333 (branch merge, don't forget to commit)
332 334 $ cat x
333 335 a
334 336 c
335 337 b
336 338 c
337 339
338 340 Verify that the old context ancestor works with / despite preferancestor:
339 341
340 342 $ hg log -r 'ancestor(head())' --config merge.preferancestor=1 -T '{rev}\n'
341 343 1
342 344 $ hg log -r 'ancestor(head())' --config merge.preferancestor=2 -T '{rev}\n'
343 345 2
344 346 $ hg log -r 'ancestor(head())' --config merge.preferancestor=3 -T '{rev}\n'
345 347 1
346 348 $ hg log -r 'ancestor(head())' --config merge.preferancestor='1337 * - 2' -T '{rev}\n'
347 349 2
348 350
349 351 $ cd ..
@@ -1,1030 +1,1032 b''
1 1 test merge-tools configuration - mostly exercising filemerge.py
2 2
3 3 $ unset HGMERGE # make sure HGMERGE doesn't interfere with the test
4 4 $ hg init
5 5
6 6 revision 0
7 7
8 8 $ echo "revision 0" > f
9 9 $ echo "space" >> f
10 10 $ hg commit -Am "revision 0"
11 11 adding f
12 12
13 13 revision 1
14 14
15 15 $ echo "revision 1" > f
16 16 $ echo "space" >> f
17 17 $ hg commit -Am "revision 1"
18 18 $ hg update 0 > /dev/null
19 19
20 20 revision 2
21 21
22 22 $ echo "revision 2" > f
23 23 $ echo "space" >> f
24 24 $ hg commit -Am "revision 2"
25 25 created new head
26 26 $ hg update 0 > /dev/null
27 27
28 28 revision 3 - simple to merge
29 29
30 30 $ echo "revision 3" >> f
31 31 $ hg commit -Am "revision 3"
32 32 created new head
33 33
34 34 revision 4 - hard to merge
35 35
36 36 $ hg update 0 > /dev/null
37 37 $ echo "revision 4" > f
38 38 $ hg commit -Am "revision 4"
39 39 created new head
40 40
41 41 $ echo "[merge-tools]" > .hg/hgrc
42 42
43 43 $ beforemerge() {
44 44 > cat .hg/hgrc
45 45 > echo "# hg update -C 1"
46 46 > hg update -C 1 > /dev/null
47 47 > }
48 48 $ aftermerge() {
49 49 > echo "# cat f"
50 50 > cat f
51 51 > echo "# hg stat"
52 52 > hg stat
53 53 > rm -f f.orig
54 54 > }
55 55
56 56 Tool selection
57 57
58 58 default is internal merge:
59 59
60 60 $ beforemerge
61 61 [merge-tools]
62 62 # hg update -C 1
63 63
64 64 hg merge -r 2
65 65 override $PATH to ensure hgmerge not visible; use $PYTHON in case we're
66 66 running from a devel copy, not a temp installation
67 67
68 68 $ PATH="$BINDIR:/usr/sbin" $PYTHON "$BINDIR"/hg merge -r 2
69 69 merging f
70 70 warning: conflicts during merge.
71 71 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
72 72 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
73 73 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
74 74 [1]
75 75 $ aftermerge
76 76 # cat f
77 77 <<<<<<< local: ef83787e2614 - test: revision 1
78 78 revision 1
79 79 =======
80 80 revision 2
81 81 >>>>>>> other: 0185f4e0cf02 - test: revision 2
82 82 space
83 83 # hg stat
84 84 M f
85 85 ? f.orig
86 86
87 87 simplest hgrc using false for merge:
88 88
89 89 $ echo "false.whatever=" >> .hg/hgrc
90 90 $ beforemerge
91 91 [merge-tools]
92 92 false.whatever=
93 93 # hg update -C 1
94 94 $ hg merge -r 2
95 95 merging f
96 96 merging f failed!
97 97 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
98 98 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
99 99 [1]
100 100 $ aftermerge
101 101 # cat f
102 102 revision 1
103 103 space
104 104 # hg stat
105 105 M f
106 106 ? f.orig
107 107
108 108 #if unix-permissions
109 109
110 110 unexecutable file in $PATH shouldn't be found:
111 111
112 112 $ echo "echo fail" > false
113 113 $ hg up -qC 1
114 114 $ PATH="`pwd`:$BINDIR:/usr/sbin" $PYTHON "$BINDIR"/hg merge -r 2
115 115 merging f
116 116 warning: conflicts during merge.
117 117 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
118 118 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
119 119 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
120 120 [1]
121 121 $ rm false
122 122
123 123 #endif
124 124
125 125 executable directory in $PATH shouldn't be found:
126 126
127 127 $ mkdir false
128 128 $ hg up -qC 1
129 129 $ PATH="`pwd`:$BINDIR:/usr/sbin" $PYTHON "$BINDIR"/hg merge -r 2
130 130 merging f
131 131 warning: conflicts during merge.
132 132 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
133 133 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
134 134 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
135 135 [1]
136 136 $ rmdir false
137 137
138 138 true with higher .priority gets precedence:
139 139
140 140 $ echo "true.priority=1" >> .hg/hgrc
141 141 $ beforemerge
142 142 [merge-tools]
143 143 false.whatever=
144 144 true.priority=1
145 145 # hg update -C 1
146 146 $ hg merge -r 2
147 147 merging f
148 148 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
149 149 (branch merge, don't forget to commit)
150 150 $ aftermerge
151 151 # cat f
152 152 revision 1
153 153 space
154 154 # hg stat
155 155 M f
156 156
157 157 unless lowered on command line:
158 158
159 159 $ beforemerge
160 160 [merge-tools]
161 161 false.whatever=
162 162 true.priority=1
163 163 # hg update -C 1
164 164 $ hg merge -r 2 --config merge-tools.true.priority=-7
165 165 merging f
166 166 merging f failed!
167 167 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
168 168 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
169 169 [1]
170 170 $ aftermerge
171 171 # cat f
172 172 revision 1
173 173 space
174 174 # hg stat
175 175 M f
176 176 ? f.orig
177 177
178 178 or false set higher on command line:
179 179
180 180 $ beforemerge
181 181 [merge-tools]
182 182 false.whatever=
183 183 true.priority=1
184 184 # hg update -C 1
185 185 $ hg merge -r 2 --config merge-tools.false.priority=117
186 186 merging f
187 187 merging f failed!
188 188 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
189 189 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
190 190 [1]
191 191 $ aftermerge
192 192 # cat f
193 193 revision 1
194 194 space
195 195 # hg stat
196 196 M f
197 197 ? f.orig
198 198
199 199 or true.executable not found in PATH:
200 200
201 201 $ beforemerge
202 202 [merge-tools]
203 203 false.whatever=
204 204 true.priority=1
205 205 # hg update -C 1
206 206 $ hg merge -r 2 --config merge-tools.true.executable=nonexistentmergetool
207 207 merging f
208 208 merging f failed!
209 209 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
210 210 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
211 211 [1]
212 212 $ aftermerge
213 213 # cat f
214 214 revision 1
215 215 space
216 216 # hg stat
217 217 M f
218 218 ? f.orig
219 219
220 220 or true.executable with bogus path:
221 221
222 222 $ beforemerge
223 223 [merge-tools]
224 224 false.whatever=
225 225 true.priority=1
226 226 # hg update -C 1
227 227 $ hg merge -r 2 --config merge-tools.true.executable=/nonexistent/mergetool
228 228 merging f
229 229 merging f failed!
230 230 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
231 231 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
232 232 [1]
233 233 $ aftermerge
234 234 # cat f
235 235 revision 1
236 236 space
237 237 # hg stat
238 238 M f
239 239 ? f.orig
240 240
241 241 but true.executable set to cat found in PATH works:
242 242
243 243 $ echo "true.executable=cat" >> .hg/hgrc
244 244 $ beforemerge
245 245 [merge-tools]
246 246 false.whatever=
247 247 true.priority=1
248 248 true.executable=cat
249 249 # hg update -C 1
250 250 $ hg merge -r 2
251 251 merging f
252 252 revision 1
253 253 space
254 254 revision 0
255 255 space
256 256 revision 2
257 257 space
258 258 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
259 259 (branch merge, don't forget to commit)
260 260 $ aftermerge
261 261 # cat f
262 262 revision 1
263 263 space
264 264 # hg stat
265 265 M f
266 266
267 267 and true.executable set to cat with path works:
268 268
269 269 $ beforemerge
270 270 [merge-tools]
271 271 false.whatever=
272 272 true.priority=1
273 273 true.executable=cat
274 274 # hg update -C 1
275 275 $ hg merge -r 2 --config merge-tools.true.executable=cat
276 276 merging f
277 277 revision 1
278 278 space
279 279 revision 0
280 280 space
281 281 revision 2
282 282 space
283 283 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
284 284 (branch merge, don't forget to commit)
285 285 $ aftermerge
286 286 # cat f
287 287 revision 1
288 288 space
289 289 # hg stat
290 290 M f
291 291
292 292 #if unix-permissions
293 293
294 294 environment variables in true.executable are handled:
295 295
296 296 $ echo 'echo "custom merge tool"' > .hg/merge.sh
297 297 $ beforemerge
298 298 [merge-tools]
299 299 false.whatever=
300 300 true.priority=1
301 301 true.executable=cat
302 302 # hg update -C 1
303 303 $ hg --config merge-tools.true.executable='sh' \
304 304 > --config merge-tools.true.args=.hg/merge.sh \
305 305 > merge -r 2
306 306 merging f
307 307 custom merge tool
308 308 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
309 309 (branch merge, don't forget to commit)
310 310 $ aftermerge
311 311 # cat f
312 312 revision 1
313 313 space
314 314 # hg stat
315 315 M f
316 316
317 317 #endif
318 318
319 319 Tool selection and merge-patterns
320 320
321 321 merge-patterns specifies new tool false:
322 322
323 323 $ beforemerge
324 324 [merge-tools]
325 325 false.whatever=
326 326 true.priority=1
327 327 true.executable=cat
328 328 # hg update -C 1
329 329 $ hg merge -r 2 --config merge-patterns.f=false
330 330 merging f
331 331 merging f failed!
332 332 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
333 333 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
334 334 [1]
335 335 $ aftermerge
336 336 # cat f
337 337 revision 1
338 338 space
339 339 # hg stat
340 340 M f
341 341 ? f.orig
342 342
343 343 merge-patterns specifies executable not found in PATH and gets warning:
344 344
345 345 $ beforemerge
346 346 [merge-tools]
347 347 false.whatever=
348 348 true.priority=1
349 349 true.executable=cat
350 350 # hg update -C 1
351 351 $ hg merge -r 2 --config merge-patterns.f=true --config merge-tools.true.executable=nonexistentmergetool
352 352 couldn't find merge tool true specified for f
353 353 merging f
354 couldn't find merge tool true specified for f
354 355 merging f failed!
355 356 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
356 357 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
357 358 [1]
358 359 $ aftermerge
359 360 # cat f
360 361 revision 1
361 362 space
362 363 # hg stat
363 364 M f
364 365 ? f.orig
365 366
366 367 merge-patterns specifies executable with bogus path and gets warning:
367 368
368 369 $ beforemerge
369 370 [merge-tools]
370 371 false.whatever=
371 372 true.priority=1
372 373 true.executable=cat
373 374 # hg update -C 1
374 375 $ hg merge -r 2 --config merge-patterns.f=true --config merge-tools.true.executable=/nonexistent/mergetool
375 376 couldn't find merge tool true specified for f
376 377 merging f
378 couldn't find merge tool true specified for f
377 379 merging f failed!
378 380 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
379 381 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
380 382 [1]
381 383 $ aftermerge
382 384 # cat f
383 385 revision 1
384 386 space
385 387 # hg stat
386 388 M f
387 389 ? f.orig
388 390
389 391 ui.merge overrules priority
390 392
391 393 ui.merge specifies false:
392 394
393 395 $ beforemerge
394 396 [merge-tools]
395 397 false.whatever=
396 398 true.priority=1
397 399 true.executable=cat
398 400 # hg update -C 1
399 401 $ hg merge -r 2 --config ui.merge=false
400 402 merging f
401 403 merging f failed!
402 404 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
403 405 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
404 406 [1]
405 407 $ aftermerge
406 408 # cat f
407 409 revision 1
408 410 space
409 411 # hg stat
410 412 M f
411 413 ? f.orig
412 414
413 415 ui.merge specifies internal:fail:
414 416
415 417 $ beforemerge
416 418 [merge-tools]
417 419 false.whatever=
418 420 true.priority=1
419 421 true.executable=cat
420 422 # hg update -C 1
421 423 $ hg merge -r 2 --config ui.merge=internal:fail
422 424 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
423 425 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
424 426 [1]
425 427 $ aftermerge
426 428 # cat f
427 429 revision 1
428 430 space
429 431 # hg stat
430 432 M f
431 433
432 434 ui.merge specifies :local (without internal prefix):
433 435
434 436 $ beforemerge
435 437 [merge-tools]
436 438 false.whatever=
437 439 true.priority=1
438 440 true.executable=cat
439 441 # hg update -C 1
440 442 $ hg merge -r 2 --config ui.merge=:local
441 443 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
442 444 (branch merge, don't forget to commit)
443 445 $ aftermerge
444 446 # cat f
445 447 revision 1
446 448 space
447 449 # hg stat
448 450 M f
449 451
450 452 ui.merge specifies internal:other:
451 453
452 454 $ beforemerge
453 455 [merge-tools]
454 456 false.whatever=
455 457 true.priority=1
456 458 true.executable=cat
457 459 # hg update -C 1
458 460 $ hg merge -r 2 --config ui.merge=internal:other
459 461 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
460 462 (branch merge, don't forget to commit)
461 463 $ aftermerge
462 464 # cat f
463 465 revision 2
464 466 space
465 467 # hg stat
466 468 M f
467 469
468 470 ui.merge specifies internal:prompt:
469 471
470 472 $ beforemerge
471 473 [merge-tools]
472 474 false.whatever=
473 475 true.priority=1
474 476 true.executable=cat
475 477 # hg update -C 1
476 478 $ hg merge -r 2 --config ui.merge=internal:prompt
477 479 no tool found to merge f
478 480 keep (l)ocal or take (o)ther? l
479 481 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
480 482 (branch merge, don't forget to commit)
481 483 $ aftermerge
482 484 # cat f
483 485 revision 1
484 486 space
485 487 # hg stat
486 488 M f
487 489
488 490 ui.merge specifies internal:dump:
489 491
490 492 $ beforemerge
491 493 [merge-tools]
492 494 false.whatever=
493 495 true.priority=1
494 496 true.executable=cat
495 497 # hg update -C 1
496 498 $ hg merge -r 2 --config ui.merge=internal:dump
497 499 merging f
498 500 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
499 501 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
500 502 [1]
501 503 $ aftermerge
502 504 # cat f
503 505 revision 1
504 506 space
505 507 # hg stat
506 508 M f
507 509 ? f.base
508 510 ? f.local
509 511 ? f.orig
510 512 ? f.other
511 513
512 514 f.base:
513 515
514 516 $ cat f.base
515 517 revision 0
516 518 space
517 519
518 520 f.local:
519 521
520 522 $ cat f.local
521 523 revision 1
522 524 space
523 525
524 526 f.other:
525 527
526 528 $ cat f.other
527 529 revision 2
528 530 space
529 531 $ rm f.base f.local f.other
530 532
531 533 ui.merge specifies internal:other but is overruled by pattern for false:
532 534
533 535 $ beforemerge
534 536 [merge-tools]
535 537 false.whatever=
536 538 true.priority=1
537 539 true.executable=cat
538 540 # hg update -C 1
539 541 $ hg merge -r 2 --config ui.merge=internal:other --config merge-patterns.f=false
540 542 merging f
541 543 merging f failed!
542 544 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
543 545 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
544 546 [1]
545 547 $ aftermerge
546 548 # cat f
547 549 revision 1
548 550 space
549 551 # hg stat
550 552 M f
551 553 ? f.orig
552 554
553 555 Premerge
554 556
555 557 ui.merge specifies internal:other but is overruled by --tool=false
556 558
557 559 $ beforemerge
558 560 [merge-tools]
559 561 false.whatever=
560 562 true.priority=1
561 563 true.executable=cat
562 564 # hg update -C 1
563 565 $ hg merge -r 2 --config ui.merge=internal:other --tool=false
564 566 merging f
565 567 merging f failed!
566 568 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
567 569 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
568 570 [1]
569 571 $ aftermerge
570 572 # cat f
571 573 revision 1
572 574 space
573 575 # hg stat
574 576 M f
575 577 ? f.orig
576 578
577 579 HGMERGE specifies internal:other but is overruled by --tool=false
578 580
579 581 $ HGMERGE=internal:other ; export HGMERGE
580 582 $ beforemerge
581 583 [merge-tools]
582 584 false.whatever=
583 585 true.priority=1
584 586 true.executable=cat
585 587 # hg update -C 1
586 588 $ hg merge -r 2 --tool=false
587 589 merging f
588 590 merging f failed!
589 591 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
590 592 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
591 593 [1]
592 594 $ aftermerge
593 595 # cat f
594 596 revision 1
595 597 space
596 598 # hg stat
597 599 M f
598 600 ? f.orig
599 601
600 602 $ unset HGMERGE # make sure HGMERGE doesn't interfere with remaining tests
601 603
602 604 update is a merge ...
603 605
604 606 (this also tests that files reverted with '--rev REV' are treated as
605 607 "modified", even if none of mode, size and timestamp of them isn't
606 608 changed on the filesystem (see also issue4583))
607 609
608 610 $ cat >> $HGRCPATH <<EOF
609 611 > [fakedirstatewritetime]
610 612 > # emulate invoking dirstate.write() via repo.status()
611 613 > # at 2000-01-01 00:00
612 614 > fakenow = 200001010000
613 615 > EOF
614 616
615 617 $ beforemerge
616 618 [merge-tools]
617 619 false.whatever=
618 620 true.priority=1
619 621 true.executable=cat
620 622 # hg update -C 1
621 623 $ hg update -q 0
622 624 $ f -s f
623 625 f: size=17
624 626 $ touch -t 200001010000 f
625 627 $ hg debugrebuildstate
626 628 $ cat >> $HGRCPATH <<EOF
627 629 > [extensions]
628 630 > fakedirstatewritetime = $TESTDIR/fakedirstatewritetime.py
629 631 > EOF
630 632 $ hg revert -q -r 1 .
631 633 $ cat >> $HGRCPATH <<EOF
632 634 > [extensions]
633 635 > fakedirstatewritetime = !
634 636 > EOF
635 637 $ f -s f
636 638 f: size=17
637 639 $ touch -t 200001010000 f
638 640 $ hg status f
639 641 M f
640 642 $ hg update -r 2
641 643 merging f
642 644 revision 1
643 645 space
644 646 revision 0
645 647 space
646 648 revision 2
647 649 space
648 650 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
649 651 $ aftermerge
650 652 # cat f
651 653 revision 1
652 654 space
653 655 # hg stat
654 656 M f
655 657
656 658 update should also have --tool
657 659
658 660 $ beforemerge
659 661 [merge-tools]
660 662 false.whatever=
661 663 true.priority=1
662 664 true.executable=cat
663 665 # hg update -C 1
664 666 $ hg update -q 0
665 667 $ f -s f
666 668 f: size=17
667 669 $ touch -t 200001010000 f
668 670 $ hg debugrebuildstate
669 671 $ cat >> $HGRCPATH <<EOF
670 672 > [extensions]
671 673 > fakedirstatewritetime = $TESTDIR/fakedirstatewritetime.py
672 674 > EOF
673 675 $ hg revert -q -r 1 .
674 676 $ cat >> $HGRCPATH <<EOF
675 677 > [extensions]
676 678 > fakedirstatewritetime = !
677 679 > EOF
678 680 $ f -s f
679 681 f: size=17
680 682 $ touch -t 200001010000 f
681 683 $ hg status f
682 684 M f
683 685 $ hg update -r 2 --tool false
684 686 merging f
685 687 merging f failed!
686 688 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
687 689 use 'hg resolve' to retry unresolved file merges
688 690 [1]
689 691 $ aftermerge
690 692 # cat f
691 693 revision 1
692 694 space
693 695 # hg stat
694 696 M f
695 697 ? f.orig
696 698
697 699 Default is silent simplemerge:
698 700
699 701 $ beforemerge
700 702 [merge-tools]
701 703 false.whatever=
702 704 true.priority=1
703 705 true.executable=cat
704 706 # hg update -C 1
705 707 $ hg merge -r 3
706 708 merging f
707 709 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
708 710 (branch merge, don't forget to commit)
709 711 $ aftermerge
710 712 # cat f
711 713 revision 1
712 714 space
713 715 revision 3
714 716 # hg stat
715 717 M f
716 718
717 719 .premerge=True is same:
718 720
719 721 $ beforemerge
720 722 [merge-tools]
721 723 false.whatever=
722 724 true.priority=1
723 725 true.executable=cat
724 726 # hg update -C 1
725 727 $ hg merge -r 3 --config merge-tools.true.premerge=True
726 728 merging f
727 729 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
728 730 (branch merge, don't forget to commit)
729 731 $ aftermerge
730 732 # cat f
731 733 revision 1
732 734 space
733 735 revision 3
734 736 # hg stat
735 737 M f
736 738
737 739 .premerge=False executes merge-tool:
738 740
739 741 $ beforemerge
740 742 [merge-tools]
741 743 false.whatever=
742 744 true.priority=1
743 745 true.executable=cat
744 746 # hg update -C 1
745 747 $ hg merge -r 3 --config merge-tools.true.premerge=False
746 748 merging f
747 749 revision 1
748 750 space
749 751 revision 0
750 752 space
751 753 revision 0
752 754 space
753 755 revision 3
754 756 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
755 757 (branch merge, don't forget to commit)
756 758 $ aftermerge
757 759 # cat f
758 760 revision 1
759 761 space
760 762 # hg stat
761 763 M f
762 764
763 765 premerge=keep keeps conflict markers in:
764 766
765 767 $ beforemerge
766 768 [merge-tools]
767 769 false.whatever=
768 770 true.priority=1
769 771 true.executable=cat
770 772 # hg update -C 1
771 773 $ hg merge -r 4 --config merge-tools.true.premerge=keep
772 774 merging f
773 775 <<<<<<< local: ef83787e2614 - test: revision 1
774 776 revision 1
775 777 space
776 778 =======
777 779 revision 4
778 780 >>>>>>> other: 81448d39c9a0 - test: revision 4
779 781 revision 0
780 782 space
781 783 revision 4
782 784 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
783 785 (branch merge, don't forget to commit)
784 786 $ aftermerge
785 787 # cat f
786 788 <<<<<<< local: ef83787e2614 - test: revision 1
787 789 revision 1
788 790 space
789 791 =======
790 792 revision 4
791 793 >>>>>>> other: 81448d39c9a0 - test: revision 4
792 794 # hg stat
793 795 M f
794 796
795 797 premerge=keep-merge3 keeps conflict markers with base content:
796 798
797 799 $ beforemerge
798 800 [merge-tools]
799 801 false.whatever=
800 802 true.priority=1
801 803 true.executable=cat
802 804 # hg update -C 1
803 805 $ hg merge -r 4 --config merge-tools.true.premerge=keep-merge3
804 806 merging f
805 807 <<<<<<< local: ef83787e2614 - test: revision 1
806 808 revision 1
807 809 space
808 810 ||||||| base
809 811 revision 0
810 812 space
811 813 =======
812 814 revision 4
813 815 >>>>>>> other: 81448d39c9a0 - test: revision 4
814 816 revision 0
815 817 space
816 818 revision 4
817 819 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
818 820 (branch merge, don't forget to commit)
819 821 $ aftermerge
820 822 # cat f
821 823 <<<<<<< local: ef83787e2614 - test: revision 1
822 824 revision 1
823 825 space
824 826 ||||||| base
825 827 revision 0
826 828 space
827 829 =======
828 830 revision 4
829 831 >>>>>>> other: 81448d39c9a0 - test: revision 4
830 832 # hg stat
831 833 M f
832 834
833 835
834 836 Tool execution
835 837
836 838 set tools.args explicit to include $base $local $other $output:
837 839
838 840 $ beforemerge
839 841 [merge-tools]
840 842 false.whatever=
841 843 true.priority=1
842 844 true.executable=cat
843 845 # hg update -C 1
844 846 $ hg merge -r 2 --config merge-tools.true.executable=head --config merge-tools.true.args='$base $local $other $output' \
845 847 > | sed 's,==> .* <==,==> ... <==,g'
846 848 merging f
847 849 ==> ... <==
848 850 revision 0
849 851 space
850 852
851 853 ==> ... <==
852 854 revision 1
853 855 space
854 856
855 857 ==> ... <==
856 858 revision 2
857 859 space
858 860
859 861 ==> ... <==
860 862 revision 1
861 863 space
862 864 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
863 865 (branch merge, don't forget to commit)
864 866 $ aftermerge
865 867 # cat f
866 868 revision 1
867 869 space
868 870 # hg stat
869 871 M f
870 872
871 873 Merge with "echo mergeresult > $local":
872 874
873 875 $ beforemerge
874 876 [merge-tools]
875 877 false.whatever=
876 878 true.priority=1
877 879 true.executable=cat
878 880 # hg update -C 1
879 881 $ hg merge -r 2 --config merge-tools.true.executable=echo --config merge-tools.true.args='mergeresult > $local'
880 882 merging f
881 883 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
882 884 (branch merge, don't forget to commit)
883 885 $ aftermerge
884 886 # cat f
885 887 mergeresult
886 888 # hg stat
887 889 M f
888 890
889 891 - and $local is the file f:
890 892
891 893 $ beforemerge
892 894 [merge-tools]
893 895 false.whatever=
894 896 true.priority=1
895 897 true.executable=cat
896 898 # hg update -C 1
897 899 $ hg merge -r 2 --config merge-tools.true.executable=echo --config merge-tools.true.args='mergeresult > f'
898 900 merging f
899 901 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
900 902 (branch merge, don't forget to commit)
901 903 $ aftermerge
902 904 # cat f
903 905 mergeresult
904 906 # hg stat
905 907 M f
906 908
907 909 Merge with "echo mergeresult > $output" - the variable is a bit magic:
908 910
909 911 $ beforemerge
910 912 [merge-tools]
911 913 false.whatever=
912 914 true.priority=1
913 915 true.executable=cat
914 916 # hg update -C 1
915 917 $ hg merge -r 2 --config merge-tools.true.executable=echo --config merge-tools.true.args='mergeresult > $output'
916 918 merging f
917 919 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
918 920 (branch merge, don't forget to commit)
919 921 $ aftermerge
920 922 # cat f
921 923 mergeresult
922 924 # hg stat
923 925 M f
924 926
925 927 Merge using tool with a path that must be quoted:
926 928
927 929 $ beforemerge
928 930 [merge-tools]
929 931 false.whatever=
930 932 true.priority=1
931 933 true.executable=cat
932 934 # hg update -C 1
933 935 $ cat <<EOF > 'my merge tool'
934 936 > cat "\$1" "\$2" "\$3" > "\$4"
935 937 > EOF
936 938 $ hg --config merge-tools.true.executable='sh' \
937 939 > --config merge-tools.true.args='"./my merge tool" $base $local $other $output' \
938 940 > merge -r 2
939 941 merging f
940 942 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
941 943 (branch merge, don't forget to commit)
942 944 $ rm -f 'my merge tool'
943 945 $ aftermerge
944 946 # cat f
945 947 revision 0
946 948 space
947 949 revision 1
948 950 space
949 951 revision 2
950 952 space
951 953 # hg stat
952 954 M f
953 955
954 956 Issue3581: Merging a filename that needs to be quoted
955 957 (This test doesn't work on Windows filesystems even on Linux, so check
956 958 for Unix-like permission)
957 959
958 960 #if unix-permissions
959 961 $ beforemerge
960 962 [merge-tools]
961 963 false.whatever=
962 964 true.priority=1
963 965 true.executable=cat
964 966 # hg update -C 1
965 967 $ echo "revision 5" > '"; exit 1; echo "'
966 968 $ hg commit -Am "revision 5"
967 969 adding "; exit 1; echo "
968 970 warning: filename contains '"', which is reserved on Windows: '"; exit 1; echo "'
969 971 $ hg update -C 1 > /dev/null
970 972 $ echo "revision 6" > '"; exit 1; echo "'
971 973 $ hg commit -Am "revision 6"
972 974 adding "; exit 1; echo "
973 975 warning: filename contains '"', which is reserved on Windows: '"; exit 1; echo "'
974 976 created new head
975 977 $ hg merge --config merge-tools.true.executable="true" -r 5
976 978 merging "; exit 1; echo "
977 979 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
978 980 (branch merge, don't forget to commit)
979 981 $ hg update -C 1 > /dev/null
980 982 #endif
981 983
982 984 Merge post-processing
983 985
984 986 cat is a bad merge-tool and doesn't change:
985 987
986 988 $ beforemerge
987 989 [merge-tools]
988 990 false.whatever=
989 991 true.priority=1
990 992 true.executable=cat
991 993 # hg update -C 1
992 994 $ hg merge -y -r 2 --config merge-tools.true.checkchanged=1
993 995 merging f
994 996 revision 1
995 997 space
996 998 revision 0
997 999 space
998 1000 revision 2
999 1001 space
1000 1002 output file f appears unchanged
1001 1003 was merge successful (yn)? n
1002 1004 merging f failed!
1003 1005 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1004 1006 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1005 1007 [1]
1006 1008 $ aftermerge
1007 1009 # cat f
1008 1010 revision 1
1009 1011 space
1010 1012 # hg stat
1011 1013 M f
1012 1014 ? f.orig
1013 1015
1014 1016 #if symlink
1015 1017
1016 1018 internal merge cannot handle symlinks and shouldn't try:
1017 1019
1018 1020 $ hg update -q -C 1
1019 1021 $ rm f
1020 1022 $ ln -s symlink f
1021 1023 $ hg commit -qm 'f is symlink'
1022 1024 $ hg merge -r 2 --tool internal:merge
1023 1025 merging f
1024 1026 warning: internal :merge cannot merge symlinks for f
1025 1027 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
1026 1028 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
1027 1029 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1028 1030 [1]
1029 1031
1030 1032 #endif
@@ -1,147 +1,149 b''
1 1 initial
2 2 $ hg init test-a
3 3 $ cd test-a
4 4 $ cat >test.txt <<"EOF"
5 5 > 1
6 6 > 2
7 7 > 3
8 8 > EOF
9 9 $ hg add test.txt
10 10 $ hg commit -m "Initial"
11 11
12 12 clone
13 13 $ cd ..
14 14 $ hg clone test-a test-b
15 15 updating to branch default
16 16 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
17 17
18 18 change test-a
19 19 $ cd test-a
20 20 $ cat >test.txt <<"EOF"
21 21 > one
22 22 > two
23 23 > three
24 24 > EOF
25 25 $ hg commit -m "Numbers as words"
26 26
27 27 change test-b
28 28 $ cd ../test-b
29 29 $ cat >test.txt <<"EOF"
30 30 > 1
31 31 > 2.5
32 32 > 3
33 33 > EOF
34 34 $ hg commit -m "2 -> 2.5"
35 35
36 36 now pull and merge from test-a
37 37 $ hg pull ../test-a
38 38 pulling from ../test-a
39 39 searching for changes
40 40 adding changesets
41 41 adding manifests
42 42 adding file changes
43 43 added 1 changesets with 1 changes to 1 files (+1 heads)
44 44 (run 'hg heads' to see heads, 'hg merge' to merge)
45 45 $ hg merge
46 46 merging test.txt
47 47 warning: conflicts during merge.
48 48 merging test.txt incomplete! (edit conflicts, then use 'hg resolve --mark')
49 49 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
50 50 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
51 51 [1]
52 52 resolve conflict
53 53 $ cat >test.txt <<"EOF"
54 54 > one
55 55 > two-point-five
56 56 > three
57 57 > EOF
58 58 $ rm -f *.orig
59 59 $ hg resolve -m test.txt
60 60 (no more unresolved files)
61 61 $ hg commit -m "Merge 1"
62 62
63 63 change test-a again
64 64 $ cd ../test-a
65 65 $ cat >test.txt <<"EOF"
66 66 > one
67 67 > two-point-one
68 68 > three
69 69 > EOF
70 70 $ hg commit -m "two -> two-point-one"
71 71
72 72 pull and merge from test-a again
73 73 $ cd ../test-b
74 74 $ hg pull ../test-a
75 75 pulling from ../test-a
76 76 searching for changes
77 77 adding changesets
78 78 adding manifests
79 79 adding file changes
80 80 added 1 changesets with 1 changes to 1 files (+1 heads)
81 81 (run 'hg heads' to see heads, 'hg merge' to merge)
82 82 $ hg merge --debug
83 83 searching for copies back to rev 1
84 84 resolving manifests
85 85 branchmerge: True, force: False, partial: False
86 86 ancestor: 96b70246a118, local: 50c3a7e29886+, remote: 40d11a4173a8
87 87 preserving test.txt for resolve of test.txt
88 88 test.txt: versions differ -> m
89 89 picked tool ':merge' for test.txt (binary False symlink False)
90 90 merging test.txt
91 91 my test.txt@50c3a7e29886+ other test.txt@40d11a4173a8 ancestor test.txt@96b70246a118
92 picked tool ':merge' for test.txt (binary False symlink False)
93 my test.txt@50c3a7e29886+ other test.txt@40d11a4173a8 ancestor test.txt@96b70246a118
92 94 warning: conflicts during merge.
93 95 merging test.txt incomplete! (edit conflicts, then use 'hg resolve --mark')
94 96 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
95 97 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
96 98 [1]
97 99
98 100 $ cat test.txt
99 101 one
100 102 <<<<<<< local: 50c3a7e29886 - test: Merge 1
101 103 two-point-five
102 104 =======
103 105 two-point-one
104 106 >>>>>>> other: 40d11a4173a8 - test: two -> two-point-one
105 107 three
106 108
107 109 $ hg debugindex test.txt
108 110 rev offset length ..... linkrev nodeid p1 p2 (re)
109 111 0 0 7 ..... 0 01365c4cca56 000000000000 000000000000 (re)
110 112 1 7 9 ..... 1 7b013192566a 01365c4cca56 000000000000 (re)
111 113 2 16 15 ..... 2 8fe46a3eb557 01365c4cca56 000000000000 (re)
112 114 3 31 2. ..... 3 fc3148072371 7b013192566a 8fe46a3eb557 (re)
113 115 4 5. 25 ..... 4 d40249267ae3 8fe46a3eb557 000000000000 (re)
114 116
115 117 $ hg log
116 118 changeset: 4:40d11a4173a8
117 119 tag: tip
118 120 parent: 2:96b70246a118
119 121 user: test
120 122 date: Thu Jan 01 00:00:00 1970 +0000
121 123 summary: two -> two-point-one
122 124
123 125 changeset: 3:50c3a7e29886
124 126 parent: 1:d1e159716d41
125 127 parent: 2:96b70246a118
126 128 user: test
127 129 date: Thu Jan 01 00:00:00 1970 +0000
128 130 summary: Merge 1
129 131
130 132 changeset: 2:96b70246a118
131 133 parent: 0:b1832b9d912a
132 134 user: test
133 135 date: Thu Jan 01 00:00:00 1970 +0000
134 136 summary: Numbers as words
135 137
136 138 changeset: 1:d1e159716d41
137 139 user: test
138 140 date: Thu Jan 01 00:00:00 1970 +0000
139 141 summary: 2 -> 2.5
140 142
141 143 changeset: 0:b1832b9d912a
142 144 user: test
143 145 date: Thu Jan 01 00:00:00 1970 +0000
144 146 summary: Initial
145 147
146 148
147 149 $ cd ..
@@ -1,975 +1,1039 b''
1 1
2 2 $ mkdir -p t
3 3 $ cd t
4 4 $ cat <<EOF > merge
5 5 > import sys, os
6 6 > f = open(sys.argv[1], "wb")
7 7 > f.write("merge %s %s %s" % (sys.argv[1], sys.argv[2], sys.argv[3]))
8 8 > f.close()
9 9 > EOF
10 10
11 11 perform a test merge with possible renaming
12 12 args:
13 13 $1 = action in local branch
14 14 $2 = action in remote branch
15 15 $3 = action in working dir
16 16 $4 = expected result
17 17
18 18 $ tm()
19 19 > {
20 20 > hg init t
21 21 > cd t
22 22 > echo "[merge]" >> .hg/hgrc
23 23 > echo "followcopies = 1" >> .hg/hgrc
24 24 >
25 25 > # base
26 26 > echo base > a
27 27 > echo base > rev # used to force commits
28 28 > hg add a rev
29 29 > hg ci -m "base"
30 30 >
31 31 > # remote
32 32 > echo remote > rev
33 33 > if [ "$2" != "" ] ; then $2 ; fi
34 34 > hg ci -m "remote"
35 35 >
36 36 > # local
37 37 > hg co -q 0
38 38 > echo local > rev
39 39 > if [ "$1" != "" ] ; then $1 ; fi
40 40 > hg ci -m "local"
41 41 >
42 42 > # working dir
43 43 > echo local > rev
44 44 > if [ "$3" != "" ] ; then $3 ; fi
45 45 >
46 46 > # merge
47 47 > echo "--------------"
48 48 > echo "test L:$1 R:$2 W:$3 - $4"
49 49 > echo "--------------"
50 50 > hg merge -y --debug --traceback --tool="python ../merge"
51 51 >
52 52 > echo "--------------"
53 53 > hg status -camC -X rev
54 54 >
55 55 > hg ci -m "merge"
56 56 >
57 57 > echo "--------------"
58 58 > echo
59 59 >
60 60 > cd ..
61 61 > rm -r t
62 62 > }
63 63 $ up() {
64 64 > cp rev $1
65 65 > hg add $1 2> /dev/null
66 66 > if [ "$2" != "" ] ; then
67 67 > cp rev $2
68 68 > hg add $2 2> /dev/null
69 69 > fi
70 70 > }
71 71 $ uc() { up $1; hg cp $1 $2; } # update + copy
72 72 $ um() { up $1; hg mv $1 $2; }
73 73 $ nc() { hg cp $1 $2; } # just copy
74 74 $ nm() { hg mv $1 $2; } # just move
75 75 $ tm "up a " "nc a b" " " "1 get local a to b"
76 76 created new head
77 77 --------------
78 78 test L:up a R:nc a b W: - 1 get local a to b
79 79 --------------
80 80 searching for copies back to rev 1
81 81 unmatched files in other:
82 82 b
83 83 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
84 84 src: 'a' -> dst: 'b' *
85 85 checking for directory renames
86 86 resolving manifests
87 87 branchmerge: True, force: False, partial: False
88 88 ancestor: 924404dff337, local: e300d1c794ec+, remote: 4ce40f5aca24
89 89 preserving a for resolve of b
90 90 preserving rev for resolve of rev
91 91 a: remote unchanged -> k
92 92 b: remote copied from a -> m
93 93 picked tool 'python ../merge' for b (binary False symlink False)
94 94 merging a and b to b
95 95 my b@e300d1c794ec+ other b@4ce40f5aca24 ancestor a@924404dff337
96 96 premerge successful
97 97 rev: versions differ -> m
98 98 picked tool 'python ../merge' for rev (binary False symlink False)
99 99 merging rev
100 100 my rev@e300d1c794ec+ other rev@4ce40f5aca24 ancestor rev@924404dff337
101 picked tool 'python ../merge' for rev (binary False symlink False)
102 my rev@e300d1c794ec+ other rev@4ce40f5aca24 ancestor rev@924404dff337
101 103 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
102 104 merge tool returned: 0
103 105 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
104 106 (branch merge, don't forget to commit)
105 107 --------------
106 108 M b
107 109 a
108 110 C a
109 111 --------------
110 112
111 113 $ tm "nc a b" "up a " " " "2 get rem change to a and b"
112 114 created new head
113 115 --------------
114 116 test L:nc a b R:up a W: - 2 get rem change to a and b
115 117 --------------
116 118 searching for copies back to rev 1
117 119 unmatched files in local:
118 120 b
119 121 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
120 122 src: 'a' -> dst: 'b' *
121 123 checking for directory renames
122 124 resolving manifests
123 125 branchmerge: True, force: False, partial: False
124 126 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: f4db7e329e71
125 127 preserving b for resolve of b
126 128 preserving rev for resolve of rev
127 129 a: remote is newer -> g
128 130 getting a
129 131 b: local copied/moved from a -> m
130 132 picked tool 'python ../merge' for b (binary False symlink False)
131 133 merging b and a to b
132 134 my b@86a2aa42fc76+ other a@f4db7e329e71 ancestor a@924404dff337
133 135 premerge successful
134 136 rev: versions differ -> m
135 137 picked tool 'python ../merge' for rev (binary False symlink False)
136 138 merging rev
137 139 my rev@86a2aa42fc76+ other rev@f4db7e329e71 ancestor rev@924404dff337
138 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * (glob)
140 picked tool 'python ../merge' for rev (binary False symlink False)
141 my rev@86a2aa42fc76+ other rev@f4db7e329e71 ancestor rev@924404dff337
142 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
139 143 merge tool returned: 0
140 144 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
141 145 (branch merge, don't forget to commit)
142 146 --------------
143 147 M a
144 148 M b
145 149 a
146 150 --------------
147 151
148 152 $ tm "up a " "nm a b" " " "3 get local a change to b, remove a"
149 153 created new head
150 154 --------------
151 155 test L:up a R:nm a b W: - 3 get local a change to b, remove a
152 156 --------------
153 157 searching for copies back to rev 1
154 158 unmatched files in other:
155 159 b
156 160 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
157 161 src: 'a' -> dst: 'b' *
158 162 checking for directory renames
159 163 resolving manifests
160 164 branchmerge: True, force: False, partial: False
161 165 ancestor: 924404dff337, local: e300d1c794ec+, remote: bdb19105162a
162 166 preserving a for resolve of b
163 167 preserving rev for resolve of rev
164 168 removing a
165 169 b: remote moved from a -> m
166 170 picked tool 'python ../merge' for b (binary False symlink False)
167 171 merging a and b to b
168 172 my b@e300d1c794ec+ other b@bdb19105162a ancestor a@924404dff337
169 173 premerge successful
170 174 rev: versions differ -> m
171 175 picked tool 'python ../merge' for rev (binary False symlink False)
172 176 merging rev
173 177 my rev@e300d1c794ec+ other rev@bdb19105162a ancestor rev@924404dff337
178 picked tool 'python ../merge' for rev (binary False symlink False)
179 my rev@e300d1c794ec+ other rev@bdb19105162a ancestor rev@924404dff337
174 180 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
175 181 merge tool returned: 0
176 182 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
177 183 (branch merge, don't forget to commit)
178 184 --------------
179 185 M b
180 186 a
181 187 --------------
182 188
183 189 $ tm "nm a b" "up a " " " "4 get remote change to b"
184 190 created new head
185 191 --------------
186 192 test L:nm a b R:up a W: - 4 get remote change to b
187 193 --------------
188 194 searching for copies back to rev 1
189 195 unmatched files in local:
190 196 b
191 197 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
192 198 src: 'a' -> dst: 'b' *
193 199 checking for directory renames
194 200 resolving manifests
195 201 branchmerge: True, force: False, partial: False
196 202 ancestor: 924404dff337, local: 02963e448370+, remote: f4db7e329e71
197 203 preserving b for resolve of b
198 204 preserving rev for resolve of rev
199 205 b: local copied/moved from a -> m
200 206 picked tool 'python ../merge' for b (binary False symlink False)
201 207 merging b and a to b
202 208 my b@02963e448370+ other a@f4db7e329e71 ancestor a@924404dff337
203 209 premerge successful
204 210 rev: versions differ -> m
205 211 picked tool 'python ../merge' for rev (binary False symlink False)
206 212 merging rev
207 213 my rev@02963e448370+ other rev@f4db7e329e71 ancestor rev@924404dff337
214 picked tool 'python ../merge' for rev (binary False symlink False)
215 my rev@02963e448370+ other rev@f4db7e329e71 ancestor rev@924404dff337
208 216 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
209 217 merge tool returned: 0
210 218 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
211 219 (branch merge, don't forget to commit)
212 220 --------------
213 221 M b
214 222 a
215 223 --------------
216 224
217 225 $ tm " " "nc a b" " " "5 get b"
218 226 created new head
219 227 --------------
220 228 test L: R:nc a b W: - 5 get b
221 229 --------------
222 230 searching for copies back to rev 1
223 231 unmatched files in other:
224 232 b
225 233 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
226 234 src: 'a' -> dst: 'b'
227 235 checking for directory renames
228 236 resolving manifests
229 237 branchmerge: True, force: False, partial: False
230 238 ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: 4ce40f5aca24
231 239 preserving rev for resolve of rev
232 240 b: remote created -> g
233 241 getting b
234 242 rev: versions differ -> m
235 243 picked tool 'python ../merge' for rev (binary False symlink False)
236 244 merging rev
237 245 my rev@94b33a1b7f2d+ other rev@4ce40f5aca24 ancestor rev@924404dff337
246 picked tool 'python ../merge' for rev (binary False symlink False)
247 my rev@94b33a1b7f2d+ other rev@4ce40f5aca24 ancestor rev@924404dff337
238 248 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
239 249 merge tool returned: 0
240 250 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
241 251 (branch merge, don't forget to commit)
242 252 --------------
243 253 M b
244 254 C a
245 255 --------------
246 256
247 257 $ tm "nc a b" " " " " "6 nothing"
248 258 created new head
249 259 --------------
250 260 test L:nc a b R: W: - 6 nothing
251 261 --------------
252 262 searching for copies back to rev 1
253 263 unmatched files in local:
254 264 b
255 265 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
256 266 src: 'a' -> dst: 'b'
257 267 checking for directory renames
258 268 resolving manifests
259 269 branchmerge: True, force: False, partial: False
260 270 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 97c705ade336
261 271 preserving rev for resolve of rev
262 272 rev: versions differ -> m
263 273 picked tool 'python ../merge' for rev (binary False symlink False)
264 274 merging rev
265 275 my rev@86a2aa42fc76+ other rev@97c705ade336 ancestor rev@924404dff337
276 picked tool 'python ../merge' for rev (binary False symlink False)
277 my rev@86a2aa42fc76+ other rev@97c705ade336 ancestor rev@924404dff337
266 278 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
267 279 merge tool returned: 0
268 280 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
269 281 (branch merge, don't forget to commit)
270 282 --------------
271 283 C a
272 284 C b
273 285 --------------
274 286
275 287 $ tm " " "nm a b" " " "7 get b"
276 288 created new head
277 289 --------------
278 290 test L: R:nm a b W: - 7 get b
279 291 --------------
280 292 searching for copies back to rev 1
281 293 unmatched files in other:
282 294 b
283 295 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
284 296 src: 'a' -> dst: 'b'
285 297 checking for directory renames
286 298 resolving manifests
287 299 branchmerge: True, force: False, partial: False
288 300 ancestor: 924404dff337, local: 94b33a1b7f2d+, remote: bdb19105162a
289 301 preserving rev for resolve of rev
290 302 a: other deleted -> r
291 303 removing a
292 304 b: remote created -> g
293 305 getting b
294 306 rev: versions differ -> m
295 307 picked tool 'python ../merge' for rev (binary False symlink False)
296 308 merging rev
297 309 my rev@94b33a1b7f2d+ other rev@bdb19105162a ancestor rev@924404dff337
310 picked tool 'python ../merge' for rev (binary False symlink False)
311 my rev@94b33a1b7f2d+ other rev@bdb19105162a ancestor rev@924404dff337
298 312 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
299 313 merge tool returned: 0
300 314 1 files updated, 1 files merged, 1 files removed, 0 files unresolved
301 315 (branch merge, don't forget to commit)
302 316 --------------
303 317 M b
304 318 --------------
305 319
306 320 $ tm "nm a b" " " " " "8 nothing"
307 321 created new head
308 322 --------------
309 323 test L:nm a b R: W: - 8 nothing
310 324 --------------
311 325 searching for copies back to rev 1
312 326 unmatched files in local:
313 327 b
314 328 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
315 329 src: 'a' -> dst: 'b'
316 330 checking for directory renames
317 331 resolving manifests
318 332 branchmerge: True, force: False, partial: False
319 333 ancestor: 924404dff337, local: 02963e448370+, remote: 97c705ade336
320 334 preserving rev for resolve of rev
321 335 rev: versions differ -> m
322 336 picked tool 'python ../merge' for rev (binary False symlink False)
323 337 merging rev
324 338 my rev@02963e448370+ other rev@97c705ade336 ancestor rev@924404dff337
339 picked tool 'python ../merge' for rev (binary False symlink False)
340 my rev@02963e448370+ other rev@97c705ade336 ancestor rev@924404dff337
325 341 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
326 342 merge tool returned: 0
327 343 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
328 344 (branch merge, don't forget to commit)
329 345 --------------
330 346 C b
331 347 --------------
332 348
333 349 $ tm "um a b" "um a b" " " "9 do merge with ancestor in a"
334 350 created new head
335 351 --------------
336 352 test L:um a b R:um a b W: - 9 do merge with ancestor in a
337 353 --------------
338 354 searching for copies back to rev 1
339 355 unmatched files new in both:
340 356 b
341 357 resolving manifests
342 358 branchmerge: True, force: False, partial: False
343 359 ancestor: 924404dff337, local: 62e7bf090eba+, remote: 49b6d8032493
344 360 preserving b for resolve of b
345 361 preserving rev for resolve of rev
346 362 b: both renamed from a -> m
347 363 picked tool 'python ../merge' for b (binary False symlink False)
348 364 merging b
349 365 my b@62e7bf090eba+ other b@49b6d8032493 ancestor a@924404dff337
366 picked tool 'python ../merge' for b (binary False symlink False)
367 my b@62e7bf090eba+ other b@49b6d8032493 ancestor a@924404dff337
350 368 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
351 369 merge tool returned: 0
352 370 rev: versions differ -> m
353 371 picked tool 'python ../merge' for rev (binary False symlink False)
354 372 merging rev
355 373 my rev@62e7bf090eba+ other rev@49b6d8032493 ancestor rev@924404dff337
374 picked tool 'python ../merge' for rev (binary False symlink False)
375 my rev@62e7bf090eba+ other rev@49b6d8032493 ancestor rev@924404dff337
356 376 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
357 377 merge tool returned: 0
358 378 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
359 379 (branch merge, don't forget to commit)
360 380 --------------
361 381 M b
362 382 --------------
363 383
364 384
365 385 m "um a c" "um x c" " " "10 do merge with no ancestor"
366 386
367 387 $ tm "nm a b" "nm a c" " " "11 get c, keep b"
368 388 created new head
369 389 --------------
370 390 test L:nm a b R:nm a c W: - 11 get c, keep b
371 391 --------------
372 392 searching for copies back to rev 1
373 393 unmatched files in local:
374 394 b
375 395 unmatched files in other:
376 396 c
377 397 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
378 398 src: 'a' -> dst: 'b' !
379 399 src: 'a' -> dst: 'c' !
380 400 checking for directory renames
381 401 resolving manifests
382 402 branchmerge: True, force: False, partial: False
383 403 ancestor: 924404dff337, local: 02963e448370+, remote: fe905ef2c33e
384 404 preserving rev for resolve of rev
385 405 c: remote created -> g
386 406 getting c
387 407 rev: versions differ -> m
388 408 picked tool 'python ../merge' for rev (binary False symlink False)
389 409 merging rev
390 410 my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
411 picked tool 'python ../merge' for rev (binary False symlink False)
412 my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
391 413 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
392 414 merge tool returned: 0
393 415 note: possible conflict - a was renamed multiple times to:
394 416 b
395 417 c
396 418 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
397 419 (branch merge, don't forget to commit)
398 420 --------------
399 421 M c
400 422 C b
401 423 --------------
402 424
403 425 $ tm "nc a b" "up b " " " "12 merge b no ancestor"
404 426 created new head
405 427 --------------
406 428 test L:nc a b R:up b W: - 12 merge b no ancestor
407 429 --------------
408 430 searching for copies back to rev 1
409 431 unmatched files new in both:
410 432 b
411 433 resolving manifests
412 434 branchmerge: True, force: False, partial: False
413 435 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: af30c7647fc7
414 436 preserving b for resolve of b
415 437 preserving rev for resolve of rev
416 438 b: both created -> m
417 439 picked tool 'python ../merge' for b (binary False symlink False)
418 440 merging b
419 441 my b@86a2aa42fc76+ other b@af30c7647fc7 ancestor b@000000000000
442 picked tool 'python ../merge' for b (binary False symlink False)
443 my b@86a2aa42fc76+ other b@af30c7647fc7 ancestor b@000000000000
420 444 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
421 445 merge tool returned: 0
422 446 rev: versions differ -> m
423 447 picked tool 'python ../merge' for rev (binary False symlink False)
424 448 merging rev
425 449 my rev@86a2aa42fc76+ other rev@af30c7647fc7 ancestor rev@924404dff337
450 picked tool 'python ../merge' for rev (binary False symlink False)
451 my rev@86a2aa42fc76+ other rev@af30c7647fc7 ancestor rev@924404dff337
426 452 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
427 453 merge tool returned: 0
428 454 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
429 455 (branch merge, don't forget to commit)
430 456 --------------
431 457 M b
432 458 C a
433 459 --------------
434 460
435 461 $ tm "up b " "nm a b" " " "13 merge b no ancestor"
436 462 created new head
437 463 --------------
438 464 test L:up b R:nm a b W: - 13 merge b no ancestor
439 465 --------------
440 466 searching for copies back to rev 1
441 467 unmatched files new in both:
442 468 b
443 469 resolving manifests
444 470 branchmerge: True, force: False, partial: False
445 471 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
446 472 preserving b for resolve of b
447 473 preserving rev for resolve of rev
448 474 a: other deleted -> r
449 475 removing a
450 476 b: both created -> m
451 477 picked tool 'python ../merge' for b (binary False symlink False)
452 478 merging b
453 479 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
480 picked tool 'python ../merge' for b (binary False symlink False)
481 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
454 482 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
455 483 merge tool returned: 0
456 484 rev: versions differ -> m
457 485 picked tool 'python ../merge' for rev (binary False symlink False)
458 486 merging rev
459 487 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
488 picked tool 'python ../merge' for rev (binary False symlink False)
489 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
460 490 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
461 491 merge tool returned: 0
462 492 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
463 493 (branch merge, don't forget to commit)
464 494 --------------
465 495 M b
466 496 --------------
467 497
468 498 $ tm "nc a b" "up a b" " " "14 merge b no ancestor"
469 499 created new head
470 500 --------------
471 501 test L:nc a b R:up a b W: - 14 merge b no ancestor
472 502 --------------
473 503 searching for copies back to rev 1
474 504 unmatched files new in both:
475 505 b
476 506 resolving manifests
477 507 branchmerge: True, force: False, partial: False
478 508 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
479 509 preserving b for resolve of b
480 510 preserving rev for resolve of rev
481 511 a: remote is newer -> g
482 512 getting a
483 513 b: both created -> m
484 514 picked tool 'python ../merge' for b (binary False symlink False)
485 515 merging b
486 516 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
517 picked tool 'python ../merge' for b (binary False symlink False)
518 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
487 519 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
488 520 merge tool returned: 0
489 521 rev: versions differ -> m
490 522 picked tool 'python ../merge' for rev (binary False symlink False)
491 523 merging rev
492 524 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
525 picked tool 'python ../merge' for rev (binary False symlink False)
526 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
493 527 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
494 528 merge tool returned: 0
495 529 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
496 530 (branch merge, don't forget to commit)
497 531 --------------
498 532 M a
499 533 M b
500 534 --------------
501 535
502 536 $ tm "up b " "nm a b" " " "15 merge b no ancestor, remove a"
503 537 created new head
504 538 --------------
505 539 test L:up b R:nm a b W: - 15 merge b no ancestor, remove a
506 540 --------------
507 541 searching for copies back to rev 1
508 542 unmatched files new in both:
509 543 b
510 544 resolving manifests
511 545 branchmerge: True, force: False, partial: False
512 546 ancestor: 924404dff337, local: 59318016310c+, remote: bdb19105162a
513 547 preserving b for resolve of b
514 548 preserving rev for resolve of rev
515 549 a: other deleted -> r
516 550 removing a
517 551 b: both created -> m
518 552 picked tool 'python ../merge' for b (binary False symlink False)
519 553 merging b
520 554 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
555 picked tool 'python ../merge' for b (binary False symlink False)
556 my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
521 557 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
522 558 merge tool returned: 0
523 559 rev: versions differ -> m
524 560 picked tool 'python ../merge' for rev (binary False symlink False)
525 561 merging rev
526 562 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
563 picked tool 'python ../merge' for rev (binary False symlink False)
564 my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
527 565 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
528 566 merge tool returned: 0
529 567 0 files updated, 2 files merged, 1 files removed, 0 files unresolved
530 568 (branch merge, don't forget to commit)
531 569 --------------
532 570 M b
533 571 --------------
534 572
535 573 $ tm "nc a b" "up a b" " " "16 get a, merge b no ancestor"
536 574 created new head
537 575 --------------
538 576 test L:nc a b R:up a b W: - 16 get a, merge b no ancestor
539 577 --------------
540 578 searching for copies back to rev 1
541 579 unmatched files new in both:
542 580 b
543 581 resolving manifests
544 582 branchmerge: True, force: False, partial: False
545 583 ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 8dbce441892a
546 584 preserving b for resolve of b
547 585 preserving rev for resolve of rev
548 586 a: remote is newer -> g
549 587 getting a
550 588 b: both created -> m
551 589 picked tool 'python ../merge' for b (binary False symlink False)
552 590 merging b
553 591 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
592 picked tool 'python ../merge' for b (binary False symlink False)
593 my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
554 594 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
555 595 merge tool returned: 0
556 596 rev: versions differ -> m
557 597 picked tool 'python ../merge' for rev (binary False symlink False)
558 598 merging rev
559 599 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
600 picked tool 'python ../merge' for rev (binary False symlink False)
601 my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
560 602 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
561 603 merge tool returned: 0
562 604 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
563 605 (branch merge, don't forget to commit)
564 606 --------------
565 607 M a
566 608 M b
567 609 --------------
568 610
569 611 $ tm "up a b" "nc a b" " " "17 keep a, merge b no ancestor"
570 612 created new head
571 613 --------------
572 614 test L:up a b R:nc a b W: - 17 keep a, merge b no ancestor
573 615 --------------
574 616 searching for copies back to rev 1
575 617 unmatched files new in both:
576 618 b
577 619 resolving manifests
578 620 branchmerge: True, force: False, partial: False
579 621 ancestor: 924404dff337, local: 0b76e65c8289+, remote: 4ce40f5aca24
580 622 preserving b for resolve of b
581 623 preserving rev for resolve of rev
582 624 a: remote unchanged -> k
583 625 b: both created -> m
584 626 picked tool 'python ../merge' for b (binary False symlink False)
585 627 merging b
586 628 my b@0b76e65c8289+ other b@4ce40f5aca24 ancestor b@000000000000
629 picked tool 'python ../merge' for b (binary False symlink False)
630 my b@0b76e65c8289+ other b@4ce40f5aca24 ancestor b@000000000000
587 631 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
588 632 merge tool returned: 0
589 633 rev: versions differ -> m
590 634 picked tool 'python ../merge' for rev (binary False symlink False)
591 635 merging rev
592 636 my rev@0b76e65c8289+ other rev@4ce40f5aca24 ancestor rev@924404dff337
637 picked tool 'python ../merge' for rev (binary False symlink False)
638 my rev@0b76e65c8289+ other rev@4ce40f5aca24 ancestor rev@924404dff337
593 639 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
594 640 merge tool returned: 0
595 641 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
596 642 (branch merge, don't forget to commit)
597 643 --------------
598 644 M b
599 645 C a
600 646 --------------
601 647
602 648 $ tm "nm a b" "up a b" " " "18 merge b no ancestor"
603 649 created new head
604 650 --------------
605 651 test L:nm a b R:up a b W: - 18 merge b no ancestor
606 652 --------------
607 653 searching for copies back to rev 1
608 654 unmatched files new in both:
609 655 b
610 656 resolving manifests
611 657 branchmerge: True, force: False, partial: False
612 658 ancestor: 924404dff337, local: 02963e448370+, remote: 8dbce441892a
613 659 remote changed a which local deleted
614 660 use (c)hanged version or leave (d)eleted? c
615 661 preserving b for resolve of b
616 662 preserving rev for resolve of rev
617 663 a: prompt recreating -> g
618 664 getting a
619 665 b: both created -> m
620 666 picked tool 'python ../merge' for b (binary False symlink False)
621 667 merging b
622 668 my b@02963e448370+ other b@8dbce441892a ancestor b@000000000000
669 picked tool 'python ../merge' for b (binary False symlink False)
670 my b@02963e448370+ other b@8dbce441892a ancestor b@000000000000
623 671 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
624 672 merge tool returned: 0
625 673 rev: versions differ -> m
626 674 picked tool 'python ../merge' for rev (binary False symlink False)
627 675 merging rev
628 676 my rev@02963e448370+ other rev@8dbce441892a ancestor rev@924404dff337
677 picked tool 'python ../merge' for rev (binary False symlink False)
678 my rev@02963e448370+ other rev@8dbce441892a ancestor rev@924404dff337
629 679 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
630 680 merge tool returned: 0
631 681 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
632 682 (branch merge, don't forget to commit)
633 683 --------------
634 684 M a
635 685 M b
636 686 --------------
637 687
638 688 $ tm "up a b" "nm a b" " " "19 merge b no ancestor, prompt remove a"
639 689 created new head
640 690 --------------
641 691 test L:up a b R:nm a b W: - 19 merge b no ancestor, prompt remove a
642 692 --------------
643 693 searching for copies back to rev 1
644 694 unmatched files new in both:
645 695 b
646 696 resolving manifests
647 697 branchmerge: True, force: False, partial: False
648 698 ancestor: 924404dff337, local: 0b76e65c8289+, remote: bdb19105162a
649 699 local changed a which remote deleted
650 700 use (c)hanged version or (d)elete? c
651 701 preserving b for resolve of b
652 702 preserving rev for resolve of rev
653 703 a: prompt keep -> a
654 704 b: both created -> m
655 705 picked tool 'python ../merge' for b (binary False symlink False)
656 706 merging b
657 707 my b@0b76e65c8289+ other b@bdb19105162a ancestor b@000000000000
708 picked tool 'python ../merge' for b (binary False symlink False)
709 my b@0b76e65c8289+ other b@bdb19105162a ancestor b@000000000000
658 710 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
659 711 merge tool returned: 0
660 712 rev: versions differ -> m
661 713 picked tool 'python ../merge' for rev (binary False symlink False)
662 714 merging rev
663 715 my rev@0b76e65c8289+ other rev@bdb19105162a ancestor rev@924404dff337
716 picked tool 'python ../merge' for rev (binary False symlink False)
717 my rev@0b76e65c8289+ other rev@bdb19105162a ancestor rev@924404dff337
664 718 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
665 719 merge tool returned: 0
666 720 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
667 721 (branch merge, don't forget to commit)
668 722 --------------
669 723 M b
670 724 C a
671 725 --------------
672 726
673 727 $ tm "up a " "um a b" " " "20 merge a and b to b, remove a"
674 728 created new head
675 729 --------------
676 730 test L:up a R:um a b W: - 20 merge a and b to b, remove a
677 731 --------------
678 732 searching for copies back to rev 1
679 733 unmatched files in other:
680 734 b
681 735 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
682 736 src: 'a' -> dst: 'b' *
683 737 checking for directory renames
684 738 resolving manifests
685 739 branchmerge: True, force: False, partial: False
686 740 ancestor: 924404dff337, local: e300d1c794ec+, remote: 49b6d8032493
687 741 preserving a for resolve of b
688 742 preserving rev for resolve of rev
689 743 removing a
690 744 b: remote moved from a -> m
691 745 picked tool 'python ../merge' for b (binary False symlink False)
692 746 merging a and b to b
693 747 my b@e300d1c794ec+ other b@49b6d8032493 ancestor a@924404dff337
748 picked tool 'python ../merge' for b (binary False symlink False)
749 my b@e300d1c794ec+ other b@49b6d8032493 ancestor a@924404dff337
694 750 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
695 751 merge tool returned: 0
696 752 rev: versions differ -> m
697 753 picked tool 'python ../merge' for rev (binary False symlink False)
698 754 merging rev
699 755 my rev@e300d1c794ec+ other rev@49b6d8032493 ancestor rev@924404dff337
756 picked tool 'python ../merge' for rev (binary False symlink False)
757 my rev@e300d1c794ec+ other rev@49b6d8032493 ancestor rev@924404dff337
700 758 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
701 759 merge tool returned: 0
702 760 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
703 761 (branch merge, don't forget to commit)
704 762 --------------
705 763 M b
706 764 a
707 765 --------------
708 766
709 767 $ tm "um a b" "up a " " " "21 merge a and b to b"
710 768 created new head
711 769 --------------
712 770 test L:um a b R:up a W: - 21 merge a and b to b
713 771 --------------
714 772 searching for copies back to rev 1
715 773 unmatched files in local:
716 774 b
717 775 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
718 776 src: 'a' -> dst: 'b' *
719 777 checking for directory renames
720 778 resolving manifests
721 779 branchmerge: True, force: False, partial: False
722 780 ancestor: 924404dff337, local: 62e7bf090eba+, remote: f4db7e329e71
723 781 preserving b for resolve of b
724 782 preserving rev for resolve of rev
725 783 b: local copied/moved from a -> m
726 784 picked tool 'python ../merge' for b (binary False symlink False)
727 785 merging b and a to b
728 786 my b@62e7bf090eba+ other a@f4db7e329e71 ancestor a@924404dff337
787 picked tool 'python ../merge' for b (binary False symlink False)
788 my b@62e7bf090eba+ other a@f4db7e329e71 ancestor a@924404dff337
729 789 launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
730 790 merge tool returned: 0
731 791 rev: versions differ -> m
732 792 picked tool 'python ../merge' for rev (binary False symlink False)
733 793 merging rev
734 794 my rev@62e7bf090eba+ other rev@f4db7e329e71 ancestor rev@924404dff337
795 picked tool 'python ../merge' for rev (binary False symlink False)
796 my rev@62e7bf090eba+ other rev@f4db7e329e71 ancestor rev@924404dff337
735 797 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
736 798 merge tool returned: 0
737 799 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
738 800 (branch merge, don't forget to commit)
739 801 --------------
740 802 M b
741 803 a
742 804 --------------
743 805
744 806
745 807 m "nm a b" "um x a" " " "22 get a, keep b"
746 808
747 809 $ tm "nm a b" "up a c" " " "23 get c, keep b"
748 810 created new head
749 811 --------------
750 812 test L:nm a b R:up a c W: - 23 get c, keep b
751 813 --------------
752 814 searching for copies back to rev 1
753 815 unmatched files in local:
754 816 b
755 817 unmatched files in other:
756 818 c
757 819 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
758 820 src: 'a' -> dst: 'b' *
759 821 checking for directory renames
760 822 resolving manifests
761 823 branchmerge: True, force: False, partial: False
762 824 ancestor: 924404dff337, local: 02963e448370+, remote: 2b958612230f
763 825 preserving b for resolve of b
764 826 preserving rev for resolve of rev
765 827 c: remote created -> g
766 828 getting c
767 829 b: local copied/moved from a -> m
768 830 picked tool 'python ../merge' for b (binary False symlink False)
769 831 merging b and a to b
770 832 my b@02963e448370+ other a@2b958612230f ancestor a@924404dff337
771 833 premerge successful
772 834 rev: versions differ -> m
773 835 picked tool 'python ../merge' for rev (binary False symlink False)
774 836 merging rev
775 837 my rev@02963e448370+ other rev@2b958612230f ancestor rev@924404dff337
838 picked tool 'python ../merge' for rev (binary False symlink False)
839 my rev@02963e448370+ other rev@2b958612230f ancestor rev@924404dff337
776 840 launching merge tool: python ../merge *$TESTTMP/t/t/rev* * * (glob)
777 841 merge tool returned: 0
778 842 1 files updated, 2 files merged, 0 files removed, 0 files unresolved
779 843 (branch merge, don't forget to commit)
780 844 --------------
781 845 M b
782 846 a
783 847 M c
784 848 --------------
785 849
786 850
787 851 $ cd ..
788 852
789 853
790 854 Systematic and terse testing of merge merges and ancestor calculation:
791 855
792 856 Expected result:
793 857
794 858 \ a m1 m2 dst
795 859 0 - f f f "versions differ"
796 860 1 f g g g "versions differ"
797 861 2 f f f f "versions differ"
798 862 3 f f g f+g "remote copied to " + f
799 863 4 f f g g "remote moved to " + f
800 864 5 f g f f+g "local copied to " + f2
801 865 6 f g f g "local moved to " + f2
802 866 7 - (f) f f "remote differs from untracked local"
803 867 8 f (f) f f "remote differs from untracked local"
804 868
805 869 $ hg init ancestortest
806 870 $ cd ancestortest
807 871 $ for x in 1 2 3 4 5 6 8; do mkdir $x; echo a > $x/f; done
808 872 $ hg ci -Aqm "a"
809 873 $ mkdir 0
810 874 $ touch 0/f
811 875 $ hg mv 1/f 1/g
812 876 $ hg cp 5/f 5/g
813 877 $ hg mv 6/f 6/g
814 878 $ hg rm 8/f
815 879 $ for x in */*; do echo m1 > $x; done
816 880 $ hg ci -Aqm "m1"
817 881 $ hg up -qr0
818 882 $ mkdir 0 7
819 883 $ touch 0/f 7/f
820 884 $ hg mv 1/f 1/g
821 885 $ hg cp 3/f 3/g
822 886 $ hg mv 4/f 4/g
823 887 $ for x in */*; do echo m2 > $x; done
824 888 $ hg ci -Aqm "m2"
825 889 $ hg up -qr1
826 890 $ mkdir 7 8
827 891 $ echo m > 7/f
828 892 $ echo m > 8/f
829 893 $ hg merge -f --tool internal:dump -v --debug -r2 | sed '/^ 0\/f: both created -> m/,$d' 2> /dev/null
830 894 searching for copies back to rev 1
831 895 unmatched files in local:
832 896 5/g
833 897 6/g
834 898 unmatched files in other:
835 899 3/g
836 900 4/g
837 901 7/f
838 902 unmatched files new in both:
839 903 0/f
840 904 1/g
841 905 all copies found (* = to merge, ! = divergent, % = renamed and deleted):
842 906 src: '3/f' -> dst: '3/g' *
843 907 src: '4/f' -> dst: '4/g' *
844 908 src: '5/f' -> dst: '5/g' *
845 909 src: '6/f' -> dst: '6/g' *
846 910 checking for directory renames
847 911 resolving manifests
848 912 branchmerge: True, force: True, partial: False
849 913 ancestor: e6cb3cf11019, local: ec44bf929ab5+, remote: c62e34d0b898
850 914 remote changed 8/f which local deleted
851 915 use (c)hanged version or leave (d)eleted? c
852 916 preserving 0/f for resolve of 0/f
853 917 preserving 1/g for resolve of 1/g
854 918 preserving 2/f for resolve of 2/f
855 919 preserving 3/f for resolve of 3/f
856 920 preserving 3/f for resolve of 3/g
857 921 preserving 4/f for resolve of 4/g
858 922 preserving 5/f for resolve of 5/f
859 923 preserving 5/g for resolve of 5/g
860 924 preserving 6/g for resolve of 6/g
861 925 preserving 7/f for resolve of 7/f
862 926 removing 4/f
863 927 8/f: prompt recreating -> g
864 928 getting 8/f
865 929 $ hg mani
866 930 0/f
867 931 1/g
868 932 2/f
869 933 3/f
870 934 4/f
871 935 5/f
872 936 5/g
873 937 6/g
874 938 $ for f in */*; do echo $f:; cat $f; done
875 939 0/f:
876 940 m1
877 941 0/f.base:
878 942 0/f.local:
879 943 m1
880 944 0/f.orig:
881 945 m1
882 946 0/f.other:
883 947 m2
884 948 1/g:
885 949 m1
886 950 1/g.base:
887 951 a
888 952 1/g.local:
889 953 m1
890 954 1/g.orig:
891 955 m1
892 956 1/g.other:
893 957 m2
894 958 2/f:
895 959 m1
896 960 2/f.base:
897 961 a
898 962 2/f.local:
899 963 m1
900 964 2/f.orig:
901 965 m1
902 966 2/f.other:
903 967 m2
904 968 3/f:
905 969 m1
906 970 3/f.base:
907 971 a
908 972 3/f.local:
909 973 m1
910 974 3/f.orig:
911 975 m1
912 976 3/f.other:
913 977 m2
914 978 3/g:
915 979 m1
916 980 3/g.base:
917 981 a
918 982 3/g.local:
919 983 m1
920 984 3/g.orig:
921 985 m1
922 986 3/g.other:
923 987 m2
924 988 4/g:
925 989 m1
926 990 4/g.base:
927 991 a
928 992 4/g.local:
929 993 m1
930 994 4/g.orig:
931 995 m1
932 996 4/g.other:
933 997 m2
934 998 5/f:
935 999 m1
936 1000 5/f.base:
937 1001 a
938 1002 5/f.local:
939 1003 m1
940 1004 5/f.orig:
941 1005 m1
942 1006 5/f.other:
943 1007 m2
944 1008 5/g:
945 1009 m1
946 1010 5/g.base:
947 1011 a
948 1012 5/g.local:
949 1013 m1
950 1014 5/g.orig:
951 1015 m1
952 1016 5/g.other:
953 1017 m2
954 1018 6/g:
955 1019 m1
956 1020 6/g.base:
957 1021 a
958 1022 6/g.local:
959 1023 m1
960 1024 6/g.orig:
961 1025 m1
962 1026 6/g.other:
963 1027 m2
964 1028 7/f:
965 1029 m
966 1030 7/f.base:
967 1031 7/f.local:
968 1032 m
969 1033 7/f.orig:
970 1034 m
971 1035 7/f.other:
972 1036 m2
973 1037 8/f:
974 1038 m2
975 1039 $ cd ..
@@ -1,1757 +1,1759 b''
1 1 Let commit recurse into subrepos by default to match pre-2.0 behavior:
2 2
3 3 $ echo "[ui]" >> $HGRCPATH
4 4 $ echo "commitsubrepos = Yes" >> $HGRCPATH
5 5
6 6 $ hg init t
7 7 $ cd t
8 8
9 9 first revision, no sub
10 10
11 11 $ echo a > a
12 12 $ hg ci -Am0
13 13 adding a
14 14
15 15 add first sub
16 16
17 17 $ echo s = s > .hgsub
18 18 $ hg add .hgsub
19 19 $ hg init s
20 20 $ echo a > s/a
21 21
22 22 Issue2232: committing a subrepo without .hgsub
23 23
24 24 $ hg ci -mbad s
25 25 abort: can't commit subrepos without .hgsub
26 26 [255]
27 27
28 28 $ hg -R s add s/a
29 29 $ hg files -S
30 30 .hgsub
31 31 a
32 32 s/a (glob)
33 33
34 34 $ hg -R s ci -Ams0
35 35 $ hg sum
36 36 parent: 0:f7b1eb17ad24 tip
37 37 0
38 38 branch: default
39 39 commit: 1 added, 1 subrepos
40 40 update: (current)
41 41 phases: 1 draft
42 42 $ hg ci -m1
43 43
44 44 test handling .hgsubstate "added" explicitly.
45 45
46 46 $ hg parents --template '{node}\n{files}\n'
47 47 7cf8cfea66e410e8e3336508dfeec07b3192de51
48 48 .hgsub .hgsubstate
49 49 $ hg rollback -q
50 50 $ hg add .hgsubstate
51 51 $ hg ci -m1
52 52 $ hg parents --template '{node}\n{files}\n'
53 53 7cf8cfea66e410e8e3336508dfeec07b3192de51
54 54 .hgsub .hgsubstate
55 55
56 56 Revert subrepo and test subrepo fileset keyword:
57 57
58 58 $ echo b > s/a
59 59 $ hg revert --dry-run "set:subrepo('glob:s*')"
60 60 reverting subrepo s
61 61 reverting s/a (glob)
62 62 $ cat s/a
63 63 b
64 64 $ hg revert "set:subrepo('glob:s*')"
65 65 reverting subrepo s
66 66 reverting s/a (glob)
67 67 $ cat s/a
68 68 a
69 69 $ rm s/a.orig
70 70
71 71 Revert subrepo with no backup. The "reverting s/a" line is gone since
72 72 we're really running 'hg update' in the subrepo:
73 73
74 74 $ echo b > s/a
75 75 $ hg revert --no-backup s
76 76 reverting subrepo s
77 77
78 78 Issue2022: update -C
79 79
80 80 $ echo b > s/a
81 81 $ hg sum
82 82 parent: 1:7cf8cfea66e4 tip
83 83 1
84 84 branch: default
85 85 commit: 1 subrepos
86 86 update: (current)
87 87 phases: 2 draft
88 88 $ hg co -C 1
89 89 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 90 $ hg sum
91 91 parent: 1:7cf8cfea66e4 tip
92 92 1
93 93 branch: default
94 94 commit: (clean)
95 95 update: (current)
96 96 phases: 2 draft
97 97
98 98 commands that require a clean repo should respect subrepos
99 99
100 100 $ echo b >> s/a
101 101 $ hg backout tip
102 102 abort: uncommitted changes in subrepository 's'
103 103 [255]
104 104 $ hg revert -C -R s s/a
105 105
106 106 add sub sub
107 107
108 108 $ echo ss = ss > s/.hgsub
109 109 $ hg init s/ss
110 110 $ echo a > s/ss/a
111 111 $ hg -R s add s/.hgsub
112 112 $ hg -R s/ss add s/ss/a
113 113 $ hg sum
114 114 parent: 1:7cf8cfea66e4 tip
115 115 1
116 116 branch: default
117 117 commit: 1 subrepos
118 118 update: (current)
119 119 phases: 2 draft
120 120 $ hg ci -m2
121 121 committing subrepository s
122 122 committing subrepository s/ss (glob)
123 123 $ hg sum
124 124 parent: 2:df30734270ae tip
125 125 2
126 126 branch: default
127 127 commit: (clean)
128 128 update: (current)
129 129 phases: 3 draft
130 130
131 131 test handling .hgsubstate "modified" explicitly.
132 132
133 133 $ hg parents --template '{node}\n{files}\n'
134 134 df30734270ae757feb35e643b7018e818e78a9aa
135 135 .hgsubstate
136 136 $ hg rollback -q
137 137 $ hg status -A .hgsubstate
138 138 M .hgsubstate
139 139 $ hg ci -m2
140 140 $ hg parents --template '{node}\n{files}\n'
141 141 df30734270ae757feb35e643b7018e818e78a9aa
142 142 .hgsubstate
143 143
144 144 bump sub rev (and check it is ignored by ui.commitsubrepos)
145 145
146 146 $ echo b > s/a
147 147 $ hg -R s ci -ms1
148 148 $ hg --config ui.commitsubrepos=no ci -m3
149 149
150 150 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
151 151
152 152 $ echo c > s/a
153 153 $ hg --config ui.commitsubrepos=no ci -m4
154 154 abort: uncommitted changes in subrepository 's'
155 155 (use --subrepos for recursive commit)
156 156 [255]
157 157 $ hg id
158 158 f6affe3fbfaa+ tip
159 159 $ hg -R s ci -mc
160 160 $ hg id
161 161 f6affe3fbfaa+ tip
162 162 $ echo d > s/a
163 163 $ hg ci -m4
164 164 committing subrepository s
165 165 $ hg tip -R s
166 166 changeset: 4:02dcf1d70411
167 167 tag: tip
168 168 user: test
169 169 date: Thu Jan 01 00:00:00 1970 +0000
170 170 summary: 4
171 171
172 172
173 173 check caching
174 174
175 175 $ hg co 0
176 176 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
177 177 $ hg debugsub
178 178
179 179 restore
180 180
181 181 $ hg co
182 182 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
183 183 $ hg debugsub
184 184 path s
185 185 source s
186 186 revision 02dcf1d704118aee3ee306ccfa1910850d5b05ef
187 187
188 188 new branch for merge tests
189 189
190 190 $ hg co 1
191 191 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
192 192 $ echo t = t >> .hgsub
193 193 $ hg init t
194 194 $ echo t > t/t
195 195 $ hg -R t add t
196 196 adding t/t (glob)
197 197
198 198 5
199 199
200 200 $ hg ci -m5 # add sub
201 201 committing subrepository t
202 202 created new head
203 203 $ echo t2 > t/t
204 204
205 205 6
206 206
207 207 $ hg st -R s
208 208 $ hg ci -m6 # change sub
209 209 committing subrepository t
210 210 $ hg debugsub
211 211 path s
212 212 source s
213 213 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
214 214 path t
215 215 source t
216 216 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
217 217 $ echo t3 > t/t
218 218
219 219 7
220 220
221 221 $ hg ci -m7 # change sub again for conflict test
222 222 committing subrepository t
223 223 $ hg rm .hgsub
224 224
225 225 8
226 226
227 227 $ hg ci -m8 # remove sub
228 228
229 229 test handling .hgsubstate "removed" explicitly.
230 230
231 231 $ hg parents --template '{node}\n{files}\n'
232 232 96615c1dad2dc8e3796d7332c77ce69156f7b78e
233 233 .hgsub .hgsubstate
234 234 $ hg rollback -q
235 235 $ hg remove .hgsubstate
236 236 $ hg ci -m8
237 237 $ hg parents --template '{node}\n{files}\n'
238 238 96615c1dad2dc8e3796d7332c77ce69156f7b78e
239 239 .hgsub .hgsubstate
240 240
241 241 merge tests
242 242
243 243 $ hg co -C 3
244 244 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
245 245 $ hg merge 5 # test adding
246 246 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
247 247 (branch merge, don't forget to commit)
248 248 $ hg debugsub
249 249 path s
250 250 source s
251 251 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
252 252 path t
253 253 source t
254 254 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
255 255 $ hg ci -m9
256 256 created new head
257 257 $ hg merge 6 --debug # test change
258 258 searching for copies back to rev 2
259 259 resolving manifests
260 260 branchmerge: True, force: False, partial: False
261 261 ancestor: 1f14a2e2d3ec, local: f0d2028bf86d+, remote: 1831e14459c4
262 262 .hgsubstate: versions differ -> m
263 263 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
264 264 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
265 265 getting subrepo t
266 266 resolving manifests
267 267 branchmerge: False, force: False, partial: False
268 268 ancestor: 60ca1237c194, local: 60ca1237c194+, remote: 6747d179aa9a
269 269 t: remote is newer -> g
270 270 getting t
271 271 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
272 272 (branch merge, don't forget to commit)
273 273 $ hg debugsub
274 274 path s
275 275 source s
276 276 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
277 277 path t
278 278 source t
279 279 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
280 280 $ echo conflict > t/t
281 281 $ hg ci -m10
282 282 committing subrepository t
283 283 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
284 284 searching for copies back to rev 2
285 285 resolving manifests
286 286 branchmerge: True, force: False, partial: False
287 287 ancestor: 1831e14459c4, local: e45c8b14af55+, remote: f94576341bcf
288 288 .hgsubstate: versions differ -> m
289 289 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
290 290 subrepo t: both sides changed
291 291 subrepository t diverged (local revision: 20a0db6fbf6c, remote revision: 7af322bc1198)
292 292 (M)erge, keep (l)ocal or keep (r)emote? m
293 293 merging subrepo t
294 294 searching for copies back to rev 2
295 295 resolving manifests
296 296 branchmerge: True, force: False, partial: False
297 297 ancestor: 6747d179aa9a, local: 20a0db6fbf6c+, remote: 7af322bc1198
298 298 preserving t for resolve of t
299 299 t: versions differ -> m
300 300 picked tool ':merge' for t (binary False symlink False)
301 301 merging t
302 302 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
303 picked tool ':merge' for t (binary False symlink False)
304 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
303 305 warning: conflicts during merge.
304 306 merging t incomplete! (edit conflicts, then use 'hg resolve --mark')
305 307 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
306 308 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
307 309 subrepo t: merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
308 310 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
309 311 (branch merge, don't forget to commit)
310 312
311 313 should conflict
312 314
313 315 $ cat t/t
314 316 <<<<<<< local: 20a0db6fbf6c - test: 10
315 317 conflict
316 318 =======
317 319 t3
318 320 >>>>>>> other: 7af322bc1198 - test: 7
319 321
320 322 11: remove subrepo t
321 323
322 324 $ hg co -C 5
323 325 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
324 326 $ hg revert -r 4 .hgsub # remove t
325 327 $ hg ci -m11
326 328 created new head
327 329 $ hg debugsub
328 330 path s
329 331 source s
330 332 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
331 333
332 334 local removed, remote changed, keep changed
333 335
334 336 $ hg merge 6
335 337 remote changed subrepository t which local removed
336 338 use (c)hanged version or (d)elete? c
337 339 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
338 340 (branch merge, don't forget to commit)
339 341 BROKEN: should include subrepo t
340 342 $ hg debugsub
341 343 path s
342 344 source s
343 345 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
344 346 $ cat .hgsubstate
345 347 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
346 348 6747d179aa9a688023c4b0cad32e4c92bb7f34ad t
347 349 $ hg ci -m 'local removed, remote changed, keep changed'
348 350 BROKEN: should include subrepo t
349 351 $ hg debugsub
350 352 path s
351 353 source s
352 354 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
353 355 BROKEN: should include subrepo t
354 356 $ cat .hgsubstate
355 357 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
356 358 $ cat t/t
357 359 t2
358 360
359 361 local removed, remote changed, keep removed
360 362
361 363 $ hg co -C 11
362 364 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
363 365 $ hg merge --config ui.interactive=true 6 <<EOF
364 366 > d
365 367 > EOF
366 368 remote changed subrepository t which local removed
367 369 use (c)hanged version or (d)elete? d
368 370 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
369 371 (branch merge, don't forget to commit)
370 372 $ hg debugsub
371 373 path s
372 374 source s
373 375 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
374 376 $ cat .hgsubstate
375 377 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
376 378 $ hg ci -m 'local removed, remote changed, keep removed'
377 379 created new head
378 380 $ hg debugsub
379 381 path s
380 382 source s
381 383 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
382 384 $ cat .hgsubstate
383 385 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
384 386
385 387 local changed, remote removed, keep changed
386 388
387 389 $ hg co -C 6
388 390 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
389 391 $ hg merge 11
390 392 local changed subrepository t which remote removed
391 393 use (c)hanged version or (d)elete? c
392 394 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
393 395 (branch merge, don't forget to commit)
394 396 BROKEN: should include subrepo t
395 397 $ hg debugsub
396 398 path s
397 399 source s
398 400 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
399 401 BROKEN: should include subrepo t
400 402 $ cat .hgsubstate
401 403 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
402 404 $ hg ci -m 'local changed, remote removed, keep changed'
403 405 created new head
404 406 BROKEN: should include subrepo t
405 407 $ hg debugsub
406 408 path s
407 409 source s
408 410 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
409 411 BROKEN: should include subrepo t
410 412 $ cat .hgsubstate
411 413 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
412 414 $ cat t/t
413 415 t2
414 416
415 417 local changed, remote removed, keep removed
416 418
417 419 $ hg co -C 6
418 420 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
419 421 $ hg merge --config ui.interactive=true 11 <<EOF
420 422 > d
421 423 > EOF
422 424 local changed subrepository t which remote removed
423 425 use (c)hanged version or (d)elete? d
424 426 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 427 (branch merge, don't forget to commit)
426 428 $ hg debugsub
427 429 path s
428 430 source s
429 431 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
430 432 $ cat .hgsubstate
431 433 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
432 434 $ hg ci -m 'local changed, remote removed, keep removed'
433 435 created new head
434 436 $ hg debugsub
435 437 path s
436 438 source s
437 439 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
438 440 $ cat .hgsubstate
439 441 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
440 442
441 443 clean up to avoid having to fix up the tests below
442 444
443 445 $ hg co -C 10
444 446 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
445 447 $ cat >> $HGRCPATH <<EOF
446 448 > [extensions]
447 449 > strip=
448 450 > EOF
449 451 $ hg strip -r 11:15
450 452 saved backup bundle to $TESTTMP/t/.hg/strip-backup/*-backup.hg (glob)
451 453
452 454 clone
453 455
454 456 $ cd ..
455 457 $ hg clone t tc
456 458 updating to branch default
457 459 cloning subrepo s from $TESTTMP/t/s
458 460 cloning subrepo s/ss from $TESTTMP/t/s/ss (glob)
459 461 cloning subrepo t from $TESTTMP/t/t
460 462 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
461 463 $ cd tc
462 464 $ hg debugsub
463 465 path s
464 466 source s
465 467 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
466 468 path t
467 469 source t
468 470 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
469 471
470 472 push
471 473
472 474 $ echo bah > t/t
473 475 $ hg ci -m11
474 476 committing subrepository t
475 477 $ hg push
476 478 pushing to $TESTTMP/t (glob)
477 479 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
478 480 no changes made to subrepo s since last push to $TESTTMP/t/s
479 481 pushing subrepo t to $TESTTMP/t/t
480 482 searching for changes
481 483 adding changesets
482 484 adding manifests
483 485 adding file changes
484 486 added 1 changesets with 1 changes to 1 files
485 487 searching for changes
486 488 adding changesets
487 489 adding manifests
488 490 adding file changes
489 491 added 1 changesets with 1 changes to 1 files
490 492
491 493 push -f
492 494
493 495 $ echo bah > s/a
494 496 $ hg ci -m12
495 497 committing subrepository s
496 498 $ hg push
497 499 pushing to $TESTTMP/t (glob)
498 500 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
499 501 pushing subrepo s to $TESTTMP/t/s
500 502 searching for changes
501 503 abort: push creates new remote head 12a213df6fa9! (in subrepo s)
502 504 (merge or see "hg help push" for details about pushing new heads)
503 505 [255]
504 506 $ hg push -f
505 507 pushing to $TESTTMP/t (glob)
506 508 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
507 509 searching for changes
508 510 no changes found
509 511 pushing subrepo s to $TESTTMP/t/s
510 512 searching for changes
511 513 adding changesets
512 514 adding manifests
513 515 adding file changes
514 516 added 1 changesets with 1 changes to 1 files (+1 heads)
515 517 pushing subrepo t to $TESTTMP/t/t
516 518 searching for changes
517 519 no changes found
518 520 searching for changes
519 521 adding changesets
520 522 adding manifests
521 523 adding file changes
522 524 added 1 changesets with 1 changes to 1 files
523 525
524 526 check that unmodified subrepos are not pushed
525 527
526 528 $ hg clone . ../tcc
527 529 updating to branch default
528 530 cloning subrepo s from $TESTTMP/tc/s
529 531 cloning subrepo s/ss from $TESTTMP/tc/s/ss (glob)
530 532 cloning subrepo t from $TESTTMP/tc/t
531 533 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
532 534
533 535 the subrepos on the new clone have nothing to push to its source
534 536
535 537 $ hg push -R ../tcc .
536 538 pushing to .
537 539 no changes made to subrepo s/ss since last push to s/ss (glob)
538 540 no changes made to subrepo s since last push to s
539 541 no changes made to subrepo t since last push to t
540 542 searching for changes
541 543 no changes found
542 544 [1]
543 545
544 546 the subrepos on the source do not have a clean store versus the clone target
545 547 because they were never explicitly pushed to the source
546 548
547 549 $ hg push ../tcc
548 550 pushing to ../tcc
549 551 pushing subrepo s/ss to ../tcc/s/ss (glob)
550 552 searching for changes
551 553 no changes found
552 554 pushing subrepo s to ../tcc/s
553 555 searching for changes
554 556 no changes found
555 557 pushing subrepo t to ../tcc/t
556 558 searching for changes
557 559 no changes found
558 560 searching for changes
559 561 no changes found
560 562 [1]
561 563
562 564 after push their stores become clean
563 565
564 566 $ hg push ../tcc
565 567 pushing to ../tcc
566 568 no changes made to subrepo s/ss since last push to ../tcc/s/ss (glob)
567 569 no changes made to subrepo s since last push to ../tcc/s
568 570 no changes made to subrepo t since last push to ../tcc/t
569 571 searching for changes
570 572 no changes found
571 573 [1]
572 574
573 575 updating a subrepo to a different revision or changing
574 576 its working directory does not make its store dirty
575 577
576 578 $ hg -R s update '.^'
577 579 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
578 580 $ hg push
579 581 pushing to $TESTTMP/t (glob)
580 582 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
581 583 no changes made to subrepo s since last push to $TESTTMP/t/s
582 584 no changes made to subrepo t since last push to $TESTTMP/t/t
583 585 searching for changes
584 586 no changes found
585 587 [1]
586 588 $ echo foo >> s/a
587 589 $ hg push
588 590 pushing to $TESTTMP/t (glob)
589 591 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
590 592 no changes made to subrepo s since last push to $TESTTMP/t/s
591 593 no changes made to subrepo t since last push to $TESTTMP/t/t
592 594 searching for changes
593 595 no changes found
594 596 [1]
595 597 $ hg -R s update -C tip
596 598 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
597 599
598 600 committing into a subrepo makes its store (but not its parent's store) dirty
599 601
600 602 $ echo foo >> s/ss/a
601 603 $ hg -R s/ss commit -m 'test dirty store detection'
602 604
603 605 $ hg out -S -r `hg log -r tip -T "{node|short}"`
604 606 comparing with $TESTTMP/t (glob)
605 607 searching for changes
606 608 no changes found
607 609 comparing with $TESTTMP/t/s
608 610 searching for changes
609 611 no changes found
610 612 comparing with $TESTTMP/t/s/ss
611 613 searching for changes
612 614 changeset: 1:79ea5566a333
613 615 tag: tip
614 616 user: test
615 617 date: Thu Jan 01 00:00:00 1970 +0000
616 618 summary: test dirty store detection
617 619
618 620 comparing with $TESTTMP/t/t
619 621 searching for changes
620 622 no changes found
621 623
622 624 $ hg push
623 625 pushing to $TESTTMP/t (glob)
624 626 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
625 627 searching for changes
626 628 adding changesets
627 629 adding manifests
628 630 adding file changes
629 631 added 1 changesets with 1 changes to 1 files
630 632 no changes made to subrepo s since last push to $TESTTMP/t/s
631 633 no changes made to subrepo t since last push to $TESTTMP/t/t
632 634 searching for changes
633 635 no changes found
634 636 [1]
635 637
636 638 a subrepo store may be clean versus one repo but not versus another
637 639
638 640 $ hg push
639 641 pushing to $TESTTMP/t (glob)
640 642 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
641 643 no changes made to subrepo s since last push to $TESTTMP/t/s
642 644 no changes made to subrepo t since last push to $TESTTMP/t/t
643 645 searching for changes
644 646 no changes found
645 647 [1]
646 648 $ hg push ../tcc
647 649 pushing to ../tcc
648 650 pushing subrepo s/ss to ../tcc/s/ss (glob)
649 651 searching for changes
650 652 adding changesets
651 653 adding manifests
652 654 adding file changes
653 655 added 1 changesets with 1 changes to 1 files
654 656 no changes made to subrepo s since last push to ../tcc/s
655 657 no changes made to subrepo t since last push to ../tcc/t
656 658 searching for changes
657 659 no changes found
658 660 [1]
659 661
660 662 update
661 663
662 664 $ cd ../t
663 665 $ hg up -C # discard our earlier merge
664 666 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
665 667 $ echo blah > t/t
666 668 $ hg ci -m13
667 669 committing subrepository t
668 670
669 671 backout calls revert internally with minimal opts, which should not raise
670 672 KeyError
671 673
672 674 $ hg backout ".^"
673 675 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
674 676 changeset c373c8102e68 backed out, don't forget to commit.
675 677
676 678 $ hg up -C # discard changes
677 679 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
678 680
679 681 pull
680 682
681 683 $ cd ../tc
682 684 $ hg pull
683 685 pulling from $TESTTMP/t (glob)
684 686 searching for changes
685 687 adding changesets
686 688 adding manifests
687 689 adding file changes
688 690 added 1 changesets with 1 changes to 1 files
689 691 (run 'hg update' to get a working copy)
690 692
691 693 should pull t
692 694
693 695 $ hg incoming -S -r `hg log -r tip -T "{node|short}"`
694 696 comparing with $TESTTMP/t (glob)
695 697 no changes found
696 698 comparing with $TESTTMP/t/s
697 699 searching for changes
698 700 no changes found
699 701 comparing with $TESTTMP/t/s/ss
700 702 searching for changes
701 703 no changes found
702 704 comparing with $TESTTMP/t/t
703 705 searching for changes
704 706 changeset: 5:52c0adc0515a
705 707 tag: tip
706 708 user: test
707 709 date: Thu Jan 01 00:00:00 1970 +0000
708 710 summary: 13
709 711
710 712
711 713 $ hg up
712 714 pulling subrepo t from $TESTTMP/t/t
713 715 searching for changes
714 716 adding changesets
715 717 adding manifests
716 718 adding file changes
717 719 added 1 changesets with 1 changes to 1 files
718 720 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
719 721 $ cat t/t
720 722 blah
721 723
722 724 bogus subrepo path aborts
723 725
724 726 $ echo 'bogus=[boguspath' >> .hgsub
725 727 $ hg ci -m 'bogus subrepo path'
726 728 abort: missing ] in subrepo source
727 729 [255]
728 730
729 731 Issue1986: merge aborts when trying to merge a subrepo that
730 732 shouldn't need merging
731 733
732 734 # subrepo layout
733 735 #
734 736 # o 5 br
735 737 # /|
736 738 # o | 4 default
737 739 # | |
738 740 # | o 3 br
739 741 # |/|
740 742 # o | 2 default
741 743 # | |
742 744 # | o 1 br
743 745 # |/
744 746 # o 0 default
745 747
746 748 $ cd ..
747 749 $ rm -rf sub
748 750 $ hg init main
749 751 $ cd main
750 752 $ hg init s
751 753 $ cd s
752 754 $ echo a > a
753 755 $ hg ci -Am1
754 756 adding a
755 757 $ hg branch br
756 758 marked working directory as branch br
757 759 (branches are permanent and global, did you want a bookmark?)
758 760 $ echo a >> a
759 761 $ hg ci -m1
760 762 $ hg up default
761 763 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
762 764 $ echo b > b
763 765 $ hg ci -Am1
764 766 adding b
765 767 $ hg up br
766 768 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
767 769 $ hg merge tip
768 770 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
769 771 (branch merge, don't forget to commit)
770 772 $ hg ci -m1
771 773 $ hg up 2
772 774 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
773 775 $ echo c > c
774 776 $ hg ci -Am1
775 777 adding c
776 778 $ hg up 3
777 779 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
778 780 $ hg merge 4
779 781 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
780 782 (branch merge, don't forget to commit)
781 783 $ hg ci -m1
782 784
783 785 # main repo layout:
784 786 #
785 787 # * <-- try to merge default into br again
786 788 # .`|
787 789 # . o 5 br --> substate = 5
788 790 # . |
789 791 # o | 4 default --> substate = 4
790 792 # | |
791 793 # | o 3 br --> substate = 2
792 794 # |/|
793 795 # o | 2 default --> substate = 2
794 796 # | |
795 797 # | o 1 br --> substate = 3
796 798 # |/
797 799 # o 0 default --> substate = 2
798 800
799 801 $ cd ..
800 802 $ echo 's = s' > .hgsub
801 803 $ hg -R s up 2
802 804 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
803 805 $ hg ci -Am1
804 806 adding .hgsub
805 807 $ hg branch br
806 808 marked working directory as branch br
807 809 (branches are permanent and global, did you want a bookmark?)
808 810 $ echo b > b
809 811 $ hg -R s up 3
810 812 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
811 813 $ hg ci -Am1
812 814 adding b
813 815 $ hg up default
814 816 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
815 817 $ echo c > c
816 818 $ hg ci -Am1
817 819 adding c
818 820 $ hg up 1
819 821 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
820 822 $ hg merge 2
821 823 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
822 824 (branch merge, don't forget to commit)
823 825 $ hg ci -m1
824 826 $ hg up 2
825 827 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
826 828 $ hg -R s up 4
827 829 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
828 830 $ echo d > d
829 831 $ hg ci -Am1
830 832 adding d
831 833 $ hg up 3
832 834 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
833 835 $ hg -R s up 5
834 836 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
835 837 $ echo e > e
836 838 $ hg ci -Am1
837 839 adding e
838 840
839 841 $ hg up 5
840 842 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
841 843 $ hg merge 4 # try to merge default into br again
842 844 subrepository s diverged (local revision: f8f13b33206e, remote revision: a3f9062a4f88)
843 845 (M)erge, keep (l)ocal or keep (r)emote? m
844 846 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
845 847 (branch merge, don't forget to commit)
846 848 $ cd ..
847 849
848 850 test subrepo delete from .hgsubstate
849 851
850 852 $ hg init testdelete
851 853 $ mkdir testdelete/nested testdelete/nested2
852 854 $ hg init testdelete/nested
853 855 $ hg init testdelete/nested2
854 856 $ echo test > testdelete/nested/foo
855 857 $ echo test > testdelete/nested2/foo
856 858 $ hg -R testdelete/nested add
857 859 adding testdelete/nested/foo (glob)
858 860 $ hg -R testdelete/nested2 add
859 861 adding testdelete/nested2/foo (glob)
860 862 $ hg -R testdelete/nested ci -m test
861 863 $ hg -R testdelete/nested2 ci -m test
862 864 $ echo nested = nested > testdelete/.hgsub
863 865 $ echo nested2 = nested2 >> testdelete/.hgsub
864 866 $ hg -R testdelete add
865 867 adding testdelete/.hgsub (glob)
866 868 $ hg -R testdelete ci -m "nested 1 & 2 added"
867 869 $ echo nested = nested > testdelete/.hgsub
868 870 $ hg -R testdelete ci -m "nested 2 deleted"
869 871 $ cat testdelete/.hgsubstate
870 872 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
871 873 $ hg -R testdelete remove testdelete/.hgsub
872 874 $ hg -R testdelete ci -m ".hgsub deleted"
873 875 $ cat testdelete/.hgsubstate
874 876 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
875 877
876 878 test repository cloning
877 879
878 880 $ mkdir mercurial mercurial2
879 881 $ hg init nested_absolute
880 882 $ echo test > nested_absolute/foo
881 883 $ hg -R nested_absolute add
882 884 adding nested_absolute/foo (glob)
883 885 $ hg -R nested_absolute ci -mtest
884 886 $ cd mercurial
885 887 $ hg init nested_relative
886 888 $ echo test2 > nested_relative/foo2
887 889 $ hg -R nested_relative add
888 890 adding nested_relative/foo2 (glob)
889 891 $ hg -R nested_relative ci -mtest2
890 892 $ hg init main
891 893 $ echo "nested_relative = ../nested_relative" > main/.hgsub
892 894 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
893 895 $ hg -R main add
894 896 adding main/.hgsub (glob)
895 897 $ hg -R main ci -m "add subrepos"
896 898 $ cd ..
897 899 $ hg clone mercurial/main mercurial2/main
898 900 updating to branch default
899 901 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
900 902 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
901 903 > mercurial2/main/nested_relative/.hg/hgrc
902 904 [paths]
903 905 default = $TESTTMP/mercurial/nested_absolute
904 906 [paths]
905 907 default = $TESTTMP/mercurial/nested_relative
906 908 $ rm -rf mercurial mercurial2
907 909
908 910 Issue1977: multirepo push should fail if subrepo push fails
909 911
910 912 $ hg init repo
911 913 $ hg init repo/s
912 914 $ echo a > repo/s/a
913 915 $ hg -R repo/s ci -Am0
914 916 adding a
915 917 $ echo s = s > repo/.hgsub
916 918 $ hg -R repo ci -Am1
917 919 adding .hgsub
918 920 $ hg clone repo repo2
919 921 updating to branch default
920 922 cloning subrepo s from $TESTTMP/repo/s
921 923 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
922 924 $ hg -q -R repo2 pull -u
923 925 $ echo 1 > repo2/s/a
924 926 $ hg -R repo2/s ci -m2
925 927 $ hg -q -R repo2/s push
926 928 $ hg -R repo2/s up -C 0
927 929 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
928 930 $ echo 2 > repo2/s/b
929 931 $ hg -R repo2/s ci -m3 -A
930 932 adding b
931 933 created new head
932 934 $ hg -R repo2 ci -m3
933 935 $ hg -q -R repo2 push
934 936 abort: push creates new remote head cc505f09a8b2! (in subrepo s)
935 937 (merge or see "hg help push" for details about pushing new heads)
936 938 [255]
937 939 $ hg -R repo update
938 940 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
939 941
940 942 test if untracked file is not overwritten
941 943
942 944 (this also tests that updated .hgsubstate is treated as "modified",
943 945 when 'merge.update()' is aborted before 'merge.recordupdates()', even
944 946 if none of mode, size and timestamp of it isn't changed on the
945 947 filesystem (see also issue4583))
946 948
947 949 $ echo issue3276_ok > repo/s/b
948 950 $ hg -R repo2 push -f -q
949 951 $ touch -t 200001010000 repo/.hgsubstate
950 952
951 953 $ cat >> repo/.hg/hgrc <<EOF
952 954 > [fakedirstatewritetime]
953 955 > # emulate invoking dirstate.write() via repo.status()
954 956 > # at 2000-01-01 00:00
955 957 > fakenow = 200001010000
956 958 >
957 959 > [extensions]
958 960 > fakedirstatewritetime = $TESTDIR/fakedirstatewritetime.py
959 961 > EOF
960 962 $ hg -R repo update
961 963 b: untracked file differs
962 964 abort: untracked files in working directory differ from files in requested revision (in subrepo s)
963 965 [255]
964 966 $ cat >> repo/.hg/hgrc <<EOF
965 967 > [extensions]
966 968 > fakedirstatewritetime = !
967 969 > EOF
968 970
969 971 $ cat repo/s/b
970 972 issue3276_ok
971 973 $ rm repo/s/b
972 974 $ touch -t 200001010000 repo/.hgsubstate
973 975 $ hg -R repo revert --all
974 976 reverting repo/.hgsubstate (glob)
975 977 reverting subrepo s
976 978 $ hg -R repo update
977 979 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
978 980 $ cat repo/s/b
979 981 2
980 982 $ rm -rf repo2 repo
981 983
982 984
983 985 Issue1852 subrepos with relative paths always push/pull relative to default
984 986
985 987 Prepare a repo with subrepo
986 988
987 989 $ hg init issue1852a
988 990 $ cd issue1852a
989 991 $ hg init sub/repo
990 992 $ echo test > sub/repo/foo
991 993 $ hg -R sub/repo add sub/repo/foo
992 994 $ echo sub/repo = sub/repo > .hgsub
993 995 $ hg add .hgsub
994 996 $ hg ci -mtest
995 997 committing subrepository sub/repo (glob)
996 998 $ echo test >> sub/repo/foo
997 999 $ hg ci -mtest
998 1000 committing subrepository sub/repo (glob)
999 1001 $ hg cat sub/repo/foo
1000 1002 test
1001 1003 test
1002 1004 $ mkdir -p tmp/sub/repo
1003 1005 $ hg cat -r 0 --output tmp/%p_p sub/repo/foo
1004 1006 $ cat tmp/sub/repo/foo_p
1005 1007 test
1006 1008 $ mv sub/repo sub_
1007 1009 $ hg cat sub/repo/baz
1008 1010 skipping missing subrepository: sub/repo
1009 1011 [1]
1010 1012 $ rm -rf sub/repo
1011 1013 $ mv sub_ sub/repo
1012 1014 $ cd ..
1013 1015
1014 1016 Create repo without default path, pull top repo, and see what happens on update
1015 1017
1016 1018 $ hg init issue1852b
1017 1019 $ hg -R issue1852b pull issue1852a
1018 1020 pulling from issue1852a
1019 1021 requesting all changes
1020 1022 adding changesets
1021 1023 adding manifests
1022 1024 adding file changes
1023 1025 added 2 changesets with 3 changes to 2 files
1024 1026 (run 'hg update' to get a working copy)
1025 1027 $ hg -R issue1852b update
1026 1028 abort: default path for subrepository not found (in subrepo sub/repo) (glob)
1027 1029 [255]
1028 1030
1029 1031 Ensure a full traceback, not just the SubrepoAbort part
1030 1032
1031 1033 $ hg -R issue1852b update --traceback 2>&1 | grep 'raise error\.Abort'
1032 1034 raise error.Abort(_("default path for subrepository not found"))
1033 1035
1034 1036 Pull -u now doesn't help
1035 1037
1036 1038 $ hg -R issue1852b pull -u issue1852a
1037 1039 pulling from issue1852a
1038 1040 searching for changes
1039 1041 no changes found
1040 1042
1041 1043 Try the same, but with pull -u
1042 1044
1043 1045 $ hg init issue1852c
1044 1046 $ hg -R issue1852c pull -r0 -u issue1852a
1045 1047 pulling from issue1852a
1046 1048 adding changesets
1047 1049 adding manifests
1048 1050 adding file changes
1049 1051 added 1 changesets with 2 changes to 2 files
1050 1052 cloning subrepo sub/repo from issue1852a/sub/repo (glob)
1051 1053 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1052 1054
1053 1055 Try to push from the other side
1054 1056
1055 1057 $ hg -R issue1852a push `pwd`/issue1852c
1056 1058 pushing to $TESTTMP/issue1852c (glob)
1057 1059 pushing subrepo sub/repo to $TESTTMP/issue1852c/sub/repo (glob)
1058 1060 searching for changes
1059 1061 no changes found
1060 1062 searching for changes
1061 1063 adding changesets
1062 1064 adding manifests
1063 1065 adding file changes
1064 1066 added 1 changesets with 1 changes to 1 files
1065 1067
1066 1068 Incoming and outgoing should not use the default path:
1067 1069
1068 1070 $ hg clone -q issue1852a issue1852d
1069 1071 $ hg -R issue1852d outgoing --subrepos issue1852c
1070 1072 comparing with issue1852c
1071 1073 searching for changes
1072 1074 no changes found
1073 1075 comparing with issue1852c/sub/repo
1074 1076 searching for changes
1075 1077 no changes found
1076 1078 [1]
1077 1079 $ hg -R issue1852d incoming --subrepos issue1852c
1078 1080 comparing with issue1852c
1079 1081 searching for changes
1080 1082 no changes found
1081 1083 comparing with issue1852c/sub/repo
1082 1084 searching for changes
1083 1085 no changes found
1084 1086 [1]
1085 1087
1086 1088 Check that merge of a new subrepo doesn't write the uncommitted state to
1087 1089 .hgsubstate (issue4622)
1088 1090
1089 1091 $ hg init issue1852a/addedsub
1090 1092 $ echo zzz > issue1852a/addedsub/zz.txt
1091 1093 $ hg -R issue1852a/addedsub ci -Aqm "initial ZZ"
1092 1094
1093 1095 $ hg clone issue1852a/addedsub issue1852d/addedsub
1094 1096 updating to branch default
1095 1097 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1096 1098
1097 1099 $ echo def > issue1852a/sub/repo/foo
1098 1100 $ hg -R issue1852a ci -SAm 'tweaked subrepo'
1099 1101 adding tmp/sub/repo/foo_p
1100 1102 committing subrepository sub/repo (glob)
1101 1103
1102 1104 $ echo 'addedsub = addedsub' >> issue1852d/.hgsub
1103 1105 $ echo xyz > issue1852d/sub/repo/foo
1104 1106 $ hg -R issue1852d pull -u
1105 1107 pulling from $TESTTMP/issue1852a (glob)
1106 1108 searching for changes
1107 1109 adding changesets
1108 1110 adding manifests
1109 1111 adding file changes
1110 1112 added 1 changesets with 2 changes to 2 files
1111 1113 subrepository sub/repo diverged (local revision: f42d5c7504a8, remote revision: 46cd4aac504c)
1112 1114 (M)erge, keep (l)ocal or keep (r)emote? m
1113 1115 pulling subrepo sub/repo from $TESTTMP/issue1852a/sub/repo (glob)
1114 1116 searching for changes
1115 1117 adding changesets
1116 1118 adding manifests
1117 1119 adding file changes
1118 1120 added 1 changesets with 1 changes to 1 files
1119 1121 subrepository sources for sub/repo differ (glob)
1120 1122 use (l)ocal source (f42d5c7504a8) or (r)emote source (46cd4aac504c)? l
1121 1123 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1122 1124 $ cat issue1852d/.hgsubstate
1123 1125 f42d5c7504a811dda50f5cf3e5e16c3330b87172 sub/repo
1124 1126
1125 1127 Check status of files when none of them belong to the first
1126 1128 subrepository:
1127 1129
1128 1130 $ hg init subrepo-status
1129 1131 $ cd subrepo-status
1130 1132 $ hg init subrepo-1
1131 1133 $ hg init subrepo-2
1132 1134 $ cd subrepo-2
1133 1135 $ touch file
1134 1136 $ hg add file
1135 1137 $ cd ..
1136 1138 $ echo subrepo-1 = subrepo-1 > .hgsub
1137 1139 $ echo subrepo-2 = subrepo-2 >> .hgsub
1138 1140 $ hg add .hgsub
1139 1141 $ hg ci -m 'Added subrepos'
1140 1142 committing subrepository subrepo-2
1141 1143 $ hg st subrepo-2/file
1142 1144
1143 1145 Check that share works with subrepo
1144 1146 $ hg --config extensions.share= share . ../shared
1145 1147 updating working directory
1146 1148 cloning subrepo subrepo-2 from $TESTTMP/subrepo-status/subrepo-2
1147 1149 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1148 1150 $ test -f ../shared/subrepo-1/.hg/sharedpath
1149 1151 [1]
1150 1152 $ hg -R ../shared in
1151 1153 abort: repository default not found!
1152 1154 [255]
1153 1155 $ hg -R ../shared/subrepo-2 showconfig paths
1154 1156 paths.default=$TESTTMP/subrepo-status/subrepo-2
1155 1157 $ hg -R ../shared/subrepo-1 sum --remote
1156 1158 parent: -1:000000000000 tip (empty repository)
1157 1159 branch: default
1158 1160 commit: (clean)
1159 1161 update: (current)
1160 1162 remote: (synced)
1161 1163
1162 1164 Check hg update --clean
1163 1165 $ cd $TESTTMP/t
1164 1166 $ rm -r t/t.orig
1165 1167 $ hg status -S --all
1166 1168 C .hgsub
1167 1169 C .hgsubstate
1168 1170 C a
1169 1171 C s/.hgsub
1170 1172 C s/.hgsubstate
1171 1173 C s/a
1172 1174 C s/ss/a
1173 1175 C t/t
1174 1176 $ echo c1 > s/a
1175 1177 $ cd s
1176 1178 $ echo c1 > b
1177 1179 $ echo c1 > c
1178 1180 $ hg add b
1179 1181 $ cd ..
1180 1182 $ hg status -S
1181 1183 M s/a
1182 1184 A s/b
1183 1185 ? s/c
1184 1186 $ hg update -C
1185 1187 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1186 1188 $ hg status -S
1187 1189 ? s/b
1188 1190 ? s/c
1189 1191
1190 1192 Sticky subrepositories, no changes
1191 1193 $ cd $TESTTMP/t
1192 1194 $ hg id
1193 1195 925c17564ef8 tip
1194 1196 $ hg -R s id
1195 1197 12a213df6fa9 tip
1196 1198 $ hg -R t id
1197 1199 52c0adc0515a tip
1198 1200 $ hg update 11
1199 1201 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1200 1202 $ hg id
1201 1203 365661e5936a
1202 1204 $ hg -R s id
1203 1205 fc627a69481f
1204 1206 $ hg -R t id
1205 1207 e95bcfa18a35
1206 1208
1207 1209 Sticky subrepositories, file changes
1208 1210 $ touch s/f1
1209 1211 $ touch t/f1
1210 1212 $ hg add -S s/f1
1211 1213 $ hg add -S t/f1
1212 1214 $ hg id
1213 1215 365661e5936a+
1214 1216 $ hg -R s id
1215 1217 fc627a69481f+
1216 1218 $ hg -R t id
1217 1219 e95bcfa18a35+
1218 1220 $ hg update tip
1219 1221 subrepository s diverged (local revision: fc627a69481f, remote revision: 12a213df6fa9)
1220 1222 (M)erge, keep (l)ocal or keep (r)emote? m
1221 1223 subrepository sources for s differ
1222 1224 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)? l
1223 1225 subrepository t diverged (local revision: e95bcfa18a35, remote revision: 52c0adc0515a)
1224 1226 (M)erge, keep (l)ocal or keep (r)emote? m
1225 1227 subrepository sources for t differ
1226 1228 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)? l
1227 1229 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1228 1230 $ hg id
1229 1231 925c17564ef8+ tip
1230 1232 $ hg -R s id
1231 1233 fc627a69481f+
1232 1234 $ hg -R t id
1233 1235 e95bcfa18a35+
1234 1236 $ hg update --clean tip
1235 1237 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1236 1238
1237 1239 Sticky subrepository, revision updates
1238 1240 $ hg id
1239 1241 925c17564ef8 tip
1240 1242 $ hg -R s id
1241 1243 12a213df6fa9 tip
1242 1244 $ hg -R t id
1243 1245 52c0adc0515a tip
1244 1246 $ cd s
1245 1247 $ hg update -r -2
1246 1248 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1247 1249 $ cd ../t
1248 1250 $ hg update -r 2
1249 1251 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1250 1252 $ cd ..
1251 1253 $ hg update 10
1252 1254 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
1253 1255 (M)erge, keep (l)ocal or keep (r)emote? m
1254 1256 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 20a0db6fbf6c)
1255 1257 (M)erge, keep (l)ocal or keep (r)emote? m
1256 1258 subrepository sources for t differ (in checked out version)
1257 1259 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)? l
1258 1260 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1259 1261 $ hg id
1260 1262 e45c8b14af55+
1261 1263 $ hg -R s id
1262 1264 02dcf1d70411
1263 1265 $ hg -R t id
1264 1266 7af322bc1198
1265 1267
1266 1268 Sticky subrepository, file changes and revision updates
1267 1269 $ touch s/f1
1268 1270 $ touch t/f1
1269 1271 $ hg add -S s/f1
1270 1272 $ hg add -S t/f1
1271 1273 $ hg id
1272 1274 e45c8b14af55+
1273 1275 $ hg -R s id
1274 1276 02dcf1d70411+
1275 1277 $ hg -R t id
1276 1278 7af322bc1198+
1277 1279 $ hg update tip
1278 1280 subrepository s diverged (local revision: 12a213df6fa9, remote revision: 12a213df6fa9)
1279 1281 (M)erge, keep (l)ocal or keep (r)emote? m
1280 1282 subrepository sources for s differ
1281 1283 use (l)ocal source (02dcf1d70411) or (r)emote source (12a213df6fa9)? l
1282 1284 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 52c0adc0515a)
1283 1285 (M)erge, keep (l)ocal or keep (r)emote? m
1284 1286 subrepository sources for t differ
1285 1287 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)? l
1286 1288 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1287 1289 $ hg id
1288 1290 925c17564ef8+ tip
1289 1291 $ hg -R s id
1290 1292 02dcf1d70411+
1291 1293 $ hg -R t id
1292 1294 7af322bc1198+
1293 1295
1294 1296 Sticky repository, update --clean
1295 1297 $ hg update --clean tip
1296 1298 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1297 1299 $ hg id
1298 1300 925c17564ef8 tip
1299 1301 $ hg -R s id
1300 1302 12a213df6fa9 tip
1301 1303 $ hg -R t id
1302 1304 52c0adc0515a tip
1303 1305
1304 1306 Test subrepo already at intended revision:
1305 1307 $ cd s
1306 1308 $ hg update fc627a69481f
1307 1309 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1308 1310 $ cd ..
1309 1311 $ hg update 11
1310 1312 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
1311 1313 (M)erge, keep (l)ocal or keep (r)emote? m
1312 1314 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1313 1315 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1314 1316 $ hg id -n
1315 1317 11+
1316 1318 $ hg -R s id
1317 1319 fc627a69481f
1318 1320 $ hg -R t id
1319 1321 e95bcfa18a35
1320 1322
1321 1323 Test that removing .hgsubstate doesn't break anything:
1322 1324
1323 1325 $ hg rm -f .hgsubstate
1324 1326 $ hg ci -mrm
1325 1327 nothing changed
1326 1328 [1]
1327 1329 $ hg log -vr tip
1328 1330 changeset: 13:925c17564ef8
1329 1331 tag: tip
1330 1332 user: test
1331 1333 date: Thu Jan 01 00:00:00 1970 +0000
1332 1334 files: .hgsubstate
1333 1335 description:
1334 1336 13
1335 1337
1336 1338
1337 1339
1338 1340 Test that removing .hgsub removes .hgsubstate:
1339 1341
1340 1342 $ hg rm .hgsub
1341 1343 $ hg ci -mrm2
1342 1344 created new head
1343 1345 $ hg log -vr tip
1344 1346 changeset: 14:2400bccd50af
1345 1347 tag: tip
1346 1348 parent: 11:365661e5936a
1347 1349 user: test
1348 1350 date: Thu Jan 01 00:00:00 1970 +0000
1349 1351 files: .hgsub .hgsubstate
1350 1352 description:
1351 1353 rm2
1352 1354
1353 1355
1354 1356 Test issue3153: diff -S with deleted subrepos
1355 1357
1356 1358 $ hg diff --nodates -S -c .
1357 1359 diff -r 365661e5936a -r 2400bccd50af .hgsub
1358 1360 --- a/.hgsub
1359 1361 +++ /dev/null
1360 1362 @@ -1,2 +0,0 @@
1361 1363 -s = s
1362 1364 -t = t
1363 1365 diff -r 365661e5936a -r 2400bccd50af .hgsubstate
1364 1366 --- a/.hgsubstate
1365 1367 +++ /dev/null
1366 1368 @@ -1,2 +0,0 @@
1367 1369 -fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1368 1370 -e95bcfa18a358dc4936da981ebf4147b4cad1362 t
1369 1371
1370 1372 Test behavior of add for explicit path in subrepo:
1371 1373 $ cd ..
1372 1374 $ hg init explicit
1373 1375 $ cd explicit
1374 1376 $ echo s = s > .hgsub
1375 1377 $ hg add .hgsub
1376 1378 $ hg init s
1377 1379 $ hg ci -m0
1378 1380 Adding with an explicit path in a subrepo adds the file
1379 1381 $ echo c1 > f1
1380 1382 $ echo c2 > s/f2
1381 1383 $ hg st -S
1382 1384 ? f1
1383 1385 ? s/f2
1384 1386 $ hg add s/f2
1385 1387 $ hg st -S
1386 1388 A s/f2
1387 1389 ? f1
1388 1390 $ hg ci -R s -m0
1389 1391 $ hg ci -Am1
1390 1392 adding f1
1391 1393 Adding with an explicit path in a subrepo with -S has the same behavior
1392 1394 $ echo c3 > f3
1393 1395 $ echo c4 > s/f4
1394 1396 $ hg st -S
1395 1397 ? f3
1396 1398 ? s/f4
1397 1399 $ hg add -S s/f4
1398 1400 $ hg st -S
1399 1401 A s/f4
1400 1402 ? f3
1401 1403 $ hg ci -R s -m1
1402 1404 $ hg ci -Ama2
1403 1405 adding f3
1404 1406 Adding without a path or pattern silently ignores subrepos
1405 1407 $ echo c5 > f5
1406 1408 $ echo c6 > s/f6
1407 1409 $ echo c7 > s/f7
1408 1410 $ hg st -S
1409 1411 ? f5
1410 1412 ? s/f6
1411 1413 ? s/f7
1412 1414 $ hg add
1413 1415 adding f5
1414 1416 $ hg st -S
1415 1417 A f5
1416 1418 ? s/f6
1417 1419 ? s/f7
1418 1420 $ hg ci -R s -Am2
1419 1421 adding f6
1420 1422 adding f7
1421 1423 $ hg ci -m3
1422 1424 Adding without a path or pattern with -S also adds files in subrepos
1423 1425 $ echo c8 > f8
1424 1426 $ echo c9 > s/f9
1425 1427 $ echo c10 > s/f10
1426 1428 $ hg st -S
1427 1429 ? f8
1428 1430 ? s/f10
1429 1431 ? s/f9
1430 1432 $ hg add -S
1431 1433 adding f8
1432 1434 adding s/f10 (glob)
1433 1435 adding s/f9 (glob)
1434 1436 $ hg st -S
1435 1437 A f8
1436 1438 A s/f10
1437 1439 A s/f9
1438 1440 $ hg ci -R s -m3
1439 1441 $ hg ci -m4
1440 1442 Adding with a pattern silently ignores subrepos
1441 1443 $ echo c11 > fm11
1442 1444 $ echo c12 > fn12
1443 1445 $ echo c13 > s/fm13
1444 1446 $ echo c14 > s/fn14
1445 1447 $ hg st -S
1446 1448 ? fm11
1447 1449 ? fn12
1448 1450 ? s/fm13
1449 1451 ? s/fn14
1450 1452 $ hg add 'glob:**fm*'
1451 1453 adding fm11
1452 1454 $ hg st -S
1453 1455 A fm11
1454 1456 ? fn12
1455 1457 ? s/fm13
1456 1458 ? s/fn14
1457 1459 $ hg ci -R s -Am4
1458 1460 adding fm13
1459 1461 adding fn14
1460 1462 $ hg ci -Am5
1461 1463 adding fn12
1462 1464 Adding with a pattern with -S also adds matches in subrepos
1463 1465 $ echo c15 > fm15
1464 1466 $ echo c16 > fn16
1465 1467 $ echo c17 > s/fm17
1466 1468 $ echo c18 > s/fn18
1467 1469 $ hg st -S
1468 1470 ? fm15
1469 1471 ? fn16
1470 1472 ? s/fm17
1471 1473 ? s/fn18
1472 1474 $ hg add -S 'glob:**fm*'
1473 1475 adding fm15
1474 1476 adding s/fm17 (glob)
1475 1477 $ hg st -S
1476 1478 A fm15
1477 1479 A s/fm17
1478 1480 ? fn16
1479 1481 ? s/fn18
1480 1482 $ hg ci -R s -Am5
1481 1483 adding fn18
1482 1484 $ hg ci -Am6
1483 1485 adding fn16
1484 1486
1485 1487 Test behavior of forget for explicit path in subrepo:
1486 1488 Forgetting an explicit path in a subrepo untracks the file
1487 1489 $ echo c19 > s/f19
1488 1490 $ hg add s/f19
1489 1491 $ hg st -S
1490 1492 A s/f19
1491 1493 $ hg forget s/f19
1492 1494 $ hg st -S
1493 1495 ? s/f19
1494 1496 $ rm s/f19
1495 1497 $ cd ..
1496 1498
1497 1499 Courtesy phases synchronisation to publishing server does not block the push
1498 1500 (issue3781)
1499 1501
1500 1502 $ cp -r main issue3781
1501 1503 $ cp -r main issue3781-dest
1502 1504 $ cd issue3781-dest/s
1503 1505 $ hg phase tip # show we have draft changeset
1504 1506 5: draft
1505 1507 $ chmod a-w .hg/store/phaseroots # prevent phase push
1506 1508 $ cd ../../issue3781
1507 1509 $ cat >> .hg/hgrc << EOF
1508 1510 > [paths]
1509 1511 > default=../issue3781-dest/
1510 1512 > EOF
1511 1513 $ hg push --config experimental.bundle2-exp=False
1512 1514 pushing to $TESTTMP/issue3781-dest (glob)
1513 1515 pushing subrepo s to $TESTTMP/issue3781-dest/s
1514 1516 searching for changes
1515 1517 no changes found
1516 1518 searching for changes
1517 1519 no changes found
1518 1520 [1]
1519 1521 # clean the push cache
1520 1522 $ rm s/.hg/cache/storehash/*
1521 1523 $ hg push --config experimental.bundle2-exp=True
1522 1524 pushing to $TESTTMP/issue3781-dest (glob)
1523 1525 pushing subrepo s to $TESTTMP/issue3781-dest/s
1524 1526 searching for changes
1525 1527 no changes found
1526 1528 searching for changes
1527 1529 no changes found
1528 1530 [1]
1529 1531 $ cd ..
1530 1532
1531 1533 Test phase choice for newly created commit with "phases.subrepochecks"
1532 1534 configuration
1533 1535
1534 1536 $ cd t
1535 1537 $ hg update -q -r 12
1536 1538
1537 1539 $ cat >> s/ss/.hg/hgrc <<EOF
1538 1540 > [phases]
1539 1541 > new-commit = secret
1540 1542 > EOF
1541 1543 $ cat >> s/.hg/hgrc <<EOF
1542 1544 > [phases]
1543 1545 > new-commit = draft
1544 1546 > EOF
1545 1547 $ echo phasecheck1 >> s/ss/a
1546 1548 $ hg -R s commit -S --config phases.checksubrepos=abort -m phasecheck1
1547 1549 committing subrepository ss
1548 1550 transaction abort!
1549 1551 rollback completed
1550 1552 abort: can't commit in draft phase conflicting secret from subrepository ss
1551 1553 [255]
1552 1554 $ echo phasecheck2 >> s/ss/a
1553 1555 $ hg -R s commit -S --config phases.checksubrepos=ignore -m phasecheck2
1554 1556 committing subrepository ss
1555 1557 $ hg -R s/ss phase tip
1556 1558 3: secret
1557 1559 $ hg -R s phase tip
1558 1560 6: draft
1559 1561 $ echo phasecheck3 >> s/ss/a
1560 1562 $ hg -R s commit -S -m phasecheck3
1561 1563 committing subrepository ss
1562 1564 warning: changes are committed in secret phase from subrepository ss
1563 1565 $ hg -R s/ss phase tip
1564 1566 4: secret
1565 1567 $ hg -R s phase tip
1566 1568 7: secret
1567 1569
1568 1570 $ cat >> t/.hg/hgrc <<EOF
1569 1571 > [phases]
1570 1572 > new-commit = draft
1571 1573 > EOF
1572 1574 $ cat >> .hg/hgrc <<EOF
1573 1575 > [phases]
1574 1576 > new-commit = public
1575 1577 > EOF
1576 1578 $ echo phasecheck4 >> s/ss/a
1577 1579 $ echo phasecheck4 >> t/t
1578 1580 $ hg commit -S -m phasecheck4
1579 1581 committing subrepository s
1580 1582 committing subrepository s/ss (glob)
1581 1583 warning: changes are committed in secret phase from subrepository ss
1582 1584 committing subrepository t
1583 1585 warning: changes are committed in secret phase from subrepository s
1584 1586 created new head
1585 1587 $ hg -R s/ss phase tip
1586 1588 5: secret
1587 1589 $ hg -R s phase tip
1588 1590 8: secret
1589 1591 $ hg -R t phase tip
1590 1592 6: draft
1591 1593 $ hg phase tip
1592 1594 15: secret
1593 1595
1594 1596 $ cd ..
1595 1597
1596 1598
1597 1599 Test that commit --secret works on both repo and subrepo (issue4182)
1598 1600
1599 1601 $ cd main
1600 1602 $ echo secret >> b
1601 1603 $ echo secret >> s/b
1602 1604 $ hg commit --secret --subrepo -m "secret"
1603 1605 committing subrepository s
1604 1606 $ hg phase -r .
1605 1607 6: secret
1606 1608 $ cd s
1607 1609 $ hg phase -r .
1608 1610 6: secret
1609 1611 $ cd ../../
1610 1612
1611 1613 Test "subrepos" template keyword
1612 1614
1613 1615 $ cd t
1614 1616 $ hg update -q 15
1615 1617 $ cat > .hgsub <<EOF
1616 1618 > s = s
1617 1619 > EOF
1618 1620 $ hg commit -m "16"
1619 1621 warning: changes are committed in secret phase from subrepository s
1620 1622
1621 1623 (addition of ".hgsub" itself)
1622 1624
1623 1625 $ hg diff --nodates -c 1 .hgsubstate
1624 1626 diff -r f7b1eb17ad24 -r 7cf8cfea66e4 .hgsubstate
1625 1627 --- /dev/null
1626 1628 +++ b/.hgsubstate
1627 1629 @@ -0,0 +1,1 @@
1628 1630 +e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1629 1631 $ hg log -r 1 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1630 1632 f7b1eb17ad24 000000000000
1631 1633 s
1632 1634
1633 1635 (modification of existing entry)
1634 1636
1635 1637 $ hg diff --nodates -c 2 .hgsubstate
1636 1638 diff -r 7cf8cfea66e4 -r df30734270ae .hgsubstate
1637 1639 --- a/.hgsubstate
1638 1640 +++ b/.hgsubstate
1639 1641 @@ -1,1 +1,1 @@
1640 1642 -e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1641 1643 +dc73e2e6d2675eb2e41e33c205f4bdab4ea5111d s
1642 1644 $ hg log -r 2 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1643 1645 7cf8cfea66e4 000000000000
1644 1646 s
1645 1647
1646 1648 (addition of entry)
1647 1649
1648 1650 $ hg diff --nodates -c 5 .hgsubstate
1649 1651 diff -r 7cf8cfea66e4 -r 1f14a2e2d3ec .hgsubstate
1650 1652 --- a/.hgsubstate
1651 1653 +++ b/.hgsubstate
1652 1654 @@ -1,1 +1,2 @@
1653 1655 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1654 1656 +60ca1237c19474e7a3978b0dc1ca4e6f36d51382 t
1655 1657 $ hg log -r 5 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1656 1658 7cf8cfea66e4 000000000000
1657 1659 t
1658 1660
1659 1661 (removal of existing entry)
1660 1662
1661 1663 $ hg diff --nodates -c 16 .hgsubstate
1662 1664 diff -r 8bec38d2bd0b -r f2f70bc3d3c9 .hgsubstate
1663 1665 --- a/.hgsubstate
1664 1666 +++ b/.hgsubstate
1665 1667 @@ -1,2 +1,1 @@
1666 1668 0731af8ca9423976d3743119d0865097c07bdc1b s
1667 1669 -e202dc79b04c88a636ea8913d9182a1346d9b3dc t
1668 1670 $ hg log -r 16 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1669 1671 8bec38d2bd0b 000000000000
1670 1672 t
1671 1673
1672 1674 (merging)
1673 1675
1674 1676 $ hg diff --nodates -c 9 .hgsubstate
1675 1677 diff -r f6affe3fbfaa -r f0d2028bf86d .hgsubstate
1676 1678 --- a/.hgsubstate
1677 1679 +++ b/.hgsubstate
1678 1680 @@ -1,1 +1,2 @@
1679 1681 fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1680 1682 +60ca1237c19474e7a3978b0dc1ca4e6f36d51382 t
1681 1683 $ hg log -r 9 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1682 1684 f6affe3fbfaa 1f14a2e2d3ec
1683 1685 t
1684 1686
1685 1687 (removal of ".hgsub" itself)
1686 1688
1687 1689 $ hg diff --nodates -c 8 .hgsubstate
1688 1690 diff -r f94576341bcf -r 96615c1dad2d .hgsubstate
1689 1691 --- a/.hgsubstate
1690 1692 +++ /dev/null
1691 1693 @@ -1,2 +0,0 @@
1692 1694 -e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1693 1695 -7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4 t
1694 1696 $ hg log -r 8 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1695 1697 f94576341bcf 000000000000
1696 1698
1697 1699 Test that '[paths]' is configured correctly at subrepo creation
1698 1700
1699 1701 $ cd $TESTTMP/tc
1700 1702 $ cat > .hgsub <<EOF
1701 1703 > # to clear bogus subrepo path 'bogus=[boguspath'
1702 1704 > s = s
1703 1705 > t = t
1704 1706 > EOF
1705 1707 $ hg update -q --clean null
1706 1708 $ rm -rf s t
1707 1709 $ cat >> .hg/hgrc <<EOF
1708 1710 > [paths]
1709 1711 > default-push = /foo/bar
1710 1712 > EOF
1711 1713 $ hg update -q
1712 1714 $ cat s/.hg/hgrc
1713 1715 [paths]
1714 1716 default = $TESTTMP/t/s
1715 1717 default-push = /foo/bar/s
1716 1718 $ cat s/ss/.hg/hgrc
1717 1719 [paths]
1718 1720 default = $TESTTMP/t/s/ss
1719 1721 default-push = /foo/bar/s/ss
1720 1722 $ cat t/.hg/hgrc
1721 1723 [paths]
1722 1724 default = $TESTTMP/t/t
1723 1725 default-push = /foo/bar/t
1724 1726
1725 1727 $ cd $TESTTMP/t
1726 1728 $ hg up -qC 0
1727 1729 $ echo 'bar' > bar.txt
1728 1730 $ hg ci -Am 'branch before subrepo add'
1729 1731 adding bar.txt
1730 1732 created new head
1731 1733 $ hg merge -r "first(subrepo('s'))"
1732 1734 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1733 1735 (branch merge, don't forget to commit)
1734 1736 $ hg status -S -X '.hgsub*'
1735 1737 A s/a
1736 1738 ? s/b
1737 1739 ? s/c
1738 1740 ? s/f1
1739 1741 $ hg status -S --rev 'p2()'
1740 1742 A bar.txt
1741 1743 ? s/b
1742 1744 ? s/c
1743 1745 ? s/f1
1744 1746 $ hg diff -S -X '.hgsub*' --nodates
1745 1747 diff -r 000000000000 s/a
1746 1748 --- /dev/null
1747 1749 +++ b/s/a
1748 1750 @@ -0,0 +1,1 @@
1749 1751 +a
1750 1752 $ hg diff -S --rev 'p2()' --nodates
1751 1753 diff -r 7cf8cfea66e4 bar.txt
1752 1754 --- /dev/null
1753 1755 +++ b/bar.txt
1754 1756 @@ -0,0 +1,1 @@
1755 1757 +bar
1756 1758
1757 1759 $ cd ..
@@ -1,222 +1,228 b''
1 1 $ HGMERGE=true; export HGMERGE
2 2
3 3 $ hg init r1
4 4 $ cd r1
5 5 $ echo a > a
6 6 $ hg addremove
7 7 adding a
8 8 $ hg commit -m "1"
9 9
10 10 $ hg clone . ../r2
11 11 updating to branch default
12 12 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
13 13 $ cd ../r2
14 14 $ hg up
15 15 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 16 $ echo abc > a
17 17 $ hg diff --nodates
18 18 diff -r c19d34741b0a a
19 19 --- a/a
20 20 +++ b/a
21 21 @@ -1,1 +1,1 @@
22 22 -a
23 23 +abc
24 24
25 25 $ cd ../r1
26 26 $ echo b > b
27 27 $ echo a2 > a
28 28 $ hg addremove
29 29 adding b
30 30 $ hg commit -m "2"
31 31
32 32 $ cd ../r2
33 33 $ hg -q pull ../r1
34 34 $ hg status
35 35 M a
36 36 $ hg parents
37 37 changeset: 0:c19d34741b0a
38 38 user: test
39 39 date: Thu Jan 01 00:00:00 1970 +0000
40 40 summary: 1
41 41
42 42 $ hg --debug up
43 43 searching for copies back to rev 1
44 44 unmatched files in other:
45 45 b
46 46 resolving manifests
47 47 branchmerge: False, force: False, partial: False
48 48 ancestor: c19d34741b0a, local: c19d34741b0a+, remote: 1e71731e6fbb
49 49 preserving a for resolve of a
50 50 b: remote created -> g
51 51 getting b
52 52 a: versions differ -> m
53 53 picked tool 'true' for a (binary False symlink False)
54 54 merging a
55 55 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
56 launching merge tool: true *$TESTTMP/r2/a* * (glob)
56 picked tool 'true' for a (binary False symlink False)
57 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
58 launching merge tool: true *$TESTTMP/r2/a* * * (glob)
57 59 merge tool returned: 0
58 60 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
59 61 $ hg parents
60 62 changeset: 1:1e71731e6fbb
61 63 tag: tip
62 64 user: test
63 65 date: Thu Jan 01 00:00:00 1970 +0000
64 66 summary: 2
65 67
66 68 $ hg --debug up 0
67 69 resolving manifests
68 70 branchmerge: False, force: False, partial: False
69 71 ancestor: 1e71731e6fbb, local: 1e71731e6fbb+, remote: c19d34741b0a
70 72 preserving a for resolve of a
71 73 b: other deleted -> r
72 74 removing b
73 75 a: versions differ -> m
74 76 picked tool 'true' for a (binary False symlink False)
75 77 merging a
76 78 my a@1e71731e6fbb+ other a@c19d34741b0a ancestor a@1e71731e6fbb
77 launching merge tool: true *$TESTTMP/r2/a* * (glob)
79 picked tool 'true' for a (binary False symlink False)
80 my a@1e71731e6fbb+ other a@c19d34741b0a ancestor a@1e71731e6fbb
81 launching merge tool: true *$TESTTMP/r2/a* * * (glob)
78 82 merge tool returned: 0
79 83 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
80 84 $ hg parents
81 85 changeset: 0:c19d34741b0a
82 86 user: test
83 87 date: Thu Jan 01 00:00:00 1970 +0000
84 88 summary: 1
85 89
86 90 $ hg parents
87 91 changeset: 0:c19d34741b0a
88 92 user: test
89 93 date: Thu Jan 01 00:00:00 1970 +0000
90 94 summary: 1
91 95
92 96 $ hg --debug up
93 97 searching for copies back to rev 1
94 98 unmatched files in other:
95 99 b
96 100 resolving manifests
97 101 branchmerge: False, force: False, partial: False
98 102 ancestor: c19d34741b0a, local: c19d34741b0a+, remote: 1e71731e6fbb
99 103 preserving a for resolve of a
100 104 b: remote created -> g
101 105 getting b
102 106 a: versions differ -> m
103 107 picked tool 'true' for a (binary False symlink False)
104 108 merging a
105 109 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
106 launching merge tool: true *$TESTTMP/r2/a* * (glob)
110 picked tool 'true' for a (binary False symlink False)
111 my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
112 launching merge tool: true *$TESTTMP/r2/a* * * (glob)
107 113 merge tool returned: 0
108 114 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
109 115 $ hg parents
110 116 changeset: 1:1e71731e6fbb
111 117 tag: tip
112 118 user: test
113 119 date: Thu Jan 01 00:00:00 1970 +0000
114 120 summary: 2
115 121
116 122 $ hg -v history
117 123 changeset: 1:1e71731e6fbb
118 124 tag: tip
119 125 user: test
120 126 date: Thu Jan 01 00:00:00 1970 +0000
121 127 files: a b
122 128 description:
123 129 2
124 130
125 131
126 132 changeset: 0:c19d34741b0a
127 133 user: test
128 134 date: Thu Jan 01 00:00:00 1970 +0000
129 135 files: a
130 136 description:
131 137 1
132 138
133 139
134 140 $ hg diff --nodates
135 141 diff -r 1e71731e6fbb a
136 142 --- a/a
137 143 +++ b/a
138 144 @@ -1,1 +1,1 @@
139 145 -a2
140 146 +abc
141 147
142 148
143 149 create a second head
144 150
145 151 $ cd ../r1
146 152 $ hg up 0
147 153 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
148 154 $ echo b2 > b
149 155 $ echo a3 > a
150 156 $ hg addremove
151 157 adding b
152 158 $ hg commit -m "3"
153 159 created new head
154 160
155 161 $ cd ../r2
156 162 $ hg -q pull ../r1
157 163 $ hg status
158 164 M a
159 165 $ hg parents
160 166 changeset: 1:1e71731e6fbb
161 167 user: test
162 168 date: Thu Jan 01 00:00:00 1970 +0000
163 169 summary: 2
164 170
165 171 $ hg --debug up
166 172 abort: uncommitted changes
167 173 (commit and merge, or update --clean to discard changes)
168 174 [255]
169 175
170 176 test conflicting untracked files
171 177
172 178 $ hg up -qC 0
173 179 $ echo untracked > b
174 180 $ hg st
175 181 ? b
176 182 $ hg up 1
177 183 b: untracked file differs
178 184 abort: untracked files in working directory differ from files in requested revision
179 185 [255]
180 186 $ rm b
181 187
182 188 test conflicting untracked ignored file
183 189
184 190 $ hg up -qC 0
185 191 $ echo ignored > .hgignore
186 192 $ hg add .hgignore
187 193 $ hg ci -m 'add .hgignore'
188 194 created new head
189 195 $ echo ignored > ignored
190 196 $ hg add ignored
191 197 $ hg ci -m 'add ignored file'
192 198
193 199 $ hg up -q 'desc("add .hgignore")'
194 200 $ echo untracked > ignored
195 201 $ hg st
196 202 $ hg up 'desc("add ignored file")'
197 203 ignored: untracked file differs
198 204 abort: untracked files in working directory differ from files in requested revision
199 205 [255]
200 206
201 207 test a local add
202 208
203 209 $ cd ..
204 210 $ hg init a
205 211 $ hg init b
206 212 $ echo a > a/a
207 213 $ echo a > b/a
208 214 $ hg --cwd a commit -A -m a
209 215 adding a
210 216 $ cd b
211 217 $ hg add a
212 218 $ hg pull -u ../a
213 219 pulling from ../a
214 220 requesting all changes
215 221 adding changesets
216 222 adding manifests
217 223 adding file changes
218 224 added 1 changesets with 1 changes to 1 files
219 225 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
220 226 $ hg st
221 227
222 228 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now