##// END OF EJS Templates
filemerge: print correct name of tool for symlink checks...
Siddharth Agarwal -
r26518:a77679d0 default
parent child Browse files
Show More
@@ -1,566 +1,566
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 def internaltool(name, trymerge, onfailure=None, precheck=None):
42 42 '''return a decorator for populating internal merge tool table'''
43 43 def decorator(func):
44 44 fullname = ':' + name
45 45 func.__doc__ = "``%s``\n" % fullname + func.__doc__.strip()
46 46 internals[fullname] = func
47 47 internals['internal:' + name] = func
48 48 internalsdoc[fullname] = func
49 49 func.trymerge = trymerge
50 50 func.onfailure = onfailure
51 51 func.precheck = precheck
52 52 return func
53 53 return decorator
54 54
55 55 def _findtool(ui, tool):
56 56 if tool in internals:
57 57 return tool
58 58 return findexternaltool(ui, tool)
59 59
60 60 def findexternaltool(ui, tool):
61 61 for kn in ("regkey", "regkeyalt"):
62 62 k = _toolstr(ui, tool, kn)
63 63 if not k:
64 64 continue
65 65 p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
66 66 if p:
67 67 p = util.findexe(p + _toolstr(ui, tool, "regappend"))
68 68 if p:
69 69 return p
70 70 exe = _toolstr(ui, tool, "executable", tool)
71 71 return util.findexe(util.expandpath(exe))
72 72
73 73 def _picktool(repo, ui, path, binary, symlink):
74 74 def check(tool, pat, symlink, binary):
75 75 tmsg = tool
76 76 if pat:
77 77 tmsg += " specified for " + pat
78 78 if not _findtool(ui, tool):
79 79 if pat: # explicitly requested tool deserves a warning
80 80 ui.warn(_("couldn't find merge tool %s\n") % tmsg)
81 81 else: # configured but non-existing tools are more silent
82 82 ui.note(_("couldn't find merge tool %s\n") % tmsg)
83 83 elif symlink and not _toolbool(ui, tool, "symlink"):
84 84 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
85 85 elif binary and not _toolbool(ui, tool, "binary"):
86 86 ui.warn(_("tool %s can't handle binary\n") % tmsg)
87 87 elif not util.gui() and _toolbool(ui, tool, "gui"):
88 88 ui.warn(_("tool %s requires a GUI\n") % tmsg)
89 89 else:
90 90 return True
91 91 return False
92 92
93 93 # internal config: ui.forcemerge
94 94 # forcemerge comes from command line arguments, highest priority
95 95 force = ui.config('ui', 'forcemerge')
96 96 if force:
97 97 toolpath = _findtool(ui, force)
98 98 if toolpath:
99 99 return (force, util.shellquote(toolpath))
100 100 else:
101 101 # mimic HGMERGE if given tool not found
102 102 return (force, force)
103 103
104 104 # HGMERGE takes next precedence
105 105 hgmerge = os.environ.get("HGMERGE")
106 106 if hgmerge:
107 107 return (hgmerge, hgmerge)
108 108
109 109 # then patterns
110 110 for pat, tool in ui.configitems("merge-patterns"):
111 111 mf = match.match(repo.root, '', [pat])
112 112 if mf(path) and check(tool, pat, symlink, False):
113 113 toolpath = _findtool(ui, tool)
114 114 return (tool, util.shellquote(toolpath))
115 115
116 116 # then merge tools
117 117 tools = {}
118 118 for k, v in ui.configitems("merge-tools"):
119 119 t = k.split('.')[0]
120 120 if t not in tools:
121 121 tools[t] = int(_toolstr(ui, t, "priority", "0"))
122 122 names = tools.keys()
123 123 tools = sorted([(-p, t) for t, p in tools.items()])
124 124 uimerge = ui.config("ui", "merge")
125 125 if uimerge:
126 126 if uimerge not in names:
127 127 return (uimerge, uimerge)
128 128 tools.insert(0, (None, uimerge)) # highest priority
129 129 tools.append((None, "hgmerge")) # the old default, if found
130 130 for p, t in tools:
131 131 if check(t, None, symlink, binary):
132 132 toolpath = _findtool(ui, t)
133 133 return (t, util.shellquote(toolpath))
134 134
135 135 # internal merge or prompt as last resort
136 136 if symlink or binary:
137 137 return ":prompt", None
138 138 return ":merge", None
139 139
140 140 def _eoltype(data):
141 141 "Guess the EOL type of a file"
142 142 if '\0' in data: # binary
143 143 return None
144 144 if '\r\n' in data: # Windows
145 145 return '\r\n'
146 146 if '\r' in data: # Old Mac
147 147 return '\r'
148 148 if '\n' in data: # UNIX
149 149 return '\n'
150 150 return None # unknown
151 151
152 152 def _matcheol(file, origfile):
153 153 "Convert EOL markers in a file to match origfile"
154 154 tostyle = _eoltype(util.readfile(origfile))
155 155 if tostyle:
156 156 data = util.readfile(file)
157 157 style = _eoltype(data)
158 158 if style:
159 159 newdata = data.replace(style, tostyle)
160 160 if newdata != data:
161 161 util.writefile(file, newdata)
162 162
163 163 @internaltool('prompt', False)
164 164 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf):
165 165 """Asks the user which of the local or the other version to keep as
166 166 the merged version."""
167 167 ui = repo.ui
168 168 fd = fcd.path()
169 169
170 170 if ui.promptchoice(_(" no tool found to merge %s\n"
171 171 "keep (l)ocal or take (o)ther?"
172 172 "$$ &Local $$ &Other") % fd, 0):
173 173 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf)
174 174 else:
175 175 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf)
176 176
177 177 @internaltool('local', False)
178 178 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf):
179 179 """Uses the local version of files as the merged version."""
180 180 return 0
181 181
182 182 @internaltool('other', False)
183 183 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf):
184 184 """Uses the other version of files as the merged version."""
185 185 repo.wwrite(fcd.path(), fco.data(), fco.flags())
186 186 return 0
187 187
188 188 @internaltool('fail', False)
189 189 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf):
190 190 """
191 191 Rather than attempting to merge files that were modified on both
192 192 branches, it marks them as unresolved. The resolve command must be
193 193 used to resolve these conflicts."""
194 194 return 1
195 195
196 196 def _premerge(repo, toolconf, files, labels=None):
197 197 tool, toolpath, binary, symlink = toolconf
198 198 if symlink:
199 199 return 1
200 200 a, b, c, back = files
201 201
202 202 ui = repo.ui
203 203
204 204 validkeep = ['keep', 'keep-merge3']
205 205
206 206 # do we attempt to simplemerge first?
207 207 try:
208 208 premerge = _toolbool(ui, tool, "premerge", not binary)
209 209 except error.ConfigError:
210 210 premerge = _toolstr(ui, tool, "premerge").lower()
211 211 if premerge not in validkeep:
212 212 _valid = ', '.join(["'" + v + "'" for v in validkeep])
213 213 raise error.ConfigError(_("%s.premerge not valid "
214 214 "('%s' is neither boolean nor %s)") %
215 215 (tool, premerge, _valid))
216 216
217 217 if premerge:
218 218 if premerge == 'keep-merge3':
219 219 if not labels:
220 220 labels = _defaultconflictlabels
221 221 if len(labels) < 3:
222 222 labels.append('base')
223 223 r = simplemerge.simplemerge(ui, a, b, c, quiet=True, label=labels)
224 224 if not r:
225 225 ui.debug(" premerge successful\n")
226 226 return 0
227 227 if premerge not in validkeep:
228 228 util.copyfile(back, a) # restore from backup and try again
229 229 return 1 # continue merging
230 230
231 231 def _symlinkcheck(repo, mynode, orig, fcd, fco, fca, toolconf):
232 232 tool, toolpath, binary, symlink = toolconf
233 233 if symlink:
234 repo.ui.warn(_('warning: internal :merge cannot merge symlinks '
235 'for %s\n') % fcd.path())
234 repo.ui.warn(_('warning: internal %s cannot merge symlinks '
235 'for %s\n') % (tool, fcd.path()))
236 236 return False
237 237 return True
238 238
239 239 def _merge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels, mode):
240 240 """
241 241 Uses the internal non-interactive simple merge algorithm for merging
242 242 files. It will fail if there are any conflicts and leave markers in
243 243 the partially merged file. Markers will have two sections, one for each side
244 244 of merge, unless mode equals 'union' which suppresses the markers."""
245 245 r = _premerge(repo, toolconf, files, labels=labels)
246 246 if r:
247 247 a, b, c, back = files
248 248
249 249 ui = repo.ui
250 250
251 251 r = simplemerge.simplemerge(ui, a, b, c, label=labels, mode=mode)
252 252 return True, r
253 253 return False, 0
254 254
255 255 @internaltool('union', True,
256 256 _("merging %s incomplete! "
257 257 "(edit conflicts, then use 'hg resolve --mark')\n"),
258 258 precheck=_symlinkcheck)
259 259 def _iunion(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
260 260 """
261 261 Uses the internal non-interactive simple merge algorithm for merging
262 262 files. It will use both left and right sides for conflict regions.
263 263 No markers are inserted."""
264 264 return _merge(repo, mynode, orig, fcd, fco, fca, toolconf,
265 265 files, labels, 'union')
266 266
267 267 @internaltool('merge', True,
268 268 _("merging %s incomplete! "
269 269 "(edit conflicts, then use 'hg resolve --mark')\n"),
270 270 precheck=_symlinkcheck)
271 271 def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
272 272 """
273 273 Uses the internal non-interactive simple merge algorithm for merging
274 274 files. It will fail if there are any conflicts and leave markers in
275 275 the partially merged file. Markers will have two sections, one for each side
276 276 of merge."""
277 277 return _merge(repo, mynode, orig, fcd, fco, fca, toolconf,
278 278 files, labels, 'merge')
279 279
280 280 @internaltool('merge3', True,
281 281 _("merging %s incomplete! "
282 282 "(edit conflicts, then use 'hg resolve --mark')\n"))
283 283 def _imerge3(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
284 284 """
285 285 Uses the internal non-interactive simple merge algorithm for merging
286 286 files. It will fail if there are any conflicts and leave markers in
287 287 the partially merged file. Marker will have three sections, one from each
288 288 side of the merge and one for the base content."""
289 289 if not labels:
290 290 labels = _defaultconflictlabels
291 291 if len(labels) < 3:
292 292 labels.append('base')
293 293 return _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels)
294 294
295 295 def _imergeauto(repo, mynode, orig, fcd, fco, fca, toolconf, files,
296 296 labels=None, localorother=None):
297 297 """
298 298 Generic driver for _imergelocal and _imergeother
299 299 """
300 300 assert localorother is not None
301 301 tool, toolpath, binary, symlink = toolconf
302 302 if symlink:
303 303 repo.ui.warn(_('warning: :merge-%s cannot merge symlinks '
304 304 'for %s\n') % (localorother, fcd.path()))
305 305 return False, 1
306 306 a, b, c, back = files
307 307 r = simplemerge.simplemerge(repo.ui, a, b, c, label=labels,
308 308 localorother=localorother)
309 309 return True, r
310 310
311 311 @internaltool('merge-local', True)
312 312 def _imergelocal(*args, **kwargs):
313 313 """
314 314 Like :merge, but resolve all conflicts non-interactively in favor
315 315 of the local changes."""
316 316 success, status = _imergeauto(localorother='local', *args, **kwargs)
317 317 return success, status
318 318
319 319 @internaltool('merge-other', True)
320 320 def _imergeother(*args, **kwargs):
321 321 """
322 322 Like :merge, but resolve all conflicts non-interactively in favor
323 323 of the other changes."""
324 324 success, status = _imergeauto(localorother='other', *args, **kwargs)
325 325 return success, status
326 326
327 327 @internaltool('tagmerge', True,
328 328 _("automatic tag merging of %s failed! "
329 329 "(use 'hg resolve --tool :merge' or another merge "
330 330 "tool of your choice)\n"))
331 331 def _itagmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
332 332 """
333 333 Uses the internal tag merge algorithm (experimental).
334 334 """
335 335 return tagmerge.merge(repo, fcd, fco, fca)
336 336
337 337 @internaltool('dump', True)
338 338 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
339 339 """
340 340 Creates three versions of the files to merge, containing the
341 341 contents of local, other and base. These files can then be used to
342 342 perform a merge manually. If the file to be merged is named
343 343 ``a.txt``, these files will accordingly be named ``a.txt.local``,
344 344 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
345 345 same directory as ``a.txt``."""
346 346 r = _premerge(repo, toolconf, files, labels=labels)
347 347 if r:
348 348 a, b, c, back = files
349 349
350 350 fd = fcd.path()
351 351
352 352 util.copyfile(a, a + ".local")
353 353 repo.wwrite(fd + ".other", fco.data(), fco.flags())
354 354 repo.wwrite(fd + ".base", fca.data(), fca.flags())
355 355 return False, r
356 356
357 357 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
358 358 r = _premerge(repo, toolconf, files, labels=labels)
359 359 if r:
360 360 tool, toolpath, binary, symlink = toolconf
361 361 a, b, c, back = files
362 362 out = ""
363 363 env = {'HG_FILE': fcd.path(),
364 364 'HG_MY_NODE': short(mynode),
365 365 'HG_OTHER_NODE': str(fco.changectx()),
366 366 'HG_BASE_NODE': str(fca.changectx()),
367 367 'HG_MY_ISLINK': 'l' in fcd.flags(),
368 368 'HG_OTHER_ISLINK': 'l' in fco.flags(),
369 369 'HG_BASE_ISLINK': 'l' in fca.flags(),
370 370 }
371 371
372 372 ui = repo.ui
373 373
374 374 args = _toolstr(ui, tool, "args", '$local $base $other')
375 375 if "$output" in args:
376 376 out, a = a, back # read input from backup, write to original
377 377 replace = {'local': a, 'base': b, 'other': c, 'output': out}
378 378 args = util.interpolate(r'\$', replace, args,
379 379 lambda s: util.shellquote(util.localpath(s)))
380 380 cmd = toolpath + ' ' + args
381 381 repo.ui.debug('launching merge tool: %s\n' % cmd)
382 382 r = ui.system(cmd, cwd=repo.root, environ=env)
383 383 repo.ui.debug('merge tool returned: %s\n' % r)
384 384 return True, r
385 385 return False, 0
386 386
387 387 def _formatconflictmarker(repo, ctx, template, label, pad):
388 388 """Applies the given template to the ctx, prefixed by the label.
389 389
390 390 Pad is the minimum width of the label prefix, so that multiple markers
391 391 can have aligned templated parts.
392 392 """
393 393 if ctx.node() is None:
394 394 ctx = ctx.p1()
395 395
396 396 props = templatekw.keywords.copy()
397 397 props['templ'] = template
398 398 props['ctx'] = ctx
399 399 props['repo'] = repo
400 400 templateresult = template('conflictmarker', **props)
401 401
402 402 label = ('%s:' % label).ljust(pad + 1)
403 403 mark = '%s %s' % (label, templater.stringify(templateresult))
404 404
405 405 if mark:
406 406 mark = mark.splitlines()[0] # split for safety
407 407
408 408 # 8 for the prefix of conflict marker lines (e.g. '<<<<<<< ')
409 409 return util.ellipsis(mark, 80 - 8)
410 410
411 411 _defaultconflictmarker = ('{node|short} ' +
412 412 '{ifeq(tags, "tip", "", "{tags} ")}' +
413 413 '{if(bookmarks, "{bookmarks} ")}' +
414 414 '{ifeq(branch, "default", "", "{branch} ")}' +
415 415 '- {author|user}: {desc|firstline}')
416 416
417 417 _defaultconflictlabels = ['local', 'other']
418 418
419 419 def _formatlabels(repo, fcd, fco, fca, labels):
420 420 """Formats the given labels using the conflict marker template.
421 421
422 422 Returns a list of formatted labels.
423 423 """
424 424 cd = fcd.changectx()
425 425 co = fco.changectx()
426 426 ca = fca.changectx()
427 427
428 428 ui = repo.ui
429 429 template = ui.config('ui', 'mergemarkertemplate', _defaultconflictmarker)
430 430 tmpl = templater.templater(None, cache={'conflictmarker': template})
431 431
432 432 pad = max(len(l) for l in labels)
433 433
434 434 newlabels = [_formatconflictmarker(repo, cd, tmpl, labels[0], pad),
435 435 _formatconflictmarker(repo, co, tmpl, labels[1], pad)]
436 436 if len(labels) > 2:
437 437 newlabels.append(_formatconflictmarker(repo, ca, tmpl, labels[2], pad))
438 438 return newlabels
439 439
440 440 def filemerge(repo, mynode, orig, fcd, fco, fca, labels=None):
441 441 """perform a 3-way merge in the working directory
442 442
443 443 mynode = parent node before merge
444 444 orig = original local filename before merge
445 445 fco = other file context
446 446 fca = ancestor file context
447 447 fcd = local file context for current/destination file
448 448 """
449 449
450 450 if True:
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 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 trymerge = func.trymerge
477 477 onfailure = func.onfailure
478 478 precheck = func.precheck
479 479 else:
480 480 func = _xmerge
481 481 trymerge = True
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 not trymerge:
488 488 return func(repo, mynode, orig, fcd, fco, fca, toolconf)
489 489
490 490 a = repo.wjoin(fd)
491 491 b = temp("base", fca)
492 492 c = temp("other", fco)
493 493 back = a + ".orig"
494 494 util.copyfile(a, back)
495 495
496 496 if orig != fco.path():
497 497 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
498 498 else:
499 499 ui.status(_("merging %s\n") % fd)
500 500
501 501 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
502 502
503 503 r = 0
504 504 if precheck and not precheck(repo, mynode, orig, fcd, fco, fca,
505 505 toolconf):
506 506 r = 1
507 507 needcheck = False
508 508
509 509 if not r: # precheck passed
510 510 markerstyle = ui.config('ui', 'mergemarkers', 'basic')
511 511 if not labels:
512 512 labels = _defaultconflictlabels
513 513 if markerstyle != 'basic':
514 514 labels = _formatlabels(repo, fcd, fco, fca, labels)
515 515
516 516 needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf,
517 517 (a, b, c, back), labels=labels)
518 518
519 519 if not needcheck:
520 520 if r:
521 521 if onfailure:
522 522 ui.warn(onfailure % fd)
523 523 else:
524 524 util.unlink(back)
525 525
526 526 util.unlink(b)
527 527 util.unlink(c)
528 528 return r
529 529
530 530 if not r and (_toolbool(ui, tool, "checkconflicts") or
531 531 'conflicts' in _toollist(ui, tool, "check")):
532 532 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
533 533 re.MULTILINE):
534 534 r = 1
535 535
536 536 checked = False
537 537 if 'prompt' in _toollist(ui, tool, "check"):
538 538 checked = True
539 539 if ui.promptchoice(_("was merge of '%s' successful (yn)?"
540 540 "$$ &Yes $$ &No") % fd, 1):
541 541 r = 1
542 542
543 543 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
544 544 'changed' in
545 545 _toollist(ui, tool, "check")):
546 546 if filecmp.cmp(a, back):
547 547 if ui.promptchoice(_(" output file %s appears unchanged\n"
548 548 "was merge successful (yn)?"
549 549 "$$ &Yes $$ &No") % fd, 1):
550 550 r = 1
551 551
552 552 if _toolbool(ui, tool, "fixeol"):
553 553 _matcheol(a, back)
554 554
555 555 if r:
556 556 if onfailure:
557 557 ui.warn(onfailure % fd)
558 558 else:
559 559 util.unlink(back)
560 560
561 561 util.unlink(b)
562 562 util.unlink(c)
563 563 return r
564 564
565 565 # tell hggettext to extract docstrings from these functions:
566 566 i18nfunctions = internals.values()
@@ -1,376 +1,376
1 1 #require symlink execbit
2 2
3 3 $ tellmeabout() {
4 4 > if [ -h $1 ]; then
5 5 > echo $1 is a symlink:
6 6 > $TESTDIR/readlink.py $1
7 7 > elif [ -x $1 ]; then
8 8 > echo $1 is an executable file with content:
9 9 > cat $1
10 10 > else
11 11 > echo $1 is a plain file with content:
12 12 > cat $1
13 13 > fi
14 14 > }
15 15
16 16 $ hg init test1
17 17 $ cd test1
18 18
19 19 $ echo a > a
20 20 $ hg ci -Aqmadd
21 21 $ chmod +x a
22 22 $ hg ci -mexecutable
23 23
24 24 $ hg up -q 0
25 25 $ rm a
26 26 $ ln -s symlink a
27 27 $ hg ci -msymlink
28 28 created new head
29 29
30 30 Symlink is local parent, executable is other:
31 31
32 32 $ hg merge --debug
33 33 searching for copies back to rev 1
34 34 resolving manifests
35 35 branchmerge: True, force: False, partial: False
36 36 ancestor: c334dc3be0da, local: 521a1e40188f+, remote: 3574f3e69b1c
37 37 preserving a for resolve of a
38 38 a: versions differ -> m
39 39 picked tool ':merge' for a (binary False symlink True)
40 40 merging a
41 41 my a@521a1e40188f+ other a@3574f3e69b1c ancestor a@c334dc3be0da
42 42 warning: internal :merge cannot merge symlinks for a
43 43 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
44 44 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
45 45 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
46 46 [1]
47 47
48 48 $ tellmeabout a
49 49 a is a symlink:
50 50 a -> symlink
51 51 $ hg resolve a --tool internal:other
52 52 (no more unresolved files)
53 53 $ tellmeabout a
54 54 a is an executable file with content:
55 55 a
56 56 $ hg st
57 57 M a
58 58 ? a.orig
59 59
60 60 Symlink is other parent, executable is local:
61 61
62 62 $ hg update -C 1
63 63 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 64
65 $ hg merge --debug
65 $ hg merge --debug --tool :union
66 66 searching for copies back to rev 1
67 67 resolving manifests
68 68 branchmerge: True, force: False, partial: False
69 69 ancestor: c334dc3be0da, local: 3574f3e69b1c+, remote: 521a1e40188f
70 70 preserving a for resolve of a
71 71 a: versions differ -> m
72 picked tool ':merge' for a (binary False symlink True)
72 picked tool ':union' for a (binary False symlink True)
73 73 merging a
74 74 my a@3574f3e69b1c+ other a@521a1e40188f ancestor a@c334dc3be0da
75 warning: internal :merge cannot merge symlinks for a
75 warning: internal :union cannot merge symlinks for a
76 76 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
77 77 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
78 78 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
79 79 [1]
80 80
81 81 $ tellmeabout a
82 82 a is an executable file with content:
83 83 a
84 84
85 85 Update to link without local change should get us a symlink (issue3316):
86 86
87 87 $ hg up -C 0
88 88 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 89 $ hg up
90 90 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 91 $ hg st
92 92 ? a.orig
93 93
94 94 Update to link with local change should cause a merge prompt (issue3200):
95 95
96 96 $ hg up -Cq 0
97 97 $ echo data > a
98 98 $ HGMERGE= hg up -y --debug
99 99 searching for copies back to rev 2
100 100 resolving manifests
101 101 branchmerge: False, force: False, partial: False
102 102 ancestor: c334dc3be0da, local: c334dc3be0da+, remote: 521a1e40188f
103 103 preserving a for resolve of a
104 104 a: versions differ -> m
105 105 (couldn't find merge tool hgmerge|tool hgmerge can't handle symlinks) (re)
106 106 picked tool ':prompt' for a (binary False symlink True)
107 107 no tool found to merge a
108 108 keep (l)ocal or take (o)ther? l
109 109 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
110 110 $ hg diff --git
111 111 diff --git a/a b/a
112 112 old mode 120000
113 113 new mode 100644
114 114 --- a/a
115 115 +++ b/a
116 116 @@ -1,1 +1,1 @@
117 117 -symlink
118 118 \ No newline at end of file
119 119 +data
120 120
121 121
122 122 Test only 'l' change - happens rarely, except when recovering from situations
123 123 where that was what happened.
124 124
125 125 $ hg init test2
126 126 $ cd test2
127 127 $ printf base > f
128 128 $ hg ci -Aqm0
129 129 $ echo file > f
130 130 $ echo content >> f
131 131 $ hg ci -qm1
132 132 $ hg up -qr0
133 133 $ rm f
134 134 $ ln -s base f
135 135 $ hg ci -qm2
136 136 $ hg merge
137 137 merging f
138 138 warning: internal :merge cannot merge symlinks for f
139 139 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
140 140 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
141 141 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
142 142 [1]
143 143 $ tellmeabout f
144 144 f is a symlink:
145 145 f -> base
146 146
147 147 $ hg up -Cqr1
148 148 $ hg merge
149 149 merging f
150 150 warning: internal :merge cannot merge symlinks for f
151 151 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
152 152 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
153 153 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
154 154 [1]
155 155 $ tellmeabout f
156 156 f is a plain file with content:
157 157 file
158 158 content
159 159
160 160 $ cd ..
161 161
162 162 Test removed 'x' flag merged with change to symlink
163 163
164 164 $ hg init test3
165 165 $ cd test3
166 166 $ echo f > f
167 167 $ chmod +x f
168 168 $ hg ci -Aqm0
169 169 $ chmod -x f
170 170 $ hg ci -qm1
171 171 $ hg up -qr0
172 172 $ rm f
173 173 $ ln -s dangling f
174 174 $ hg ci -qm2
175 175 $ hg merge
176 176 merging f
177 177 warning: internal :merge cannot merge symlinks for f
178 178 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
179 179 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
180 180 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
181 181 [1]
182 182 $ tellmeabout f
183 183 f is a symlink:
184 184 f -> dangling
185 185
186 186 $ hg up -Cqr1
187 187 $ hg merge
188 188 merging f
189 189 warning: internal :merge cannot merge symlinks for f
190 190 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
191 191 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
192 192 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
193 193 [1]
194 194 $ tellmeabout f
195 195 f is a plain file with content:
196 196 f
197 197
198 198 Test removed 'x' flag merged with content change - both ways
199 199
200 200 $ hg up -Cqr0
201 201 $ echo change > f
202 202 $ hg ci -qm3
203 203 $ hg merge -r1
204 204 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
205 205 (branch merge, don't forget to commit)
206 206 $ tellmeabout f
207 207 f is a plain file with content:
208 208 change
209 209
210 210 $ hg up -qCr1
211 211 $ hg merge -r3
212 212 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
213 213 (branch merge, don't forget to commit)
214 214 $ tellmeabout f
215 215 f is a plain file with content:
216 216 change
217 217
218 218 $ cd ..
219 219
220 220 Test merge with no common ancestor:
221 221 a: just different
222 222 b: x vs -, different (cannot calculate x, cannot ask merge tool)
223 223 c: x vs -, same (cannot calculate x, merge tool is no good)
224 224 d: x vs l, different
225 225 e: x vs l, same
226 226 f: - vs l, different
227 227 g: - vs l, same
228 228 h: l vs l, different
229 229 (where same means the filelog entry is shared and there thus is an ancestor!)
230 230
231 231 $ hg init test4
232 232 $ cd test4
233 233 $ echo 0 > 0
234 234 $ hg ci -Aqm0
235 235
236 236 $ echo 1 > a
237 237 $ echo 1 > b
238 238 $ chmod +x b
239 239 $ echo x > c
240 240 $ chmod +x c
241 241 $ echo 1 > d
242 242 $ chmod +x d
243 243 $ printf x > e
244 244 $ chmod +x e
245 245 $ echo 1 > f
246 246 $ printf x > g
247 247 $ ln -s 1 h
248 248 $ hg ci -qAm1
249 249
250 250 $ hg up -qr0
251 251 $ echo 2 > a
252 252 $ echo 2 > b
253 253 $ echo x > c
254 254 $ ln -s 2 d
255 255 $ ln -s x e
256 256 $ ln -s 2 f
257 257 $ ln -s x g
258 258 $ ln -s 2 h
259 259 $ hg ci -Aqm2
260 260
261 261 $ hg merge
262 262 merging a
263 263 warning: conflicts during merge.
264 264 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
265 265 warning: cannot merge flags for b
266 266 merging b
267 267 warning: conflicts during merge.
268 268 merging b incomplete! (edit conflicts, then use 'hg resolve --mark')
269 269 warning: cannot merge flags for c
270 270 merging d
271 271 warning: internal :merge cannot merge symlinks for d
272 272 merging d incomplete! (edit conflicts, then use 'hg resolve --mark')
273 273 merging f
274 274 warning: internal :merge cannot merge symlinks for f
275 275 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
276 276 merging h
277 277 warning: internal :merge cannot merge symlinks for h
278 278 merging h incomplete! (edit conflicts, then use 'hg resolve --mark')
279 279 3 files updated, 0 files merged, 0 files removed, 5 files unresolved
280 280 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
281 281 [1]
282 282 $ hg resolve -l
283 283 U a
284 284 U b
285 285 U d
286 286 U f
287 287 U h
288 288 $ tellmeabout a
289 289 a is a plain file with content:
290 290 <<<<<<< local: 0139c5610547 - test: 2
291 291 2
292 292 =======
293 293 1
294 294 >>>>>>> other: 97e29675e796 - test: 1
295 295 $ tellmeabout b
296 296 b is a plain file with content:
297 297 <<<<<<< local: 0139c5610547 - test: 2
298 298 2
299 299 =======
300 300 1
301 301 >>>>>>> other: 97e29675e796 - test: 1
302 302 $ tellmeabout c
303 303 c is a plain file with content:
304 304 x
305 305 $ tellmeabout d
306 306 d is a symlink:
307 307 d -> 2
308 308 $ tellmeabout e
309 309 e is a symlink:
310 310 e -> x
311 311 $ tellmeabout f
312 312 f is a symlink:
313 313 f -> 2
314 314 $ tellmeabout g
315 315 g is a symlink:
316 316 g -> x
317 317 $ tellmeabout h
318 318 h is a symlink:
319 319 h -> 2
320 320
321 321 $ hg up -Cqr1
322 322 $ hg merge
323 323 merging a
324 324 warning: conflicts during merge.
325 325 merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
326 326 warning: cannot merge flags for b
327 327 merging b
328 328 warning: conflicts during merge.
329 329 merging b incomplete! (edit conflicts, then use 'hg resolve --mark')
330 330 warning: cannot merge flags for c
331 331 merging d
332 332 warning: internal :merge cannot merge symlinks for d
333 333 merging d incomplete! (edit conflicts, then use 'hg resolve --mark')
334 334 merging f
335 335 warning: internal :merge cannot merge symlinks for f
336 336 merging f incomplete! (edit conflicts, then use 'hg resolve --mark')
337 337 merging h
338 338 warning: internal :merge cannot merge symlinks for h
339 339 merging h incomplete! (edit conflicts, then use 'hg resolve --mark')
340 340 3 files updated, 0 files merged, 0 files removed, 5 files unresolved
341 341 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
342 342 [1]
343 343 $ tellmeabout a
344 344 a is a plain file with content:
345 345 <<<<<<< local: 97e29675e796 - test: 1
346 346 1
347 347 =======
348 348 2
349 349 >>>>>>> other: 0139c5610547 - test: 2
350 350 $ tellmeabout b
351 351 b is an executable file with content:
352 352 <<<<<<< local: 97e29675e796 - test: 1
353 353 1
354 354 =======
355 355 2
356 356 >>>>>>> other: 0139c5610547 - test: 2
357 357 $ tellmeabout c
358 358 c is an executable file with content:
359 359 x
360 360 $ tellmeabout d
361 361 d is an executable file with content:
362 362 1
363 363 $ tellmeabout e
364 364 e is an executable file with content:
365 365 x (no-eol)
366 366 $ tellmeabout f
367 367 f is a plain file with content:
368 368 1
369 369 $ tellmeabout g
370 370 g is a plain file with content:
371 371 x (no-eol)
372 372 $ tellmeabout h
373 373 h is a symlink:
374 374 h -> 1
375 375
376 376 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now