Mercurial > hg
comparison tests/test-tag.t @ 21922:50e20154cb68
filemerge: add internal:tagmerge merge tool
Add a new internal:tagmerge merge tool which implements an automatic merge
algorithm for mercurial's tag files
The tagmerge algorithm is able to resolve most merge conflicts that
currently would trigger a .hgtags merge conflict. The only case that
it does not (and cannot) handle is that in which two tags point to
different revisions on each merge parent _and_ their corresponding tag
histories have the same rank (i.e. the same length). In all other
cases the merge algorithm will choose the revision belonging to the
parent with the highest ranked tag history. The merged tag history is
the combination of both tag histories (special care is taken to try to
combine common tag histories where possible).
The algorithm also handles cases in which tags have been manually
removed from the .hgtags file and other similar corner cases.
In addition to actually merging the tags from two parents, taking into
account the base, the algorithm also tries to minimize the difference
between the merged tag file and the first parent's tag file (i.e. it
tries to make the merged tag order as as similar as possible to the
first parent's tag file order).
The algorithm works as follows:
1. read the tags from p1, p2 and the base
- when reading the p1 tags, also get the line numbers associated to each
tag node (these will be used to sort the merged tags in a way that
minimizes the diff to p1). Ignore the file numbers when reading p2 and
the base
2. recover the "lost tags" (i.e. those that are found in the base but not on p1
or p2) and add them back to p1 and/or p2
- at this point the only tags that are on p1 but not on p2 are those new
tags that were introduced in p1. Same thing for the tags that are on p2
but not on p2
3. take all tags that are only on p1 or only on p2 (but not on the base)
- Note that these are the tags that were introduced between base and p1 and
between base and p2, possibly on separate clones
4. for each tag found both on p1 and p2 perform the following merge algorithm:
- the tags conflict if their tag "histories" have the same "rank" (i.e.
length) _AND_ the last (current) tag is _NOT_ the same
- for non conflicting tags:
- choose which are the high and the low ranking nodes
- the high ranking list of nodes is the one that is longer.
In case of draw favor p1
- the merged node list is made of 3 parts:
- first the nodes that are common to the beginning of both the
low and the high ranking nodes
- second the non common low ranking nodes
- finally the non common high ranking nodes (with the last one
being the merged tag node)
- note that this is equivalent to putting the whole low ranking node
list first, followed by the non common high ranking nodes
- note that during the merge we keep the "node line numbers", which will
be used when writing the merged tags to the tag file
5. write the merged tags taking into account to their positions in the first
parent (i.e. try to keep the relative ordering of the nodes that come
from p1). This minimizes the diff between the merged and the p1 tag files
This is done by using the following algorithm
- group the nodes for a given tag that must be written next to each other
- A: nodes that come from consecutive lines on p1
- B: nodes that come from p2 (i.e. whose associated line number is None)
and are next to one of the a nodes in A
- each group is associated with a line number coming from p1
- generate a "tag block" for each of the groups
- a tag block is a set of consecutive "node tag" lines belonging to the
same tag and which will be written next to each other on the merged
tags file
- sort the "tag blocks" according to their associated number line
- put blocks whose nodes come all from p2 first
- write the tag blocks in the sorted order
Notes:
- A few tests have been added to test-tag.t. These tests are very specific to
the new internal:tagmerge tool, so perhaps they should be moved to their own
test file.
- The merge algorithm was discussed in a thread on the mercurial mailing list.
In http://markmail.org/message/anqaxldup4tmgyrx a slightly different algorithm
was suggested. In it the p1 and p2 tags would have been interleaved instead of
put one before the other. It would be possible to implement that but my tests
suggest that the merge result would be more confusing and harder to understand.
author | Angel Ezquerra <angel.ezquerra@gmail.com> |
---|---|
date | Thu, 26 Jun 2014 01:20:25 +0200 |
parents | d4b8fc753455 |
children | a5168eb9b2bc |
comparison
equal
deleted
inserted
replaced
21921:ecc1387138ba | 21922:50e20154cb68 |
---|---|
401 adding changesets | 401 adding changesets |
402 adding manifests | 402 adding manifests |
403 adding file changes | 403 adding file changes |
404 added 2 changesets with 2 changes to 2 files | 404 added 2 changesets with 2 changes to 2 files |
405 | 405 |
406 automatically merge resolvable tag conflicts (i.e. tags that differ in rank) | |
407 create two clones with some different tags as well as some common tags | |
408 check that we can merge tags that differ in rank | |
409 | |
410 $ hg init repo-automatic-tag-merge | |
411 $ cd repo-automatic-tag-merge | |
412 $ echo c0 > f0 | |
413 $ hg ci -A -m0 | |
414 adding f0 | |
415 $ hg tag tbase | |
416 $ cd .. | |
417 $ hg clone repo-automatic-tag-merge repo-automatic-tag-merge-clone | |
418 updating to branch default | |
419 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
420 $ cd repo-automatic-tag-merge-clone | |
421 $ echo c1 > f1 | |
422 $ hg ci -A -m1 | |
423 adding f1 | |
424 $ hg tag t1 t2 t3 | |
425 $ hg tag --remove t2 | |
426 $ hg tag t5 | |
427 $ echo c2 > f2 | |
428 $ hg ci -A -m2 | |
429 adding f2 | |
430 $ hg tag -f t3 | |
431 | |
432 $ cd ../repo-automatic-tag-merge | |
433 $ echo c3 > f3 | |
434 $ hg ci -A -m3 | |
435 adding f3 | |
436 $ hg tag -f t4 t5 t6 | |
437 $ hg tag --remove t5 | |
438 $ echo c4 > f4 | |
439 $ hg ci -A -m4 | |
440 adding f4 | |
441 $ hg tag t2 | |
442 $ hg tag -f t6 | |
443 | |
444 $ cd ../repo-automatic-tag-merge-clone | |
445 $ hg pull | |
446 pulling from $TESTTMP/repo-automatic-tag-merge (glob) | |
447 searching for changes | |
448 adding changesets | |
449 adding manifests | |
450 adding file changes | |
451 added 6 changesets with 6 changes to 3 files (+1 heads) | |
452 (run 'hg heads' to see heads, 'hg merge' to merge) | |
453 $ hg merge --tool internal:tagmerge | |
454 merging .hgtags | |
455 2 files updated, 1 files merged, 0 files removed, 0 files unresolved | |
456 (branch merge, don't forget to commit) | |
457 $ hg status | |
458 M .hgtags | |
459 M f3 | |
460 M f4 | |
461 $ hg resolve -l | |
462 R .hgtags | |
463 $ cat .hgtags | |
464 9aa4e1292a27a248f8d07339bed9931d54907be7 t4 | |
465 9aa4e1292a27a248f8d07339bed9931d54907be7 t6 | |
466 9aa4e1292a27a248f8d07339bed9931d54907be7 t6 | |
467 09af2ce14077a94effef208b49a718f4836d4338 t6 | |
468 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase | |
469 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1 | |
470 929bca7b18d067cbf3844c3896319a940059d748 t2 | |
471 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2 | |
472 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3 | |
473 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2 | |
474 0000000000000000000000000000000000000000 t2 | |
475 875517b4806a848f942811a315a5bce30804ae85 t5 | |
476 9aa4e1292a27a248f8d07339bed9931d54907be7 t5 | |
477 9aa4e1292a27a248f8d07339bed9931d54907be7 t5 | |
478 0000000000000000000000000000000000000000 t5 | |
479 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3 | |
480 79505d5360b07e3e79d1052e347e73c02b8afa5b t3 | |
481 | |
482 check that the merge tried to minimize the diff witht he first merge parent | |
483 | |
484 $ hg diff --git -r 'p1()' .hgtags | |
485 diff --git a/.hgtags b/.hgtags | |
486 --- a/.hgtags | |
487 +++ b/.hgtags | |
488 @@ -1,9 +1,17 @@ | |
489 +9aa4e1292a27a248f8d07339bed9931d54907be7 t4 | |
490 +9aa4e1292a27a248f8d07339bed9931d54907be7 t6 | |
491 +9aa4e1292a27a248f8d07339bed9931d54907be7 t6 | |
492 +09af2ce14077a94effef208b49a718f4836d4338 t6 | |
493 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase | |
494 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1 | |
495 +929bca7b18d067cbf3844c3896319a940059d748 t2 | |
496 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2 | |
497 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3 | |
498 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2 | |
499 0000000000000000000000000000000000000000 t2 | |
500 875517b4806a848f942811a315a5bce30804ae85 t5 | |
501 +9aa4e1292a27a248f8d07339bed9931d54907be7 t5 | |
502 +9aa4e1292a27a248f8d07339bed9931d54907be7 t5 | |
503 +0000000000000000000000000000000000000000 t5 | |
504 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3 | |
505 79505d5360b07e3e79d1052e347e73c02b8afa5b t3 | |
506 | |
507 detect merge tag conflicts | |
508 | |
509 $ hg update -C -r tip | |
510 3 files updated, 0 files merged, 2 files removed, 0 files unresolved | |
511 $ hg tag t7 | |
512 $ hg update -C -r 'first(sort(head()))' | |
513 3 files updated, 0 files merged, 2 files removed, 0 files unresolved | |
514 $ printf "%s %s\n" `hg log -r . --template "{node} t7"` >> .hgtags | |
515 $ hg commit -m "manually add conflicting t7 tag" | |
516 $ hg merge --tool internal:tagmerge | |
517 merging .hgtags | |
518 automatic .hgtags merge failed | |
519 the following 1 tags are in conflict: t7 | |
520 automatic tag merging of .hgtags failed! (use 'hg resolve --tool internal:merge' or another merge tool of your choice) | |
521 2 files updated, 0 files merged, 0 files removed, 1 files unresolved | |
522 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon | |
523 [1] | |
524 $ hg resolve -l | |
525 U .hgtags | |
526 $ cat .hgtags | |
527 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase | |
528 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1 | |
529 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2 | |
530 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3 | |
531 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2 | |
532 0000000000000000000000000000000000000000 t2 | |
533 875517b4806a848f942811a315a5bce30804ae85 t5 | |
534 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3 | |
535 79505d5360b07e3e79d1052e347e73c02b8afa5b t3 | |
536 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7 | |
537 | |
538 $ cd .. | |
539 | |
540 handle the loss of tags | |
541 | |
542 $ hg clone repo-automatic-tag-merge-clone repo-merge-lost-tags | |
543 updating to branch default | |
544 4 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
545 $ cd repo-merge-lost-tags | |
546 $ echo c5 > f5 | |
547 $ hg ci -A -m5 | |
548 adding f5 | |
549 $ hg tag -f t7 | |
550 $ hg update -r 'p1(t7)' | |
551 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |
552 $ printf '' > .hgtags | |
553 $ hg commit -m 'delete all tags' | |
554 created new head | |
555 $ hg update -r 'max(t7::)' | |
556 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
557 $ hg merge -r tip --tool internal:tagmerge | |
558 merging .hgtags | |
559 0 files updated, 1 files merged, 0 files removed, 0 files unresolved | |
560 (branch merge, don't forget to commit) | |
561 $ hg resolve -l | |
562 R .hgtags | |
563 $ cat .hgtags | |
564 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase | |
565 0000000000000000000000000000000000000000 tbase | |
566 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1 | |
567 0000000000000000000000000000000000000000 t1 | |
568 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2 | |
569 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3 | |
570 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2 | |
571 0000000000000000000000000000000000000000 t2 | |
572 875517b4806a848f942811a315a5bce30804ae85 t5 | |
573 0000000000000000000000000000000000000000 t5 | |
574 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3 | |
575 79505d5360b07e3e79d1052e347e73c02b8afa5b t3 | |
576 0000000000000000000000000000000000000000 t3 | |
577 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7 | |
578 0000000000000000000000000000000000000000 t7 | |
579 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7 | |
580 fd3a9e394ce3afb354a496323bf68ac1755a30de t7 | |
581 | |
582 also check that we minimize the diff with the 1st merge parent | |
583 | |
584 $ hg diff --git -r 'p1()' .hgtags | |
585 diff --git a/.hgtags b/.hgtags | |
586 --- a/.hgtags | |
587 +++ b/.hgtags | |
588 @@ -1,12 +1,17 @@ | |
589 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase | |
590 +0000000000000000000000000000000000000000 tbase | |
591 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1 | |
592 +0000000000000000000000000000000000000000 t1 | |
593 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2 | |
594 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3 | |
595 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2 | |
596 0000000000000000000000000000000000000000 t2 | |
597 875517b4806a848f942811a315a5bce30804ae85 t5 | |
598 +0000000000000000000000000000000000000000 t5 | |
599 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3 | |
600 79505d5360b07e3e79d1052e347e73c02b8afa5b t3 | |
601 +0000000000000000000000000000000000000000 t3 | |
602 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7 | |
603 +0000000000000000000000000000000000000000 t7 | |
604 ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7 | |
605 fd3a9e394ce3afb354a496323bf68ac1755a30de t7 | |
606 |