Fossil SCM
Added --dry-run support to add/rm/addremove --reset.
Commit
a7a75e7d412130d6d63afe4120b41409b5d96972153e752c0fcc2e3759943ff3
Parent
72fdb21ae8cffc1…
1 file changed
+57
-45
+57
-45
| --- src/add.c | ||
| +++ src/add.c | ||
| @@ -242,86 +242,97 @@ | ||
| 242 | 242 | blob_reset(&repoName); |
| 243 | 243 | return nAdd; |
| 244 | 244 | } |
| 245 | 245 | |
| 246 | 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(). | |
| 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(). | |
| 256 | 261 | ** |
| 257 | 262 | ** Un-added files are not modified but any un-rm'd files which are |
| 258 | 263 | ** missing from the checkout are restored from the repo. un-rm'd files |
| 259 | 264 | ** which exist in the checkout are left as-is, rather than restoring |
| 260 | 265 | ** them using vfile_to_disk(), to avoid overwriting any local changes |
| 261 | 266 | ** made to those files. |
| 262 | 267 | */ |
| 263 | -static void addremove_reset(int fIsAdd, int fVerbose){ | |
| 268 | +static void addremove_reset(int bIsAdd, int bDryRun, int bVerbose){ | |
| 264 | 269 | int nReset = 0; /* # of entries which get reset */ |
| 265 | 270 | Stmt stmt; /* vfile loop query */ |
| 266 | 271 | |
| 267 | 272 | db_begin_transaction(); |
| 268 | 273 | db_prepare(&stmt, "SELECT id, pathname FROM vfile " |
| 269 | 274 | "WHERE %s ORDER BY pathname", |
| 270 | - fIsAdd==0 ? "deleted<>0" : "rid=0"/*safe-for-%s*/); | |
| 275 | + bIsAdd==0 ? "deleted<>0" : "rid=0"/*safe-for-%s*/); | |
| 271 | 276 | while( db_step(&stmt)==SQLITE_ROW ){ |
| 272 | 277 | /* This loop exists only so we can restore the contents of un-rm'd |
| 273 | 278 | ** files and support verbose mode. All manipulation of vfile's |
| 274 | 279 | ** contents happens after the loop. For the ADD case in non-verbose |
| 275 | 280 | ** mode we "could" skip this loop entirely. |
| 276 | 281 | */ |
| 277 | 282 | int const id = db_column_int(&stmt, 0); |
| 278 | 283 | char const * zPathname = db_column_text(&stmt, 1); |
| 279 | 284 | Blob relName = empty_blob; |
| 280 | - if(fIsAdd==0 || fVerbose!=0){ | |
| 285 | + if(bIsAdd==0 || bVerbose!=0){ | |
| 281 | 286 | /* Make filename relative... */ |
| 282 | 287 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 283 | 288 | file_relative_name(zFullName, &relName, 0); |
| 284 | 289 | fossil_free(zFullName); |
| 285 | 290 | } |
| 286 | - if(fIsAdd==0){ | |
| 291 | + if(bIsAdd==0){ | |
| 287 | 292 | /* Restore contents of missing un-rm'd files. We don't do this |
| 288 | 293 | ** unconditionally because we might cause data loss if a file |
| 289 | 294 | ** is modified, rm'd, then un-rm'd. |
| 290 | 295 | */ |
| 291 | 296 | ++nReset; |
| 292 | 297 | 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){ | |
| 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){ | |
| 301 | 308 | fossil_print("Un-removed: %b\n", &relName); |
| 302 | 309 | } |
| 303 | 310 | }else{ |
| 304 | 311 | /* un-add... */ |
| 305 | 312 | ++nReset; |
| 306 | - if(fVerbose){ | |
| 313 | + if(bVerbose){ | |
| 307 | 314 | fossil_print("Un-added: %b\n", &relName); |
| 308 | 315 | } |
| 309 | 316 | } |
| 310 | 317 | blob_reset(&relName); |
| 311 | 318 | } |
| 312 | 319 | db_finalize(&stmt); |
| 313 | 320 | if(nReset>0){ |
| 314 | - if(fIsAdd==0){ | |
| 315 | - db_exec_sql("UPDATE vfile SET deleted=0 WHERE deleted<>0"); | |
| 321 | + if(bIsAdd==0){ | |
| 322 | + if(bDryRun==0){ | |
| 323 | + db_exec_sql("UPDATE vfile SET deleted=0 WHERE deleted<>0"); | |
| 324 | + } | |
| 316 | 325 | fossil_print("Un-removed %d file(s).\n", nReset); |
| 317 | 326 | }else{ |
| 318 | - db_exec_sql("DELETE FROM vfile WHERE rid=0"); | |
| 327 | + if(bDryRun==0){ | |
| 328 | + db_exec_sql("DELETE FROM vfile WHERE rid=0"); | |
| 329 | + } | |
| 319 | 330 | fossil_print("Un-added %d file(s).\n", nReset); |
| 320 | 331 | } |
| 321 | 332 | } |
| 322 | - db_end_transaction(0); | |
| 333 | + db_end_transaction(bDryRun ? 1 : 0); | |
| 323 | 334 | } |
| 324 | 335 | |
| 325 | 336 | |
| 326 | 337 | /* |
| 327 | 338 | ** COMMAND: add |
| @@ -356,16 +367,17 @@ | ||
| 356 | 367 | ** -f|--force Add files without prompting |
| 357 | 368 | ** --ignore <CSG> Ignore unmanaged files matching patterns from |
| 358 | 369 | ** the comma separated list of glob patterns. |
| 359 | 370 | ** --clean <CSG> Also ignore files matching patterns from |
| 360 | 371 | ** the comma separated list of glob patterns. |
| 361 | -** --reset Reset the ADD state of a checkout, such that | |
| 372 | +** --reset Reset the ADDEd state of a checkout, such that | |
| 362 | 373 | ** 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. | |
| 374 | +** are no longer added. | |
| 375 | +** | |
| 376 | +** The following options are only valid with --reset: | |
| 377 | +** -v|--verbose Outputs information about each --reset file. | |
| 378 | +** -n|--dry-run Display instead of run actions. | |
| 367 | 379 | ** |
| 368 | 380 | ** See also: addremove, rm |
| 369 | 381 | */ |
| 370 | 382 | void add_cmd(void){ |
| 371 | 383 | int i; /* Loop counter */ |
| @@ -377,13 +389,14 @@ | ||
| 377 | 389 | unsigned scanFlags = 0; /* Flags passed to vfile_scan() */ |
| 378 | 390 | int forceFlag; |
| 379 | 391 | |
| 380 | 392 | if(0!=find_option("reset",0,0)){ |
| 381 | 393 | int const verboseFlag = find_option("verbose","v",0)!=0; |
| 394 | + int const dryRunFlag = find_option("dry-run","n",0)!=0; | |
| 382 | 395 | db_must_be_within_tree(); |
| 383 | 396 | verify_all_options(); |
| 384 | - addremove_reset(1, verboseFlag); | |
| 397 | + addremove_reset(1, dryRunFlag, verboseFlag); | |
| 385 | 398 | return; |
| 386 | 399 | } |
| 387 | 400 | |
| 388 | 401 | zCleanFlag = find_option("clean",0,1); |
| 389 | 402 | zIgnoreFlag = find_option("ignore",0,1); |
| @@ -548,24 +561,23 @@ | ||
| 548 | 561 | ** See also: addremove, add |
| 549 | 562 | */ |
| 550 | 563 | void delete_cmd(void){ |
| 551 | 564 | int i; |
| 552 | 565 | int removeFiles; |
| 553 | - int dryRunFlag; | |
| 566 | + int dryRunFlag = find_option("dry-run","n",0)!=0; | |
| 554 | 567 | int softFlag; |
| 555 | 568 | int hardFlag; |
| 556 | 569 | Stmt loop; |
| 557 | 570 | |
| 558 | 571 | if(0!=find_option("reset",0,0)){ |
| 559 | 572 | int const verboseFlag = find_option("verbose","v",0)!=0; |
| 560 | 573 | db_must_be_within_tree(); |
| 561 | 574 | verify_all_options(); |
| 562 | - addremove_reset(0, verboseFlag); | |
| 575 | + addremove_reset(0, dryRunFlag, verboseFlag); | |
| 563 | 576 | return; |
| 564 | 577 | } |
| 565 | 578 | |
| 566 | - dryRunFlag = find_option("dry-run","n",0)!=0; | |
| 567 | 579 | softFlag = find_option("soft",0,0)!=0; |
| 568 | 580 | hardFlag = find_option("hard",0,0)!=0; |
| 569 | 581 | |
| 570 | 582 | /* We should be done with options.. */ |
| 571 | 583 | verify_all_options(); |
| @@ -734,13 +746,13 @@ | ||
| 734 | 746 | ** the comma separated list of glob patterns. |
| 735 | 747 | ** -n|--dry-run If given, display instead of run actions. |
| 736 | 748 | ** --reset Reset the ADDED/DELETED state of a checkout, |
| 737 | 749 | ** such that all newly-added (but not yet committed) |
| 738 | 750 | ** 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. | |
| 751 | +** (but not yet committed) files are no longer | |
| 752 | +** removed. No flags other than --verbose and | |
| 753 | +** --dry-run may be used with --reset. | |
| 742 | 754 | ** --verbose|-v Outputs information about each --reset file. |
| 743 | 755 | ** Only usable with --reset. |
| 744 | 756 | ** |
| 745 | 757 | ** See also: add, rm |
| 746 | 758 | */ |
| @@ -747,34 +759,34 @@ | ||
| 747 | 759 | void addremove_cmd(void){ |
| 748 | 760 | Blob path; |
| 749 | 761 | const char *zCleanFlag; |
| 750 | 762 | const char *zIgnoreFlag; |
| 751 | 763 | unsigned scanFlags; |
| 752 | - int dryRunFlag; | |
| 764 | + int dryRunFlag = find_option("dry-run","n",0)!=0; | |
| 753 | 765 | int n; |
| 754 | 766 | Stmt q; |
| 755 | 767 | int vid; |
| 756 | 768 | int nAdd = 0; |
| 757 | 769 | int nDelete = 0; |
| 758 | 770 | Glob *pIgnore, *pClean; |
| 771 | + | |
| 772 | + if( !dryRunFlag ){ | |
| 773 | + dryRunFlag = find_option("test",0,0)!=0; /* deprecated */ | |
| 774 | + } | |
| 759 | 775 | |
| 760 | 776 | if(0!=find_option("reset",0,0)){ |
| 761 | 777 | int const verboseFlag = find_option("verbose","v",0)!=0; |
| 762 | 778 | db_must_be_within_tree(); |
| 763 | 779 | verify_all_options(); |
| 764 | - addremove_reset(0, verboseFlag); | |
| 765 | - addremove_reset(1, verboseFlag); | |
| 780 | + addremove_reset(0, dryRunFlag, verboseFlag); | |
| 781 | + addremove_reset(1, dryRunFlag, verboseFlag); | |
| 766 | 782 | return; |
| 767 | 783 | } |
| 768 | 784 | |
| 769 | 785 | zCleanFlag = find_option("clean",0,1); |
| 770 | 786 | zIgnoreFlag = find_option("ignore",0,1); |
| 771 | 787 | 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 | 788 | |
| 777 | 789 | /* We should be done with options.. */ |
| 778 | 790 | verify_all_options(); |
| 779 | 791 | |
| 780 | 792 | /* Fail if unprocessed arguments are present, in case user expect the |
| 781 | 793 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -242,86 +242,97 @@ | |
| 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 |
| @@ -356,16 +367,17 @@ | |
| 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 */ |
| @@ -377,13 +389,14 @@ | |
| 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); |
| @@ -548,24 +561,23 @@ | |
| 548 | ** See also: addremove, add |
| 549 | */ |
| 550 | void delete_cmd(void){ |
| 551 | int i; |
| 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 | |
| 570 | /* We should be done with options.. */ |
| 571 | verify_all_options(); |
| @@ -734,13 +746,13 @@ | |
| 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,34 +759,34 @@ | |
| 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.. */ |
| 778 | verify_all_options(); |
| 779 | |
| 780 | /* Fail if unprocessed arguments are present, in case user expect the |
| 781 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -242,86 +242,97 @@ | |
| 242 | blob_reset(&repoName); |
| 243 | return nAdd; |
| 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 | |
| 336 | |
| 337 | /* |
| 338 | ** COMMAND: add |
| @@ -356,16 +367,17 @@ | |
| 367 | ** -f|--force Add files without prompting |
| 368 | ** --ignore <CSG> Ignore unmanaged files matching patterns from |
| 369 | ** the comma separated list of glob patterns. |
| 370 | ** --clean <CSG> Also ignore files matching patterns from |
| 371 | ** the comma separated list of glob patterns. |
| 372 | ** --reset Reset the ADDEd state of a checkout, such that |
| 373 | ** all newly-added (but not yet committed) files |
| 374 | ** are no longer added. |
| 375 | ** |
| 376 | ** The following options are only valid with --reset: |
| 377 | ** -v|--verbose Outputs information about each --reset file. |
| 378 | ** -n|--dry-run Display instead of run actions. |
| 379 | ** |
| 380 | ** See also: addremove, rm |
| 381 | */ |
| 382 | void add_cmd(void){ |
| 383 | int i; /* Loop counter */ |
| @@ -377,13 +389,14 @@ | |
| 389 | unsigned scanFlags = 0; /* Flags passed to vfile_scan() */ |
| 390 | int forceFlag; |
| 391 | |
| 392 | if(0!=find_option("reset",0,0)){ |
| 393 | int const verboseFlag = find_option("verbose","v",0)!=0; |
| 394 | int const dryRunFlag = find_option("dry-run","n",0)!=0; |
| 395 | db_must_be_within_tree(); |
| 396 | verify_all_options(); |
| 397 | addremove_reset(1, dryRunFlag, verboseFlag); |
| 398 | return; |
| 399 | } |
| 400 | |
| 401 | zCleanFlag = find_option("clean",0,1); |
| 402 | zIgnoreFlag = find_option("ignore",0,1); |
| @@ -548,24 +561,23 @@ | |
| 561 | ** See also: addremove, add |
| 562 | */ |
| 563 | void delete_cmd(void){ |
| 564 | int i; |
| 565 | int removeFiles; |
| 566 | int dryRunFlag = find_option("dry-run","n",0)!=0; |
| 567 | int softFlag; |
| 568 | int hardFlag; |
| 569 | Stmt loop; |
| 570 | |
| 571 | if(0!=find_option("reset",0,0)){ |
| 572 | int const verboseFlag = find_option("verbose","v",0)!=0; |
| 573 | db_must_be_within_tree(); |
| 574 | verify_all_options(); |
| 575 | addremove_reset(0, dryRunFlag, verboseFlag); |
| 576 | return; |
| 577 | } |
| 578 | |
| 579 | softFlag = find_option("soft",0,0)!=0; |
| 580 | hardFlag = find_option("hard",0,0)!=0; |
| 581 | |
| 582 | /* We should be done with options.. */ |
| 583 | verify_all_options(); |
| @@ -734,13 +746,13 @@ | |
| 746 | ** the comma separated list of glob patterns. |
| 747 | ** -n|--dry-run If given, display instead of run actions. |
| 748 | ** --reset Reset the ADDED/DELETED state of a checkout, |
| 749 | ** such that all newly-added (but not yet committed) |
| 750 | ** files are no longer added and all newly-removed |
| 751 | ** (but not yet committed) files are no longer |
| 752 | ** removed. No flags other than --verbose and |
| 753 | ** --dry-run may be used with --reset. |
| 754 | ** --verbose|-v Outputs information about each --reset file. |
| 755 | ** Only usable with --reset. |
| 756 | ** |
| 757 | ** See also: add, rm |
| 758 | */ |
| @@ -747,34 +759,34 @@ | |
| 759 | void addremove_cmd(void){ |
| 760 | Blob path; |
| 761 | const char *zCleanFlag; |
| 762 | const char *zIgnoreFlag; |
| 763 | unsigned scanFlags; |
| 764 | int dryRunFlag = find_option("dry-run","n",0)!=0; |
| 765 | int n; |
| 766 | Stmt q; |
| 767 | int vid; |
| 768 | int nAdd = 0; |
| 769 | int nDelete = 0; |
| 770 | Glob *pIgnore, *pClean; |
| 771 | |
| 772 | if( !dryRunFlag ){ |
| 773 | dryRunFlag = find_option("test",0,0)!=0; /* deprecated */ |
| 774 | } |
| 775 | |
| 776 | if(0!=find_option("reset",0,0)){ |
| 777 | int const verboseFlag = find_option("verbose","v",0)!=0; |
| 778 | db_must_be_within_tree(); |
| 779 | verify_all_options(); |
| 780 | addremove_reset(0, dryRunFlag, verboseFlag); |
| 781 | addremove_reset(1, dryRunFlag, verboseFlag); |
| 782 | return; |
| 783 | } |
| 784 | |
| 785 | zCleanFlag = find_option("clean",0,1); |
| 786 | zIgnoreFlag = find_option("ignore",0,1); |
| 787 | scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0; |
| 788 | |
| 789 | /* We should be done with options.. */ |
| 790 | verify_all_options(); |
| 791 | |
| 792 | /* Fail if unprocessed arguments are present, in case user expect the |
| 793 |