Fossil SCM
Initial draft of new unaddremove command (will be renamed once a suitable name is found), as discussed at [https://fossil-scm.org/forum/forumpost/b9b20b04bd|forumpost/b9b20b04bd].
Commit
369a14b33fb79ffca48f9de37ee95f183d76daba0970034dcf43d7d27bc88fee
Parent
c6890fd46a42cca…
1 file changed
+79
+79
| --- src/add.c | ||
| +++ src/add.c | ||
| @@ -711,10 +711,89 @@ | ||
| 711 | 711 | fossil_print("added %d files, deleted %d files\n", nAdd, nDelete); |
| 712 | 712 | |
| 713 | 713 | db_end_transaction(dryRunFlag); |
| 714 | 714 | } |
| 715 | 715 | |
| 716 | +/* | |
| 717 | +** COMMAND: unaddremove* | |
| 718 | +** | |
| 719 | +** Resets the ADD/REMOVE state of a checkout, such that all newly-added | |
| 720 | +** (but not yet committed) files are no longer added and newly-removed | |
| 721 | +** (but not yet committed) files are no longer removed. | |
| 722 | +** | |
| 723 | +** This command does not touch un-added files but restores any un-rm'd | |
| 724 | +** files which are missing from the checkout. | |
| 725 | +** | |
| 726 | +** Options: | |
| 727 | +** | |
| 728 | +** -v|--verbose Output name of each un-added/un-removed file. | |
| 729 | +** | |
| 730 | +*/ | |
| 731 | +void unaddremove_cmd(void){ | |
| 732 | + int nDeleted = 0; /* # of files which get un-rm'd */ | |
| 733 | + int nAdded = 0; /* # of files which get un-added */ | |
| 734 | + int fVerbose; /* true if --verbose */ | |
| 735 | + Stmt stmt; /* vfile loop query */ | |
| 736 | + | |
| 737 | + db_must_be_within_tree(); | |
| 738 | + fVerbose = find_option("verbose", "v", 0)!=0; | |
| 739 | + verify_all_options(); | |
| 740 | + | |
| 741 | + db_begin_transaction(); | |
| 742 | + db_prepare(&stmt, "SELECT id, rid, deleted, pathname FROM vfile " | |
| 743 | + "ORDER BY deleted<>0, pathname"); | |
| 744 | + while( db_step(&stmt)==SQLITE_ROW ){ | |
| 745 | + /* This loop exists only so we can restore the contents of un-rm'd | |
| 746 | + ** files. All manipulation of vfile's contents happens after the | |
| 747 | + ** loop. */ | |
| 748 | + int const rid = db_column_int(&stmt, 1); | |
| 749 | + int const deleted = db_column_int(&stmt, 2); | |
| 750 | + if(deleted!=0 || rid==0){ | |
| 751 | + int const id = db_column_int(&stmt, 0); | |
| 752 | + char const * zPathname = db_column_text(&stmt, 3); | |
| 753 | + char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); | |
| 754 | + Blob relName = empty_blob; | |
| 755 | + file_relative_name(zFullName, &relName, 0); | |
| 756 | + fossil_free(zFullName); | |
| 757 | + zFullName = 0; | |
| 758 | + if(deleted!=0){ | |
| 759 | + /* Restore contents of missing un-rm'd files. We don't do this | |
| 760 | + ** unconditionally because we might cause data loss if a file | |
| 761 | + ** is modified, rm'd, then un-rm'd. | |
| 762 | + */ | |
| 763 | + ++nDeleted; | |
| 764 | + if(!file_isfile_or_link(blob_str(&relName))){ | |
| 765 | + vfile_to_disk(0, id, 0, 0); | |
| 766 | + } | |
| 767 | + /* *Potential* corner case: relName refers to a directory, | |
| 768 | + ** meaning the user rm'd the file and replaced it with a | |
| 769 | + ** directory. In that case, vfile_to_disk() will fail fatally, | |
| 770 | + ** which is arguably the best course of action. | |
| 771 | + */ | |
| 772 | + if(fVerbose){ | |
| 773 | + fossil_print("Un-removed: %b\n", &relName); | |
| 774 | + } | |
| 775 | + }else if(rid==0){ | |
| 776 | + ++nAdded; | |
| 777 | + if(fVerbose){ | |
| 778 | + fossil_print("Un-added: %b\n", &relName); | |
| 779 | + } | |
| 780 | + } | |
| 781 | + blob_reset(&relName); | |
| 782 | + } | |
| 783 | + } | |
| 784 | + db_finalize(&stmt); | |
| 785 | + if(nDeleted>0){ | |
| 786 | + db_multi_exec("UPDATE vfile SET deleted=0 WHERE deleted<>0"); | |
| 787 | + fossil_print("Un-removed %d file(s).\n", nDeleted); | |
| 788 | + } | |
| 789 | + if(nAdded>0){ | |
| 790 | + db_multi_exec("DELETE FROM vfile WHERE rid=0"); | |
| 791 | + fossil_print("Un-added %d file(s).\n", nAdded); | |
| 792 | + } | |
| 793 | + db_end_transaction(0); | |
| 794 | +} | |
| 716 | 795 | |
| 717 | 796 | /* |
| 718 | 797 | ** Rename a single file. |
| 719 | 798 | ** |
| 720 | 799 | ** The original name of the file is zOrig. The new filename is zNew. |
| 721 | 800 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -711,10 +711,89 @@ | |
| 711 | fossil_print("added %d files, deleted %d files\n", nAdd, nDelete); |
| 712 | |
| 713 | db_end_transaction(dryRunFlag); |
| 714 | } |
| 715 | |
| 716 | |
| 717 | /* |
| 718 | ** Rename a single file. |
| 719 | ** |
| 720 | ** The original name of the file is zOrig. The new filename is zNew. |
| 721 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -711,10 +711,89 @@ | |
| 711 | fossil_print("added %d files, deleted %d files\n", nAdd, nDelete); |
| 712 | |
| 713 | db_end_transaction(dryRunFlag); |
| 714 | } |
| 715 | |
| 716 | /* |
| 717 | ** COMMAND: unaddremove* |
| 718 | ** |
| 719 | ** Resets the ADD/REMOVE state of a checkout, such that all newly-added |
| 720 | ** (but not yet committed) files are no longer added and newly-removed |
| 721 | ** (but not yet committed) files are no longer removed. |
| 722 | ** |
| 723 | ** This command does not touch un-added files but restores any un-rm'd |
| 724 | ** files which are missing from the checkout. |
| 725 | ** |
| 726 | ** Options: |
| 727 | ** |
| 728 | ** -v|--verbose Output name of each un-added/un-removed file. |
| 729 | ** |
| 730 | */ |
| 731 | void unaddremove_cmd(void){ |
| 732 | int nDeleted = 0; /* # of files which get un-rm'd */ |
| 733 | int nAdded = 0; /* # of files which get un-added */ |
| 734 | int fVerbose; /* true if --verbose */ |
| 735 | Stmt stmt; /* vfile loop query */ |
| 736 | |
| 737 | db_must_be_within_tree(); |
| 738 | fVerbose = find_option("verbose", "v", 0)!=0; |
| 739 | verify_all_options(); |
| 740 | |
| 741 | db_begin_transaction(); |
| 742 | db_prepare(&stmt, "SELECT id, rid, deleted, pathname FROM vfile " |
| 743 | "ORDER BY deleted<>0, pathname"); |
| 744 | while( db_step(&stmt)==SQLITE_ROW ){ |
| 745 | /* This loop exists only so we can restore the contents of un-rm'd |
| 746 | ** files. All manipulation of vfile's contents happens after the |
| 747 | ** loop. */ |
| 748 | int const rid = db_column_int(&stmt, 1); |
| 749 | int const deleted = db_column_int(&stmt, 2); |
| 750 | if(deleted!=0 || rid==0){ |
| 751 | int const id = db_column_int(&stmt, 0); |
| 752 | char const * zPathname = db_column_text(&stmt, 3); |
| 753 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 754 | Blob relName = empty_blob; |
| 755 | file_relative_name(zFullName, &relName, 0); |
| 756 | fossil_free(zFullName); |
| 757 | zFullName = 0; |
| 758 | if(deleted!=0){ |
| 759 | /* Restore contents of missing un-rm'd files. We don't do this |
| 760 | ** unconditionally because we might cause data loss if a file |
| 761 | ** is modified, rm'd, then un-rm'd. |
| 762 | */ |
| 763 | ++nDeleted; |
| 764 | if(!file_isfile_or_link(blob_str(&relName))){ |
| 765 | vfile_to_disk(0, id, 0, 0); |
| 766 | } |
| 767 | /* *Potential* corner case: relName refers to a directory, |
| 768 | ** meaning the user rm'd the file and replaced it with a |
| 769 | ** directory. In that case, vfile_to_disk() will fail fatally, |
| 770 | ** which is arguably the best course of action. |
| 771 | */ |
| 772 | if(fVerbose){ |
| 773 | fossil_print("Un-removed: %b\n", &relName); |
| 774 | } |
| 775 | }else if(rid==0){ |
| 776 | ++nAdded; |
| 777 | if(fVerbose){ |
| 778 | fossil_print("Un-added: %b\n", &relName); |
| 779 | } |
| 780 | } |
| 781 | blob_reset(&relName); |
| 782 | } |
| 783 | } |
| 784 | db_finalize(&stmt); |
| 785 | if(nDeleted>0){ |
| 786 | db_multi_exec("UPDATE vfile SET deleted=0 WHERE deleted<>0"); |
| 787 | fossil_print("Un-removed %d file(s).\n", nDeleted); |
| 788 | } |
| 789 | if(nAdded>0){ |
| 790 | db_multi_exec("DELETE FROM vfile WHERE rid=0"); |
| 791 | fossil_print("Un-added %d file(s).\n", nAdded); |
| 792 | } |
| 793 | db_end_transaction(0); |
| 794 | } |
| 795 | |
| 796 | /* |
| 797 | ** Rename a single file. |
| 798 | ** |
| 799 | ** The original name of the file is zOrig. The new filename is zNew. |
| 800 |