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