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