diff options
author | Vicent Marti <vicent@github.com> | 2014-05-28 13:47:55 +0200 |
---|---|---|
committer | Vicent Marti <vicent@github.com> | 2014-05-28 13:47:55 +0200 |
commit | 63e8c3fde26c20c36c3d850d48e1d94a437318cf (patch) | |
tree | 0e2eed2ab33d565c09a848d3af552959877a4bef | |
parent | 433ba614a2ef948008510a1b1189702d515d2fc4 (diff) | |
parent | eff531e1034401b144b02ff2913a361669d04129 (diff) | |
download | libgit2-63e8c3fde26c20c36c3d850d48e1d94a437318cf.tar.gz |
Merge pull request #2337 from ethomson/merge_ff
Introduce GIT_MERGE_CONFIG_* for merge.ff settings
-rw-r--r-- | include/git2/merge.h | 21 | ||||
-rw-r--r-- | src/merge.c | 61 | ||||
-rw-r--r-- | tests/merge/workdir/analysis.c | 77 |
3 files changed, 125 insertions, 34 deletions
diff --git a/include/git2/merge.h b/include/git2/merge.h index 7915050b0..9eb14ccb1 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -268,6 +268,26 @@ typedef enum { GIT_MERGE_ANALYSIS_UNBORN = (1 << 3), } git_merge_analysis_t; +typedef enum { + /* + * No configuration was found that suggests a preferred behavior for + * merge. + */ + GIT_MERGE_PREFERENCE_NONE = 0, + + /** + * There is a `merge.ff=false` configuration setting, suggesting that + * the user does not want to allow a fast-forward merge. + */ + GIT_MERGE_PREFERENCE_NO_FASTFORWARD = (1 << 0), + + /** + * There is a `merge.ff=only` configuration setting, suggesting that + * the user only wants fast-forward merges. + */ + GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY = (1 << 1), +} git_merge_preference_t; + /** * Analyzes the given branch(es) and determines the opportunities for * merging them into the HEAD of the repository. @@ -280,6 +300,7 @@ typedef enum { */ GIT_EXTERN(int) git_merge_analysis( git_merge_analysis_t *analysis_out, + git_merge_preference_t *preference_out, git_repository *repo, const git_merge_head **their_heads, size_t their_heads_len); diff --git a/src/merge.c b/src/merge.c index 6a8e5874f..a279d31d4 100644 --- a/src/merge.c +++ b/src/merge.c @@ -2564,8 +2564,42 @@ done: return error; } +static int merge_preference(git_merge_preference_t *out, git_repository *repo) +{ + git_config *config; + const char *value; + int bool_value, error = 0; + + *out = GIT_MERGE_PREFERENCE_NONE; + + if ((error = git_repository_config_snapshot(&config, repo)) < 0) + goto done; + + if ((error = git_config_get_string(&value, config, "merge.ff")) < 0) { + if (error == GIT_ENOTFOUND) { + giterr_clear(); + error = 0; + } + + goto done; + } + + if (git_config_parse_bool(&bool_value, value) == 0) { + if (!bool_value) + *out |= GIT_MERGE_PREFERENCE_NO_FASTFORWARD; + } else { + if (strcasecmp(value, "only") == 0) + *out |= GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY; + } + +done: + git_config_free(config); + return error; +} + int git_merge_analysis( - git_merge_analysis_t *out, + git_merge_analysis_t *analysis_out, + git_merge_preference_t *preference_out, git_repository *repo, const git_merge_head **their_heads, size_t their_heads_len) @@ -2573,14 +2607,7 @@ int git_merge_analysis( git_merge_head *ancestor_head = NULL, *our_head = NULL; int error = 0; - assert(out && repo && their_heads); - - *out = GIT_MERGE_ANALYSIS_NONE; - - if (git_repository_head_unborn(repo)) { - *out = GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_UNBORN; - goto done; - } + assert(analysis_out && preference_out && repo && their_heads); if (their_heads_len != 1) { giterr_set(GITERR_MERGE, "Can only merge a single branch"); @@ -2588,20 +2615,30 @@ int git_merge_analysis( goto done; } + *analysis_out = GIT_MERGE_ANALYSIS_NONE; + + if ((error = merge_preference(preference_out, repo)) < 0) + goto done; + + if (git_repository_head_unborn(repo)) { + *analysis_out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_UNBORN; + goto done; + } + if ((error = merge_heads(&ancestor_head, &our_head, repo, their_heads, their_heads_len)) < 0) goto done; /* We're up-to-date if we're trying to merge our own common ancestor. */ if (ancestor_head && git_oid_equal(&ancestor_head->oid, &their_heads[0]->oid)) - *out = GIT_MERGE_ANALYSIS_UP_TO_DATE; + *analysis_out |= GIT_MERGE_ANALYSIS_UP_TO_DATE; /* We're fastforwardable if we're our own common ancestor. */ else if (ancestor_head && git_oid_equal(&ancestor_head->oid, &our_head->oid)) - *out = GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_NORMAL; + *analysis_out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_NORMAL; /* Otherwise, just a normal merge is possible. */ else - *out = GIT_MERGE_ANALYSIS_NORMAL; + *analysis_out |= GIT_MERGE_ANALYSIS_NORMAL; done: git_merge_head_free(ancestor_head); diff --git a/tests/merge/workdir/analysis.c b/tests/merge/workdir/analysis.c index 0e937857f..85918abe4 100644 --- a/tests/merge/workdir/analysis.c +++ b/tests/merge/workdir/analysis.c @@ -36,72 +36,105 @@ void test_merge_workdir_analysis__cleanup(void) cl_git_sandbox_cleanup(); } -static git_merge_analysis_t analysis_from_branch(const char *branchname) +static void analysis_from_branch( + git_merge_analysis_t *merge_analysis, + git_merge_preference_t *merge_pref, + const char *branchname) { git_buf refname = GIT_BUF_INIT; git_reference *their_ref; git_merge_head *their_head; - git_merge_analysis_t analysis; git_buf_printf(&refname, "%s%s", GIT_REFS_HEADS_DIR, branchname); cl_git_pass(git_reference_lookup(&their_ref, repo, git_buf_cstr(&refname))); cl_git_pass(git_merge_head_from_ref(&their_head, repo, their_ref)); - cl_git_pass(git_merge_analysis(&analysis, repo, (const git_merge_head **)&their_head, 1)); + cl_git_pass(git_merge_analysis(merge_analysis, merge_pref, repo, (const git_merge_head **)&their_head, 1)); git_buf_free(&refname); git_merge_head_free(their_head); git_reference_free(their_ref); - - return analysis; } void test_merge_workdir_analysis__fastforward(void) { - git_merge_analysis_t analysis; + git_merge_analysis_t merge_analysis; + git_merge_preference_t merge_pref; - analysis = analysis_from_branch(FASTFORWARD_BRANCH); - cl_assert_equal_i(GIT_MERGE_ANALYSIS_FASTFORWARD, (analysis & GIT_MERGE_ANALYSIS_FASTFORWARD)); - cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL, (analysis & GIT_MERGE_ANALYSIS_NORMAL)); + analysis_from_branch(&merge_analysis, &merge_pref, FASTFORWARD_BRANCH); + cl_assert_equal_i(GIT_MERGE_ANALYSIS_FASTFORWARD, (merge_analysis & GIT_MERGE_ANALYSIS_FASTFORWARD)); + cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL, (merge_analysis & GIT_MERGE_ANALYSIS_NORMAL)); } void test_merge_workdir_analysis__no_fastforward(void) { - git_merge_analysis_t analysis; + git_merge_analysis_t merge_analysis; + git_merge_preference_t merge_pref; - analysis = analysis_from_branch(NOFASTFORWARD_BRANCH); - cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL, analysis); + analysis_from_branch(&merge_analysis, &merge_pref, NOFASTFORWARD_BRANCH); + cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL, merge_analysis); } void test_merge_workdir_analysis__uptodate(void) { - git_merge_analysis_t analysis; + git_merge_analysis_t merge_analysis; + git_merge_preference_t merge_pref; - analysis = analysis_from_branch(UPTODATE_BRANCH); - cl_assert_equal_i(GIT_MERGE_ANALYSIS_UP_TO_DATE, analysis); + analysis_from_branch(&merge_analysis, &merge_pref, UPTODATE_BRANCH); + cl_assert_equal_i(GIT_MERGE_ANALYSIS_UP_TO_DATE, merge_analysis); } void test_merge_workdir_analysis__uptodate_merging_prev_commit(void) { - git_merge_analysis_t analysis; + git_merge_analysis_t merge_analysis; + git_merge_preference_t merge_pref; - analysis = analysis_from_branch(PREVIOUS_BRANCH); - cl_assert_equal_i(GIT_MERGE_ANALYSIS_UP_TO_DATE, analysis); + analysis_from_branch(&merge_analysis, &merge_pref, PREVIOUS_BRANCH); + cl_assert_equal_i(GIT_MERGE_ANALYSIS_UP_TO_DATE, merge_analysis); } void test_merge_workdir_analysis__unborn(void) { - git_merge_analysis_t analysis; + git_merge_analysis_t merge_analysis; + git_merge_preference_t merge_pref; git_buf master = GIT_BUF_INIT; git_buf_joinpath(&master, git_repository_path(repo), "refs/heads/master"); p_unlink(git_buf_cstr(&master)); - analysis = analysis_from_branch(NOFASTFORWARD_BRANCH); - cl_assert_equal_i(GIT_MERGE_ANALYSIS_FASTFORWARD, (analysis & GIT_MERGE_ANALYSIS_FASTFORWARD)); - cl_assert_equal_i(GIT_MERGE_ANALYSIS_UNBORN, (analysis & GIT_MERGE_ANALYSIS_UNBORN)); + analysis_from_branch(&merge_analysis, &merge_pref, NOFASTFORWARD_BRANCH); + cl_assert_equal_i(GIT_MERGE_ANALYSIS_FASTFORWARD, (merge_analysis & GIT_MERGE_ANALYSIS_FASTFORWARD)); + cl_assert_equal_i(GIT_MERGE_ANALYSIS_UNBORN, (merge_analysis & GIT_MERGE_ANALYSIS_UNBORN)); git_buf_free(&master); } +void test_merge_workdir_analysis__fastforward_with_config_noff(void) +{ + git_config *config; + git_merge_analysis_t merge_analysis; + git_merge_preference_t merge_pref; + + git_repository_config(&config, repo); + git_config_set_string(config, "merge.ff", "false"); + + analysis_from_branch(&merge_analysis, &merge_pref, FASTFORWARD_BRANCH); + cl_assert_equal_i(GIT_MERGE_ANALYSIS_FASTFORWARD, (merge_analysis & GIT_MERGE_ANALYSIS_FASTFORWARD)); + cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL, (merge_analysis & GIT_MERGE_ANALYSIS_NORMAL)); + cl_assert_equal_i(GIT_MERGE_PREFERENCE_NO_FASTFORWARD, (merge_pref & GIT_MERGE_PREFERENCE_NO_FASTFORWARD)); +} + +void test_merge_workdir_analysis__no_fastforward_with_config_ffonly(void) +{ + git_config *config; + git_merge_analysis_t merge_analysis; + git_merge_preference_t merge_pref; + + git_repository_config(&config, repo); + git_config_set_string(config, "merge.ff", "only"); + + analysis_from_branch(&merge_analysis, &merge_pref, NOFASTFORWARD_BRANCH); + cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL, (merge_analysis & GIT_MERGE_ANALYSIS_NORMAL)); + cl_assert_equal_i(GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY, (merge_pref & GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY)); +} |