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