/* * call-seq: * index.conflict_remove(path) -> nil * * Removes the index entries that represent the conflict at +path+. */ static VALUE rb_git_conflict_remove(VALUE self, VALUE rb_path) { git_index *index; int error; Check_Type(rb_path, T_STRING); Data_Get_Struct(self, git_index, index); error = git_index_conflict_remove(index, StringValueCStr(rb_path)); rugged_exception_check(error); return Qnil; }
void test_index_conflicts__remove(void) { const git_index_entry *entry; size_t i; cl_assert(git_index_entrycount(repo_index) == 8); cl_git_pass(git_index_conflict_remove(repo_index, "conflicts-one.txt")); cl_assert(git_index_entrycount(repo_index) == 5); for (i = 0; i < git_index_entrycount(repo_index); i++) { cl_assert(entry = git_index_get_byindex(repo_index, i)); cl_assert(strcmp(entry->path, "conflicts-one.txt") != 0); } cl_git_pass(git_index_conflict_remove(repo_index, "conflicts-two.txt")); cl_assert(git_index_entrycount(repo_index) == 2); for (i = 0; i < git_index_entrycount(repo_index); i++) { cl_assert(entry = git_index_get_byindex(repo_index, i)); cl_assert(strcmp(entry->path, "conflicts-two.txt") != 0); } }
int git_reset_default( git_repository *repo, const git_object *target, const git_strarray* pathspecs) { git_object *commit = NULL; git_tree *tree = NULL; git_diff *diff = NULL; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; size_t i, max_i; git_index_entry entry; int error; git_index *index = NULL; assert(pathspecs != NULL && pathspecs->count > 0); memset(&entry, 0, sizeof(git_index_entry)); if ((error = git_repository_index(&index, repo)) < 0) goto cleanup; if (target) { if (git_object_owner(target) != repo) { giterr_set(GITERR_OBJECT, "%s_default - The given target does not belong to this repository.", ERROR_MSG); return -1; } if ((error = git_object_peel(&commit, target, GIT_OBJECT_COMMIT)) < 0 || (error = git_commit_tree(&tree, (git_commit *)commit)) < 0) goto cleanup; } opts.pathspec = *pathspecs; opts.flags = GIT_DIFF_REVERSE; if ((error = git_diff_tree_to_index( &diff, repo, tree, index, &opts)) < 0) goto cleanup; for (i = 0, max_i = git_diff_num_deltas(diff); i < max_i; ++i) { const git_diff_delta *delta = git_diff_get_delta(diff, i); assert(delta->status == GIT_DELTA_ADDED || delta->status == GIT_DELTA_MODIFIED || delta->status == GIT_DELTA_CONFLICTED || delta->status == GIT_DELTA_DELETED); error = git_index_conflict_remove(index, delta->old_file.path); if (error < 0) { if (delta->status == GIT_DELTA_ADDED && error == GIT_ENOTFOUND) giterr_clear(); else goto cleanup; } if (delta->status == GIT_DELTA_DELETED) { if ((error = git_index_remove(index, delta->old_file.path, 0)) < 0) goto cleanup; } else { entry.mode = delta->new_file.mode; git_oid_cpy(&entry.id, &delta->new_file.id); entry.path = (char *)delta->new_file.path; if ((error = git_index_add(index, &entry)) < 0) goto cleanup; } } error = git_index_write(index); cleanup: git_object_free(commit); git_tree_free(tree); git_index_free(index); git_diff_free(diff); return error; }
static int try_to_git_merge(git_repository *repo, git_reference *local, git_reference *remote, git_oid *base, const git_oid *local_id, const git_oid *remote_id) { git_tree *local_tree, *remote_tree, *base_tree; git_commit *local_commit, *remote_commit, *base_commit; git_index *merged_index; git_merge_options merge_options; if (verbose) { char outlocal[41], outremote[41]; outlocal[40] = outremote[40] = 0; git_oid_fmt(outlocal, local_id); git_oid_fmt(outremote, remote_id); fprintf(stderr, "trying to merge local SHA %s remote SHA %s\n", outlocal, outremote); } git_merge_init_options(&merge_options, GIT_MERGE_OPTIONS_VERSION); #ifdef USE_LIBGIT23_API merge_options.tree_flags = GIT_MERGE_TREE_FIND_RENAMES; #else merge_options.flags = GIT_MERGE_TREE_FIND_RENAMES; #endif merge_options.file_favor = GIT_MERGE_FILE_FAVOR_UNION; merge_options.rename_threshold = 100; if (git_commit_lookup(&local_commit, repo, local_id)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: can't get commit (%s)"), giterr_last()->message); if (git_commit_tree(&local_tree, local_commit)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: failed local tree lookup (%s)"), giterr_last()->message); if (git_commit_lookup(&remote_commit, repo, remote_id)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: can't get commit (%s)"), giterr_last()->message); if (git_commit_tree(&remote_tree, remote_commit)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: failed remote tree lookup (%s)"), giterr_last()->message); if (git_commit_lookup(&base_commit, repo, base)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: can't get commit: (%s)"), giterr_last()->message); if (git_commit_tree(&base_tree, base_commit)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: failed base tree lookup: (%s)"), giterr_last()->message); if (git_merge_trees(&merged_index, repo, base_tree, local_tree, remote_tree, &merge_options)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: merge failed (%s)"), giterr_last()->message); if (git_index_has_conflicts(merged_index)) { int error; const git_index_entry *ancestor = NULL, *ours = NULL, *theirs = NULL; git_index_conflict_iterator *iter = NULL; error = git_index_conflict_iterator_new(&iter, merged_index); while (git_index_conflict_next(&ancestor, &ours, &theirs, iter) != GIT_ITEROVER) { /* Mark this conflict as resolved */ fprintf(stderr, "conflict in %s / %s / %s -- ", ours ? ours->path : "-", theirs ? theirs->path : "-", ancestor ? ancestor->path : "-"); if ((!ours && theirs && ancestor) || (ours && !theirs && ancestor)) { // the file was removed on one side or the other - just remove it fprintf(stderr, "looks like a delete on one side; removing the file from the index\n"); error = git_index_remove(merged_index, ours ? ours->path : theirs->path, GIT_INDEX_STAGE_ANY); } else { error = git_index_conflict_remove(merged_index, ours ? ours->path : theirs ? theirs->path : ancestor->path); } if (error) { fprintf(stderr, "error at conflict resplution (%s)", giterr_last()->message); } } git_index_conflict_cleanup(merged_index); git_index_conflict_iterator_free(iter); report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: merge conflict - manual intervention needed")); } git_oid merge_oid, commit_oid; git_tree *merged_tree; git_signature *author; git_commit *commit; if (git_index_write_tree_to(&merge_oid, merged_index, repo)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: writing the tree failed (%s)"), giterr_last()->message); if (git_tree_lookup(&merged_tree, repo, &merge_oid)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: tree lookup failed (%s)"), giterr_last()->message); if (git_signature_default(&author, repo) < 0) return report_error(translate("gettextFromC", "Failed to get author: (%s)"), giterr_last()->message); if (git_commit_create_v(&commit_oid, repo, NULL, author, author, NULL, "automatic merge", merged_tree, 2, local_commit, remote_commit)) return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: git commit create failed (%s)"), giterr_last()->message); if (git_commit_lookup(&commit, repo, &commit_oid)) return report_error(translate("gettextFromC", "Error: could not lookup the merge commit I just created (%s)"), giterr_last()->message); if (git_branch_is_head(local) && !git_repository_is_bare(repo)) { git_object *parent; git_reference_peel(&parent, local, GIT_OBJ_COMMIT); if (update_git_checkout(repo, parent, merged_tree)) { report_error("Warning: checked out branch is inconsistent with git data"); } } if (git_reference_set_target(&local, local, &commit_oid, "Subsurface merge event")) return report_error("Error: failed to update branch (%s)", giterr_last()->message); set_git_id(&commit_oid); git_signature_free(author); return 0; }
static int try_to_git_merge(git_repository *repo, git_reference **local_p, git_reference *remote, git_oid *base, const git_oid *local_id, const git_oid *remote_id) { UNUSED(remote); git_tree *local_tree, *remote_tree, *base_tree; git_commit *local_commit, *remote_commit, *base_commit; git_index *merged_index; git_merge_options merge_options; if (verbose) { char outlocal[41], outremote[41]; outlocal[40] = outremote[40] = 0; git_oid_fmt(outlocal, local_id); git_oid_fmt(outremote, remote_id); fprintf(stderr, "trying to merge local SHA %s remote SHA %s\n", outlocal, outremote); } git_merge_init_options(&merge_options, GIT_MERGE_OPTIONS_VERSION); #if !LIBGIT2_VER_MAJOR && LIBGIT2_VER_MINOR > 23 merge_options.flags = GIT_MERGE_FIND_RENAMES; #else merge_options.tree_flags = GIT_MERGE_TREE_FIND_RENAMES; #endif merge_options.file_favor = GIT_MERGE_FILE_FAVOR_UNION; merge_options.rename_threshold = 100; if (git_commit_lookup(&local_commit, repo, local_id)) { fprintf(stderr, "Remote storage and local data diverged. Error: can't get commit (%s)", giterr_last()->message); goto diverged_error; } if (git_commit_tree(&local_tree, local_commit)) { fprintf(stderr, "Remote storage and local data diverged. Error: failed local tree lookup (%s)", giterr_last()->message); goto diverged_error; } if (git_commit_lookup(&remote_commit, repo, remote_id)) { fprintf(stderr, "Remote storage and local data diverged. Error: can't get commit (%s)", giterr_last()->message); goto diverged_error; } if (git_commit_tree(&remote_tree, remote_commit)) { fprintf(stderr, "Remote storage and local data diverged. Error: failed local tree lookup (%s)", giterr_last()->message); goto diverged_error; } if (git_commit_lookup(&base_commit, repo, base)) { fprintf(stderr, "Remote storage and local data diverged. Error: can't get commit (%s)", giterr_last()->message); goto diverged_error; } if (git_commit_tree(&base_tree, base_commit)) { fprintf(stderr, "Remote storage and local data diverged. Error: failed base tree lookup (%s)", giterr_last()->message); goto diverged_error; } if (git_merge_trees(&merged_index, repo, base_tree, local_tree, remote_tree, &merge_options)) { fprintf(stderr, "Remote storage and local data diverged. Error: merge failed (%s)", giterr_last()->message); // this is the one where I want to report more detail to the user - can't quite explain why return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: merge failed (%s)"), giterr_last()->message); } if (git_index_has_conflicts(merged_index)) { int error; const git_index_entry *ancestor = NULL, *ours = NULL, *theirs = NULL; git_index_conflict_iterator *iter = NULL; error = git_index_conflict_iterator_new(&iter, merged_index); while (git_index_conflict_next(&ancestor, &ours, &theirs, iter) != GIT_ITEROVER) { /* Mark this conflict as resolved */ fprintf(stderr, "conflict in %s / %s / %s -- ", ours ? ours->path : "-", theirs ? theirs->path : "-", ancestor ? ancestor->path : "-"); if ((!ours && theirs && ancestor) || (ours && !theirs && ancestor)) { // the file was removed on one side or the other - just remove it fprintf(stderr, "looks like a delete on one side; removing the file from the index\n"); error = git_index_remove(merged_index, ours ? ours->path : theirs->path, GIT_INDEX_STAGE_ANY); } else if (ancestor) { error = git_index_conflict_remove(merged_index, ours ? ours->path : theirs ? theirs->path : ancestor->path); } if (error) { fprintf(stderr, "error at conflict resplution (%s)", giterr_last()->message); } } git_index_conflict_cleanup(merged_index); git_index_conflict_iterator_free(iter); report_error(translate("gettextFromC", "Remote storage and local data diverged. Cannot combine local and remote changes")); } git_oid merge_oid, commit_oid; git_tree *merged_tree; git_signature *author; git_commit *commit; if (git_index_write_tree_to(&merge_oid, merged_index, repo)) goto write_error; if (git_tree_lookup(&merged_tree, repo, &merge_oid)) goto write_error; if (git_signature_default(&author, repo) < 0) if (git_signature_now(&author, "Subsurface", "noemail@given") < 0) goto write_error; if (git_commit_create_v(&commit_oid, repo, NULL, author, author, NULL, "automatic merge", merged_tree, 2, local_commit, remote_commit)) goto write_error; if (git_commit_lookup(&commit, repo, &commit_oid)) goto write_error; if (git_branch_is_head(*local_p) && !git_repository_is_bare(repo)) { git_object *parent; git_reference_peel(&parent, *local_p, GIT_OBJ_COMMIT); if (update_git_checkout(repo, parent, merged_tree)) { goto write_error; } } if (git_reference_set_target(local_p, *local_p, &commit_oid, "Subsurface merge event")) goto write_error; set_git_id(&commit_oid); git_signature_free(author); if (verbose) fprintf(stderr, "Successfully merged repositories"); return 0; diverged_error: return report_error(translate("gettextFromC", "Remote storage and local data diverged")); write_error: return report_error(translate("gettextFromC", "Remote storage and local data diverged. Error: writing the data failed (%s)"), giterr_last()->message); }
void Index::removeConflict(const std::string& path) { Exception::git2_assert(git_index_conflict_remove(data(), path.c_str())); }
void test_rebase_inmemory__can_resolve_conflicts(void) { git_rebase *rebase; git_reference *branch_ref, *upstream_ref; git_annotated_commit *branch_head, *upstream_head; git_rebase_operation *rebase_operation; git_status_list *status_list; git_oid pick_id, commit_id, expected_commit_id; git_signature *signature; git_index *repo_index; git_index_entry resolution = {{0}}; git_rebase_options opts = GIT_REBASE_OPTIONS_INIT; cl_git_pass(git_signature_new(&signature, "Rebaser", "*****@*****.**", 1405694510, 0)); opts.inmemory = true; cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/asparagus")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); cl_git_pass(git_rebase_init(&rebase, repo, branch_head, upstream_head, NULL, &opts)); cl_git_pass(git_rebase_next(&rebase_operation, rebase)); git_oid_fromstr(&pick_id, "33f915f9e4dbd9f4b24430e48731a59b45b15500"); cl_assert_equal_i(GIT_REBASE_OPERATION_PICK, rebase_operation->type); cl_assert_equal_oid(&pick_id, &rebase_operation->id); /* ensure that we did not do anything stupid to the workdir or repo index */ cl_git_pass(git_repository_index(&repo_index, repo)); cl_assert(!git_index_has_conflicts(repo_index)); cl_git_pass(git_status_list_new(&status_list, repo, NULL)); cl_assert_equal_i(0, git_status_list_entrycount(status_list)); /* but that the index returned from rebase does have conflicts */ cl_assert(git_index_has_conflicts(rebase_operation->index)); cl_git_fail_with(GIT_EUNMERGED, git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); /* ensure that we can work with the in-memory index to resolve the conflict */ resolution.path = "asparagus.txt"; resolution.mode = GIT_FILEMODE_BLOB; git_oid_fromstr(&resolution.id, "414dfc71ead79c07acd4ea47fecf91f289afc4b9"); cl_git_pass(git_index_conflict_remove(rebase_operation->index, "asparagus.txt")); cl_git_pass(git_index_add(rebase_operation->index, &resolution)); /* and finally create a commit for the resolved rebase operation */ cl_git_pass(git_rebase_commit(&commit_id, rebase, NULL, signature, NULL, NULL)); cl_git_pass(git_oid_fromstr(&expected_commit_id, "db7af47222181e548810da2ab5fec0e9357c5637")); cl_assert_equal_oid(&commit_id, &expected_commit_id); git_signature_free(signature); git_status_list_free(status_list); git_annotated_commit_free(branch_head); git_annotated_commit_free(upstream_head); git_reference_free(branch_ref); git_reference_free(upstream_ref); git_index_free(repo_index); git_rebase_free(rebase); }