void test_stash_apply__with_default(void) { cl_git_pass(git_stash_apply(repo, 0, NULL)); cl_assert_equal_i(git_index_has_conflicts(repo_index), 0); assert_status(repo, "what", GIT_STATUS_WT_MODIFIED); assert_status(repo, "how", GIT_STATUS_CURRENT); assert_status(repo, "who", GIT_STATUS_WT_MODIFIED); assert_status(repo, "when", GIT_STATUS_WT_NEW); }
void test_index_conflicts__remove_all_conflicts(void) { size_t i; const git_index_entry *entry; cl_assert(git_index_entrycount(repo_index) == 8); cl_assert_equal_i(true, git_index_has_conflicts(repo_index)); git_index_conflict_cleanup(repo_index); cl_assert_equal_i(false, git_index_has_conflicts(repo_index)); 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(git_index_entry_stage(entry) == 0); } }
void test_stash_apply__conflict_workdir_with_default(void) { cl_git_rewritefile("stash/what", "ciao\n"); cl_git_fail_with(git_stash_apply(repo, 0, NULL), GIT_ECONFLICT); cl_assert_equal_i(git_index_has_conflicts(repo_index), 0); assert_status(repo, "what", GIT_STATUS_WT_MODIFIED); assert_status(repo, "how", GIT_STATUS_CURRENT); assert_status(repo, "who", GIT_STATUS_CURRENT); assert_status(repo, "when", GIT_STATUS_WT_NEW); }
void test_stash_apply__uses_reflog_like_indices_2(void) { git_oid oid; cl_git_mkfile("stash/untracked", "untracked\n"); cl_git_pass(git_stash_save(&oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED)); assert_status(repo, "untracked", GIT_ENOTFOUND); // stash@{0} is the newest stash we made immediately above cl_git_pass(git_stash_apply(repo, 0, NULL)); cl_assert_equal_i(git_index_has_conflicts(repo_index), 0); assert_status(repo, "untracked", GIT_STATUS_WT_NEW); }
void test_stash_apply__conflict_untracked_with_default(void) { git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT; cl_git_mkfile("stash/when", "nothing\n"); cl_git_fail_with(git_stash_apply(repo, 0, &opts), GIT_ECONFLICT); cl_assert_equal_i(git_index_has_conflicts(repo_index), 0); assert_status(repo, "what", GIT_STATUS_CURRENT); assert_status(repo, "how", GIT_STATUS_CURRENT); assert_status(repo, "who", GIT_STATUS_CURRENT); assert_status(repo, "when", GIT_STATUS_WT_NEW); }
void test_stash_apply__with_reinstate_index(void) { git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT; opts.flags = GIT_STASH_APPLY_REINSTATE_INDEX; cl_git_pass(git_stash_apply(repo, 0, &opts)); cl_assert_equal_i(git_index_has_conflicts(repo_index), 0); assert_status(repo, "what", GIT_STATUS_WT_MODIFIED); assert_status(repo, "how", GIT_STATUS_CURRENT); assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED); assert_status(repo, "when", GIT_STATUS_WT_NEW); }
void test_stash_apply__fails_with_uncommitted_changes_in_index(void) { cl_git_rewritefile("stash/who", "nothing\n"); cl_git_pass(git_index_add_bypath(repo_index, "who")); cl_git_pass(git_index_write(repo_index)); cl_git_fail_with(git_stash_apply(repo, 0, NULL), GIT_EUNCOMMITTED); cl_assert_equal_i(git_index_has_conflicts(repo_index), 0); assert_status(repo, "what", GIT_STATUS_CURRENT); assert_status(repo, "how", GIT_STATUS_CURRENT); assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED); assert_status(repo, "when", GIT_ENOTFOUND); assert_status(repo, "why", GIT_ENOTFOUND); }
void test_stash_apply__conflict_workdir_with_reinstate_index(void) { git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT; opts.flags = GIT_STASH_APPLY_REINSTATE_INDEX; cl_git_rewritefile("stash/what", "ciao\n"); cl_git_fail_with(git_stash_apply(repo, 0, &opts), GIT_ECONFLICT); cl_assert_equal_i(git_index_has_conflicts(repo_index), 0); assert_status(repo, "what", GIT_STATUS_WT_MODIFIED); assert_status(repo, "how", GIT_STATUS_CURRENT); assert_status(repo, "who", GIT_STATUS_CURRENT); assert_status(repo, "when", GIT_STATUS_WT_NEW); }
void test_stash_apply__merges_new_file(void) { const git_index_entry *ancestor, *our, *their; cl_git_mkfile("stash/where", "committed before stash\n"); cl_git_pass(git_index_add_bypath(repo_index, "where")); cl_repo_commit_from_index(NULL, repo, signature, 0, "Other commit"); cl_git_pass(git_stash_apply(repo, 0, NULL)); cl_assert_equal_i(1, git_index_has_conflicts(repo_index)); assert_status(repo, "what", GIT_STATUS_INDEX_MODIFIED); cl_git_pass(git_index_conflict_get(&ancestor, &our, &their, repo_index, "where")); /* unmerged */ assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED); assert_status(repo, "when", GIT_STATUS_WT_NEW); assert_status(repo, "why", GIT_STATUS_INDEX_NEW); }
void test_stash_apply__uses_reflog_like_indices_1(void) { git_oid oid; cl_git_mkfile("stash/untracked", "untracked\n"); cl_git_pass(git_stash_save(&oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED)); assert_status(repo, "untracked", GIT_ENOTFOUND); // stash@{1} is the oldest (first) stash we made cl_git_pass(git_stash_apply(repo, 1, NULL)); cl_assert_equal_i(git_index_has_conflicts(repo_index), 0); assert_status(repo, "what", GIT_STATUS_WT_MODIFIED); assert_status(repo, "how", GIT_STATUS_CURRENT); assert_status(repo, "who", GIT_STATUS_WT_MODIFIED); assert_status(repo, "when", GIT_STATUS_WT_NEW); assert_status(repo, "why", GIT_STATUS_INDEX_NEW); assert_status(repo, "where", GIT_STATUS_INDEX_NEW); }
void test_stash_apply__conflict_index_with_default(void) { const git_index_entry *ancestor; const git_index_entry *our; const git_index_entry *their; cl_git_rewritefile("stash/who", "nothing\n"); cl_git_pass(git_index_add_bypath(repo_index, "who")); cl_git_pass(git_index_write(repo_index)); cl_git_pass(git_stash_apply(repo, 0, NULL)); cl_assert_equal_i(git_index_has_conflicts(repo_index), 1); assert_status(repo, "what", GIT_STATUS_INDEX_MODIFIED); assert_status(repo, "how", GIT_STATUS_CURRENT); cl_git_pass(git_index_conflict_get(&ancestor, &our, &their, repo_index, "who")); /* unmerged */ assert_status(repo, "when", GIT_STATUS_WT_NEW); }
void test_stash_apply__conflict_index_with_reinstate_index(void) { git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT; opts.flags = GIT_STASH_APPLY_REINSTATE_INDEX; cl_git_rewritefile("stash/who", "nothing\n"); cl_git_pass(git_index_add_bypath(repo_index, "who")); cl_git_pass(git_index_write(repo_index)); cl_git_fail_with(git_stash_apply(repo, 0, &opts), GIT_ECONFLICT); cl_assert_equal_i(git_index_has_conflicts(repo_index), 0); assert_status(repo, "what", GIT_STATUS_CURRENT); assert_status(repo, "how", GIT_STATUS_CURRENT); assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED); assert_status(repo, "when", GIT_ENOTFOUND); }
void test_stash_apply__with_default(void) { git_buf where = GIT_BUF_INIT; cl_git_pass(git_stash_apply(repo, 0, NULL)); cl_assert_equal_i(git_index_has_conflicts(repo_index), 0); assert_status(repo, "what", GIT_STATUS_WT_MODIFIED); assert_status(repo, "how", GIT_STATUS_CURRENT); assert_status(repo, "who", GIT_STATUS_WT_MODIFIED); assert_status(repo, "when", GIT_STATUS_WT_NEW); assert_status(repo, "why", GIT_STATUS_INDEX_NEW); assert_status(repo, "where", GIT_STATUS_INDEX_NEW); cl_git_pass(git_futils_readbuffer(&where, "stash/where")); cl_assert_equal_s("....\n", where.ptr); git_buf_free(&where); }
void test_stash_apply__conflict_commit_with_reinstate_index(void) { git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT; const git_index_entry *ancestor; const git_index_entry *our; const git_index_entry *their; opts.flags = GIT_STASH_APPLY_REINSTATE_INDEX; cl_git_rewritefile("stash/what", "ciao\n"); cl_git_pass(git_index_add_bypath(repo_index, "what")); cl_repo_commit_from_index(NULL, repo, signature, 0, "Other commit"); cl_git_pass(git_stash_apply(repo, 0, &opts)); cl_assert_equal_i(git_index_has_conflicts(repo_index), 1); cl_git_pass(git_index_conflict_get(&ancestor, &our, &their, repo_index, "what")); /* unmerged */ assert_status(repo, "how", GIT_STATUS_CURRENT); assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED); assert_status(repo, "when", GIT_STATUS_WT_NEW); }
void test_stash_apply__executes_notify_cb(void) { git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT; struct seen_paths seen_paths = {0}; opts.checkout_options.notify_cb = checkout_notify; opts.checkout_options.notify_flags = GIT_CHECKOUT_NOTIFY_ALL; opts.checkout_options.notify_payload = &seen_paths; cl_git_pass(git_stash_apply(repo, 0, &opts)); cl_assert_equal_i(git_index_has_conflicts(repo_index), 0); assert_status(repo, "what", GIT_STATUS_WT_MODIFIED); assert_status(repo, "how", GIT_STATUS_CURRENT); assert_status(repo, "who", GIT_STATUS_WT_MODIFIED); assert_status(repo, "when", GIT_STATUS_WT_NEW); cl_assert_equal_b(true, seen_paths.what); cl_assert_equal_b(false, seen_paths.how); cl_assert_equal_b(true, seen_paths.who); cl_assert_equal_b(true, seen_paths.when); }
void test_stash_apply__with_reinstate_index(void) { git_buf where = GIT_BUF_INIT; git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT; opts.flags = GIT_STASH_APPLY_REINSTATE_INDEX; cl_git_pass(git_stash_apply(repo, 0, &opts)); cl_assert_equal_i(git_index_has_conflicts(repo_index), 0); assert_status(repo, "what", GIT_STATUS_WT_MODIFIED); assert_status(repo, "how", GIT_STATUS_CURRENT); assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED); assert_status(repo, "when", GIT_STATUS_WT_NEW); assert_status(repo, "why", GIT_STATUS_INDEX_NEW); assert_status(repo, "where", GIT_STATUS_INDEX_NEW | GIT_STATUS_WT_MODIFIED); cl_git_pass(git_futils_readbuffer(&where, "stash/where")); cl_assert_equal_s("....\n", where.ptr); git_buf_free(&where); }
void test_reset_soft__fails_when_index_contains_conflicts_independently_of_MERGE_HEAD_file_existence(void) { git_index *index; git_reference *head; git_buf merge_head_path = GIT_BUF_INIT; cl_git_sandbox_cleanup(); repo = cl_git_sandbox_init("mergedrepo"); cl_git_pass(git_buf_joinpath(&merge_head_path, git_repository_path(repo), "MERGE_HEAD")); cl_git_pass(p_unlink(git_buf_cstr(&merge_head_path))); git_buf_free(&merge_head_path); cl_git_pass(git_repository_index(&index, repo)); cl_assert_equal_i(true, git_index_has_conflicts(index)); git_index_free(index); cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel(&target, head, GIT_OBJ_COMMIT)); git_reference_free(head); cl_assert_equal_i(GIT_EUNMERGED, git_reset(repo, target, GIT_RESET_SOFT)); }
int git_reset( git_repository *repo, git_object *target, git_reset_t reset_type) { git_object *commit = NULL; git_index *index = NULL; git_tree *tree = NULL; int error = 0; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; assert(repo && target); if (git_object_owner(target) != repo) { giterr_set(GITERR_OBJECT, "%s - The given target does not belong to this repository.", ERROR_MSG); return -1; } if (reset_type != GIT_RESET_SOFT && (error = git_repository__ensure_not_bare(repo, reset_type == GIT_RESET_MIXED ? "reset mixed" : "reset hard")) < 0) return error; if ((error = git_object_peel(&commit, target, GIT_OBJ_COMMIT)) < 0 || (error = git_repository_index(&index, repo)) < 0 || (error = git_commit_tree(&tree, (git_commit *)commit)) < 0) goto cleanup; if (reset_type == GIT_RESET_SOFT && (git_repository_state(repo) == GIT_REPOSITORY_STATE_MERGE || git_index_has_conflicts(index))) { giterr_set(GITERR_OBJECT, "%s (soft) in the middle of a merge.", ERROR_MSG); error = GIT_EUNMERGED; goto cleanup; } /* move HEAD to the new target */ if ((error = update_head(repo, commit)) < 0) goto cleanup; if (reset_type == GIT_RESET_HARD) { /* overwrite working directory with HEAD */ opts.checkout_strategy = GIT_CHECKOUT_FORCE; if ((error = git_checkout_tree(repo, (git_object *)tree, &opts)) < 0) goto cleanup; } if (reset_type > GIT_RESET_SOFT) { /* reset index to the target content */ if ((error = git_index_read_tree(index, tree)) < 0 || (error = git_index_write(index)) < 0) goto cleanup; if ((error = git_repository_merge_cleanup(repo)) < 0) { giterr_set(GITERR_INDEX, "%s - failed to clean up merge data", ERROR_MSG); goto cleanup; } } cleanup: git_object_free(commit); git_index_free(index); git_tree_free(tree); return error; }
static int rebase_commit__create( git_commit **out, git_rebase *rebase, git_index *index, git_commit *parent_commit, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message) { git_rebase_operation *operation; git_commit *current_commit = NULL, *commit = NULL; git_tree *parent_tree = NULL, *tree = NULL; git_oid tree_id, commit_id; int error; operation = git_array_get(rebase->operations, rebase->current); if (git_index_has_conflicts(index)) { giterr_set(GITERR_REBASE, "conflicts have not been resolved"); error = GIT_EUNMERGED; goto done; } if ((error = git_commit_lookup(¤t_commit, rebase->repo, &operation->id)) < 0 || (error = git_commit_tree(&parent_tree, parent_commit)) < 0 || (error = git_index_write_tree_to(&tree_id, index, rebase->repo)) < 0 || (error = git_tree_lookup(&tree, rebase->repo, &tree_id)) < 0) goto done; if (git_oid_equal(&tree_id, git_tree_id(parent_tree))) { giterr_set(GITERR_REBASE, "this patch has already been applied"); error = GIT_EAPPLIED; goto done; } if (!author) author = git_commit_author(current_commit); if (!message) { message_encoding = git_commit_message_encoding(current_commit); message = git_commit_message(current_commit); } if ((error = git_commit_create(&commit_id, rebase->repo, NULL, author, committer, message_encoding, message, tree, 1, (const git_commit **)&parent_commit)) < 0 || (error = git_commit_lookup(&commit, rebase->repo, &commit_id)) < 0) goto done; *out = commit; done: if (error < 0) git_commit_free(commit); git_commit_free(current_commit); git_tree_free(parent_tree); git_tree_free(tree); 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; }
/* * call-seq: * index.conflicts? -> true or false * * Determines if the index contains entries representing conflicts. */ static VALUE rb_git_index_conflicts_p(VALUE self) { git_index *index; Data_Get_Struct(self, git_index, index); return git_index_has_conflicts(index) ? Qtrue : Qfalse; }
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); }
static int rebase_commit_merge( git_oid *commit_id, git_rebase *rebase, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message) { git_index *index = NULL; git_reference *head = NULL; git_commit *current_commit = NULL, *head_commit = NULL, *commit = NULL; git_rebase_operation *operation; git_tree *head_tree = NULL, *tree = NULL; git_diff *diff = NULL; git_oid tree_id; git_buf reflog_msg = GIT_BUF_INIT; char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ]; int error; operation = git_array_get(rebase->operations, rebase->current); assert(operation); if ((error = git_repository_index(&index, rebase->repo)) < 0) goto done; if (git_index_has_conflicts(index)) { giterr_set(GITERR_REBASE, "Conflicts have not been resolved"); error = GIT_EMERGECONFLICT; goto done; } if ((error = git_commit_lookup(¤t_commit, rebase->repo, &operation->id)) < 0 || (error = git_repository_head(&head, rebase->repo)) < 0 || (error = git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)) < 0 || (error = git_commit_tree(&head_tree, head_commit)) < 0 || (error = git_diff_tree_to_index(&diff, rebase->repo, head_tree, index, NULL)) < 0) goto done; if (git_diff_num_deltas(diff) == 0) { giterr_set(GITERR_REBASE, "This patch has already been applied"); error = GIT_EAPPLIED; goto done; } if ((error = git_index_write_tree(&tree_id, index)) < 0 || (error = git_tree_lookup(&tree, rebase->repo, &tree_id)) < 0) goto done; if (!author) author = git_commit_author(current_commit); if (!message) { message_encoding = git_commit_message_encoding(current_commit); message = git_commit_message(current_commit); } if ((error = git_commit_create(commit_id, rebase->repo, NULL, author, committer, message_encoding, message, tree, 1, (const git_commit **)&head_commit)) < 0 || (error = git_commit_lookup(&commit, rebase->repo, commit_id)) < 0 || (error = git_reference__update_for_commit( rebase->repo, NULL, "HEAD", commit_id, "rebase")) < 0) goto done; git_oid_fmt(old_idstr, git_commit_id(current_commit)); git_oid_fmt(new_idstr, commit_id); error = rebase_setupfile(rebase, REWRITTEN_FILE, O_CREAT|O_WRONLY|O_APPEND, "%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr); done: git_buf_free(&reflog_msg); git_commit_free(commit); git_diff_free(diff); git_tree_free(tree); git_tree_free(head_tree); git_commit_free(head_commit); git_commit_free(current_commit); git_reference_free(head); git_index_free(index); return error; }
bool Index::hasConflicts()const { return git_index_has_conflicts(data()) != 0; }
PmrWorkspace::WorkspaceStatus PmrWorkspace::gitWorkspaceStatus() const { // Get the status of the workspace WorkspaceStatus res = StatusUnknown; if (isOpen()) { if (git_repository_head_unborn(mGitRepository) == 1) { res = StatusCurrent; } else { git_oid masterOid; bool error = false; if (git_reference_name_to_id(&masterOid, mGitRepository, "refs/heads/master") == GIT_OK) { git_oid originMasterOid; if (git_reference_name_to_id(&originMasterOid, mGitRepository, "refs/remotes/origin/master") == GIT_OK) { size_t ahead = 0; size_t behind = 0; if (git_graph_ahead_behind(&ahead, &behind, mGitRepository, &masterOid, &originMasterOid) == GIT_OK) { res = (ahead != 0)? StatusAhead: (behind != 0)? StatusBehind: StatusCurrent; } else { error = true; } } else { res = StatusAhead; } } else { error = true; } if (error) { emitGitError(tr("An error occurred while trying to get the remote status of %1.").arg(mPath)); } } git_index *index; if (git_repository_index(&index, mGitRepository) == GIT_OK) { if (git_index_has_conflicts(index) != 0) { res = WorkspaceStatus(res|StatusConflict); } else { if (mStagedCount != 0) { res = WorkspaceStatus(res|StatusStaged); } if (mUnstagedCount != 0) { res = WorkspaceStatus(res|StatusUnstaged); } } git_index_free(index); } } return res; }
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); }
int main() { git_libgit2_init(); git_repository* rep = nullptr; const git_annotated_commit* their_head[10]; git_merge_options merge_opt = GIT_MERGE_OPTIONS_INIT; git_checkout_options checkout_opt = GIT_CHECKOUT_OPTIONS_INIT; git_reference* branch = nullptr; git_index* index = nullptr; git_index_conflict_iterator* conflict_iterator = nullptr; git_oid new_tree_id; git_tree* new_tree = nullptr; git_signature* me = nullptr; git_reference* head = nullptr; git_commit* parent_our = nullptr; git_commit* parent_their = nullptr; git_oid commit_id; int error = 0; // git open error = git_repository_open(&rep, path); if (error < 0) { const git_error *e = giterr_last(); std::cout << "Error: " << error << " / " << e->klass << " : " << e->message << std::endl; goto SHUTDOWN; } // git merge <branch> git_reference_dwim(&branch, rep, "new"); git_annotated_commit_from_ref((git_annotated_commit **)&their_head[0], rep, branch); error = git_merge(rep, their_head, 1, &merge_opt, &checkout_opt); if (error < 0) { const git_error *e = giterr_last(); std::cout << "Error: " << error << " / " << e->klass << " : " << e->message << std::endl; goto SHUTDOWN; } git_repository_index(&index, rep); // reslove conflicts if (git_index_has_conflicts(index)) { const git_index_entry* ancestor_out = nullptr; const git_index_entry* our_out = nullptr; const git_index_entry* their_out = nullptr; git_index_conflict_iterator_new(&conflict_iterator, index); while (git_index_conflict_next(&ancestor_out, &our_out, &their_out, conflict_iterator) != GIT_ITEROVER) { if (ancestor_out) std::cout<< "ancestor: " << ancestor_out->path <<std::endl; if (our_out) std::cout<< "our: " << our_out->path <<std::endl; if (their_out) std::cout<< "their: " << their_out->path <<std::endl; // do sth. or rewrite file by code. ... // and remove the conflict // git_index_conflict_remove(index, "..."); } // git checkout --theirs <file> git_checkout_options opt = GIT_CHECKOUT_OPTIONS_INIT; opt.checkout_strategy |= GIT_CHECKOUT_USE_THEIRS; // const char* p = "file"; // opt.paths.strings = (char**)&p; // opt.paths.count = 1; git_checkout_index(rep, index, &opt); git_index_conflict_iterator_free(conflict_iterator); } // add and commit git_index_update_all(index, nullptr, nullptr, nullptr); git_index_write(index); git_index_write_tree(&new_tree_id, index); git_tree_lookup(&new_tree, rep, &new_tree_id); git_signature_now(&me, "XiaochenFTX", "*****@*****.**"); git_repository_head(&head, rep); git_commit_lookup(&parent_our, rep, git_reference_target(head)); git_commit_lookup(&parent_their, rep, git_reference_target(branch)); git_commit_create_v(&commit_id, rep, "HEAD", me, me, "UTF-8", "merge commit", new_tree, 2, parent_our, parent_their); git_repository_state_cleanup(rep); SHUTDOWN: git_repository_free(rep); git_libgit2_shutdown(); return 0; }
static int reset( git_repository *repo, const git_object *target, const char *to, git_reset_t reset_type, const git_checkout_options *checkout_opts) { git_object *commit = NULL; git_index *index = NULL; git_tree *tree = NULL; int error = 0; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_buf log_message = GIT_BUF_INIT; assert(repo && target); if (checkout_opts) opts = *checkout_opts; if (git_object_owner(target) != repo) { giterr_set(GITERR_OBJECT, "%s - The given target does not belong to this repository.", ERROR_MSG); return -1; } if (reset_type != GIT_RESET_SOFT && (error = git_repository__ensure_not_bare(repo, reset_type == GIT_RESET_MIXED ? "reset mixed" : "reset hard")) < 0) return error; if ((error = git_object_peel(&commit, target, GIT_OBJECT_COMMIT)) < 0 || (error = git_repository_index(&index, repo)) < 0 || (error = git_commit_tree(&tree, (git_commit *)commit)) < 0) goto cleanup; if (reset_type == GIT_RESET_SOFT && (git_repository_state(repo) == GIT_REPOSITORY_STATE_MERGE || git_index_has_conflicts(index))) { giterr_set(GITERR_OBJECT, "%s (soft) in the middle of a merge", ERROR_MSG); error = GIT_EUNMERGED; goto cleanup; } if ((error = git_buf_printf(&log_message, "reset: moving to %s", to)) < 0) return error; if (reset_type == GIT_RESET_HARD) { /* overwrite working directory with the new tree */ opts.checkout_strategy = GIT_CHECKOUT_FORCE; if ((error = git_checkout_tree(repo, (git_object *)tree, &opts)) < 0) goto cleanup; } /* move HEAD to the new target */ if ((error = git_reference__update_terminal(repo, GIT_HEAD_FILE, git_object_id(commit), NULL, git_buf_cstr(&log_message))) < 0) goto cleanup; if (reset_type > GIT_RESET_SOFT) { /* reset index to the target content */ if ((error = git_index_read_tree(index, tree)) < 0 || (error = git_index_write(index)) < 0) goto cleanup; if ((error = git_repository_state_cleanup(repo)) < 0) { giterr_set(GITERR_INDEX, "%s - failed to clean up merge data", ERROR_MSG); goto cleanup; } } cleanup: git_object_free(commit); git_index_free(index); git_tree_free(tree); git_buf_dispose(&log_message); return error; }
/** * Perform a normal merge * * @param merge_result S4 class git_merge_result * @param merge_heads The merge heads to merge * @param n The number of merge heads * @param repository The repository * @param message The commit message of the merge * @param merger Who is performing the merge * @param commit_on_success Commit merge commit, if one was created * @param merge_opts Merge options * @return 0 on success, or error code */ static int git2r_normal_merge( SEXP merge_result, const git_annotated_commit **merge_heads, size_t n, git_repository *repository, const char *message, git_signature *merger, int commit_on_success, const git_checkout_options *checkout_opts, const git_merge_options *merge_opts) { int err; git_commit *commit = NULL; git_index *index = NULL; SET_SLOT(merge_result, Rf_install("fast_forward"), ScalarLogical(0)); err = git_merge( repository, merge_heads, n, merge_opts, checkout_opts); if (err) goto cleanup; err = git_repository_index(&index, repository); if (err) goto cleanup; if (git_index_has_conflicts(index)) { SET_SLOT(merge_result, Rf_install("conflicts"), ScalarLogical(1)); } else { SET_SLOT(merge_result, Rf_install("conflicts"), ScalarLogical(0)); if (commit_on_success) { char sha[GIT_OID_HEXSZ + 1]; git_oid oid; err = git2r_commit_create( &oid, repository, index, message, merger, merger); if (err) goto cleanup; git_oid_fmt(sha, &oid); sha[GIT_OID_HEXSZ] = '\0'; SET_SLOT(merge_result, Rf_install("sha"), mkString(sha)); } } cleanup: if (commit) git_commit_free(commit); if (index) git_index_free(index); return err; }
int main() { git_libgit2_init(); git_repository* rep = nullptr; git_rebase* prebase = nullptr; git_rebase_options rebase_opt = GIT_REBASE_OPTIONS_INIT; git_reference* onto_branch = nullptr; git_annotated_commit* onto = nullptr; git_rebase_operation* operation = nullptr; size_t entrycount; size_t current; git_signature* me = nullptr; git_index* index = nullptr; git_oid new_commit; int error = 0; // git open git_repository_open(&rep, path); error = git_rebase_open(&prebase, rep, &rebase_opt); // There is no rebase in progress if (error == GIT_ENOTFOUND) { git_branch_lookup(&onto_branch, rep, "new", GIT_BRANCH_LOCAL); git_annotated_commit_from_ref(&onto, rep, onto_branch); git_rebase_init(&prebase, rep, nullptr /* current branch */, nullptr /* upstream */ , onto /* branch to rebase onto */, &rebase_opt); } else if (error < 0) { const git_error *e = giterr_last(); std::cout << "Error: " << error << " / " << e->klass << " : " << e->message << std::endl; goto SHUTDOWN; } entrycount = git_rebase_operation_entrycount(prebase); std::cout<< "rebase entry count: " << entrycount << "\n"; while (git_rebase_next(&operation, prebase) != GIT_ITEROVER) { current = git_rebase_operation_current(prebase); // (called `init` but not yet `next`) then this returns `GIT_REBASE_NO_OPERATION` std::cout<< "rebase current index: " << current << "\n"; if (GIT_REBASE_NO_OPERATION == current) { std::cout<< "rebase no operation" << "\n"; } operation = git_rebase_operation_byindex(prebase, 0); } // reslove conflicts git_repository_index(&index, rep); if (git_index_has_conflicts(index)) { // git checkout --theirs git_checkout_options opt = GIT_CHECKOUT_OPTIONS_INIT; opt.checkout_strategy |= GIT_CHECKOUT_USE_THEIRS; git_checkout_index(rep, index, &opt); } // add git_index_update_all(index, nullptr, nullptr, nullptr); git_index_write(index); // commit git_signature_now(&me, "XiaochenFTX", "*****@*****.**"); git_rebase_commit(&new_commit, prebase, me, me, "UTF-8", "new rebase"); error = git_rebase_finish(prebase, me); if (error < 0) { const git_error *e = giterr_last(); std::cout << "Error: " << error << " / " << e->klass << " : " << e->message << std::endl; goto SHUTDOWN; } // git_rebase_abort(prebase); git_rebase_free(prebase); SHUTDOWN: git_repository_free(rep); git_libgit2_shutdown(); return 0; }