| | @@ -240,10 +240,101 @@ |
| 240 | 240 | } |
| 241 | 241 | db_finalize(&loop); |
| 242 | 242 | blob_reset(&repoName); |
| 243 | 243 | return nAdd; |
| 244 | 244 | } |
| 245 | + |
| 246 | +/* |
| 247 | +** Resets the ADDED/DELETED state of a checkout, such that all |
| 248 | +** newly-added (but not yet committed) files are no longer added and |
| 249 | +** newly-removed (but not yet committed) files are no longer |
| 250 | +** removed. If bIsAdd is true, it operates on the "add" state, else it |
| 251 | +** operates on the "rm" state. |
| 252 | +** |
| 253 | +** If bDryRun is true it outputs what it would have done, but does not |
| 254 | +** actually do it. In this case it rolls back the transaction it |
| 255 | +** starts (so don't start a transaction before calling this). |
| 256 | +** |
| 257 | +** If bVerbose is true it outputs the name of each reset entry. |
| 258 | +** |
| 259 | +** This is intended to be called only in the context of the |
| 260 | +** add/rm/addremove commands, after a call to verify_all_options(). |
| 261 | +** |
| 262 | +** Un-added files are not modified but any un-rm'd files which are |
| 263 | +** missing from the checkout are restored from the repo. un-rm'd files |
| 264 | +** which exist in the checkout are left as-is, rather than restoring |
| 265 | +** them using vfile_to_disk(), to avoid overwriting any local changes |
| 266 | +** made to those files. |
| 267 | +*/ |
| 268 | +static void addremove_reset(int bIsAdd, int bDryRun, int bVerbose){ |
| 269 | + int nReset = 0; /* # of entries which get reset */ |
| 270 | + Stmt stmt; /* vfile loop query */ |
| 271 | + |
| 272 | + db_begin_transaction(); |
| 273 | + db_prepare(&stmt, "SELECT id, pathname FROM vfile " |
| 274 | + "WHERE %s ORDER BY pathname", |
| 275 | + bIsAdd==0 ? "deleted<>0" : "rid=0"/*safe-for-%s*/); |
| 276 | + while( db_step(&stmt)==SQLITE_ROW ){ |
| 277 | + /* This loop exists only so we can restore the contents of un-rm'd |
| 278 | + ** files and support verbose mode. All manipulation of vfile's |
| 279 | + ** contents happens after the loop. For the ADD case in non-verbose |
| 280 | + ** mode we "could" skip this loop entirely. |
| 281 | + */ |
| 282 | + int const id = db_column_int(&stmt, 0); |
| 283 | + char const * zPathname = db_column_text(&stmt, 1); |
| 284 | + Blob relName = empty_blob; |
| 285 | + if(bIsAdd==0 || bVerbose!=0){ |
| 286 | + /* Make filename relative... */ |
| 287 | + char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 288 | + file_relative_name(zFullName, &relName, 0); |
| 289 | + fossil_free(zFullName); |
| 290 | + } |
| 291 | + if(bIsAdd==0){ |
| 292 | + /* Restore contents of missing un-rm'd files. We don't do this |
| 293 | + ** unconditionally because we might cause data loss if a file |
| 294 | + ** is modified, rm'd, then un-rm'd. |
| 295 | + */ |
| 296 | + ++nReset; |
| 297 | + if(!file_isfile_or_link(blob_str(&relName))){ |
| 298 | + if(bDryRun==0){ |
| 299 | + vfile_to_disk(0, id, 0, 0); |
| 300 | + if(bVerbose){ |
| 301 | + fossil_print("Restored missing file: %b\n", &relName); |
| 302 | + } |
| 303 | + }else{ |
| 304 | + fossil_print("Dry-run: not restoring missing file: %b\n", &relName); |
| 305 | + } |
| 306 | + } |
| 307 | + if(bVerbose){ |
| 308 | + fossil_print("Un-removed: %b\n", &relName); |
| 309 | + } |
| 310 | + }else{ |
| 311 | + /* un-add... */ |
| 312 | + ++nReset; |
| 313 | + if(bVerbose){ |
| 314 | + fossil_print("Un-added: %b\n", &relName); |
| 315 | + } |
| 316 | + } |
| 317 | + blob_reset(&relName); |
| 318 | + } |
| 319 | + db_finalize(&stmt); |
| 320 | + if(nReset>0){ |
| 321 | + if(bIsAdd==0){ |
| 322 | + if(bDryRun==0){ |
| 323 | + db_exec_sql("UPDATE vfile SET deleted=0 WHERE deleted<>0"); |
| 324 | + } |
| 325 | + fossil_print("Un-removed %d file(s).\n", nReset); |
| 326 | + }else{ |
| 327 | + if(bDryRun==0){ |
| 328 | + db_exec_sql("DELETE FROM vfile WHERE rid=0"); |
| 329 | + } |
| 330 | + fossil_print("Un-added %d file(s).\n", nReset); |
| 331 | + } |
| 332 | + } |
| 333 | + db_end_transaction(bDryRun ? 1 : 0); |
| 334 | +} |
| 335 | + |
| 245 | 336 | |
| 246 | 337 | /* |
| 247 | 338 | ** COMMAND: add |
| 248 | 339 | ** |
| 249 | 340 | ** Usage: %fossil add ?OPTIONS? FILE1 ?FILE2 ...? |
| | @@ -276,10 +367,19 @@ |
| 276 | 367 | ** -f|--force Add files without prompting |
| 277 | 368 | ** --ignore <CSG> Ignore unmanaged files matching patterns from |
| 278 | 369 | ** the comma separated list of glob patterns. |
| 279 | 370 | ** --clean <CSG> Also ignore files matching patterns from |
| 280 | 371 | ** the comma separated list of glob patterns. |
| 372 | +** --reset Reset the ADDED state of a checkout, such |
| 373 | +** that all newly-added (but not yet committed) |
| 374 | +** files are no longer added. No flags other |
| 375 | +** than --verbose and --dry-run may be used |
| 376 | +** with --reset. |
| 377 | +** |
| 378 | +** The following options are only valid with --reset: |
| 379 | +** -v|--verbose Outputs information about each --reset file. |
| 380 | +** -n|--dry-run Display instead of run actions. |
| 281 | 381 | ** |
| 282 | 382 | ** See also: addremove, rm |
| 283 | 383 | */ |
| 284 | 384 | void add_cmd(void){ |
| 285 | 385 | int i; /* Loop counter */ |
| | @@ -288,10 +388,19 @@ |
| 288 | 388 | const char *zCleanFlag; /* The --clean option or clean-glob setting */ |
| 289 | 389 | const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */ |
| 290 | 390 | Glob *pIgnore, *pClean; /* Ignore everything matching the glob patterns */ |
| 291 | 391 | unsigned scanFlags = 0; /* Flags passed to vfile_scan() */ |
| 292 | 392 | int forceFlag; |
| 393 | + |
| 394 | + if(0!=find_option("reset",0,0)){ |
| 395 | + int const verboseFlag = find_option("verbose","v",0)!=0; |
| 396 | + int const dryRunFlag = find_option("dry-run","n",0)!=0; |
| 397 | + db_must_be_within_tree(); |
| 398 | + verify_all_options(); |
| 399 | + addremove_reset(1, dryRunFlag, verboseFlag); |
| 400 | + return; |
| 401 | + } |
| 293 | 402 | |
| 294 | 403 | zCleanFlag = find_option("clean",0,1); |
| 295 | 404 | zIgnoreFlag = find_option("ignore",0,1); |
| 296 | 405 | forceFlag = find_option("force","f",0)!=0; |
| 297 | 406 | if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL; |
| | @@ -442,22 +551,36 @@ |
| 442 | 551 | ** --soft Skip removing files from the checkout. |
| 443 | 552 | ** This supersedes the --hard option. |
| 444 | 553 | ** --hard Remove files from the checkout. |
| 445 | 554 | ** --case-sensitive <BOOL> Override the case-sensitive setting. |
| 446 | 555 | ** -n|--dry-run If given, display instead of run actions. |
| 556 | +** --reset Reset the DELETED state of a checkout, such |
| 557 | +** that all newly-rm'd (but not yet committed) |
| 558 | +** files are no longer removed. No flags other |
| 559 | +** than --verbose or --dry-run may be used with |
| 560 | +** --reset. |
| 561 | +** --verbose|-v Outputs information about each --reset file. |
| 562 | +** Only usable with --reset. |
| 447 | 563 | ** |
| 448 | 564 | ** See also: addremove, add |
| 449 | 565 | */ |
| 450 | 566 | void delete_cmd(void){ |
| 451 | 567 | int i; |
| 452 | 568 | int removeFiles; |
| 453 | | - int dryRunFlag; |
| 569 | + int dryRunFlag = find_option("dry-run","n",0)!=0; |
| 454 | 570 | int softFlag; |
| 455 | 571 | int hardFlag; |
| 456 | 572 | Stmt loop; |
| 457 | 573 | |
| 458 | | - dryRunFlag = find_option("dry-run","n",0)!=0; |
| 574 | + if(0!=find_option("reset",0,0)){ |
| 575 | + int const verboseFlag = find_option("verbose","v",0)!=0; |
| 576 | + db_must_be_within_tree(); |
| 577 | + verify_all_options(); |
| 578 | + addremove_reset(0, dryRunFlag, verboseFlag); |
| 579 | + return; |
| 580 | + } |
| 581 | + |
| 459 | 582 | softFlag = find_option("soft",0,0)!=0; |
| 460 | 583 | hardFlag = find_option("hard",0,0)!=0; |
| 461 | 584 | |
| 462 | 585 | /* We should be done with options.. */ |
| 463 | 586 | verify_all_options(); |
| | @@ -623,18 +746,26 @@ |
| 623 | 746 | ** --ignore <CSG> Ignore unmanaged files matching patterns from |
| 624 | 747 | ** the comma separated list of glob patterns. |
| 625 | 748 | ** --clean <CSG> Also ignore files matching patterns from |
| 626 | 749 | ** the comma separated list of glob patterns. |
| 627 | 750 | ** -n|--dry-run If given, display instead of run actions. |
| 751 | +** --reset Reset the ADDED/DELETED state of a checkout, |
| 752 | +** such that all newly-added (but not yet committed) |
| 753 | +** files are no longer added and all newly-removed |
| 754 | +** (but not yet committed) files are no longer |
| 755 | +** removed. No flags other than --verbose and |
| 756 | +** --dry-run may be used with --reset. |
| 757 | +** --verbose|-v Outputs information about each --reset file. |
| 758 | +** Only usable with --reset. |
| 628 | 759 | ** |
| 629 | 760 | ** See also: add, rm |
| 630 | 761 | */ |
| 631 | 762 | void addremove_cmd(void){ |
| 632 | 763 | 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; |
| 764 | + const char *zCleanFlag; |
| 765 | + const char *zIgnoreFlag; |
| 766 | + unsigned scanFlags; |
| 636 | 767 | int dryRunFlag = find_option("dry-run","n",0)!=0; |
| 637 | 768 | int n; |
| 638 | 769 | Stmt q; |
| 639 | 770 | int vid; |
| 640 | 771 | int nAdd = 0; |
| | @@ -643,10 +774,23 @@ |
| 643 | 774 | |
| 644 | 775 | if( !dryRunFlag ){ |
| 645 | 776 | dryRunFlag = find_option("test",0,0)!=0; /* deprecated */ |
| 646 | 777 | } |
| 647 | 778 | |
| 779 | + if(0!=find_option("reset",0,0)){ |
| 780 | + int const verboseFlag = find_option("verbose","v",0)!=0; |
| 781 | + db_must_be_within_tree(); |
| 782 | + verify_all_options(); |
| 783 | + addremove_reset(0, dryRunFlag, verboseFlag); |
| 784 | + addremove_reset(1, dryRunFlag, verboseFlag); |
| 785 | + return; |
| 786 | + } |
| 787 | + |
| 788 | + zCleanFlag = find_option("clean",0,1); |
| 789 | + zIgnoreFlag = find_option("ignore",0,1); |
| 790 | + scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; |
| 791 | + |
| 648 | 792 | /* We should be done with options.. */ |
| 649 | 793 | verify_all_options(); |
| 650 | 794 | |
| 651 | 795 | /* Fail if unprocessed arguments are present, in case user expect the |
| 652 | 796 | ** addremove command to accept a list of file or directory. |
| | @@ -710,11 +854,10 @@ |
| 710 | 854 | /* show command summary */ |
| 711 | 855 | fossil_print("added %d files, deleted %d files\n", nAdd, nDelete); |
| 712 | 856 | |
| 713 | 857 | db_end_transaction(dryRunFlag); |
| 714 | 858 | } |
| 715 | | - |
| 716 | 859 | |
| 717 | 860 | /* |
| 718 | 861 | ** Rename a single file. |
| 719 | 862 | ** |
| 720 | 863 | ** The original name of the file is zOrig. The new filename is zNew. |
| 721 | 864 | |