]> git.proxmox.com Git - libgit2.git/blame - src/checkout.c
Clone should use GIT_CHECKOUT_SAFE_CREATE
[libgit2.git] / src / checkout.c
CommitLineData
14741d62
BS
1/*
2 * Copyright (C) 2009-2012 the libgit2 contributors
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7
8#include <assert.h>
9
cf208031
RB
10#include "checkout.h"
11
14741d62
BS
12#include "git2/repository.h"
13#include "git2/refs.h"
14#include "git2/tree.h"
24b0d3d5 15#include "git2/blob.h"
8651c10f 16#include "git2/config.h"
3aa443a9 17#include "git2/diff.h"
e0548c0e 18#include "git2/submodule.h"
14741d62 19
14741d62 20#include "refs.h"
24b0d3d5 21#include "repository.h"
0e874b12 22#include "filter.h"
41ad70d0 23#include "blob.h"
32def5af 24#include "diff.h"
ad9a921b 25#include "pathspec.h"
14741d62 26
cf208031
RB
27/* Key
28 * ===
29 * B1,B2,B3 - blobs with different SHAs,
30 * Bi - ignored blob (WD only)
31 * T1,T2,T3 - trees with different SHAs,
32 * Ti - ignored tree (WD only)
33 * x - nothing
34 */
35
36/* Diff with 2 non-workdir iterators
37 * =================================
38 * Old New
39 * --- ---
40 * 0 x x - nothing
41 * 1 x B1 - added blob
42 * 2 x T1 - added tree
43 * 3 B1 x - removed blob
44 * 4 B1 B1 - unmodified blob
45 * 5 B1 B2 - modified blob
46 * 6 B1 T1 - typechange blob -> tree
47 * 7 T1 x - removed tree
48 * 8 T1 B1 - typechange tree -> blob
49 * 9 T1 T1 - unmodified tree
50 * 10 T1 T2 - modified tree (implies modified/added/removed blob inside)
51 */
52
53/* Diff with non-work & workdir iterators
54 * ======================================
55 * Old New-WD
56 * --- ------
57 * 0 x x - nothing
58 * 1 x B1 - added blob
59 * 2 x Bi - ignored file
60 * 3 x T1 - added tree
61 * 4 x Ti - ignored tree
62 * 5 B1 x - removed blob
63 * 6 B1 B1 - unmodified blob
64 * 7 B1 B2 - modified blob
65 * 8 B1 T1 - typechange blob -> tree
66 * 9 B1 Ti - removed blob AND ignored tree as separate items
67 * 10 T1 x - removed tree
68 * 11 T1 B1 - typechange tree -> blob
69 * 12 T1 Bi - removed tree AND ignored blob as separate items
70 * 13 T1 T1 - unmodified tree
71 * 14 T1 T2 - modified tree (implies modified/added/removed blob inside)
72 *
73 * If there is a corresponding blob in the old, Bi is irrelevant
74 * If there is a corresponding tree in the old, Ti is irrelevant
75 */
76
77/* Checkout From 3 Iterators (2 not workdir, 1 workdir)
78 * ====================================================
79 *
80 * (Expect == Old HEAD / Desire == What To Checkout / Actual == Workdir)
81 *
82 * Expect Desire Actual-WD
83 * ------ ------ ------
84 * 0 x x x - nothing
85 * 1 x x B1/Bi/T1/Ti - untracked/ignored blob/tree (SAFE)
86 * 2+ x B1 x - add blob (SAFE)
87 * 3 x B1 B1 - independently added blob (FORCEABLE-2)
88 * 4* x B1 B2/Bi/T1/Ti - add blob with content conflict (FORCEABLE-2)
89 * 5+ x T1 x - add tree (SAFE)
90 * 6* x T1 B1/Bi - add tree with blob conflict (FORCEABLE-2)
91 * 7 x T1 T1/i - independently added tree (SAFE+MISSING)
92 * 8 B1 x x - independently deleted blob (SAFE+MISSING)
93 * 9- B1 x B1 - delete blob (SAFE)
94 * 10- B1 x B2 - delete of modified blob (FORCEABLE-1)
95 * 11 B1 x T1/Ti - independently deleted blob AND untrack/ign tree (SAFE+MISSING !!!)
96 * 12 B1 B1 x - locally deleted blob (DIRTY || SAFE+CREATE)
97 * 13+ B1 B2 x - update to deleted blob (SAFE+MISSING)
98 * 14 B1 B1 B1 - unmodified file (SAFE)
99 * 15 B1 B1 B2 - locally modified file (DIRTY)
100 * 16+ B1 B2 B1 - update unmodified blob (SAFE)
101 * 17 B1 B2 B2 - independently updated blob (FORCEABLE-1)
102 * 18+ B1 B2 B3 - update to modified blob (FORCEABLE-1)
103 * 19 B1 B1 T1/Ti - locally deleted blob AND untrack/ign tree (DIRTY)
104 * 20* B1 B2 T1/Ti - update to deleted blob AND untrack/ign tree (F-1)
105 * 21+ B1 T1 x - add tree with locally deleted blob (SAFE+MISSING)
106 * 22* B1 T1 B1 - add tree AND deleted blob (SAFE)
107 * 23* B1 T1 B2 - add tree with delete of modified blob (F-1)
108 * 24 B1 T1 T1 - add tree with deleted blob (F-1)
109 * 25 T1 x x - independently deleted tree (SAFE+MISSING)
110 * 26 T1 x B1/Bi - independently deleted tree AND untrack/ign blob (F-1)
111 * 27- T1 x T1 - deleted tree (MAYBE SAFE)
112 * 28+ T1 B1 x - deleted tree AND added blob (SAFE+MISSING)
113 * 29 T1 B1 B1 - independently typechanged tree -> blob (F-1)
114 * 30+ T1 B1 B2 - typechange tree->blob with conflicting blob (F-1)
115 * 31* T1 B1 T1/T2 - typechange tree->blob (MAYBE SAFE)
116 * 32+ T1 T1 x - restore locally deleted tree (SAFE+MISSING)
117 * 33 T1 T1 B1/Bi - locally typechange tree->untrack/ign blob (DIRTY)
118 * 34 T1 T1 T1/T2 - unmodified tree (MAYBE SAFE)
119 * 35+ T1 T2 x - update locally deleted tree (SAFE+MISSING)
120 * 36* T1 T2 B1/Bi - update to tree with typechanged tree->blob conflict (F-1)
121 * 37 T1 T2 T1/T2/T3 - update to existing tree (MAYBE SAFE)
122 *
123 * The number will be followed by ' ' if no change is needed or '+' if the
124 * case needs to write to disk or '-' if something must be deleted and '*'
125 * if there should be a delete followed by an write.
126 *
127 * There are four tiers of safe cases:
128 * - SAFE == completely safe to update
129 * - SAFE+MISSING == safe except the workdir is missing the expect content
7e5c8a5b 130 * - MAYBE SAFE == safe if workdir tree matches (or is missing) baseline
cf208031
RB
131 * content, which is unknown at this point
132 * - FORCEABLE == conflict unless FORCE is given
133 * - DIRTY == no conflict but change is not applied unless FORCE
134 *
135 * Some slightly unusual circumstances:
136 * 8 - parent dir is only deleted when file is, so parent will be left if
137 * empty even though it would be deleted if the file were present
138 * 11 - core git does not consider this a conflict but attempts to delete T1
139 * and gives "unable to unlink file" error yet does not skip the rest
140 * of the operation
141 * 12 - without FORCE file is left deleted (i.e. not restored) so new wd is
142 * dirty (and warning message "D file" is printed), with FORCE, file is
143 * restored.
144 * 24 - This should be considered MAYBE SAFE since effectively it is 7 and 8
145 * combined, but core git considers this a conflict unless forced.
146 * 26 - This combines two cases (1 & 25) (and also implied 8 for tree content)
147 * which are ok on their own, but core git treat this as a conflict.
148 * If not forced, this is a conflict. If forced, this actually doesn't
149 * have to write anything and leaves the new blob as an untracked file.
7e5c8a5b 150 * 32 - This is the only case where the baseline and target values match
cf208031 151 * and yet we will still write to the working directory. In all other
7e5c8a5b 152 * cases, if baseline == target, we don't touch the workdir (it is
cf208031
RB
153 * either already right or is "dirty"). However, since this case also
154 * implies that a ?/B1/x case will exist as well, it can be skipped.
155 *
156 * Cases 3, 17, 24, 26, and 29 are all considered conflicts even though
157 * none of them will require making any updates to the working directory.
158 */
159
160/* expect desire wd
161 * 1 x x T -> ignored dir OR untracked dir OR parent dir
162 * 2 x x I -> ignored file
163 * 3 x x A -> untracked file
164 * 4 x A x -> add from index (no conflict)
165 * 5 x A A -> independently added file
166 * 6 x A B -> add with conflicting file
167 * 7 A x x -> independently deleted file
168 * 8 A x A -> delete from index (no conflict)
169 * 9 A x B -> delete of modified file
170 * 10 A A x -> locally deleted file
171 * 11 A A A -> unmodified file (no conflict)
172 * 12 A A B -> locally modified
173 * 13 A B x -> update of deleted file
174 * 14 A B A -> update of unmodified file (no conflict)
175 * 15 A B B -> independently updated file
176 * 16 A B C -> update of modified file
177 */
178
179enum {
180 CHECKOUT_ACTION__NONE = 0,
181 CHECKOUT_ACTION__REMOVE = 1,
182 CHECKOUT_ACTION__UPDATE_BLOB = 2,
183 CHECKOUT_ACTION__UPDATE_SUBMODULE = 4,
184 CHECKOUT_ACTION__CONFLICT = 8,
185 CHECKOUT_ACTION__MAX = 8,
7e5c8a5b
RB
186 CHECKOUT_ACTION__DEFER_REMOVE = 16,
187 CHECKOUT_ACTION__REMOVE_AND_UPDATE =
188 (CHECKOUT_ACTION__UPDATE_BLOB | CHECKOUT_ACTION__REMOVE),
cf208031
RB
189};
190
ad9a921b
RB
191typedef struct {
192 git_repository *repo;
193 git_diff_list *diff;
7e5c8a5b
RB
194 git_checkout_opts opts;
195 bool opts_free_baseline;
196 char *pfx;
197 git_iterator *baseline;
5cf9875a 198 git_index *index;
7e5c8a5b
RB
199 git_pool pool;
200 git_vector removes;
201 git_buf path;
9ac8b113 202 size_t workdir_len;
7e5c8a5b
RB
203 unsigned int strategy;
204 int can_symlink;
e0548c0e 205 bool reload_submodules;
9c05c17b
BS
206 size_t total_steps;
207 size_t completed_steps;
7e5c8a5b 208} checkout_data;
3aa443a9 209
cf208031 210static int checkout_notify(
7e5c8a5b 211 checkout_data *data,
cf208031
RB
212 git_checkout_notify_t why,
213 const git_diff_delta *delta,
16a666d3 214 const git_index_entry *wditem)
cf208031 215{
16a666d3 216 git_diff_file wdfile;
7e5c8a5b
RB
217 const git_diff_file *baseline = NULL, *target = NULL, *workdir = NULL;
218
219 if (!data->opts.notify_cb)
220 return 0;
221
222 if ((why & data->opts.notify_flags) == 0)
223 return 0;
224
16a666d3
RB
225 if (wditem) {
226 memset(&wdfile, 0, sizeof(wdfile));
7e5c8a5b 227
16a666d3
RB
228 git_oid_cpy(&wdfile.oid, &wditem->oid);
229 wdfile.path = wditem->path;
230 wdfile.size = wditem->file_size;
231 wdfile.flags = GIT_DIFF_FILE_VALID_OID;
232 wdfile.mode = wditem->mode;
7e5c8a5b 233
16a666d3 234 workdir = &wdfile;
7e5c8a5b
RB
235 }
236
16a666d3 237 if (delta) {
7e5c8a5b
RB
238 switch (delta->status) {
239 case GIT_DELTA_UNMODIFIED:
240 case GIT_DELTA_MODIFIED:
241 case GIT_DELTA_TYPECHANGE:
242 default:
16a666d3
RB
243 baseline = &delta->old_file;
244 target = &delta->new_file;
7e5c8a5b
RB
245 break;
246 case GIT_DELTA_ADDED:
247 case GIT_DELTA_IGNORED:
248 case GIT_DELTA_UNTRACKED:
16a666d3 249 target = &delta->new_file;
7e5c8a5b
RB
250 break;
251 case GIT_DELTA_DELETED:
16a666d3 252 baseline = &delta->old_file;
7e5c8a5b
RB
253 break;
254 }
255 }
256
257 return data->opts.notify_cb(
16a666d3
RB
258 why, delta ? delta->old_file.path : wditem->path,
259 baseline, target, workdir, data->opts.notify_payload);
cf208031
RB
260}
261
262static bool checkout_is_workdir_modified(
7e5c8a5b 263 checkout_data *data,
5cf9875a
RB
264 const git_diff_file *baseitem,
265 const git_index_entry *wditem)
cf208031
RB
266{
267 git_oid oid;
268
e0548c0e
RB
269 /* handle "modified" submodule */
270 if (wditem->mode == GIT_FILEMODE_COMMIT) {
271 git_submodule *sm;
272 unsigned int sm_status = 0;
273 const git_oid *sm_oid = NULL;
274
275 if (git_submodule_lookup(&sm, data->repo, wditem->path) < 0 ||
276 git_submodule_status(&sm_status, sm) < 0)
277 return true;
278
279 if (GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status))
280 return true;
281
282 sm_oid = git_submodule_wd_id(sm);
283 if (!sm_oid)
284 return false;
285
286 return (git_oid_cmp(&baseitem->oid, sm_oid) != 0);
287 }
288
5cf9875a
RB
289 /* depending on where base is coming from, we may or may not know
290 * the actual size of the data, so we can't rely on this shortcut.
291 */
292 if (baseitem->size && wditem->file_size != baseitem->size)
cf208031
RB
293 return true;
294
295 if (git_diff__oid_for_file(
5cf9875a
RB
296 data->repo, wditem->path, wditem->mode,
297 wditem->file_size, &oid) < 0)
cf208031
RB
298 return false;
299
7e5c8a5b
RB
300 return (git_oid_cmp(&baseitem->oid, &oid) != 0);
301}
302
303#define CHECKOUT_ACTION_IF(FLAG,YES,NO) \
304 ((data->strategy & GIT_CHECKOUT_##FLAG) ? CHECKOUT_ACTION__##YES : CHECKOUT_ACTION__##NO)
305
7e5c8a5b
RB
306static int checkout_action_common(
307 checkout_data *data,
308 int action,
cf208031 309 const git_diff_delta *delta,
7e5c8a5b
RB
310 const git_index_entry *wd)
311{
312 git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
313
314 if (action <= 0)
315 return action;
316
317 if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
318 action = (action & ~CHECKOUT_ACTION__REMOVE);
319
320 if ((action & CHECKOUT_ACTION__UPDATE_BLOB) != 0) {
321 if (S_ISGITLINK(delta->new_file.mode))
322 action = (action & ~CHECKOUT_ACTION__UPDATE_BLOB) |
323 CHECKOUT_ACTION__UPDATE_SUBMODULE;
324
325 notify = GIT_CHECKOUT_NOTIFY_UPDATED;
326 }
327
328 if ((action & CHECKOUT_ACTION__CONFLICT) != 0)
329 notify = GIT_CHECKOUT_NOTIFY_CONFLICT;
330
331 if (notify != GIT_CHECKOUT_NOTIFY_NONE &&
332 checkout_notify(data, notify, delta, wd) != 0)
333 return GIT_EUSER;
334
335 return action;
336}
337
338static int checkout_action_no_wd(
339 checkout_data *data,
340 const git_diff_delta *delta)
cf208031
RB
341{
342 int action = CHECKOUT_ACTION__NONE;
cf208031 343
7e5c8a5b
RB
344 switch (delta->status) {
345 case GIT_DELTA_UNMODIFIED: /* case 12 */
346 if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL))
347 return GIT_EUSER;
348 action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, NONE);
349 break;
350 case GIT_DELTA_ADDED: /* case 2 or 28 (and 5 but not really) */
351 case GIT_DELTA_MODIFIED: /* case 13 (and 35 but not really) */
352 action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
353 break;
354 case GIT_DELTA_TYPECHANGE: /* case 21 (B->T) and 28 (T->B)*/
355 if (delta->new_file.mode == GIT_FILEMODE_TREE)
356 action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
357 break;
358 case GIT_DELTA_DELETED: /* case 8 or 25 */
359 default: /* impossible */
360 break;
cf208031
RB
361 }
362
7e5c8a5b
RB
363 return checkout_action_common(data, action, delta, NULL);
364}
365
366static int checkout_action_wd_only(
367 checkout_data *data,
368 git_iterator *workdir,
369 const git_index_entry *wd,
370 git_vector *pathspec)
371{
5cf9875a 372 bool remove = false;
7e5c8a5b 373 git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
5cf9875a 374 const git_index_entry *entry;
7e5c8a5b
RB
375
376 if (!git_pathspec_match_path(
377 pathspec, wd->path, false, workdir->ignore_case))
378 return 0;
379
5cf9875a
RB
380 /* check if item is tracked in the index but not in the checkout diff */
381 if (data->index != NULL &&
382 (entry = git_index_get_bypath(data->index, wd->path, 0)) != NULL)
383 {
384 notify = GIT_CHECKOUT_NOTIFY_DIRTY;
385 remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0);
386 }
387 else if (git_iterator_current_is_ignored(workdir)) {
7e5c8a5b
RB
388 notify = GIT_CHECKOUT_NOTIFY_IGNORED;
389 remove = ((data->strategy & GIT_CHECKOUT_REMOVE_IGNORED) != 0);
5cf9875a
RB
390 }
391 else {
7e5c8a5b
RB
392 notify = GIT_CHECKOUT_NOTIFY_UNTRACKED;
393 remove = ((data->strategy & GIT_CHECKOUT_REMOVE_UNTRACKED) != 0);
cf208031
RB
394 }
395
7e5c8a5b
RB
396 if (checkout_notify(data, notify, NULL, wd))
397 return GIT_EUSER;
cf208031 398
7e5c8a5b
RB
399 if (remove) {
400 char *path = git_pool_strdup(&data->pool, wd->path);
401 GITERR_CHECK_ALLOC(path);
402
403 if (git_vector_insert(&data->removes, path) < 0)
404 return -1;
405 }
406
407 return 0;
408}
409
e0548c0e
RB
410static bool submodule_is_config_only(
411 checkout_data *data,
412 const char *path)
413{
414 git_submodule *sm = NULL;
415 unsigned int sm_loc = 0;
416
417 if (git_submodule_lookup(&sm, data->repo, path) < 0 ||
418 git_submodule_location(&sm_loc, sm) < 0 ||
419 sm_loc == GIT_SUBMODULE_STATUS_IN_CONFIG)
420 return true;
421
422 return false;
423}
424
7e5c8a5b
RB
425static int checkout_action_with_wd(
426 checkout_data *data,
427 const git_diff_delta *delta,
428 const git_index_entry *wd)
429{
430 int action = CHECKOUT_ACTION__NONE;
431
432 switch (delta->status) {
433 case GIT_DELTA_UNMODIFIED: /* case 14/15 or 33 */
e0548c0e 434 if (checkout_is_workdir_modified(data, &delta->old_file, wd)) {
7e5c8a5b
RB
435 if (checkout_notify(
436 data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd))
437 return GIT_EUSER;
438 action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, NONE);
cf208031 439 }
7e5c8a5b
RB
440 break;
441 case GIT_DELTA_ADDED: /* case 3, 4 or 6 */
442 action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
443 break;
444 case GIT_DELTA_DELETED: /* case 9 or 10 (or 26 but not really) */
445 if (checkout_is_workdir_modified(data, &delta->old_file, wd))
446 action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
447 else
448 action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE);
449 break;
450 case GIT_DELTA_MODIFIED: /* case 16, 17, 18 (or 36 but not really) */
451 if (checkout_is_workdir_modified(data, &delta->old_file, wd))
452 action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
453 else
454 action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
455 break;
456 case GIT_DELTA_TYPECHANGE: /* case 22, 23, 29, 30 */
e0548c0e
RB
457 if (delta->old_file.mode == GIT_FILEMODE_TREE) {
458 if (wd->mode == GIT_FILEMODE_TREE)
459 /* either deleting items in old tree will delete the wd dir,
460 * or we'll get a conflict when we attempt blob update...
461 */
462 action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
463 else if (wd->mode == GIT_FILEMODE_COMMIT) {
464 /* workdir is possibly a "phantom" submodule - treat as a
465 * tree if the only submodule info came from the config
466 */
467 if (submodule_is_config_only(data, wd->path))
468 action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
469 else
470 action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
471 } else
472 action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
473 }
7e5c8a5b
RB
474 else if (checkout_is_workdir_modified(data, &delta->old_file, wd))
475 action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
476 else
477 action = CHECKOUT_ACTION_IF(SAFE, REMOVE_AND_UPDATE, NONE);
e0548c0e
RB
478
479 /* don't update if the typechange is to a tree */
480 if (delta->new_file.mode == GIT_FILEMODE_TREE)
481 action = (action & ~CHECKOUT_ACTION__UPDATE_BLOB);
7e5c8a5b
RB
482 break;
483 default: /* impossible */
484 break;
cf208031
RB
485 }
486
7e5c8a5b
RB
487 return checkout_action_common(data, action, delta, wd);
488}
cf208031 489
7e5c8a5b
RB
490static int checkout_action_with_wd_blocker(
491 checkout_data *data,
492 const git_diff_delta *delta,
493 const git_index_entry *wd)
494{
495 int action = CHECKOUT_ACTION__NONE;
cf208031 496
7e5c8a5b
RB
497 switch (delta->status) {
498 case GIT_DELTA_UNMODIFIED:
499 /* should show delta as dirty / deleted */
500 if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd))
cf208031 501 return GIT_EUSER;
7e5c8a5b
RB
502 action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE);
503 break;
504 case GIT_DELTA_ADDED:
505 case GIT_DELTA_MODIFIED:
506 action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
507 break;
508 case GIT_DELTA_DELETED:
509 action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
510 break;
511 case GIT_DELTA_TYPECHANGE:
512 /* not 100% certain about this... */
513 action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
514 break;
515 default: /* impossible */
516 break;
cf208031
RB
517 }
518
7e5c8a5b
RB
519 return checkout_action_common(data, action, delta, wd);
520}
521
522static int checkout_action_with_wd_dir(
523 checkout_data *data,
524 const git_diff_delta *delta,
525 const git_index_entry *wd)
526{
527 int action = CHECKOUT_ACTION__NONE;
528
529 switch (delta->status) {
530 case GIT_DELTA_UNMODIFIED: /* case 19 or 24 (or 34 but not really) */
531 if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL) ||
532 checkout_notify(
533 data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd))
cf208031 534 return GIT_EUSER;
7e5c8a5b
RB
535 break;
536 case GIT_DELTA_ADDED:/* case 4 (and 7 for dir) */
537 case GIT_DELTA_MODIFIED: /* case 20 (or 37 but not really) */
e0548c0e
RB
538 if (delta->old_file.mode == GIT_FILEMODE_COMMIT)
539 /* expected submodule (and maybe found one) */;
540 else if (delta->new_file.mode != GIT_FILEMODE_TREE)
7e5c8a5b
RB
541 action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
542 break;
543 case GIT_DELTA_DELETED: /* case 11 (and 27 for dir) */
544 if (delta->old_file.mode != GIT_FILEMODE_TREE &&
545 checkout_notify(
546 data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd))
547 return GIT_EUSER;
548 break;
549 case GIT_DELTA_TYPECHANGE: /* case 24 or 31 */
7e5c8a5b 550 if (delta->old_file.mode == GIT_FILEMODE_TREE) {
e0548c0e
RB
551 /* For typechange from dir, remove dir and add blob, but it is
552 * not safe to remove dir if it contains modified files.
553 * However, safely removing child files will remove the parent
554 * directory if is it left empty, so we can defer removing the
555 * dir and it will succeed if no children are left.
556 */
7e5c8a5b
RB
557 action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
558 if (action != CHECKOUT_ACTION__NONE)
559 action |= CHECKOUT_ACTION__DEFER_REMOVE;
560 }
e0548c0e
RB
561 else if (delta->new_file.mode != GIT_FILEMODE_TREE)
562 /* For typechange to dir, dir is already created so no action */
563 action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
7e5c8a5b
RB
564 break;
565 default: /* impossible */
566 break;
cf208031
RB
567 }
568
7e5c8a5b 569 return checkout_action_common(data, action, delta, wd);
cf208031
RB
570}
571
7e5c8a5b
RB
572static int checkout_action(
573 checkout_data *data,
cf208031 574 git_diff_delta *delta,
7e5c8a5b
RB
575 git_iterator *workdir,
576 const git_index_entry **wditem_ptr,
cf208031
RB
577 git_vector *pathspec)
578{
7e5c8a5b
RB
579 const git_index_entry *wd = *wditem_ptr;
580 int cmp = -1, act;
581 int (*strcomp)(const char *, const char *) = data->diff->strcomp;
582 int (*pfxcomp)(const char *str, const char *pfx) = data->diff->pfxcomp;
583
584 /* move workdir iterator to follow along with deltas */
585
586 while (1) {
587 if (!wd)
588 return checkout_action_no_wd(data, delta);
589
590 cmp = strcomp(wd->path, delta->old_file.path);
591
592 /* 1. wd before delta ("a/a" before "a/b")
593 * 2. wd prefixes delta & should expand ("a/" before "a/b")
594 * 3. wd prefixes delta & cannot expand ("a/b" before "a/b/c")
595 * 4. wd equals delta ("a/b" and "a/b")
596 * 5. wd after delta & delta prefixes wd ("a/b/c" after "a/b/" or "a/b")
597 * 6. wd after delta ("a/c" after "a/b")
598 */
599
600 if (cmp < 0) {
601 cmp = pfxcomp(delta->old_file.path, wd->path);
602
603 if (cmp == 0) {
604 if (wd->mode == GIT_FILEMODE_TREE) {
605 /* case 2 - descend in wd */
606 if (git_iterator_advance_into_directory(workdir, &wd) < 0)
607 goto fail;
608 continue;
609 }
610
611 /* case 3 - wd contains non-dir where dir expected */
612 act = checkout_action_with_wd_blocker(data, delta, wd);
613 *wditem_ptr = git_iterator_advance(workdir, &wd) ? NULL : wd;
614 return act;
615 }
cf208031 616
7e5c8a5b
RB
617 /* case 1 - handle wd item (if it matches pathspec) */
618 if (checkout_action_wd_only(data, workdir, wd, pathspec) < 0 ||
619 git_iterator_advance(workdir, &wd) < 0)
620 goto fail;
cf208031 621
7e5c8a5b
RB
622 *wditem_ptr = wd;
623 continue;
624 }
cf208031 625
7e5c8a5b
RB
626 if (cmp == 0) {
627 /* case 4 */
628 act = checkout_action_with_wd(data, delta, wd);
629 *wditem_ptr = git_iterator_advance(workdir, &wd) ? NULL : wd;
630 return act;
631 }
cf208031 632
7e5c8a5b 633 cmp = pfxcomp(wd->path, delta->old_file.path);
cf208031 634
7e5c8a5b 635 if (cmp == 0) { /* case 5 */
e0548c0e
RB
636 size_t pathlen = strlen(delta->old_file.path);
637 if (wd->path[pathlen] != '/')
638 return checkout_action_no_wd(data, delta);
639
640 if (delta->status == GIT_DELTA_TYPECHANGE) {
641 if (delta->old_file.mode == GIT_FILEMODE_TREE) {
642 act = checkout_action_with_wd(data, delta, wd);
643 if (git_iterator_advance_into_directory(workdir, &wd) < 0)
644 wd = NULL;
645 *wditem_ptr = wd;
646 return act;
647 }
648
649 if (delta->new_file.mode == GIT_FILEMODE_TREE ||
650 delta->new_file.mode == GIT_FILEMODE_COMMIT ||
651 delta->old_file.mode == GIT_FILEMODE_COMMIT)
652 {
653 act = checkout_action_with_wd(data, delta, wd);
654 if (git_iterator_advance(workdir, &wd) < 0)
655 wd = NULL;
656 *wditem_ptr = wd;
657 return act;
658 }
cf208031 659 }
cf208031 660
7e5c8a5b
RB
661 return checkout_action_with_wd_dir(data, delta, wd);
662 }
cf208031 663
7e5c8a5b
RB
664 /* case 6 - wd is after delta */
665 return checkout_action_no_wd(data, delta);
cf208031
RB
666 }
667
7e5c8a5b
RB
668fail:
669 *wditem_ptr = NULL;
670 return -1;
cf208031
RB
671}
672
673static int checkout_get_actions(
674 uint32_t **actions_ptr,
675 size_t **counts_ptr,
7e5c8a5b
RB
676 checkout_data *data,
677 git_iterator *workdir)
cf208031
RB
678{
679 int error = 0;
cf208031
RB
680 const git_index_entry *wditem;
681 git_vector pathspec = GIT_VECTOR_INIT, *deltas;
682 git_pool pathpool = GIT_POOL_INIT_STRINGPOOL;
683 git_diff_delta *delta;
684 size_t i, *counts = NULL;
685 uint32_t *actions = NULL;
cf208031 686
7e5c8a5b
RB
687 if (data->opts.paths.count > 0 &&
688 git_pathspec_init(&pathspec, &data->opts.paths, &pathpool) < 0)
cf208031
RB
689 return -1;
690
7e5c8a5b 691 if ((error = git_iterator_current(workdir, &wditem)) < 0)
cf208031
RB
692 goto fail;
693
694 deltas = &data->diff->deltas;
695
696 *counts_ptr = counts = git__calloc(CHECKOUT_ACTION__MAX+1, sizeof(size_t));
697 *actions_ptr = actions = git__calloc(
698 deltas->length ? deltas->length : 1, sizeof(uint32_t));
699 if (!counts || !actions) {
700 error = -1;
701 goto fail;
702 }
703
704 git_vector_foreach(deltas, i, delta) {
7e5c8a5b 705 int act = checkout_action(data, delta, workdir, &wditem, &pathspec);
cf208031 706
cf208031
RB
707 if (act < 0) {
708 error = act;
709 goto fail;
710 }
711
cf208031
RB
712 actions[i] = act;
713
714 if (act & CHECKOUT_ACTION__REMOVE)
715 counts[CHECKOUT_ACTION__REMOVE]++;
716 if (act & CHECKOUT_ACTION__UPDATE_BLOB)
717 counts[CHECKOUT_ACTION__UPDATE_BLOB]++;
718 if (act & CHECKOUT_ACTION__UPDATE_SUBMODULE)
719 counts[CHECKOUT_ACTION__UPDATE_SUBMODULE]++;
720 if (act & CHECKOUT_ACTION__CONFLICT)
721 counts[CHECKOUT_ACTION__CONFLICT]++;
722 }
723
16a666d3
RB
724 while (wditem != NULL) {
725 error = checkout_action_wd_only(data, workdir, wditem, &pathspec);
726 if (!error)
727 error = git_iterator_advance(workdir, &wditem);
728 if (error < 0)
729 goto fail;
730 }
731
7e5c8a5b
RB
732 counts[CHECKOUT_ACTION__REMOVE] += data->removes.length;
733
734 if (counts[CHECKOUT_ACTION__CONFLICT] > 0 &&
735 (data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) == 0)
736 {
cf208031
RB
737 giterr_set(GITERR_CHECKOUT, "%d conflicts prevent checkout",
738 (int)counts[CHECKOUT_ACTION__CONFLICT]);
739 error = -1;
740 goto fail;
741 }
742
cf208031
RB
743 git_pathspec_free(&pathspec);
744 git_pool_clear(&pathpool);
745
746 return 0;
747
748fail:
749 *counts_ptr = NULL;
750 git__free(counts);
751 *actions_ptr = NULL;
752 git__free(actions);
753
cf208031
RB
754 git_pathspec_free(&pathspec);
755 git_pool_clear(&pathpool);
756
757 return error;
758}
759
3aa443a9 760static int buffer_to_file(
5cf9875a 761 struct stat *st,
3aa443a9 762 git_buf *buffer,
763 const char *path,
28abf3db 764 mode_t dir_mode,
3aa443a9 765 int file_open_flags,
766 mode_t file_mode)
767{
32def5af 768 int fd, error;
ec532d5e 769
0d64bef9
RB
770 if ((error = git_futils_mkpath2file(path, dir_mode)) < 0)
771 return error;
ec532d5e 772
32def5af
RB
773 if ((fd = p_open(path, file_open_flags, file_mode)) < 0) {
774 giterr_set(GITERR_OS, "Could not open '%s' for writing", path);
0d64bef9 775 return fd;
32def5af 776 }
0d64bef9 777
32def5af
RB
778 if ((error = p_write(fd, git_buf_cstr(buffer), git_buf_len(buffer))) < 0) {
779 giterr_set(GITERR_OS, "Could not write to '%s'", path);
780 (void)p_close(fd);
781 } else {
5cf9875a
RB
782 if ((error = p_fstat(fd, st)) < 0)
783 giterr_set(GITERR_OS, "Error while statting '%s'", path);
784
32def5af
RB
785 if ((error = p_close(fd)) < 0)
786 giterr_set(GITERR_OS, "Error while closing '%s'", path);
787 }
0d64bef9
RB
788
789 if (!error &&
790 (file_mode & 0100) != 0 &&
791 (error = p_chmod(path, file_mode)) < 0)
792 giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
793
794 return error;
1d68fcd0
BS
795}
796
3aa443a9 797static int blob_content_to_file(
5cf9875a 798 struct stat *st,
3aa443a9 799 git_blob *blob,
800 const char *path,
28abf3db 801 mode_t entry_filemode,
3aa443a9 802 git_checkout_opts *opts)
dc1b0909 803{
d75074f4 804 int error = -1, nb_filters = 0;
28abf3db 805 mode_t file_mode = opts->file_mode;
5e4cb4f4 806 bool dont_free_filtered = false;
807 git_buf unfiltered = GIT_BUF_INIT, filtered = GIT_BUF_INIT;
808 git_vector filters = GIT_VECTOR_INIT;
6eb240b0 809
5e4cb4f4 810 if (opts->disable_filters ||
811 (nb_filters = git_filters_load(
812 &filters,
813 git_object_owner((git_object *)blob),
814 path,
815 GIT_FILTER_TO_WORKTREE)) == 0) {
816
817 /* Create a fake git_buf from the blob raw data... */
818 filtered.ptr = blob->odb_object->raw.data;
819 filtered.size = blob->odb_object->raw.len;
820
821 /* ... and make sure it doesn't get unexpectedly freed */
822 dont_free_filtered = true;
823 }
824
825 if (nb_filters < 0)
826 return nb_filters;
3aa443a9 827
5e4cb4f4 828 if (nb_filters > 0) {
fade21db 829 if ((error = git_blob__getbuf(&unfiltered, blob)) < 0)
5e4cb4f4 830 goto cleanup;
831
832 if ((error = git_filters_apply(&filtered, &unfiltered, &filters)) < 0)
833 goto cleanup;
834 }
095ccc01 835
8e4aae1a
BS
836 /* Allow overriding of file mode */
837 if (!file_mode)
3aa443a9 838 file_mode = entry_filemode;
8e4aae1a 839
ad9a921b 840 error = buffer_to_file(
5cf9875a
RB
841 st, &filtered, path, opts->dir_mode, opts->file_open_flags, file_mode);
842
843 if (!error) {
844 st->st_size = blob->odb_object->raw.len;
845 st->st_mode = entry_filemode;
846 }
095ccc01 847
3aa443a9 848cleanup:
5e4cb4f4 849 git_filters_free(&filters);
850 git_buf_free(&unfiltered);
851 if (!dont_free_filtered)
852 git_buf_free(&filtered);
853
854 return error;
3aa443a9 855}
856
ad9a921b 857static int blob_content_to_link(
5cf9875a 858 struct stat *st, git_blob *blob, const char *path, int can_symlink)
3aa443a9 859{
860 git_buf linktarget = GIT_BUF_INIT;
861 int error;
6eb240b0 862
fade21db
RB
863 if ((error = git_blob__getbuf(&linktarget, blob)) < 0)
864 return error;
3aa443a9 865
5cf9875a
RB
866 if (can_symlink) {
867 if ((error = p_symlink(git_buf_cstr(&linktarget), path)) < 0)
868 giterr_set(GITERR_CHECKOUT, "Could not create symlink %s\n", path);
869 } else {
3aa443a9 870 error = git_futils_fake_symlink(git_buf_cstr(&linktarget), path);
5cf9875a
RB
871 }
872
873 if (!error) {
874 if ((error = p_lstat(path, st)) < 0)
875 giterr_set(GITERR_CHECKOUT, "Could not stat symlink %s", path);
876
877 st->st_mode = GIT_FILEMODE_LINK;
878 }
4a26ee4f 879
3aa443a9 880 git_buf_free(&linktarget);
881
882 return error;
24b0d3d5
BS
883}
884
5cf9875a
RB
885static int checkout_update_index(
886 checkout_data *data,
887 const git_diff_file *file,
888 struct stat *st)
889{
890 git_index_entry entry;
891
892 if (!data->index)
893 return 0;
894
895 memset(&entry, 0, sizeof(entry));
896 entry.path = (char *)file->path; /* cast to prevent warning */
897 git_index_entry__init_from_stat(&entry, st);
898 git_oid_cpy(&entry.oid, &file->oid);
899
900 return git_index_add(data->index, &entry);
901}
902
0d64bef9 903static int checkout_submodule(
7e5c8a5b 904 checkout_data *data,
0d64bef9
RB
905 const git_diff_file *file)
906{
5cf9875a 907 int error = 0;
e0548c0e 908 git_submodule *sm;
5cf9875a 909
ad9a921b 910 /* Until submodules are supported, UPDATE_ONLY means do nothing here */
7e5c8a5b 911 if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
ad9a921b
RB
912 return 0;
913
5cf9875a 914 if ((error = git_futils_mkdir(
ad9a921b 915 file->path, git_repository_workdir(data->repo),
5cf9875a
RB
916 data->opts.dir_mode, GIT_MKDIR_PATH)) < 0)
917 return error;
0d64bef9 918
e0548c0e
RB
919 if ((error = git_submodule_lookup(&sm, data->repo, file->path)) < 0)
920 return error;
921
ad9a921b 922 /* TODO: Support checkout_strategy options. Two circumstances:
0d64bef9
RB
923 * 1 - submodule already checked out, but we need to move the HEAD
924 * to the new OID, or
925 * 2 - submodule not checked out and we should recursively check it out
926 *
ad9a921b
RB
927 * Checkout will not execute a pull on the submodule, but a clone
928 * command should probably be able to. Do we need a submodule callback?
0d64bef9
RB
929 */
930
5cf9875a
RB
931 /* update the index unless prevented */
932 if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0) {
933 struct stat st;
934
935 git_buf_truncate(&data->path, data->workdir_len);
936 if (git_buf_puts(&data->path, file->path) < 0)
937 return -1;
938
939 if ((error = p_stat(git_buf_cstr(&data->path), &st)) < 0) {
940 giterr_set(
941 GITERR_CHECKOUT, "Could not stat submodule %s\n", file->path);
942 return error;
943 }
944
945 st.st_mode = GIT_FILEMODE_COMMIT;
946
947 error = checkout_update_index(data, file, &st);
948 }
949
950 return error;
0d64bef9
RB
951}
952
45b60d7b 953static void report_progress(
7e5c8a5b 954 checkout_data *data,
32def5af 955 const char *path)
45b60d7b 956{
7e5c8a5b
RB
957 if (data->opts.progress_cb)
958 data->opts.progress_cb(
ad9a921b 959 path, data->completed_steps, data->total_steps,
7e5c8a5b 960 data->opts.progress_payload);
45b60d7b
BS
961}
962
3aa443a9 963static int checkout_blob(
7e5c8a5b 964 checkout_data *data,
9c05c17b 965 const git_diff_file *file)
ec532d5e 966{
32def5af 967 int error = 0;
ad9a921b 968 git_blob *blob;
5cf9875a 969 struct stat st;
1d68fcd0 970
7e5c8a5b
RB
971 git_buf_truncate(&data->path, data->workdir_len);
972 if (git_buf_puts(&data->path, file->path) < 0)
0d64bef9 973 return -1;
3aa443a9 974
ad9a921b 975 if ((error = git_blob_lookup(&blob, data->repo, &file->oid)) < 0)
0d64bef9
RB
976 return error;
977
978 if (S_ISLNK(file->mode))
979 error = blob_content_to_link(
5cf9875a 980 &st, blob, git_buf_cstr(&data->path), data->can_symlink);
3aa443a9 981 else
0d64bef9 982 error = blob_content_to_file(
5cf9875a 983 &st, blob, git_buf_cstr(&data->path), file->mode, &data->opts);
3aa443a9 984
985 git_blob_free(blob);
986
7e5c8a5b
RB
987 /* if we try to create the blob and an existing directory blocks it from
988 * being written, then there must have been a typechange conflict in a
989 * parent directory - suppress the error and try to continue.
990 */
991 if ((data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) != 0 &&
992 (error == GIT_ENOTFOUND || error == GIT_EEXISTS))
993 {
994 giterr_clear();
995 error = 0;
996 }
997
5cf9875a
RB
998 /* update the index unless prevented */
999 if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
1000 error = checkout_update_index(data, file, &st);
1001
e0548c0e
RB
1002 /* update the submodule data if this was a new .gitmodules file */
1003 if (!error && strcmp(file->path, ".gitmodules") == 0)
1004 data->reload_submodules = true;
1005
3aa443a9 1006 return error;
1007}
1008
32def5af 1009static int checkout_remove_the_old(
32def5af 1010 unsigned int *actions,
7e5c8a5b 1011 checkout_data *data)
32def5af 1012{
cf208031 1013 int error = 0;
32def5af 1014 git_diff_delta *delta;
7e5c8a5b 1015 const char *str;
32def5af 1016 size_t i;
7e5c8a5b
RB
1017 const char *workdir = git_buf_cstr(&data->path);
1018 uint32_t flg = GIT_RMDIR_EMPTY_PARENTS |
1019 GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS;
32def5af 1020
7e5c8a5b 1021 git_buf_truncate(&data->path, data->workdir_len);
ad9a921b 1022
cf208031 1023 git_vector_foreach(&data->diff->deltas, i, delta) {
32def5af 1024 if (actions[i] & CHECKOUT_ACTION__REMOVE) {
cf208031 1025 error = git_futils_rmdir_r(delta->old_file.path, workdir, flg);
7e5c8a5b 1026 if (error < 0)
32def5af
RB
1027 return error;
1028
1029 data->completed_steps++;
cf208031 1030 report_progress(data, delta->old_file.path);
5cf9875a
RB
1031
1032 if ((actions[i] & CHECKOUT_ACTION__UPDATE_BLOB) == 0 &&
1033 (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 &&
1034 data->index != NULL)
1035 {
1036 (void)git_index_remove(data->index, delta->old_file.path, 0);
1037 }
32def5af
RB
1038 }
1039 }
1040
7e5c8a5b
RB
1041 git_vector_foreach(&data->removes, i, str) {
1042 error = git_futils_rmdir_r(str, workdir, flg);
1043 if (error < 0)
1044 return error;
1045
1046 data->completed_steps++;
1047 report_progress(data, str);
5cf9875a
RB
1048
1049 if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 &&
1050 data->index != NULL)
1051 {
1052 (void)git_index_remove(data->index, str, 0);
1053 }
7e5c8a5b
RB
1054 }
1055
1056 return 0;
1057}
1058
1059static int checkout_deferred_remove(git_repository *repo, const char *path)
1060{
1061#if 0
1062 int error = git_futils_rmdir_r(
1063 path, git_repository_workdir(repo), GIT_RMDIR_EMPTY_PARENTS);
1064
1065 if (error == GIT_ENOTFOUND) {
1066 error = 0;
1067 giterr_clear();
1068 }
1069
1070 return error;
1071#else
1072 GIT_UNUSED(repo);
1073 GIT_UNUSED(path);
5cf9875a 1074 assert(false);
32def5af 1075 return 0;
7e5c8a5b 1076#endif
32def5af
RB
1077}
1078
1079static int checkout_create_the_new(
32def5af 1080 unsigned int *actions,
7e5c8a5b 1081 checkout_data *data)
32def5af 1082{
7e5c8a5b 1083 int error = 0;
32def5af
RB
1084 git_diff_delta *delta;
1085 size_t i;
1086
cf208031 1087 git_vector_foreach(&data->diff->deltas, i, delta) {
7e5c8a5b
RB
1088 if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) {
1089 /* this had a blocker directory that should only be removed iff
1090 * all of the contents of the directory were safely removed
1091 */
1092 if ((error = checkout_deferred_remove(
1093 data->repo, delta->old_file.path)) < 0)
1094 return error;
1095 }
1096
ad9a921b 1097 if (actions[i] & CHECKOUT_ACTION__UPDATE_BLOB) {
7e5c8a5b 1098 error = checkout_blob(data, &delta->new_file);
ad9a921b 1099 if (error < 0)
32def5af
RB
1100 return error;
1101
1102 data->completed_steps++;
cf208031 1103 report_progress(data, delta->new_file.path);
32def5af 1104 }
32def5af
RB
1105 }
1106
1107 return 0;
1108}
1109
1110static int checkout_create_submodules(
32def5af 1111 unsigned int *actions,
7e5c8a5b 1112 checkout_data *data)
32def5af 1113{
7e5c8a5b 1114 int error = 0;
32def5af
RB
1115 git_diff_delta *delta;
1116 size_t i;
1117
e0548c0e
RB
1118 /* initial reload of submodules if .gitmodules was changed */
1119 if (data->reload_submodules &&
1120 (error = git_submodule_reload_all(data->repo)) < 0)
1121 return error;
1122
cf208031 1123 git_vector_foreach(&data->diff->deltas, i, delta) {
7e5c8a5b
RB
1124 if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) {
1125 /* this has a blocker directory that should only be removed iff
1126 * all of the contents of the directory were safely removed
1127 */
1128 if ((error = checkout_deferred_remove(
1129 data->repo, delta->old_file.path)) < 0)
1130 return error;
1131 }
1132
ad9a921b 1133 if (actions[i] & CHECKOUT_ACTION__UPDATE_SUBMODULE) {
cf208031 1134 int error = checkout_submodule(data, &delta->new_file);
32def5af
RB
1135 if (error < 0)
1136 return error;
1137
1138 data->completed_steps++;
cf208031 1139 report_progress(data, delta->new_file.path);
32def5af
RB
1140 }
1141 }
1142
e0548c0e
RB
1143 /* final reload once submodules have been updated */
1144 return git_submodule_reload_all(data->repo);
32def5af
RB
1145}
1146
7e5c8a5b
RB
1147static int checkout_lookup_head_tree(git_tree **out, git_repository *repo)
1148{
1149 int error = 0;
1150 git_reference *ref = NULL;
1151 git_object *head;
1152
1153 if (!(error = git_repository_head(&ref, repo)) &&
1154 !(error = git_reference_peel(&head, ref, GIT_OBJ_TREE)))
1155 *out = (git_tree *)head;
1156
1157 git_reference_free(ref);
1158
1159 return error;
1160}
1161
1162static void checkout_data_clear(checkout_data *data)
1163{
1164 if (data->opts_free_baseline) {
1165 git_tree_free(data->opts.baseline);
1166 data->opts.baseline = NULL;
1167 }
1168
1169 git_vector_free(&data->removes);
1170 git_pool_clear(&data->pool);
1171
1172 git__free(data->pfx);
1173 data->pfx = NULL;
1174
1175 git_buf_free(&data->path);
5cf9875a
RB
1176
1177 git_index_free(data->index);
1178 data->index = NULL;
7e5c8a5b
RB
1179}
1180
1181static int checkout_data_init(
1182 checkout_data *data,
5cf9875a 1183 git_iterator *target,
7e5c8a5b 1184 git_checkout_opts *proposed)
3aa443a9 1185{
7e5c8a5b 1186 int error = 0;
cf208031 1187 git_config *cfg;
5cf9875a 1188 git_repository *repo = git_iterator_owner(target);
cf208031 1189
7e5c8a5b
RB
1190 memset(data, 0, sizeof(*data));
1191
1192 if (!repo) {
1193 giterr_set(GITERR_CHECKOUT, "Cannot checkout nothing");
cf208031 1194 return -1;
7e5c8a5b 1195 }
cf208031 1196
7e5c8a5b
RB
1197 if ((error = git_repository__ensure_not_bare(repo, "checkout")) < 0)
1198 return error;
cf208031 1199
7e5c8a5b
RB
1200 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
1201 return error;
1202
1203 data->repo = repo;
1204
1205 GITERR_CHECK_VERSION(
1206 proposed, GIT_CHECKOUT_OPTS_VERSION, "git_checkout_opts");
1207
1208 if (!proposed)
1209 GIT_INIT_STRUCTURE(&data->opts, GIT_CHECKOUT_OPTS_VERSION);
1210 else
1211 memmove(&data->opts, proposed, sizeof(git_checkout_opts));
1212
5cf9875a
RB
1213 /* refresh config and index content unless NO_REFRESH is given */
1214 if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) {
1215 if ((error = git_config_refresh(cfg)) < 0)
1216 goto cleanup;
1217
1218 if (git_iterator_inner_type(target) == GIT_ITERATOR_INDEX) {
1219 /* if we are iterating over the index, don't reload */
1220 data->index = git_iterator_index_get_index(target);
1221 GIT_REFCOUNT_INC(data->index);
1222 } else {
1223 /* otherwise, grab and reload the index */
1224 if ((error = git_repository_index(&data->index, data->repo)) < 0 ||
1225 (error = git_index_read(data->index)) < 0)
1226 goto cleanup;
1227 }
1228 }
7e5c8a5b 1229
5cf9875a 1230 /* if you are forcing, definitely allow safe updates */
7e5c8a5b
RB
1231 if ((data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) != 0)
1232 data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE_CREATE;
1233 if ((data->opts.checkout_strategy & GIT_CHECKOUT_SAFE_CREATE) != 0)
1234 data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE;
1235
1236 data->strategy = data->opts.checkout_strategy;
1237
1238 /* opts->disable_filters is false by default */
1239
1240 if (!data->opts.dir_mode)
1241 data->opts.dir_mode = GIT_DIR_MODE;
1242
1243 if (!data->opts.file_open_flags)
1244 data->opts.file_open_flags = O_CREAT | O_TRUNC | O_WRONLY;
1245
1246 data->pfx = git_pathspec_prefix(&data->opts.paths);
1247
1248 error = git_config_get_bool(&data->can_symlink, cfg, "core.symlinks");
1249 if (error < 0) {
1250 if (error != GIT_ENOTFOUND)
1251 goto cleanup;
1252
1253 /* If "core.symlinks" is not found anywhere, default to true. */
1254 data->can_symlink = true;
1255 giterr_clear();
cf208031
RB
1256 error = 0;
1257 }
1258
7e5c8a5b
RB
1259 if (!data->opts.baseline) {
1260 data->opts_free_baseline = true;
1261 if ((error = checkout_lookup_head_tree(&data->opts.baseline, repo)) < 0)
1262 goto cleanup;
1263 }
1264
1265 if ((error = git_vector_init(&data->removes, 0, git__strcmp_cb)) < 0 ||
1266 (error = git_pool_init(&data->pool, 1, 0)) < 0 ||
1267 (error = git_buf_puts(&data->path, git_repository_workdir(repo))) < 0)
1268 goto cleanup;
1269
1270 data->workdir_len = git_buf_len(&data->path);
1271
1272cleanup:
1273 if (error < 0)
1274 checkout_data_clear(data);
cf208031
RB
1275
1276 return error;
1277}
1278
7e5c8a5b
RB
1279int git_checkout_iterator(
1280 git_iterator *target,
1281 git_checkout_opts *opts)
cf208031
RB
1282{
1283 int error = 0;
7e5c8a5b
RB
1284 git_iterator *baseline = NULL, *workdir = NULL;
1285 checkout_data data = {0};
cf208031 1286 git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
32def5af
RB
1287 uint32_t *actions = NULL;
1288 size_t *counts = NULL;
3aa443a9 1289
7e5c8a5b 1290 /* initialize structures and options */
5cf9875a 1291 error = checkout_data_init(&data, target, opts);
7e5c8a5b
RB
1292 if (error < 0)
1293 return error;
c7231c45 1294
7e5c8a5b
RB
1295 diff_opts.flags =
1296 GIT_DIFF_INCLUDE_UNMODIFIED |
1297 GIT_DIFF_INCLUDE_UNTRACKED |
1298 GIT_DIFF_RECURSE_UNTRACKED_DIRS | /* needed to match baseline */
1299 GIT_DIFF_INCLUDE_IGNORED |
1300 GIT_DIFF_INCLUDE_TYPECHANGE |
1301 GIT_DIFF_INCLUDE_TYPECHANGE_TREES |
1302 GIT_DIFF_SKIP_BINARY_CHECK;
1303 if (data.opts.paths.count > 0)
1304 diff_opts.pathspec = data.opts.paths;
1305
1306 /* set up iterators */
1307 if ((error = git_iterator_reset(target, data.pfx, data.pfx)) < 0 ||
1308 (error = git_iterator_for_workdir_range(
1309 &workdir, data.repo, data.pfx, data.pfx)) < 0 ||
1310 (error = git_iterator_for_tree_range(
1311 &baseline, data.opts.baseline, data.pfx, data.pfx)) < 0)
1312 goto cleanup;
1313
1314 /* Handle case insensitivity for baseline if necessary */
1315 if (workdir->ignore_case && !baseline->ignore_case) {
546d65a8 1316 if ((error = git_iterator_spoolandsort_push(baseline, true)) < 0)
7e5c8a5b 1317 goto cleanup;
cf208031 1318 }
3aa443a9 1319
7e5c8a5b
RB
1320 /* Checkout can be driven either off a target-to-workdir diff or a
1321 * baseline-to-target diff. There are pros and cons of each.
1322 *
1323 * Target-to-workdir means the diff includes every file that could be
1324 * modified, which simplifies bookkeeping, but the code to constantly
1325 * refer back to the baseline gets complicated.
1326 *
1327 * Baseline-to-target has simpler code because the diff defines the
1328 * action to take, but needs special handling for untracked and ignored
1329 * files, if they need to be removed.
1330 *
1331 * I've implemented both versions and opted for the second.
cf208031
RB
1332 */
1333 if ((error = git_diff__from_iterators(
7e5c8a5b 1334 &data.diff, data.repo, baseline, target, &diff_opts)) < 0)
3aa443a9 1335 goto cleanup;
1336
cf208031
RB
1337 /* In order to detect conflicts prior to performing any operations,
1338 * and in order to deal with some order dependencies, checkout is best
1339 * performed with up to four passes through the diff.
32def5af 1340 *
cf208031
RB
1341 * 0. Figure out the actions to be taken,
1342 * 1. Remove any files / directories as needed (because alphabetical
1343 * iteration means that an untracked directory will end up sorted
1344 * *after* a blob that should be checked out with the same name),
1345 * 2. Then update all blobs,
1346 * 3. Then update all submodules in case a new .gitmodules blob was
32def5af
RB
1347 * checked out during pass #2.
1348 */
7e5c8a5b 1349 if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) < 0)
ad9a921b
RB
1350 goto cleanup;
1351
32def5af 1352 data.total_steps = counts[CHECKOUT_ACTION__REMOVE] +
ad9a921b
RB
1353 counts[CHECKOUT_ACTION__UPDATE_BLOB] +
1354 counts[CHECKOUT_ACTION__UPDATE_SUBMODULE];
3aa443a9 1355
ad9a921b 1356 report_progress(&data, NULL); /* establish 0 baseline */
45b60d7b 1357
cf208031
RB
1358 /* TODO: add ability to update index entries while checking out */
1359
32def5af 1360 if (counts[CHECKOUT_ACTION__REMOVE] > 0 &&
cf208031 1361 (error = checkout_remove_the_old(actions, &data)) < 0)
32def5af
RB
1362 goto cleanup;
1363
ad9a921b 1364 if (counts[CHECKOUT_ACTION__UPDATE_BLOB] > 0 &&
cf208031 1365 (error = checkout_create_the_new(actions, &data)) < 0)
32def5af
RB
1366 goto cleanup;
1367
ad9a921b 1368 if (counts[CHECKOUT_ACTION__UPDATE_SUBMODULE] > 0 &&
cf208031 1369 (error = checkout_create_submodules(actions, &data)) < 0)
32def5af
RB
1370 goto cleanup;
1371
1372 assert(data.completed_steps == data.total_steps);
3aa443a9 1373
0d64bef9 1374cleanup:
fade21db 1375 if (error == GIT_EUSER)
32def5af 1376 giterr_clear();
fade21db 1377
5cf9875a
RB
1378 if (!error && data.index != NULL &&
1379 (data.strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
1380 error = git_index_write(data.index);
1381
cf208031 1382 git_diff_list_free(data.diff);
7e5c8a5b
RB
1383 git_iterator_free(workdir);
1384 git_iterator_free(data.baseline);
32def5af
RB
1385 git__free(actions);
1386 git__free(counts);
7e5c8a5b 1387 checkout_data_clear(&data);
cf208031
RB
1388
1389 return error;
1390}
1391
cf208031
RB
1392int git_checkout_index(
1393 git_repository *repo,
1394 git_index *index,
1395 git_checkout_opts *opts)
1396{
1397 int error;
7e5c8a5b 1398 git_iterator *index_i;
cf208031
RB
1399
1400 if ((error = git_repository__ensure_not_bare(repo, "checkout index")) < 0)
1401 return error;
1402
1403 if (!index && (error = git_repository_index__weakptr(&index, repo)) < 0)
1404 return error;
7e5c8a5b 1405 GIT_REFCOUNT_INC(index);
cf208031 1406
7e5c8a5b
RB
1407 if (!(error = git_iterator_for_index(&index_i, index)))
1408 error = git_checkout_iterator(index_i, opts);
cf208031 1409
cf208031 1410 git_iterator_free(index_i);
7e5c8a5b 1411 git_index_free(index);
0d64bef9 1412
e93af304 1413 return error;
1414}
1415
1416int git_checkout_tree(
1417 git_repository *repo,
cfbe4be3 1418 const git_object *treeish,
80642656 1419 git_checkout_opts *opts)
e93af304 1420{
cf208031 1421 int error;
7e5c8a5b
RB
1422 git_tree *tree = NULL;
1423 git_iterator *tree_i = NULL;
cf208031
RB
1424
1425 if ((error = git_repository__ensure_not_bare(repo, "checkout tree")) < 0)
1426 return error;
e93af304 1427
1428 if (git_object_peel((git_object **)&tree, treeish, GIT_OBJ_TREE) < 0) {
ad9a921b
RB
1429 giterr_set(
1430 GITERR_CHECKOUT, "Provided object cannot be peeled to a tree");
1431 return -1;
e93af304 1432 }
1433
7e5c8a5b
RB
1434 if (!(error = git_iterator_for_tree(&tree_i, tree)))
1435 error = git_checkout_iterator(tree_i, opts);
e93af304 1436
cf208031 1437 git_iterator_free(tree_i);
3aa443a9 1438 git_tree_free(tree);
ad9a921b 1439
3aa443a9 1440 return error;
14741d62
BS
1441}
1442
3aa443a9 1443int git_checkout_head(
1444 git_repository *repo,
80642656 1445 git_checkout_opts *opts)
3aa443a9 1446{
1447 int error;
7e5c8a5b
RB
1448 git_tree *head = NULL;
1449 git_iterator *head_i = NULL;
3aa443a9 1450
cf208031
RB
1451 if ((error = git_repository__ensure_not_bare(repo, "checkout head")) < 0)
1452 return error;
1453
7e5c8a5b
RB
1454 if (!(error = checkout_lookup_head_tree(&head, repo)) &&
1455 !(error = git_iterator_for_tree(&head_i, head)))
1456 error = git_checkout_iterator(head_i, opts);
cf208031 1457
7e5c8a5b 1458 git_iterator_free(head_i);
cf208031 1459 git_tree_free(head);
14741d62 1460
3aa443a9 1461 return error;
1462}