Checkout has to handle a lot of different cases. It examines the differences between the target tree, the baseline tree and the working directory, plus the contents of the index, and groups files into five categories:
Right now, this classification is done via 3 iterators (for the three trees), with a final lookup in the index. At some point, this may move to a 4 iterator version to incorporate the index better.
The actual checkout is done in five phases (at least right now).
Checkout could 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.
The current checkout implementation is based on a baseline-to-target diff.
The most interesting aspect of this is phase 2, picking the actions that should be taken. There are a lot of corner cases, so it may be easier to start by looking at the rules for a simple 2-iterator diff:
|6||B1||T1||typechange blob -> tree|
|8||T1||B1||typechange tree -> blob|
|10||T1||T2||modified tree (implies modified/added/removed blob inside)|
Now, let's make the “New” iterator into a working directory iterator, so we replace “added” items with either untracked or ignored, like this:
|8||B1||T1||typechange blob -> tree|
|9||B1||Ti||removed blob AND ignored tree as separate items|
|11||T1||B1||typechange tree -> blob|
|12||T1||Bi||removed tree AND ignored blob as separate items|
|14||T1||T2||modified tree (implies modified/added/removed blob inside)|
Note: if there is a corresponding entry in the old tree, then a working directory item won't be ignored (i.e. no Bi or Ti for tracked items).
Now, expand this to three iterators: a baseline tree, a target tree, and an actual working directory tree:
(base == old HEAD; target == what to checkout; actual == working dir)
|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|
|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 is 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:
Some slightly unusual circumstances:
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.