2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
12 #include "git2/repository.h"
13 #include "git2/refs.h"
14 #include "git2/tree.h"
15 #include "git2/blob.h"
16 #include "git2/config.h"
17 #include "git2/diff.h"
18 #include "git2/submodule.h"
19 #include "git2/sys/index.h"
20 #include "git2/sys/filter.h"
21 #include "git2/merge.h"
24 #include "repository.h"
31 #include "diff_xdiff.h"
39 /* See docs/checkout-internals.md for more information */
42 CHECKOUT_ACTION__NONE
= 0,
43 CHECKOUT_ACTION__REMOVE
= 1,
44 CHECKOUT_ACTION__UPDATE_BLOB
= 2,
45 CHECKOUT_ACTION__UPDATE_SUBMODULE
= 4,
46 CHECKOUT_ACTION__CONFLICT
= 8,
47 CHECKOUT_ACTION__REMOVE_CONFLICT
= 16,
48 CHECKOUT_ACTION__UPDATE_CONFLICT
= 32,
49 CHECKOUT_ACTION__MAX
= 32,
50 CHECKOUT_ACTION__DEFER_REMOVE
= 64,
51 CHECKOUT_ACTION__REMOVE_AND_UPDATE
=
52 (CHECKOUT_ACTION__UPDATE_BLOB
| CHECKOUT_ACTION__REMOVE
),
59 git_checkout_options opts
;
60 bool opts_free_baseline
;
65 git_vector remove_conflicts
;
66 git_vector update_conflicts
;
67 git_vector
*update_reuc
;
68 git_vector
*update_names
;
72 unsigned int strategy
;
74 bool reload_submodules
;
76 size_t completed_steps
;
77 git_checkout_perfdata perfdata
;
78 git_strmap
*mkdir_map
;
79 git_attr_session attr_session
;
83 const git_index_entry
*ancestor
;
84 const git_index_entry
*ours
;
85 const git_index_entry
*theirs
;
92 } checkout_conflictdata
;
94 static int checkout_notify(
96 git_checkout_notify_t why
,
97 const git_diff_delta
*delta
,
98 const git_index_entry
*wditem
)
100 git_diff_file wdfile
;
101 const git_diff_file
*baseline
= NULL
, *target
= NULL
, *workdir
= NULL
;
102 const char *path
= NULL
;
104 if (!data
->opts
.notify_cb
||
105 (why
& data
->opts
.notify_flags
) == 0)
109 memset(&wdfile
, 0, sizeof(wdfile
));
111 git_oid_cpy(&wdfile
.id
, &wditem
->id
);
112 wdfile
.path
= wditem
->path
;
113 wdfile
.size
= wditem
->file_size
;
114 wdfile
.flags
= GIT_DIFF_FLAG_VALID_ID
;
115 wdfile
.mode
= wditem
->mode
;
123 switch (delta
->status
) {
124 case GIT_DELTA_UNMODIFIED
:
125 case GIT_DELTA_MODIFIED
:
126 case GIT_DELTA_TYPECHANGE
:
128 baseline
= &delta
->old_file
;
129 target
= &delta
->new_file
;
131 case GIT_DELTA_ADDED
:
132 case GIT_DELTA_IGNORED
:
133 case GIT_DELTA_UNTRACKED
:
134 case GIT_DELTA_UNREADABLE
:
135 target
= &delta
->new_file
;
137 case GIT_DELTA_DELETED
:
138 baseline
= &delta
->old_file
;
142 path
= delta
->old_file
.path
;
146 int error
= data
->opts
.notify_cb(
147 why
, path
, baseline
, target
, workdir
, data
->opts
.notify_payload
);
149 return giterr_set_after_callback_function(
150 error
, "git_checkout notification");
154 GIT_INLINE(bool) is_workdir_base_or_new(
155 const git_oid
*workdir_id
,
156 const git_diff_file
*baseitem
,
157 const git_diff_file
*newitem
)
159 return (git_oid__cmp(&baseitem
->id
, workdir_id
) == 0 ||
160 git_oid__cmp(&newitem
->id
, workdir_id
) == 0);
163 static bool checkout_is_workdir_modified(
165 const git_diff_file
*baseitem
,
166 const git_diff_file
*newitem
,
167 const git_index_entry
*wditem
)
170 const git_index_entry
*ie
;
172 /* handle "modified" submodule */
173 if (wditem
->mode
== GIT_FILEMODE_COMMIT
) {
175 unsigned int sm_status
= 0;
176 const git_oid
*sm_oid
= NULL
;
179 if (git_submodule_lookup(&sm
, data
->repo
, wditem
->path
) < 0) {
184 if (git_submodule_status(&sm_status
, data
->repo
, wditem
->path
, GIT_SUBMODULE_IGNORE_UNSPECIFIED
) < 0 ||
185 GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status
))
187 else if ((sm_oid
= git_submodule_wd_id(sm
)) == NULL
)
190 rval
= (git_oid__cmp(&baseitem
->id
, sm_oid
) != 0);
192 git_submodule_free(sm
);
196 /* Look at the cache to decide if the workdir is modified. If not,
197 * we can simply compare the oid in the cache to the baseitem instead
198 * of hashing the file. If so, we allow the checkout to proceed if the
199 * oid is identical (ie, the staged item is what we're trying to check
202 if ((ie
= git_index_get_bypath(data
->index
, wditem
->path
, 0)) != NULL
) {
203 if (git_index_time_eq(&wditem
->mtime
, &ie
->mtime
) &&
204 wditem
->file_size
== ie
->file_size
)
205 return !is_workdir_base_or_new(&ie
->id
, baseitem
, newitem
);
208 /* depending on where base is coming from, we may or may not know
209 * the actual size of the data, so we can't rely on this shortcut.
211 if (baseitem
->size
&& wditem
->file_size
!= baseitem
->size
)
214 if (git_diff__oid_for_entry(&oid
, data
->diff
, wditem
, wditem
->mode
, NULL
) < 0)
217 /* Allow the checkout if the workdir is not modified *or* if the checkout
218 * target's contents are already in the working directory.
220 return !is_workdir_base_or_new(&oid
, baseitem
, newitem
);
223 #define CHECKOUT_ACTION_IF(FLAG,YES,NO) \
224 ((data->strategy & GIT_CHECKOUT_##FLAG) ? CHECKOUT_ACTION__##YES : CHECKOUT_ACTION__##NO)
226 static int checkout_action_common(
229 const git_diff_delta
*delta
,
230 const git_index_entry
*wd
)
232 git_checkout_notify_t notify
= GIT_CHECKOUT_NOTIFY_NONE
;
234 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0)
235 *action
= (*action
& ~CHECKOUT_ACTION__REMOVE
);
237 if ((*action
& CHECKOUT_ACTION__UPDATE_BLOB
) != 0) {
238 if (S_ISGITLINK(delta
->new_file
.mode
))
239 *action
= (*action
& ~CHECKOUT_ACTION__UPDATE_BLOB
) |
240 CHECKOUT_ACTION__UPDATE_SUBMODULE
;
242 /* to "update" a symlink, we must remove the old one first */
243 if (delta
->new_file
.mode
== GIT_FILEMODE_LINK
&& wd
!= NULL
)
244 *action
|= CHECKOUT_ACTION__REMOVE
;
246 /* if the file is on disk and doesn't match our mode, force update */
248 GIT_PERMS_IS_EXEC(wd
->mode
) !=
249 GIT_PERMS_IS_EXEC(delta
->new_file
.mode
))
250 *action
|= CHECKOUT_ACTION__REMOVE
;
252 notify
= GIT_CHECKOUT_NOTIFY_UPDATED
;
255 if ((*action
& CHECKOUT_ACTION__CONFLICT
) != 0)
256 notify
= GIT_CHECKOUT_NOTIFY_CONFLICT
;
258 return checkout_notify(data
, notify
, delta
, wd
);
261 static int checkout_action_no_wd(
264 const git_diff_delta
*delta
)
268 *action
= CHECKOUT_ACTION__NONE
;
270 switch (delta
->status
) {
271 case GIT_DELTA_UNMODIFIED
: /* case 12 */
272 error
= checkout_notify(data
, GIT_CHECKOUT_NOTIFY_DIRTY
, delta
, NULL
);
275 *action
= CHECKOUT_ACTION_IF(RECREATE_MISSING
, UPDATE_BLOB
, NONE
);
277 case GIT_DELTA_ADDED
: /* case 2 or 28 (and 5 but not really) */
278 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
280 case GIT_DELTA_MODIFIED
: /* case 13 (and 35 but not really) */
281 *action
= CHECKOUT_ACTION_IF(RECREATE_MISSING
, UPDATE_BLOB
, CONFLICT
);
283 case GIT_DELTA_TYPECHANGE
: /* case 21 (B->T) and 28 (T->B)*/
284 if (delta
->new_file
.mode
== GIT_FILEMODE_TREE
)
285 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
287 case GIT_DELTA_DELETED
: /* case 8 or 25 */
288 *action
= CHECKOUT_ACTION_IF(SAFE
, REMOVE
, NONE
);
290 default: /* impossible */
294 return checkout_action_common(action
, data
, delta
, NULL
);
297 static bool wd_item_is_removable(git_iterator
*iter
, const git_index_entry
*wd
)
299 git_buf
*full
= NULL
;
301 if (wd
->mode
!= GIT_FILEMODE_TREE
)
303 if (git_iterator_current_workdir_path(&full
, iter
) < 0)
305 return !full
|| !git_path_contains(full
, DOT_GIT
);
308 static int checkout_queue_remove(checkout_data
*data
, const char *path
)
310 char *copy
= git_pool_strdup(&data
->pool
, path
);
311 GITERR_CHECK_ALLOC(copy
);
312 return git_vector_insert(&data
->removes
, copy
);
315 /* note that this advances the iterator over the wd item */
316 static int checkout_action_wd_only(
318 git_iterator
*workdir
,
319 const git_index_entry
**wditem
,
320 git_vector
*pathspec
)
324 git_checkout_notify_t notify
= GIT_CHECKOUT_NOTIFY_NONE
;
325 const git_index_entry
*wd
= *wditem
;
327 if (!git_pathspec__match(
329 (data
->strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
) != 0,
330 git_iterator_ignore_case(workdir
), NULL
, NULL
))
331 return git_iterator_advance(wditem
, workdir
);
333 /* check if item is tracked in the index but not in the checkout diff */
334 if (data
->index
!= NULL
) {
337 error
= git_index__find_pos(
338 &pos
, data
->index
, wd
->path
, 0, GIT_INDEX_STAGE_ANY
);
340 if (wd
->mode
!= GIT_FILEMODE_TREE
) {
341 if (!error
) { /* found by git_index__find_pos call */
342 notify
= GIT_CHECKOUT_NOTIFY_DIRTY
;
343 remove
= ((data
->strategy
& GIT_CHECKOUT_FORCE
) != 0);
344 } else if (error
!= GIT_ENOTFOUND
)
347 error
= 0; /* git_index__find_pos does not set error msg */
349 /* for tree entries, we have to see if there are any index
350 * entries that are contained inside that tree
352 const git_index_entry
*e
= git_index_get_byindex(data
->index
, pos
);
354 if (e
!= NULL
&& data
->diff
->pfxcomp(e
->path
, wd
->path
) == 0) {
355 notify
= GIT_CHECKOUT_NOTIFY_DIRTY
;
356 remove
= ((data
->strategy
& GIT_CHECKOUT_FORCE
) != 0);
361 if (notify
!= GIT_CHECKOUT_NOTIFY_NONE
) {
362 /* if we found something in the index, notify and advance */
363 if ((error
= checkout_notify(data
, notify
, NULL
, wd
)) != 0)
366 if (remove
&& wd_item_is_removable(workdir
, wd
))
367 error
= checkout_queue_remove(data
, wd
->path
);
370 error
= git_iterator_advance(wditem
, workdir
);
372 /* untracked or ignored - can't know which until we advance through */
373 bool over
= false, removable
= wd_item_is_removable(workdir
, wd
);
374 git_iterator_status_t untracked_state
;
376 /* copy the entry for issuing notification callback later */
377 git_index_entry saved_wd
= *wd
;
378 git_buf_sets(&data
->tmp
, wd
->path
);
379 saved_wd
.path
= data
->tmp
.ptr
;
381 error
= git_iterator_advance_over_with_status(
382 wditem
, &untracked_state
, workdir
);
383 if (error
== GIT_ITEROVER
)
388 if (untracked_state
== GIT_ITERATOR_STATUS_IGNORED
) {
389 notify
= GIT_CHECKOUT_NOTIFY_IGNORED
;
390 remove
= ((data
->strategy
& GIT_CHECKOUT_REMOVE_IGNORED
) != 0);
392 notify
= GIT_CHECKOUT_NOTIFY_UNTRACKED
;
393 remove
= ((data
->strategy
& GIT_CHECKOUT_REMOVE_UNTRACKED
) != 0);
396 if ((error
= checkout_notify(data
, notify
, NULL
, &saved_wd
)) != 0)
399 if (remove
&& removable
)
400 error
= checkout_queue_remove(data
, saved_wd
.path
);
402 if (!error
&& over
) /* restore ITEROVER if needed */
403 error
= GIT_ITEROVER
;
409 static bool submodule_is_config_only(
413 git_submodule
*sm
= NULL
;
414 unsigned int sm_loc
= 0;
417 if (git_submodule_lookup(&sm
, data
->repo
, path
) < 0)
420 if (git_submodule_location(&sm_loc
, sm
) < 0 ||
421 sm_loc
== GIT_SUBMODULE_STATUS_IN_CONFIG
)
424 git_submodule_free(sm
);
429 static bool checkout_is_empty_dir(checkout_data
*data
, const char *path
)
431 git_buf_truncate(&data
->path
, data
->workdir_len
);
432 if (git_buf_puts(&data
->path
, path
) < 0)
434 return git_path_is_empty_dir(data
->path
.ptr
);
437 static int checkout_action_with_wd(
440 const git_diff_delta
*delta
,
441 git_iterator
*workdir
,
442 const git_index_entry
*wd
)
444 *action
= CHECKOUT_ACTION__NONE
;
446 switch (delta
->status
) {
447 case GIT_DELTA_UNMODIFIED
: /* case 14/15 or 33 */
448 if (checkout_is_workdir_modified(data
, &delta
->old_file
, &delta
->new_file
, wd
)) {
450 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_DIRTY
, delta
, wd
) );
451 *action
= CHECKOUT_ACTION_IF(FORCE
, UPDATE_BLOB
, NONE
);
454 case GIT_DELTA_ADDED
: /* case 3, 4 or 6 */
455 if (git_iterator_current_is_ignored(workdir
))
456 *action
= CHECKOUT_ACTION_IF(DONT_OVERWRITE_IGNORED
, CONFLICT
, UPDATE_BLOB
);
458 *action
= CHECKOUT_ACTION_IF(FORCE
, UPDATE_BLOB
, CONFLICT
);
460 case GIT_DELTA_DELETED
: /* case 9 or 10 (or 26 but not really) */
461 if (checkout_is_workdir_modified(data
, &delta
->old_file
, &delta
->new_file
, wd
))
462 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE
, CONFLICT
);
464 *action
= CHECKOUT_ACTION_IF(SAFE
, REMOVE
, NONE
);
466 case GIT_DELTA_MODIFIED
: /* case 16, 17, 18 (or 36 but not really) */
467 if (wd
->mode
!= GIT_FILEMODE_COMMIT
&&
468 checkout_is_workdir_modified(data
, &delta
->old_file
, &delta
->new_file
, wd
))
469 *action
= CHECKOUT_ACTION_IF(FORCE
, UPDATE_BLOB
, CONFLICT
);
471 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
473 case GIT_DELTA_TYPECHANGE
: /* case 22, 23, 29, 30 */
474 if (delta
->old_file
.mode
== GIT_FILEMODE_TREE
) {
475 if (wd
->mode
== GIT_FILEMODE_TREE
)
476 /* either deleting items in old tree will delete the wd dir,
477 * or we'll get a conflict when we attempt blob update...
479 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
480 else if (wd
->mode
== GIT_FILEMODE_COMMIT
) {
481 /* workdir is possibly a "phantom" submodule - treat as a
482 * tree if the only submodule info came from the config
484 if (submodule_is_config_only(data
, wd
->path
))
485 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
487 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
489 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE
, CONFLICT
);
491 else if (checkout_is_workdir_modified(data
, &delta
->old_file
, &delta
->new_file
, wd
))
492 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
494 *action
= CHECKOUT_ACTION_IF(SAFE
, REMOVE_AND_UPDATE
, NONE
);
496 /* don't update if the typechange is to a tree */
497 if (delta
->new_file
.mode
== GIT_FILEMODE_TREE
)
498 *action
= (*action
& ~CHECKOUT_ACTION__UPDATE_BLOB
);
500 default: /* impossible */
504 return checkout_action_common(action
, data
, delta
, wd
);
507 static int checkout_action_with_wd_blocker(
510 const git_diff_delta
*delta
,
511 const git_index_entry
*wd
)
513 *action
= CHECKOUT_ACTION__NONE
;
515 switch (delta
->status
) {
516 case GIT_DELTA_UNMODIFIED
:
517 /* should show delta as dirty / deleted */
519 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_DIRTY
, delta
, wd
) );
520 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, NONE
);
522 case GIT_DELTA_ADDED
:
523 case GIT_DELTA_MODIFIED
:
524 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
526 case GIT_DELTA_DELETED
:
527 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE
, CONFLICT
);
529 case GIT_DELTA_TYPECHANGE
:
530 /* not 100% certain about this... */
531 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
533 default: /* impossible */
537 return checkout_action_common(action
, data
, delta
, wd
);
540 static int checkout_action_with_wd_dir(
543 const git_diff_delta
*delta
,
544 git_iterator
*workdir
,
545 const git_index_entry
*wd
)
547 *action
= CHECKOUT_ACTION__NONE
;
549 switch (delta
->status
) {
550 case GIT_DELTA_UNMODIFIED
: /* case 19 or 24 (or 34 but not really) */
552 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_DIRTY
, delta
, NULL
));
554 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_UNTRACKED
, NULL
, wd
));
555 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, NONE
);
557 case GIT_DELTA_ADDED
:/* case 4 (and 7 for dir) */
558 case GIT_DELTA_MODIFIED
: /* case 20 (or 37 but not really) */
559 if (delta
->old_file
.mode
== GIT_FILEMODE_COMMIT
)
560 /* expected submodule (and maybe found one) */;
561 else if (delta
->new_file
.mode
!= GIT_FILEMODE_TREE
)
562 *action
= git_iterator_current_is_ignored(workdir
) ?
563 CHECKOUT_ACTION_IF(DONT_OVERWRITE_IGNORED
, CONFLICT
, REMOVE_AND_UPDATE
) :
564 CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
566 case GIT_DELTA_DELETED
: /* case 11 (and 27 for dir) */
567 if (delta
->old_file
.mode
!= GIT_FILEMODE_TREE
)
569 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_UNTRACKED
, NULL
, wd
));
571 case GIT_DELTA_TYPECHANGE
: /* case 24 or 31 */
572 if (delta
->old_file
.mode
== GIT_FILEMODE_TREE
) {
573 /* For typechange from dir, remove dir and add blob, but it is
574 * not safe to remove dir if it contains modified files.
575 * However, safely removing child files will remove the parent
576 * directory if is it left empty, so we can defer removing the
577 * dir and it will succeed if no children are left.
579 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
581 else if (delta
->new_file
.mode
!= GIT_FILEMODE_TREE
)
582 /* For typechange to dir, dir is already created so no action */
583 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
585 default: /* impossible */
589 return checkout_action_common(action
, data
, delta
, wd
);
592 static int checkout_action_with_wd_dir_empty(
595 const git_diff_delta
*delta
)
597 int error
= checkout_action_no_wd(action
, data
, delta
);
599 /* We can always safely remove an empty directory. */
600 if (error
== 0 && *action
!= CHECKOUT_ACTION__NONE
)
601 *action
|= CHECKOUT_ACTION__REMOVE
;
606 static int checkout_action(
609 git_diff_delta
*delta
,
610 git_iterator
*workdir
,
611 const git_index_entry
**wditem
,
612 git_vector
*pathspec
)
615 int (*strcomp
)(const char *, const char *) = data
->diff
->strcomp
;
616 int (*pfxcomp
)(const char *str
, const char *pfx
) = data
->diff
->pfxcomp
;
617 int (*advance
)(const git_index_entry
**, git_iterator
*) = NULL
;
619 /* move workdir iterator to follow along with deltas */
622 const git_index_entry
*wd
= *wditem
;
625 return checkout_action_no_wd(action
, data
, delta
);
627 cmp
= strcomp(wd
->path
, delta
->old_file
.path
);
629 /* 1. wd before delta ("a/a" before "a/b")
630 * 2. wd prefixes delta & should expand ("a/" before "a/b")
631 * 3. wd prefixes delta & cannot expand ("a/b" before "a/b/c")
632 * 4. wd equals delta ("a/b" and "a/b")
633 * 5. wd after delta & delta prefixes wd ("a/b/c" after "a/b/" or "a/b")
634 * 6. wd after delta ("a/c" after "a/b")
638 cmp
= pfxcomp(delta
->old_file
.path
, wd
->path
);
641 if (wd
->mode
== GIT_FILEMODE_TREE
) {
642 /* case 2 - entry prefixed by workdir tree */
643 error
= git_iterator_advance_into_or_over(wditem
, workdir
);
644 if (error
< 0 && error
!= GIT_ITEROVER
)
649 /* case 3 maybe - wd contains non-dir where dir expected */
650 if (delta
->old_file
.path
[strlen(wd
->path
)] == '/') {
651 error
= checkout_action_with_wd_blocker(
652 action
, data
, delta
, wd
);
653 advance
= git_iterator_advance
;
658 /* case 1 - handle wd item (if it matches pathspec) */
659 error
= checkout_action_wd_only(data
, workdir
, wditem
, pathspec
);
660 if (error
&& error
!= GIT_ITEROVER
)
667 error
= checkout_action_with_wd(action
, data
, delta
, workdir
, wd
);
668 advance
= git_iterator_advance
;
672 cmp
= pfxcomp(wd
->path
, delta
->old_file
.path
);
674 if (cmp
== 0) { /* case 5 */
675 if (wd
->path
[strlen(delta
->old_file
.path
)] != '/')
676 return checkout_action_no_wd(action
, data
, delta
);
678 if (delta
->status
== GIT_DELTA_TYPECHANGE
) {
679 if (delta
->old_file
.mode
== GIT_FILEMODE_TREE
) {
680 error
= checkout_action_with_wd(action
, data
, delta
, workdir
, wd
);
681 advance
= git_iterator_advance_into
;
685 if (delta
->new_file
.mode
== GIT_FILEMODE_TREE
||
686 delta
->new_file
.mode
== GIT_FILEMODE_COMMIT
||
687 delta
->old_file
.mode
== GIT_FILEMODE_COMMIT
)
689 error
= checkout_action_with_wd(action
, data
, delta
, workdir
, wd
);
690 advance
= git_iterator_advance
;
695 return checkout_is_empty_dir(data
, wd
->path
) ?
696 checkout_action_with_wd_dir_empty(action
, data
, delta
) :
697 checkout_action_with_wd_dir(action
, data
, delta
, workdir
, wd
);
700 /* case 6 - wd is after delta */
701 return checkout_action_no_wd(action
, data
, delta
);
705 if (!error
&& advance
!= NULL
&&
706 (error
= advance(wditem
, workdir
)) < 0) {
708 if (error
== GIT_ITEROVER
)
715 static int checkout_remaining_wd_items(
717 git_iterator
*workdir
,
718 const git_index_entry
*wd
,
724 error
= checkout_action_wd_only(data
, workdir
, &wd
, spec
);
726 if (error
== GIT_ITEROVER
)
732 GIT_INLINE(int) checkout_idxentry_cmp(
733 const git_index_entry
*a
,
734 const git_index_entry
*b
)
743 return strcmp(a
->path
, b
->path
);
746 static int checkout_conflictdata_cmp(const void *a
, const void *b
)
748 const checkout_conflictdata
*ca
= a
;
749 const checkout_conflictdata
*cb
= b
;
752 if ((diff
= checkout_idxentry_cmp(ca
->ancestor
, cb
->ancestor
)) == 0 &&
753 (diff
= checkout_idxentry_cmp(ca
->ours
, cb
->theirs
)) == 0)
754 diff
= checkout_idxentry_cmp(ca
->theirs
, cb
->theirs
);
759 int checkout_conflictdata_empty(
760 const git_vector
*conflicts
, size_t idx
, void *payload
)
762 checkout_conflictdata
*conflict
;
766 if ((conflict
= git_vector_get(conflicts
, idx
)) == NULL
)
769 if (conflict
->ancestor
|| conflict
->ours
|| conflict
->theirs
)
776 GIT_INLINE(bool) conflict_pathspec_match(
778 git_iterator
*workdir
,
779 git_vector
*pathspec
,
780 const git_index_entry
*ancestor
,
781 const git_index_entry
*ours
,
782 const git_index_entry
*theirs
)
784 /* if the pathspec matches ours *or* theirs, proceed */
785 if (ours
&& git_pathspec__match(pathspec
, ours
->path
,
786 (data
->strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
) != 0,
787 git_iterator_ignore_case(workdir
), NULL
, NULL
))
790 if (theirs
&& git_pathspec__match(pathspec
, theirs
->path
,
791 (data
->strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
) != 0,
792 git_iterator_ignore_case(workdir
), NULL
, NULL
))
795 if (ancestor
&& git_pathspec__match(pathspec
, ancestor
->path
,
796 (data
->strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
) != 0,
797 git_iterator_ignore_case(workdir
), NULL
, NULL
))
803 GIT_INLINE(int) checkout_conflict_detect_submodule(checkout_conflictdata
*conflict
)
805 conflict
->submodule
= ((conflict
->ancestor
&& S_ISGITLINK(conflict
->ancestor
->mode
)) ||
806 (conflict
->ours
&& S_ISGITLINK(conflict
->ours
->mode
)) ||
807 (conflict
->theirs
&& S_ISGITLINK(conflict
->theirs
->mode
)));
811 GIT_INLINE(int) checkout_conflict_detect_binary(git_repository
*repo
, checkout_conflictdata
*conflict
)
813 git_blob
*ancestor_blob
= NULL
, *our_blob
= NULL
, *their_blob
= NULL
;
816 if (conflict
->submodule
)
819 if (conflict
->ancestor
) {
820 if ((error
= git_blob_lookup(&ancestor_blob
, repo
, &conflict
->ancestor
->id
)) < 0)
823 conflict
->binary
= git_blob_is_binary(ancestor_blob
);
826 if (!conflict
->binary
&& conflict
->ours
) {
827 if ((error
= git_blob_lookup(&our_blob
, repo
, &conflict
->ours
->id
)) < 0)
830 conflict
->binary
= git_blob_is_binary(our_blob
);
833 if (!conflict
->binary
&& conflict
->theirs
) {
834 if ((error
= git_blob_lookup(&their_blob
, repo
, &conflict
->theirs
->id
)) < 0)
837 conflict
->binary
= git_blob_is_binary(their_blob
);
841 git_blob_free(ancestor_blob
);
842 git_blob_free(our_blob
);
843 git_blob_free(their_blob
);
848 static int checkout_conflict_append_update(
849 const git_index_entry
*ancestor
,
850 const git_index_entry
*ours
,
851 const git_index_entry
*theirs
,
854 checkout_data
*data
= payload
;
855 checkout_conflictdata
*conflict
;
858 conflict
= git__calloc(1, sizeof(checkout_conflictdata
));
859 GITERR_CHECK_ALLOC(conflict
);
861 conflict
->ancestor
= ancestor
;
862 conflict
->ours
= ours
;
863 conflict
->theirs
= theirs
;
865 if ((error
= checkout_conflict_detect_submodule(conflict
)) < 0 ||
866 (error
= checkout_conflict_detect_binary(data
->repo
, conflict
)) < 0)
872 if (git_vector_insert(&data
->update_conflicts
, conflict
))
878 static int checkout_conflicts_foreach(
881 git_iterator
*workdir
,
882 git_vector
*pathspec
,
883 int (*cb
)(const git_index_entry
*, const git_index_entry
*, const git_index_entry
*, void *),
886 git_index_conflict_iterator
*iterator
= NULL
;
887 const git_index_entry
*ancestor
, *ours
, *theirs
;
890 if ((error
= git_index_conflict_iterator_new(&iterator
, index
)) < 0)
893 /* Collect the conflicts */
894 while ((error
= git_index_conflict_next(&ancestor
, &ours
, &theirs
, iterator
)) == 0) {
895 if (!conflict_pathspec_match(data
, workdir
, pathspec
, ancestor
, ours
, theirs
))
898 if ((error
= cb(ancestor
, ours
, theirs
, payload
)) < 0)
902 if (error
== GIT_ITEROVER
)
906 git_index_conflict_iterator_free(iterator
);
911 static int checkout_conflicts_load(checkout_data
*data
, git_iterator
*workdir
, git_vector
*pathspec
)
915 /* Only write conficts from sources that have them: indexes. */
916 if ((index
= git_iterator_get_index(data
->target
)) == NULL
)
919 data
->update_conflicts
._cmp
= checkout_conflictdata_cmp
;
921 if (checkout_conflicts_foreach(data
, index
, workdir
, pathspec
, checkout_conflict_append_update
, data
) < 0)
924 /* Collect the REUC and NAME entries */
925 data
->update_reuc
= &index
->reuc
;
926 data
->update_names
= &index
->names
;
931 GIT_INLINE(int) checkout_conflicts_cmp_entry(
933 const git_index_entry
*entry
)
935 return strcmp((const char *)path
, entry
->path
);
938 static int checkout_conflicts_cmp_ancestor(const void *p
, const void *c
)
940 const char *path
= p
;
941 const checkout_conflictdata
*conflict
= c
;
943 if (!conflict
->ancestor
)
946 return checkout_conflicts_cmp_entry(path
, conflict
->ancestor
);
949 static checkout_conflictdata
*checkout_conflicts_search_ancestor(
955 if (git_vector_bsearch2(&pos
, &data
->update_conflicts
, checkout_conflicts_cmp_ancestor
, path
) < 0)
958 return git_vector_get(&data
->update_conflicts
, pos
);
961 static checkout_conflictdata
*checkout_conflicts_search_branch(
965 checkout_conflictdata
*conflict
;
968 git_vector_foreach(&data
->update_conflicts
, i
, conflict
) {
971 if (conflict
->ancestor
)
975 cmp
= checkout_conflicts_cmp_entry(path
, conflict
->ours
);
976 else if (conflict
->theirs
)
977 cmp
= checkout_conflicts_cmp_entry(path
, conflict
->theirs
);
986 static int checkout_conflicts_load_byname_entry(
987 checkout_conflictdata
**ancestor_out
,
988 checkout_conflictdata
**ours_out
,
989 checkout_conflictdata
**theirs_out
,
991 const git_index_name_entry
*name_entry
)
993 checkout_conflictdata
*ancestor
, *ours
= NULL
, *theirs
= NULL
;
996 *ancestor_out
= NULL
;
1000 if (!name_entry
->ancestor
) {
1001 giterr_set(GITERR_INDEX
, "A NAME entry exists without an ancestor");
1006 if (!name_entry
->ours
&& !name_entry
->theirs
) {
1007 giterr_set(GITERR_INDEX
, "A NAME entry exists without an ours or theirs");
1012 if ((ancestor
= checkout_conflicts_search_ancestor(data
,
1013 name_entry
->ancestor
)) == NULL
) {
1014 giterr_set(GITERR_INDEX
,
1015 "A NAME entry referenced ancestor entry '%s' which does not exist in the main index",
1016 name_entry
->ancestor
);
1021 if (name_entry
->ours
) {
1022 if (strcmp(name_entry
->ancestor
, name_entry
->ours
) == 0)
1024 else if ((ours
= checkout_conflicts_search_branch(data
, name_entry
->ours
)) == NULL
||
1025 ours
->ours
== NULL
) {
1026 giterr_set(GITERR_INDEX
,
1027 "A NAME entry referenced our entry '%s' which does not exist in the main index",
1034 if (name_entry
->theirs
) {
1035 if (strcmp(name_entry
->ancestor
, name_entry
->theirs
) == 0)
1037 else if (name_entry
->ours
&& strcmp(name_entry
->ours
, name_entry
->theirs
) == 0)
1039 else if ((theirs
= checkout_conflicts_search_branch(data
, name_entry
->theirs
)) == NULL
||
1040 theirs
->theirs
== NULL
) {
1041 giterr_set(GITERR_INDEX
,
1042 "A NAME entry referenced their entry '%s' which does not exist in the main index",
1043 name_entry
->theirs
);
1049 *ancestor_out
= ancestor
;
1051 *theirs_out
= theirs
;
1057 static int checkout_conflicts_coalesce_renames(
1058 checkout_data
*data
)
1061 const git_index_name_entry
*name_entry
;
1062 checkout_conflictdata
*ancestor_conflict
, *our_conflict
, *their_conflict
;
1066 if ((index
= git_iterator_get_index(data
->target
)) == NULL
)
1069 /* Juggle entries based on renames */
1070 names
= git_index_name_entrycount(index
);
1072 for (i
= 0; i
< names
; i
++) {
1073 name_entry
= git_index_name_get_byindex(index
, i
);
1075 if ((error
= checkout_conflicts_load_byname_entry(
1076 &ancestor_conflict
, &our_conflict
, &their_conflict
,
1077 data
, name_entry
)) < 0)
1080 if (our_conflict
&& our_conflict
!= ancestor_conflict
) {
1081 ancestor_conflict
->ours
= our_conflict
->ours
;
1082 our_conflict
->ours
= NULL
;
1084 if (our_conflict
->theirs
)
1085 our_conflict
->name_collision
= 1;
1087 if (our_conflict
->name_collision
)
1088 ancestor_conflict
->name_collision
= 1;
1091 if (their_conflict
&& their_conflict
!= ancestor_conflict
) {
1092 ancestor_conflict
->theirs
= their_conflict
->theirs
;
1093 their_conflict
->theirs
= NULL
;
1095 if (their_conflict
->ours
)
1096 their_conflict
->name_collision
= 1;
1098 if (their_conflict
->name_collision
)
1099 ancestor_conflict
->name_collision
= 1;
1102 if (our_conflict
&& our_conflict
!= ancestor_conflict
&&
1103 their_conflict
&& their_conflict
!= ancestor_conflict
)
1104 ancestor_conflict
->one_to_two
= 1;
1107 git_vector_remove_matching(
1108 &data
->update_conflicts
, checkout_conflictdata_empty
, NULL
);
1114 static int checkout_conflicts_mark_directoryfile(
1115 checkout_data
*data
)
1118 checkout_conflictdata
*conflict
;
1119 const git_index_entry
*entry
;
1122 int prefixed
, error
= 0;
1124 if ((index
= git_iterator_get_index(data
->target
)) == NULL
)
1127 len
= git_index_entrycount(index
);
1129 /* Find d/f conflicts */
1130 git_vector_foreach(&data
->update_conflicts
, i
, conflict
) {
1131 if ((conflict
->ours
&& conflict
->theirs
) ||
1132 (!conflict
->ours
&& !conflict
->theirs
))
1135 path
= conflict
->ours
?
1136 conflict
->ours
->path
: conflict
->theirs
->path
;
1138 if ((error
= git_index_find(&j
, index
, path
)) < 0) {
1139 if (error
== GIT_ENOTFOUND
)
1140 giterr_set(GITERR_INDEX
,
1141 "Index inconsistency, could not find entry for expected conflict '%s'", path
);
1146 for (; j
< len
; j
++) {
1147 if ((entry
= git_index_get_byindex(index
, j
)) == NULL
) {
1148 giterr_set(GITERR_INDEX
,
1149 "Index inconsistency, truncated index while loading expected conflict '%s'", path
);
1154 prefixed
= git_path_equal_or_prefixed(path
, entry
->path
, NULL
);
1156 if (prefixed
== GIT_PATH_EQUAL
)
1159 if (prefixed
== GIT_PATH_PREFIX
)
1160 conflict
->directoryfile
= 1;
1170 static int checkout_get_update_conflicts(
1171 checkout_data
*data
,
1172 git_iterator
*workdir
,
1173 git_vector
*pathspec
)
1177 if (data
->strategy
& GIT_CHECKOUT_SKIP_UNMERGED
)
1180 if ((error
= checkout_conflicts_load(data
, workdir
, pathspec
)) < 0 ||
1181 (error
= checkout_conflicts_coalesce_renames(data
)) < 0 ||
1182 (error
= checkout_conflicts_mark_directoryfile(data
)) < 0)
1189 static int checkout_conflict_append_remove(
1190 const git_index_entry
*ancestor
,
1191 const git_index_entry
*ours
,
1192 const git_index_entry
*theirs
,
1195 checkout_data
*data
= payload
;
1198 assert(ancestor
|| ours
|| theirs
);
1201 name
= git__strdup(ancestor
->path
);
1203 name
= git__strdup(ours
->path
);
1205 name
= git__strdup(theirs
->path
);
1209 GITERR_CHECK_ALLOC(name
);
1211 return git_vector_insert(&data
->remove_conflicts
, (char *)name
);
1214 static int checkout_get_remove_conflicts(
1215 checkout_data
*data
,
1216 git_iterator
*workdir
,
1217 git_vector
*pathspec
)
1219 if ((data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) != 0)
1222 return checkout_conflicts_foreach(data
, data
->index
, workdir
, pathspec
, checkout_conflict_append_remove
, data
);
1225 static int checkout_verify_paths(
1226 git_repository
*repo
,
1228 git_diff_delta
*delta
)
1230 unsigned int flags
= GIT_PATH_REJECT_WORKDIR_DEFAULTS
;
1232 if (action
& CHECKOUT_ACTION__REMOVE
) {
1233 if (!git_path_isvalid(repo
, delta
->old_file
.path
, flags
)) {
1234 giterr_set(GITERR_CHECKOUT
, "Cannot remove invalid path '%s'", delta
->old_file
.path
);
1239 if (action
& ~CHECKOUT_ACTION__REMOVE
) {
1240 if (!git_path_isvalid(repo
, delta
->new_file
.path
, flags
)) {
1241 giterr_set(GITERR_CHECKOUT
, "Cannot checkout to invalid path '%s'", delta
->new_file
.path
);
1249 static int checkout_get_actions(
1250 uint32_t **actions_ptr
,
1251 size_t **counts_ptr
,
1252 checkout_data
*data
,
1253 git_iterator
*workdir
)
1256 const git_index_entry
*wditem
;
1257 git_vector pathspec
= GIT_VECTOR_INIT
, *deltas
;
1259 git_diff_delta
*delta
;
1260 size_t i
, *counts
= NULL
;
1261 uint32_t *actions
= NULL
;
1263 git_pool_init(&pathpool
, 1);
1265 if (data
->opts
.paths
.count
> 0 &&
1266 git_pathspec__vinit(&pathspec
, &data
->opts
.paths
, &pathpool
) < 0)
1269 if ((error
= git_iterator_current(&wditem
, workdir
)) < 0 &&
1270 error
!= GIT_ITEROVER
)
1273 deltas
= &data
->diff
->deltas
;
1275 *counts_ptr
= counts
= git__calloc(CHECKOUT_ACTION__MAX
+1, sizeof(size_t));
1276 *actions_ptr
= actions
= git__calloc(
1277 deltas
->length
? deltas
->length
: 1, sizeof(uint32_t));
1278 if (!counts
|| !actions
) {
1283 git_vector_foreach(deltas
, i
, delta
) {
1284 if ((error
= checkout_action(&act
, data
, delta
, workdir
, &wditem
, &pathspec
)) == 0)
1285 error
= checkout_verify_paths(data
->repo
, act
, delta
);
1292 if (act
& CHECKOUT_ACTION__REMOVE
)
1293 counts
[CHECKOUT_ACTION__REMOVE
]++;
1294 if (act
& CHECKOUT_ACTION__UPDATE_BLOB
)
1295 counts
[CHECKOUT_ACTION__UPDATE_BLOB
]++;
1296 if (act
& CHECKOUT_ACTION__UPDATE_SUBMODULE
)
1297 counts
[CHECKOUT_ACTION__UPDATE_SUBMODULE
]++;
1298 if (act
& CHECKOUT_ACTION__CONFLICT
)
1299 counts
[CHECKOUT_ACTION__CONFLICT
]++;
1302 error
= checkout_remaining_wd_items(data
, workdir
, wditem
, &pathspec
);
1306 counts
[CHECKOUT_ACTION__REMOVE
] += data
->removes
.length
;
1308 if (counts
[CHECKOUT_ACTION__CONFLICT
] > 0 &&
1309 (data
->strategy
& GIT_CHECKOUT_ALLOW_CONFLICTS
) == 0)
1311 giterr_set(GITERR_CHECKOUT
, "%"PRIuZ
" %s checkout",
1312 counts
[CHECKOUT_ACTION__CONFLICT
],
1313 counts
[CHECKOUT_ACTION__CONFLICT
] == 1 ?
1314 "conflict prevents" : "conflicts prevent");
1315 error
= GIT_ECONFLICT
;
1320 if ((error
= checkout_get_remove_conflicts(data
, workdir
, &pathspec
)) < 0 ||
1321 (error
= checkout_get_update_conflicts(data
, workdir
, &pathspec
)) < 0)
1324 counts
[CHECKOUT_ACTION__REMOVE_CONFLICT
] = git_vector_length(&data
->remove_conflicts
);
1325 counts
[CHECKOUT_ACTION__UPDATE_CONFLICT
] = git_vector_length(&data
->update_conflicts
);
1327 git_pathspec__vfree(&pathspec
);
1328 git_pool_clear(&pathpool
);
1335 *actions_ptr
= NULL
;
1338 git_pathspec__vfree(&pathspec
);
1339 git_pool_clear(&pathpool
);
1344 static bool should_remove_existing(checkout_data
*data
)
1348 if (git_repository__cvar(&ignorecase
, data
->repo
, GIT_CVAR_IGNORECASE
) < 0) {
1352 return (ignorecase
&&
1353 (data
->strategy
& GIT_CHECKOUT_DONT_REMOVE_EXISTING
) == 0);
1356 #define MKDIR_NORMAL \
1357 GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR
1358 #define MKDIR_REMOVE_EXISTING \
1359 MKDIR_NORMAL | GIT_MKDIR_REMOVE_FILES | GIT_MKDIR_REMOVE_SYMLINKS
1361 static int checkout_mkdir(
1362 checkout_data
*data
,
1368 struct git_futils_mkdir_options mkdir_opts
= {0};
1371 mkdir_opts
.dir_map
= data
->mkdir_map
;
1372 mkdir_opts
.pool
= &data
->pool
;
1374 error
= git_futils_mkdir_relative(
1375 path
, base
, mode
, flags
, &mkdir_opts
);
1377 data
->perfdata
.mkdir_calls
+= mkdir_opts
.perfdata
.mkdir_calls
;
1378 data
->perfdata
.stat_calls
+= mkdir_opts
.perfdata
.stat_calls
;
1379 data
->perfdata
.chmod_calls
+= mkdir_opts
.perfdata
.chmod_calls
;
1384 static int mkpath2file(
1385 checkout_data
*data
, const char *path
, unsigned int mode
)
1388 bool remove_existing
= should_remove_existing(data
);
1389 unsigned int flags
=
1390 (remove_existing
? MKDIR_REMOVE_EXISTING
: MKDIR_NORMAL
) |
1391 GIT_MKDIR_SKIP_LAST
;
1394 if ((error
= checkout_mkdir(
1395 data
, path
, data
->opts
.target_directory
, mode
, flags
)) < 0)
1398 if (remove_existing
) {
1399 data
->perfdata
.stat_calls
++;
1401 if (p_lstat(path
, &st
) == 0) {
1403 /* Some file, symlink or folder already exists at this name.
1404 * We would have removed it in remove_the_old unless we're on
1405 * a case inensitive filesystem (or the user has asked us not
1406 * to). Remove the similarly named file to write the new.
1408 error
= git_futils_rmdir_r(path
, NULL
, GIT_RMDIR_REMOVE_FILES
);
1409 } else if (errno
!= ENOENT
) {
1410 giterr_set(GITERR_OS
, "Failed to stat file '%s'", path
);
1420 struct checkout_stream
{
1421 git_writestream base
;
1427 static int checkout_stream_write(
1428 git_writestream
*s
, const char *buffer
, size_t len
)
1430 struct checkout_stream
*stream
= (struct checkout_stream
*)s
;
1433 if ((ret
= p_write(stream
->fd
, buffer
, len
)) < 0)
1434 giterr_set(GITERR_OS
, "Could not write to '%s'", stream
->path
);
1439 static int checkout_stream_close(git_writestream
*s
)
1441 struct checkout_stream
*stream
= (struct checkout_stream
*)s
;
1442 assert(stream
&& stream
->open
);
1445 return p_close(stream
->fd
);
1448 static void checkout_stream_free(git_writestream
*s
)
1453 static int blob_content_to_file(
1454 checkout_data
*data
,
1458 const char *hint_path
,
1459 mode_t entry_filemode
)
1461 int flags
= data
->opts
.file_open_flags
;
1462 mode_t file_mode
= data
->opts
.file_mode
?
1463 data
->opts
.file_mode
: entry_filemode
;
1464 git_filter_options filter_opts
= GIT_FILTER_OPTIONS_INIT
;
1465 struct checkout_stream writer
;
1467 git_filter_list
*fl
= NULL
;
1471 if (hint_path
== NULL
)
1474 if ((error
= mkpath2file(data
, path
, data
->opts
.dir_mode
)) < 0)
1478 flags
= O_CREAT
| O_TRUNC
| O_WRONLY
;
1479 if (!(mode
= file_mode
))
1480 mode
= GIT_FILEMODE_BLOB
;
1482 if ((fd
= p_open(path
, flags
, mode
)) < 0) {
1483 giterr_set(GITERR_OS
, "Could not open '%s' for writing", path
);
1487 filter_opts
.attr_session
= &data
->attr_session
;
1488 filter_opts
.temp_buf
= &data
->tmp
;
1490 if (!data
->opts
.disable_filters
&&
1491 (error
= git_filter_list__load_ext(
1492 &fl
, data
->repo
, blob
, hint_path
,
1493 GIT_FILTER_TO_WORKTREE
, &filter_opts
))) {
1498 /* setup the writer */
1499 memset(&writer
, 0, sizeof(struct checkout_stream
));
1500 writer
.base
.write
= checkout_stream_write
;
1501 writer
.base
.close
= checkout_stream_close
;
1502 writer
.base
.free
= checkout_stream_free
;
1507 error
= git_filter_list_stream_blob(fl
, blob
, &writer
.base
);
1509 assert(writer
.open
== 0);
1511 git_filter_list_free(fl
);
1517 data
->perfdata
.stat_calls
++;
1519 if ((error
= p_stat(path
, st
)) < 0) {
1520 giterr_set(GITERR_OS
, "Error statting '%s'", path
);
1524 st
->st_mode
= entry_filemode
;
1530 static int blob_content_to_link(
1531 checkout_data
*data
,
1536 git_buf linktarget
= GIT_BUF_INIT
;
1539 if ((error
= mkpath2file(data
, path
, data
->opts
.dir_mode
)) < 0)
1542 if ((error
= git_blob__getbuf(&linktarget
, blob
)) < 0)
1545 if (data
->can_symlink
) {
1546 if ((error
= p_symlink(git_buf_cstr(&linktarget
), path
)) < 0)
1547 giterr_set(GITERR_OS
, "Could not create symlink %s", path
);
1549 error
= git_futils_fake_symlink(git_buf_cstr(&linktarget
), path
);
1553 data
->perfdata
.stat_calls
++;
1555 if ((error
= p_lstat(path
, st
)) < 0)
1556 giterr_set(GITERR_CHECKOUT
, "Could not stat symlink %s", path
);
1558 st
->st_mode
= GIT_FILEMODE_LINK
;
1561 git_buf_free(&linktarget
);
1566 static int checkout_update_index(
1567 checkout_data
*data
,
1568 const git_diff_file
*file
,
1571 git_index_entry entry
;
1576 memset(&entry
, 0, sizeof(entry
));
1577 entry
.path
= (char *)file
->path
; /* cast to prevent warning */
1578 git_index_entry__init_from_stat(&entry
, st
, true);
1579 git_oid_cpy(&entry
.id
, &file
->id
);
1581 return git_index_add(data
->index
, &entry
);
1584 static int checkout_submodule_update_index(
1585 checkout_data
*data
,
1586 const git_diff_file
*file
)
1590 /* update the index unless prevented */
1591 if ((data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) != 0)
1594 git_buf_truncate(&data
->path
, data
->workdir_len
);
1595 if (git_buf_puts(&data
->path
, file
->path
) < 0)
1598 data
->perfdata
.stat_calls
++;
1599 if (p_stat(git_buf_cstr(&data
->path
), &st
) < 0) {
1601 GITERR_CHECKOUT
, "Could not stat submodule %s\n", file
->path
);
1602 return GIT_ENOTFOUND
;
1605 st
.st_mode
= GIT_FILEMODE_COMMIT
;
1607 return checkout_update_index(data
, file
, &st
);
1610 static int checkout_submodule(
1611 checkout_data
*data
,
1612 const git_diff_file
*file
)
1614 bool remove_existing
= should_remove_existing(data
);
1617 /* Until submodules are supported, UPDATE_ONLY means do nothing here */
1618 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0)
1621 if ((error
= checkout_mkdir(
1623 file
->path
, data
->opts
.target_directory
, data
->opts
.dir_mode
,
1624 remove_existing
? MKDIR_REMOVE_EXISTING
: MKDIR_NORMAL
)) < 0)
1627 if ((error
= git_submodule_lookup(NULL
, data
->repo
, file
->path
)) < 0) {
1628 /* I've observed repos with submodules in the tree that do not
1629 * have a .gitmodules - core Git just makes an empty directory
1631 if (error
== GIT_ENOTFOUND
) {
1633 return checkout_submodule_update_index(data
, file
);
1639 /* TODO: Support checkout_strategy options. Two circumstances:
1640 * 1 - submodule already checked out, but we need to move the HEAD
1641 * to the new OID, or
1642 * 2 - submodule not checked out and we should recursively check it out
1644 * Checkout will not execute a pull on the submodule, but a clone
1645 * command should probably be able to. Do we need a submodule callback?
1648 return checkout_submodule_update_index(data
, file
);
1651 static void report_progress(
1652 checkout_data
*data
,
1655 if (data
->opts
.progress_cb
)
1656 data
->opts
.progress_cb(
1657 path
, data
->completed_steps
, data
->total_steps
,
1658 data
->opts
.progress_payload
);
1661 static int checkout_safe_for_update_only(
1662 checkout_data
*data
, const char *path
, mode_t expected_mode
)
1666 data
->perfdata
.stat_calls
++;
1668 if (p_lstat(path
, &st
) < 0) {
1669 /* if doesn't exist, then no error and no update */
1670 if (errno
== ENOENT
|| errno
== ENOTDIR
)
1673 /* otherwise, stat error and no update */
1674 giterr_set(GITERR_OS
, "Failed to stat file '%s'", path
);
1678 /* only safe for update if this is the same type of file */
1679 if ((st
.st_mode
& ~0777) == (expected_mode
& ~0777))
1685 static int checkout_write_content(
1686 checkout_data
*data
,
1688 const char *full_path
,
1689 const char *hint_path
,
1696 if ((error
= git_blob_lookup(&blob
, data
->repo
, oid
)) < 0)
1700 error
= blob_content_to_link(data
, st
, blob
, full_path
);
1702 error
= blob_content_to_file(data
, st
, blob
, full_path
, hint_path
, mode
);
1704 git_blob_free(blob
);
1706 /* if we try to create the blob and an existing directory blocks it from
1707 * being written, then there must have been a typechange conflict in a
1708 * parent directory - suppress the error and try to continue.
1710 if ((data
->strategy
& GIT_CHECKOUT_ALLOW_CONFLICTS
) != 0 &&
1711 (error
== GIT_ENOTFOUND
|| error
== GIT_EEXISTS
))
1720 static int checkout_blob(
1721 checkout_data
*data
,
1722 const git_diff_file
*file
)
1727 git_buf_truncate(&data
->path
, data
->workdir_len
);
1728 if (git_buf_puts(&data
->path
, file
->path
) < 0)
1731 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0) {
1732 int rval
= checkout_safe_for_update_only(
1733 data
, git_buf_cstr(&data
->path
), file
->mode
);
1738 error
= checkout_write_content(
1739 data
, &file
->id
, git_buf_cstr(&data
->path
), NULL
, file
->mode
, &st
);
1741 /* update the index unless prevented */
1742 if (!error
&& (data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) == 0)
1743 error
= checkout_update_index(data
, file
, &st
);
1745 /* update the submodule data if this was a new .gitmodules file */
1746 if (!error
&& strcmp(file
->path
, ".gitmodules") == 0)
1747 data
->reload_submodules
= true;
1752 static int checkout_remove_the_old(
1753 unsigned int *actions
,
1754 checkout_data
*data
)
1757 git_diff_delta
*delta
;
1760 const char *workdir
= git_buf_cstr(&data
->path
);
1761 uint32_t flg
= GIT_RMDIR_EMPTY_PARENTS
|
1762 GIT_RMDIR_REMOVE_FILES
| GIT_RMDIR_REMOVE_BLOCKERS
;
1764 if (data
->opts
.checkout_strategy
& GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES
)
1765 flg
|= GIT_RMDIR_SKIP_NONEMPTY
;
1767 git_buf_truncate(&data
->path
, data
->workdir_len
);
1769 git_vector_foreach(&data
->diff
->deltas
, i
, delta
) {
1770 if (actions
[i
] & CHECKOUT_ACTION__REMOVE
) {
1771 error
= git_futils_rmdir_r(delta
->old_file
.path
, workdir
, flg
);
1775 data
->completed_steps
++;
1776 report_progress(data
, delta
->old_file
.path
);
1778 if ((actions
[i
] & CHECKOUT_ACTION__UPDATE_BLOB
) == 0 &&
1779 (data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) == 0 &&
1780 data
->index
!= NULL
)
1782 (void)git_index_remove(data
->index
, delta
->old_file
.path
, 0);
1787 git_vector_foreach(&data
->removes
, i
, str
) {
1788 error
= git_futils_rmdir_r(str
, workdir
, flg
);
1792 data
->completed_steps
++;
1793 report_progress(data
, str
);
1795 if ((data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) == 0 &&
1796 data
->index
!= NULL
)
1798 if (str
[strlen(str
) - 1] == '/')
1799 (void)git_index_remove_directory(data
->index
, str
, 0);
1801 (void)git_index_remove(data
->index
, str
, 0);
1808 static int checkout_deferred_remove(git_repository
*repo
, const char *path
)
1811 int error
= git_futils_rmdir_r(
1812 path
, data
->opts
.target_directory
, GIT_RMDIR_EMPTY_PARENTS
);
1814 if (error
== GIT_ENOTFOUND
) {
1828 static int checkout_create_the_new(
1829 unsigned int *actions
,
1830 checkout_data
*data
)
1833 git_diff_delta
*delta
;
1836 git_vector_foreach(&data
->diff
->deltas
, i
, delta
) {
1837 if (actions
[i
] & CHECKOUT_ACTION__DEFER_REMOVE
) {
1838 /* this had a blocker directory that should only be removed iff
1839 * all of the contents of the directory were safely removed
1841 if ((error
= checkout_deferred_remove(
1842 data
->repo
, delta
->old_file
.path
)) < 0)
1846 if (actions
[i
] & CHECKOUT_ACTION__UPDATE_BLOB
) {
1847 error
= checkout_blob(data
, &delta
->new_file
);
1851 data
->completed_steps
++;
1852 report_progress(data
, delta
->new_file
.path
);
1859 static int checkout_create_submodules(
1860 unsigned int *actions
,
1861 checkout_data
*data
)
1864 git_diff_delta
*delta
;
1867 git_vector_foreach(&data
->diff
->deltas
, i
, delta
) {
1868 if (actions
[i
] & CHECKOUT_ACTION__DEFER_REMOVE
) {
1869 /* this has a blocker directory that should only be removed iff
1870 * all of the contents of the directory were safely removed
1872 if ((error
= checkout_deferred_remove(
1873 data
->repo
, delta
->old_file
.path
)) < 0)
1877 if (actions
[i
] & CHECKOUT_ACTION__UPDATE_SUBMODULE
) {
1878 int error
= checkout_submodule(data
, &delta
->new_file
);
1882 data
->completed_steps
++;
1883 report_progress(data
, delta
->new_file
.path
);
1890 static int checkout_lookup_head_tree(git_tree
**out
, git_repository
*repo
)
1893 git_reference
*ref
= NULL
;
1896 if (!(error
= git_repository_head(&ref
, repo
)) &&
1897 !(error
= git_reference_peel(&head
, ref
, GIT_OBJ_TREE
)))
1898 *out
= (git_tree
*)head
;
1900 git_reference_free(ref
);
1906 static int conflict_entry_name(
1908 const char *side_name
,
1909 const char *filename
)
1911 if (git_buf_puts(out
, side_name
) < 0 ||
1912 git_buf_putc(out
, ':') < 0 ||
1913 git_buf_puts(out
, filename
) < 0)
1919 static int checkout_path_suffixed(git_buf
*path
, const char *suffix
)
1922 int i
= 0, error
= 0;
1924 if ((error
= git_buf_putc(path
, '~')) < 0 || (error
= git_buf_puts(path
, suffix
)) < 0)
1927 path_len
= git_buf_len(path
);
1929 while (git_path_exists(git_buf_cstr(path
)) && i
< INT_MAX
) {
1930 git_buf_truncate(path
, path_len
);
1932 if ((error
= git_buf_putc(path
, '_')) < 0 ||
1933 (error
= git_buf_printf(path
, "%d", i
)) < 0)
1940 git_buf_truncate(path
, path_len
);
1942 giterr_set(GITERR_CHECKOUT
, "Could not write '%s': working directory file exists", path
);
1949 static int checkout_write_entry(
1950 checkout_data
*data
,
1951 checkout_conflictdata
*conflict
,
1952 const git_index_entry
*side
)
1954 const char *hint_path
= NULL
, *suffix
;
1958 assert (side
== conflict
->ours
|| side
== conflict
->theirs
);
1960 git_buf_truncate(&data
->path
, data
->workdir_len
);
1961 if (git_buf_puts(&data
->path
, side
->path
) < 0)
1964 if ((conflict
->name_collision
|| conflict
->directoryfile
) &&
1965 (data
->strategy
& GIT_CHECKOUT_USE_OURS
) == 0 &&
1966 (data
->strategy
& GIT_CHECKOUT_USE_THEIRS
) == 0) {
1968 if (side
== conflict
->ours
)
1969 suffix
= data
->opts
.our_label
? data
->opts
.our_label
:
1972 suffix
= data
->opts
.their_label
? data
->opts
.their_label
:
1975 if (checkout_path_suffixed(&data
->path
, suffix
) < 0)
1978 hint_path
= side
->path
;
1981 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0 &&
1982 (error
= checkout_safe_for_update_only(data
, git_buf_cstr(&data
->path
), side
->mode
)) <= 0)
1985 return checkout_write_content(data
,
1986 &side
->id
, git_buf_cstr(&data
->path
), hint_path
, side
->mode
, &st
);
1989 static int checkout_write_entries(
1990 checkout_data
*data
,
1991 checkout_conflictdata
*conflict
)
1995 if ((error
= checkout_write_entry(data
, conflict
, conflict
->ours
)) >= 0)
1996 error
= checkout_write_entry(data
, conflict
, conflict
->theirs
);
2001 static int checkout_merge_path(
2003 checkout_data
*data
,
2004 checkout_conflictdata
*conflict
,
2005 git_merge_file_result
*result
)
2007 const char *our_label_raw
, *their_label_raw
, *suffix
;
2010 if ((error
= git_buf_joinpath(out
, git_repository_workdir(data
->repo
), result
->path
)) < 0)
2013 /* Most conflicts simply use the filename in the index */
2014 if (!conflict
->name_collision
)
2017 /* Rename 2->1 conflicts need the branch name appended */
2018 our_label_raw
= data
->opts
.our_label
? data
->opts
.our_label
: "ours";
2019 their_label_raw
= data
->opts
.their_label
? data
->opts
.their_label
: "theirs";
2020 suffix
= strcmp(result
->path
, conflict
->ours
->path
) == 0 ? our_label_raw
: their_label_raw
;
2022 if ((error
= checkout_path_suffixed(out
, suffix
)) < 0)
2028 static int checkout_write_merge(
2029 checkout_data
*data
,
2030 checkout_conflictdata
*conflict
)
2032 git_buf our_label
= GIT_BUF_INIT
, their_label
= GIT_BUF_INIT
,
2033 path_suffixed
= GIT_BUF_INIT
, path_workdir
= GIT_BUF_INIT
,
2034 in_data
= GIT_BUF_INIT
, out_data
= GIT_BUF_INIT
;
2035 git_merge_file_options opts
= GIT_MERGE_FILE_OPTIONS_INIT
;
2036 git_merge_file_result result
= {0};
2037 git_filebuf output
= GIT_FILEBUF_INIT
;
2038 git_filter_list
*fl
= NULL
;
2039 git_filter_options filter_opts
= GIT_FILTER_OPTIONS_INIT
;
2042 if (data
->opts
.checkout_strategy
& GIT_CHECKOUT_CONFLICT_STYLE_DIFF3
)
2043 opts
.flags
|= GIT_MERGE_FILE_STYLE_DIFF3
;
2045 opts
.ancestor_label
= data
->opts
.ancestor_label
?
2046 data
->opts
.ancestor_label
: "ancestor";
2047 opts
.our_label
= data
->opts
.our_label
?
2048 data
->opts
.our_label
: "ours";
2049 opts
.their_label
= data
->opts
.their_label
?
2050 data
->opts
.their_label
: "theirs";
2052 /* If all the paths are identical, decorate the diff3 file with the branch
2053 * names. Otherwise, append branch_name:path.
2055 if (conflict
->ours
&& conflict
->theirs
&&
2056 strcmp(conflict
->ours
->path
, conflict
->theirs
->path
) != 0) {
2058 if ((error
= conflict_entry_name(
2059 &our_label
, opts
.our_label
, conflict
->ours
->path
)) < 0 ||
2060 (error
= conflict_entry_name(
2061 &their_label
, opts
.their_label
, conflict
->theirs
->path
)) < 0)
2064 opts
.our_label
= git_buf_cstr(&our_label
);
2065 opts
.their_label
= git_buf_cstr(&their_label
);
2068 if ((error
= git_merge_file_from_index(&result
, data
->repo
,
2069 conflict
->ancestor
, conflict
->ours
, conflict
->theirs
, &opts
)) < 0)
2072 if (result
.path
== NULL
|| result
.mode
== 0) {
2073 giterr_set(GITERR_CHECKOUT
, "Could not merge contents of file");
2074 error
= GIT_ECONFLICT
;
2078 if ((error
= checkout_merge_path(&path_workdir
, data
, conflict
, &result
)) < 0)
2081 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0 &&
2082 (error
= checkout_safe_for_update_only(data
, git_buf_cstr(&path_workdir
), result
.mode
)) <= 0)
2085 if (!data
->opts
.disable_filters
) {
2086 in_data
.ptr
= (char *)result
.ptr
;
2087 in_data
.size
= result
.len
;
2089 filter_opts
.attr_session
= &data
->attr_session
;
2090 filter_opts
.temp_buf
= &data
->tmp
;
2092 if ((error
= git_filter_list__load_ext(
2093 &fl
, data
->repo
, NULL
, git_buf_cstr(&path_workdir
),
2094 GIT_FILTER_TO_WORKTREE
, &filter_opts
)) < 0 ||
2095 (error
= git_filter_list_apply_to_data(&out_data
, fl
, &in_data
)) < 0)
2098 out_data
.ptr
= (char *)result
.ptr
;
2099 out_data
.size
= result
.len
;
2102 if ((error
= mkpath2file(data
, path_workdir
.ptr
, data
->opts
.dir_mode
)) < 0 ||
2103 (error
= git_filebuf_open(&output
, git_buf_cstr(&path_workdir
), GIT_FILEBUF_DO_NOT_BUFFER
, result
.mode
)) < 0 ||
2104 (error
= git_filebuf_write(&output
, out_data
.ptr
, out_data
.size
)) < 0 ||
2105 (error
= git_filebuf_commit(&output
)) < 0)
2109 git_filter_list_free(fl
);
2111 git_buf_free(&out_data
);
2112 git_buf_free(&our_label
);
2113 git_buf_free(&their_label
);
2115 git_merge_file_result_free(&result
);
2116 git_buf_free(&path_workdir
);
2117 git_buf_free(&path_suffixed
);
2122 static int checkout_conflict_add(
2123 checkout_data
*data
,
2124 const git_index_entry
*conflict
)
2126 int error
= git_index_remove(data
->index
, conflict
->path
, 0);
2128 if (error
== GIT_ENOTFOUND
)
2133 return git_index_add(data
->index
, conflict
);
2136 static int checkout_conflict_update_index(
2137 checkout_data
*data
,
2138 checkout_conflictdata
*conflict
)
2142 if (conflict
->ancestor
)
2143 error
= checkout_conflict_add(data
, conflict
->ancestor
);
2145 if (!error
&& conflict
->ours
)
2146 error
= checkout_conflict_add(data
, conflict
->ours
);
2148 if (!error
&& conflict
->theirs
)
2149 error
= checkout_conflict_add(data
, conflict
->theirs
);
2154 static int checkout_create_conflicts(checkout_data
*data
)
2156 checkout_conflictdata
*conflict
;
2160 git_vector_foreach(&data
->update_conflicts
, i
, conflict
) {
2162 /* Both deleted: nothing to do */
2163 if (conflict
->ours
== NULL
&& conflict
->theirs
== NULL
)
2166 else if ((data
->strategy
& GIT_CHECKOUT_USE_OURS
) &&
2168 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2169 else if ((data
->strategy
& GIT_CHECKOUT_USE_THEIRS
) &&
2171 error
= checkout_write_entry(data
, conflict
, conflict
->theirs
);
2173 /* Ignore the other side of name collisions. */
2174 else if ((data
->strategy
& GIT_CHECKOUT_USE_OURS
) &&
2175 !conflict
->ours
&& conflict
->name_collision
)
2177 else if ((data
->strategy
& GIT_CHECKOUT_USE_THEIRS
) &&
2178 !conflict
->theirs
&& conflict
->name_collision
)
2181 /* For modify/delete, name collisions and d/f conflicts, write
2182 * the file (potentially with the name mangled.
2184 else if (conflict
->ours
!= NULL
&& conflict
->theirs
== NULL
)
2185 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2186 else if (conflict
->ours
== NULL
&& conflict
->theirs
!= NULL
)
2187 error
= checkout_write_entry(data
, conflict
, conflict
->theirs
);
2189 /* Add/add conflicts and rename 1->2 conflicts, write the
2190 * ours/theirs sides (potentially name mangled).
2192 else if (conflict
->one_to_two
)
2193 error
= checkout_write_entries(data
, conflict
);
2195 /* If all sides are links, write the ours side */
2196 else if (S_ISLNK(conflict
->ours
->mode
) &&
2197 S_ISLNK(conflict
->theirs
->mode
))
2198 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2199 /* Link/file conflicts, write the file side */
2200 else if (S_ISLNK(conflict
->ours
->mode
))
2201 error
= checkout_write_entry(data
, conflict
, conflict
->theirs
);
2202 else if (S_ISLNK(conflict
->theirs
->mode
))
2203 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2205 /* If any side is a gitlink, do nothing. */
2206 else if (conflict
->submodule
)
2209 /* If any side is binary, write the ours side */
2210 else if (conflict
->binary
)
2211 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2214 error
= checkout_write_merge(data
, conflict
);
2216 /* Update the index extensions (REUC and NAME) if we're checking
2217 * out a different index. (Otherwise just leave them there.)
2219 if (!error
&& (data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) == 0)
2220 error
= checkout_conflict_update_index(data
, conflict
);
2225 data
->completed_steps
++;
2226 report_progress(data
,
2227 conflict
->ours
? conflict
->ours
->path
:
2228 (conflict
->theirs
? conflict
->theirs
->path
: conflict
->ancestor
->path
));
2234 static int checkout_remove_conflicts(checkout_data
*data
)
2236 const char *conflict
;
2239 git_vector_foreach(&data
->remove_conflicts
, i
, conflict
) {
2240 if (git_index_conflict_remove(data
->index
, conflict
) < 0)
2243 data
->completed_steps
++;
2249 static int checkout_extensions_update_index(checkout_data
*data
)
2251 const git_index_reuc_entry
*reuc_entry
;
2252 const git_index_name_entry
*name_entry
;
2256 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0)
2259 if (data
->update_reuc
) {
2260 git_vector_foreach(data
->update_reuc
, i
, reuc_entry
) {
2261 if ((error
= git_index_reuc_add(data
->index
, reuc_entry
->path
,
2262 reuc_entry
->mode
[0], &reuc_entry
->oid
[0],
2263 reuc_entry
->mode
[1], &reuc_entry
->oid
[1],
2264 reuc_entry
->mode
[2], &reuc_entry
->oid
[2])) < 0)
2269 if (data
->update_names
) {
2270 git_vector_foreach(data
->update_names
, i
, name_entry
) {
2271 if ((error
= git_index_name_add(data
->index
, name_entry
->ancestor
,
2272 name_entry
->ours
, name_entry
->theirs
)) < 0)
2281 static void checkout_data_clear(checkout_data
*data
)
2283 if (data
->opts_free_baseline
) {
2284 git_tree_free(data
->opts
.baseline
);
2285 data
->opts
.baseline
= NULL
;
2288 git_vector_free(&data
->removes
);
2289 git_pool_clear(&data
->pool
);
2291 git_vector_free_deep(&data
->remove_conflicts
);
2292 git_vector_free_deep(&data
->update_conflicts
);
2294 git__free(data
->pfx
);
2297 git_strmap_free(data
->mkdir_map
);
2299 git_buf_free(&data
->path
);
2300 git_buf_free(&data
->tmp
);
2302 git_index_free(data
->index
);
2305 git_strmap_free(data
->mkdir_map
);
2307 git_attr_session__free(&data
->attr_session
);
2310 static int checkout_data_init(
2311 checkout_data
*data
,
2312 git_iterator
*target
,
2313 const git_checkout_options
*proposed
)
2316 git_repository
*repo
= git_iterator_owner(target
);
2318 memset(data
, 0, sizeof(*data
));
2321 giterr_set(GITERR_CHECKOUT
, "Cannot checkout nothing");
2325 if ((!proposed
|| !proposed
->target_directory
) &&
2326 (error
= git_repository__ensure_not_bare(repo
, "checkout")) < 0)
2330 data
->target
= target
;
2332 GITERR_CHECK_VERSION(
2333 proposed
, GIT_CHECKOUT_OPTIONS_VERSION
, "git_checkout_options");
2336 GIT_INIT_STRUCTURE(&data
->opts
, GIT_CHECKOUT_OPTIONS_VERSION
);
2338 memmove(&data
->opts
, proposed
, sizeof(git_checkout_options
));
2340 if (!data
->opts
.target_directory
)
2341 data
->opts
.target_directory
= git_repository_workdir(repo
);
2342 else if (!git_path_isdir(data
->opts
.target_directory
) &&
2343 (error
= checkout_mkdir(data
,
2344 data
->opts
.target_directory
, NULL
,
2345 GIT_DIR_MODE
, GIT_MKDIR_VERIFY_DIR
)) < 0)
2348 /* refresh config and index content unless NO_REFRESH is given */
2349 if ((data
->opts
.checkout_strategy
& GIT_CHECKOUT_NO_REFRESH
) == 0) {
2352 if ((error
= git_repository_config__weakptr(&cfg
, repo
)) < 0)
2355 /* Get the repository index and reload it (unless we're checking
2356 * out the index; then it has the changes we're trying to check
2357 * out and those should not be overwritten.)
2359 if ((error
= git_repository_index(&data
->index
, data
->repo
)) < 0)
2362 if (data
->index
!= git_iterator_get_index(target
)) {
2363 if ((error
= git_index_read(data
->index
, true)) < 0)
2366 /* cannot checkout if unresolved conflicts exist */
2367 if ((data
->opts
.checkout_strategy
& GIT_CHECKOUT_FORCE
) == 0 &&
2368 git_index_has_conflicts(data
->index
)) {
2369 error
= GIT_ECONFLICT
;
2370 giterr_set(GITERR_CHECKOUT
,
2371 "unresolved conflicts exist in the index");
2375 /* clean conflict data in the current index */
2376 git_index_name_clear(data
->index
);
2377 git_index_reuc_clear(data
->index
);
2381 /* if you are forcing, allow all safe updates, plus recreate missing */
2382 if ((data
->opts
.checkout_strategy
& GIT_CHECKOUT_FORCE
) != 0)
2383 data
->opts
.checkout_strategy
|= GIT_CHECKOUT_SAFE
|
2384 GIT_CHECKOUT_RECREATE_MISSING
;
2386 /* if the repository does not actually have an index file, then this
2387 * is an initial checkout (perhaps from clone), so we allow safe updates
2389 if (!data
->index
->on_disk
&&
2390 (data
->opts
.checkout_strategy
& GIT_CHECKOUT_SAFE
) != 0)
2391 data
->opts
.checkout_strategy
|= GIT_CHECKOUT_RECREATE_MISSING
;
2393 data
->strategy
= data
->opts
.checkout_strategy
;
2395 /* opts->disable_filters is false by default */
2397 if (!data
->opts
.dir_mode
)
2398 data
->opts
.dir_mode
= GIT_DIR_MODE
;
2400 if (!data
->opts
.file_open_flags
)
2401 data
->opts
.file_open_flags
= O_CREAT
| O_TRUNC
| O_WRONLY
;
2403 data
->pfx
= git_pathspec_prefix(&data
->opts
.paths
);
2405 if ((error
= git_repository__cvar(
2406 &data
->can_symlink
, repo
, GIT_CVAR_SYMLINKS
)) < 0)
2409 if (!data
->opts
.baseline
&& !data
->opts
.baseline_index
) {
2410 data
->opts_free_baseline
= true;
2413 /* if we don't have an index, this is an initial checkout and
2414 * should be against an empty baseline
2416 if (data
->index
->on_disk
)
2417 error
= checkout_lookup_head_tree(&data
->opts
.baseline
, repo
);
2419 if (error
== GIT_EUNBORNBRANCH
) {
2428 if ((data
->opts
.checkout_strategy
&
2429 (GIT_CHECKOUT_CONFLICT_STYLE_MERGE
| GIT_CHECKOUT_CONFLICT_STYLE_DIFF3
)) == 0) {
2430 git_config_entry
*conflict_style
= NULL
;
2431 git_config
*cfg
= NULL
;
2433 if ((error
= git_repository_config__weakptr(&cfg
, repo
)) < 0 ||
2434 (error
= git_config_get_entry(&conflict_style
, cfg
, "merge.conflictstyle")) < 0 ||
2435 error
== GIT_ENOTFOUND
)
2439 else if (strcmp(conflict_style
->value
, "merge") == 0)
2440 data
->opts
.checkout_strategy
|= GIT_CHECKOUT_CONFLICT_STYLE_MERGE
;
2441 else if (strcmp(conflict_style
->value
, "diff3") == 0)
2442 data
->opts
.checkout_strategy
|= GIT_CHECKOUT_CONFLICT_STYLE_DIFF3
;
2444 giterr_set(GITERR_CHECKOUT
, "unknown style '%s' given for 'merge.conflictstyle'",
2447 git_config_entry_free(conflict_style
);
2450 git_config_entry_free(conflict_style
);
2453 git_pool_init(&data
->pool
, 1);
2455 if ((error
= git_vector_init(&data
->removes
, 0, git__strcmp_cb
)) < 0 ||
2456 (error
= git_vector_init(&data
->remove_conflicts
, 0, NULL
)) < 0 ||
2457 (error
= git_vector_init(&data
->update_conflicts
, 0, NULL
)) < 0 ||
2458 (error
= git_buf_puts(&data
->path
, data
->opts
.target_directory
)) < 0 ||
2459 (error
= git_path_to_dir(&data
->path
)) < 0 ||
2460 (error
= git_strmap_alloc(&data
->mkdir_map
)) < 0)
2463 data
->workdir_len
= git_buf_len(&data
->path
);
2465 git_attr_session__init(&data
->attr_session
, data
->repo
);
2469 checkout_data_clear(data
);
2474 #define CHECKOUT_INDEX_DONT_WRITE_MASK \
2475 (GIT_CHECKOUT_DONT_UPDATE_INDEX | GIT_CHECKOUT_DONT_WRITE_INDEX)
2477 int git_checkout_iterator(
2478 git_iterator
*target
,
2480 const git_checkout_options
*opts
)
2483 git_iterator
*baseline
= NULL
, *workdir
= NULL
;
2484 git_iterator_options baseline_opts
= GIT_ITERATOR_OPTIONS_INIT
,
2485 workdir_opts
= GIT_ITERATOR_OPTIONS_INIT
;
2486 checkout_data data
= {0};
2487 git_diff_options diff_opts
= GIT_DIFF_OPTIONS_INIT
;
2488 uint32_t *actions
= NULL
;
2489 size_t *counts
= NULL
;
2491 /* initialize structures and options */
2492 error
= checkout_data_init(&data
, target
, opts
);
2497 GIT_DIFF_INCLUDE_UNMODIFIED
|
2498 GIT_DIFF_INCLUDE_UNREADABLE
|
2499 GIT_DIFF_INCLUDE_UNTRACKED
|
2500 GIT_DIFF_RECURSE_UNTRACKED_DIRS
| /* needed to match baseline */
2501 GIT_DIFF_INCLUDE_IGNORED
|
2502 GIT_DIFF_INCLUDE_TYPECHANGE
|
2503 GIT_DIFF_INCLUDE_TYPECHANGE_TREES
|
2504 GIT_DIFF_SKIP_BINARY_CHECK
|
2505 GIT_DIFF_INCLUDE_CASECHANGE
;
2506 if (data
.opts
.checkout_strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
)
2507 diff_opts
.flags
|= GIT_DIFF_DISABLE_PATHSPEC_MATCH
;
2508 if (data
.opts
.paths
.count
> 0)
2509 diff_opts
.pathspec
= data
.opts
.paths
;
2511 /* set up iterators */
2513 workdir_opts
.flags
= git_iterator_ignore_case(target
) ?
2514 GIT_ITERATOR_IGNORE_CASE
: GIT_ITERATOR_DONT_IGNORE_CASE
;
2515 workdir_opts
.flags
|= GIT_ITERATOR_DONT_AUTOEXPAND
;
2516 workdir_opts
.start
= data
.pfx
;
2517 workdir_opts
.end
= data
.pfx
;
2519 if ((error
= git_iterator_reset(target
, data
.pfx
, data
.pfx
)) < 0 ||
2520 (error
= git_iterator_for_workdir_ext(
2521 &workdir
, data
.repo
, data
.opts
.target_directory
, index
, NULL
,
2522 &workdir_opts
)) < 0)
2525 baseline_opts
.flags
= git_iterator_ignore_case(target
) ?
2526 GIT_ITERATOR_IGNORE_CASE
: GIT_ITERATOR_DONT_IGNORE_CASE
;
2527 baseline_opts
.start
= data
.pfx
;
2528 baseline_opts
.end
= data
.pfx
;
2530 if (data
.opts
.baseline_index
) {
2531 if ((error
= git_iterator_for_index(
2532 &baseline
, git_index_owner(data
.opts
.baseline_index
),
2533 data
.opts
.baseline_index
, &baseline_opts
)) < 0)
2536 if ((error
= git_iterator_for_tree(
2537 &baseline
, data
.opts
.baseline
, &baseline_opts
)) < 0)
2541 /* Should not have case insensitivity mismatch */
2542 assert(git_iterator_ignore_case(workdir
) == git_iterator_ignore_case(baseline
));
2544 /* Generate baseline-to-target diff which will include an entry for
2545 * every possible update that might need to be made.
2547 if ((error
= git_diff__from_iterators(
2548 &data
.diff
, data
.repo
, baseline
, target
, &diff_opts
)) < 0)
2551 /* Loop through diff (and working directory iterator) building a list of
2552 * actions to be taken, plus look for conflicts and send notifications,
2553 * then loop through conflicts.
2555 if ((error
= checkout_get_actions(&actions
, &counts
, &data
, workdir
)) != 0)
2558 data
.total_steps
= counts
[CHECKOUT_ACTION__REMOVE
] +
2559 counts
[CHECKOUT_ACTION__REMOVE_CONFLICT
] +
2560 counts
[CHECKOUT_ACTION__UPDATE_BLOB
] +
2561 counts
[CHECKOUT_ACTION__UPDATE_SUBMODULE
] +
2562 counts
[CHECKOUT_ACTION__UPDATE_CONFLICT
];
2564 report_progress(&data
, NULL
); /* establish 0 baseline */
2566 /* To deal with some order dependencies, perform remaining checkout
2567 * in three passes: removes, then update blobs, then update submodules.
2569 if (counts
[CHECKOUT_ACTION__REMOVE
] > 0 &&
2570 (error
= checkout_remove_the_old(actions
, &data
)) < 0)
2573 if (counts
[CHECKOUT_ACTION__REMOVE_CONFLICT
] > 0 &&
2574 (error
= checkout_remove_conflicts(&data
)) < 0)
2577 if (counts
[CHECKOUT_ACTION__UPDATE_BLOB
] > 0 &&
2578 (error
= checkout_create_the_new(actions
, &data
)) < 0)
2581 if (counts
[CHECKOUT_ACTION__UPDATE_SUBMODULE
] > 0 &&
2582 (error
= checkout_create_submodules(actions
, &data
)) < 0)
2585 if (counts
[CHECKOUT_ACTION__UPDATE_CONFLICT
] > 0 &&
2586 (error
= checkout_create_conflicts(&data
)) < 0)
2589 if (data
.index
!= git_iterator_get_index(target
) &&
2590 (error
= checkout_extensions_update_index(&data
)) < 0)
2593 assert(data
.completed_steps
== data
.total_steps
);
2595 if (data
.opts
.perfdata_cb
)
2596 data
.opts
.perfdata_cb(&data
.perfdata
, data
.opts
.perfdata_payload
);
2599 if (!error
&& data
.index
!= NULL
&&
2600 (data
.strategy
& CHECKOUT_INDEX_DONT_WRITE_MASK
) == 0)
2601 error
= git_index_write(data
.index
);
2603 git_diff_free(data
.diff
);
2604 git_iterator_free(workdir
);
2605 git_iterator_free(baseline
);
2608 checkout_data_clear(&data
);
2613 int git_checkout_index(
2614 git_repository
*repo
,
2616 const git_checkout_options
*opts
)
2618 int error
, owned
= 0;
2619 git_iterator
*index_i
;
2621 if (!index
&& !repo
) {
2622 giterr_set(GITERR_CHECKOUT
,
2623 "Must provide either repository or index to checkout");
2627 if (index
&& repo
&&
2628 git_index_owner(index
) &&
2629 git_index_owner(index
) != repo
) {
2630 giterr_set(GITERR_CHECKOUT
,
2631 "Index to checkout does not match repository");
2633 } else if(index
&& repo
&& !git_index_owner(index
)) {
2634 GIT_REFCOUNT_OWN(index
, repo
);
2639 repo
= git_index_owner(index
);
2641 if (!index
&& (error
= git_repository_index__weakptr(&index
, repo
)) < 0)
2643 GIT_REFCOUNT_INC(index
);
2645 if (!(error
= git_iterator_for_index(&index_i
, repo
, index
, NULL
)))
2646 error
= git_checkout_iterator(index_i
, index
, opts
);
2649 GIT_REFCOUNT_OWN(index
, NULL
);
2651 git_iterator_free(index_i
);
2652 git_index_free(index
);
2657 int git_checkout_tree(
2658 git_repository
*repo
,
2659 const git_object
*treeish
,
2660 const git_checkout_options
*opts
)
2664 git_tree
*tree
= NULL
;
2665 git_iterator
*tree_i
= NULL
;
2666 git_iterator_options iter_opts
= GIT_ITERATOR_OPTIONS_INIT
;
2668 if (!treeish
&& !repo
) {
2669 giterr_set(GITERR_CHECKOUT
,
2670 "Must provide either repository or tree to checkout");
2673 if (treeish
&& repo
&& git_object_owner(treeish
) != repo
) {
2674 giterr_set(GITERR_CHECKOUT
,
2675 "Object to checkout does not match repository");
2680 repo
= git_object_owner(treeish
);
2683 if (git_object_peel((git_object
**)&tree
, treeish
, GIT_OBJ_TREE
) < 0) {
2685 GITERR_CHECKOUT
, "Provided object cannot be peeled to a tree");
2690 if ((error
= checkout_lookup_head_tree(&tree
, repo
)) < 0) {
2691 if (error
!= GIT_EUNBORNBRANCH
)
2694 "HEAD could not be peeled to a tree and no treeish given");
2699 if ((error
= git_repository_index(&index
, repo
)) < 0)
2702 if ((opts
->checkout_strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
)) {
2703 iter_opts
.pathlist
.count
= opts
->paths
.count
;
2704 iter_opts
.pathlist
.strings
= opts
->paths
.strings
;
2707 if (!(error
= git_iterator_for_tree(&tree_i
, tree
, &iter_opts
)))
2708 error
= git_checkout_iterator(tree_i
, index
, opts
);
2710 git_iterator_free(tree_i
);
2711 git_index_free(index
);
2712 git_tree_free(tree
);
2717 int git_checkout_head(
2718 git_repository
*repo
,
2719 const git_checkout_options
*opts
)
2722 return git_checkout_tree(repo
, NULL
, opts
);
2725 int git_checkout_init_options(git_checkout_options
*opts
, unsigned int version
)
2727 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2728 opts
, version
, git_checkout_options
, GIT_CHECKOUT_OPTIONS_INIT
);