vendor/libgit2/src/checkout.c in rugged-0.21.4 vs vendor/libgit2/src/checkout.c in rugged-0.22.0b1

- old
+ new

@@ -35,27 +35,32 @@ CHECKOUT_ACTION__NONE = 0, CHECKOUT_ACTION__REMOVE = 1, CHECKOUT_ACTION__UPDATE_BLOB = 2, CHECKOUT_ACTION__UPDATE_SUBMODULE = 4, CHECKOUT_ACTION__CONFLICT = 8, - CHECKOUT_ACTION__UPDATE_CONFLICT = 16, - CHECKOUT_ACTION__MAX = 16, - CHECKOUT_ACTION__DEFER_REMOVE = 32, + CHECKOUT_ACTION__REMOVE_CONFLICT = 16, + CHECKOUT_ACTION__UPDATE_CONFLICT = 32, + CHECKOUT_ACTION__MAX = 32, + CHECKOUT_ACTION__DEFER_REMOVE = 64, CHECKOUT_ACTION__REMOVE_AND_UPDATE = (CHECKOUT_ACTION__UPDATE_BLOB | CHECKOUT_ACTION__REMOVE), }; typedef struct { git_repository *repo; + git_iterator *target; git_diff *diff; git_checkout_options opts; bool opts_free_baseline; char *pfx; git_index *index; git_pool pool; git_vector removes; - git_vector conflicts; + git_vector remove_conflicts; + git_vector update_conflicts; + git_vector *update_reuc; + git_vector *update_names; git_buf path; size_t workdir_len; git_buf tmp; unsigned int strategy; int can_symlink; @@ -114,10 +119,11 @@ target = &delta->new_file; break; case GIT_DELTA_ADDED: case GIT_DELTA_IGNORED: case GIT_DELTA_UNTRACKED: + case GIT_DELTA_UNREADABLE: target = &delta->new_file; break; case GIT_DELTA_DELETED: baseline = &delta->old_file; break; @@ -136,10 +142,11 @@ } static bool checkout_is_workdir_modified( checkout_data *data, const git_diff_file *baseitem, + const git_diff_file *newitem, const git_index_entry *wditem) { git_oid oid; const git_index_entry *ie; @@ -167,17 +174,20 @@ return rval; } /* Look at the cache to decide if the workdir is modified. If not, * we can simply compare the oid in the cache to the baseitem instead - * of hashing the file. + * of hashing the file. If so, we allow the checkout to proceed if the + * oid is identical (ie, the staged item is what we're trying to check + * out.) */ if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) { if (wditem->mtime.seconds == ie->mtime.seconds && wditem->mtime.nanoseconds == ie->mtime.nanoseconds && wditem->file_size == ie->file_size) - return (git_oid__cmp(&baseitem->id, &ie->id) != 0); + return (git_oid__cmp(&baseitem->id, &ie->id) != 0 && + git_oid_cmp(&newitem->id, &ie->id) != 0); } /* depending on where base is coming from, we may or may not know * the actual size of the data, so we can't rely on this shortcut. */ @@ -399,11 +409,11 @@ { *action = CHECKOUT_ACTION__NONE; switch (delta->status) { case GIT_DELTA_UNMODIFIED: /* case 14/15 or 33 */ - if (checkout_is_workdir_modified(data, &delta->old_file, wd)) { + if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) { GITERR_CHECK_ERROR( checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd) ); *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, NONE); } break; @@ -412,17 +422,17 @@ *action = CHECKOUT_ACTION_IF(DONT_OVERWRITE_IGNORED, CONFLICT, UPDATE_BLOB); else *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT); break; case GIT_DELTA_DELETED: /* case 9 or 10 (or 26 but not really) */ - if (checkout_is_workdir_modified(data, &delta->old_file, wd)) + if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT); else *action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE); break; case GIT_DELTA_MODIFIED: /* case 16, 17, 18 (or 36 but not really) */ - if (checkout_is_workdir_modified(data, &delta->old_file, wd)) + if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT); else *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); break; case GIT_DELTA_TYPECHANGE: /* case 22, 23, 29, 30 */ @@ -441,11 +451,11 @@ else *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); } else *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT); } - else if (checkout_is_workdir_modified(data, &delta->old_file, wd)) + else if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); else *action = CHECKOUT_ACTION_IF(SAFE, REMOVE_AND_UPDATE, NONE); /* don't update if the typechange is to a tree */ @@ -783,42 +793,62 @@ git_blob_free(their_blob); return error; } -static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, git_vector *pathspec) +static int checkout_conflict_append_update( + const git_index_entry *ancestor, + const git_index_entry *ours, + const git_index_entry *theirs, + void *payload) { + checkout_data *data = payload; + checkout_conflictdata *conflict; + int error; + + conflict = git__calloc(1, sizeof(checkout_conflictdata)); + GITERR_CHECK_ALLOC(conflict); + + conflict->ancestor = ancestor; + conflict->ours = ours; + conflict->theirs = theirs; + + if ((error = checkout_conflict_detect_submodule(conflict)) < 0 || + (error = checkout_conflict_detect_binary(data->repo, conflict)) < 0) + { + git__free(conflict); + return error; + } + + if (git_vector_insert(&data->update_conflicts, conflict)) + return -1; + + return 0; +} + +static int checkout_conflicts_foreach( + checkout_data *data, + git_index *index, + git_iterator *workdir, + git_vector *pathspec, + int (*cb)(const git_index_entry *, const git_index_entry *, const git_index_entry *, void *), + void *payload) +{ git_index_conflict_iterator *iterator = NULL; const git_index_entry *ancestor, *ours, *theirs; - checkout_conflictdata *conflict; int error = 0; - if ((error = git_index_conflict_iterator_new(&iterator, data->index)) < 0) + if ((error = git_index_conflict_iterator_new(&iterator, index)) < 0) goto done; - data->conflicts._cmp = checkout_conflictdata_cmp; - /* Collect the conflicts */ while ((error = git_index_conflict_next(&ancestor, &ours, &theirs, iterator)) == 0) { if (!conflict_pathspec_match(data, workdir, pathspec, ancestor, ours, theirs)) continue; - conflict = git__calloc(1, sizeof(checkout_conflictdata)); - GITERR_CHECK_ALLOC(conflict); - - conflict->ancestor = ancestor; - conflict->ours = ours; - conflict->theirs = theirs; - - if ((error = checkout_conflict_detect_submodule(conflict)) < 0 || - (error = checkout_conflict_detect_binary(data->repo, conflict)) < 0) - { - git__free(conflict); + if ((error = cb(ancestor, ours, theirs, payload)) < 0) goto done; - } - - git_vector_insert(&data->conflicts, conflict); } if (error == GIT_ITEROVER) error = 0; @@ -826,10 +856,30 @@ git_index_conflict_iterator_free(iterator); return error; } +static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, git_vector *pathspec) +{ + git_index *index; + + /* Only write conficts from sources that have them: indexes. */ + if ((index = git_iterator_get_index(data->target)) == NULL) + return 0; + + data->update_conflicts._cmp = checkout_conflictdata_cmp; + + if (checkout_conflicts_foreach(data, index, workdir, pathspec, checkout_conflict_append_update, data) < 0) + return -1; + + /* Collect the REUC and NAME entries */ + data->update_reuc = &index->reuc; + data->update_names = &index->names; + + return 0; +} + GIT_INLINE(int) checkout_conflicts_cmp_entry( const char *path, const git_index_entry *entry) { return strcmp((const char *)path, entry->path); @@ -850,24 +900,24 @@ checkout_data *data, const char *path) { size_t pos; - if (git_vector_bsearch2(&pos, &data->conflicts, checkout_conflicts_cmp_ancestor, path) < 0) + if (git_vector_bsearch2(&pos, &data->update_conflicts, checkout_conflicts_cmp_ancestor, path) < 0) return NULL; - return git_vector_get(&data->conflicts, pos); + return git_vector_get(&data->update_conflicts, pos); } static checkout_conflictdata *checkout_conflicts_search_branch( checkout_data *data, const char *path) { checkout_conflictdata *conflict; size_t i; - git_vector_foreach(&data->conflicts, i, conflict) { + git_vector_foreach(&data->update_conflicts, i, conflict) { int cmp = -1; if (conflict->ancestor) break; @@ -955,20 +1005,24 @@ } static int checkout_conflicts_coalesce_renames( checkout_data *data) { + git_index *index; const git_index_name_entry *name_entry; checkout_conflictdata *ancestor_conflict, *our_conflict, *their_conflict; size_t i, names; int error = 0; + if ((index = git_iterator_get_index(data->target)) == NULL) + return 0; + /* Juggle entries based on renames */ - names = git_index_name_entrycount(data->index); + names = git_index_name_entrycount(index); for (i = 0; i < names; i++) { - name_entry = git_index_name_get_byindex(data->index, i); + name_entry = git_index_name_get_byindex(index, i); if ((error = checkout_conflicts_load_byname_entry( &ancestor_conflict, &our_conflict, &their_conflict, data, name_entry)) < 0) goto done; @@ -999,46 +1053,50 @@ their_conflict && their_conflict != ancestor_conflict) ancestor_conflict->one_to_two = 1; } git_vector_remove_matching( - &data->conflicts, checkout_conflictdata_empty, NULL); + &data->update_conflicts, checkout_conflictdata_empty, NULL); done: return error; } static int checkout_conflicts_mark_directoryfile( checkout_data *data) { + git_index *index; checkout_conflictdata *conflict; const git_index_entry *entry; size_t i, j, len; const char *path; int prefixed, error = 0; - len = git_index_entrycount(data->index); + if ((index = git_iterator_get_index(data->target)) == NULL) + return 0; + len = git_index_entrycount(index); + /* Find d/f conflicts */ - git_vector_foreach(&data->conflicts, i, conflict) { + git_vector_foreach(&data->update_conflicts, i, conflict) { if ((conflict->ours && conflict->theirs) || (!conflict->ours && !conflict->theirs)) continue; path = conflict->ours ? conflict->ours->path : conflict->theirs->path; - if ((error = git_index_find(&j, data->index, path)) < 0) { + if ((error = git_index_find(&j, index, path)) < 0) { if (error == GIT_ENOTFOUND) giterr_set(GITERR_INDEX, "Index inconsistency, could not find entry for expected conflict '%s'", path); goto done; } for (; j < len; j++) { - if ((entry = git_index_get_byindex(data->index, j)) == NULL) { + if ((entry = git_index_get_byindex(index, j)) == NULL) { giterr_set(GITERR_INDEX, "Index inconsistency, truncated index while loading expected conflict '%s'", path); error = -1; goto done; } @@ -1057,11 +1115,11 @@ done: return error; } -static int checkout_get_conflicts( +static int checkout_get_update_conflicts( checkout_data *data, git_iterator *workdir, git_vector *pathspec) { int error = 0; @@ -1076,34 +1134,46 @@ done: return error; } -static int checkout_verify_paths( - git_repository *repo, - int action, - git_diff_delta *delta) +static int checkout_conflict_append_remove( + const git_index_entry *ancestor, + const git_index_entry *ours, + const git_index_entry *theirs, + void *payload) { - unsigned int flags = GIT_PATH_REJECT_DEFAULTS | GIT_PATH_REJECT_DOT_GIT; + checkout_data *data = payload; + const char *name; - if (action & CHECKOUT_ACTION__REMOVE) { - if (!git_path_isvalid(repo, delta->old_file.path, flags)) { - giterr_set(GITERR_CHECKOUT, "Cannot remove invalid path '%s'", delta->old_file.path); - return -1; - } - } + assert(ancestor || ours || theirs); - if (action & ~CHECKOUT_ACTION__REMOVE) { - if (!git_path_isvalid(repo, delta->new_file.path, flags)) { - giterr_set(GITERR_CHECKOUT, "Cannot checkout to invalid path '%s'", delta->old_file.path); - return -1; - } - } + if (ancestor) + name = git__strdup(ancestor->path); + else if (ours) + name = git__strdup(ours->path); + else if (theirs) + name = git__strdup(theirs->path); + else + abort(); - return 0; + GITERR_CHECK_ALLOC(name); + + return git_vector_insert(&data->remove_conflicts, (char *)name); } +static int checkout_get_remove_conflicts( + checkout_data *data, + git_iterator *workdir, + git_vector *pathspec) +{ + if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) != 0) + return 0; + + return checkout_conflicts_foreach(data, data->index, workdir, pathspec, checkout_conflict_append_remove, data); +} + static int checkout_get_actions( uint32_t **actions_ptr, size_t **counts_ptr, checkout_data *data, git_iterator *workdir) @@ -1133,13 +1203,11 @@ error = -1; goto fail; } git_vector_foreach(deltas, i, delta) { - if ((error = checkout_action(&act, data, delta, workdir, &wditem, &pathspec)) == 0) - error = checkout_verify_paths(data->repo, act, delta); - + error = checkout_action(&act, data, delta, workdir, &wditem, &pathspec); if (error != 0) goto fail; actions[i] = act; @@ -1169,14 +1237,16 @@ error = GIT_EMERGECONFLICT; goto fail; } - if ((error = checkout_get_conflicts(data, workdir, &pathspec)) < 0) + if ((error = checkout_get_remove_conflicts(data, workdir, &pathspec)) < 0 || + (error = checkout_get_update_conflicts(data, workdir, &pathspec)) < 0) goto fail; - counts[CHECKOUT_ACTION__UPDATE_CONFLICT] = git_vector_length(&data->conflicts); + counts[CHECKOUT_ACTION__REMOVE_CONFLICT] = git_vector_length(&data->remove_conflicts); + counts[CHECKOUT_ACTION__UPDATE_CONFLICT] = git_vector_length(&data->update_conflicts); git_pathspec__vfree(&pathspec); git_pool_clear(&pathpool); return 0; @@ -1844,17 +1914,49 @@ git_buf_free(&path_suffixed); return error; } +static int checkout_conflict_add( + checkout_data *data, + const git_index_entry *conflict) +{ + int error = git_index_remove(data->index, conflict->path, 0); + + if (error == GIT_ENOTFOUND) + giterr_clear(); + else if (error < 0) + return error; + + return git_index_add(data->index, conflict); +} + +static int checkout_conflict_update_index( + checkout_data *data, + checkout_conflictdata *conflict) +{ + int error = 0; + + if (conflict->ancestor) + error = checkout_conflict_add(data, conflict->ancestor); + + if (!error && conflict->ours) + error = checkout_conflict_add(data, conflict->ours); + + if (!error && conflict->theirs) + error = checkout_conflict_add(data, conflict->theirs); + + return error; +} + static int checkout_create_conflicts(checkout_data *data) { checkout_conflictdata *conflict; size_t i; int error = 0; - git_vector_foreach(&data->conflicts, i, conflict) { + git_vector_foreach(&data->update_conflicts, i, conflict) { /* Both deleted: nothing to do */ if (conflict->ours == NULL && conflict->theirs == NULL) error = 0; @@ -1906,10 +2008,16 @@ error = checkout_write_entry(data, conflict, conflict->ours); else if (!error) error = checkout_write_merge(data, conflict); + /* Update the index extensions (REUC and NAME) if we're checking + * out a different index. (Otherwise just leave them there.) + */ + if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0) + error = checkout_conflict_update_index(data, conflict); + if (error) break; data->completed_steps++; report_progress(data, @@ -1918,22 +2026,69 @@ } return error; } +static int checkout_remove_conflicts(checkout_data *data) +{ + const char *conflict; + size_t i; + git_vector_foreach(&data->remove_conflicts, i, conflict) { + if (git_index_conflict_remove(data->index, conflict) < 0) + return -1; + + data->completed_steps++; + } + + return 0; +} + +static int checkout_extensions_update_index(checkout_data *data) +{ + const git_index_reuc_entry *reuc_entry; + const git_index_name_entry *name_entry; + size_t i; + int error = 0; + + if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) + return 0; + + if (data->update_reuc) { + git_vector_foreach(data->update_reuc, i, reuc_entry) { + if ((error = git_index_reuc_add(data->index, reuc_entry->path, + reuc_entry->mode[0], &reuc_entry->oid[0], + reuc_entry->mode[1], &reuc_entry->oid[1], + reuc_entry->mode[2], &reuc_entry->oid[2])) < 0) + goto done; + } + } + + if (data->update_names) { + git_vector_foreach(data->update_names, i, name_entry) { + if ((error = git_index_name_add(data->index, name_entry->ancestor, + name_entry->ours, name_entry->theirs)) < 0) + goto done; + } + } + +done: + return error; +} + static void checkout_data_clear(checkout_data *data) { if (data->opts_free_baseline) { git_tree_free(data->opts.baseline); data->opts.baseline = NULL; } git_vector_free(&data->removes); git_pool_clear(&data->pool); - git_vector_free_deep(&data->conflicts); + git_vector_free_deep(&data->remove_conflicts); + git_vector_free_deep(&data->update_conflicts); git__free(data->pfx); data->pfx = NULL; git_buf_free(&data->path); @@ -1961,10 +2116,11 @@ if ((!proposed || !proposed->target_directory) && (error = git_repository__ensure_not_bare(repo, "checkout")) < 0) return error; data->repo = repo; + data->target = target; GITERR_CHECK_VERSION( proposed, GIT_CHECKOUT_OPTIONS_VERSION, "git_checkout_options"); if (!proposed) @@ -1981,23 +2137,22 @@ /* refresh config and index content unless NO_REFRESH is given */ if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) { git_config *cfg; - if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 || - (error = git_config_refresh(cfg)) < 0) + if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) goto cleanup; - /* if we are checking out the index, don't reload, - * otherwise get index and force reload + /* Get the repository index and reload it (unless we're checking + * out the index; then it has the changes we're trying to check + * out and those should not be overwritten.) */ - if ((data->index = git_iterator_get_index(target)) != NULL) { - GIT_REFCOUNT_INC(data->index); - } else { - /* otherwise, grab and reload the index */ - if ((error = git_repository_index(&data->index, data->repo)) < 0 || - (error = git_index_read(data->index, true)) < 0) + if ((error = git_repository_index(&data->index, data->repo)) < 0) + goto cleanup; + + if (data->index != git_iterator_get_index(target)) { + if ((error = git_index_read(data->index, true)) < 0) goto cleanup; /* cannot checkout if unresolved conflicts exist */ if ((data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) == 0 && git_index_has_conflicts(data->index)) { @@ -2005,11 +2160,11 @@ giterr_set(GITERR_CHECKOUT, "unresolved conflicts exist in the index"); goto cleanup; } - /* clean conflict data when doing a tree or commit checkout */ + /* clean conflict data in the current index */ git_index_name_clear(data->index); git_index_reuc_clear(data->index); } } @@ -2071,11 +2226,12 @@ goto cleanup; } } if ((error = git_vector_init(&data->removes, 0, git__strcmp_cb)) < 0 || - (error = git_vector_init(&data->conflicts, 0, NULL)) < 0 || + (error = git_vector_init(&data->remove_conflicts, 0, NULL)) < 0 || + (error = git_vector_init(&data->update_conflicts, 0, NULL)) < 0 || (error = git_pool_init(&data->pool, 1, 0)) < 0 || (error = git_buf_puts(&data->path, data->opts.target_directory)) < 0 || (error = git_path_to_dir(&data->path)) < 0) goto cleanup; @@ -2088,10 +2244,11 @@ return error; } int git_checkout_iterator( git_iterator *target, + git_index *index, const git_checkout_options *opts) { int error = 0; git_iterator *baseline = NULL, *workdir = NULL; checkout_data data = {0}; @@ -2105,10 +2262,11 @@ if (error < 0) return error; diff_opts.flags = GIT_DIFF_INCLUDE_UNMODIFIED | + GIT_DIFF_INCLUDE_UNREADABLE | GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_RECURSE_UNTRACKED_DIRS | /* needed to match baseline */ GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_INCLUDE_TYPECHANGE_TREES | @@ -2123,11 +2281,11 @@ iterflags = git_iterator_ignore_case(target) ? GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE; if ((error = git_iterator_reset(target, data.pfx, data.pfx)) < 0 || (error = git_iterator_for_workdir_ext( - &workdir, data.repo, data.opts.target_directory, + &workdir, data.repo, data.opts.target_directory, index, NULL, iterflags | GIT_ITERATOR_DONT_AUTOEXPAND, data.pfx, data.pfx)) < 0 || (error = git_iterator_for_tree( &baseline, data.opts.baseline, iterflags, data.pfx, data.pfx)) < 0) @@ -2149,10 +2307,11 @@ */ if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) != 0) goto cleanup; data.total_steps = counts[CHECKOUT_ACTION__REMOVE] + + counts[CHECKOUT_ACTION__REMOVE_CONFLICT] + counts[CHECKOUT_ACTION__UPDATE_BLOB] + counts[CHECKOUT_ACTION__UPDATE_SUBMODULE] + counts[CHECKOUT_ACTION__UPDATE_CONFLICT]; report_progress(&data, NULL); /* establish 0 baseline */ @@ -2162,10 +2321,14 @@ */ if (counts[CHECKOUT_ACTION__REMOVE] > 0 && (error = checkout_remove_the_old(actions, &data)) < 0) goto cleanup; + if (counts[CHECKOUT_ACTION__REMOVE_CONFLICT] > 0 && + (error = checkout_remove_conflicts(&data)) < 0) + goto cleanup; + if (counts[CHECKOUT_ACTION__UPDATE_BLOB] > 0 && (error = checkout_create_the_new(actions, &data)) < 0) goto cleanup; if (counts[CHECKOUT_ACTION__UPDATE_SUBMODULE] > 0 && @@ -2174,10 +2337,14 @@ if (counts[CHECKOUT_ACTION__UPDATE_CONFLICT] > 0 && (error = checkout_create_conflicts(&data)) < 0) goto cleanup; + if (data.index != git_iterator_get_index(target) && + (error = checkout_extensions_update_index(&data)) < 0) + goto cleanup; + assert(data.completed_steps == data.total_steps); cleanup: if (!error && data.index != NULL && (data.strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0) @@ -2196,34 +2363,43 @@ int git_checkout_index( git_repository *repo, git_index *index, const git_checkout_options *opts) { - int error; + int error, owned = 0; git_iterator *index_i; if (!index && !repo) { giterr_set(GITERR_CHECKOUT, "Must provide either repository or index to checkout"); return -1; } - if (index && repo && git_index_owner(index) != repo) { + + if (index && repo && + git_index_owner(index) && + git_index_owner(index) != repo) { giterr_set(GITERR_CHECKOUT, "Index to checkout does not match repository"); return -1; + } else if(index && repo && !git_index_owner(index)) { + GIT_REFCOUNT_OWN(index, repo); + owned = 1; } if (!repo) repo = git_index_owner(index); if (!index && (error = git_repository_index__weakptr(&index, repo)) < 0) return error; GIT_REFCOUNT_INC(index); if (!(error = git_iterator_for_index(&index_i, index, 0, NULL, NULL))) - error = git_checkout_iterator(index_i, opts); + error = git_checkout_iterator(index_i, index, opts); + if (owned) + GIT_REFCOUNT_OWN(index, NULL); + git_iterator_free(index_i); git_index_free(index); return error; } @@ -2232,10 +2408,11 @@ git_repository *repo, const git_object *treeish, const git_checkout_options *opts) { int error; + git_index *index; git_tree *tree = NULL; git_iterator *tree_i = NULL; if (!treeish && !repo) { giterr_set(GITERR_CHECKOUT, @@ -2266,13 +2443,17 @@ "HEAD could not be peeled to a tree and no treeish given"); return error; } } + if ((error = git_repository_index(&index, repo)) < 0) + return error; + if (!(error = git_iterator_for_tree(&tree_i, tree, 0, NULL, NULL))) - error = git_checkout_iterator(tree_i, opts); + error = git_checkout_iterator(tree_i, index, opts); git_iterator_free(tree_i); + git_index_free(index); git_tree_free(tree); return error; }