Introduce GIT_MERGE_CONFIG_* for merge.ff settings git_merge_analysis will now return GIT_MERGE_CONFIG_NO_FASTFORWARD when merge.ff=false and GIT_MERGE_CONFIG_FASTFORWARD_ONLY when merge.ff=true
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
diff --git a/include/git2/merge.h b/include/git2/merge.h
index 7915050..dc63ed5 100644
--- a/include/git2/merge.h
+++ b/include/git2/merge.h
@@ -266,6 +266,18 @@ typedef enum {
* to simply set HEAD to the target commit(s).
*/
GIT_MERGE_ANALYSIS_UNBORN = (1 << 3),
+
+ /**
+ * There is a `merge.ff=false` configuration setting, suggesting that
+ * the user does not want to allow a fast-forward merge.
+ */
+ GIT_MERGE_CONFIG_NO_FASTFORWARD = (1 << 4),
+
+ /**
+ * There is a `merge.ff=only` configuration setting, suggesting that
+ * the user only wants fast-forward merges.
+ */
+ GIT_MERGE_CONFIG_FASTFORWARD_ONLY = (1 << 5),
} git_merge_analysis_t;
/**
diff --git a/src/merge.c b/src/merge.c
index 6a8e587..85b7448 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -2564,6 +2564,37 @@ done:
return error;
}
+int analysis_config(git_merge_analysis_t *out, git_repository *repo)
+{
+ git_config *config;
+ const char *value;
+ int bool_value, error = 0;
+
+ if ((error = git_repository_config(&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_CONFIG_NO_FASTFORWARD;
+ } else {
+ if (strcasecmp(value, "only") == 0)
+ *out |= GIT_MERGE_CONFIG_FASTFORWARD_ONLY;
+ }
+
+done:
+ git_config_free(config);
+ return error;
+}
+
int git_merge_analysis(
git_merge_analysis_t *out,
git_repository *repo,
@@ -2575,16 +2606,19 @@ int git_merge_analysis(
assert(out && repo && their_heads);
+ if (their_heads_len != 1) {
+ giterr_set(GITERR_MERGE, "Can only merge a single branch");
+ error = -1;
+ goto done;
+ }
+
*out = GIT_MERGE_ANALYSIS_NONE;
- if (git_repository_head_unborn(repo)) {
- *out = GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_UNBORN;
+ if ((error = analysis_config(out, repo)) < 0)
goto done;
- }
- if (their_heads_len != 1) {
- giterr_set(GITERR_MERGE, "Can only merge a single branch");
- error = -1;
+ if (git_repository_head_unborn(repo)) {
+ *out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_UNBORN;
goto done;
}
@@ -2593,15 +2627,15 @@ int git_merge_analysis(
/* 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;
+ *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;
+ *out |= GIT_MERGE_ANALYSIS_FASTFORWARD | GIT_MERGE_ANALYSIS_NORMAL;
/* Otherwise, just a normal merge is possible. */
else
- *out = GIT_MERGE_ANALYSIS_NORMAL;
+ *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 0e93785..daa4e9d 100644
--- a/tests/merge/workdir/analysis.c
+++ b/tests/merge/workdir/analysis.c
@@ -105,3 +105,29 @@ void test_merge_workdir_analysis__unborn(void)
git_buf_free(&master);
}
+void test_merge_workdir_analysis__fastforward_with_config_noff(void)
+{
+ git_config *config;
+ git_merge_analysis_t analysis;
+
+ git_repository_config(&config, repo);
+ git_config_set_string(config, "merge.ff", "false");
+
+ 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));
+ cl_assert_equal_i(GIT_MERGE_CONFIG_NO_FASTFORWARD, (analysis & GIT_MERGE_CONFIG_NO_FASTFORWARD));
+}
+
+void test_merge_workdir_analysis__no_fastforward_with_config_ffonly(void)
+{
+ git_config *config;
+ git_merge_analysis_t analysis;
+
+ git_repository_config(&config, repo);
+ git_config_set_string(config, "merge.ff", "only");
+
+ analysis = analysis_from_branch(NOFASTFORWARD_BRANCH);
+ cl_assert_equal_i(GIT_MERGE_ANALYSIS_NORMAL, (analysis & GIT_MERGE_ANALYSIS_NORMAL));
+ cl_assert_equal_i(GIT_MERGE_CONFIG_FASTFORWARD_ONLY, (analysis & GIT_MERGE_CONFIG_FASTFORWARD_ONLY));
+}