Fossil SCM
Refactored unaddremove into (add|rm|addremove --reset).
Commit
72fdb21ae8cffc16ce8239cfa3c766e009f2ff4c09bb76eb11741be990903819
Parent
6e21c7d70626f33…
1 file changed
+133
-84
+133
-84
| --- src/add.c | ||
| +++ src/add.c | ||
| @@ -240,10 +240,90 @@ | ||
| 240 | 240 | } |
| 241 | 241 | db_finalize(&loop); |
| 242 | 242 | blob_reset(&repoName); |
| 243 | 243 | return nAdd; |
| 244 | 244 | } |
| 245 | + | |
| 246 | +/* | |
| 247 | +** Resets the ADD/REMOVE state of a checkout, such that all newly-added | |
| 248 | +** (but not yet committed) files are no longer added and newly-removed | |
| 249 | +** (but not yet committed) files are no longer removed. If fIsAdd is true, | |
| 250 | +** it operates on the "add" state, else it operates on the "rm" state. | |
| 251 | +** | |
| 252 | +** If fVerbose is true it outputs the name of each reset entry. | |
| 253 | +** | |
| 254 | +** This is intended to be called only in the context of the add/rm | |
| 255 | +** commands, after the call to verify_all_options(). | |
| 256 | +** | |
| 257 | +** Un-added files are not modified but any un-rm'd files which are | |
| 258 | +** missing from the checkout are restored from the repo. un-rm'd files | |
| 259 | +** which exist in the checkout are left as-is, rather than restoring | |
| 260 | +** them using vfile_to_disk(), to avoid overwriting any local changes | |
| 261 | +** made to those files. | |
| 262 | +*/ | |
| 263 | +static void addremove_reset(int fIsAdd, int fVerbose){ | |
| 264 | + int nReset = 0; /* # of entries which get reset */ | |
| 265 | + Stmt stmt; /* vfile loop query */ | |
| 266 | + | |
| 267 | + db_begin_transaction(); | |
| 268 | + db_prepare(&stmt, "SELECT id, pathname FROM vfile " | |
| 269 | + "WHERE %s ORDER BY pathname", | |
| 270 | + fIsAdd==0 ? "deleted<>0" : "rid=0"/*safe-for-%s*/); | |
| 271 | + while( db_step(&stmt)==SQLITE_ROW ){ | |
| 272 | + /* This loop exists only so we can restore the contents of un-rm'd | |
| 273 | + ** files and support verbose mode. All manipulation of vfile's | |
| 274 | + ** contents happens after the loop. For the ADD case in non-verbose | |
| 275 | + ** mode we "could" skip this loop entirely. | |
| 276 | + */ | |
| 277 | + int const id = db_column_int(&stmt, 0); | |
| 278 | + char const * zPathname = db_column_text(&stmt, 1); | |
| 279 | + Blob relName = empty_blob; | |
| 280 | + if(fIsAdd==0 || fVerbose!=0){ | |
| 281 | + /* Make filename relative... */ | |
| 282 | + char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); | |
| 283 | + file_relative_name(zFullName, &relName, 0); | |
| 284 | + fossil_free(zFullName); | |
| 285 | + } | |
| 286 | + if(fIsAdd==0){ | |
| 287 | + /* Restore contents of missing un-rm'd files. We don't do this | |
| 288 | + ** unconditionally because we might cause data loss if a file | |
| 289 | + ** is modified, rm'd, then un-rm'd. | |
| 290 | + */ | |
| 291 | + ++nReset; | |
| 292 | + if(!file_isfile_or_link(blob_str(&relName))){ | |
| 293 | + vfile_to_disk(0, id, 0, 0); | |
| 294 | + } | |
| 295 | + /* *Potential* corner case: relName refers to a directory, | |
| 296 | + ** meaning the user rm'd the file and replaced it with a | |
| 297 | + ** directory. In that case, vfile_to_disk() will fail fatally, | |
| 298 | + ** which is arguably the best course of action. | |
| 299 | + */ | |
| 300 | + if(fVerbose){ | |
| 301 | + fossil_print("Un-removed: %b\n", &relName); | |
| 302 | + } | |
| 303 | + }else{ | |
| 304 | + /* un-add... */ | |
| 305 | + ++nReset; | |
| 306 | + if(fVerbose){ | |
| 307 | + fossil_print("Un-added: %b\n", &relName); | |
| 308 | + } | |
| 309 | + } | |
| 310 | + blob_reset(&relName); | |
| 311 | + } | |
| 312 | + db_finalize(&stmt); | |
| 313 | + if(nReset>0){ | |
| 314 | + if(fIsAdd==0){ | |
| 315 | + db_exec_sql("UPDATE vfile SET deleted=0 WHERE deleted<>0"); | |
| 316 | + fossil_print("Un-removed %d file(s).\n", nReset); | |
| 317 | + }else{ | |
| 318 | + db_exec_sql("DELETE FROM vfile WHERE rid=0"); | |
| 319 | + fossil_print("Un-added %d file(s).\n", nReset); | |
| 320 | + } | |
| 321 | + } | |
| 322 | + db_end_transaction(0); | |
| 323 | +} | |
| 324 | + | |
| 245 | 325 | |
| 246 | 326 | /* |
| 247 | 327 | ** COMMAND: add |
| 248 | 328 | ** |
| 249 | 329 | ** Usage: %fossil add ?OPTIONS? FILE1 ?FILE2 ...? |
| @@ -276,10 +356,16 @@ | ||
| 276 | 356 | ** -f|--force Add files without prompting |
| 277 | 357 | ** --ignore <CSG> Ignore unmanaged files matching patterns from |
| 278 | 358 | ** the comma separated list of glob patterns. |
| 279 | 359 | ** --clean <CSG> Also ignore files matching patterns from |
| 280 | 360 | ** the comma separated list of glob patterns. |
| 361 | +** --reset Reset the ADD state of a checkout, such that | |
| 362 | +** all newly-added (but not yet committed) files | |
| 363 | +** are no longer added. No flags other than | |
| 364 | +** --verbose may be used with --reset. | |
| 365 | +** --verbose|-v Outputs information about each --reset file. | |
| 366 | +** Only usable with --reset. | |
| 281 | 367 | ** |
| 282 | 368 | ** See also: addremove, rm |
| 283 | 369 | */ |
| 284 | 370 | void add_cmd(void){ |
| 285 | 371 | int i; /* Loop counter */ |
| @@ -288,10 +374,18 @@ | ||
| 288 | 374 | const char *zCleanFlag; /* The --clean option or clean-glob setting */ |
| 289 | 375 | const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */ |
| 290 | 376 | Glob *pIgnore, *pClean; /* Ignore everything matching the glob patterns */ |
| 291 | 377 | unsigned scanFlags = 0; /* Flags passed to vfile_scan() */ |
| 292 | 378 | int forceFlag; |
| 379 | + | |
| 380 | + if(0!=find_option("reset",0,0)){ | |
| 381 | + int const verboseFlag = find_option("verbose","v",0)!=0; | |
| 382 | + db_must_be_within_tree(); | |
| 383 | + verify_all_options(); | |
| 384 | + addremove_reset(1, verboseFlag); | |
| 385 | + return; | |
| 386 | + } | |
| 293 | 387 | |
| 294 | 388 | zCleanFlag = find_option("clean",0,1); |
| 295 | 389 | zIgnoreFlag = find_option("ignore",0,1); |
| 296 | 390 | forceFlag = find_option("force","f",0)!=0; |
| 297 | 391 | if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; |
| @@ -442,10 +536,16 @@ | ||
| 442 | 536 | ** --soft Skip removing files from the checkout. |
| 443 | 537 | ** This supersedes the --hard option. |
| 444 | 538 | ** --hard Remove files from the checkout. |
| 445 | 539 | ** --case-sensitive <BOOL> Override the case-sensitive setting. |
| 446 | 540 | ** -n|--dry-run If given, display instead of run actions. |
| 541 | +** --reset Reset the DELETED state of a checkout, such | |
| 542 | +** that all newly-rm'd (but not yet committed) | |
| 543 | +** files are no longer removed. No flags other | |
| 544 | +** than --verbose may be used with --reset. | |
| 545 | +** --verbose|-v Outputs information about each --reset file. | |
| 546 | +** Only usable with --reset. | |
| 447 | 547 | ** |
| 448 | 548 | ** See also: addremove, add |
| 449 | 549 | */ |
| 450 | 550 | void delete_cmd(void){ |
| 451 | 551 | int i; |
| @@ -452,10 +552,18 @@ | ||
| 452 | 552 | int removeFiles; |
| 453 | 553 | int dryRunFlag; |
| 454 | 554 | int softFlag; |
| 455 | 555 | int hardFlag; |
| 456 | 556 | Stmt loop; |
| 557 | + | |
| 558 | + if(0!=find_option("reset",0,0)){ | |
| 559 | + int const verboseFlag = find_option("verbose","v",0)!=0; | |
| 560 | + db_must_be_within_tree(); | |
| 561 | + verify_all_options(); | |
| 562 | + addremove_reset(0, verboseFlag); | |
| 563 | + return; | |
| 564 | + } | |
| 457 | 565 | |
| 458 | 566 | dryRunFlag = find_option("dry-run","n",0)!=0; |
| 459 | 567 | softFlag = find_option("soft",0,0)!=0; |
| 460 | 568 | hardFlag = find_option("hard",0,0)!=0; |
| 461 | 569 | |
| @@ -623,26 +731,47 @@ | ||
| 623 | 731 | ** --ignore <CSG> Ignore unmanaged files matching patterns from |
| 624 | 732 | ** the comma separated list of glob patterns. |
| 625 | 733 | ** --clean <CSG> Also ignore files matching patterns from |
| 626 | 734 | ** the comma separated list of glob patterns. |
| 627 | 735 | ** -n|--dry-run If given, display instead of run actions. |
| 736 | +** --reset Reset the ADDED/DELETED state of a checkout, | |
| 737 | +** such that all newly-added (but not yet committed) | |
| 738 | +** files are no longer added and all newly-removed | |
| 739 | +** (but not yet committed) flags are no longer | |
| 740 | +** removed. No flags other than --verbose may be | |
| 741 | +** used with --reset. | |
| 742 | +** --verbose|-v Outputs information about each --reset file. | |
| 743 | +** Only usable with --reset. | |
| 628 | 744 | ** |
| 629 | 745 | ** See also: add, rm |
| 630 | 746 | */ |
| 631 | 747 | void addremove_cmd(void){ |
| 632 | 748 | Blob path; |
| 633 | - const char *zCleanFlag = find_option("clean",0,1); | |
| 634 | - const char *zIgnoreFlag = find_option("ignore",0,1); | |
| 635 | - unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; | |
| 636 | - int dryRunFlag = find_option("dry-run","n",0)!=0; | |
| 749 | + const char *zCleanFlag; | |
| 750 | + const char *zIgnoreFlag; | |
| 751 | + unsigned scanFlags; | |
| 752 | + int dryRunFlag; | |
| 637 | 753 | int n; |
| 638 | 754 | Stmt q; |
| 639 | 755 | int vid; |
| 640 | 756 | int nAdd = 0; |
| 641 | 757 | int nDelete = 0; |
| 642 | 758 | Glob *pIgnore, *pClean; |
| 643 | 759 | |
| 760 | + if(0!=find_option("reset",0,0)){ | |
| 761 | + int const verboseFlag = find_option("verbose","v",0)!=0; | |
| 762 | + db_must_be_within_tree(); | |
| 763 | + verify_all_options(); | |
| 764 | + addremove_reset(0, verboseFlag); | |
| 765 | + addremove_reset(1, verboseFlag); | |
| 766 | + return; | |
| 767 | + } | |
| 768 | + | |
| 769 | + zCleanFlag = find_option("clean",0,1); | |
| 770 | + zIgnoreFlag = find_option("ignore",0,1); | |
| 771 | + scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; | |
| 772 | + dryRunFlag = find_option("dry-run","n",0)!=0; | |
| 644 | 773 | if( !dryRunFlag ){ |
| 645 | 774 | dryRunFlag = find_option("test",0,0)!=0; /* deprecated */ |
| 646 | 775 | } |
| 647 | 776 | |
| 648 | 777 | /* We should be done with options.. */ |
| @@ -711,90 +840,10 @@ | ||
| 711 | 840 | fossil_print("added %d files, deleted %d files\n", nAdd, nDelete); |
| 712 | 841 | |
| 713 | 842 | db_end_transaction(dryRunFlag); |
| 714 | 843 | } |
| 715 | 844 | |
| 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 | 845 | /* |
| 797 | 846 | ** Rename a single file. |
| 798 | 847 | ** |
| 799 | 848 | ** The original name of the file is zOrig. The new filename is zNew. |
| 800 | 849 | */ |
| 801 | 850 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -240,10 +240,90 @@ | |
| 240 | } |
| 241 | db_finalize(&loop); |
| 242 | blob_reset(&repoName); |
| 243 | return nAdd; |
| 244 | } |
| 245 | |
| 246 | /* |
| 247 | ** COMMAND: add |
| 248 | ** |
| 249 | ** Usage: %fossil add ?OPTIONS? FILE1 ?FILE2 ...? |
| @@ -276,10 +356,16 @@ | |
| 276 | ** -f|--force Add files without prompting |
| 277 | ** --ignore <CSG> Ignore unmanaged files matching patterns from |
| 278 | ** the comma separated list of glob patterns. |
| 279 | ** --clean <CSG> Also ignore files matching patterns from |
| 280 | ** the comma separated list of glob patterns. |
| 281 | ** |
| 282 | ** See also: addremove, rm |
| 283 | */ |
| 284 | void add_cmd(void){ |
| 285 | int i; /* Loop counter */ |
| @@ -288,10 +374,18 @@ | |
| 288 | const char *zCleanFlag; /* The --clean option or clean-glob setting */ |
| 289 | const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */ |
| 290 | Glob *pIgnore, *pClean; /* Ignore everything matching the glob patterns */ |
| 291 | unsigned scanFlags = 0; /* Flags passed to vfile_scan() */ |
| 292 | int forceFlag; |
| 293 | |
| 294 | zCleanFlag = find_option("clean",0,1); |
| 295 | zIgnoreFlag = find_option("ignore",0,1); |
| 296 | forceFlag = find_option("force","f",0)!=0; |
| 297 | if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; |
| @@ -442,10 +536,16 @@ | |
| 442 | ** --soft Skip removing files from the checkout. |
| 443 | ** This supersedes the --hard option. |
| 444 | ** --hard Remove files from the checkout. |
| 445 | ** --case-sensitive <BOOL> Override the case-sensitive setting. |
| 446 | ** -n|--dry-run If given, display instead of run actions. |
| 447 | ** |
| 448 | ** See also: addremove, add |
| 449 | */ |
| 450 | void delete_cmd(void){ |
| 451 | int i; |
| @@ -452,10 +552,18 @@ | |
| 452 | int removeFiles; |
| 453 | int dryRunFlag; |
| 454 | int softFlag; |
| 455 | int hardFlag; |
| 456 | Stmt loop; |
| 457 | |
| 458 | dryRunFlag = find_option("dry-run","n",0)!=0; |
| 459 | softFlag = find_option("soft",0,0)!=0; |
| 460 | hardFlag = find_option("hard",0,0)!=0; |
| 461 | |
| @@ -623,26 +731,47 @@ | |
| 623 | ** --ignore <CSG> Ignore unmanaged files matching patterns from |
| 624 | ** the comma separated list of glob patterns. |
| 625 | ** --clean <CSG> Also ignore files matching patterns from |
| 626 | ** the comma separated list of glob patterns. |
| 627 | ** -n|--dry-run If given, display instead of run actions. |
| 628 | ** |
| 629 | ** See also: add, rm |
| 630 | */ |
| 631 | void addremove_cmd(void){ |
| 632 | Blob path; |
| 633 | const char *zCleanFlag = find_option("clean",0,1); |
| 634 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 635 | unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; |
| 636 | int dryRunFlag = find_option("dry-run","n",0)!=0; |
| 637 | int n; |
| 638 | Stmt q; |
| 639 | int vid; |
| 640 | int nAdd = 0; |
| 641 | int nDelete = 0; |
| 642 | Glob *pIgnore, *pClean; |
| 643 | |
| 644 | if( !dryRunFlag ){ |
| 645 | dryRunFlag = find_option("test",0,0)!=0; /* deprecated */ |
| 646 | } |
| 647 | |
| 648 | /* We should be done with options.. */ |
| @@ -711,90 +840,10 @@ | |
| 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 | */ |
| 801 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -240,10 +240,90 @@ | |
| 240 | } |
| 241 | db_finalize(&loop); |
| 242 | blob_reset(&repoName); |
| 243 | return nAdd; |
| 244 | } |
| 245 | |
| 246 | /* |
| 247 | ** Resets the ADD/REMOVE state of a checkout, such that all newly-added |
| 248 | ** (but not yet committed) files are no longer added and newly-removed |
| 249 | ** (but not yet committed) files are no longer removed. If fIsAdd is true, |
| 250 | ** it operates on the "add" state, else it operates on the "rm" state. |
| 251 | ** |
| 252 | ** If fVerbose is true it outputs the name of each reset entry. |
| 253 | ** |
| 254 | ** This is intended to be called only in the context of the add/rm |
| 255 | ** commands, after the call to verify_all_options(). |
| 256 | ** |
| 257 | ** Un-added files are not modified but any un-rm'd files which are |
| 258 | ** missing from the checkout are restored from the repo. un-rm'd files |
| 259 | ** which exist in the checkout are left as-is, rather than restoring |
| 260 | ** them using vfile_to_disk(), to avoid overwriting any local changes |
| 261 | ** made to those files. |
| 262 | */ |
| 263 | static void addremove_reset(int fIsAdd, int fVerbose){ |
| 264 | int nReset = 0; /* # of entries which get reset */ |
| 265 | Stmt stmt; /* vfile loop query */ |
| 266 | |
| 267 | db_begin_transaction(); |
| 268 | db_prepare(&stmt, "SELECT id, pathname FROM vfile " |
| 269 | "WHERE %s ORDER BY pathname", |
| 270 | fIsAdd==0 ? "deleted<>0" : "rid=0"/*safe-for-%s*/); |
| 271 | while( db_step(&stmt)==SQLITE_ROW ){ |
| 272 | /* This loop exists only so we can restore the contents of un-rm'd |
| 273 | ** files and support verbose mode. All manipulation of vfile's |
| 274 | ** contents happens after the loop. For the ADD case in non-verbose |
| 275 | ** mode we "could" skip this loop entirely. |
| 276 | */ |
| 277 | int const id = db_column_int(&stmt, 0); |
| 278 | char const * zPathname = db_column_text(&stmt, 1); |
| 279 | Blob relName = empty_blob; |
| 280 | if(fIsAdd==0 || fVerbose!=0){ |
| 281 | /* Make filename relative... */ |
| 282 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 283 | file_relative_name(zFullName, &relName, 0); |
| 284 | fossil_free(zFullName); |
| 285 | } |
| 286 | if(fIsAdd==0){ |
| 287 | /* Restore contents of missing un-rm'd files. We don't do this |
| 288 | ** unconditionally because we might cause data loss if a file |
| 289 | ** is modified, rm'd, then un-rm'd. |
| 290 | */ |
| 291 | ++nReset; |
| 292 | if(!file_isfile_or_link(blob_str(&relName))){ |
| 293 | vfile_to_disk(0, id, 0, 0); |
| 294 | } |
| 295 | /* *Potential* corner case: relName refers to a directory, |
| 296 | ** meaning the user rm'd the file and replaced it with a |
| 297 | ** directory. In that case, vfile_to_disk() will fail fatally, |
| 298 | ** which is arguably the best course of action. |
| 299 | */ |
| 300 | if(fVerbose){ |
| 301 | fossil_print("Un-removed: %b\n", &relName); |
| 302 | } |
| 303 | }else{ |
| 304 | /* un-add... */ |
| 305 | ++nReset; |
| 306 | if(fVerbose){ |
| 307 | fossil_print("Un-added: %b\n", &relName); |
| 308 | } |
| 309 | } |
| 310 | blob_reset(&relName); |
| 311 | } |
| 312 | db_finalize(&stmt); |
| 313 | if(nReset>0){ |
| 314 | if(fIsAdd==0){ |
| 315 | db_exec_sql("UPDATE vfile SET deleted=0 WHERE deleted<>0"); |
| 316 | fossil_print("Un-removed %d file(s).\n", nReset); |
| 317 | }else{ |
| 318 | db_exec_sql("DELETE FROM vfile WHERE rid=0"); |
| 319 | fossil_print("Un-added %d file(s).\n", nReset); |
| 320 | } |
| 321 | } |
| 322 | db_end_transaction(0); |
| 323 | } |
| 324 | |
| 325 | |
| 326 | /* |
| 327 | ** COMMAND: add |
| 328 | ** |
| 329 | ** Usage: %fossil add ?OPTIONS? FILE1 ?FILE2 ...? |
| @@ -276,10 +356,16 @@ | |
| 356 | ** -f|--force Add files without prompting |
| 357 | ** --ignore <CSG> Ignore unmanaged files matching patterns from |
| 358 | ** the comma separated list of glob patterns. |
| 359 | ** --clean <CSG> Also ignore files matching patterns from |
| 360 | ** the comma separated list of glob patterns. |
| 361 | ** --reset Reset the ADD state of a checkout, such that |
| 362 | ** all newly-added (but not yet committed) files |
| 363 | ** are no longer added. No flags other than |
| 364 | ** --verbose may be used with --reset. |
| 365 | ** --verbose|-v Outputs information about each --reset file. |
| 366 | ** Only usable with --reset. |
| 367 | ** |
| 368 | ** See also: addremove, rm |
| 369 | */ |
| 370 | void add_cmd(void){ |
| 371 | int i; /* Loop counter */ |
| @@ -288,10 +374,18 @@ | |
| 374 | const char *zCleanFlag; /* The --clean option or clean-glob setting */ |
| 375 | const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */ |
| 376 | Glob *pIgnore, *pClean; /* Ignore everything matching the glob patterns */ |
| 377 | unsigned scanFlags = 0; /* Flags passed to vfile_scan() */ |
| 378 | int forceFlag; |
| 379 | |
| 380 | if(0!=find_option("reset",0,0)){ |
| 381 | int const verboseFlag = find_option("verbose","v",0)!=0; |
| 382 | db_must_be_within_tree(); |
| 383 | verify_all_options(); |
| 384 | addremove_reset(1, verboseFlag); |
| 385 | return; |
| 386 | } |
| 387 | |
| 388 | zCleanFlag = find_option("clean",0,1); |
| 389 | zIgnoreFlag = find_option("ignore",0,1); |
| 390 | forceFlag = find_option("force","f",0)!=0; |
| 391 | if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; |
| @@ -442,10 +536,16 @@ | |
| 536 | ** --soft Skip removing files from the checkout. |
| 537 | ** This supersedes the --hard option. |
| 538 | ** --hard Remove files from the checkout. |
| 539 | ** --case-sensitive <BOOL> Override the case-sensitive setting. |
| 540 | ** -n|--dry-run If given, display instead of run actions. |
| 541 | ** --reset Reset the DELETED state of a checkout, such |
| 542 | ** that all newly-rm'd (but not yet committed) |
| 543 | ** files are no longer removed. No flags other |
| 544 | ** than --verbose may be used with --reset. |
| 545 | ** --verbose|-v Outputs information about each --reset file. |
| 546 | ** Only usable with --reset. |
| 547 | ** |
| 548 | ** See also: addremove, add |
| 549 | */ |
| 550 | void delete_cmd(void){ |
| 551 | int i; |
| @@ -452,10 +552,18 @@ | |
| 552 | int removeFiles; |
| 553 | int dryRunFlag; |
| 554 | int softFlag; |
| 555 | int hardFlag; |
| 556 | Stmt loop; |
| 557 | |
| 558 | if(0!=find_option("reset",0,0)){ |
| 559 | int const verboseFlag = find_option("verbose","v",0)!=0; |
| 560 | db_must_be_within_tree(); |
| 561 | verify_all_options(); |
| 562 | addremove_reset(0, verboseFlag); |
| 563 | return; |
| 564 | } |
| 565 | |
| 566 | dryRunFlag = find_option("dry-run","n",0)!=0; |
| 567 | softFlag = find_option("soft",0,0)!=0; |
| 568 | hardFlag = find_option("hard",0,0)!=0; |
| 569 | |
| @@ -623,26 +731,47 @@ | |
| 731 | ** --ignore <CSG> Ignore unmanaged files matching patterns from |
| 732 | ** the comma separated list of glob patterns. |
| 733 | ** --clean <CSG> Also ignore files matching patterns from |
| 734 | ** the comma separated list of glob patterns. |
| 735 | ** -n|--dry-run If given, display instead of run actions. |
| 736 | ** --reset Reset the ADDED/DELETED state of a checkout, |
| 737 | ** such that all newly-added (but not yet committed) |
| 738 | ** files are no longer added and all newly-removed |
| 739 | ** (but not yet committed) flags are no longer |
| 740 | ** removed. No flags other than --verbose may be |
| 741 | ** used with --reset. |
| 742 | ** --verbose|-v Outputs information about each --reset file. |
| 743 | ** Only usable with --reset. |
| 744 | ** |
| 745 | ** See also: add, rm |
| 746 | */ |
| 747 | void addremove_cmd(void){ |
| 748 | Blob path; |
| 749 | const char *zCleanFlag; |
| 750 | const char *zIgnoreFlag; |
| 751 | unsigned scanFlags; |
| 752 | int dryRunFlag; |
| 753 | int n; |
| 754 | Stmt q; |
| 755 | int vid; |
| 756 | int nAdd = 0; |
| 757 | int nDelete = 0; |
| 758 | Glob *pIgnore, *pClean; |
| 759 | |
| 760 | if(0!=find_option("reset",0,0)){ |
| 761 | int const verboseFlag = find_option("verbose","v",0)!=0; |
| 762 | db_must_be_within_tree(); |
| 763 | verify_all_options(); |
| 764 | addremove_reset(0, verboseFlag); |
| 765 | addremove_reset(1, verboseFlag); |
| 766 | return; |
| 767 | } |
| 768 | |
| 769 | zCleanFlag = find_option("clean",0,1); |
| 770 | zIgnoreFlag = find_option("ignore",0,1); |
| 771 | scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; |
| 772 | dryRunFlag = find_option("dry-run","n",0)!=0; |
| 773 | if( !dryRunFlag ){ |
| 774 | dryRunFlag = find_option("test",0,0)!=0; /* deprecated */ |
| 775 | } |
| 776 | |
| 777 | /* We should be done with options.. */ |
| @@ -711,90 +840,10 @@ | |
| 840 | fossil_print("added %d files, deleted %d files\n", nAdd, nDelete); |
| 841 | |
| 842 | db_end_transaction(dryRunFlag); |
| 843 | } |
| 844 | |
| 845 | /* |
| 846 | ** Rename a single file. |
| 847 | ** |
| 848 | ** The original name of the file is zOrig. The new filename is zNew. |
| 849 | */ |
| 850 |