Commit 967f5a76 by Edward Thomson Committed by Edward Thomson

git_checkout_index: checkout other indexes

git_checkout_index can now check out other git_index's (that are not
necessarily the repository index).  This allows checkout_index to use
the repository's index for stat cache information instead of the index
data being checked out.  git_merge and friends now check out their
indexes directly instead of trying to blend it into the running index.
parent 1453bd20
......@@ -171,7 +171,7 @@ int git_cherry_pick(
char commit_oidstr[GIT_OID_HEXSZ + 1];
const char *commit_msg, *commit_summary;
git_buf their_label = GIT_BUF_INIT;
git_index *index_new = NULL, *index_repo = NULL;
git_index *index_new = NULL;
int error = 0;
assert(repo && commit);
......@@ -196,12 +196,10 @@ int git_cherry_pick(
(error = git_repository_head(&our_ref, repo)) < 0 ||
(error = git_reference_peel((git_object **)&our_commit, our_ref, GIT_OBJ_COMMIT)) < 0 ||
(error = git_cherry_pick_commit(&index_new, repo, commit, our_commit, opts.mainline, &opts.merge_opts)) < 0 ||
(error = git_merge__indexes(repo, index_new)) < 0 ||
(error = git_repository_index(&index_repo, repo)) < 0 ||
(error = git_merge__append_conflicts_to_merge_msg(repo, index_repo)) < 0 ||
(error = git_checkout_index(repo, index_repo, &opts.checkout_opts)) < 0)
(error = git_merge__check_result(repo, index_new)) < 0 ||
(error = git_merge__append_conflicts_to_merge_msg(repo, index_new)) < 0 ||
(error = git_checkout_index(repo, index_new, &opts.checkout_opts)) < 0)
goto on_error;
goto done;
on_error:
......@@ -209,7 +207,6 @@ on_error:
done:
git_index_free(index_new);
git_index_free(index_repo);
git_commit_free(our_commit);
git_reference_free(our_ref);
git_buf_free(&their_label);
......
......@@ -2226,64 +2226,6 @@ static int merge_normalize_checkout_opts(
return error;
}
static int merge_affected_paths(git_vector *paths, git_repository *repo, git_index *index_new)
{
git_tree *head_tree = NULL;
git_iterator *iter_head = NULL, *iter_new = NULL;
git_diff *merged_list = NULL;
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
git_diff_delta *delta;
size_t i;
const git_index_entry *e;
char *path;
int error = 0;
if ((error = git_repository_head_tree(&head_tree, repo)) < 0 ||
(error = git_iterator_for_tree(&iter_head, head_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
(error = git_iterator_for_index(&iter_new, index_new, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
(error = git_diff__from_iterators(&merged_list, repo, iter_head, iter_new, &opts)) < 0)
goto done;
git_vector_foreach(&merged_list->deltas, i, delta) {
path = git__strdup(delta->new_file.path);
GITERR_CHECK_ALLOC(path);
if ((error = git_vector_insert(paths, path)) < 0)
goto on_error;
}
for (i = 0; i < git_index_entrycount(index_new); i++) {
e = git_index_get_byindex(index_new, i);
if (git_index_entry_stage(e) != 0 &&
(git_vector_last(paths) == NULL ||
strcmp(git_vector_last(paths), e->path) != 0)) {
path = git__strdup(e->path);
GITERR_CHECK_ALLOC(path);
if ((error = git_vector_insert(paths, path)) < 0)
goto on_error;
}
}
goto done;
on_error:
git_vector_foreach(paths, i, path)
git__free(path);
git_vector_clear(paths);
done:
git_tree_free(head_tree);
git_iterator_free(iter_head);
git_iterator_free(iter_new);
git_diff_free(merged_list);
return error;
}
static int merge_check_index(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths)
{
git_tree *head_tree = NULL;
......@@ -2372,99 +2314,58 @@ done:
return error;
}
int git_merge__indexes(git_repository *repo, git_index *index_new)
int git_merge__check_result(git_repository *repo, git_index *index_new)
{
git_index *index_repo = NULL;
int index_repo_caps = 0;
git_tree *head_tree = NULL;
git_iterator *iter_head = NULL, *iter_new = NULL;
git_diff *merged_list = NULL;
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
git_diff_delta *delta;
git_vector paths = GIT_VECTOR_INIT;
size_t index_conflicts = 0, wd_conflicts = 0, conflicts, i;
char *path;
size_t i, index_conflicts = 0, wd_conflicts = 0, conflicts;
const git_index_entry *e;
const git_index_name_entry *name;
const git_index_reuc_entry *reuc;
int error = 0;
if ((error = git_repository_index(&index_repo, repo)) < 0)
goto done;
/* Set the index to case sensitive to handle the merge */
index_repo_caps = git_index_caps(index_repo);
if ((error = git_index_set_caps(index_repo, (index_repo_caps & ~GIT_INDEXCAP_IGNORE_CASE))) < 0)
goto done;
/* Make sure the index and workdir state do not prevent merging */
if ((error = merge_affected_paths(&paths, repo, index_new)) < 0 ||
(error = merge_check_index(&index_conflicts, repo, index_new, &paths)) < 0 ||
(error = merge_check_workdir(&wd_conflicts, repo, index_new, &paths)) < 0)
goto done;
if ((conflicts = index_conflicts + wd_conflicts) > 0) {
giterr_set(GITERR_MERGE, "%d uncommitted change%s would be overwritten by merge",
conflicts, (conflicts != 1) ? "s" : "");
error = GIT_EMERGECONFLICT;
if ((error = git_repository_head_tree(&head_tree, repo)) < 0 ||
(error = git_iterator_for_tree(&iter_head, head_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
(error = git_iterator_for_index(&iter_new, index_new, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
(error = git_diff__from_iterators(&merged_list, repo, iter_head, iter_new, &opts)) < 0)
goto done;
}
/* Remove removed items from the index */
git_vector_foreach(&paths, i, path) {
if (git_index_get_bypath(index_new, path, 0) == NULL) {
if ((error = git_index_remove(index_repo, path, 0)) < 0 &&
error != GIT_ENOTFOUND)
goto done;
}
}
/* Add updated items to the index */
git_vector_foreach(&paths, i, path) {
if ((e = git_index_get_bypath(index_new, path, 0)) != NULL) {
if ((error = git_index_add(index_repo, e)) < 0)
goto done;
}
git_vector_foreach(&merged_list->deltas, i, delta) {
if ((error = git_vector_insert(&paths, (char *)delta->new_file.path)) < 0)
goto done;
}
/* Add conflicts */
git_index_conflict_cleanup(index_repo);
for (i = 0; i < git_index_entrycount(index_new); i++) {
e = git_index_get_byindex(index_new, i);
if (git_index_entry_stage(e) != 0 &&
(error = git_index_add(index_repo, e)) < 0)
goto done;
}
(git_vector_last(&paths) == NULL ||
strcmp(git_vector_last(&paths), e->path) != 0)) {
/* Add name entries */
git_index_name_clear(index_repo);
for (i = 0; i < git_index_name_entrycount(index_new); i++) {
name = git_index_name_get_byindex(index_new, i);
if ((error = git_index_name_add(index_repo,
name->ancestor, name->ours, name->theirs)) < 0)
goto done;
if ((error = git_vector_insert(&paths, (char *)e->path)) < 0)
goto done;
}
}
/* Add the reuc */
git_index_reuc_clear(index_repo);
for (i = 0; i < git_index_reuc_entrycount(index_new); i++) {
reuc = (git_index_reuc_entry *)git_index_reuc_get_byindex(index_new, i);
/* Make sure the index and workdir state do not prevent merging */
if ((error = merge_check_index(&index_conflicts, repo, index_new, &paths)) < 0 ||
(error = merge_check_workdir(&wd_conflicts, repo, index_new, &paths)) < 0)
goto done;
if ((error = git_index_reuc_add(index_repo, reuc->path,
reuc->mode[0], &reuc->oid[0],
reuc->mode[1], &reuc->oid[1],
reuc->mode[2], &reuc->oid[2])) < 0)
goto done;
if ((conflicts = index_conflicts + wd_conflicts) > 0) {
giterr_set(GITERR_MERGE, "%d uncommitted change%s would be overwritten by merge",
conflicts, (conflicts != 1) ? "s" : "");
error = GIT_EMERGECONFLICT;
}
done:
if (index_repo != NULL)
git_index_set_caps(index_repo, index_repo_caps);
git_index_free(index_repo);
git_vector_free_deep(&paths);
git_vector_free(&paths);
git_tree_free(head_tree);
git_iterator_free(iter_head);
git_iterator_free(iter_new);
git_diff_free(merged_list);
return error;
}
......@@ -2657,7 +2558,7 @@ int git_merge(
git_checkout_options checkout_opts;
git_merge_head *ancestor_head = NULL, *our_head = NULL;
git_tree *ancestor_tree = NULL, *our_tree = NULL, **their_trees = NULL;
git_index *index_new = NULL, *index_repo = NULL;
git_index *index_new = NULL;
size_t i;
int error = 0;
......@@ -2697,10 +2598,9 @@ int git_merge(
/* TODO: recursive, octopus, etc... */
if ((error = git_merge_trees(&index_new, repo, ancestor_tree, our_tree, their_trees[0], merge_opts)) < 0 ||
(error = git_merge__indexes(repo, index_new)) < 0 ||
(error = git_repository_index(&index_repo, repo)) < 0 ||
(error = git_merge__append_conflicts_to_merge_msg(repo, index_repo)) < 0 ||
(error = git_checkout_index(repo, index_repo, &checkout_opts)) < 0)
(error = git_merge__check_result(repo, index_new)) < 0 ||
(error = git_merge__append_conflicts_to_merge_msg(repo, index_new)) < 0 ||
(error = git_checkout_index(repo, index_new, &checkout_opts)) < 0)
goto on_error;
goto done;
......@@ -2710,7 +2610,6 @@ on_error:
done:
git_index_free(index_new);
git_index_free(index_repo);
git_tree_free(ancestor_tree);
git_tree_free(our_tree);
......
......@@ -149,7 +149,7 @@ int git_merge__setup(
const git_merge_head *heads[],
size_t heads_len);
int git_merge__indexes(git_repository *repo, git_index *index_new);
int git_merge__check_result(git_repository *repo, git_index *index_new);
int git_merge__append_conflicts_to_merge_msg(git_repository *repo, git_index *index);
......
......@@ -174,7 +174,7 @@ int git_revert(
char commit_oidstr[GIT_OID_HEXSZ + 1];
const char *commit_msg;
git_buf their_label = GIT_BUF_INIT;
git_index *index_new = NULL, *index_repo = NULL;
git_index *index_new = NULL;
int error;
assert(repo && commit);
......@@ -199,10 +199,9 @@ int git_revert(
(error = git_repository_head(&our_ref, repo)) < 0 ||
(error = git_reference_peel((git_object **)&our_commit, our_ref, GIT_OBJ_COMMIT)) < 0 ||
(error = git_revert_commit(&index_new, repo, commit, our_commit, opts.mainline, &opts.merge_opts)) < 0 ||
(error = git_merge__indexes(repo, index_new)) < 0 ||
(error = git_repository_index(&index_repo, repo)) < 0 ||
(error = git_merge__append_conflicts_to_merge_msg(repo, index_repo)) < 0 ||
(error = git_checkout_index(repo, index_repo, &opts.checkout_opts)) < 0)
(error = git_merge__check_result(repo, index_new)) < 0 ||
(error = git_merge__append_conflicts_to_merge_msg(repo, index_new)) < 0 ||
(error = git_checkout_index(repo, index_new, &opts.checkout_opts)) < 0)
goto on_error;
goto done;
......@@ -212,7 +211,6 @@ on_error:
done:
git_index_free(index_new);
git_index_free(index_repo);
git_commit_free(our_commit);
git_reference_free(our_ref);
git_buf_free(&their_label);
......
......@@ -97,7 +97,7 @@ static int merge_branch(void)
cl_git_pass(git_oid_fromstr(&their_oids[0], MERGE_BRANCH_OID));
cl_git_pass(git_merge_head_from_id(&their_heads[0], repo, &their_oids[0]));
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_ALLOW_CONFLICTS;
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
error = git_merge(repo, (const git_merge_head **)their_heads, 1, &merge_opts, &checkout_opts);
git_merge_head_free(their_heads[0]);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment