##// END OF EJS Templates
filemerge: return whether the file is deleted for nomerge internal tools...
Siddharth Agarwal -
r27032:28ee7af4 default
parent child Browse files
Show More
@@ -1,630 +1,631
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 nullid, short
17 17
18 18 from . import (
19 19 cmdutil,
20 20 error,
21 21 match,
22 22 simplemerge,
23 23 tagmerge,
24 24 templatekw,
25 25 templater,
26 26 util,
27 27 )
28 28
29 29 def _toolstr(ui, tool, part, default=""):
30 30 return ui.config("merge-tools", tool + "." + part, default)
31 31
32 32 def _toolbool(ui, tool, part, default=False):
33 33 return ui.configbool("merge-tools", tool + "." + part, default)
34 34
35 35 def _toollist(ui, tool, part, default=[]):
36 36 return ui.configlist("merge-tools", tool + "." + part, default)
37 37
38 38 internals = {}
39 39 # Merge tools to document.
40 40 internalsdoc = {}
41 41
42 42 # internal tool merge types
43 43 nomerge = None
44 44 mergeonly = 'mergeonly' # just the full merge, no premerge
45 45 fullmerge = 'fullmerge' # both premerge and merge
46 46
47 47 class absentfilectx(object):
48 48 """Represents a file that's ostensibly in a context but is actually not
49 49 present in it.
50 50
51 51 This is here because it's very specific to the filemerge code for now --
52 52 other code is likely going to break with the values this returns."""
53 53 def __init__(self, ctx, f):
54 54 self._ctx = ctx
55 55 self._f = f
56 56
57 57 def path(self):
58 58 return self._f
59 59
60 60 def size(self):
61 61 return None
62 62
63 63 def data(self):
64 64 return None
65 65
66 66 def filenode(self):
67 67 return nullid
68 68
69 69 _customcmp = True
70 70 def cmp(self, fctx):
71 71 """compare with other file context
72 72
73 73 returns True if different from fctx.
74 74 """
75 75 return not (fctx.isabsent() and
76 76 fctx.ctx() == self.ctx() and
77 77 fctx.path() == self.path())
78 78
79 79 def flags(self):
80 80 return ''
81 81
82 82 def changectx(self):
83 83 return self._ctx
84 84
85 85 def isbinary(self):
86 86 return False
87 87
88 88 def isabsent(self):
89 89 return True
90 90
91 91 def internaltool(name, mergetype, onfailure=None, precheck=None):
92 92 '''return a decorator for populating internal merge tool table'''
93 93 def decorator(func):
94 94 fullname = ':' + name
95 95 func.__doc__ = "``%s``\n" % fullname + func.__doc__.strip()
96 96 internals[fullname] = func
97 97 internals['internal:' + name] = func
98 98 internalsdoc[fullname] = func
99 99 func.mergetype = mergetype
100 100 func.onfailure = onfailure
101 101 func.precheck = precheck
102 102 return func
103 103 return decorator
104 104
105 105 def _findtool(ui, tool):
106 106 if tool in internals:
107 107 return tool
108 108 return findexternaltool(ui, tool)
109 109
110 110 def findexternaltool(ui, tool):
111 111 for kn in ("regkey", "regkeyalt"):
112 112 k = _toolstr(ui, tool, kn)
113 113 if not k:
114 114 continue
115 115 p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
116 116 if p:
117 117 p = util.findexe(p + _toolstr(ui, tool, "regappend"))
118 118 if p:
119 119 return p
120 120 exe = _toolstr(ui, tool, "executable", tool)
121 121 return util.findexe(util.expandpath(exe))
122 122
123 123 def _picktool(repo, ui, path, binary, symlink):
124 124 def check(tool, pat, symlink, binary):
125 125 tmsg = tool
126 126 if pat:
127 127 tmsg += " specified for " + pat
128 128 if not _findtool(ui, tool):
129 129 if pat: # explicitly requested tool deserves a warning
130 130 ui.warn(_("couldn't find merge tool %s\n") % tmsg)
131 131 else: # configured but non-existing tools are more silent
132 132 ui.note(_("couldn't find merge tool %s\n") % tmsg)
133 133 elif symlink and not _toolbool(ui, tool, "symlink"):
134 134 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
135 135 elif binary and not _toolbool(ui, tool, "binary"):
136 136 ui.warn(_("tool %s can't handle binary\n") % tmsg)
137 137 elif not util.gui() and _toolbool(ui, tool, "gui"):
138 138 ui.warn(_("tool %s requires a GUI\n") % tmsg)
139 139 else:
140 140 return True
141 141 return False
142 142
143 143 # internal config: ui.forcemerge
144 144 # forcemerge comes from command line arguments, highest priority
145 145 force = ui.config('ui', 'forcemerge')
146 146 if force:
147 147 toolpath = _findtool(ui, force)
148 148 if toolpath:
149 149 return (force, util.shellquote(toolpath))
150 150 else:
151 151 # mimic HGMERGE if given tool not found
152 152 return (force, force)
153 153
154 154 # HGMERGE takes next precedence
155 155 hgmerge = os.environ.get("HGMERGE")
156 156 if hgmerge:
157 157 return (hgmerge, hgmerge)
158 158
159 159 # then patterns
160 160 for pat, tool in ui.configitems("merge-patterns"):
161 161 mf = match.match(repo.root, '', [pat])
162 162 if mf(path) and check(tool, pat, symlink, False):
163 163 toolpath = _findtool(ui, tool)
164 164 return (tool, util.shellquote(toolpath))
165 165
166 166 # then merge tools
167 167 tools = {}
168 168 disabled = set()
169 169 for k, v in ui.configitems("merge-tools"):
170 170 t = k.split('.')[0]
171 171 if t not in tools:
172 172 tools[t] = int(_toolstr(ui, t, "priority", "0"))
173 173 if _toolbool(ui, t, "disabled", False):
174 174 disabled.add(t)
175 175 names = tools.keys()
176 176 tools = sorted([(-p, t) for t, p in tools.items() if t not in disabled])
177 177 uimerge = ui.config("ui", "merge")
178 178 if uimerge:
179 179 if uimerge not in names:
180 180 return (uimerge, uimerge)
181 181 tools.insert(0, (None, uimerge)) # highest priority
182 182 tools.append((None, "hgmerge")) # the old default, if found
183 183 for p, t in tools:
184 184 if check(t, None, symlink, binary):
185 185 toolpath = _findtool(ui, t)
186 186 return (t, util.shellquote(toolpath))
187 187
188 188 # internal merge or prompt as last resort
189 189 if symlink or binary:
190 190 return ":prompt", None
191 191 return ":merge", None
192 192
193 193 def _eoltype(data):
194 194 "Guess the EOL type of a file"
195 195 if '\0' in data: # binary
196 196 return None
197 197 if '\r\n' in data: # Windows
198 198 return '\r\n'
199 199 if '\r' in data: # Old Mac
200 200 return '\r'
201 201 if '\n' in data: # UNIX
202 202 return '\n'
203 203 return None # unknown
204 204
205 205 def _matcheol(file, origfile):
206 206 "Convert EOL markers in a file to match origfile"
207 207 tostyle = _eoltype(util.readfile(origfile))
208 208 if tostyle:
209 209 data = util.readfile(file)
210 210 style = _eoltype(data)
211 211 if style:
212 212 newdata = data.replace(style, tostyle)
213 213 if newdata != data:
214 214 util.writefile(file, newdata)
215 215
216 216 @internaltool('prompt', nomerge)
217 217 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf):
218 218 """Asks the user which of the local or the other version to keep as
219 219 the merged version."""
220 220 ui = repo.ui
221 221 fd = fcd.path()
222 222
223 223 try:
224 224 index = ui.promptchoice(_("no tool found to merge %s\n"
225 225 "keep (l)ocal or take (o)ther?"
226 226 "$$ &Local $$ &Other") % fd, 0)
227 227 choice = ['local', 'other'][index]
228 228
229 229 if choice == 'other':
230 230 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf)
231 231 else:
232 232 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf)
233 233 except error.ResponseExpected:
234 234 ui.write("\n")
235 return 1
235 return 1, False
236 236
237 237 @internaltool('local', nomerge)
238 238 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf):
239 239 """Uses the local version of files as the merged version."""
240 return 0
240 return 0, False
241 241
242 242 @internaltool('other', nomerge)
243 243 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf):
244 244 """Uses the other version of files as the merged version."""
245 245 repo.wwrite(fcd.path(), fco.data(), fco.flags())
246 return 0
246 return 0, False
247 247
248 248 @internaltool('fail', nomerge)
249 249 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf):
250 250 """
251 251 Rather than attempting to merge files that were modified on both
252 252 branches, it marks them as unresolved. The resolve command must be
253 253 used to resolve these conflicts."""
254 return 1
254 return 1, False
255 255
256 256 def _premerge(repo, toolconf, files, labels=None):
257 257 tool, toolpath, binary, symlink = toolconf
258 258 if symlink:
259 259 return 1
260 260 a, b, c, back = files
261 261
262 262 ui = repo.ui
263 263
264 264 validkeep = ['keep', 'keep-merge3']
265 265
266 266 # do we attempt to simplemerge first?
267 267 try:
268 268 premerge = _toolbool(ui, tool, "premerge", not binary)
269 269 except error.ConfigError:
270 270 premerge = _toolstr(ui, tool, "premerge").lower()
271 271 if premerge not in validkeep:
272 272 _valid = ', '.join(["'" + v + "'" for v in validkeep])
273 273 raise error.ConfigError(_("%s.premerge not valid "
274 274 "('%s' is neither boolean nor %s)") %
275 275 (tool, premerge, _valid))
276 276
277 277 if premerge:
278 278 if premerge == 'keep-merge3':
279 279 if not labels:
280 280 labels = _defaultconflictlabels
281 281 if len(labels) < 3:
282 282 labels.append('base')
283 283 r = simplemerge.simplemerge(ui, a, b, c, quiet=True, label=labels)
284 284 if not r:
285 285 ui.debug(" premerge successful\n")
286 286 return 0
287 287 if premerge not in validkeep:
288 288 util.copyfile(back, a) # restore from backup and try again
289 289 return 1 # continue merging
290 290
291 291 def _mergecheck(repo, mynode, orig, fcd, fco, fca, toolconf):
292 292 tool, toolpath, binary, symlink = toolconf
293 293 if symlink:
294 294 repo.ui.warn(_('warning: internal %s cannot merge symlinks '
295 295 'for %s\n') % (tool, fcd.path()))
296 296 return False
297 297 return True
298 298
299 299 def _merge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels, mode):
300 300 """
301 301 Uses the internal non-interactive simple merge algorithm for merging
302 302 files. It will fail if there are any conflicts and leave markers in
303 303 the partially merged file. Markers will have two sections, one for each side
304 304 of merge, unless mode equals 'union' which suppresses the markers."""
305 305 a, b, c, back = files
306 306
307 307 ui = repo.ui
308 308
309 309 r = simplemerge.simplemerge(ui, a, b, c, label=labels, mode=mode)
310 310 return True, r
311 311
312 312 @internaltool('union', fullmerge,
313 313 _("warning: conflicts while merging %s! "
314 314 "(edit, then use 'hg resolve --mark')\n"),
315 315 precheck=_mergecheck)
316 316 def _iunion(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
317 317 """
318 318 Uses the internal non-interactive simple merge algorithm for merging
319 319 files. It will use both left and right sides for conflict regions.
320 320 No markers are inserted."""
321 321 return _merge(repo, mynode, orig, fcd, fco, fca, toolconf,
322 322 files, labels, 'union')
323 323
324 324 @internaltool('merge', fullmerge,
325 325 _("warning: conflicts while merging %s! "
326 326 "(edit, then use 'hg resolve --mark')\n"),
327 327 precheck=_mergecheck)
328 328 def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
329 329 """
330 330 Uses the internal non-interactive simple merge algorithm for merging
331 331 files. It will fail if there are any conflicts and leave markers in
332 332 the partially merged file. Markers will have two sections, one for each side
333 333 of merge."""
334 334 return _merge(repo, mynode, orig, fcd, fco, fca, toolconf,
335 335 files, labels, 'merge')
336 336
337 337 @internaltool('merge3', fullmerge,
338 338 _("warning: conflicts while merging %s! "
339 339 "(edit, then use 'hg resolve --mark')\n"),
340 340 precheck=_mergecheck)
341 341 def _imerge3(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
342 342 """
343 343 Uses the internal non-interactive simple merge algorithm for merging
344 344 files. It will fail if there are any conflicts and leave markers in
345 345 the partially merged file. Marker will have three sections, one from each
346 346 side of the merge and one for the base content."""
347 347 if not labels:
348 348 labels = _defaultconflictlabels
349 349 if len(labels) < 3:
350 350 labels.append('base')
351 351 return _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels)
352 352
353 353 def _imergeauto(repo, mynode, orig, fcd, fco, fca, toolconf, files,
354 354 labels=None, localorother=None):
355 355 """
356 356 Generic driver for _imergelocal and _imergeother
357 357 """
358 358 assert localorother is not None
359 359 tool, toolpath, binary, symlink = toolconf
360 360 a, b, c, back = files
361 361 r = simplemerge.simplemerge(repo.ui, a, b, c, label=labels,
362 362 localorother=localorother)
363 363 return True, r
364 364
365 365 @internaltool('merge-local', mergeonly, precheck=_mergecheck)
366 366 def _imergelocal(*args, **kwargs):
367 367 """
368 368 Like :merge, but resolve all conflicts non-interactively in favor
369 369 of the local changes."""
370 370 success, status = _imergeauto(localorother='local', *args, **kwargs)
371 371 return success, status
372 372
373 373 @internaltool('merge-other', mergeonly, precheck=_mergecheck)
374 374 def _imergeother(*args, **kwargs):
375 375 """
376 376 Like :merge, but resolve all conflicts non-interactively in favor
377 377 of the other changes."""
378 378 success, status = _imergeauto(localorother='other', *args, **kwargs)
379 379 return success, status
380 380
381 381 @internaltool('tagmerge', mergeonly,
382 382 _("automatic tag merging of %s failed! "
383 383 "(use 'hg resolve --tool :merge' or another merge "
384 384 "tool of your choice)\n"))
385 385 def _itagmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
386 386 """
387 387 Uses the internal tag merge algorithm (experimental).
388 388 """
389 389 return tagmerge.merge(repo, fcd, fco, fca)
390 390
391 391 @internaltool('dump', fullmerge)
392 392 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
393 393 """
394 394 Creates three versions of the files to merge, containing the
395 395 contents of local, other and base. These files can then be used to
396 396 perform a merge manually. If the file to be merged is named
397 397 ``a.txt``, these files will accordingly be named ``a.txt.local``,
398 398 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
399 399 same directory as ``a.txt``."""
400 400 a, b, c, back = files
401 401
402 402 fd = fcd.path()
403 403
404 404 util.copyfile(a, a + ".local")
405 405 repo.wwrite(fd + ".other", fco.data(), fco.flags())
406 406 repo.wwrite(fd + ".base", fca.data(), fca.flags())
407 407 return False, 1
408 408
409 409 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
410 410 tool, toolpath, binary, symlink = toolconf
411 411 a, b, c, back = files
412 412 out = ""
413 413 env = {'HG_FILE': fcd.path(),
414 414 'HG_MY_NODE': short(mynode),
415 415 'HG_OTHER_NODE': str(fco.changectx()),
416 416 'HG_BASE_NODE': str(fca.changectx()),
417 417 'HG_MY_ISLINK': 'l' in fcd.flags(),
418 418 'HG_OTHER_ISLINK': 'l' in fco.flags(),
419 419 'HG_BASE_ISLINK': 'l' in fca.flags(),
420 420 }
421 421
422 422 ui = repo.ui
423 423
424 424 args = _toolstr(ui, tool, "args", '$local $base $other')
425 425 if "$output" in args:
426 426 out, a = a, back # read input from backup, write to original
427 427 replace = {'local': a, 'base': b, 'other': c, 'output': out}
428 428 args = util.interpolate(r'\$', replace, args,
429 429 lambda s: util.shellquote(util.localpath(s)))
430 430 cmd = toolpath + ' ' + args
431 431 repo.ui.debug('launching merge tool: %s\n' % cmd)
432 432 r = ui.system(cmd, cwd=repo.root, environ=env)
433 433 repo.ui.debug('merge tool returned: %s\n' % r)
434 434 return True, r
435 435
436 436 def _formatconflictmarker(repo, ctx, template, label, pad):
437 437 """Applies the given template to the ctx, prefixed by the label.
438 438
439 439 Pad is the minimum width of the label prefix, so that multiple markers
440 440 can have aligned templated parts.
441 441 """
442 442 if ctx.node() is None:
443 443 ctx = ctx.p1()
444 444
445 445 props = templatekw.keywords.copy()
446 446 props['templ'] = template
447 447 props['ctx'] = ctx
448 448 props['repo'] = repo
449 449 templateresult = template('conflictmarker', **props)
450 450
451 451 label = ('%s:' % label).ljust(pad + 1)
452 452 mark = '%s %s' % (label, templater.stringify(templateresult))
453 453
454 454 if mark:
455 455 mark = mark.splitlines()[0] # split for safety
456 456
457 457 # 8 for the prefix of conflict marker lines (e.g. '<<<<<<< ')
458 458 return util.ellipsis(mark, 80 - 8)
459 459
460 460 _defaultconflictmarker = ('{node|short} ' +
461 461 '{ifeq(tags, "tip", "", "{tags} ")}' +
462 462 '{if(bookmarks, "{bookmarks} ")}' +
463 463 '{ifeq(branch, "default", "", "{branch} ")}' +
464 464 '- {author|user}: {desc|firstline}')
465 465
466 466 _defaultconflictlabels = ['local', 'other']
467 467
468 468 def _formatlabels(repo, fcd, fco, fca, labels):
469 469 """Formats the given labels using the conflict marker template.
470 470
471 471 Returns a list of formatted labels.
472 472 """
473 473 cd = fcd.changectx()
474 474 co = fco.changectx()
475 475 ca = fca.changectx()
476 476
477 477 ui = repo.ui
478 478 template = ui.config('ui', 'mergemarkertemplate', _defaultconflictmarker)
479 479 tmpl = templater.templater(None, cache={'conflictmarker': template})
480 480
481 481 pad = max(len(l) for l in labels)
482 482
483 483 newlabels = [_formatconflictmarker(repo, cd, tmpl, labels[0], pad),
484 484 _formatconflictmarker(repo, co, tmpl, labels[1], pad)]
485 485 if len(labels) > 2:
486 486 newlabels.append(_formatconflictmarker(repo, ca, tmpl, labels[2], pad))
487 487 return newlabels
488 488
489 489 def _filemerge(premerge, repo, mynode, orig, fcd, fco, fca, labels=None):
490 490 """perform a 3-way merge in the working directory
491 491
492 492 premerge = whether this is a premerge
493 493 mynode = parent node before merge
494 494 orig = original local filename before merge
495 495 fco = other file context
496 496 fca = ancestor file context
497 497 fcd = local file context for current/destination file
498 498
499 499 Returns whether the merge is complete, and the return value of the merge.
500 500 """
501 501
502 502 def temp(prefix, ctx):
503 503 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
504 504 (fd, name) = tempfile.mkstemp(prefix=pre)
505 505 data = repo.wwritedata(ctx.path(), ctx.data())
506 506 f = os.fdopen(fd, "wb")
507 507 f.write(data)
508 508 f.close()
509 509 return name
510 510
511 511 if not fco.cmp(fcd): # files identical?
512 512 return True, None
513 513
514 514 ui = repo.ui
515 515 fd = fcd.path()
516 516 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
517 517 symlink = 'l' in fcd.flags() + fco.flags()
518 518 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
519 519 if tool in internals and tool.startswith('internal:'):
520 520 # normalize to new-style names (':merge' etc)
521 521 tool = tool[len('internal'):]
522 522 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
523 523 (tool, fd, binary, symlink))
524 524
525 525 if tool in internals:
526 526 func = internals[tool]
527 527 mergetype = func.mergetype
528 528 onfailure = func.onfailure
529 529 precheck = func.precheck
530 530 else:
531 531 func = _xmerge
532 532 mergetype = fullmerge
533 533 onfailure = _("merging %s failed!\n")
534 534 precheck = None
535 535
536 536 toolconf = tool, toolpath, binary, symlink
537 537
538 538 if mergetype == nomerge:
539 return True, func(repo, mynode, orig, fcd, fco, fca, toolconf)
539 r, deleted = func(repo, mynode, orig, fcd, fco, fca, toolconf)
540 return True, r
540 541
541 542 if premerge:
542 543 if orig != fco.path():
543 544 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
544 545 else:
545 546 ui.status(_("merging %s\n") % fd)
546 547
547 548 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
548 549
549 550 if precheck and not precheck(repo, mynode, orig, fcd, fco, fca,
550 551 toolconf):
551 552 if onfailure:
552 553 ui.warn(onfailure % fd)
553 554 return True, 1
554 555
555 556 a = repo.wjoin(fd)
556 557 b = temp("base", fca)
557 558 c = temp("other", fco)
558 559 back = cmdutil.origpath(ui, repo, a)
559 560 if premerge:
560 561 util.copyfile(a, back)
561 562 files = (a, b, c, back)
562 563
563 564 r = 1
564 565 try:
565 566 markerstyle = ui.config('ui', 'mergemarkers', 'basic')
566 567 if not labels:
567 568 labels = _defaultconflictlabels
568 569 if markerstyle != 'basic':
569 570 labels = _formatlabels(repo, fcd, fco, fca, labels)
570 571
571 572 if premerge and mergetype == fullmerge:
572 573 r = _premerge(repo, toolconf, files, labels=labels)
573 574 # complete if premerge successful (r is 0)
574 575 return not r, r
575 576
576 577 needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf, files,
577 578 labels=labels)
578 579 if needcheck:
579 580 r = _check(r, ui, tool, fcd, files)
580 581
581 582 if r:
582 583 if onfailure:
583 584 ui.warn(onfailure % fd)
584 585
585 586 return True, r
586 587 finally:
587 588 if not r:
588 589 util.unlink(back)
589 590 util.unlink(b)
590 591 util.unlink(c)
591 592
592 593 def _check(r, ui, tool, fcd, files):
593 594 fd = fcd.path()
594 595 a, b, c, back = files
595 596
596 597 if not r and (_toolbool(ui, tool, "checkconflicts") or
597 598 'conflicts' in _toollist(ui, tool, "check")):
598 599 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
599 600 re.MULTILINE):
600 601 r = 1
601 602
602 603 checked = False
603 604 if 'prompt' in _toollist(ui, tool, "check"):
604 605 checked = True
605 606 if ui.promptchoice(_("was merge of '%s' successful (yn)?"
606 607 "$$ &Yes $$ &No") % fd, 1):
607 608 r = 1
608 609
609 610 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
610 611 'changed' in
611 612 _toollist(ui, tool, "check")):
612 613 if filecmp.cmp(a, back):
613 614 if ui.promptchoice(_(" output file %s appears unchanged\n"
614 615 "was merge successful (yn)?"
615 616 "$$ &Yes $$ &No") % fd, 1):
616 617 r = 1
617 618
618 619 if _toolbool(ui, tool, "fixeol"):
619 620 _matcheol(a, back)
620 621
621 622 return r
622 623
623 624 def premerge(repo, mynode, orig, fcd, fco, fca, labels=None):
624 625 return _filemerge(True, repo, mynode, orig, fcd, fco, fca, labels=labels)
625 626
626 627 def filemerge(repo, mynode, orig, fcd, fco, fca, labels=None):
627 628 return _filemerge(False, repo, mynode, orig, fcd, fco, fca, labels=labels)
628 629
629 630 # tell hggettext to extract docstrings from these functions:
630 631 i18nfunctions = internals.values()
General Comments 0
You need to be logged in to leave comments. Login now