diff options
Diffstat (limited to 'src/checkout.c')
-rw-r--r-- | src/checkout.c | 184 |
1 files changed, 8 insertions, 176 deletions
diff --git a/src/checkout.c b/src/checkout.c index a26f007b1..2e132947d 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -24,157 +24,7 @@ #include "diff.h" #include "pathspec.h" -/* Key - * === - * B1,B2,B3 - blobs with different SHAs, - * Bi - ignored blob (WD only) - * T1,T2,T3 - trees with different SHAs, - * Ti - ignored tree (WD only) - * x - nothing - */ - -/* Diff with 2 non-workdir iterators - * ================================= - * Old New - * --- --- - * 0 x x - nothing - * 1 x B1 - added blob - * 2 x T1 - added tree - * 3 B1 x - removed blob - * 4 B1 B1 - unmodified blob - * 5 B1 B2 - modified blob - * 6 B1 T1 - typechange blob -> tree - * 7 T1 x - removed tree - * 8 T1 B1 - typechange tree -> blob - * 9 T1 T1 - unmodified tree - * 10 T1 T2 - modified tree (implies modified/added/removed blob inside) - */ - -/* Diff with non-work & workdir iterators - * ====================================== - * Old New-WD - * --- ------ - * 0 x x - nothing - * 1 x B1 - added blob - * 2 x Bi - ignored file - * 3 x T1 - added tree - * 4 x Ti - ignored tree - * 5 B1 x - removed blob - * 6 B1 B1 - unmodified blob - * 7 B1 B2 - modified blob - * 8 B1 T1 - typechange blob -> tree - * 9 B1 Ti - removed blob AND ignored tree as separate items - * 10 T1 x - removed tree - * 11 T1 B1 - typechange tree -> blob - * 12 T1 Bi - removed tree AND ignored blob as separate items - * 13 T1 T1 - unmodified tree - * 14 T1 T2 - modified tree (implies modified/added/removed blob inside) - * - * If there is a corresponding blob in the old, Bi is irrelevant - * If there is a corresponding tree in the old, Ti is irrelevant - */ - -/* Checkout From 3 Iterators (2 not workdir, 1 workdir) - * ==================================================== - * - * (Expect == Old HEAD / Desire == What To Checkout / Actual == Workdir) - * - * Expect Desire Actual-WD - * ------ ------ ------ - * 0 x x x - nothing - * 1 x x B1/Bi/T1/Ti - untracked/ignored blob/tree (SAFE) - * 2+ x B1 x - add blob (SAFE) - * 3 x B1 B1 - independently added blob (FORCEABLE-2) - * 4* x B1 B2/Bi/T1/Ti - add blob with content conflict (FORCEABLE-2) - * 5+ x T1 x - add tree (SAFE) - * 6* x T1 B1/Bi - add tree with blob conflict (FORCEABLE-2) - * 7 x T1 T1/i - independently added tree (SAFE+MISSING) - * 8 B1 x x - independently deleted blob (SAFE+MISSING) - * 9- B1 x B1 - delete blob (SAFE) - * 10- B1 x B2 - delete of modified blob (FORCEABLE-1) - * 11 B1 x T1/Ti - independently deleted blob AND untrack/ign tree (SAFE+MISSING !!!) - * 12 B1 B1 x - locally deleted blob (DIRTY || SAFE+CREATE) - * 13+ B1 B2 x - update to deleted blob (SAFE+MISSING) - * 14 B1 B1 B1 - unmodified file (SAFE) - * 15 B1 B1 B2 - locally modified file (DIRTY) - * 16+ B1 B2 B1 - update unmodified blob (SAFE) - * 17 B1 B2 B2 - independently updated blob (FORCEABLE-1) - * 18+ B1 B2 B3 - update to modified blob (FORCEABLE-1) - * 19 B1 B1 T1/Ti - locally deleted blob AND untrack/ign tree (DIRTY) - * 20* B1 B2 T1/Ti - update to deleted blob AND untrack/ign tree (F-1) - * 21+ B1 T1 x - add tree with locally deleted blob (SAFE+MISSING) - * 22* B1 T1 B1 - add tree AND deleted blob (SAFE) - * 23* B1 T1 B2 - add tree with delete of modified blob (F-1) - * 24 B1 T1 T1 - add tree with deleted blob (F-1) - * 25 T1 x x - independently deleted tree (SAFE+MISSING) - * 26 T1 x B1/Bi - independently deleted tree AND untrack/ign blob (F-1) - * 27- T1 x T1 - deleted tree (MAYBE SAFE) - * 28+ T1 B1 x - deleted tree AND added blob (SAFE+MISSING) - * 29 T1 B1 B1 - independently typechanged tree -> blob (F-1) - * 30+ T1 B1 B2 - typechange tree->blob with conflicting blob (F-1) - * 31* T1 B1 T1/T2 - typechange tree->blob (MAYBE SAFE) - * 32+ T1 T1 x - restore locally deleted tree (SAFE+MISSING) - * 33 T1 T1 B1/Bi - locally typechange tree->untrack/ign blob (DIRTY) - * 34 T1 T1 T1/T2 - unmodified tree (MAYBE SAFE) - * 35+ T1 T2 x - update locally deleted tree (SAFE+MISSING) - * 36* T1 T2 B1/Bi - update to tree with typechanged tree->blob conflict (F-1) - * 37 T1 T2 T1/T2/T3 - update to existing tree (MAYBE SAFE) - * - * The number will be followed by ' ' if no change is needed or '+' if the - * case needs to write to disk or '-' if something must be deleted and '*' - * if there should be a delete followed by an write. - * - * There are four tiers of safe cases: - * - SAFE == completely safe to update - * - SAFE+MISSING == safe except the workdir is missing the expect content - * - MAYBE SAFE == safe if workdir tree matches (or is missing) baseline - * content, which is unknown at this point - * - FORCEABLE == conflict unless FORCE is given - * - DIRTY == no conflict but change is not applied unless FORCE - * - * Some slightly unusual circumstances: - * 8 - parent dir is only deleted when file is, so parent will be left if - * empty even though it would be deleted if the file were present - * 11 - core git does not consider this a conflict but attempts to delete T1 - * and gives "unable to unlink file" error yet does not skip the rest - * of the operation - * 12 - without FORCE file is left deleted (i.e. not restored) so new wd is - * dirty (and warning message "D file" is printed), with FORCE, file is - * restored. - * 24 - This should be considered MAYBE SAFE since effectively it is 7 and 8 - * combined, but core git considers this a conflict unless forced. - * 26 - This combines two cases (1 & 25) (and also implied 8 for tree content) - * which are ok on their own, but core git treat this as a conflict. - * If not forced, this is a conflict. If forced, this actually doesn't - * have to write anything and leaves the new blob as an untracked file. - * 32 - This is the only case where the baseline and target values match - * and yet we will still write to the working directory. In all other - * cases, if baseline == target, we don't touch the workdir (it is - * either already right or is "dirty"). However, since this case also - * implies that a ?/B1/x case will exist as well, it can be skipped. - * - * Cases 3, 17, 24, 26, and 29 are all considered conflicts even though - * none of them will require making any updates to the working directory. - */ - -/* expect desire wd - * 1 x x T -> ignored dir OR untracked dir OR parent dir - * 2 x x I -> ignored file - * 3 x x A -> untracked file - * 4 x A x -> add from index (no conflict) - * 5 x A A -> independently added file - * 6 x A B -> add with conflicting file - * 7 A x x -> independently deleted file - * 8 A x A -> delete from index (no conflict) - * 9 A x B -> delete of modified file - * 10 A A x -> locally deleted file - * 11 A A A -> unmodified file (no conflict) - * 12 A A B -> locally modified - * 13 A B x -> update of deleted file - * 14 A B A -> update of unmodified file (no conflict) - * 15 A B B -> independently updated file - * 16 A B C -> update of modified file - */ +/* See docs/checkout-internals.md for more information */ enum { CHECKOUT_ACTION__NONE = 0, @@ -1317,34 +1167,15 @@ int git_checkout_iterator( goto cleanup; } - /* Checkout can be driven either off a target-to-workdir diff or a - * baseline-to-target diff. There are pros and cons of each. - * - * Target-to-workdir means the diff includes every file that could be - * modified, which simplifies bookkeeping, but the code to constantly - * refer back to the baseline gets complicated. - * - * Baseline-to-target has simpler code because the diff defines the - * action to take, but needs special handling for untracked and ignored - * files, if they need to be removed. - * - * I've implemented both versions and opted for the second. + /* Generate baseline-to-target diff which will include an entry for + * every possible update that might need to be made. */ if ((error = git_diff__from_iterators( &data.diff, data.repo, baseline, target, &diff_opts)) < 0) goto cleanup; - /* In order to detect conflicts prior to performing any operations, - * and in order to deal with some order dependencies, checkout is best - * performed with up to four passes through the diff. - * - * 0. Figure out the actions to be taken, - * 1. Remove any files / directories as needed (because alphabetical - * iteration means that an untracked directory will end up sorted - * *after* a blob that should be checked out with the same name), - * 2. Then update all blobs, - * 3. Then update all submodules in case a new .gitmodules blob was - * checked out during pass #2. + /* Loop through diff (and working directory iterator) building a list of + * actions to be taken, plus look for conflicts and send notifications. */ if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) < 0) goto cleanup; @@ -1355,8 +1186,9 @@ int git_checkout_iterator( report_progress(&data, NULL); /* establish 0 baseline */ - /* TODO: add ability to update index entries while checking out */ - + /* To deal with some order dependencies, perform remaining checkout + * in three passes: removes, then update blobs, then update submodules. + */ if (counts[CHECKOUT_ACTION__REMOVE] > 0 && (error = checkout_remove_the_old(actions, &data)) < 0) goto cleanup; |