Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a bug in the "fossil patch pull" command that caused "fossil revert" that occurs after a "fossil merge" to be lost. Also, improve "fossil patch pull" so that it does not mess with the undo log and does not do unnecessary syncs. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
3a39ae4c87773acf4c86e5229c49d7cd |
User & Date: | drh 2024-12-16 16:17:49 |
References
2024-12-16
| ||
16:21 | • Reply: Bug in "fossil patch pull" ... (artifact: 2456e414 user: drh) | |
Context
2024-12-16
| ||
16:22 | Add missing word in the help text for 'merge'. ... (check-in: bdc6bb1c user: danield tags: trunk) | |
16:17 | Fix a bug in the "fossil patch pull" command that caused "fossil revert" that occurs after a "fossil merge" to be lost. Also, improve "fossil patch pull" so that it does not mess with the undo log and does not do unnecessary syncs. ... (check-in: 3a39ae4c user: drh tags: trunk) | |
16:15 | Do not sync or fill the undo log when running subcommands due to patch. ... (Closed-Leaf check-in: cf8f0e4d user: drh tags: patch-pull-fix) | |
07:40 | Internal tweaks and docs in the diff-toggling code. No visible changes. ... (check-in: 6f263954 user: stephan tags: trunk) | |
Changes
Changes to src/merge.c.
︙ | ︙ | |||
685 686 687 688 689 690 691 692 693 694 695 696 697 698 | ** --force-missing Force the merge even if there is missing content ** --integrate Merged branch will be closed when committing ** -K|--keep-merge-files On merge conflict, retain the temporary files ** used for merging, named *-baseline, *-original, ** and *-merge. ** -n|--dry-run Do not actually change files on disk ** --nosync Do not auto-sync prior to merging ** -v|--verbose Show additional details of the merge */ void merge_cmd(void){ int vid; /* Current version "V" */ int mid; /* Version we are merging from "M" */ int pid = 0; /* The pivot version - most recent common ancestor P */ int nid = 0; /* The name pivot version "N" */ | > | 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 | ** --force-missing Force the merge even if there is missing content ** --integrate Merged branch will be closed when committing ** -K|--keep-merge-files On merge conflict, retain the temporary files ** used for merging, named *-baseline, *-original, ** and *-merge. ** -n|--dry-run Do not actually change files on disk ** --nosync Do not auto-sync prior to merging ** --noundo Do not changes in the undo log ** -v|--verbose Show additional details of the merge */ void merge_cmd(void){ int vid; /* Current version "V" */ int mid; /* Version we are merging from "M" */ int pid = 0; /* The pivot version - most recent common ancestor P */ int nid = 0; /* The name pivot version "N" */ |
︙ | ︙ | |||
710 711 712 713 714 715 716 717 718 719 720 721 722 723 | int keepMergeFlag; /* True if --keep-merge-files is present */ int nConflict = 0; /* Number of conflicts seen */ int nOverwrite = 0; /* Number of unmanaged files overwritten */ char vAncestor = 'p'; /* If P is an ancestor of V then 'p', else 'n' */ const char *zVersion; /* The VERSION argument */ int bMultiMerge = 0; /* True if there are two or more VERSION arguments */ int nMerge = 0; /* Number of prior merges processed */ Stmt q; /* SQL statment used for merge processing */ /* Notation: ** ** V The current check-out ** M The version being merged in | > | 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 | int keepMergeFlag; /* True if --keep-merge-files is present */ int nConflict = 0; /* Number of conflicts seen */ int nOverwrite = 0; /* Number of unmanaged files overwritten */ char vAncestor = 'p'; /* If P is an ancestor of V then 'p', else 'n' */ const char *zVersion; /* The VERSION argument */ int bMultiMerge = 0; /* True if there are two or more VERSION arguments */ int nMerge = 0; /* Number of prior merges processed */ int useUndo = 1; /* True to record changes in the undo log */ Stmt q; /* SQL statment used for merge processing */ /* Notation: ** ** V The current check-out ** M The version being merged in |
︙ | ︙ | |||
758 759 760 761 762 763 764 765 766 767 768 769 770 771 | ** Hints: ** * Combine --debug and --verbose for still more output. ** * The --dry-run option is also useful in combination with --debug. */ debugFlag = find_option("debug",0,0)!=0; if( debugFlag && verboseFlag ) debugFlag = 2; showVfileFlag = find_option("show-vfile",0,0)!=0; verify_all_options(); db_must_be_within_tree(); if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); vid = db_lget_int("checkout", 0); if( vid==0 ){ fossil_fatal("nothing is checked out"); | > > | 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 | ** Hints: ** * Combine --debug and --verbose for still more output. ** * The --dry-run option is also useful in combination with --debug. */ debugFlag = find_option("debug",0,0)!=0; if( debugFlag && verboseFlag ) debugFlag = 2; showVfileFlag = find_option("show-vfile",0,0)!=0; useUndo = find_option("noundo",0,0)==0; if( dryRunFlag ) useUndo = 0; verify_all_options(); db_must_be_within_tree(); if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); vid = db_lget_int("checkout", 0); if( vid==0 ){ fossil_fatal("nothing is checked out"); |
︙ | ︙ | |||
924 925 926 927 928 929 930 | if( verboseFlag ){ print_checkin_description(mid, 12, integrateFlag ? "integrate:" : "merge-from:"); print_checkin_description(pid, 12, "baseline:"); } vfile_check_signature(vid, CKSIG_ENOTFILE); if( nMerge==0 ) db_begin_transaction(); | | | 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 | if( verboseFlag ){ print_checkin_description(mid, 12, integrateFlag ? "integrate:" : "merge-from:"); print_checkin_description(pid, 12, "baseline:"); } vfile_check_signature(vid, CKSIG_ENOTFILE); if( nMerge==0 ) db_begin_transaction(); if( useUndo ) undo_begin(); if( load_vfile_from_rid(mid) && !forceMissingFlag ){ fossil_fatal("missing content, unable to merge"); } if( load_vfile_from_rid(pid) && !forceMissingFlag ){ fossil_fatal("missing content, unable to merge"); } if( zPivot ){ |
︙ | ︙ | |||
1181 1182 1183 1184 1185 1186 1187 1188 | while( db_step(&q)==SQLITE_ROW ){ int idv = db_column_int(&q, 0); int ridm = db_column_int(&q, 1); const char *zName = db_column_text(&q, 2); int islinkm = db_column_int(&q, 3); /* Copy content from idm over into idv. Overwrite idv. */ fossil_print("UPDATE %s\n", zName); if( !dryRunFlag ){ | > < | 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 | while( db_step(&q)==SQLITE_ROW ){ int idv = db_column_int(&q, 0); int ridm = db_column_int(&q, 1); const char *zName = db_column_text(&q, 2); int islinkm = db_column_int(&q, 3); /* Copy content from idm over into idv. Overwrite idv. */ fossil_print("UPDATE %s\n", zName); if( useUndo ) undo_save(zName); if( !dryRunFlag ){ db_multi_exec( "UPDATE vfile SET mtime=0, mrid=%d, chnged=%d, islink=%d," " mhash=CASE WHEN rid<>%d" " THEN (SELECT uuid FROM blob WHERE blob.rid=%d) END" " WHERE id=%d", ridm, integrateFlag?4:2, islinkm, ridm, ridm, idv ); vfile_to_disk(0, idv, 0, 0); |
︙ | ︙ | |||
1263 1264 1265 1266 1267 1268 1269 | /* fnr */ zName ); }else{ i64 sz; const char *zErrMsg = 0; int nc = 0; | | | 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 | /* fnr */ zName ); }else{ i64 sz; const char *zErrMsg = 0; int nc = 0; if( useUndo ) undo_save(zName); zFullPath = mprintf("%s/%s", g.zLocalRoot, zName); sz = file_size(zFullPath, ExtFILE); content_get(ridp, &p); content_get(ridm, &m); if( isBinary ){ rc = -1; blob_zero(&r); |
︙ | ︙ | |||
1350 1351 1352 1353 1354 1355 1356 | ridv = 0; nc = 1; zErrMsg = "local edits lost"; zFullPath = mprintf("%s/%s", g.zLocalRoot, zName); sz = file_size(zFullPath, ExtFILE); fossil_free(zFullPath); } | | | 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 | ridv = 0; nc = 1; zErrMsg = "local edits lost"; zFullPath = mprintf("%s/%s", g.zLocalRoot, zName); sz = file_size(zFullPath, ExtFILE); fossil_free(zFullPath); } if( useUndo ) undo_save(zName); db_multi_exec( "UPDATE vfile SET deleted=1 WHERE id=%d", idv ); if( !dryRunFlag ){ char *zFullPath = mprintf("%s%s", g.zLocalRoot, zName); file_delete(zFullPath); free(zFullPath); |
︙ | ︙ | |||
1397 1398 1399 1400 1401 1402 1403 | ); while( db_step(&q)==SQLITE_ROW ){ int idv = db_column_int(&q, 0); const char *zOldName = db_column_text(&q, 1); const char *zNewName = db_column_text(&q, 2); int isExe = db_column_int(&q, 3); fossil_print("RENAME %s -> %s\n", zOldName, zNewName); | | | | 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 | ); while( db_step(&q)==SQLITE_ROW ){ int idv = db_column_int(&q, 0); const char *zOldName = db_column_text(&q, 1); const char *zNewName = db_column_text(&q, 2); int isExe = db_column_int(&q, 3); fossil_print("RENAME %s -> %s\n", zOldName, zNewName); if( useUndo ) undo_save(zOldName); if( useUndo ) undo_save(zNewName); db_multi_exec( "UPDATE mergestat SET fnr=fnm WHERE fnp=%Q", zOldName ); db_multi_exec( "UPDATE vfile SET pathname=NULL, origname=pathname" " WHERE vid=%d AND pathname=%Q;" |
︙ | ︙ | |||
1496 1497 1498 1499 1500 1501 1502 1503 | db_multi_exec( "INSERT INTO mergestat(op,fnm,ridm,fnr)" "VALUES('ADDED',%Q,%d,%Q)", /* fnm */ zName, /* ridm */ db_column_int(&q,2), /* fnr */ zName ); if( !dryRunFlag ){ | > < | 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 | db_multi_exec( "INSERT INTO mergestat(op,fnm,ridm,fnr)" "VALUES('ADDED',%Q,%d,%Q)", /* fnm */ zName, /* ridm */ db_column_int(&q,2), /* fnr */ zName ); if( useUndo ) undo_save(zName); if( !dryRunFlag ){ vfile_to_disk(0, idm, 0, 0); } } db_finalize(&q); /* Report on conflicts */ |
︙ | ︙ | |||
1556 1557 1558 1559 1560 1561 1562 | }else{ vmerge_insert(0, mid); } if( bMultiMerge && nConflict==0 ){ nMerge++; goto merge_next_child; } | | | 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 | }else{ vmerge_insert(0, mid); } if( bMultiMerge && nConflict==0 ){ nMerge++; goto merge_next_child; } if( useUndo ) undo_finish(); db_end_transaction(dryRunFlag); } |
Changes to src/patch.c.
︙ | ︙ | |||
385 386 387 388 389 390 391 | blob_init(&cmd, 0, 0); if( unsaved_changes(0) ){ if( (mFlags & PATCH_FORCE)==0 ){ fossil_fatal("Cannot apply patch: there are unsaved changes " "in the current check-out"); }else{ | | | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | blob_init(&cmd, 0, 0); if( unsaved_changes(0) ){ if( (mFlags & PATCH_FORCE)==0 ){ fossil_fatal("Cannot apply patch: there are unsaved changes " "in the current check-out"); }else{ blob_appendf(&cmd, "%$ revert --noundo", g.nameOfExe); if( mFlags & PATCH_DRYRUN ){ fossil_print("%s\n", blob_str(&cmd)); }else{ int rc = fossil_system(blob_str(&cmd)); if( rc ){ fossil_fatal("unable to revert preexisting changes: %s", blob_str(&cmd)); |
︙ | ︙ | |||
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 | fossil_fatal("unable to update to the baseline check-out: %s", blob_str(&cmd)); } } } blob_reset(&cmd); if( db_table_exists("patch","patchmerge") ){ db_prepare(&q, "SELECT type, mhash, upper(type) FROM patch.patchmerge" " WHERE type IN ('merge','cherrypick','backout','integrate')" " AND mhash NOT GLOB '*[^a-fA-F0-9]*';" ); while( db_step(&q)==SQLITE_ROW ){ const char *zType = db_column_text(&q,0); blob_append_escaped_arg(&cmd, g.nameOfExe, 1); if( strcmp(zType,"merge")==0 ){ | > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 | fossil_fatal("unable to update to the baseline check-out: %s", blob_str(&cmd)); } } } blob_reset(&cmd); if( db_table_exists("patch","patchmerge") ){ int nMerge = 0; db_prepare(&q, "SELECT type, mhash, upper(type) FROM patch.patchmerge" " WHERE type IN ('merge','cherrypick','backout','integrate')" " AND mhash NOT GLOB '*[^a-fA-F0-9]*';" ); while( db_step(&q)==SQLITE_ROW ){ const char *zType = db_column_text(&q,0); blob_append_escaped_arg(&cmd, g.nameOfExe, 1); if( strcmp(zType,"merge")==0 ){ blob_appendf(&cmd, " merge --noundo --nosync %s\n", db_column_text(&q,1)); }else{ blob_appendf(&cmd, " merge --%s --noundo --nosync %s\n", zType, db_column_text(&q,1)); } nMerge++; if( mFlags & PATCH_VERBOSE ){ fossil_print("%-10s %s\n", db_column_text(&q,2), db_column_text(&q,0)); } } db_finalize(&q); if( mFlags & PATCH_DRYRUN ){ fossil_print("%s", blob_str(&cmd)); }else{ int rc = fossil_unsafe_system(blob_str(&cmd)); if( rc ){ fossil_fatal("unable to do merges:\n%s", blob_str(&cmd)); } } blob_reset(&cmd); /* 2024-12-16 https://fossil-scm.org/home/forumpost/51a37054 ** If one or more merge operations occurred in the patch and there are ** files that are marked as "chnged' in the local VFILE but which ** are not mentioned as having been modified in the patch, then ** revert those files. */ if( nMerge ){ int vid = db_lget_int("checkout", 0); int nRevert = 0; blob_append_escaped_arg(&cmd, g.nameOfExe, 1); blob_appendf(&cmd, " revert --noundo "); db_prepare(&q, "SELECT pathname FROM vfile WHERE vid=%d AND chnged " "EXCEPT SELECT pathname FROM chng", vid ); while( db_step(&q)==SQLITE_ROW ){ blob_append_escaped_arg(&cmd, db_column_text(&q,0), 1); nRevert++; } db_finalize(&q); if( nRevert ){ if( mFlags & PATCH_DRYRUN ){ fossil_print("%s", blob_str(&cmd)); }else{ int rc = fossil_unsafe_system(blob_str(&cmd)); if( rc ){ fossil_fatal("unable to do reverts:\n%s", blob_str(&cmd)); } } } blob_reset(&cmd); } } /* Deletions */ db_prepare(&q, "SELECT pathname FROM patch.chng" " WHERE origname IS NULL AND delta IS NULL"); while( db_step(&q)==SQLITE_ROW ){ if( blob_size(&cmd)==0 ){ |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 | ** ** Revert all files if no file name is provided. ** ** If a file is reverted accidentally, it can be restored using ** the "fossil undo" command. ** ** Options: ** -r|--revision VERSION Revert given FILE(s) back to given ** VERSION ** ** See also: [[redo]], [[undo]], [[checkout]], [[update]] */ void revert_cmd(void){ Manifest *pCoManifest; /* Manifest of current check-out */ Manifest *pRvManifest; /* Manifest of selected revert version */ ManifestFile *pCoFile; /* File within current check-out manifest */ ManifestFile *pRvFile; /* File within revert version manifest */ const char *zFile; /* Filename relative to check-out root */ const char *zRevision; /* Selected revert version, NULL if current */ Blob record = BLOB_INITIALIZER; /* Contents of each reverted file */ int i; Stmt q; int revertAll = 0; int revisionOptNotSupported = 0; undo_capture_command_line(); zRevision = find_option("revision", "r", 1); verify_all_options(); if( g.argc<2 ){ usage("?OPTIONS? [FILE] ..."); } if( zRevision && g.argc<3 ){ fossil_fatal("directories or the entire tree can only be reverted" " back to current version"); } db_must_be_within_tree(); /* Get manifests of revert version and (if different) current check-out. */ pRvManifest = historical_manifest(zRevision); pCoManifest = zRevision ? historical_manifest(0) : 0; db_begin_transaction(); | > > > > | > > > | 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 | ** ** Revert all files if no file name is provided. ** ** If a file is reverted accidentally, it can be restored using ** the "fossil undo" command. ** ** Options: ** --noundo Do not record changes in the undo/redo log. ** -r|--revision VERSION Revert given FILE(s) back to given ** VERSION ** ** See also: [[redo]], [[undo]], [[checkout]], [[update]] */ void revert_cmd(void){ Manifest *pCoManifest; /* Manifest of current check-out */ Manifest *pRvManifest; /* Manifest of selected revert version */ ManifestFile *pCoFile; /* File within current check-out manifest */ ManifestFile *pRvFile; /* File within revert version manifest */ const char *zFile; /* Filename relative to check-out root */ const char *zRevision; /* Selected revert version, NULL if current */ Blob record = BLOB_INITIALIZER; /* Contents of each reverted file */ int useUndo = 1; /* True to record changes in UNDO */ int i; Stmt q; int revertAll = 0; int revisionOptNotSupported = 0; undo_capture_command_line(); zRevision = find_option("revision", "r", 1); useUndo = find_option("noundo", 0, 0)==0; verify_all_options(); if( g.argc<2 ){ usage("?OPTIONS? [FILE] ..."); } if( zRevision && g.argc<3 ){ fossil_fatal("directories or the entire tree can only be reverted" " back to current version"); } db_must_be_within_tree(); /* Get manifests of revert version and (if different) current check-out. */ pRvManifest = historical_manifest(zRevision); pCoManifest = zRevision ? historical_manifest(0) : 0; db_begin_transaction(); if( useUndo ){ undo_begin(); }else{ undo_reset(); } db_multi_exec("CREATE TEMP TABLE torevert(name UNIQUE);"); if( g.argc>2 ){ for(i=2; i<g.argc; i++){ Blob fname; zFile = mprintf("%/", g.argv[i]); blob_zero(&fname); |
︙ | ︙ | |||
985 986 987 988 989 990 991 | zFull = mprintf("%/%/", g.zLocalRoot, zFile); pRvFile = pRvManifest? manifest_file_find(pRvManifest, zFile) : 0; if( !pRvFile ){ if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q", zFile, zFile)==0 ){ fossil_print("UNMANAGE %s\n", zFile); }else{ | | | 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 | zFull = mprintf("%/%/", g.zLocalRoot, zFile); pRvFile = pRvManifest? manifest_file_find(pRvManifest, zFile) : 0; if( !pRvFile ){ if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q", zFile, zFile)==0 ){ fossil_print("UNMANAGE %s\n", zFile); }else{ if( useUndo ) undo_save(zFile); file_delete(zFull); fossil_print("DELETE %s\n", zFile); } db_multi_exec( "UPDATE OR REPLACE vfile" " SET pathname=origname, origname=NULL" " WHERE pathname=%Q AND origname!=pathname;" |
︙ | ︙ | |||
1012 1013 1014 1015 1016 1017 1018 | rvChnged = manifest_file_mperm(pRvFile)!=rvPerm || fossil_strcmp(pRvFile->zUuid, pCoFile->zUuid)!=0; } /* Get contents of reverted-to file. */ content_get(fast_uuid_to_rid(pRvFile->zUuid), &record); | | | 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 | rvChnged = manifest_file_mperm(pRvFile)!=rvPerm || fossil_strcmp(pRvFile->zUuid, pCoFile->zUuid)!=0; } /* Get contents of reverted-to file. */ content_get(fast_uuid_to_rid(pRvFile->zUuid), &record); if( useUndo ) undo_save(zFile); if( file_size(zFull, RepoFILE)>=0 && (rvPerm==PERM_LNK || file_islink(0)) ){ file_delete(zFull); } if( rvPerm==PERM_LNK ){ symlink_create(blob_str(&record), zFull); |
︙ | ︙ | |||
1038 1039 1040 1041 1042 1043 1044 | mtime, rvChnged, rvPerm==PERM_EXE, rvPerm==PERM_LNK, zFile, zFile ); } blob_reset(&record); free(zFull); } db_finalize(&q); | | | 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 | mtime, rvChnged, rvPerm==PERM_EXE, rvPerm==PERM_LNK, zFile, zFile ); } blob_reset(&record); free(zFull); } db_finalize(&q); if( useUndo) undo_finish(); db_end_transaction(0); /* Deallocate parsed manifest structures. */ manifest_destroy(pRvManifest); manifest_destroy(pCoManifest); } |