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"
29 #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__REMOVE_AND_UPDATE
=
48 (CHECKOUT_ACTION__UPDATE_BLOB
| CHECKOUT_ACTION__REMOVE
)
55 git_checkout_options opts
;
56 bool opts_free_baseline
;
61 git_vector remove_conflicts
;
62 git_vector update_conflicts
;
63 git_vector
*update_reuc
;
64 git_vector
*update_names
;
68 unsigned int strategy
;
71 bool reload_submodules
;
73 size_t completed_steps
;
74 git_checkout_perfdata perfdata
;
75 git_strmap
*mkdir_map
;
76 git_attr_session attr_session
;
80 const git_index_entry
*ancestor
;
81 const git_index_entry
*ours
;
82 const git_index_entry
*theirs
;
84 unsigned int name_collision
:1,
89 } checkout_conflictdata
;
91 static int checkout_notify(
93 git_checkout_notify_t why
,
94 const git_diff_delta
*delta
,
95 const git_index_entry
*wditem
)
98 const git_diff_file
*baseline
= NULL
, *target
= NULL
, *workdir
= NULL
;
99 const char *path
= NULL
;
101 if (!data
->opts
.notify_cb
||
102 (why
& data
->opts
.notify_flags
) == 0)
106 memset(&wdfile
, 0, sizeof(wdfile
));
108 git_oid_cpy(&wdfile
.id
, &wditem
->id
);
109 wdfile
.path
= wditem
->path
;
110 wdfile
.size
= wditem
->file_size
;
111 wdfile
.flags
= GIT_DIFF_FLAG_VALID_ID
;
112 wdfile
.mode
= wditem
->mode
;
120 switch (delta
->status
) {
121 case GIT_DELTA_UNMODIFIED
:
122 case GIT_DELTA_MODIFIED
:
123 case GIT_DELTA_TYPECHANGE
:
125 baseline
= &delta
->old_file
;
126 target
= &delta
->new_file
;
128 case GIT_DELTA_ADDED
:
129 case GIT_DELTA_IGNORED
:
130 case GIT_DELTA_UNTRACKED
:
131 case GIT_DELTA_UNREADABLE
:
132 target
= &delta
->new_file
;
134 case GIT_DELTA_DELETED
:
135 baseline
= &delta
->old_file
;
139 path
= delta
->old_file
.path
;
143 int error
= data
->opts
.notify_cb(
144 why
, path
, baseline
, target
, workdir
, data
->opts
.notify_payload
);
146 return git_error_set_after_callback_function(
147 error
, "git_checkout notification");
151 GIT_INLINE(bool) is_workdir_base_or_new(
152 const git_oid
*workdir_id
,
153 const git_diff_file
*baseitem
,
154 const git_diff_file
*newitem
)
156 return (git_oid__cmp(&baseitem
->id
, workdir_id
) == 0 ||
157 git_oid__cmp(&newitem
->id
, workdir_id
) == 0);
160 GIT_INLINE(bool) is_filemode_changed(git_filemode_t a
, git_filemode_t b
, int respect_filemode
)
162 /* If core.filemode = false, ignore links in the repository and executable bit changes */
163 if (!respect_filemode
) {
165 a
= GIT_FILEMODE_BLOB
;
167 b
= GIT_FILEMODE_BLOB
;
176 static bool checkout_is_workdir_modified(
178 const git_diff_file
*baseitem
,
179 const git_diff_file
*newitem
,
180 const git_index_entry
*wditem
)
183 const git_index_entry
*ie
;
185 /* handle "modified" submodule */
186 if (wditem
->mode
== GIT_FILEMODE_COMMIT
) {
188 unsigned int sm_status
= 0;
189 const git_oid
*sm_oid
= NULL
;
192 if (git_submodule_lookup(&sm
, data
->repo
, wditem
->path
) < 0) {
197 if (git_submodule_status(&sm_status
, data
->repo
, wditem
->path
, GIT_SUBMODULE_IGNORE_UNSPECIFIED
) < 0 ||
198 GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status
))
200 else if ((sm_oid
= git_submodule_wd_id(sm
)) == NULL
)
203 rval
= (git_oid__cmp(&baseitem
->id
, sm_oid
) != 0);
205 git_submodule_free(sm
);
210 * Look at the cache to decide if the workdir is modified: if the
211 * cache contents match the workdir contents, then we do not need
212 * to examine the working directory directly, instead we can
213 * examine the cache to see if _it_ has been modified. This allows
214 * us to avoid touching the disk.
216 ie
= git_index_get_bypath(data
->index
, wditem
->path
, 0);
219 !git_index_entry_newer_than_index(ie
, data
->index
) &&
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
) != GIT_PERMS_IS_EXEC(delta
->new_file
.mode
))
277 *action
|= CHECKOUT_ACTION__REMOVE
;
279 notify
= GIT_CHECKOUT_NOTIFY_UPDATED
;
282 if ((*action
& CHECKOUT_ACTION__CONFLICT
) != 0)
283 notify
= GIT_CHECKOUT_NOTIFY_CONFLICT
;
285 return checkout_notify(data
, notify
, delta
, wd
);
288 static int checkout_action_no_wd(
291 const git_diff_delta
*delta
)
295 *action
= CHECKOUT_ACTION__NONE
;
297 switch (delta
->status
) {
298 case GIT_DELTA_UNMODIFIED
: /* case 12 */
299 error
= checkout_notify(data
, GIT_CHECKOUT_NOTIFY_DIRTY
, delta
, NULL
);
302 *action
= CHECKOUT_ACTION_IF(RECREATE_MISSING
, UPDATE_BLOB
, NONE
);
304 case GIT_DELTA_ADDED
: /* case 2 or 28 (and 5 but not really) */
305 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
307 case GIT_DELTA_MODIFIED
: /* case 13 (and 35 but not really) */
308 *action
= CHECKOUT_ACTION_IF(RECREATE_MISSING
, UPDATE_BLOB
, CONFLICT
);
310 case GIT_DELTA_TYPECHANGE
: /* case 21 (B->T) and 28 (T->B)*/
311 if (delta
->new_file
.mode
== GIT_FILEMODE_TREE
)
312 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
314 case GIT_DELTA_DELETED
: /* case 8 or 25 */
315 *action
= CHECKOUT_ACTION_IF(SAFE
, REMOVE
, NONE
);
317 default: /* impossible */
321 return checkout_action_common(action
, data
, delta
, NULL
);
324 static int checkout_target_fullpath(
325 git_str
**out
, checkout_data
*data
, const char *path
)
327 git_str_truncate(&data
->target_path
, data
->target_len
);
329 if (path
&& git_str_puts(&data
->target_path
, path
) < 0)
332 if (git_path_validate_str_length(data
->repo
, &data
->target_path
) < 0)
335 *out
= &data
->target_path
;
340 static bool wd_item_is_removable(
341 checkout_data
*data
, const git_index_entry
*wd
)
345 if (wd
->mode
!= GIT_FILEMODE_TREE
)
348 if (checkout_target_fullpath(&full
, data
, wd
->path
) < 0)
351 return !full
|| !git_fs_path_contains(full
, DOT_GIT
);
354 static int checkout_queue_remove(checkout_data
*data
, const char *path
)
356 char *copy
= git_pool_strdup(&data
->pool
, path
);
357 GIT_ERROR_CHECK_ALLOC(copy
);
358 return git_vector_insert(&data
->removes
, copy
);
361 /* note that this advances the iterator over the wd item */
362 static int checkout_action_wd_only(
364 git_iterator
*workdir
,
365 const git_index_entry
**wditem
,
366 git_vector
*pathspec
)
370 git_checkout_notify_t notify
= GIT_CHECKOUT_NOTIFY_NONE
;
371 const git_index_entry
*wd
= *wditem
;
373 if (!git_pathspec__match(
375 (data
->strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
) != 0,
376 git_iterator_ignore_case(workdir
), NULL
, NULL
)) {
378 if (wd
->mode
== GIT_FILEMODE_TREE
)
379 return git_iterator_advance_into(wditem
, workdir
);
381 return git_iterator_advance(wditem
, workdir
);
384 /* check if item is tracked in the index but not in the checkout diff */
385 if (data
->index
!= NULL
) {
388 error
= git_index__find_pos(
389 &pos
, data
->index
, wd
->path
, 0, GIT_INDEX_STAGE_ANY
);
391 if (wd
->mode
!= GIT_FILEMODE_TREE
) {
392 if (!error
) { /* found by git_index__find_pos call */
393 notify
= GIT_CHECKOUT_NOTIFY_DIRTY
;
394 remove
= ((data
->strategy
& GIT_CHECKOUT_FORCE
) != 0);
395 } else if (error
!= GIT_ENOTFOUND
)
398 error
= 0; /* git_index__find_pos does not set error msg */
400 /* for tree entries, we have to see if there are any index
401 * entries that are contained inside that tree
403 const git_index_entry
*e
= git_index_get_byindex(data
->index
, pos
);
405 if (e
!= NULL
&& data
->diff
->pfxcomp(e
->path
, wd
->path
) == 0)
406 return git_iterator_advance_into(wditem
, workdir
);
410 if (notify
!= GIT_CHECKOUT_NOTIFY_NONE
) {
411 /* if we found something in the index, notify and advance */
412 if ((error
= checkout_notify(data
, notify
, NULL
, wd
)) != 0)
415 if (remove
&& wd_item_is_removable(data
, wd
))
416 error
= checkout_queue_remove(data
, wd
->path
);
419 error
= git_iterator_advance(wditem
, workdir
);
421 /* untracked or ignored - can't know which until we advance through */
422 bool over
= false, removable
= wd_item_is_removable(data
, wd
);
423 git_iterator_status_t untracked_state
;
425 /* copy the entry for issuing notification callback later */
426 git_index_entry saved_wd
= *wd
;
427 git_str_sets(&data
->tmp
, wd
->path
);
428 saved_wd
.path
= data
->tmp
.ptr
;
430 error
= git_iterator_advance_over(
431 wditem
, &untracked_state
, workdir
);
432 if (error
== GIT_ITEROVER
)
437 if (untracked_state
== GIT_ITERATOR_STATUS_IGNORED
) {
438 notify
= GIT_CHECKOUT_NOTIFY_IGNORED
;
439 remove
= ((data
->strategy
& GIT_CHECKOUT_REMOVE_IGNORED
) != 0);
441 notify
= GIT_CHECKOUT_NOTIFY_UNTRACKED
;
442 remove
= ((data
->strategy
& GIT_CHECKOUT_REMOVE_UNTRACKED
) != 0);
445 if ((error
= checkout_notify(data
, notify
, NULL
, &saved_wd
)) != 0)
448 if (remove
&& removable
)
449 error
= checkout_queue_remove(data
, saved_wd
.path
);
451 if (!error
&& over
) /* restore ITEROVER if needed */
452 error
= GIT_ITEROVER
;
458 static bool submodule_is_config_only(
462 git_submodule
*sm
= NULL
;
463 unsigned int sm_loc
= 0;
466 if (git_submodule_lookup(&sm
, data
->repo
, path
) < 0)
469 if (git_submodule_location(&sm_loc
, sm
) < 0 ||
470 sm_loc
== GIT_SUBMODULE_STATUS_IN_CONFIG
)
473 git_submodule_free(sm
);
478 static bool checkout_is_empty_dir(checkout_data
*data
, const char *path
)
482 if (checkout_target_fullpath(&fullpath
, data
, path
) < 0)
485 return git_fs_path_is_empty_dir(fullpath
->ptr
);
488 static int checkout_action_with_wd(
491 const git_diff_delta
*delta
,
492 git_iterator
*workdir
,
493 const git_index_entry
*wd
)
495 *action
= CHECKOUT_ACTION__NONE
;
497 switch (delta
->status
) {
498 case GIT_DELTA_UNMODIFIED
: /* case 14/15 or 33 */
499 if (checkout_is_workdir_modified(data
, &delta
->old_file
, &delta
->new_file
, wd
)) {
500 GIT_ERROR_CHECK_ERROR(
501 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_DIRTY
, delta
, wd
) );
502 *action
= CHECKOUT_ACTION_IF(FORCE
, UPDATE_BLOB
, NONE
);
505 case GIT_DELTA_ADDED
: /* case 3, 4 or 6 */
506 if (git_iterator_current_is_ignored(workdir
))
507 *action
= CHECKOUT_ACTION_IF(DONT_OVERWRITE_IGNORED
, CONFLICT
, UPDATE_BLOB
);
509 *action
= CHECKOUT_ACTION_IF(FORCE
, UPDATE_BLOB
, CONFLICT
);
511 case GIT_DELTA_DELETED
: /* case 9 or 10 (or 26 but not really) */
512 if (checkout_is_workdir_modified(data
, &delta
->old_file
, &delta
->new_file
, wd
))
513 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE
, CONFLICT
);
515 *action
= CHECKOUT_ACTION_IF(SAFE
, REMOVE
, NONE
);
517 case GIT_DELTA_MODIFIED
: /* case 16, 17, 18 (or 36 but not really) */
518 if (wd
->mode
!= GIT_FILEMODE_COMMIT
&&
519 checkout_is_workdir_modified(data
, &delta
->old_file
, &delta
->new_file
, wd
))
520 *action
= CHECKOUT_ACTION_IF(FORCE
, UPDATE_BLOB
, CONFLICT
);
522 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
524 case GIT_DELTA_TYPECHANGE
: /* case 22, 23, 29, 30 */
525 if (delta
->old_file
.mode
== GIT_FILEMODE_TREE
) {
526 if (wd
->mode
== GIT_FILEMODE_TREE
)
527 /* either deleting items in old tree will delete the wd dir,
528 * or we'll get a conflict when we attempt blob update...
530 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
531 else if (wd
->mode
== GIT_FILEMODE_COMMIT
) {
532 /* workdir is possibly a "phantom" submodule - treat as a
533 * tree if the only submodule info came from the config
535 if (submodule_is_config_only(data
, wd
->path
))
536 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
538 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
540 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE
, CONFLICT
);
542 else if (checkout_is_workdir_modified(data
, &delta
->old_file
, &delta
->new_file
, wd
))
543 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
545 *action
= CHECKOUT_ACTION_IF(SAFE
, REMOVE_AND_UPDATE
, NONE
);
547 /* don't update if the typechange is to a tree */
548 if (delta
->new_file
.mode
== GIT_FILEMODE_TREE
)
549 *action
= (*action
& ~CHECKOUT_ACTION__UPDATE_BLOB
);
551 default: /* impossible */
555 return checkout_action_common(action
, data
, delta
, wd
);
558 static int checkout_action_with_wd_blocker(
561 const git_diff_delta
*delta
,
562 const git_index_entry
*wd
)
564 *action
= CHECKOUT_ACTION__NONE
;
566 switch (delta
->status
) {
567 case GIT_DELTA_UNMODIFIED
:
568 /* should show delta as dirty / deleted */
569 GIT_ERROR_CHECK_ERROR(
570 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_DIRTY
, delta
, wd
) );
571 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, NONE
);
573 case GIT_DELTA_ADDED
:
574 case GIT_DELTA_MODIFIED
:
575 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
577 case GIT_DELTA_DELETED
:
578 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE
, CONFLICT
);
580 case GIT_DELTA_TYPECHANGE
:
581 /* not 100% certain about this... */
582 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
584 default: /* impossible */
588 return checkout_action_common(action
, data
, delta
, wd
);
591 static int checkout_action_with_wd_dir(
594 const git_diff_delta
*delta
,
595 git_iterator
*workdir
,
596 const git_index_entry
*wd
)
598 *action
= CHECKOUT_ACTION__NONE
;
600 switch (delta
->status
) {
601 case GIT_DELTA_UNMODIFIED
: /* case 19 or 24 (or 34 but not really) */
602 GIT_ERROR_CHECK_ERROR(
603 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_DIRTY
, delta
, NULL
));
604 GIT_ERROR_CHECK_ERROR(
605 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_UNTRACKED
, NULL
, wd
));
606 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, NONE
);
608 case GIT_DELTA_ADDED
:/* case 4 (and 7 for dir) */
609 case GIT_DELTA_MODIFIED
: /* case 20 (or 37 but not really) */
610 if (delta
->old_file
.mode
== GIT_FILEMODE_COMMIT
)
611 /* expected submodule (and maybe found one) */;
612 else if (delta
->new_file
.mode
!= GIT_FILEMODE_TREE
)
613 *action
= git_iterator_current_is_ignored(workdir
) ?
614 CHECKOUT_ACTION_IF(DONT_OVERWRITE_IGNORED
, CONFLICT
, REMOVE_AND_UPDATE
) :
615 CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
617 case GIT_DELTA_DELETED
: /* case 11 (and 27 for dir) */
618 if (delta
->old_file
.mode
!= GIT_FILEMODE_TREE
)
619 GIT_ERROR_CHECK_ERROR(
620 checkout_notify(data
, GIT_CHECKOUT_NOTIFY_UNTRACKED
, NULL
, wd
));
622 case GIT_DELTA_TYPECHANGE
: /* case 24 or 31 */
623 if (delta
->old_file
.mode
== GIT_FILEMODE_TREE
) {
624 /* For typechange from dir, remove dir and add blob, but it is
625 * not safe to remove dir if it contains modified files.
626 * However, safely removing child files will remove the parent
627 * directory if is it left empty, so we can defer removing the
628 * dir and it will succeed if no children are left.
630 *action
= CHECKOUT_ACTION_IF(SAFE
, UPDATE_BLOB
, NONE
);
632 else if (delta
->new_file
.mode
!= GIT_FILEMODE_TREE
)
633 /* For typechange to dir, dir is already created so no action */
634 *action
= CHECKOUT_ACTION_IF(FORCE
, REMOVE_AND_UPDATE
, CONFLICT
);
636 default: /* impossible */
640 return checkout_action_common(action
, data
, delta
, wd
);
643 static int checkout_action_with_wd_dir_empty(
646 const git_diff_delta
*delta
)
648 int error
= checkout_action_no_wd(action
, data
, delta
);
650 /* We can always safely remove an empty directory. */
651 if (error
== 0 && *action
!= CHECKOUT_ACTION__NONE
)
652 *action
|= CHECKOUT_ACTION__REMOVE
;
657 static int checkout_action(
660 git_diff_delta
*delta
,
661 git_iterator
*workdir
,
662 const git_index_entry
**wditem
,
663 git_vector
*pathspec
)
666 int (*strcomp
)(const char *, const char *) = data
->diff
->strcomp
;
667 int (*pfxcomp
)(const char *str
, const char *pfx
) = data
->diff
->pfxcomp
;
668 int (*advance
)(const git_index_entry
**, git_iterator
*) = NULL
;
670 /* move workdir iterator to follow along with deltas */
673 const git_index_entry
*wd
= *wditem
;
676 return checkout_action_no_wd(action
, data
, delta
);
678 cmp
= strcomp(wd
->path
, delta
->old_file
.path
);
680 /* 1. wd before delta ("a/a" before "a/b")
681 * 2. wd prefixes delta & should expand ("a/" before "a/b")
682 * 3. wd prefixes delta & cannot expand ("a/b" before "a/b/c")
683 * 4. wd equals delta ("a/b" and "a/b")
684 * 5. wd after delta & delta prefixes wd ("a/b/c" after "a/b/" or "a/b")
685 * 6. wd after delta ("a/c" after "a/b")
689 cmp
= pfxcomp(delta
->old_file
.path
, wd
->path
);
692 if (wd
->mode
== GIT_FILEMODE_TREE
) {
693 /* case 2 - entry prefixed by workdir tree */
694 error
= git_iterator_advance_into(wditem
, workdir
);
695 if (error
< 0 && error
!= GIT_ITEROVER
)
700 /* case 3 maybe - wd contains non-dir where dir expected */
701 if (delta
->old_file
.path
[strlen(wd
->path
)] == '/') {
702 error
= checkout_action_with_wd_blocker(
703 action
, data
, delta
, wd
);
704 advance
= git_iterator_advance
;
709 /* case 1 - handle wd item (if it matches pathspec) */
710 error
= checkout_action_wd_only(data
, workdir
, wditem
, pathspec
);
711 if (error
&& error
!= GIT_ITEROVER
)
718 error
= checkout_action_with_wd(action
, data
, delta
, workdir
, wd
);
719 advance
= git_iterator_advance
;
723 cmp
= pfxcomp(wd
->path
, delta
->old_file
.path
);
725 if (cmp
== 0) { /* case 5 */
726 if (wd
->path
[strlen(delta
->old_file
.path
)] != '/')
727 return checkout_action_no_wd(action
, data
, delta
);
729 if (delta
->status
== GIT_DELTA_TYPECHANGE
) {
730 if (delta
->old_file
.mode
== GIT_FILEMODE_TREE
) {
731 error
= checkout_action_with_wd(action
, data
, delta
, workdir
, wd
);
732 advance
= git_iterator_advance_into
;
736 if (delta
->new_file
.mode
== GIT_FILEMODE_TREE
||
737 delta
->new_file
.mode
== GIT_FILEMODE_COMMIT
||
738 delta
->old_file
.mode
== GIT_FILEMODE_COMMIT
)
740 error
= checkout_action_with_wd(action
, data
, delta
, workdir
, wd
);
741 advance
= git_iterator_advance
;
746 return checkout_is_empty_dir(data
, wd
->path
) ?
747 checkout_action_with_wd_dir_empty(action
, data
, delta
) :
748 checkout_action_with_wd_dir(action
, data
, delta
, workdir
, wd
);
751 /* case 6 - wd is after delta */
752 return checkout_action_no_wd(action
, data
, delta
);
756 if (!error
&& advance
!= NULL
&&
757 (error
= advance(wditem
, workdir
)) < 0) {
759 if (error
== GIT_ITEROVER
)
766 static int checkout_remaining_wd_items(
768 git_iterator
*workdir
,
769 const git_index_entry
*wd
,
775 error
= checkout_action_wd_only(data
, workdir
, &wd
, spec
);
777 if (error
== GIT_ITEROVER
)
783 GIT_INLINE(int) checkout_idxentry_cmp(
784 const git_index_entry
*a
,
785 const git_index_entry
*b
)
794 return strcmp(a
->path
, b
->path
);
797 static int checkout_conflictdata_cmp(const void *a
, const void *b
)
799 const checkout_conflictdata
*ca
= a
;
800 const checkout_conflictdata
*cb
= b
;
803 if ((diff
= checkout_idxentry_cmp(ca
->ancestor
, cb
->ancestor
)) == 0 &&
804 (diff
= checkout_idxentry_cmp(ca
->ours
, cb
->theirs
)) == 0)
805 diff
= checkout_idxentry_cmp(ca
->theirs
, cb
->theirs
);
810 static int checkout_conflictdata_empty(
811 const git_vector
*conflicts
, size_t idx
, void *payload
)
813 checkout_conflictdata
*conflict
;
817 if ((conflict
= git_vector_get(conflicts
, idx
)) == NULL
)
820 if (conflict
->ancestor
|| conflict
->ours
|| conflict
->theirs
)
827 GIT_INLINE(bool) conflict_pathspec_match(
829 git_iterator
*workdir
,
830 git_vector
*pathspec
,
831 const git_index_entry
*ancestor
,
832 const git_index_entry
*ours
,
833 const git_index_entry
*theirs
)
835 /* if the pathspec matches ours *or* theirs, proceed */
836 if (ours
&& git_pathspec__match(pathspec
, ours
->path
,
837 (data
->strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
) != 0,
838 git_iterator_ignore_case(workdir
), NULL
, NULL
))
841 if (theirs
&& git_pathspec__match(pathspec
, theirs
->path
,
842 (data
->strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
) != 0,
843 git_iterator_ignore_case(workdir
), NULL
, NULL
))
846 if (ancestor
&& git_pathspec__match(pathspec
, ancestor
->path
,
847 (data
->strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
) != 0,
848 git_iterator_ignore_case(workdir
), NULL
, NULL
))
854 GIT_INLINE(int) checkout_conflict_detect_submodule(checkout_conflictdata
*conflict
)
856 conflict
->submodule
= ((conflict
->ancestor
&& S_ISGITLINK(conflict
->ancestor
->mode
)) ||
857 (conflict
->ours
&& S_ISGITLINK(conflict
->ours
->mode
)) ||
858 (conflict
->theirs
&& S_ISGITLINK(conflict
->theirs
->mode
)));
862 GIT_INLINE(int) checkout_conflict_detect_binary(git_repository
*repo
, checkout_conflictdata
*conflict
)
864 git_blob
*ancestor_blob
= NULL
, *our_blob
= NULL
, *their_blob
= NULL
;
867 if (conflict
->submodule
)
870 if (conflict
->ancestor
) {
871 if ((error
= git_blob_lookup(&ancestor_blob
, repo
, &conflict
->ancestor
->id
)) < 0)
874 conflict
->binary
= git_blob_is_binary(ancestor_blob
);
877 if (!conflict
->binary
&& conflict
->ours
) {
878 if ((error
= git_blob_lookup(&our_blob
, repo
, &conflict
->ours
->id
)) < 0)
881 conflict
->binary
= git_blob_is_binary(our_blob
);
884 if (!conflict
->binary
&& conflict
->theirs
) {
885 if ((error
= git_blob_lookup(&their_blob
, repo
, &conflict
->theirs
->id
)) < 0)
888 conflict
->binary
= git_blob_is_binary(their_blob
);
892 git_blob_free(ancestor_blob
);
893 git_blob_free(our_blob
);
894 git_blob_free(their_blob
);
899 static int checkout_conflict_append_update(
900 const git_index_entry
*ancestor
,
901 const git_index_entry
*ours
,
902 const git_index_entry
*theirs
,
905 checkout_data
*data
= payload
;
906 checkout_conflictdata
*conflict
;
909 conflict
= git__calloc(1, sizeof(checkout_conflictdata
));
910 GIT_ERROR_CHECK_ALLOC(conflict
);
912 conflict
->ancestor
= ancestor
;
913 conflict
->ours
= ours
;
914 conflict
->theirs
= theirs
;
916 if ((error
= checkout_conflict_detect_submodule(conflict
)) < 0 ||
917 (error
= checkout_conflict_detect_binary(data
->repo
, conflict
)) < 0)
923 if (git_vector_insert(&data
->update_conflicts
, conflict
))
929 static int checkout_conflicts_foreach(
932 git_iterator
*workdir
,
933 git_vector
*pathspec
,
934 int (*cb
)(const git_index_entry
*, const git_index_entry
*, const git_index_entry
*, void *),
937 git_index_conflict_iterator
*iterator
= NULL
;
938 const git_index_entry
*ancestor
, *ours
, *theirs
;
941 if ((error
= git_index_conflict_iterator_new(&iterator
, index
)) < 0)
944 /* Collect the conflicts */
945 while ((error
= git_index_conflict_next(&ancestor
, &ours
, &theirs
, iterator
)) == 0) {
946 if (!conflict_pathspec_match(data
, workdir
, pathspec
, ancestor
, ours
, theirs
))
949 if ((error
= cb(ancestor
, ours
, theirs
, payload
)) < 0)
953 if (error
== GIT_ITEROVER
)
957 git_index_conflict_iterator_free(iterator
);
962 static int checkout_conflicts_load(checkout_data
*data
, git_iterator
*workdir
, git_vector
*pathspec
)
966 /* Only write conflicts from sources that have them: indexes. */
967 if ((index
= git_iterator_index(data
->target
)) == NULL
)
970 data
->update_conflicts
._cmp
= checkout_conflictdata_cmp
;
972 if (checkout_conflicts_foreach(data
, index
, workdir
, pathspec
, checkout_conflict_append_update
, data
) < 0)
975 /* Collect the REUC and NAME entries */
976 data
->update_reuc
= &index
->reuc
;
977 data
->update_names
= &index
->names
;
982 GIT_INLINE(int) checkout_conflicts_cmp_entry(
984 const git_index_entry
*entry
)
986 return strcmp((const char *)path
, entry
->path
);
989 static int checkout_conflicts_cmp_ancestor(const void *p
, const void *c
)
991 const char *path
= p
;
992 const checkout_conflictdata
*conflict
= c
;
994 if (!conflict
->ancestor
)
997 return checkout_conflicts_cmp_entry(path
, conflict
->ancestor
);
1000 static checkout_conflictdata
*checkout_conflicts_search_ancestor(
1001 checkout_data
*data
,
1006 if (git_vector_bsearch2(&pos
, &data
->update_conflicts
, checkout_conflicts_cmp_ancestor
, path
) < 0)
1009 return git_vector_get(&data
->update_conflicts
, pos
);
1012 static checkout_conflictdata
*checkout_conflicts_search_branch(
1013 checkout_data
*data
,
1016 checkout_conflictdata
*conflict
;
1019 git_vector_foreach(&data
->update_conflicts
, i
, conflict
) {
1022 if (conflict
->ancestor
)
1026 cmp
= checkout_conflicts_cmp_entry(path
, conflict
->ours
);
1027 else if (conflict
->theirs
)
1028 cmp
= checkout_conflicts_cmp_entry(path
, conflict
->theirs
);
1037 static int checkout_conflicts_load_byname_entry(
1038 checkout_conflictdata
**ancestor_out
,
1039 checkout_conflictdata
**ours_out
,
1040 checkout_conflictdata
**theirs_out
,
1041 checkout_data
*data
,
1042 const git_index_name_entry
*name_entry
)
1044 checkout_conflictdata
*ancestor
, *ours
= NULL
, *theirs
= NULL
;
1047 *ancestor_out
= NULL
;
1051 if (!name_entry
->ancestor
) {
1052 git_error_set(GIT_ERROR_INDEX
, "a NAME entry exists without an ancestor");
1057 if (!name_entry
->ours
&& !name_entry
->theirs
) {
1058 git_error_set(GIT_ERROR_INDEX
, "a NAME entry exists without an ours or theirs");
1063 if ((ancestor
= checkout_conflicts_search_ancestor(data
,
1064 name_entry
->ancestor
)) == NULL
) {
1065 git_error_set(GIT_ERROR_INDEX
,
1066 "a NAME entry referenced ancestor entry '%s' which does not exist in the main index",
1067 name_entry
->ancestor
);
1072 if (name_entry
->ours
) {
1073 if (strcmp(name_entry
->ancestor
, name_entry
->ours
) == 0)
1075 else if ((ours
= checkout_conflicts_search_branch(data
, name_entry
->ours
)) == NULL
||
1076 ours
->ours
== NULL
) {
1077 git_error_set(GIT_ERROR_INDEX
,
1078 "a NAME entry referenced our entry '%s' which does not exist in the main index",
1085 if (name_entry
->theirs
) {
1086 if (strcmp(name_entry
->ancestor
, name_entry
->theirs
) == 0)
1088 else if (name_entry
->ours
&& strcmp(name_entry
->ours
, name_entry
->theirs
) == 0)
1090 else if ((theirs
= checkout_conflicts_search_branch(data
, name_entry
->theirs
)) == NULL
||
1091 theirs
->theirs
== NULL
) {
1092 git_error_set(GIT_ERROR_INDEX
,
1093 "a NAME entry referenced their entry '%s' which does not exist in the main index",
1094 name_entry
->theirs
);
1100 *ancestor_out
= ancestor
;
1102 *theirs_out
= theirs
;
1108 static int checkout_conflicts_coalesce_renames(
1109 checkout_data
*data
)
1112 const git_index_name_entry
*name_entry
;
1113 checkout_conflictdata
*ancestor_conflict
, *our_conflict
, *their_conflict
;
1117 if ((index
= git_iterator_index(data
->target
)) == NULL
)
1120 /* Juggle entries based on renames */
1121 names
= git_index_name_entrycount(index
);
1123 for (i
= 0; i
< names
; i
++) {
1124 name_entry
= git_index_name_get_byindex(index
, i
);
1126 if ((error
= checkout_conflicts_load_byname_entry(
1127 &ancestor_conflict
, &our_conflict
, &their_conflict
,
1128 data
, name_entry
)) < 0)
1131 if (our_conflict
&& our_conflict
!= ancestor_conflict
) {
1132 ancestor_conflict
->ours
= our_conflict
->ours
;
1133 our_conflict
->ours
= NULL
;
1135 if (our_conflict
->theirs
)
1136 our_conflict
->name_collision
= 1;
1138 if (our_conflict
->name_collision
)
1139 ancestor_conflict
->name_collision
= 1;
1142 if (their_conflict
&& their_conflict
!= ancestor_conflict
) {
1143 ancestor_conflict
->theirs
= their_conflict
->theirs
;
1144 their_conflict
->theirs
= NULL
;
1146 if (their_conflict
->ours
)
1147 their_conflict
->name_collision
= 1;
1149 if (their_conflict
->name_collision
)
1150 ancestor_conflict
->name_collision
= 1;
1153 if (our_conflict
&& our_conflict
!= ancestor_conflict
&&
1154 their_conflict
&& their_conflict
!= ancestor_conflict
)
1155 ancestor_conflict
->one_to_two
= 1;
1158 git_vector_remove_matching(
1159 &data
->update_conflicts
, checkout_conflictdata_empty
, NULL
);
1165 static int checkout_conflicts_mark_directoryfile(
1166 checkout_data
*data
)
1169 checkout_conflictdata
*conflict
;
1170 const git_index_entry
*entry
;
1173 int prefixed
, error
= 0;
1175 if ((index
= git_iterator_index(data
->target
)) == NULL
)
1178 len
= git_index_entrycount(index
);
1180 /* Find d/f conflicts */
1181 git_vector_foreach(&data
->update_conflicts
, i
, conflict
) {
1182 if ((conflict
->ours
&& conflict
->theirs
) ||
1183 (!conflict
->ours
&& !conflict
->theirs
))
1186 path
= conflict
->ours
?
1187 conflict
->ours
->path
: conflict
->theirs
->path
;
1189 if ((error
= git_index_find(&j
, index
, path
)) < 0) {
1190 if (error
== GIT_ENOTFOUND
)
1191 git_error_set(GIT_ERROR_INDEX
,
1192 "index inconsistency, could not find entry for expected conflict '%s'", path
);
1197 for (; j
< len
; j
++) {
1198 if ((entry
= git_index_get_byindex(index
, j
)) == NULL
) {
1199 git_error_set(GIT_ERROR_INDEX
,
1200 "index inconsistency, truncated index while loading expected conflict '%s'", path
);
1205 prefixed
= git_fs_path_equal_or_prefixed(path
, entry
->path
, NULL
);
1207 if (prefixed
== GIT_FS_PATH_EQUAL
)
1210 if (prefixed
== GIT_FS_PATH_PREFIX
)
1211 conflict
->directoryfile
= 1;
1221 static int checkout_get_update_conflicts(
1222 checkout_data
*data
,
1223 git_iterator
*workdir
,
1224 git_vector
*pathspec
)
1228 if (data
->strategy
& GIT_CHECKOUT_SKIP_UNMERGED
)
1231 if ((error
= checkout_conflicts_load(data
, workdir
, pathspec
)) < 0 ||
1232 (error
= checkout_conflicts_coalesce_renames(data
)) < 0 ||
1233 (error
= checkout_conflicts_mark_directoryfile(data
)) < 0)
1240 static int checkout_conflict_append_remove(
1241 const git_index_entry
*ancestor
,
1242 const git_index_entry
*ours
,
1243 const git_index_entry
*theirs
,
1246 checkout_data
*data
= payload
;
1249 GIT_ASSERT_ARG(ancestor
|| ours
|| theirs
);
1252 name
= git__strdup(ancestor
->path
);
1254 name
= git__strdup(ours
->path
);
1256 name
= git__strdup(theirs
->path
);
1260 GIT_ERROR_CHECK_ALLOC(name
);
1262 return git_vector_insert(&data
->remove_conflicts
, (char *)name
);
1265 static int checkout_get_remove_conflicts(
1266 checkout_data
*data
,
1267 git_iterator
*workdir
,
1268 git_vector
*pathspec
)
1270 if ((data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) != 0)
1273 return checkout_conflicts_foreach(data
, data
->index
, workdir
, pathspec
, checkout_conflict_append_remove
, data
);
1276 static int checkout_verify_paths(
1277 git_repository
*repo
,
1279 git_diff_delta
*delta
)
1281 unsigned int flags
= GIT_PATH_REJECT_WORKDIR_DEFAULTS
;
1283 if (action
& CHECKOUT_ACTION__REMOVE
) {
1284 if (!git_path_is_valid(repo
, delta
->old_file
.path
, delta
->old_file
.mode
, flags
)) {
1285 git_error_set(GIT_ERROR_CHECKOUT
, "cannot remove invalid path '%s'", delta
->old_file
.path
);
1290 if (action
& ~CHECKOUT_ACTION__REMOVE
) {
1291 if (!git_path_is_valid(repo
, delta
->new_file
.path
, delta
->new_file
.mode
, flags
)) {
1292 git_error_set(GIT_ERROR_CHECKOUT
, "cannot checkout to invalid path '%s'", delta
->new_file
.path
);
1300 static int checkout_get_actions(
1301 uint32_t **actions_ptr
,
1302 size_t **counts_ptr
,
1303 checkout_data
*data
,
1304 git_iterator
*workdir
)
1307 const git_index_entry
*wditem
;
1308 git_vector pathspec
= GIT_VECTOR_INIT
, *deltas
;
1310 git_diff_delta
*delta
;
1311 size_t i
, *counts
= NULL
;
1312 uint32_t *actions
= NULL
;
1314 if (git_pool_init(&pathpool
, 1) < 0)
1317 if (data
->opts
.paths
.count
> 0 &&
1318 git_pathspec__vinit(&pathspec
, &data
->opts
.paths
, &pathpool
) < 0)
1321 if ((error
= git_iterator_current(&wditem
, workdir
)) < 0 &&
1322 error
!= GIT_ITEROVER
)
1325 deltas
= &data
->diff
->deltas
;
1327 *counts_ptr
= counts
= git__calloc(CHECKOUT_ACTION__MAX
+1, sizeof(size_t));
1328 *actions_ptr
= actions
= git__calloc(
1329 deltas
->length
? deltas
->length
: 1, sizeof(uint32_t));
1330 if (!counts
|| !actions
) {
1335 git_vector_foreach(deltas
, i
, delta
) {
1336 if ((error
= checkout_action(&act
, data
, delta
, workdir
, &wditem
, &pathspec
)) == 0)
1337 error
= checkout_verify_paths(data
->repo
, act
, delta
);
1344 if (act
& CHECKOUT_ACTION__REMOVE
)
1345 counts
[CHECKOUT_ACTION__REMOVE
]++;
1346 if (act
& CHECKOUT_ACTION__UPDATE_BLOB
)
1347 counts
[CHECKOUT_ACTION__UPDATE_BLOB
]++;
1348 if (act
& CHECKOUT_ACTION__UPDATE_SUBMODULE
)
1349 counts
[CHECKOUT_ACTION__UPDATE_SUBMODULE
]++;
1350 if (act
& CHECKOUT_ACTION__CONFLICT
)
1351 counts
[CHECKOUT_ACTION__CONFLICT
]++;
1354 error
= checkout_remaining_wd_items(data
, workdir
, wditem
, &pathspec
);
1358 counts
[CHECKOUT_ACTION__REMOVE
] += data
->removes
.length
;
1360 if (counts
[CHECKOUT_ACTION__CONFLICT
] > 0 &&
1361 (data
->strategy
& GIT_CHECKOUT_ALLOW_CONFLICTS
) == 0) {
1362 git_error_set(GIT_ERROR_CHECKOUT
, "%"PRIuZ
" %s checkout",
1363 counts
[CHECKOUT_ACTION__CONFLICT
],
1364 counts
[CHECKOUT_ACTION__CONFLICT
] == 1 ?
1365 "conflict prevents" : "conflicts prevent");
1366 error
= GIT_ECONFLICT
;
1371 if ((error
= checkout_get_remove_conflicts(data
, workdir
, &pathspec
)) < 0 ||
1372 (error
= checkout_get_update_conflicts(data
, workdir
, &pathspec
)) < 0)
1375 counts
[CHECKOUT_ACTION__REMOVE_CONFLICT
] = git_vector_length(&data
->remove_conflicts
);
1376 counts
[CHECKOUT_ACTION__UPDATE_CONFLICT
] = git_vector_length(&data
->update_conflicts
);
1378 git_pathspec__vfree(&pathspec
);
1379 git_pool_clear(&pathpool
);
1386 *actions_ptr
= NULL
;
1389 git_pathspec__vfree(&pathspec
);
1390 git_pool_clear(&pathpool
);
1395 static bool should_remove_existing(checkout_data
*data
)
1399 if (git_repository__configmap_lookup(&ignorecase
, data
->repo
, GIT_CONFIGMAP_IGNORECASE
) < 0) {
1403 return (ignorecase
&&
1404 (data
->strategy
& GIT_CHECKOUT_DONT_REMOVE_EXISTING
) == 0);
1407 #define MKDIR_NORMAL \
1408 GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR
1409 #define MKDIR_REMOVE_EXISTING \
1410 MKDIR_NORMAL | GIT_MKDIR_REMOVE_FILES | GIT_MKDIR_REMOVE_SYMLINKS
1412 static int checkout_mkdir(
1413 checkout_data
*data
,
1419 struct git_futils_mkdir_options mkdir_opts
= {0};
1422 mkdir_opts
.dir_map
= data
->mkdir_map
;
1423 mkdir_opts
.pool
= &data
->pool
;
1425 error
= git_futils_mkdir_relative(
1426 path
, base
, mode
, flags
, &mkdir_opts
);
1428 data
->perfdata
.mkdir_calls
+= mkdir_opts
.perfdata
.mkdir_calls
;
1429 data
->perfdata
.stat_calls
+= mkdir_opts
.perfdata
.stat_calls
;
1430 data
->perfdata
.chmod_calls
+= mkdir_opts
.perfdata
.chmod_calls
;
1435 static int mkpath2file(
1436 checkout_data
*data
, const char *path
, unsigned int mode
)
1439 bool remove_existing
= should_remove_existing(data
);
1440 unsigned int flags
=
1441 (remove_existing
? MKDIR_REMOVE_EXISTING
: MKDIR_NORMAL
) |
1442 GIT_MKDIR_SKIP_LAST
;
1445 if ((error
= checkout_mkdir(
1446 data
, path
, data
->opts
.target_directory
, mode
, flags
)) < 0)
1449 if (remove_existing
) {
1450 data
->perfdata
.stat_calls
++;
1452 if (p_lstat(path
, &st
) == 0) {
1454 /* Some file, symlink or folder already exists at this name.
1455 * We would have removed it in remove_the_old unless we're on
1456 * a case inensitive filesystem (or the user has asked us not
1457 * to). Remove the similarly named file to write the new.
1459 error
= git_futils_rmdir_r(path
, NULL
, GIT_RMDIR_REMOVE_FILES
);
1460 } else if (errno
!= ENOENT
) {
1461 git_error_set(GIT_ERROR_OS
, "failed to stat '%s'", path
);
1471 struct checkout_stream
{
1472 git_writestream base
;
1478 static int checkout_stream_write(
1479 git_writestream
*s
, const char *buffer
, size_t len
)
1481 struct checkout_stream
*stream
= (struct checkout_stream
*)s
;
1484 if ((ret
= p_write(stream
->fd
, buffer
, len
)) < 0)
1485 git_error_set(GIT_ERROR_OS
, "could not write to '%s'", stream
->path
);
1490 static int checkout_stream_close(git_writestream
*s
)
1492 struct checkout_stream
*stream
= (struct checkout_stream
*)s
;
1494 GIT_ASSERT_ARG(stream
);
1495 GIT_ASSERT_ARG(stream
->open
);
1498 return p_close(stream
->fd
);
1501 static void checkout_stream_free(git_writestream
*s
)
1506 static int blob_content_to_file(
1507 checkout_data
*data
,
1511 const char *hint_path
,
1512 mode_t entry_filemode
)
1514 int flags
= data
->opts
.file_open_flags
;
1515 mode_t file_mode
= data
->opts
.file_mode
?
1516 data
->opts
.file_mode
: entry_filemode
;
1517 git_filter_session filter_session
= GIT_FILTER_SESSION_INIT
;
1518 struct checkout_stream writer
;
1520 git_filter_list
*fl
= NULL
;
1524 GIT_ASSERT(hint_path
!= NULL
);
1526 if ((error
= mkpath2file(data
, path
, data
->opts
.dir_mode
)) < 0)
1530 flags
= O_CREAT
| O_TRUNC
| O_WRONLY
;
1531 if (!(mode
= file_mode
))
1532 mode
= GIT_FILEMODE_BLOB
;
1534 if ((fd
= p_open(path
, flags
, mode
)) < 0) {
1535 git_error_set(GIT_ERROR_OS
, "could not open '%s' for writing", path
);
1539 filter_session
.attr_session
= &data
->attr_session
;
1540 filter_session
.temp_buf
= &data
->tmp
;
1542 if (!data
->opts
.disable_filters
&&
1543 (error
= git_filter_list__load(
1544 &fl
, data
->repo
, blob
, hint_path
,
1545 GIT_FILTER_TO_WORKTREE
, &filter_session
))) {
1550 /* setup the writer */
1551 memset(&writer
, 0, sizeof(struct checkout_stream
));
1552 writer
.base
.write
= checkout_stream_write
;
1553 writer
.base
.close
= checkout_stream_close
;
1554 writer
.base
.free
= checkout_stream_free
;
1559 error
= git_filter_list_stream_blob(fl
, blob
, &writer
.base
);
1561 GIT_ASSERT(writer
.open
== 0);
1563 git_filter_list_free(fl
);
1569 data
->perfdata
.stat_calls
++;
1571 if ((error
= p_stat(path
, st
)) < 0) {
1572 git_error_set(GIT_ERROR_OS
, "failed to stat '%s'", path
);
1576 st
->st_mode
= entry_filemode
;
1582 static int blob_content_to_link(
1583 checkout_data
*data
,
1588 git_str linktarget
= GIT_STR_INIT
;
1591 if ((error
= mkpath2file(data
, path
, data
->opts
.dir_mode
)) < 0)
1594 if ((error
= git_blob__getbuf(&linktarget
, blob
)) < 0)
1597 if (data
->can_symlink
) {
1598 if ((error
= p_symlink(git_str_cstr(&linktarget
), path
)) < 0)
1599 git_error_set(GIT_ERROR_OS
, "could not create symlink %s", path
);
1601 error
= git_futils_fake_symlink(git_str_cstr(&linktarget
), path
);
1605 data
->perfdata
.stat_calls
++;
1607 if ((error
= p_lstat(path
, st
)) < 0)
1608 git_error_set(GIT_ERROR_CHECKOUT
, "could not stat symlink %s", path
);
1610 st
->st_mode
= GIT_FILEMODE_LINK
;
1613 git_str_dispose(&linktarget
);
1618 static int checkout_update_index(
1619 checkout_data
*data
,
1620 const git_diff_file
*file
,
1623 git_index_entry entry
;
1628 memset(&entry
, 0, sizeof(entry
));
1629 entry
.path
= (char *)file
->path
; /* cast to prevent warning */
1630 git_index_entry__init_from_stat(&entry
, st
, true);
1631 git_oid_cpy(&entry
.id
, &file
->id
);
1633 return git_index_add(data
->index
, &entry
);
1636 static int checkout_submodule_update_index(
1637 checkout_data
*data
,
1638 const git_diff_file
*file
)
1643 /* update the index unless prevented */
1644 if ((data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) != 0)
1647 if (checkout_target_fullpath(&fullpath
, data
, file
->path
) < 0)
1650 data
->perfdata
.stat_calls
++;
1651 if (p_stat(fullpath
->ptr
, &st
) < 0) {
1653 GIT_ERROR_CHECKOUT
, "could not stat submodule %s\n", file
->path
);
1654 return GIT_ENOTFOUND
;
1657 st
.st_mode
= GIT_FILEMODE_COMMIT
;
1659 return checkout_update_index(data
, file
, &st
);
1662 static int checkout_submodule(
1663 checkout_data
*data
,
1664 const git_diff_file
*file
)
1666 bool remove_existing
= should_remove_existing(data
);
1669 /* Until submodules are supported, UPDATE_ONLY means do nothing here */
1670 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0)
1673 if ((error
= checkout_mkdir(
1675 file
->path
, data
->opts
.target_directory
, data
->opts
.dir_mode
,
1676 remove_existing
? MKDIR_REMOVE_EXISTING
: MKDIR_NORMAL
)) < 0)
1679 if ((error
= git_submodule_lookup(NULL
, data
->repo
, file
->path
)) < 0) {
1680 /* I've observed repos with submodules in the tree that do not
1681 * have a .gitmodules - core Git just makes an empty directory
1683 if (error
== GIT_ENOTFOUND
) {
1685 return checkout_submodule_update_index(data
, file
);
1691 /* TODO: Support checkout_strategy options. Two circumstances:
1692 * 1 - submodule already checked out, but we need to move the HEAD
1693 * to the new OID, or
1694 * 2 - submodule not checked out and we should recursively check it out
1696 * Checkout will not execute a pull on the submodule, but a clone
1697 * command should probably be able to. Do we need a submodule callback?
1700 return checkout_submodule_update_index(data
, file
);
1703 static void report_progress(
1704 checkout_data
*data
,
1707 if (data
->opts
.progress_cb
)
1708 data
->opts
.progress_cb(
1709 path
, data
->completed_steps
, data
->total_steps
,
1710 data
->opts
.progress_payload
);
1713 static int checkout_safe_for_update_only(
1714 checkout_data
*data
, const char *path
, mode_t expected_mode
)
1718 data
->perfdata
.stat_calls
++;
1720 if (p_lstat(path
, &st
) < 0) {
1721 /* if doesn't exist, then no error and no update */
1722 if (errno
== ENOENT
|| errno
== ENOTDIR
)
1725 /* otherwise, stat error and no update */
1726 git_error_set(GIT_ERROR_OS
, "failed to stat '%s'", path
);
1730 /* only safe for update if this is the same type of file */
1731 if ((st
.st_mode
& ~0777) == (expected_mode
& ~0777))
1737 static int checkout_write_content(
1738 checkout_data
*data
,
1740 const char *full_path
,
1741 const char *hint_path
,
1748 if ((error
= git_blob_lookup(&blob
, data
->repo
, oid
)) < 0)
1752 error
= blob_content_to_link(data
, st
, blob
, full_path
);
1754 error
= blob_content_to_file(data
, st
, blob
, full_path
, hint_path
, mode
);
1756 git_blob_free(blob
);
1758 /* if we try to create the blob and an existing directory blocks it from
1759 * being written, then there must have been a typechange conflict in a
1760 * parent directory - suppress the error and try to continue.
1762 if ((data
->strategy
& GIT_CHECKOUT_ALLOW_CONFLICTS
) != 0 &&
1763 (error
== GIT_ENOTFOUND
|| error
== GIT_EEXISTS
))
1772 static int checkout_blob(
1773 checkout_data
*data
,
1774 const git_diff_file
*file
)
1780 if (checkout_target_fullpath(&fullpath
, data
, file
->path
) < 0)
1783 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0) {
1784 int rval
= checkout_safe_for_update_only(
1785 data
, fullpath
->ptr
, file
->mode
);
1791 error
= checkout_write_content(
1792 data
, &file
->id
, fullpath
->ptr
, file
->path
, file
->mode
, &st
);
1794 /* update the index unless prevented */
1795 if (!error
&& (data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) == 0)
1796 error
= checkout_update_index(data
, file
, &st
);
1798 /* update the submodule data if this was a new .gitmodules file */
1799 if (!error
&& strcmp(file
->path
, ".gitmodules") == 0)
1800 data
->reload_submodules
= true;
1805 static int checkout_remove_the_old(
1806 unsigned int *actions
,
1807 checkout_data
*data
)
1810 git_diff_delta
*delta
;
1814 uint32_t flg
= GIT_RMDIR_EMPTY_PARENTS
|
1815 GIT_RMDIR_REMOVE_FILES
| GIT_RMDIR_REMOVE_BLOCKERS
;
1817 if (data
->opts
.checkout_strategy
& GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES
)
1818 flg
|= GIT_RMDIR_SKIP_NONEMPTY
;
1820 if (checkout_target_fullpath(&fullpath
, data
, NULL
) < 0)
1823 git_vector_foreach(&data
->diff
->deltas
, i
, delta
) {
1824 if (actions
[i
] & CHECKOUT_ACTION__REMOVE
) {
1825 error
= git_futils_rmdir_r(
1826 delta
->old_file
.path
, fullpath
->ptr
, flg
);
1831 data
->completed_steps
++;
1832 report_progress(data
, delta
->old_file
.path
);
1834 if ((actions
[i
] & CHECKOUT_ACTION__UPDATE_BLOB
) == 0 &&
1835 (data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) == 0 &&
1836 data
->index
!= NULL
)
1838 (void)git_index_remove(data
->index
, delta
->old_file
.path
, 0);
1843 git_vector_foreach(&data
->removes
, i
, str
) {
1844 error
= git_futils_rmdir_r(str
, fullpath
->ptr
, flg
);
1848 data
->completed_steps
++;
1849 report_progress(data
, str
);
1851 if ((data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) == 0 &&
1852 data
->index
!= NULL
)
1854 if (str
[strlen(str
) - 1] == '/')
1855 (void)git_index_remove_directory(data
->index
, str
, 0);
1857 (void)git_index_remove(data
->index
, str
, 0);
1864 static int checkout_create_the_new(
1865 unsigned int *actions
,
1866 checkout_data
*data
)
1869 git_diff_delta
*delta
;
1872 git_vector_foreach(&data
->diff
->deltas
, i
, delta
) {
1873 if (actions
[i
] & CHECKOUT_ACTION__UPDATE_BLOB
&& !S_ISLNK(delta
->new_file
.mode
)) {
1874 if ((error
= checkout_blob(data
, &delta
->new_file
)) < 0)
1876 data
->completed_steps
++;
1877 report_progress(data
, delta
->new_file
.path
);
1881 git_vector_foreach(&data
->diff
->deltas
, i
, delta
) {
1882 if (actions
[i
] & CHECKOUT_ACTION__UPDATE_BLOB
&& S_ISLNK(delta
->new_file
.mode
)) {
1883 if ((error
= checkout_blob(data
, &delta
->new_file
)) < 0)
1885 data
->completed_steps
++;
1886 report_progress(data
, delta
->new_file
.path
);
1893 static int checkout_create_submodules(
1894 unsigned int *actions
,
1895 checkout_data
*data
)
1897 git_diff_delta
*delta
;
1900 git_vector_foreach(&data
->diff
->deltas
, i
, delta
) {
1901 if (actions
[i
] & CHECKOUT_ACTION__UPDATE_SUBMODULE
) {
1902 int error
= checkout_submodule(data
, &delta
->new_file
);
1906 data
->completed_steps
++;
1907 report_progress(data
, delta
->new_file
.path
);
1914 static int checkout_lookup_head_tree(git_tree
**out
, git_repository
*repo
)
1917 git_reference
*ref
= NULL
;
1920 if (!(error
= git_repository_head(&ref
, repo
)) &&
1921 !(error
= git_reference_peel(&head
, ref
, GIT_OBJECT_TREE
)))
1922 *out
= (git_tree
*)head
;
1924 git_reference_free(ref
);
1930 static int conflict_entry_name(
1932 const char *side_name
,
1933 const char *filename
)
1935 if (git_str_puts(out
, side_name
) < 0 ||
1936 git_str_putc(out
, ':') < 0 ||
1937 git_str_puts(out
, filename
) < 0)
1943 static int checkout_path_suffixed(git_str
*path
, const char *suffix
)
1946 int i
= 0, error
= 0;
1948 if ((error
= git_str_putc(path
, '~')) < 0 || (error
= git_str_puts(path
, suffix
)) < 0)
1951 path_len
= git_str_len(path
);
1953 while (git_fs_path_exists(git_str_cstr(path
)) && i
< INT_MAX
) {
1954 git_str_truncate(path
, path_len
);
1956 if ((error
= git_str_putc(path
, '_')) < 0 ||
1957 (error
= git_str_printf(path
, "%d", i
)) < 0)
1964 git_str_truncate(path
, path_len
);
1966 git_error_set(GIT_ERROR_CHECKOUT
, "could not write '%s': working directory file exists", path
->ptr
);
1973 static int checkout_write_entry(
1974 checkout_data
*data
,
1975 checkout_conflictdata
*conflict
,
1976 const git_index_entry
*side
)
1978 const char *hint_path
= NULL
, *suffix
;
1983 GIT_ASSERT(side
== conflict
->ours
|| side
== conflict
->theirs
);
1985 if (checkout_target_fullpath(&fullpath
, data
, side
->path
) < 0)
1988 if ((conflict
->name_collision
|| conflict
->directoryfile
) &&
1989 (data
->strategy
& GIT_CHECKOUT_USE_OURS
) == 0 &&
1990 (data
->strategy
& GIT_CHECKOUT_USE_THEIRS
) == 0) {
1992 if (side
== conflict
->ours
)
1993 suffix
= data
->opts
.our_label
? data
->opts
.our_label
:
1996 suffix
= data
->opts
.their_label
? data
->opts
.their_label
:
1999 if (checkout_path_suffixed(fullpath
, suffix
) < 0)
2003 hint_path
= side
->path
;
2005 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0 &&
2006 (error
= checkout_safe_for_update_only(data
, fullpath
->ptr
, side
->mode
)) <= 0)
2009 if (!S_ISGITLINK(side
->mode
))
2010 return checkout_write_content(data
,
2011 &side
->id
, fullpath
->ptr
, hint_path
, side
->mode
, &st
);
2016 static int checkout_write_entries(
2017 checkout_data
*data
,
2018 checkout_conflictdata
*conflict
)
2022 if ((error
= checkout_write_entry(data
, conflict
, conflict
->ours
)) >= 0)
2023 error
= checkout_write_entry(data
, conflict
, conflict
->theirs
);
2028 static int checkout_merge_path(
2030 checkout_data
*data
,
2031 checkout_conflictdata
*conflict
,
2032 git_merge_file_result
*result
)
2034 const char *our_label_raw
, *their_label_raw
, *suffix
;
2037 if ((error
= git_str_joinpath(out
, data
->opts
.target_directory
, result
->path
)) < 0 ||
2038 (error
= git_path_validate_str_length(data
->repo
, out
)) < 0)
2041 /* Most conflicts simply use the filename in the index */
2042 if (!conflict
->name_collision
)
2045 /* Rename 2->1 conflicts need the branch name appended */
2046 our_label_raw
= data
->opts
.our_label
? data
->opts
.our_label
: "ours";
2047 their_label_raw
= data
->opts
.their_label
? data
->opts
.their_label
: "theirs";
2048 suffix
= strcmp(result
->path
, conflict
->ours
->path
) == 0 ? our_label_raw
: their_label_raw
;
2050 if ((error
= checkout_path_suffixed(out
, suffix
)) < 0)
2056 static int checkout_write_merge(
2057 checkout_data
*data
,
2058 checkout_conflictdata
*conflict
)
2060 git_str our_label
= GIT_STR_INIT
, their_label
= GIT_STR_INIT
,
2061 path_suffixed
= GIT_STR_INIT
, path_workdir
= GIT_STR_INIT
,
2062 in_data
= GIT_STR_INIT
, out_data
= GIT_STR_INIT
;
2063 git_merge_file_options opts
= GIT_MERGE_FILE_OPTIONS_INIT
;
2064 git_merge_file_result result
= {0};
2065 git_filebuf output
= GIT_FILEBUF_INIT
;
2066 git_filter_list
*fl
= NULL
;
2067 git_filter_session filter_session
= GIT_FILTER_SESSION_INIT
;
2070 if (data
->opts
.checkout_strategy
& GIT_CHECKOUT_CONFLICT_STYLE_DIFF3
)
2071 opts
.flags
|= GIT_MERGE_FILE_STYLE_DIFF3
;
2073 if (data
->opts
.checkout_strategy
& GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3
)
2074 opts
.flags
|= GIT_MERGE_FILE_STYLE_ZDIFF3
;
2076 opts
.ancestor_label
= data
->opts
.ancestor_label
?
2077 data
->opts
.ancestor_label
: "ancestor";
2078 opts
.our_label
= data
->opts
.our_label
?
2079 data
->opts
.our_label
: "ours";
2080 opts
.their_label
= data
->opts
.their_label
?
2081 data
->opts
.their_label
: "theirs";
2083 /* If all the paths are identical, decorate the diff3 file with the branch
2084 * names. Otherwise, append branch_name:path.
2086 if (conflict
->ours
&& conflict
->theirs
&&
2087 strcmp(conflict
->ours
->path
, conflict
->theirs
->path
) != 0) {
2089 if ((error
= conflict_entry_name(
2090 &our_label
, opts
.our_label
, conflict
->ours
->path
)) < 0 ||
2091 (error
= conflict_entry_name(
2092 &their_label
, opts
.their_label
, conflict
->theirs
->path
)) < 0)
2095 opts
.our_label
= git_str_cstr(&our_label
);
2096 opts
.their_label
= git_str_cstr(&their_label
);
2099 if ((error
= git_merge_file_from_index(&result
, data
->repo
,
2100 conflict
->ancestor
, conflict
->ours
, conflict
->theirs
, &opts
)) < 0)
2103 if (result
.path
== NULL
|| result
.mode
== 0) {
2104 git_error_set(GIT_ERROR_CHECKOUT
, "could not merge contents of file");
2105 error
= GIT_ECONFLICT
;
2109 if ((error
= checkout_merge_path(&path_workdir
, data
, conflict
, &result
)) < 0)
2112 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0 &&
2113 (error
= checkout_safe_for_update_only(data
, git_str_cstr(&path_workdir
), result
.mode
)) <= 0)
2116 if (!data
->opts
.disable_filters
) {
2117 in_data
.ptr
= (char *)result
.ptr
;
2118 in_data
.size
= result
.len
;
2120 filter_session
.attr_session
= &data
->attr_session
;
2121 filter_session
.temp_buf
= &data
->tmp
;
2123 if ((error
= git_filter_list__load(
2124 &fl
, data
->repo
, NULL
, result
.path
,
2125 GIT_FILTER_TO_WORKTREE
, &filter_session
)) < 0 ||
2126 (error
= git_filter_list__convert_buf(&out_data
, fl
, &in_data
)) < 0)
2129 out_data
.ptr
= (char *)result
.ptr
;
2130 out_data
.size
= result
.len
;
2133 if ((error
= mkpath2file(data
, path_workdir
.ptr
, data
->opts
.dir_mode
)) < 0 ||
2134 (error
= git_filebuf_open(&output
, git_str_cstr(&path_workdir
), GIT_FILEBUF_DO_NOT_BUFFER
, result
.mode
)) < 0 ||
2135 (error
= git_filebuf_write(&output
, out_data
.ptr
, out_data
.size
)) < 0 ||
2136 (error
= git_filebuf_commit(&output
)) < 0)
2140 git_filter_list_free(fl
);
2142 git_str_dispose(&out_data
);
2143 git_str_dispose(&our_label
);
2144 git_str_dispose(&their_label
);
2146 git_merge_file_result_free(&result
);
2147 git_str_dispose(&path_workdir
);
2148 git_str_dispose(&path_suffixed
);
2153 static int checkout_conflict_add(
2154 checkout_data
*data
,
2155 const git_index_entry
*conflict
)
2157 int error
= git_index_remove(data
->index
, conflict
->path
, 0);
2159 if (error
== GIT_ENOTFOUND
)
2164 return git_index_add(data
->index
, conflict
);
2167 static int checkout_conflict_update_index(
2168 checkout_data
*data
,
2169 checkout_conflictdata
*conflict
)
2173 if (conflict
->ancestor
)
2174 error
= checkout_conflict_add(data
, conflict
->ancestor
);
2176 if (!error
&& conflict
->ours
)
2177 error
= checkout_conflict_add(data
, conflict
->ours
);
2179 if (!error
&& conflict
->theirs
)
2180 error
= checkout_conflict_add(data
, conflict
->theirs
);
2185 static int checkout_create_conflicts(checkout_data
*data
)
2187 checkout_conflictdata
*conflict
;
2191 git_vector_foreach(&data
->update_conflicts
, i
, conflict
) {
2193 /* Both deleted: nothing to do */
2194 if (conflict
->ours
== NULL
&& conflict
->theirs
== NULL
)
2197 else if ((data
->strategy
& GIT_CHECKOUT_USE_OURS
) &&
2199 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2200 else if ((data
->strategy
& GIT_CHECKOUT_USE_THEIRS
) &&
2202 error
= checkout_write_entry(data
, conflict
, conflict
->theirs
);
2204 /* Ignore the other side of name collisions. */
2205 else if ((data
->strategy
& GIT_CHECKOUT_USE_OURS
) &&
2206 !conflict
->ours
&& conflict
->name_collision
)
2208 else if ((data
->strategy
& GIT_CHECKOUT_USE_THEIRS
) &&
2209 !conflict
->theirs
&& conflict
->name_collision
)
2212 /* For modify/delete, name collisions and d/f conflicts, write
2213 * the file (potentially with the name mangled.
2215 else if (conflict
->ours
!= NULL
&& conflict
->theirs
== NULL
)
2216 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2217 else if (conflict
->ours
== NULL
&& conflict
->theirs
!= NULL
)
2218 error
= checkout_write_entry(data
, conflict
, conflict
->theirs
);
2220 /* Add/add conflicts and rename 1->2 conflicts, write the
2221 * ours/theirs sides (potentially name mangled).
2223 else if (conflict
->one_to_two
)
2224 error
= checkout_write_entries(data
, conflict
);
2226 /* If all sides are links, write the ours side */
2227 else if (S_ISLNK(conflict
->ours
->mode
) &&
2228 S_ISLNK(conflict
->theirs
->mode
))
2229 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2230 /* Link/file conflicts, write the file side */
2231 else if (S_ISLNK(conflict
->ours
->mode
))
2232 error
= checkout_write_entry(data
, conflict
, conflict
->theirs
);
2233 else if (S_ISLNK(conflict
->theirs
->mode
))
2234 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2236 /* If any side is a gitlink, do nothing. */
2237 else if (conflict
->submodule
)
2240 /* If any side is binary, write the ours side */
2241 else if (conflict
->binary
)
2242 error
= checkout_write_entry(data
, conflict
, conflict
->ours
);
2245 error
= checkout_write_merge(data
, conflict
);
2247 /* Update the index extensions (REUC and NAME) if we're checking
2248 * out a different index. (Otherwise just leave them there.)
2250 if (!error
&& (data
->strategy
& GIT_CHECKOUT_DONT_UPDATE_INDEX
) == 0)
2251 error
= checkout_conflict_update_index(data
, conflict
);
2256 data
->completed_steps
++;
2257 report_progress(data
,
2258 conflict
->ours
? conflict
->ours
->path
:
2259 (conflict
->theirs
? conflict
->theirs
->path
: conflict
->ancestor
->path
));
2265 static int checkout_remove_conflicts(checkout_data
*data
)
2267 const char *conflict
;
2270 git_vector_foreach(&data
->remove_conflicts
, i
, conflict
) {
2271 if (git_index_conflict_remove(data
->index
, conflict
) < 0)
2274 data
->completed_steps
++;
2280 static int checkout_extensions_update_index(checkout_data
*data
)
2282 const git_index_reuc_entry
*reuc_entry
;
2283 const git_index_name_entry
*name_entry
;
2287 if ((data
->strategy
& GIT_CHECKOUT_UPDATE_ONLY
) != 0)
2290 if (data
->update_reuc
) {
2291 git_vector_foreach(data
->update_reuc
, i
, reuc_entry
) {
2292 if ((error
= git_index_reuc_add(data
->index
, reuc_entry
->path
,
2293 reuc_entry
->mode
[0], &reuc_entry
->oid
[0],
2294 reuc_entry
->mode
[1], &reuc_entry
->oid
[1],
2295 reuc_entry
->mode
[2], &reuc_entry
->oid
[2])) < 0)
2300 if (data
->update_names
) {
2301 git_vector_foreach(data
->update_names
, i
, name_entry
) {
2302 if ((error
= git_index_name_add(data
->index
, name_entry
->ancestor
,
2303 name_entry
->ours
, name_entry
->theirs
)) < 0)
2312 static void checkout_data_clear(checkout_data
*data
)
2314 if (data
->opts_free_baseline
) {
2315 git_tree_free(data
->opts
.baseline
);
2316 data
->opts
.baseline
= NULL
;
2319 git_vector_free(&data
->removes
);
2320 git_pool_clear(&data
->pool
);
2322 git_vector_free_deep(&data
->remove_conflicts
);
2323 git_vector_free_deep(&data
->update_conflicts
);
2325 git__free(data
->pfx
);
2328 git_str_dispose(&data
->target_path
);
2329 git_str_dispose(&data
->tmp
);
2331 git_index_free(data
->index
);
2334 git_strmap_free(data
->mkdir_map
);
2335 data
->mkdir_map
= NULL
;
2337 git_attr_session__free(&data
->attr_session
);
2340 static int validate_target_directory(checkout_data
*data
)
2344 if ((error
= git_path_validate_length(data
->repo
, data
->opts
.target_directory
)) < 0)
2347 if (git_fs_path_isdir(data
->opts
.target_directory
))
2350 error
= checkout_mkdir(data
, data
->opts
.target_directory
, NULL
,
2351 GIT_DIR_MODE
, GIT_MKDIR_VERIFY_DIR
);
2356 static int checkout_data_init(
2357 checkout_data
*data
,
2358 git_iterator
*target
,
2359 const git_checkout_options
*proposed
)
2362 git_repository
*repo
= git_iterator_owner(target
);
2364 memset(data
, 0, sizeof(*data
));
2367 git_error_set(GIT_ERROR_CHECKOUT
, "cannot checkout nothing");
2371 if ((!proposed
|| !proposed
->target_directory
) &&
2372 (error
= git_repository__ensure_not_bare(repo
, "checkout")) < 0)
2376 data
->target
= target
;
2378 GIT_ERROR_CHECK_VERSION(
2379 proposed
, GIT_CHECKOUT_OPTIONS_VERSION
, "git_checkout_options");
2382 GIT_INIT_STRUCTURE(&data
->opts
, GIT_CHECKOUT_OPTIONS_VERSION
);
2384 memmove(&data
->opts
, proposed
, sizeof(git_checkout_options
));
2386 if (!data
->opts
.target_directory
)
2387 data
->opts
.target_directory
= git_repository_workdir(repo
);
2388 else if ((error
= validate_target_directory(data
)) < 0)
2391 if ((error
= git_repository_index(&data
->index
, data
->repo
)) < 0)
2394 /* refresh config and index content unless NO_REFRESH is given */
2395 if ((data
->opts
.checkout_strategy
& GIT_CHECKOUT_NO_REFRESH
) == 0) {
2398 if ((error
= git_repository_config__weakptr(&cfg
, repo
)) < 0)
2401 /* Reload the repository index (unless we're checking out the
2402 * index; then it has the changes we're trying to check out
2403 * and those should not be overwritten.)
2405 if (data
->index
!= git_iterator_index(target
)) {
2406 if (data
->opts
.checkout_strategy
& GIT_CHECKOUT_FORCE
) {
2407 /* When forcing, we can blindly re-read the index */
2408 if ((error
= git_index_read(data
->index
, false)) < 0)
2412 * When not being forced, we need to check for unresolved
2413 * conflicts and unsaved changes in the index before
2416 if (git_index_has_conflicts(data
->index
)) {
2417 error
= GIT_ECONFLICT
;
2418 git_error_set(GIT_ERROR_CHECKOUT
,
2419 "unresolved conflicts exist in the index");
2423 if ((error
= git_index_read_safely(data
->index
)) < 0)
2427 /* clean conflict data in the current index */
2428 git_index_name_clear(data
->index
);
2429 git_index_reuc_clear(data
->index
);
2433 /* if you are forcing, allow all safe updates, plus recreate missing */
2434 if ((data
->opts
.checkout_strategy
& GIT_CHECKOUT_FORCE
) != 0)
2435 data
->opts
.checkout_strategy
|= GIT_CHECKOUT_SAFE
|
2436 GIT_CHECKOUT_RECREATE_MISSING
;
2438 /* if the repository does not actually have an index file, then this
2439 * is an initial checkout (perhaps from clone), so we allow safe updates
2441 if (!data
->index
->on_disk
&&
2442 (data
->opts
.checkout_strategy
& GIT_CHECKOUT_SAFE
) != 0)
2443 data
->opts
.checkout_strategy
|= GIT_CHECKOUT_RECREATE_MISSING
;
2445 data
->strategy
= data
->opts
.checkout_strategy
;
2447 /* opts->disable_filters is false by default */
2449 if (!data
->opts
.dir_mode
)
2450 data
->opts
.dir_mode
= GIT_DIR_MODE
;
2452 if (!data
->opts
.file_open_flags
)
2453 data
->opts
.file_open_flags
= O_CREAT
| O_TRUNC
| O_WRONLY
;
2455 data
->pfx
= git_pathspec_prefix(&data
->opts
.paths
);
2457 if ((error
= git_repository__configmap_lookup(
2458 &data
->can_symlink
, repo
, GIT_CONFIGMAP_SYMLINKS
)) < 0)
2461 if ((error
= git_repository__configmap_lookup(
2462 &data
->respect_filemode
, repo
, GIT_CONFIGMAP_FILEMODE
)) < 0)
2465 if (!data
->opts
.baseline
&& !data
->opts
.baseline_index
) {
2466 data
->opts_free_baseline
= true;
2469 /* if we don't have an index, this is an initial checkout and
2470 * should be against an empty baseline
2472 if (data
->index
->on_disk
)
2473 error
= checkout_lookup_head_tree(&data
->opts
.baseline
, repo
);
2475 if (error
== GIT_EUNBORNBRANCH
) {
2484 if ((data
->opts
.checkout_strategy
&
2485 (GIT_CHECKOUT_CONFLICT_STYLE_MERGE
| GIT_CHECKOUT_CONFLICT_STYLE_DIFF3
)) == 0) {
2486 git_config_entry
*conflict_style
= NULL
;
2487 git_config
*cfg
= NULL
;
2489 if ((error
= git_repository_config__weakptr(&cfg
, repo
)) < 0 ||
2490 (error
= git_config_get_entry(&conflict_style
, cfg
, "merge.conflictstyle")) < 0 ||
2491 error
== GIT_ENOTFOUND
)
2495 else if (strcmp(conflict_style
->value
, "merge") == 0)
2496 data
->opts
.checkout_strategy
|= GIT_CHECKOUT_CONFLICT_STYLE_MERGE
;
2497 else if (strcmp(conflict_style
->value
, "diff3") == 0)
2498 data
->opts
.checkout_strategy
|= GIT_CHECKOUT_CONFLICT_STYLE_DIFF3
;
2499 else if (strcmp(conflict_style
->value
, "zdiff3") == 0)
2500 data
->opts
.checkout_strategy
|= GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3
;
2502 git_error_set(GIT_ERROR_CHECKOUT
, "unknown style '%s' given for 'merge.conflictstyle'",
2503 conflict_style
->value
);
2505 git_config_entry_free(conflict_style
);
2508 git_config_entry_free(conflict_style
);
2511 if ((error
= git_pool_init(&data
->pool
, 1)) < 0 ||
2512 (error
= git_vector_init(&data
->removes
, 0, git__strcmp_cb
)) < 0 ||
2513 (error
= git_vector_init(&data
->remove_conflicts
, 0, NULL
)) < 0 ||
2514 (error
= git_vector_init(&data
->update_conflicts
, 0, NULL
)) < 0 ||
2515 (error
= git_str_puts(&data
->target_path
, data
->opts
.target_directory
)) < 0 ||
2516 (error
= git_fs_path_to_dir(&data
->target_path
)) < 0 ||
2517 (error
= git_strmap_new(&data
->mkdir_map
)) < 0)
2520 data
->target_len
= git_str_len(&data
->target_path
);
2522 git_attr_session__init(&data
->attr_session
, data
->repo
);
2526 checkout_data_clear(data
);
2531 #define CHECKOUT_INDEX_DONT_WRITE_MASK \
2532 (GIT_CHECKOUT_DONT_UPDATE_INDEX | GIT_CHECKOUT_DONT_WRITE_INDEX)
2534 GIT_INLINE(void) setup_pathspecs(
2535 git_iterator_options
*iter_opts
,
2536 const git_checkout_options
*checkout_opts
)
2538 if (checkout_opts
&&
2539 (checkout_opts
->checkout_strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
)) {
2540 iter_opts
->pathlist
.count
= checkout_opts
->paths
.count
;
2541 iter_opts
->pathlist
.strings
= checkout_opts
->paths
.strings
;
2545 int git_checkout_iterator(
2546 git_iterator
*target
,
2548 const git_checkout_options
*opts
)
2551 git_iterator
*baseline
= NULL
, *workdir
= NULL
;
2552 git_iterator_options baseline_opts
= GIT_ITERATOR_OPTIONS_INIT
,
2553 workdir_opts
= GIT_ITERATOR_OPTIONS_INIT
;
2554 checkout_data data
= {0};
2555 git_diff_options diff_opts
= GIT_DIFF_OPTIONS_INIT
;
2556 uint32_t *actions
= NULL
;
2557 size_t *counts
= NULL
;
2559 /* initialize structures and options */
2560 error
= checkout_data_init(&data
, target
, opts
);
2565 GIT_DIFF_INCLUDE_UNMODIFIED
|
2566 GIT_DIFF_INCLUDE_UNREADABLE
|
2567 GIT_DIFF_INCLUDE_UNTRACKED
|
2568 GIT_DIFF_RECURSE_UNTRACKED_DIRS
| /* needed to match baseline */
2569 GIT_DIFF_INCLUDE_IGNORED
|
2570 GIT_DIFF_INCLUDE_TYPECHANGE
|
2571 GIT_DIFF_INCLUDE_TYPECHANGE_TREES
|
2572 GIT_DIFF_SKIP_BINARY_CHECK
|
2573 GIT_DIFF_INCLUDE_CASECHANGE
;
2574 if (data
.opts
.checkout_strategy
& GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH
)
2575 diff_opts
.flags
|= GIT_DIFF_DISABLE_PATHSPEC_MATCH
;
2576 if (data
.opts
.paths
.count
> 0)
2577 diff_opts
.pathspec
= data
.opts
.paths
;
2579 /* set up iterators */
2581 workdir_opts
.flags
= git_iterator_ignore_case(target
) ?
2582 GIT_ITERATOR_IGNORE_CASE
: GIT_ITERATOR_DONT_IGNORE_CASE
;
2583 workdir_opts
.flags
|= GIT_ITERATOR_DONT_AUTOEXPAND
;
2584 workdir_opts
.start
= data
.pfx
;
2585 workdir_opts
.end
= data
.pfx
;
2587 setup_pathspecs(&workdir_opts
, opts
);
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
;
2600 setup_pathspecs(&baseline_opts
, opts
);
2602 if (data
.opts
.baseline_index
) {
2603 if ((error
= git_iterator_for_index(
2604 &baseline
, git_index_owner(data
.opts
.baseline_index
),
2605 data
.opts
.baseline_index
, &baseline_opts
)) < 0)
2608 if ((error
= git_iterator_for_tree(
2609 &baseline
, data
.opts
.baseline
, &baseline_opts
)) < 0)
2613 /* Should not have case insensitivity mismatch */
2614 GIT_ASSERT(git_iterator_ignore_case(workdir
) == git_iterator_ignore_case(baseline
));
2616 /* Generate baseline-to-target diff which will include an entry for
2617 * every possible update that might need to be made.
2619 if ((error
= git_diff__from_iterators(
2620 &data
.diff
, data
.repo
, baseline
, target
, &diff_opts
)) < 0)
2623 /* Loop through diff (and working directory iterator) building a list of
2624 * actions to be taken, plus look for conflicts and send notifications,
2625 * then loop through conflicts.
2627 if ((error
= checkout_get_actions(&actions
, &counts
, &data
, workdir
)) != 0)
2630 if (data
.strategy
& GIT_CHECKOUT_DRY_RUN
)
2633 data
.total_steps
= counts
[CHECKOUT_ACTION__REMOVE
] +
2634 counts
[CHECKOUT_ACTION__REMOVE_CONFLICT
] +
2635 counts
[CHECKOUT_ACTION__UPDATE_BLOB
] +
2636 counts
[CHECKOUT_ACTION__UPDATE_SUBMODULE
] +
2637 counts
[CHECKOUT_ACTION__UPDATE_CONFLICT
];
2639 report_progress(&data
, NULL
); /* establish 0 baseline */
2641 /* To deal with some order dependencies, perform remaining checkout
2642 * in three passes: removes, then update blobs, then update submodules.
2644 if (counts
[CHECKOUT_ACTION__REMOVE
] > 0 &&
2645 (error
= checkout_remove_the_old(actions
, &data
)) < 0)
2648 if (counts
[CHECKOUT_ACTION__REMOVE_CONFLICT
] > 0 &&
2649 (error
= checkout_remove_conflicts(&data
)) < 0)
2652 if (counts
[CHECKOUT_ACTION__UPDATE_BLOB
] > 0 &&
2653 (error
= checkout_create_the_new(actions
, &data
)) < 0)
2656 if (counts
[CHECKOUT_ACTION__UPDATE_SUBMODULE
] > 0 &&
2657 (error
= checkout_create_submodules(actions
, &data
)) < 0)
2660 if (counts
[CHECKOUT_ACTION__UPDATE_CONFLICT
] > 0 &&
2661 (error
= checkout_create_conflicts(&data
)) < 0)
2664 if (data
.index
!= git_iterator_index(target
) &&
2665 (error
= checkout_extensions_update_index(&data
)) < 0)
2668 GIT_ASSERT(data
.completed_steps
== data
.total_steps
);
2670 if (data
.opts
.perfdata_cb
)
2671 data
.opts
.perfdata_cb(&data
.perfdata
, data
.opts
.perfdata_payload
);
2674 if (!error
&& data
.index
!= NULL
&&
2675 (data
.strategy
& CHECKOUT_INDEX_DONT_WRITE_MASK
) == 0)
2676 error
= git_index_write(data
.index
);
2678 git_diff_free(data
.diff
);
2679 git_iterator_free(workdir
);
2680 git_iterator_free(baseline
);
2683 checkout_data_clear(&data
);
2688 int git_checkout_index(
2689 git_repository
*repo
,
2691 const git_checkout_options
*opts
)
2693 git_iterator_options iter_opts
= GIT_ITERATOR_OPTIONS_INIT
;
2694 int error
, owned
= 0;
2695 git_iterator
*index_i
;
2697 if (!index
&& !repo
) {
2698 git_error_set(GIT_ERROR_CHECKOUT
,
2699 "must provide either repository or index to checkout");
2703 if (index
&& repo
&&
2704 git_index_owner(index
) &&
2705 git_index_owner(index
) != repo
) {
2706 git_error_set(GIT_ERROR_CHECKOUT
,
2707 "index to checkout does not match repository");
2709 } else if(index
&& repo
&& !git_index_owner(index
)) {
2710 GIT_REFCOUNT_OWN(index
, repo
);
2715 repo
= git_index_owner(index
);
2717 if (!index
&& (error
= git_repository_index__weakptr(&index
, repo
)) < 0)
2719 GIT_REFCOUNT_INC(index
);
2721 setup_pathspecs(&iter_opts
, opts
);
2723 if (!(error
= git_iterator_for_index(&index_i
, repo
, index
, &iter_opts
)))
2724 error
= git_checkout_iterator(index_i
, index
, opts
);
2727 GIT_REFCOUNT_OWN(index
, NULL
);
2729 git_iterator_free(index_i
);
2730 git_index_free(index
);
2735 int git_checkout_tree(
2736 git_repository
*repo
,
2737 const git_object
*treeish
,
2738 const git_checkout_options
*opts
)
2742 git_tree
*tree
= NULL
;
2743 git_iterator
*tree_i
= NULL
;
2744 git_iterator_options iter_opts
= GIT_ITERATOR_OPTIONS_INIT
;
2746 if (!treeish
&& !repo
) {
2747 git_error_set(GIT_ERROR_CHECKOUT
,
2748 "must provide either repository or tree to checkout");
2751 if (treeish
&& repo
&& git_object_owner(treeish
) != repo
) {
2752 git_error_set(GIT_ERROR_CHECKOUT
,
2753 "object to checkout does not match repository");
2758 repo
= git_object_owner(treeish
);
2761 if (git_object_peel((git_object
**)&tree
, treeish
, GIT_OBJECT_TREE
) < 0) {
2763 GIT_ERROR_CHECKOUT
, "provided object cannot be peeled to a tree");
2768 if ((error
= checkout_lookup_head_tree(&tree
, repo
)) < 0) {
2769 if (error
!= GIT_EUNBORNBRANCH
)
2772 "HEAD could not be peeled to a tree and no treeish given");
2777 if ((error
= git_repository_index(&index
, repo
)) < 0)
2780 setup_pathspecs(&iter_opts
, opts
);
2782 if (!(error
= git_iterator_for_tree(&tree_i
, tree
, &iter_opts
)))
2783 error
= git_checkout_iterator(tree_i
, index
, opts
);
2785 git_iterator_free(tree_i
);
2786 git_index_free(index
);
2787 git_tree_free(tree
);
2792 int git_checkout_head(
2793 git_repository
*repo
,
2794 const git_checkout_options
*opts
)
2796 GIT_ASSERT_ARG(repo
);
2798 return git_checkout_tree(repo
, NULL
, opts
);
2801 int git_checkout_options_init(git_checkout_options
*opts
, unsigned int version
)
2803 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2804 opts
, version
, git_checkout_options
, GIT_CHECKOUT_OPTIONS_INIT
);
2808 #ifndef GIT_DEPRECATE_HARD
2809 int git_checkout_init_options(git_checkout_options
*opts
, unsigned int version
)
2811 return git_checkout_options_init(opts
, version
);