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.
10 #include "git2/repository.h"
11 #include "git2/refs.h"
12 #include "git2/tree.h"
13 #include "git2/blob.h"
14 #include "git2/config.h"
15 #include "git2/diff.h"
16 #include "git2/submodule.h"
17 #include "git2/sys/index.h"
18 #include "git2/sys/filter.h"
19 #include "git2/merge.h"
22 #include "repository.h"
27 #include "diff_generate.h"
30 #include "diff_xdiff.h"
36 /* See docs/checkout-internals.md for more information */
39 CHECKOUT_ACTION__NONE
= 0,
40 CHECKOUT_ACTION__REMOVE
= 1,
41 CHECKOUT_ACTION__UPDATE_BLOB
= 2,
42 CHECKOUT_ACTION__UPDATE_SUBMODULE
= 4,
43 CHECKOUT_ACTION__CONFLICT
= 8,
44 CHECKOUT_ACTION__REMOVE_CONFLICT
= 16,
45 CHECKOUT_ACTION__UPDATE_CONFLICT
= 32,
46 CHECKOUT_ACTION__MAX
= 32,
47 CHECKOUT_ACTION__DEFER_REMOVE
= 64,
48 CHECKOUT_ACTION__REMOVE_AND_UPDATE
=
49 (CHECKOUT_ACTION__UPDATE_BLOB
| CHECKOUT_ACTION__REMOVE
),
56 git_checkout_options opts
;
57 bool opts_free_baseline
;
62 git_vector remove_conflicts
;
63 git_vector update_conflicts
;
64 git_vector
*update_reuc
;
65 git_vector
*update_names
;
69 unsigned int strategy
;
72 bool reload_submodules
;
74 size_t completed_steps
;
75 git_checkout_perfdata perfdata
;
76 git_strmap
*mkdir_map
;
77 git_attr_session attr_session
;
81 const git_index_entry
*ancestor
;
82 const git_index_entry
*ours
;
83 const git_index_entry
*theirs
;
90 } checkout_conflictdata
;
92 static int checkout_notify(
94 git_checkout_notify_t why
,
95 const git_diff_delta
*delta
,
96 const git_index_entry
*wditem
)
99 const git_diff_file
*baseline
= NULL
, *target
= NULL
, *workdir
= NULL
;
100 const char *path
= NULL
;
102 if (!data
->opts
.notify_cb
||
103 (why
& data
->opts
.notify_flags
) == 0)
107 memset(&wdfile
, 0, sizeof(wdfile
));
109 git_oid_cpy(&wdfile
.id
, &wditem
->id
);
110 wdfile
.path
= wditem
->path
;
111 wdfile
.size
= wditem
->file_size
;
112 wdfile
.flags
= GIT_DIFF_FLAG_VALID_ID
;
113 wdfile
.mode
= wditem
->mode
;
121 switch (delta
->status
) {
122 case GIT_DELTA_UNMODIFIED
:
123 case GIT_DELTA_MODIFIED
:
124 case GIT_DELTA_TYPECHANGE
:
126 baseline
= &delta
->old_file
;
127 target
= &delta
->new_file
;
129 case GIT_DELTA_ADDED
:
130 case GIT_DELTA_IGNORED
:
131 case GIT_DELTA_UNTRACKED
:
132 case GIT_DELTA_UNREADABLE
:
133 target
= &delta
->new_file
;
135 case GIT_DELTA_DELETED
:
136 baseline
= &delta
->old_file
;
140 path
= delta
->old_file
.path
;
144 int error
= data
->opts
.notify_cb(
145 why
, path
, baseline
, target
, workdir
, data
->opts
.notify_payload
);
147 return git_error_set_after_callback_function(
148 error
, "git_checkout notification");
152 GIT_INLINE(bool) is_workdir_base_or_new(
153 const git_oid
*workdir_id
,
154 const git_diff_file
*baseitem
,
155 const git_diff_file
*newitem
)
157 return (git_oid__cmp(&baseitem
->id
, workdir_id
) == 0 ||
158 git_oid__cmp(&newitem
->id
, workdir_id
) == 0);
161 GIT_INLINE(bool) is_filemode_changed(git_filemode_t a
, git_filemode_t b
, int respect_filemode
)
163 /* If core.filemode = false, ignore links in the repository and executable bit changes */
164 if (!respect_filemode
) {
166 a
= GIT_FILEMODE_BLOB
;
168 b
= GIT_FILEMODE_BLOB
;
177 static bool checkout_is_workdir_modified(
179 const git_diff_file
*baseitem
,
180 const git_diff_file
*newitem
,
181 const git_index_entry
*wditem
)
184 const git_index_entry
*ie
;
186 /* handle "modified" submodule */
187 if (wditem
->mode
== GIT_FILEMODE_COMMIT
) {
189 unsigned int sm_status
= 0;
190 const git_oid
*sm_oid
= NULL
;
193 if (git_submodule_lookup(&sm
, data
->repo
, wditem
->path
) < 0) {
198 if (git_submodule_status(&sm_status
, data
->repo
, wditem
->path
, GIT_SUBMODULE_IGNORE_UNSPECIFIED
) < 0 ||
199 GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status
))
201 else if ((sm_oid
= git_submodule_wd_id(sm
)) == NULL
)
204 rval
= (git_oid__cmp(&baseitem
->id
, sm_oid
) != 0);
206 git_submodule_free(sm
);
211 * Look at the cache to decide if the workdir is modified: if the
212 * cache contents match the workdir contents, then we do not need
213 * to examine the working directory directly, instead we can
214 * examine the cache to see if _it_ has been modified. This allows
215 * us to avoid touching the disk.
217 ie
= git_index_get_bypath(data
->index
, wditem
->path
, 0);
220 git_index_time_eq(&wditem
->mtime
, &ie
->mtime
) &&
221 wditem
->file_size
== ie
->file_size
&&
222 !is_filemode_changed(wditem
->mode
, ie
->mode
, data
->respect_filemode
)) {
224 /* The workdir is modified iff the index entry is modified */
225 return !is_workdir_base_or_new(&ie
->id
, baseitem
, newitem
) ||
226 is_filemode_changed(baseitem
->mode
, ie
->mode
, data
->respect_filemode
);
229 /* depending on where base is coming from, we may or may not know
230 * the actual size of the data, so we can't rely on this shortcut.
232 if (baseitem
->size
&& wditem
->file_size
!= baseitem
->size
)
235 /* if the workdir item is a directory, it cannot be a modified file */
236 if (S_ISDIR(wditem
->mode
))
239 if (is_filemode_changed(baseitem
->mode
, wditem
->mode
, data
->respect_filemode
))
242 if (git_diff__oid_for_entry(&oid
, data
->diff
, wditem
, wditem
->mode
, NULL
) < 0)
245 /* Allow the checkout if the workdir is not modified *or* if the checkout
246 * target's contents are already in the working directory.
248 return !is_workdir_base_or_new(&oid
, baseitem
, newitem
);
251 #define CHECKOUT_ACTION_IF(FLAG,YES,NO) \
252 ((data->strategy & GIT_CHECKOUT_##FLAG) ? CHECKOUT_ACTION__##YES : CHECKOUT_ACTION__##NO)
254 static int checkout_action_common(
257 const git_diff_delta
*delta
,
258 const git_index_entry
*wd
)
260 git_checkout_notify_t notify
= GIT_CHECKOUT_NOTIFY_NONE
;
262 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0)
263 *action
= (*action
& ~CHECKOUT_ACTION__REMOVE
);
265 if ((*action
& CHECKOUT_ACTION__UPDATE_BLOB
) != 0) {
266 if (S_ISGITLINK(delta
->new_file
.mode
))
267 *action
= (*action
& ~CHECKOUT_ACTION__UPDATE_BLOB
) |
268 CHECKOUT_ACTION__UPDATE_SUBMODULE
;
270 /* to "update" a symlink, we must remove the old one first */
271 if (delta
->new_file
.mode
== GIT_FILEMODE_LINK
&& wd
!= NULL
)
272 *action
|= CHECKOUT_ACTION__REMOVE
;
274 /* if the file is on disk and doesn't match our mode, force update */
276 GIT_PERMS_IS_EXEC(wd
->mode
) !=
277 GIT_PERMS_IS_EXEC(delta
->new_file
.mode
))
278 *action
|= CHECKOUT_ACTION__REMOVE
;
280 notify
= GIT_CHECKOUT_NOTIFY_UPDATED
;
283 if ((*action
& CHECKOUT_ACTION__CONFLICT
) != 0)
284 notify
= GIT_CHECKOUT_NOTIFY_CONFLICT
;
286 return checkout_notify(data
, notify
, delta
, wd
);
289 static int checkout_action_no_wd(
292 const git_diff_delta
*delta
)
296 *action
= CHECKOUT_ACTION__NONE
;
298 switch (delta
->status
) {
299 case GIT_DELTA_UNMODIFIED
: /* case 12 */
300 error
= checkout_notify(data
, GIT_CHECKOUT_NOTIFY_DIRTY
, delta
, NULL
);
303 *action
= CHECKOUT_ACTION_IF(RECREATE_MISSING
, UPDATE_BLOB
, NONE
);
305 case GIT_DELTA_ADDED
: /* case 2 or 28 (and 5 but not really) */
306 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
308 case GIT_DELTA_MODIFIED
: /* case 13 (and 35 but not really) */
309 *action
= CHECKOUT_ACTION_IF(RECREATE_MISSING
, UPDATE_BLOB
, CONFLICT
);
311 case GIT_DELTA_TYPECHANGE
: /* case 21 (B->T) and 28 (T->B)*/
312 if (delta
->new_file
.mode
== GIT_FILEMODE_TREE
)
313 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
315 case GIT_DELTA_DELETED
: /* case 8 or 25 */
316 *action
= CHECKOUT_ACTION_IF(SAFE
, REMOVE
, NONE
);
318 default: /* impossible */
322 return checkout_action_common(action
, data
, delta
, NULL
);
325 static int checkout_target_fullpath(
326 git_buf
**out
, checkout_data
*data
, const char *path
)
328 git_buf_truncate(&data
->target_path
, data
->target_len
);
330 if (path
&& git_buf_puts(&data
->target_path
, path
) < 0)
333 *out
= &data
->target_path
;
338 static bool wd_item_is_removable(
339 checkout_data
*data
, const git_index_entry
*wd
)
343 if (wd
->mode
!= GIT_FILEMODE_TREE
)
346 if (checkout_target_fullpath(&full
, data
, wd
->path
) < 0)
349 return !full
|| !git_path_contains(full
, DOT_GIT
);
352 static int checkout_queue_remove(checkout_data
*data
, const char *path
)
354 char *copy
= git_pool_strdup(&data
->pool
, path
);
355 GIT_ERROR_CHECK_ALLOC(copy
);
356 return git_vector_insert(&data
->removes
, copy
);
359 /* note that this advances the iterator over the wd item */
360 static int checkout_action_wd_only(
362 git_iterator
*workdir
,
363 const git_index_entry
**wditem
,
364 git_vector
*pathspec
)
368 git_checkout_notify_t notify
= GIT_CHECKOUT_NOTIFY_NONE
;
369 const git_index_entry
*wd
= *wditem
;
371 if (!git_pathspec__match(
373 (data
->strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
) != 0,
374 git_iterator_ignore_case(workdir
), NULL
, NULL
))
375 return git_iterator_advance(wditem
, workdir
);
377 /* check if item is tracked in the index but not in the checkout diff */
378 if (data
->index
!= NULL
) {
381 error
= git_index__find_pos(
382 &pos
, data
->index
, wd
->path
, 0, GIT_INDEX_STAGE_ANY
);
384 if (wd
->mode
!= GIT_FILEMODE_TREE
) {
385 if (!error
) { /* found by git_index__find_pos call */
386 notify
= GIT_CHECKOUT_NOTIFY_DIRTY
;
387 remove
= ((data
->strategy
& GIT_CHECKOUT_FORCE
) != 0);
388 } else if (error
!= GIT_ENOTFOUND
)
391 error
= 0; /* git_index__find_pos does not set error msg */
393 /* for tree entries, we have to see if there are any index
394 * entries that are contained inside that tree
396 const git_index_entry
*e
= git_index_get_byindex(data
->index
, pos
);
398 if (e
!= NULL
&& data
->diff
->pfxcomp(e
->path
, wd
->path
) == 0)
399 return git_iterator_advance_into(wditem
, workdir
);
403 if (notify
!= GIT_CHECKOUT_NOTIFY_NONE
) {
404 /* if we found something in the index, notify and advance */
405 if ((error
= checkout_notify(data
, notify
, NULL
, wd
)) != 0)
408 if (remove
&& wd_item_is_removable(data
, wd
))
409 error
= checkout_queue_remove(data
, wd
->path
);
412 error
= git_iterator_advance(wditem
, workdir
);
414 /* untracked or ignored - can't know which until we advance through */
415 bool over
= false, removable
= wd_item_is_removable(data
, wd
);
416 git_iterator_status_t untracked_state
;
418 /* copy the entry for issuing notification callback later */
419 git_index_entry saved_wd
= *wd
;
420 git_buf_sets(&data
->tmp
, wd
->path
);
421 saved_wd
.path
= data
->tmp
.ptr
;
423 error
= git_iterator_advance_over(
424 wditem
, &untracked_state
, workdir
);
425 if (error
== GIT_ITEROVER
)
430 if (untracked_state
== GIT_ITERATOR_STATUS_IGNORED
) {
431 notify
= GIT_CHECKOUT_NOTIFY_IGNORED
;
432 remove
= ((data
->strategy
& GIT_CHECKOUT_REMOVE_IGNORED
) != 0);
434 notify
= GIT_CHECKOUT_NOTIFY_UNTRACKED
;
435 remove
= ((data
->strategy
& GIT_CHECKOUT_REMOVE_UNTRACKED
) != 0);
438 if ((error
= checkout_notify(data
, notify
, NULL
, &saved_wd
)) != 0)
441 if (remove
&& removable
)
442 error
= checkout_queue_remove(data
, saved_wd
.path
);
444 if (!error
&& over
) /* restore ITEROVER if needed */
445 error
= GIT_ITEROVER
;
451 static bool submodule_is_config_only(
455 git_submodule
*sm
= NULL
;
456 unsigned int sm_loc
= 0;
459 if (git_submodule_lookup(&sm
, data
->repo
, path
) < 0)
462 if (git_submodule_location(&sm_loc
, sm
) < 0 ||
463 sm_loc
== GIT_SUBMODULE_STATUS_IN_CONFIG
)
466 git_submodule_free(sm
);
471 static bool checkout_is_empty_dir(checkout_data
*data
, const char *path
)
475 if (checkout_target_fullpath(&fullpath
, data
, path
) < 0)
478 return git_path_is_empty_dir(fullpath
->ptr
);
481 static int checkout_action_with_wd(
484 const git_diff_delta
*delta
,
485 git_iterator
*workdir
,
486 const git_index_entry
*wd
)
488 *action
= CHECKOUT_ACTION__NONE
;
490 switch (delta
->status
) {
491 case GIT_DELTA_UNMODIFIED
: /* case 14/15 or 33 */
492 if (checkout_is_workdir_modified(data
, &delta
->old_file
, &delta
->new_file
, wd
)) {
493 GIT_ERROR_CHECK_ERROR(
494 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_DIRTY
, delta
, wd
) );
495 *action
= CHECKOUT_ACTION_IF(FORCE
, UPDATE_BLOB
, NONE
);
498 case GIT_DELTA_ADDED
: /* case 3, 4 or 6 */
499 if (git_iterator_current_is_ignored(workdir
))
500 *action
= CHECKOUT_ACTION_IF(DONT_OVERWRITE_IGNORED
, CONFLICT
, UPDATE_BLOB
);
502 *action
= CHECKOUT_ACTION_IF(FORCE
, UPDATE_BLOB
, CONFLICT
);
504 case GIT_DELTA_DELETED
: /* case 9 or 10 (or 26 but not really) */
505 if (checkout_is_workdir_modified(data
, &delta
->old_file
, &delta
->new_file
, wd
))
506 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE
, CONFLICT
);
508 *action
= CHECKOUT_ACTION_IF(SAFE
, REMOVE
, NONE
);
510 case GIT_DELTA_MODIFIED
: /* case 16, 17, 18 (or 36 but not really) */
511 if (wd
->mode
!= GIT_FILEMODE_COMMIT
&&
512 checkout_is_workdir_modified(data
, &delta
->old_file
, &delta
->new_file
, wd
))
513 *action
= CHECKOUT_ACTION_IF(FORCE
, UPDATE_BLOB
, CONFLICT
);
515 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
517 case GIT_DELTA_TYPECHANGE
: /* case 22, 23, 29, 30 */
518 if (delta
->old_file
.mode
== GIT_FILEMODE_TREE
) {
519 if (wd
->mode
== GIT_FILEMODE_TREE
)
520 /* either deleting items in old tree will delete the wd dir,
521 * or we'll get a conflict when we attempt blob update...
523 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
524 else if (wd
->mode
== GIT_FILEMODE_COMMIT
) {
525 /* workdir is possibly a "phantom" submodule - treat as a
526 * tree if the only submodule info came from the config
528 if (submodule_is_config_only(data
, wd
->path
))
529 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
531 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
533 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE
, CONFLICT
);
535 else if (checkout_is_workdir_modified(data
, &delta
->old_file
, &delta
->new_file
, wd
))
536 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
538 *action
= CHECKOUT_ACTION_IF(SAFE
, REMOVE_AND_UPDATE
, NONE
);
540 /* don't update if the typechange is to a tree */
541 if (delta
->new_file
.mode
== GIT_FILEMODE_TREE
)
542 *action
= (*action
& ~CHECKOUT_ACTION__UPDATE_BLOB
);
544 default: /* impossible */
548 return checkout_action_common(action
, data
, delta
, wd
);
551 static int checkout_action_with_wd_blocker(
554 const git_diff_delta
*delta
,
555 const git_index_entry
*wd
)
557 *action
= CHECKOUT_ACTION__NONE
;
559 switch (delta
->status
) {
560 case GIT_DELTA_UNMODIFIED
:
561 /* should show delta as dirty / deleted */
562 GIT_ERROR_CHECK_ERROR(
563 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_DIRTY
, delta
, wd
) );
564 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, NONE
);
566 case GIT_DELTA_ADDED
:
567 case GIT_DELTA_MODIFIED
:
568 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
570 case GIT_DELTA_DELETED
:
571 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE
, CONFLICT
);
573 case GIT_DELTA_TYPECHANGE
:
574 /* not 100% certain about this... */
575 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
577 default: /* impossible */
581 return checkout_action_common(action
, data
, delta
, wd
);
584 static int checkout_action_with_wd_dir(
587 const git_diff_delta
*delta
,
588 git_iterator
*workdir
,
589 const git_index_entry
*wd
)
591 *action
= CHECKOUT_ACTION__NONE
;
593 switch (delta
->status
) {
594 case GIT_DELTA_UNMODIFIED
: /* case 19 or 24 (or 34 but not really) */
595 GIT_ERROR_CHECK_ERROR(
596 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_DIRTY
, delta
, NULL
));
597 GIT_ERROR_CHECK_ERROR(
598 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_UNTRACKED
, NULL
, wd
));
599 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, NONE
);
601 case GIT_DELTA_ADDED
:/* case 4 (and 7 for dir) */
602 case GIT_DELTA_MODIFIED
: /* case 20 (or 37 but not really) */
603 if (delta
->old_file
.mode
== GIT_FILEMODE_COMMIT
)
604 /* expected submodule (and maybe found one) */;
605 else if (delta
->new_file
.mode
!= GIT_FILEMODE_TREE
)
606 *action
= git_iterator_current_is_ignored(workdir
) ?
607 CHECKOUT_ACTION_IF(DONT_OVERWRITE_IGNORED
, CONFLICT
, REMOVE_AND_UPDATE
) :
608 CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
610 case GIT_DELTA_DELETED
: /* case 11 (and 27 for dir) */
611 if (delta
->old_file
.mode
!= GIT_FILEMODE_TREE
)
612 GIT_ERROR_CHECK_ERROR(
613 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_UNTRACKED
, NULL
, wd
));
615 case GIT_DELTA_TYPECHANGE
: /* case 24 or 31 */
616 if (delta
->old_file
.mode
== GIT_FILEMODE_TREE
) {
617 /* For typechange from dir, remove dir and add blob, but it is
618 * not safe to remove dir if it contains modified files.
619 * However, safely removing child files will remove the parent
620 * directory if is it left empty, so we can defer removing the
621 * dir and it will succeed if no children are left.
623 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
625 else if (delta
->new_file
.mode
!= GIT_FILEMODE_TREE
)
626 /* For typechange to dir, dir is already created so no action */
627 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
629 default: /* impossible */
633 return checkout_action_common(action
, data
, delta
, wd
);
636 static int checkout_action_with_wd_dir_empty(
639 const git_diff_delta
*delta
)
641 int error
= checkout_action_no_wd(action
, data
, delta
);
643 /* We can always safely remove an empty directory. */
644 if (error
== 0 && *action
!= CHECKOUT_ACTION__NONE
)
645 *action
|= CHECKOUT_ACTION__REMOVE
;
650 static int checkout_action(
653 git_diff_delta
*delta
,
654 git_iterator
*workdir
,
655 const git_index_entry
**wditem
,
656 git_vector
*pathspec
)
659 int (*strcomp
)(const char *, const char *) = data
->diff
->strcomp
;
660 int (*pfxcomp
)(const char *str
, const char *pfx
) = data
->diff
->pfxcomp
;
661 int (*advance
)(const git_index_entry
**, git_iterator
*) = NULL
;
663 /* move workdir iterator to follow along with deltas */
666 const git_index_entry
*wd
= *wditem
;
669 return checkout_action_no_wd(action
, data
, delta
);
671 cmp
= strcomp(wd
->path
, delta
->old_file
.path
);
673 /* 1. wd before delta ("a/a" before "a/b")
674 * 2. wd prefixes delta & should expand ("a/" before "a/b")
675 * 3. wd prefixes delta & cannot expand ("a/b" before "a/b/c")
676 * 4. wd equals delta ("a/b" and "a/b")
677 * 5. wd after delta & delta prefixes wd ("a/b/c" after "a/b/" or "a/b")
678 * 6. wd after delta ("a/c" after "a/b")
682 cmp
= pfxcomp(delta
->old_file
.path
, wd
->path
);
685 if (wd
->mode
== GIT_FILEMODE_TREE
) {
686 /* case 2 - entry prefixed by workdir tree */
687 error
= git_iterator_advance_into(wditem
, workdir
);
688 if (error
< 0 && error
!= GIT_ITEROVER
)
693 /* case 3 maybe - wd contains non-dir where dir expected */
694 if (delta
->old_file
.path
[strlen(wd
->path
)] == '/') {
695 error
= checkout_action_with_wd_blocker(
696 action
, data
, delta
, wd
);
697 advance
= git_iterator_advance
;
702 /* case 1 - handle wd item (if it matches pathspec) */
703 error
= checkout_action_wd_only(data
, workdir
, wditem
, pathspec
);
704 if (error
&& error
!= GIT_ITEROVER
)
711 error
= checkout_action_with_wd(action
, data
, delta
, workdir
, wd
);
712 advance
= git_iterator_advance
;
716 cmp
= pfxcomp(wd
->path
, delta
->old_file
.path
);
718 if (cmp
== 0) { /* case 5 */
719 if (wd
->path
[strlen(delta
->old_file
.path
)] != '/')
720 return checkout_action_no_wd(action
, data
, delta
);
722 if (delta
->status
== GIT_DELTA_TYPECHANGE
) {
723 if (delta
->old_file
.mode
== GIT_FILEMODE_TREE
) {
724 error
= checkout_action_with_wd(action
, data
, delta
, workdir
, wd
);
725 advance
= git_iterator_advance_into
;
729 if (delta
->new_file
.mode
== GIT_FILEMODE_TREE
||
730 delta
->new_file
.mode
== GIT_FILEMODE_COMMIT
||
731 delta
->old_file
.mode
== GIT_FILEMODE_COMMIT
)
733 error
= checkout_action_with_wd(action
, data
, delta
, workdir
, wd
);
734 advance
= git_iterator_advance
;
739 return checkout_is_empty_dir(data
, wd
->path
) ?
740 checkout_action_with_wd_dir_empty(action
, data
, delta
) :
741 checkout_action_with_wd_dir(action
, data
, delta
, workdir
, wd
);
744 /* case 6 - wd is after delta */
745 return checkout_action_no_wd(action
, data
, delta
);
749 if (!error
&& advance
!= NULL
&&
750 (error
= advance(wditem
, workdir
)) < 0) {
752 if (error
== GIT_ITEROVER
)
759 static int checkout_remaining_wd_items(
761 git_iterator
*workdir
,
762 const git_index_entry
*wd
,
768 error
= checkout_action_wd_only(data
, workdir
, &wd
, spec
);
770 if (error
== GIT_ITEROVER
)
776 GIT_INLINE(int) checkout_idxentry_cmp(
777 const git_index_entry
*a
,
778 const git_index_entry
*b
)
787 return strcmp(a
->path
, b
->path
);
790 static int checkout_conflictdata_cmp(const void *a
, const void *b
)
792 const checkout_conflictdata
*ca
= a
;
793 const checkout_conflictdata
*cb
= b
;
796 if ((diff
= checkout_idxentry_cmp(ca
->ancestor
, cb
->ancestor
)) == 0 &&
797 (diff
= checkout_idxentry_cmp(ca
->ours
, cb
->theirs
)) == 0)
798 diff
= checkout_idxentry_cmp(ca
->theirs
, cb
->theirs
);
803 int checkout_conflictdata_empty(
804 const git_vector
*conflicts
, size_t idx
, void *payload
)
806 checkout_conflictdata
*conflict
;
810 if ((conflict
= git_vector_get(conflicts
, idx
)) == NULL
)
813 if (conflict
->ancestor
|| conflict
->ours
|| conflict
->theirs
)
820 GIT_INLINE(bool) conflict_pathspec_match(
822 git_iterator
*workdir
,
823 git_vector
*pathspec
,
824 const git_index_entry
*ancestor
,
825 const git_index_entry
*ours
,
826 const git_index_entry
*theirs
)
828 /* if the pathspec matches ours *or* theirs, proceed */
829 if (ours
&& git_pathspec__match(pathspec
, ours
->path
,
830 (data
->strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
) != 0,
831 git_iterator_ignore_case(workdir
), NULL
, NULL
))
834 if (theirs
&& git_pathspec__match(pathspec
, theirs
->path
,
835 (data
->strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
) != 0,
836 git_iterator_ignore_case(workdir
), NULL
, NULL
))
839 if (ancestor
&& git_pathspec__match(pathspec
, ancestor
->path
,
840 (data
->strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
) != 0,
841 git_iterator_ignore_case(workdir
), NULL
, NULL
))
847 GIT_INLINE(int) checkout_conflict_detect_submodule(checkout_conflictdata
*conflict
)
849 conflict
->submodule
= ((conflict
->ancestor
&& S_ISGITLINK(conflict
->ancestor
->mode
)) ||
850 (conflict
->ours
&& S_ISGITLINK(conflict
->ours
->mode
)) ||
851 (conflict
->theirs
&& S_ISGITLINK(conflict
->theirs
->mode
)));
855 GIT_INLINE(int) checkout_conflict_detect_binary(git_repository
*repo
, checkout_conflictdata
*conflict
)
857 git_blob
*ancestor_blob
= NULL
, *our_blob
= NULL
, *their_blob
= NULL
;
860 if (conflict
->submodule
)
863 if (conflict
->ancestor
) {
864 if ((error
= git_blob_lookup(&ancestor_blob
, repo
, &conflict
->ancestor
->id
)) < 0)
867 conflict
->binary
= git_blob_is_binary(ancestor_blob
);
870 if (!conflict
->binary
&& conflict
->ours
) {
871 if ((error
= git_blob_lookup(&our_blob
, repo
, &conflict
->ours
->id
)) < 0)
874 conflict
->binary
= git_blob_is_binary(our_blob
);
877 if (!conflict
->binary
&& conflict
->theirs
) {
878 if ((error
= git_blob_lookup(&their_blob
, repo
, &conflict
->theirs
->id
)) < 0)
881 conflict
->binary
= git_blob_is_binary(their_blob
);
885 git_blob_free(ancestor_blob
);
886 git_blob_free(our_blob
);
887 git_blob_free(their_blob
);
892 static int checkout_conflict_append_update(
893 const git_index_entry
*ancestor
,
894 const git_index_entry
*ours
,
895 const git_index_entry
*theirs
,
898 checkout_data
*data
= payload
;
899 checkout_conflictdata
*conflict
;
902 conflict
= git__calloc(1, sizeof(checkout_conflictdata
));
903 GIT_ERROR_CHECK_ALLOC(conflict
);
905 conflict
->ancestor
= ancestor
;
906 conflict
->ours
= ours
;
907 conflict
->theirs
= theirs
;
909 if ((error
= checkout_conflict_detect_submodule(conflict
)) < 0 ||
910 (error
= checkout_conflict_detect_binary(data
->repo
, conflict
)) < 0)
916 if (git_vector_insert(&data
->update_conflicts
, conflict
))
922 static int checkout_conflicts_foreach(
925 git_iterator
*workdir
,
926 git_vector
*pathspec
,
927 int (*cb
)(const git_index_entry
*, const git_index_entry
*, const git_index_entry
*, void *),
930 git_index_conflict_iterator
*iterator
= NULL
;
931 const git_index_entry
*ancestor
, *ours
, *theirs
;
934 if ((error
= git_index_conflict_iterator_new(&iterator
, index
)) < 0)
937 /* Collect the conflicts */
938 while ((error
= git_index_conflict_next(&ancestor
, &ours
, &theirs
, iterator
)) == 0) {
939 if (!conflict_pathspec_match(data
, workdir
, pathspec
, ancestor
, ours
, theirs
))
942 if ((error
= cb(ancestor
, ours
, theirs
, payload
)) < 0)
946 if (error
== GIT_ITEROVER
)
950 git_index_conflict_iterator_free(iterator
);
955 static int checkout_conflicts_load(checkout_data
*data
, git_iterator
*workdir
, git_vector
*pathspec
)
959 /* Only write conficts from sources that have them: indexes. */
960 if ((index
= git_iterator_index(data
->target
)) == NULL
)
963 data
->update_conflicts
._cmp
= checkout_conflictdata_cmp
;
965 if (checkout_conflicts_foreach(data
, index
, workdir
, pathspec
, checkout_conflict_append_update
, data
) < 0)
968 /* Collect the REUC and NAME entries */
969 data
->update_reuc
= &index
->reuc
;
970 data
->update_names
= &index
->names
;
975 GIT_INLINE(int) checkout_conflicts_cmp_entry(
977 const git_index_entry
*entry
)
979 return strcmp((const char *)path
, entry
->path
);
982 static int checkout_conflicts_cmp_ancestor(const void *p
, const void *c
)
984 const char *path
= p
;
985 const checkout_conflictdata
*conflict
= c
;
987 if (!conflict
->ancestor
)
990 return checkout_conflicts_cmp_entry(path
, conflict
->ancestor
);
993 static checkout_conflictdata
*checkout_conflicts_search_ancestor(
999 if (git_vector_bsearch2(&pos
, &data
->update_conflicts
, checkout_conflicts_cmp_ancestor
, path
) < 0)
1002 return git_vector_get(&data
->update_conflicts
, pos
);
1005 static checkout_conflictdata
*checkout_conflicts_search_branch(
1006 checkout_data
*data
,
1009 checkout_conflictdata
*conflict
;
1012 git_vector_foreach(&data
->update_conflicts
, i
, conflict
) {
1015 if (conflict
->ancestor
)
1019 cmp
= checkout_conflicts_cmp_entry(path
, conflict
->ours
);
1020 else if (conflict
->theirs
)
1021 cmp
= checkout_conflicts_cmp_entry(path
, conflict
->theirs
);
1030 static int checkout_conflicts_load_byname_entry(
1031 checkout_conflictdata
**ancestor_out
,
1032 checkout_conflictdata
**ours_out
,
1033 checkout_conflictdata
**theirs_out
,
1034 checkout_data
*data
,
1035 const git_index_name_entry
*name_entry
)
1037 checkout_conflictdata
*ancestor
, *ours
= NULL
, *theirs
= NULL
;
1040 *ancestor_out
= NULL
;
1044 if (!name_entry
->ancestor
) {
1045 git_error_set(GIT_ERROR_INDEX
, "a NAME entry exists without an ancestor");
1050 if (!name_entry
->ours
&& !name_entry
->theirs
) {
1051 git_error_set(GIT_ERROR_INDEX
, "a NAME entry exists without an ours or theirs");
1056 if ((ancestor
= checkout_conflicts_search_ancestor(data
,
1057 name_entry
->ancestor
)) == NULL
) {
1058 git_error_set(GIT_ERROR_INDEX
,
1059 "a NAME entry referenced ancestor entry '%s' which does not exist in the main index",
1060 name_entry
->ancestor
);
1065 if (name_entry
->ours
) {
1066 if (strcmp(name_entry
->ancestor
, name_entry
->ours
) == 0)
1068 else if ((ours
= checkout_conflicts_search_branch(data
, name_entry
->ours
)) == NULL
||
1069 ours
->ours
== NULL
) {
1070 git_error_set(GIT_ERROR_INDEX
,
1071 "a NAME entry referenced our entry '%s' which does not exist in the main index",
1078 if (name_entry
->theirs
) {
1079 if (strcmp(name_entry
->ancestor
, name_entry
->theirs
) == 0)
1081 else if (name_entry
->ours
&& strcmp(name_entry
->ours
, name_entry
->theirs
) == 0)
1083 else if ((theirs
= checkout_conflicts_search_branch(data
, name_entry
->theirs
)) == NULL
||
1084 theirs
->theirs
== NULL
) {
1085 git_error_set(GIT_ERROR_INDEX
,
1086 "a NAME entry referenced their entry '%s' which does not exist in the main index",
1087 name_entry
->theirs
);
1093 *ancestor_out
= ancestor
;
1095 *theirs_out
= theirs
;
1101 static int checkout_conflicts_coalesce_renames(
1102 checkout_data
*data
)
1105 const git_index_name_entry
*name_entry
;
1106 checkout_conflictdata
*ancestor_conflict
, *our_conflict
, *their_conflict
;
1110 if ((index
= git_iterator_index(data
->target
)) == NULL
)
1113 /* Juggle entries based on renames */
1114 names
= git_index_name_entrycount(index
);
1116 for (i
= 0; i
< names
; i
++) {
1117 name_entry
= git_index_name_get_byindex(index
, i
);
1119 if ((error
= checkout_conflicts_load_byname_entry(
1120 &ancestor_conflict
, &our_conflict
, &their_conflict
,
1121 data
, name_entry
)) < 0)
1124 if (our_conflict
&& our_conflict
!= ancestor_conflict
) {
1125 ancestor_conflict
->ours
= our_conflict
->ours
;
1126 our_conflict
->ours
= NULL
;
1128 if (our_conflict
->theirs
)
1129 our_conflict
->name_collision
= 1;
1131 if (our_conflict
->name_collision
)
1132 ancestor_conflict
->name_collision
= 1;
1135 if (their_conflict
&& their_conflict
!= ancestor_conflict
) {
1136 ancestor_conflict
->theirs
= their_conflict
->theirs
;
1137 their_conflict
->theirs
= NULL
;
1139 if (their_conflict
->ours
)
1140 their_conflict
->name_collision
= 1;
1142 if (their_conflict
->name_collision
)
1143 ancestor_conflict
->name_collision
= 1;
1146 if (our_conflict
&& our_conflict
!= ancestor_conflict
&&
1147 their_conflict
&& their_conflict
!= ancestor_conflict
)
1148 ancestor_conflict
->one_to_two
= 1;
1151 git_vector_remove_matching(
1152 &data
->update_conflicts
, checkout_conflictdata_empty
, NULL
);
1158 static int checkout_conflicts_mark_directoryfile(
1159 checkout_data
*data
)
1162 checkout_conflictdata
*conflict
;
1163 const git_index_entry
*entry
;
1166 int prefixed
, error
= 0;
1168 if ((index
= git_iterator_index(data
->target
)) == NULL
)
1171 len
= git_index_entrycount(index
);
1173 /* Find d/f conflicts */
1174 git_vector_foreach(&data
->update_conflicts
, i
, conflict
) {
1175 if ((conflict
->ours
&& conflict
->theirs
) ||
1176 (!conflict
->ours
&& !conflict
->theirs
))
1179 path
= conflict
->ours
?
1180 conflict
->ours
->path
: conflict
->theirs
->path
;
1182 if ((error
= git_index_find(&j
, index
, path
)) < 0) {
1183 if (error
== GIT_ENOTFOUND
)
1184 git_error_set(GIT_ERROR_INDEX
,
1185 "index inconsistency, could not find entry for expected conflict '%s'", path
);
1190 for (; j
< len
; j
++) {
1191 if ((entry
= git_index_get_byindex(index
, j
)) == NULL
) {
1192 git_error_set(GIT_ERROR_INDEX
,
1193 "index inconsistency, truncated index while loading expected conflict '%s'", path
);
1198 prefixed
= git_path_equal_or_prefixed(path
, entry
->path
, NULL
);
1200 if (prefixed
== GIT_PATH_EQUAL
)
1203 if (prefixed
== GIT_PATH_PREFIX
)
1204 conflict
->directoryfile
= 1;
1214 static int checkout_get_update_conflicts(
1215 checkout_data
*data
,
1216 git_iterator
*workdir
,
1217 git_vector
*pathspec
)
1221 if (data
->strategy
& GIT_CHECKOUT_SKIP_UNMERGED
)
1224 if ((error
= checkout_conflicts_load(data
, workdir
, pathspec
)) < 0 ||
1225 (error
= checkout_conflicts_coalesce_renames(data
)) < 0 ||
1226 (error
= checkout_conflicts_mark_directoryfile(data
)) < 0)
1233 static int checkout_conflict_append_remove(
1234 const git_index_entry
*ancestor
,
1235 const git_index_entry
*ours
,
1236 const git_index_entry
*theirs
,
1239 checkout_data
*data
= payload
;
1242 assert(ancestor
|| ours
|| theirs
);
1245 name
= git__strdup(ancestor
->path
);
1247 name
= git__strdup(ours
->path
);
1249 name
= git__strdup(theirs
->path
);
1253 GIT_ERROR_CHECK_ALLOC(name
);
1255 return git_vector_insert(&data
->remove_conflicts
, (char *)name
);
1258 static int checkout_get_remove_conflicts(
1259 checkout_data
*data
,
1260 git_iterator
*workdir
,
1261 git_vector
*pathspec
)
1263 if ((data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) != 0)
1266 return checkout_conflicts_foreach(data
, data
->index
, workdir
, pathspec
, checkout_conflict_append_remove
, data
);
1269 static int checkout_verify_paths(
1270 git_repository
*repo
,
1272 git_diff_delta
*delta
)
1274 unsigned int flags
= GIT_PATH_REJECT_WORKDIR_DEFAULTS
;
1276 if (action
& CHECKOUT_ACTION__REMOVE
) {
1277 if (!git_path_isvalid(repo
, delta
->old_file
.path
, delta
->old_file
.mode
, flags
)) {
1278 git_error_set(GIT_ERROR_CHECKOUT
, "cannot remove invalid path '%s'", delta
->old_file
.path
);
1283 if (action
& ~CHECKOUT_ACTION__REMOVE
) {
1284 if (!git_path_isvalid(repo
, delta
->new_file
.path
, delta
->new_file
.mode
, flags
)) {
1285 git_error_set(GIT_ERROR_CHECKOUT
, "cannot checkout to invalid path '%s'", delta
->new_file
.path
);
1293 static int checkout_get_actions(
1294 uint32_t **actions_ptr
,
1295 size_t **counts_ptr
,
1296 checkout_data
*data
,
1297 git_iterator
*workdir
)
1300 const git_index_entry
*wditem
;
1301 git_vector pathspec
= GIT_VECTOR_INIT
, *deltas
;
1303 git_diff_delta
*delta
;
1304 size_t i
, *counts
= NULL
;
1305 uint32_t *actions
= NULL
;
1307 git_pool_init(&pathpool
, 1);
1309 if (data
->opts
.paths
.count
> 0 &&
1310 git_pathspec__vinit(&pathspec
, &data
->opts
.paths
, &pathpool
) < 0)
1313 if ((error
= git_iterator_current(&wditem
, workdir
)) < 0 &&
1314 error
!= GIT_ITEROVER
)
1317 deltas
= &data
->diff
->deltas
;
1319 *counts_ptr
= counts
= git__calloc(CHECKOUT_ACTION__MAX
+1, sizeof(size_t));
1320 *actions_ptr
= actions
= git__calloc(
1321 deltas
->length
? deltas
->length
: 1, sizeof(uint32_t));
1322 if (!counts
|| !actions
) {
1327 git_vector_foreach(deltas
, i
, delta
) {
1328 if ((error
= checkout_action(&act
, data
, delta
, workdir
, &wditem
, &pathspec
)) == 0)
1329 error
= checkout_verify_paths(data
->repo
, act
, delta
);
1336 if (act
& CHECKOUT_ACTION__REMOVE
)
1337 counts
[CHECKOUT_ACTION__REMOVE
]++;
1338 if (act
& CHECKOUT_ACTION__UPDATE_BLOB
)
1339 counts
[CHECKOUT_ACTION__UPDATE_BLOB
]++;
1340 if (act
& CHECKOUT_ACTION__UPDATE_SUBMODULE
)
1341 counts
[CHECKOUT_ACTION__UPDATE_SUBMODULE
]++;
1342 if (act
& CHECKOUT_ACTION__CONFLICT
)
1343 counts
[CHECKOUT_ACTION__CONFLICT
]++;
1346 error
= checkout_remaining_wd_items(data
, workdir
, wditem
, &pathspec
);
1350 counts
[CHECKOUT_ACTION__REMOVE
] += data
->removes
.length
;
1352 if (counts
[CHECKOUT_ACTION__CONFLICT
] > 0 &&
1353 (data
->strategy
& GIT_CHECKOUT_ALLOW_CONFLICTS
) == 0)
1355 git_error_set(GIT_ERROR_CHECKOUT
, "%"PRIuZ
" %s checkout",
1356 counts
[CHECKOUT_ACTION__CONFLICT
],
1357 counts
[CHECKOUT_ACTION__CONFLICT
] == 1 ?
1358 "conflict prevents" : "conflicts prevent");
1359 error
= GIT_ECONFLICT
;
1364 if ((error
= checkout_get_remove_conflicts(data
, workdir
, &pathspec
)) < 0 ||
1365 (error
= checkout_get_update_conflicts(data
, workdir
, &pathspec
)) < 0)
1368 counts
[CHECKOUT_ACTION__REMOVE_CONFLICT
] = git_vector_length(&data
->remove_conflicts
);
1369 counts
[CHECKOUT_ACTION__UPDATE_CONFLICT
] = git_vector_length(&data
->update_conflicts
);
1371 git_pathspec__vfree(&pathspec
);
1372 git_pool_clear(&pathpool
);
1379 *actions_ptr
= NULL
;
1382 git_pathspec__vfree(&pathspec
);
1383 git_pool_clear(&pathpool
);
1388 static bool should_remove_existing(checkout_data
*data
)
1392 if (git_repository__configmap_lookup(&ignorecase
, data
->repo
, GIT_CONFIGMAP_IGNORECASE
) < 0) {
1396 return (ignorecase
&&
1397 (data
->strategy
& GIT_CHECKOUT_DONT_REMOVE_EXISTING
) == 0);
1400 #define MKDIR_NORMAL \
1401 GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR
1402 #define MKDIR_REMOVE_EXISTING \
1403 MKDIR_NORMAL | GIT_MKDIR_REMOVE_FILES | GIT_MKDIR_REMOVE_SYMLINKS
1405 static int checkout_mkdir(
1406 checkout_data
*data
,
1412 struct git_futils_mkdir_options mkdir_opts
= {0};
1415 mkdir_opts
.dir_map
= data
->mkdir_map
;
1416 mkdir_opts
.pool
= &data
->pool
;
1418 error
= git_futils_mkdir_relative(
1419 path
, base
, mode
, flags
, &mkdir_opts
);
1421 data
->perfdata
.mkdir_calls
+= mkdir_opts
.perfdata
.mkdir_calls
;
1422 data
->perfdata
.stat_calls
+= mkdir_opts
.perfdata
.stat_calls
;
1423 data
->perfdata
.chmod_calls
+= mkdir_opts
.perfdata
.chmod_calls
;
1428 static int mkpath2file(
1429 checkout_data
*data
, const char *path
, unsigned int mode
)
1432 bool remove_existing
= should_remove_existing(data
);
1433 unsigned int flags
=
1434 (remove_existing
? MKDIR_REMOVE_EXISTING
: MKDIR_NORMAL
) |
1435 GIT_MKDIR_SKIP_LAST
;
1438 if ((error
= checkout_mkdir(
1439 data
, path
, data
->opts
.target_directory
, mode
, flags
)) < 0)
1442 if (remove_existing
) {
1443 data
->perfdata
.stat_calls
++;
1445 if (p_lstat(path
, &st
) == 0) {
1447 /* Some file, symlink or folder already exists at this name.
1448 * We would have removed it in remove_the_old unless we're on
1449 * a case inensitive filesystem (or the user has asked us not
1450 * to). Remove the similarly named file to write the new.
1452 error
= git_futils_rmdir_r(path
, NULL
, GIT_RMDIR_REMOVE_FILES
);
1453 } else if (errno
!= ENOENT
) {
1454 git_error_set(GIT_ERROR_OS
, "failed to stat '%s'", path
);
1464 struct checkout_stream
{
1465 git_writestream base
;
1471 static int checkout_stream_write(
1472 git_writestream
*s
, const char *buffer
, size_t len
)
1474 struct checkout_stream
*stream
= (struct checkout_stream
*)s
;
1477 if ((ret
= p_write(stream
->fd
, buffer
, len
)) < 0)
1478 git_error_set(GIT_ERROR_OS
, "could not write to '%s'", stream
->path
);
1483 static int checkout_stream_close(git_writestream
*s
)
1485 struct checkout_stream
*stream
= (struct checkout_stream
*)s
;
1486 assert(stream
&& stream
->open
);
1489 return p_close(stream
->fd
);
1492 static void checkout_stream_free(git_writestream
*s
)
1497 static int blob_content_to_file(
1498 checkout_data
*data
,
1502 const char *hint_path
,
1503 mode_t entry_filemode
)
1505 int flags
= data
->opts
.file_open_flags
;
1506 mode_t file_mode
= data
->opts
.file_mode
?
1507 data
->opts
.file_mode
: entry_filemode
;
1508 git_filter_options filter_opts
= GIT_FILTER_OPTIONS_INIT
;
1509 struct checkout_stream writer
;
1511 git_filter_list
*fl
= NULL
;
1515 if (hint_path
== NULL
)
1518 if ((error
= mkpath2file(data
, path
, data
->opts
.dir_mode
)) < 0)
1522 flags
= O_CREAT
| O_TRUNC
| O_WRONLY
;
1523 if (!(mode
= file_mode
))
1524 mode
= GIT_FILEMODE_BLOB
;
1526 if ((fd
= p_open(path
, flags
, mode
)) < 0) {
1527 git_error_set(GIT_ERROR_OS
, "could not open '%s' for writing", path
);
1531 filter_opts
.attr_session
= &data
->attr_session
;
1532 filter_opts
.temp_buf
= &data
->tmp
;
1534 if (!data
->opts
.disable_filters
&&
1535 (error
= git_filter_list__load_ext(
1536 &fl
, data
->repo
, blob
, hint_path
,
1537 GIT_FILTER_TO_WORKTREE
, &filter_opts
))) {
1542 /* setup the writer */
1543 memset(&writer
, 0, sizeof(struct checkout_stream
));
1544 writer
.base
.write
= checkout_stream_write
;
1545 writer
.base
.close
= checkout_stream_close
;
1546 writer
.base
.free
= checkout_stream_free
;
1551 error
= git_filter_list_stream_blob(fl
, blob
, &writer
.base
);
1553 assert(writer
.open
== 0);
1555 git_filter_list_free(fl
);
1561 data
->perfdata
.stat_calls
++;
1563 if ((error
= p_stat(path
, st
)) < 0) {
1564 git_error_set(GIT_ERROR_OS
, "failed to stat '%s'", path
);
1568 st
->st_mode
= entry_filemode
;
1574 static int blob_content_to_link(
1575 checkout_data
*data
,
1580 git_buf linktarget
= GIT_BUF_INIT
;
1583 if ((error
= mkpath2file(data
, path
, data
->opts
.dir_mode
)) < 0)
1586 if ((error
= git_blob__getbuf(&linktarget
, blob
)) < 0)
1589 if (data
->can_symlink
) {
1590 if ((error
= p_symlink(git_buf_cstr(&linktarget
), path
)) < 0)
1591 git_error_set(GIT_ERROR_OS
, "could not create symlink %s", path
);
1593 error
= git_futils_fake_symlink(git_buf_cstr(&linktarget
), path
);
1597 data
->perfdata
.stat_calls
++;
1599 if ((error
= p_lstat(path
, st
)) < 0)
1600 git_error_set(GIT_ERROR_CHECKOUT
, "could not stat symlink %s", path
);
1602 st
->st_mode
= GIT_FILEMODE_LINK
;
1605 git_buf_dispose(&linktarget
);
1610 static int checkout_update_index(
1611 checkout_data
*data
,
1612 const git_diff_file
*file
,
1615 git_index_entry entry
;
1620 memset(&entry
, 0, sizeof(entry
));
1621 entry
.path
= (char *)file
->path
; /* cast to prevent warning */
1622 git_index_entry__init_from_stat(&entry
, st
, true);
1623 git_oid_cpy(&entry
.id
, &file
->id
);
1625 return git_index_add(data
->index
, &entry
);
1628 static int checkout_submodule_update_index(
1629 checkout_data
*data
,
1630 const git_diff_file
*file
)
1635 /* update the index unless prevented */
1636 if ((data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) != 0)
1639 if (checkout_target_fullpath(&fullpath
, data
, file
->path
) < 0)
1642 data
->perfdata
.stat_calls
++;
1643 if (p_stat(fullpath
->ptr
, &st
) < 0) {
1645 GIT_ERROR_CHECKOUT
, "could not stat submodule %s\n", file
->path
);
1646 return GIT_ENOTFOUND
;
1649 st
.st_mode
= GIT_FILEMODE_COMMIT
;
1651 return checkout_update_index(data
, file
, &st
);
1654 static int checkout_submodule(
1655 checkout_data
*data
,
1656 const git_diff_file
*file
)
1658 bool remove_existing
= should_remove_existing(data
);
1661 /* Until submodules are supported, UPDATE_ONLY means do nothing here */
1662 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0)
1665 if ((error
= checkout_mkdir(
1667 file
->path
, data
->opts
.target_directory
, data
->opts
.dir_mode
,
1668 remove_existing
? MKDIR_REMOVE_EXISTING
: MKDIR_NORMAL
)) < 0)
1671 if ((error
= git_submodule_lookup(NULL
, data
->repo
, file
->path
)) < 0) {
1672 /* I've observed repos with submodules in the tree that do not
1673 * have a .gitmodules - core Git just makes an empty directory
1675 if (error
== GIT_ENOTFOUND
) {
1677 return checkout_submodule_update_index(data
, file
);
1683 /* TODO: Support checkout_strategy options. Two circumstances:
1684 * 1 - submodule already checked out, but we need to move the HEAD
1685 * to the new OID, or
1686 * 2 - submodule not checked out and we should recursively check it out
1688 * Checkout will not execute a pull on the submodule, but a clone
1689 * command should probably be able to. Do we need a submodule callback?
1692 return checkout_submodule_update_index(data
, file
);
1695 static void report_progress(
1696 checkout_data
*data
,
1699 if (data
->opts
.progress_cb
)
1700 data
->opts
.progress_cb(
1701 path
, data
->completed_steps
, data
->total_steps
,
1702 data
->opts
.progress_payload
);
1705 static int checkout_safe_for_update_only(
1706 checkout_data
*data
, const char *path
, mode_t expected_mode
)
1710 data
->perfdata
.stat_calls
++;
1712 if (p_lstat(path
, &st
) < 0) {
1713 /* if doesn't exist, then no error and no update */
1714 if (errno
== ENOENT
|| errno
== ENOTDIR
)
1717 /* otherwise, stat error and no update */
1718 git_error_set(GIT_ERROR_OS
, "failed to stat '%s'", path
);
1722 /* only safe for update if this is the same type of file */
1723 if ((st
.st_mode
& ~0777) == (expected_mode
& ~0777))
1729 static int checkout_write_content(
1730 checkout_data
*data
,
1732 const char *full_path
,
1733 const char *hint_path
,
1740 if ((error
= git_blob_lookup(&blob
, data
->repo
, oid
)) < 0)
1744 error
= blob_content_to_link(data
, st
, blob
, full_path
);
1746 error
= blob_content_to_file(data
, st
, blob
, full_path
, hint_path
, mode
);
1748 git_blob_free(blob
);
1750 /* if we try to create the blob and an existing directory blocks it from
1751 * being written, then there must have been a typechange conflict in a
1752 * parent directory - suppress the error and try to continue.
1754 if ((data
->strategy
& GIT_CHECKOUT_ALLOW_CONFLICTS
) != 0 &&
1755 (error
== GIT_ENOTFOUND
|| error
== GIT_EEXISTS
))
1764 static int checkout_blob(
1765 checkout_data
*data
,
1766 const git_diff_file
*file
)
1772 if (checkout_target_fullpath(&fullpath
, data
, file
->path
) < 0)
1775 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0) {
1776 int rval
= checkout_safe_for_update_only(
1777 data
, fullpath
->ptr
, file
->mode
);
1783 error
= checkout_write_content(
1784 data
, &file
->id
, fullpath
->ptr
, NULL
, file
->mode
, &st
);
1786 /* update the index unless prevented */
1787 if (!error
&& (data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) == 0)
1788 error
= checkout_update_index(data
, file
, &st
);
1790 /* update the submodule data if this was a new .gitmodules file */
1791 if (!error
&& strcmp(file
->path
, ".gitmodules") == 0)
1792 data
->reload_submodules
= true;
1797 static int checkout_remove_the_old(
1798 unsigned int *actions
,
1799 checkout_data
*data
)
1802 git_diff_delta
*delta
;
1806 uint32_t flg
= GIT_RMDIR_EMPTY_PARENTS
|
1807 GIT_RMDIR_REMOVE_FILES
| GIT_RMDIR_REMOVE_BLOCKERS
;
1809 if (data
->opts
.checkout_strategy
& GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES
)
1810 flg
|= GIT_RMDIR_SKIP_NONEMPTY
;
1812 if (checkout_target_fullpath(&fullpath
, data
, NULL
) < 0)
1815 git_vector_foreach(&data
->diff
->deltas
, i
, delta
) {
1816 if (actions
[i
] & CHECKOUT_ACTION__REMOVE
) {
1817 error
= git_futils_rmdir_r(
1818 delta
->old_file
.path
, fullpath
->ptr
, flg
);
1823 data
->completed_steps
++;
1824 report_progress(data
, delta
->old_file
.path
);
1826 if ((actions
[i
] & CHECKOUT_ACTION__UPDATE_BLOB
) == 0 &&
1827 (data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) == 0 &&
1828 data
->index
!= NULL
)
1830 (void)git_index_remove(data
->index
, delta
->old_file
.path
, 0);
1835 git_vector_foreach(&data
->removes
, i
, str
) {
1836 error
= git_futils_rmdir_r(str
, fullpath
->ptr
, flg
);
1840 data
->completed_steps
++;
1841 report_progress(data
, str
);
1843 if ((data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) == 0 &&
1844 data
->index
!= NULL
)
1846 if (str
[strlen(str
) - 1] == '/')
1847 (void)git_index_remove_directory(data
->index
, str
, 0);
1849 (void)git_index_remove(data
->index
, str
, 0);
1856 static int checkout_deferred_remove(git_repository
*repo
, const char *path
)
1859 int error
= git_futils_rmdir_r(
1860 path
, data
->opts
.target_directory
, GIT_RMDIR_EMPTY_PARENTS
);
1862 if (error
== GIT_ENOTFOUND
) {
1876 static int checkout_create_the_new(
1877 unsigned int *actions
,
1878 checkout_data
*data
)
1881 git_diff_delta
*delta
;
1884 git_vector_foreach(&data
->diff
->deltas
, i
, delta
) {
1885 if (actions
[i
] & CHECKOUT_ACTION__DEFER_REMOVE
) {
1886 /* this had a blocker directory that should only be removed iff
1887 * all of the contents of the directory were safely removed
1889 if ((error
= checkout_deferred_remove(
1890 data
->repo
, delta
->old_file
.path
)) < 0)
1894 if (actions
[i
] & CHECKOUT_ACTION__UPDATE_BLOB
&& !S_ISLNK(delta
->new_file
.mode
)) {
1895 if ((error
= checkout_blob(data
, &delta
->new_file
)) < 0)
1897 data
->completed_steps
++;
1898 report_progress(data
, delta
->new_file
.path
);
1902 git_vector_foreach(&data
->diff
->deltas
, i
, delta
) {
1903 if (actions
[i
] & CHECKOUT_ACTION__UPDATE_BLOB
&& S_ISLNK(delta
->new_file
.mode
)) {
1904 if ((error
= checkout_blob(data
, &delta
->new_file
)) < 0)
1906 data
->completed_steps
++;
1907 report_progress(data
, delta
->new_file
.path
);
1914 static int checkout_create_submodules(
1915 unsigned int *actions
,
1916 checkout_data
*data
)
1919 git_diff_delta
*delta
;
1922 git_vector_foreach(&data
->diff
->deltas
, i
, delta
) {
1923 if (actions
[i
] & CHECKOUT_ACTION__DEFER_REMOVE
) {
1924 /* this has a blocker directory that should only be removed iff
1925 * all of the contents of the directory were safely removed
1927 if ((error
= checkout_deferred_remove(
1928 data
->repo
, delta
->old_file
.path
)) < 0)
1932 if (actions
[i
] & CHECKOUT_ACTION__UPDATE_SUBMODULE
) {
1933 int error
= checkout_submodule(data
, &delta
->new_file
);
1937 data
->completed_steps
++;
1938 report_progress(data
, delta
->new_file
.path
);
1945 static int checkout_lookup_head_tree(git_tree
**out
, git_repository
*repo
)
1948 git_reference
*ref
= NULL
;
1951 if (!(error
= git_repository_head(&ref
, repo
)) &&
1952 !(error
= git_reference_peel(&head
, ref
, GIT_OBJECT_TREE
)))
1953 *out
= (git_tree
*)head
;
1955 git_reference_free(ref
);
1961 static int conflict_entry_name(
1963 const char *side_name
,
1964 const char *filename
)
1966 if (git_buf_puts(out
, side_name
) < 0 ||
1967 git_buf_putc(out
, ':') < 0 ||
1968 git_buf_puts(out
, filename
) < 0)
1974 static int checkout_path_suffixed(git_buf
*path
, const char *suffix
)
1977 int i
= 0, error
= 0;
1979 if ((error
= git_buf_putc(path
, '~')) < 0 || (error
= git_buf_puts(path
, suffix
)) < 0)
1982 path_len
= git_buf_len(path
);
1984 while (git_path_exists(git_buf_cstr(path
)) && i
< INT_MAX
) {
1985 git_buf_truncate(path
, path_len
);
1987 if ((error
= git_buf_putc(path
, '_')) < 0 ||
1988 (error
= git_buf_printf(path
, "%d", i
)) < 0)
1995 git_buf_truncate(path
, path_len
);
1997 git_error_set(GIT_ERROR_CHECKOUT
, "could not write '%s': working directory file exists", path
->ptr
);
2004 static int checkout_write_entry(
2005 checkout_data
*data
,
2006 checkout_conflictdata
*conflict
,
2007 const git_index_entry
*side
)
2009 const char *hint_path
= NULL
, *suffix
;
2014 assert (side
== conflict
->ours
|| side
== conflict
->theirs
);
2016 if (checkout_target_fullpath(&fullpath
, data
, side
->path
) < 0)
2019 if ((conflict
->name_collision
|| conflict
->directoryfile
) &&
2020 (data
->strategy
& GIT_CHECKOUT_USE_OURS
) == 0 &&
2021 (data
->strategy
& GIT_CHECKOUT_USE_THEIRS
) == 0) {
2023 if (side
== conflict
->ours
)
2024 suffix
= data
->opts
.our_label
? data
->opts
.our_label
:
2027 suffix
= data
->opts
.their_label
? data
->opts
.their_label
:
2030 if (checkout_path_suffixed(fullpath
, suffix
) < 0)
2033 hint_path
= side
->path
;
2036 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0 &&
2037 (error
= checkout_safe_for_update_only(data
, fullpath
->ptr
, side
->mode
)) <= 0)
2040 if (!S_ISGITLINK(side
->mode
))
2041 return checkout_write_content(data
,
2042 &side
->id
, fullpath
->ptr
, hint_path
, side
->mode
, &st
);
2047 static int checkout_write_entries(
2048 checkout_data
*data
,
2049 checkout_conflictdata
*conflict
)
2053 if ((error
= checkout_write_entry(data
, conflict
, conflict
->ours
)) >= 0)
2054 error
= checkout_write_entry(data
, conflict
, conflict
->theirs
);
2059 static int checkout_merge_path(
2061 checkout_data
*data
,
2062 checkout_conflictdata
*conflict
,
2063 git_merge_file_result
*result
)
2065 const char *our_label_raw
, *their_label_raw
, *suffix
;
2068 if ((error
= git_buf_joinpath(out
, git_repository_workdir(data
->repo
), result
->path
)) < 0)
2071 /* Most conflicts simply use the filename in the index */
2072 if (!conflict
->name_collision
)
2075 /* Rename 2->1 conflicts need the branch name appended */
2076 our_label_raw
= data
->opts
.our_label
? data
->opts
.our_label
: "ours";
2077 their_label_raw
= data
->opts
.their_label
? data
->opts
.their_label
: "theirs";
2078 suffix
= strcmp(result
->path
, conflict
->ours
->path
) == 0 ? our_label_raw
: their_label_raw
;
2080 if ((error
= checkout_path_suffixed(out
, suffix
)) < 0)
2086 static int checkout_write_merge(
2087 checkout_data
*data
,
2088 checkout_conflictdata
*conflict
)
2090 git_buf our_label
= GIT_BUF_INIT
, their_label
= GIT_BUF_INIT
,
2091 path_suffixed
= GIT_BUF_INIT
, path_workdir
= GIT_BUF_INIT
,
2092 in_data
= GIT_BUF_INIT
, out_data
= GIT_BUF_INIT
;
2093 git_merge_file_options opts
= GIT_MERGE_FILE_OPTIONS_INIT
;
2094 git_merge_file_result result
= {0};
2095 git_filebuf output
= GIT_FILEBUF_INIT
;
2096 git_filter_list
*fl
= NULL
;
2097 git_filter_options filter_opts
= GIT_FILTER_OPTIONS_INIT
;
2100 if (data
->opts
.checkout_strategy
& GIT_CHECKOUT_CONFLICT_STYLE_DIFF3
)
2101 opts
.flags
|= GIT_MERGE_FILE_STYLE_DIFF3
;
2103 opts
.ancestor_label
= data
->opts
.ancestor_label
?
2104 data
->opts
.ancestor_label
: "ancestor";
2105 opts
.our_label
= data
->opts
.our_label
?
2106 data
->opts
.our_label
: "ours";
2107 opts
.their_label
= data
->opts
.their_label
?
2108 data
->opts
.their_label
: "theirs";
2110 /* If all the paths are identical, decorate the diff3 file with the branch
2111 * names. Otherwise, append branch_name:path.
2113 if (conflict
->ours
&& conflict
->theirs
&&
2114 strcmp(conflict
->ours
->path
, conflict
->theirs
->path
) != 0) {
2116 if ((error
= conflict_entry_name(
2117 &our_label
, opts
.our_label
, conflict
->ours
->path
)) < 0 ||
2118 (error
= conflict_entry_name(
2119 &their_label
, opts
.their_label
, conflict
->theirs
->path
)) < 0)
2122 opts
.our_label
= git_buf_cstr(&our_label
);
2123 opts
.their_label
= git_buf_cstr(&their_label
);
2126 if ((error
= git_merge_file_from_index(&result
, data
->repo
,
2127 conflict
->ancestor
, conflict
->ours
, conflict
->theirs
, &opts
)) < 0)
2130 if (result
.path
== NULL
|| result
.mode
== 0) {
2131 git_error_set(GIT_ERROR_CHECKOUT
, "could not merge contents of file");
2132 error
= GIT_ECONFLICT
;
2136 if ((error
= checkout_merge_path(&path_workdir
, data
, conflict
, &result
)) < 0)
2139 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0 &&
2140 (error
= checkout_safe_for_update_only(data
, git_buf_cstr(&path_workdir
), result
.mode
)) <= 0)
2143 if (!data
->opts
.disable_filters
) {
2144 in_data
.ptr
= (char *)result
.ptr
;
2145 in_data
.size
= result
.len
;
2147 filter_opts
.attr_session
= &data
->attr_session
;
2148 filter_opts
.temp_buf
= &data
->tmp
;
2150 if ((error
= git_filter_list__load_ext(
2151 &fl
, data
->repo
, NULL
, git_buf_cstr(&path_workdir
),
2152 GIT_FILTER_TO_WORKTREE
, &filter_opts
)) < 0 ||
2153 (error
= git_filter_list_apply_to_data(&out_data
, fl
, &in_data
)) < 0)
2156 out_data
.ptr
= (char *)result
.ptr
;
2157 out_data
.size
= result
.len
;
2160 if ((error
= mkpath2file(data
, path_workdir
.ptr
, data
->opts
.dir_mode
)) < 0 ||
2161 (error
= git_filebuf_open(&output
, git_buf_cstr(&path_workdir
), GIT_FILEBUF_DO_NOT_BUFFER
, result
.mode
)) < 0 ||
2162 (error
= git_filebuf_write(&output
, out_data
.ptr
, out_data
.size
)) < 0 ||
2163 (error
= git_filebuf_commit(&output
)) < 0)
2167 git_filter_list_free(fl
);
2169 git_buf_dispose(&out_data
);
2170 git_buf_dispose(&our_label
);
2171 git_buf_dispose(&their_label
);
2173 git_merge_file_result_free(&result
);
2174 git_buf_dispose(&path_workdir
);
2175 git_buf_dispose(&path_suffixed
);
2180 static int checkout_conflict_add(
2181 checkout_data
*data
,
2182 const git_index_entry
*conflict
)
2184 int error
= git_index_remove(data
->index
, conflict
->path
, 0);
2186 if (error
== GIT_ENOTFOUND
)
2191 return git_index_add(data
->index
, conflict
);
2194 static int checkout_conflict_update_index(
2195 checkout_data
*data
,
2196 checkout_conflictdata
*conflict
)
2200 if (conflict
->ancestor
)
2201 error
= checkout_conflict_add(data
, conflict
->ancestor
);
2203 if (!error
&& conflict
->ours
)
2204 error
= checkout_conflict_add(data
, conflict
->ours
);
2206 if (!error
&& conflict
->theirs
)
2207 error
= checkout_conflict_add(data
, conflict
->theirs
);
2212 static int checkout_create_conflicts(checkout_data
*data
)
2214 checkout_conflictdata
*conflict
;
2218 git_vector_foreach(&data
->update_conflicts
, i
, conflict
) {
2220 /* Both deleted: nothing to do */
2221 if (conflict
->ours
== NULL
&& conflict
->theirs
== NULL
)
2224 else if ((data
->strategy
& GIT_CHECKOUT_USE_OURS
) &&
2226 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2227 else if ((data
->strategy
& GIT_CHECKOUT_USE_THEIRS
) &&
2229 error
= checkout_write_entry(data
, conflict
, conflict
->theirs
);
2231 /* Ignore the other side of name collisions. */
2232 else if ((data
->strategy
& GIT_CHECKOUT_USE_OURS
) &&
2233 !conflict
->ours
&& conflict
->name_collision
)
2235 else if ((data
->strategy
& GIT_CHECKOUT_USE_THEIRS
) &&
2236 !conflict
->theirs
&& conflict
->name_collision
)
2239 /* For modify/delete, name collisions and d/f conflicts, write
2240 * the file (potentially with the name mangled.
2242 else if (conflict
->ours
!= NULL
&& conflict
->theirs
== NULL
)
2243 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2244 else if (conflict
->ours
== NULL
&& conflict
->theirs
!= NULL
)
2245 error
= checkout_write_entry(data
, conflict
, conflict
->theirs
);
2247 /* Add/add conflicts and rename 1->2 conflicts, write the
2248 * ours/theirs sides (potentially name mangled).
2250 else if (conflict
->one_to_two
)
2251 error
= checkout_write_entries(data
, conflict
);
2253 /* If all sides are links, write the ours side */
2254 else if (S_ISLNK(conflict
->ours
->mode
) &&
2255 S_ISLNK(conflict
->theirs
->mode
))
2256 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2257 /* Link/file conflicts, write the file side */
2258 else if (S_ISLNK(conflict
->ours
->mode
))
2259 error
= checkout_write_entry(data
, conflict
, conflict
->theirs
);
2260 else if (S_ISLNK(conflict
->theirs
->mode
))
2261 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2263 /* If any side is a gitlink, do nothing. */
2264 else if (conflict
->submodule
)
2267 /* If any side is binary, write the ours side */
2268 else if (conflict
->binary
)
2269 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2272 error
= checkout_write_merge(data
, conflict
);
2274 /* Update the index extensions (REUC and NAME) if we're checking
2275 * out a different index. (Otherwise just leave them there.)
2277 if (!error
&& (data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) == 0)
2278 error
= checkout_conflict_update_index(data
, conflict
);
2283 data
->completed_steps
++;
2284 report_progress(data
,
2285 conflict
->ours
? conflict
->ours
->path
:
2286 (conflict
->theirs
? conflict
->theirs
->path
: conflict
->ancestor
->path
));
2292 static int checkout_remove_conflicts(checkout_data
*data
)
2294 const char *conflict
;
2297 git_vector_foreach(&data
->remove_conflicts
, i
, conflict
) {
2298 if (git_index_conflict_remove(data
->index
, conflict
) < 0)
2301 data
->completed_steps
++;
2307 static int checkout_extensions_update_index(checkout_data
*data
)
2309 const git_index_reuc_entry
*reuc_entry
;
2310 const git_index_name_entry
*name_entry
;
2314 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0)
2317 if (data
->update_reuc
) {
2318 git_vector_foreach(data
->update_reuc
, i
, reuc_entry
) {
2319 if ((error
= git_index_reuc_add(data
->index
, reuc_entry
->path
,
2320 reuc_entry
->mode
[0], &reuc_entry
->oid
[0],
2321 reuc_entry
->mode
[1], &reuc_entry
->oid
[1],
2322 reuc_entry
->mode
[2], &reuc_entry
->oid
[2])) < 0)
2327 if (data
->update_names
) {
2328 git_vector_foreach(data
->update_names
, i
, name_entry
) {
2329 if ((error
= git_index_name_add(data
->index
, name_entry
->ancestor
,
2330 name_entry
->ours
, name_entry
->theirs
)) < 0)
2339 static void checkout_data_clear(checkout_data
*data
)
2341 if (data
->opts_free_baseline
) {
2342 git_tree_free(data
->opts
.baseline
);
2343 data
->opts
.baseline
= NULL
;
2346 git_vector_free(&data
->removes
);
2347 git_pool_clear(&data
->pool
);
2349 git_vector_free_deep(&data
->remove_conflicts
);
2350 git_vector_free_deep(&data
->update_conflicts
);
2352 git__free(data
->pfx
);
2355 git_buf_dispose(&data
->target_path
);
2356 git_buf_dispose(&data
->tmp
);
2358 git_index_free(data
->index
);
2361 git_strmap_free(data
->mkdir_map
);
2362 data
->mkdir_map
= NULL
;
2364 git_attr_session__free(&data
->attr_session
);
2367 static int checkout_data_init(
2368 checkout_data
*data
,
2369 git_iterator
*target
,
2370 const git_checkout_options
*proposed
)
2373 git_repository
*repo
= git_iterator_owner(target
);
2375 memset(data
, 0, sizeof(*data
));
2378 git_error_set(GIT_ERROR_CHECKOUT
, "cannot checkout nothing");
2382 if ((!proposed
|| !proposed
->target_directory
) &&
2383 (error
= git_repository__ensure_not_bare(repo
, "checkout")) < 0)
2387 data
->target
= target
;
2389 GIT_ERROR_CHECK_VERSION(
2390 proposed
, GIT_CHECKOUT_OPTIONS_VERSION
, "git_checkout_options");
2393 GIT_INIT_STRUCTURE(&data
->opts
, GIT_CHECKOUT_OPTIONS_VERSION
);
2395 memmove(&data
->opts
, proposed
, sizeof(git_checkout_options
));
2397 if (!data
->opts
.target_directory
)
2398 data
->opts
.target_directory
= git_repository_workdir(repo
);
2399 else if (!git_path_isdir(data
->opts
.target_directory
) &&
2400 (error
= checkout_mkdir(data
,
2401 data
->opts
.target_directory
, NULL
,
2402 GIT_DIR_MODE
, GIT_MKDIR_VERIFY_DIR
)) < 0)
2405 if ((error
= git_repository_index(&data
->index
, data
->repo
)) < 0)
2408 /* refresh config and index content unless NO_REFRESH is given */
2409 if ((data
->opts
.checkout_strategy
& GIT_CHECKOUT_NO_REFRESH
) == 0) {
2412 if ((error
= git_repository_config__weakptr(&cfg
, repo
)) < 0)
2415 /* Reload the repository index (unless we're checking out the
2416 * index; then it has the changes we're trying to check out
2417 * and those should not be overwritten.)
2419 if (data
->index
!= git_iterator_index(target
)) {
2420 if (data
->opts
.checkout_strategy
& GIT_CHECKOUT_FORCE
) {
2421 /* When forcing, we can blindly re-read the index */
2422 if ((error
= git_index_read(data
->index
, false)) < 0)
2426 * When not being forced, we need to check for unresolved
2427 * conflicts and unsaved changes in the index before
2430 if (git_index_has_conflicts(data
->index
)) {
2431 error
= GIT_ECONFLICT
;
2432 git_error_set(GIT_ERROR_CHECKOUT
,
2433 "unresolved conflicts exist in the index");
2437 if ((error
= git_index_read_safely(data
->index
)) < 0)
2441 /* clean conflict data in the current index */
2442 git_index_name_clear(data
->index
);
2443 git_index_reuc_clear(data
->index
);
2447 /* if you are forcing, allow all safe updates, plus recreate missing */
2448 if ((data
->opts
.checkout_strategy
& GIT_CHECKOUT_FORCE
) != 0)
2449 data
->opts
.checkout_strategy
|= GIT_CHECKOUT_SAFE
|
2450 GIT_CHECKOUT_RECREATE_MISSING
;
2452 /* if the repository does not actually have an index file, then this
2453 * is an initial checkout (perhaps from clone), so we allow safe updates
2455 if (!data
->index
->on_disk
&&
2456 (data
->opts
.checkout_strategy
& GIT_CHECKOUT_SAFE
) != 0)
2457 data
->opts
.checkout_strategy
|= GIT_CHECKOUT_RECREATE_MISSING
;
2459 data
->strategy
= data
->opts
.checkout_strategy
;
2461 /* opts->disable_filters is false by default */
2463 if (!data
->opts
.dir_mode
)
2464 data
->opts
.dir_mode
= GIT_DIR_MODE
;
2466 if (!data
->opts
.file_open_flags
)
2467 data
->opts
.file_open_flags
= O_CREAT
| O_TRUNC
| O_WRONLY
;
2469 data
->pfx
= git_pathspec_prefix(&data
->opts
.paths
);
2471 if ((error
= git_repository__configmap_lookup(
2472 &data
->can_symlink
, repo
, GIT_CONFIGMAP_SYMLINKS
)) < 0)
2475 if ((error
= git_repository__configmap_lookup(
2476 &data
->respect_filemode
, repo
, GIT_CONFIGMAP_FILEMODE
)) < 0)
2479 if (!data
->opts
.baseline
&& !data
->opts
.baseline_index
) {
2480 data
->opts_free_baseline
= true;
2483 /* if we don't have an index, this is an initial checkout and
2484 * should be against an empty baseline
2486 if (data
->index
->on_disk
)
2487 error
= checkout_lookup_head_tree(&data
->opts
.baseline
, repo
);
2489 if (error
== GIT_EUNBORNBRANCH
) {
2498 if ((data
->opts
.checkout_strategy
&
2499 (GIT_CHECKOUT_CONFLICT_STYLE_MERGE
| GIT_CHECKOUT_CONFLICT_STYLE_DIFF3
)) == 0) {
2500 git_config_entry
*conflict_style
= NULL
;
2501 git_config
*cfg
= NULL
;
2503 if ((error
= git_repository_config__weakptr(&cfg
, repo
)) < 0 ||
2504 (error
= git_config_get_entry(&conflict_style
, cfg
, "merge.conflictstyle")) < 0 ||
2505 error
== GIT_ENOTFOUND
)
2509 else if (strcmp(conflict_style
->value
, "merge") == 0)
2510 data
->opts
.checkout_strategy
|= GIT_CHECKOUT_CONFLICT_STYLE_MERGE
;
2511 else if (strcmp(conflict_style
->value
, "diff3") == 0)
2512 data
->opts
.checkout_strategy
|= GIT_CHECKOUT_CONFLICT_STYLE_DIFF3
;
2514 git_error_set(GIT_ERROR_CHECKOUT
, "unknown style '%s' given for 'merge.conflictstyle'",
2515 conflict_style
->value
);
2517 git_config_entry_free(conflict_style
);
2520 git_config_entry_free(conflict_style
);
2523 git_pool_init(&data
->pool
, 1);
2525 if ((error
= git_vector_init(&data
->removes
, 0, git__strcmp_cb
)) < 0 ||
2526 (error
= git_vector_init(&data
->remove_conflicts
, 0, NULL
)) < 0 ||
2527 (error
= git_vector_init(&data
->update_conflicts
, 0, NULL
)) < 0 ||
2528 (error
= git_buf_puts(&data
->target_path
, data
->opts
.target_directory
)) < 0 ||
2529 (error
= git_path_to_dir(&data
->target_path
)) < 0 ||
2530 (error
= git_strmap_new(&data
->mkdir_map
)) < 0)
2533 data
->target_len
= git_buf_len(&data
->target_path
);
2535 git_attr_session__init(&data
->attr_session
, data
->repo
);
2539 checkout_data_clear(data
);
2544 #define CHECKOUT_INDEX_DONT_WRITE_MASK \
2545 (GIT_CHECKOUT_DONT_UPDATE_INDEX | GIT_CHECKOUT_DONT_WRITE_INDEX)
2547 int git_checkout_iterator(
2548 git_iterator
*target
,
2550 const git_checkout_options
*opts
)
2553 git_iterator
*baseline
= NULL
, *workdir
= NULL
;
2554 git_iterator_options baseline_opts
= GIT_ITERATOR_OPTIONS_INIT
,
2555 workdir_opts
= GIT_ITERATOR_OPTIONS_INIT
;
2556 checkout_data data
= {0};
2557 git_diff_options diff_opts
= GIT_DIFF_OPTIONS_INIT
;
2558 uint32_t *actions
= NULL
;
2559 size_t *counts
= NULL
;
2561 /* initialize structures and options */
2562 error
= checkout_data_init(&data
, target
, opts
);
2567 GIT_DIFF_INCLUDE_UNMODIFIED
|
2568 GIT_DIFF_INCLUDE_UNREADABLE
|
2569 GIT_DIFF_INCLUDE_UNTRACKED
|
2570 GIT_DIFF_RECURSE_UNTRACKED_DIRS
| /* needed to match baseline */
2571 GIT_DIFF_INCLUDE_IGNORED
|
2572 GIT_DIFF_INCLUDE_TYPECHANGE
|
2573 GIT_DIFF_INCLUDE_TYPECHANGE_TREES
|
2574 GIT_DIFF_SKIP_BINARY_CHECK
|
2575 GIT_DIFF_INCLUDE_CASECHANGE
;
2576 if (data
.opts
.checkout_strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
)
2577 diff_opts
.flags
|= GIT_DIFF_DISABLE_PATHSPEC_MATCH
;
2578 if (data
.opts
.paths
.count
> 0)
2579 diff_opts
.pathspec
= data
.opts
.paths
;
2581 /* set up iterators */
2583 workdir_opts
.flags
= git_iterator_ignore_case(target
) ?
2584 GIT_ITERATOR_IGNORE_CASE
: GIT_ITERATOR_DONT_IGNORE_CASE
;
2585 workdir_opts
.flags
|= GIT_ITERATOR_DONT_AUTOEXPAND
;
2586 workdir_opts
.start
= data
.pfx
;
2587 workdir_opts
.end
= data
.pfx
;
2589 if ((error
= git_iterator_reset_range(target
, data
.pfx
, data
.pfx
)) < 0 ||
2590 (error
= git_iterator_for_workdir_ext(
2591 &workdir
, data
.repo
, data
.opts
.target_directory
, index
, NULL
,
2592 &workdir_opts
)) < 0)
2595 baseline_opts
.flags
= git_iterator_ignore_case(target
) ?
2596 GIT_ITERATOR_IGNORE_CASE
: GIT_ITERATOR_DONT_IGNORE_CASE
;
2597 baseline_opts
.start
= data
.pfx
;
2598 baseline_opts
.end
= data
.pfx
;
2599 if (opts
&& (opts
->checkout_strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
)) {
2600 baseline_opts
.pathlist
.count
= opts
->paths
.count
;
2601 baseline_opts
.pathlist
.strings
= opts
->paths
.strings
;
2604 if (data
.opts
.baseline_index
) {
2605 if ((error
= git_iterator_for_index(
2606 &baseline
, git_index_owner(data
.opts
.baseline_index
),
2607 data
.opts
.baseline_index
, &baseline_opts
)) < 0)
2610 if ((error
= git_iterator_for_tree(
2611 &baseline
, data
.opts
.baseline
, &baseline_opts
)) < 0)
2615 /* Should not have case insensitivity mismatch */
2616 assert(git_iterator_ignore_case(workdir
) == git_iterator_ignore_case(baseline
));
2618 /* Generate baseline-to-target diff which will include an entry for
2619 * every possible update that might need to be made.
2621 if ((error
= git_diff__from_iterators(
2622 &data
.diff
, data
.repo
, baseline
, target
, &diff_opts
)) < 0)
2625 /* Loop through diff (and working directory iterator) building a list of
2626 * actions to be taken, plus look for conflicts and send notifications,
2627 * then loop through conflicts.
2629 if ((error
= checkout_get_actions(&actions
, &counts
, &data
, workdir
)) != 0)
2632 data
.total_steps
= counts
[CHECKOUT_ACTION__REMOVE
] +
2633 counts
[CHECKOUT_ACTION__REMOVE_CONFLICT
] +
2634 counts
[CHECKOUT_ACTION__UPDATE_BLOB
] +
2635 counts
[CHECKOUT_ACTION__UPDATE_SUBMODULE
] +
2636 counts
[CHECKOUT_ACTION__UPDATE_CONFLICT
];
2638 report_progress(&data
, NULL
); /* establish 0 baseline */
2640 /* To deal with some order dependencies, perform remaining checkout
2641 * in three passes: removes, then update blobs, then update submodules.
2643 if (counts
[CHECKOUT_ACTION__REMOVE
] > 0 &&
2644 (error
= checkout_remove_the_old(actions
, &data
)) < 0)
2647 if (counts
[CHECKOUT_ACTION__REMOVE_CONFLICT
] > 0 &&
2648 (error
= checkout_remove_conflicts(&data
)) < 0)
2651 if (counts
[CHECKOUT_ACTION__UPDATE_BLOB
] > 0 &&
2652 (error
= checkout_create_the_new(actions
, &data
)) < 0)
2655 if (counts
[CHECKOUT_ACTION__UPDATE_SUBMODULE
] > 0 &&
2656 (error
= checkout_create_submodules(actions
, &data
)) < 0)
2659 if (counts
[CHECKOUT_ACTION__UPDATE_CONFLICT
] > 0 &&
2660 (error
= checkout_create_conflicts(&data
)) < 0)
2663 if (data
.index
!= git_iterator_index(target
) &&
2664 (error
= checkout_extensions_update_index(&data
)) < 0)
2667 assert(data
.completed_steps
== data
.total_steps
);
2669 if (data
.opts
.perfdata_cb
)
2670 data
.opts
.perfdata_cb(&data
.perfdata
, data
.opts
.perfdata_payload
);
2673 if (!error
&& data
.index
!= NULL
&&
2674 (data
.strategy
& CHECKOUT_INDEX_DONT_WRITE_MASK
) == 0)
2675 error
= git_index_write(data
.index
);
2677 git_diff_free(data
.diff
);
2678 git_iterator_free(workdir
);
2679 git_iterator_free(baseline
);
2682 checkout_data_clear(&data
);
2687 int git_checkout_index(
2688 git_repository
*repo
,
2690 const git_checkout_options
*opts
)
2692 int error
, owned
= 0;
2693 git_iterator
*index_i
;
2695 if (!index
&& !repo
) {
2696 git_error_set(GIT_ERROR_CHECKOUT
,
2697 "must provide either repository or index to checkout");
2701 if (index
&& repo
&&
2702 git_index_owner(index
) &&
2703 git_index_owner(index
) != repo
) {
2704 git_error_set(GIT_ERROR_CHECKOUT
,
2705 "index to checkout does not match repository");
2707 } else if(index
&& repo
&& !git_index_owner(index
)) {
2708 GIT_REFCOUNT_OWN(index
, repo
);
2713 repo
= git_index_owner(index
);
2715 if (!index
&& (error
= git_repository_index__weakptr(&index
, repo
)) < 0)
2717 GIT_REFCOUNT_INC(index
);
2719 if (!(error
= git_iterator_for_index(&index_i
, repo
, index
, NULL
)))
2720 error
= git_checkout_iterator(index_i
, index
, opts
);
2723 GIT_REFCOUNT_OWN(index
, NULL
);
2725 git_iterator_free(index_i
);
2726 git_index_free(index
);
2731 int git_checkout_tree(
2732 git_repository
*repo
,
2733 const git_object
*treeish
,
2734 const git_checkout_options
*opts
)
2738 git_tree
*tree
= NULL
;
2739 git_iterator
*tree_i
= NULL
;
2740 git_iterator_options iter_opts
= GIT_ITERATOR_OPTIONS_INIT
;
2742 if (!treeish
&& !repo
) {
2743 git_error_set(GIT_ERROR_CHECKOUT
,
2744 "must provide either repository or tree to checkout");
2747 if (treeish
&& repo
&& git_object_owner(treeish
) != repo
) {
2748 git_error_set(GIT_ERROR_CHECKOUT
,
2749 "object to checkout does not match repository");
2754 repo
= git_object_owner(treeish
);
2757 if (git_object_peel((git_object
**)&tree
, treeish
, GIT_OBJECT_TREE
) < 0) {
2759 GIT_ERROR_CHECKOUT
, "provided object cannot be peeled to a tree");
2764 if ((error
= checkout_lookup_head_tree(&tree
, repo
)) < 0) {
2765 if (error
!= GIT_EUNBORNBRANCH
)
2768 "HEAD could not be peeled to a tree and no treeish given");
2773 if ((error
= git_repository_index(&index
, repo
)) < 0)
2776 if (opts
&& (opts
->checkout_strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
)) {
2777 iter_opts
.pathlist
.count
= opts
->paths
.count
;
2778 iter_opts
.pathlist
.strings
= opts
->paths
.strings
;
2781 if (!(error
= git_iterator_for_tree(&tree_i
, tree
, &iter_opts
)))
2782 error
= git_checkout_iterator(tree_i
, index
, opts
);
2784 git_iterator_free(tree_i
);
2785 git_index_free(index
);
2786 git_tree_free(tree
);
2791 int git_checkout_head(
2792 git_repository
*repo
,
2793 const git_checkout_options
*opts
)
2796 return git_checkout_tree(repo
, NULL
, opts
);
2799 int git_checkout_options_init(git_checkout_options
*opts
, unsigned int version
)
2801 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2802 opts
, version
, git_checkout_options
, GIT_CHECKOUT_OPTIONS_INIT
);
2806 int git_checkout_init_options(git_checkout_options
*opts
, unsigned int version
)
2808 return git_checkout_options_init(opts
, version
);