Fossil SCM
Improvements to the "fossil merge" algorithm so that it works better in complex cases involving branch merges where a file was created on one branch but not the other and had its name changed somewhere along the line. See [forum:/forumpost/549700437b|forum post 549700437b] for discussion.
Commit
cb4f38ee6733dccc54bcbed81cbb98fb20d577de8323bb2f52f11b377a06fbdf
Parent
f35eb8e2c9f8a8f…
1 file changed
+40
-2
+40
-2
| --- src/merge.c | ||
| +++ src/merge.c | ||
| @@ -135,12 +135,12 @@ | ||
| 135 | 135 | ** Add an entry to the FV table for all files renamed between |
| 136 | 136 | ** version N and the version specified by vid. |
| 137 | 137 | */ |
| 138 | 138 | static void add_renames( |
| 139 | 139 | const char *zFnCol, /* The FV column for the filename in vid */ |
| 140 | - int vid, /* The desired version's RID */ | |
| 141 | - int nid, /* Version N's RID */ | |
| 140 | + int vid, /* The desired version's checkin RID */ | |
| 141 | + int nid, /* The checkin rid for the name pivot */ | |
| 142 | 142 | int revOK, /* OK to move backwards (child->parent) if true */ |
| 143 | 143 | const char *zDebug /* Generate trace output if not NULL */ |
| 144 | 144 | ){ |
| 145 | 145 | int nChng; /* Number of file name changes */ |
| 146 | 146 | int *aChng; /* An array of file name changes */ |
| @@ -598,10 +598,48 @@ | ||
| 598 | 598 | ** Compute name changes from N to V, P, and M |
| 599 | 599 | */ |
| 600 | 600 | add_renames("fn", vid, nid, 0, debugFlag ? "N->V" : 0); |
| 601 | 601 | add_renames("fnp", pid, nid, 0, debugFlag ? "N->P" : 0); |
| 602 | 602 | add_renames("fnm", mid, nid, backoutFlag, debugFlag ? "N->M" : 0); |
| 603 | + if( nid!=pid ){ | |
| 604 | + /* See forum thread https://fossil-scm.org/forum/forumpost/549700437b | |
| 605 | + ** | |
| 606 | + ** If a filename changes between nid and one of the other check-ins | |
| 607 | + ** pid, vid, or mid, then it might not have changed for all of them. | |
| 608 | + ** try to fill in the appropriate filename in all slots where the | |
| 609 | + ** name is missing. | |
| 610 | + ** | |
| 611 | + ** This does not work if | |
| 612 | + ** (1) The filename changes more than once in between nid and vid/mid | |
| 613 | + ** (2) Two or more filenames swap places - for example if A is renamed | |
| 614 | + ** to B and B is renamed to A. | |
| 615 | + ** The Fossil merge algorithm breaks down in those cases. It will need | |
| 616 | + ** to be completely rewritten to handle such complex cases. Such cases | |
| 617 | + ** appear to be rare, and also confusing to humans. | |
| 618 | + */ | |
| 619 | + db_multi_exec( | |
| 620 | + "UPDATE fv SET fn=vfile.pathname FROM vfile" | |
| 621 | + " WHERE fn IS NULL" | |
| 622 | + " AND vfile.pathname IN (fv.fnm,fv.fnp,fv.fnn)" | |
| 623 | + " AND vfile.vid=%d;", | |
| 624 | + vid | |
| 625 | + ); | |
| 626 | + db_multi_exec( | |
| 627 | + "UPDATE fv SET fnp=vfile.pathname FROM vfile" | |
| 628 | + " WHERE fnp IS NULL" | |
| 629 | + " AND vfile.pathname IN (fv.fn,fv.fnm,fv.fnn)" | |
| 630 | + " AND vfile.vid=%d;", | |
| 631 | + pid | |
| 632 | + ); | |
| 633 | + db_multi_exec( | |
| 634 | + "UPDATE fv SET fnm=vfile.pathname FROM vfile" | |
| 635 | + " WHERE fnm IS NULL" | |
| 636 | + " AND vfile.pathname IN (fv.fn,fv.fnp,fv.fnn)" | |
| 637 | + " AND vfile.vid=%d;", | |
| 638 | + mid | |
| 639 | + ); | |
| 640 | + } | |
| 603 | 641 | if( debugFlag ){ |
| 604 | 642 | fossil_print("******** FV after name change search *******\n"); |
| 605 | 643 | debug_fv_dump(1); |
| 606 | 644 | } |
| 607 | 645 | |
| 608 | 646 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -135,12 +135,12 @@ | |
| 135 | ** Add an entry to the FV table for all files renamed between |
| 136 | ** version N and the version specified by vid. |
| 137 | */ |
| 138 | static void add_renames( |
| 139 | const char *zFnCol, /* The FV column for the filename in vid */ |
| 140 | int vid, /* The desired version's RID */ |
| 141 | int nid, /* Version N's RID */ |
| 142 | int revOK, /* OK to move backwards (child->parent) if true */ |
| 143 | const char *zDebug /* Generate trace output if not NULL */ |
| 144 | ){ |
| 145 | int nChng; /* Number of file name changes */ |
| 146 | int *aChng; /* An array of file name changes */ |
| @@ -598,10 +598,48 @@ | |
| 598 | ** Compute name changes from N to V, P, and M |
| 599 | */ |
| 600 | add_renames("fn", vid, nid, 0, debugFlag ? "N->V" : 0); |
| 601 | add_renames("fnp", pid, nid, 0, debugFlag ? "N->P" : 0); |
| 602 | add_renames("fnm", mid, nid, backoutFlag, debugFlag ? "N->M" : 0); |
| 603 | if( debugFlag ){ |
| 604 | fossil_print("******** FV after name change search *******\n"); |
| 605 | debug_fv_dump(1); |
| 606 | } |
| 607 | |
| 608 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -135,12 +135,12 @@ | |
| 135 | ** Add an entry to the FV table for all files renamed between |
| 136 | ** version N and the version specified by vid. |
| 137 | */ |
| 138 | static void add_renames( |
| 139 | const char *zFnCol, /* The FV column for the filename in vid */ |
| 140 | int vid, /* The desired version's checkin RID */ |
| 141 | int nid, /* The checkin rid for the name pivot */ |
| 142 | int revOK, /* OK to move backwards (child->parent) if true */ |
| 143 | const char *zDebug /* Generate trace output if not NULL */ |
| 144 | ){ |
| 145 | int nChng; /* Number of file name changes */ |
| 146 | int *aChng; /* An array of file name changes */ |
| @@ -598,10 +598,48 @@ | |
| 598 | ** Compute name changes from N to V, P, and M |
| 599 | */ |
| 600 | add_renames("fn", vid, nid, 0, debugFlag ? "N->V" : 0); |
| 601 | add_renames("fnp", pid, nid, 0, debugFlag ? "N->P" : 0); |
| 602 | add_renames("fnm", mid, nid, backoutFlag, debugFlag ? "N->M" : 0); |
| 603 | if( nid!=pid ){ |
| 604 | /* See forum thread https://fossil-scm.org/forum/forumpost/549700437b |
| 605 | ** |
| 606 | ** If a filename changes between nid and one of the other check-ins |
| 607 | ** pid, vid, or mid, then it might not have changed for all of them. |
| 608 | ** try to fill in the appropriate filename in all slots where the |
| 609 | ** name is missing. |
| 610 | ** |
| 611 | ** This does not work if |
| 612 | ** (1) The filename changes more than once in between nid and vid/mid |
| 613 | ** (2) Two or more filenames swap places - for example if A is renamed |
| 614 | ** to B and B is renamed to A. |
| 615 | ** The Fossil merge algorithm breaks down in those cases. It will need |
| 616 | ** to be completely rewritten to handle such complex cases. Such cases |
| 617 | ** appear to be rare, and also confusing to humans. |
| 618 | */ |
| 619 | db_multi_exec( |
| 620 | "UPDATE fv SET fn=vfile.pathname FROM vfile" |
| 621 | " WHERE fn IS NULL" |
| 622 | " AND vfile.pathname IN (fv.fnm,fv.fnp,fv.fnn)" |
| 623 | " AND vfile.vid=%d;", |
| 624 | vid |
| 625 | ); |
| 626 | db_multi_exec( |
| 627 | "UPDATE fv SET fnp=vfile.pathname FROM vfile" |
| 628 | " WHERE fnp IS NULL" |
| 629 | " AND vfile.pathname IN (fv.fn,fv.fnm,fv.fnn)" |
| 630 | " AND vfile.vid=%d;", |
| 631 | pid |
| 632 | ); |
| 633 | db_multi_exec( |
| 634 | "UPDATE fv SET fnm=vfile.pathname FROM vfile" |
| 635 | " WHERE fnm IS NULL" |
| 636 | " AND vfile.pathname IN (fv.fn,fv.fnp,fv.fnn)" |
| 637 | " AND vfile.vid=%d;", |
| 638 | mid |
| 639 | ); |
| 640 | } |
| 641 | if( debugFlag ){ |
| 642 | fossil_print("******** FV after name change search *******\n"); |
| 643 | debug_fv_dump(1); |
| 644 | } |
| 645 | |
| 646 |