From 8683d31f080eb12fe769ab2363165ec17562c840 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 22 Oct 2015 14:39:20 -0400 Subject: [PATCH] merge: add GIT_MERGE_TREE_FAIL_ON_CONFLICT Provide a new merge option, GIT_MERGE_TREE_FAIL_ON_CONFLICT, which will stop on the first conflict and fail the merge operation with GIT_EMERGECONFLICT. --- include/git2/errors.h | 1 + include/git2/merge.h | 7 +++++++ src/merge.c | 9 ++++++++- tests/merge/merge_helpers.c | 9 +++++---- tests/merge/trees/commits.c | 18 +++++++++++++++++- 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/include/git2/errors.h b/include/git2/errors.h index 4698366d8..1b528cf25 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -49,6 +49,7 @@ typedef enum { GIT_EINVALID = -21, /**< Invalid operation or input */ GIT_EUNCOMMITTED = -22, /**< Uncommitted changes in index prevented operation */ GIT_EDIRECTORY = -23, /**< The operation is not valid for a directory */ + GIT_EMERGECONFLICT = -24, /**< A merge conflict exists and cannot continue */ GIT_PASSTHROUGH = -30, /**< Internal only */ GIT_ITEROVER = -31, /**< Signals end of iteration with iterator */ diff --git a/include/git2/merge.h b/include/git2/merge.h index 5fef452b9..ced9e51ff 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -72,6 +72,13 @@ typedef enum { * the ability to merge between a modified and renamed file. */ GIT_MERGE_TREE_FIND_RENAMES = (1 << 0), + + /** + * If a conflict occurs, exit immediately instead of attempting to + * continue resolving conflicts. The merge operation will fail with + * GIT_EMERGECONFLICT and no index will be returned. + */ + GIT_MERGE_TREE_FAIL_ON_CONFLICT = (1 << 1), } git_merge_tree_flag_t; /** diff --git a/src/merge.c b/src/merge.c index 930457bdb..3bed0fd3b 100644 --- a/src/merge.c +++ b/src/merge.c @@ -1701,8 +1701,15 @@ int git_merge__iterators( if ((error = merge_conflict_resolve(&resolved, diff_list, conflict, opts.file_favor, opts.file_flags)) < 0) goto done; - if (!resolved) + if (!resolved) { + if ((opts.tree_flags & GIT_MERGE_TREE_FAIL_ON_CONFLICT)) { + giterr_set(GITERR_MERGE, "merge conflicts exist"); + error = GIT_EMERGECONFLICT; + goto done; + } + git_vector_insert(&diff_list->conflicts, conflict); + } } if (!given_opts || !given_opts->metric) diff --git a/tests/merge/merge_helpers.c b/tests/merge/merge_helpers.c index f81471424..986a365db 100644 --- a/tests/merge/merge_helpers.c +++ b/tests/merge/merge_helpers.c @@ -40,7 +40,7 @@ int merge_trees_from_branches( cl_git_pass(git_commit_tree(&our_tree, our_commit)); cl_git_pass(git_commit_tree(&their_tree, their_commit)); - cl_git_pass(git_merge_trees(index, repo, ancestor_tree, our_tree, their_tree, opts)); + error = git_merge_trees(index, repo, ancestor_tree, our_tree, their_tree, opts); git_buf_free(&branch_buf); git_tree_free(our_tree); @@ -50,7 +50,7 @@ int merge_trees_from_branches( git_commit_free(their_commit); git_commit_free(ancestor_commit); - return 0; + return error; } int merge_commits_from_branches( @@ -61,6 +61,7 @@ int merge_commits_from_branches( git_commit *our_commit, *their_commit; git_oid our_oid, their_oid; git_buf branch_buf = GIT_BUF_INIT; + int error; git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours_name); cl_git_pass(git_reference_name_to_id(&our_oid, repo, branch_buf.ptr)); @@ -71,13 +72,13 @@ int merge_commits_from_branches( cl_git_pass(git_reference_name_to_id(&their_oid, repo, branch_buf.ptr)); cl_git_pass(git_commit_lookup(&their_commit, repo, &their_oid)); - cl_git_pass(git_merge_commits(index, repo, our_commit, their_commit, opts)); + error = git_merge_commits(index, repo, our_commit, their_commit, opts); git_buf_free(&branch_buf); git_commit_free(our_commit); git_commit_free(their_commit); - return 0; + return error; } int merge_branches(git_repository *repo, diff --git a/tests/merge/trees/commits.c b/tests/merge/trees/commits.c index c4e470997..2e3c4578b 100644 --- a/tests/merge/trees/commits.c +++ b/tests/merge/trees/commits.c @@ -94,7 +94,6 @@ void test_merge_trees_commits__no_ancestor(void) git_index_free(index); } - void test_merge_trees_commits__df_conflict(void) { git_index *index; @@ -129,3 +128,20 @@ void test_merge_trees_commits__df_conflict(void) git_index_free(index); } + +void test_merge_trees_commits__fail_on_conflict(void) +{ + git_index *index; + git_merge_options opts = GIT_MERGE_OPTIONS_INIT; + + opts.tree_flags |= GIT_MERGE_TREE_FAIL_ON_CONFLICT; + + cl_git_fail_with(GIT_EMERGECONFLICT, + merge_trees_from_branches(&index, repo, "df_side1", "df_side2", &opts)); + + cl_git_fail_with(GIT_EMERGECONFLICT, + merge_commits_from_branches(&index, repo, "master", "unrelated", &opts)); + cl_git_fail_with(GIT_EMERGECONFLICT, + merge_commits_from_branches(&index, repo, "master", "branch", &opts)); +} +