Show More
@@ -532,6 +532,33 b' def _imerge3(repo, mynode, orig, fcd, fc' | |||||
532 | return _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels) |
|
532 | return _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels) | |
533 |
|
533 | |||
534 |
|
534 | |||
|
535 | @internaltool( | |||
|
536 | b'mergediff', | |||
|
537 | fullmerge, | |||
|
538 | _( | |||
|
539 | b"warning: conflicts while merging %s! " | |||
|
540 | b"(edit, then use 'hg resolve --mark')\n" | |||
|
541 | ), | |||
|
542 | precheck=_mergecheck, | |||
|
543 | ) | |||
|
544 | def _imerge_diff( | |||
|
545 | repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None | |||
|
546 | ): | |||
|
547 | """ | |||
|
548 | Uses the internal non-interactive simple merge algorithm for merging | |||
|
549 | files. It will fail if there are any conflicts and leave markers in | |||
|
550 | the partially merged file. The marker will have two sections, one with the | |||
|
551 | content from one side of the merge, and one with a diff from the base | |||
|
552 | content to the content on the other side. (experimental)""" | |||
|
553 | if not labels: | |||
|
554 | labels = _defaultconflictlabels | |||
|
555 | if len(labels) < 3: | |||
|
556 | labels.append(b'base') | |||
|
557 | return _merge( | |||
|
558 | repo, mynode, orig, fcd, fco, fca, toolconf, files, labels, b'mergediff' | |||
|
559 | ) | |||
|
560 | ||||
|
561 | ||||
535 | def _imergeauto( |
|
562 | def _imergeauto( | |
536 | repo, |
|
563 | repo, | |
537 | mynode, |
|
564 | mynode, |
@@ -455,6 +455,68 b' def is_not_null(ctx):' | |||||
455 | return ctx.node() != nodemod.nullid |
|
455 | return ctx.node() != nodemod.nullid | |
456 |
|
456 | |||
457 |
|
457 | |||
|
458 | def _mergediff(m3, name_a, name_b, name_base): | |||
|
459 | lines = [] | |||
|
460 | conflicts = False | |||
|
461 | for group in m3.merge_groups(): | |||
|
462 | if group[0] == b'conflict': | |||
|
463 | base_lines, a_lines, b_lines = group[1:] | |||
|
464 | base_text = b''.join(base_lines) | |||
|
465 | b_blocks = list( | |||
|
466 | mdiff.allblocks( | |||
|
467 | base_text, | |||
|
468 | b''.join(b_lines), | |||
|
469 | lines1=base_lines, | |||
|
470 | lines2=b_lines, | |||
|
471 | ) | |||
|
472 | ) | |||
|
473 | a_blocks = list( | |||
|
474 | mdiff.allblocks( | |||
|
475 | base_text, | |||
|
476 | b''.join(a_lines), | |||
|
477 | lines1=base_lines, | |||
|
478 | lines2=b_lines, | |||
|
479 | ) | |||
|
480 | ) | |||
|
481 | ||||
|
482 | def matching_lines(blocks): | |||
|
483 | return sum( | |||
|
484 | block[1] - block[0] | |||
|
485 | for block, kind in blocks | |||
|
486 | if kind == b'=' | |||
|
487 | ) | |||
|
488 | ||||
|
489 | def diff_lines(blocks, lines1, lines2): | |||
|
490 | for block, kind in blocks: | |||
|
491 | if kind == b'=': | |||
|
492 | for line in lines1[block[0] : block[1]]: | |||
|
493 | yield b' ' + line | |||
|
494 | else: | |||
|
495 | for line in lines1[block[0] : block[1]]: | |||
|
496 | yield b'-' + line | |||
|
497 | for line in lines2[block[2] : block[3]]: | |||
|
498 | yield b'+' + line | |||
|
499 | ||||
|
500 | lines.append(b"<<<<<<<\n") | |||
|
501 | if matching_lines(a_blocks) < matching_lines(b_blocks): | |||
|
502 | lines.append(b"======= %s\n" % name_a) | |||
|
503 | lines.extend(a_lines) | |||
|
504 | lines.append(b"------- %s\n" % name_base) | |||
|
505 | lines.append(b"+++++++ %s\n" % name_b) | |||
|
506 | lines.extend(diff_lines(b_blocks, base_lines, b_lines)) | |||
|
507 | else: | |||
|
508 | lines.append(b"------- %s\n" % name_base) | |||
|
509 | lines.append(b"+++++++ %s\n" % name_a) | |||
|
510 | lines.extend(diff_lines(a_blocks, base_lines, a_lines)) | |||
|
511 | lines.append(b"======= %s\n" % name_b) | |||
|
512 | lines.extend(b_lines) | |||
|
513 | lines.append(b">>>>>>>\n") | |||
|
514 | conflicts = True | |||
|
515 | else: | |||
|
516 | lines.extend(group[1]) | |||
|
517 | return lines, conflicts | |||
|
518 | ||||
|
519 | ||||
458 | def simplemerge(ui, localctx, basectx, otherctx, **opts): |
|
520 | def simplemerge(ui, localctx, basectx, otherctx, **opts): | |
459 | """Performs the simplemerge algorithm. |
|
521 | """Performs the simplemerge algorithm. | |
460 |
|
522 | |||
@@ -499,9 +561,15 b' def simplemerge(ui, localctx, basectx, o' | |||||
499 | extrakwargs[b'name_base'] = name_base |
|
561 | extrakwargs[b'name_base'] = name_base | |
500 | extrakwargs[b'minimize'] = False |
|
562 | extrakwargs[b'minimize'] = False | |
501 |
|
563 | |||
502 | lines = m3.merge_lines( |
|
564 | if mode == b'mergediff': | |
|
565 | lines, conflicts = _mergediff(m3, name_a, name_b, name_base) | |||
|
566 | else: | |||
|
567 | lines = list( | |||
|
568 | m3.merge_lines( | |||
503 | name_a=name_a, name_b=name_b, **pycompat.strkwargs(extrakwargs) |
|
569 | name_a=name_a, name_b=name_b, **pycompat.strkwargs(extrakwargs) | |
504 | ) |
|
570 | ) | |
|
571 | ) | |||
|
572 | conflicts = m3.conflicts | |||
505 |
|
573 | |||
506 | # merge flags if necessary |
|
574 | # merge flags if necessary | |
507 | flags = localctx.flags() |
|
575 | flags = localctx.flags() | |
@@ -519,5 +587,5 b' def simplemerge(ui, localctx, basectx, o' | |||||
519 | else: |
|
587 | else: | |
520 | localctx.write(mergedtext, flags) |
|
588 | localctx.write(mergedtext, flags) | |
521 |
|
589 | |||
522 |
if |
|
590 | if conflicts and not mode == b'union': | |
523 | return 1 |
|
591 | return 1 |
@@ -27,6 +27,13 b'' | |||||
27 | * The memory footprint per changeset during pull/unbundle |
|
27 | * The memory footprint per changeset during pull/unbundle | |
28 | operations has been further reduced. |
|
28 | operations has been further reduced. | |
29 |
|
29 | |||
|
30 | * There is a new internal merge tool called `internal:mergediff` (can | |||
|
31 | be set as the value for the `merge` config in the `[ui]` | |||
|
32 | section). It resolves merges the same was as `internal:merge` and | |||
|
33 | `internal:merge3`, but it shows conflicts differently. Instead of | |||
|
34 | showing 2 or 3 snapshots of the conflicting pieces of code, it | |||
|
35 | shows one snapshot and a diff. This may be useful when at least one | |||
|
36 | side of the conflict is similar to the base. | |||
30 |
|
37 | |||
31 | == New Experimental Features == |
|
38 | == New Experimental Features == | |
32 |
|
39 |
@@ -282,6 +282,80 b' internal:merge3' | |||||
282 | >>>>>>> merge rev |
|
282 | >>>>>>> merge rev | |
283 | Hop we are done. |
|
283 | Hop we are done. | |
284 |
|
284 | |||
|
285 | internal:mergediff | |||
|
286 | ||||
|
287 | $ hg co -C 1 | |||
|
288 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
289 | $ cat << EOF > a | |||
|
290 | > Small Mathematical Series. | |||
|
291 | > 1 | |||
|
292 | > 2 | |||
|
293 | > 3 | |||
|
294 | > 4 | |||
|
295 | > 4.5 | |||
|
296 | > 5 | |||
|
297 | > Hop we are done. | |||
|
298 | > EOF | |||
|
299 | $ hg co -m 2 -t internal:mergediff | |||
|
300 | merging a | |||
|
301 | warning: conflicts while merging a! (edit, then use 'hg resolve --mark') | |||
|
302 | 0 files updated, 0 files merged, 0 files removed, 1 files unresolved | |||
|
303 | use 'hg resolve' to retry unresolved file merges | |||
|
304 | [1] | |||
|
305 | $ cat a | |||
|
306 | Small Mathematical Series. | |||
|
307 | 1 | |||
|
308 | 2 | |||
|
309 | 3 | |||
|
310 | <<<<<<< | |||
|
311 | ------- base | |||
|
312 | +++++++ working copy | |||
|
313 | 4 | |||
|
314 | +4.5 | |||
|
315 | 5 | |||
|
316 | ======= destination | |||
|
317 | 6 | |||
|
318 | 8 | |||
|
319 | >>>>>>> | |||
|
320 | Hop we are done. | |||
|
321 | Test the same thing as above but modify a bit more so we instead get the working | |||
|
322 | copy in full and the diff from base to destination. | |||
|
323 | $ hg co -C 1 | |||
|
324 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |||
|
325 | $ cat << EOF > a | |||
|
326 | > Small Mathematical Series. | |||
|
327 | > 1 | |||
|
328 | > 2 | |||
|
329 | > 3.5 | |||
|
330 | > 4.5 | |||
|
331 | > 5.5 | |||
|
332 | > Hop we are done. | |||
|
333 | > EOF | |||
|
334 | $ hg co -m 2 -t internal:mergediff | |||
|
335 | merging a | |||
|
336 | warning: conflicts while merging a! (edit, then use 'hg resolve --mark') | |||
|
337 | 0 files updated, 0 files merged, 0 files removed, 1 files unresolved | |||
|
338 | use 'hg resolve' to retry unresolved file merges | |||
|
339 | [1] | |||
|
340 | $ cat a | |||
|
341 | Small Mathematical Series. | |||
|
342 | 1 | |||
|
343 | 2 | |||
|
344 | <<<<<<< | |||
|
345 | ======= working copy | |||
|
346 | 3.5 | |||
|
347 | 4.5 | |||
|
348 | 5.5 | |||
|
349 | ------- base | |||
|
350 | +++++++ destination | |||
|
351 | 3 | |||
|
352 | -4 | |||
|
353 | -5 | |||
|
354 | +6 | |||
|
355 | +8 | |||
|
356 | >>>>>>> | |||
|
357 | Hop we are done. | |||
|
358 | ||||
285 | Add some unconflicting changes on each head, to make sure we really |
|
359 | Add some unconflicting changes on each head, to make sure we really | |
286 | are merging, unlike :local and :other |
|
360 | are merging, unlike :local and :other | |
287 |
|
361 |
@@ -2057,6 +2057,13 b' Test dynamic list of merge tools only sh' | |||||
2057 | partially merged file. Marker will have three sections, one from each |
|
2057 | partially merged file. Marker will have three sections, one from each | |
2058 | side of the merge and one for the base content. |
|
2058 | side of the merge and one for the base content. | |
2059 |
|
2059 | |||
|
2060 | ":mergediff" | |||
|
2061 | Uses the internal non-interactive simple merge algorithm for merging | |||
|
2062 | files. It will fail if there are any conflicts and leave markers in the | |||
|
2063 | partially merged file. The marker will have two sections, one with the | |||
|
2064 | content from one side of the merge, and one with a diff from the base | |||
|
2065 | content to the content on the other side. (experimental) | |||
|
2066 | ||||
2060 | ":other" |
|
2067 | ":other" | |
2061 | Uses the other 'p2()' version of files as the merged version. |
|
2068 | Uses the other 'p2()' version of files as the merged version. | |
2062 |
|
2069 |
General Comments 0
You need to be logged in to leave comments.
Login now