summaryrefslogtreecommitdiff
path: root/sequencer.c
diff options
context:
space:
mode:
authorElijah Newren <newren@gmail.com>2020-11-02 23:45:34 (GMT)
committerJunio C Hamano <gitster@pobox.com>2020-11-03 00:35:50 (GMT)
commit14c4586c2dfa94d86d71a60481dd20bc5b56e562 (patch)
tree86ef342952fc4a78c51723dfb96b89fb6cae7443 /sequencer.c
parentfe1a21d5267cae88d4312e3595909720717eb31c (diff)
downloadgit-14c4586c2dfa94d86d71a60481dd20bc5b56e562.zip
git-14c4586c2dfa94d86d71a60481dd20bc5b56e562.tar.gz
git-14c4586c2dfa94d86d71a60481dd20bc5b56e562.tar.bz2
merge,rebase,revert: select ort or recursive by config or environment
Allow the testsuite to run where it treats requests for "recursive" or the default merge algorithm via consulting the environment variable GIT_TEST_MERGE_ALGORITHM which is expected to either be "recursive" (the old traditional algorithm) or "ort" (the new algorithm). Also, allow folks to pick the new algorithm via config setting. It turns out builtin/merge.c already had a way to allow users to specify a different default merge algorithm: pull.twohead. Rather odd configuration name (especially to be in the 'pull' namespace rather than 'merge') but it's there. Add that same configuration to rebase, cherry-pick, and revert. This required updating the various callsites that called merge_trees() or merge_recursive() to conditionally call the new API, so this serves as another demonstration of what the new API looks and feels like. There are almost certainly some callsites that have not yet been modified to work with the new merge algorithm, but this represents the ones that I have been testing with thus far. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'sequencer.c')
-rw-r--r--sequencer.c72
1 files changed, 61 insertions, 11 deletions
diff --git a/sequencer.c b/sequencer.c
index 00acb12..6b6c15c 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -14,7 +14,8 @@
#include "diff.h"
#include "revision.h"
#include "rerere.h"
-#include "merge-recursive.h"
+#include "merge-ort.h"
+#include "merge-ort-wrappers.h"
#include "refs.h"
#include "strvec.h"
#include "quote.h"
@@ -204,6 +205,20 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
return 0;
}
+ if (!opts->default_strategy && !strcmp(k, "pull.twohead")) {
+ int ret = git_config_string((const char**)&opts->default_strategy, k, v);
+ if (ret == 0) {
+ /*
+ * pull.twohead is allowed to be multi-valued; we only
+ * care about the first value.
+ */
+ char *tmp = strchr(opts->default_strategy, ' ');
+ if (tmp)
+ *tmp = '\0';
+ }
+ return ret;
+ }
+
status = git_gpg_config(k, v, NULL);
if (status)
return status;
@@ -317,6 +332,7 @@ int sequencer_remove_state(struct replay_opts *opts)
free(opts->committer_name);
free(opts->committer_email);
free(opts->gpg_sign);
+ free(opts->default_strategy);
free(opts->strategy);
for (i = 0; i < opts->xopts_nr; i++)
free(opts->xopts[i]);
@@ -595,8 +611,9 @@ static int do_recursive_merge(struct repository *r,
struct replay_opts *opts)
{
struct merge_options o;
+ struct merge_result result;
struct tree *next_tree, *base_tree, *head_tree;
- int clean;
+ int clean, show_output;
int i;
struct lock_file index_lock = LOCK_INIT;
@@ -620,12 +637,27 @@ static int do_recursive_merge(struct repository *r,
for (i = 0; i < opts->xopts_nr; i++)
parse_merge_opt(&o, opts->xopts[i]);
- clean = merge_trees(&o,
- head_tree,
- next_tree, base_tree);
- if (is_rebase_i(opts) && clean <= 0)
- fputs(o.obuf.buf, stdout);
- strbuf_release(&o.obuf);
+ if (opts->strategy && !strcmp(opts->strategy, "ort")) {
+ memset(&result, 0, sizeof(result));
+ merge_incore_nonrecursive(&o, base_tree, head_tree, next_tree,
+ &result);
+ show_output = !is_rebase_i(opts) || !result.clean;
+ /*
+ * TODO: merge_switch_to_result will update index/working tree;
+ * we only really want to do that if !result.clean || this is
+ * the final patch to be picked. But determining this is the
+ * final patch would take some work, and "head_tree" would need
+ * to be replace with the tree the index matched before we
+ * started doing any picks.
+ */
+ merge_switch_to_result(&o, head_tree, &result, 1, show_output);
+ clean = result.clean;
+ } else {
+ clean = merge_trees(&o, head_tree, next_tree, base_tree);
+ if (is_rebase_i(opts) && clean <= 0)
+ fputs(o.obuf.buf, stdout);
+ strbuf_release(&o.obuf);
+ }
if (clean < 0) {
rollback_lock_file(&index_lock);
return clean;
@@ -1991,7 +2023,10 @@ static int do_pick_commit(struct repository *r,
if (is_rebase_i(opts) && write_author_script(msg.message) < 0)
res = -1;
- else if (!opts->strategy || !strcmp(opts->strategy, "recursive") || command == TODO_REVERT) {
+ else if (!opts->strategy ||
+ !strcmp(opts->strategy, "recursive") ||
+ !strcmp(opts->strategy, "ort") ||
+ command == TODO_REVERT) {
res = do_recursive_merge(r, base, next, base_label, next_label,
&head, &msgbuf, opts);
if (res < 0)
@@ -3485,7 +3520,9 @@ static int do_merge(struct repository *r,
struct commit_list *bases, *j, *reversed = NULL;
struct commit_list *to_merge = NULL, **tail = &to_merge;
const char *strategy = !opts->xopts_nr &&
- (!opts->strategy || !strcmp(opts->strategy, "recursive")) ?
+ (!opts->strategy ||
+ !strcmp(opts->strategy, "recursive") ||
+ !strcmp(opts->strategy, "ort")) ?
NULL : opts->strategy;
struct merge_options o;
int merge_arg_len, oneline_offset, can_fast_forward, ret, k;
@@ -3722,7 +3759,20 @@ static int do_merge(struct repository *r,
o.branch2 = ref_name.buf;
o.buffer_output = 2;
- ret = merge_recursive(&o, head_commit, merge_commit, reversed, &i);
+ if (opts->strategy && !strcmp(opts->strategy, "ort")) {
+ /*
+ * TODO: Should use merge_incore_recursive() and
+ * merge_switch_to_result(), skipping the call to
+ * merge_switch_to_result() when we don't actually need to
+ * update the index and working copy immediately.
+ */
+ ret = merge_ort_recursive(&o,
+ head_commit, merge_commit, reversed,
+ &i);
+ } else {
+ ret = merge_recursive(&o, head_commit, merge_commit, reversed,
+ &i);
+ }
if (ret <= 0)
fputs(o.obuf.buf, stdout);
strbuf_release(&o.obuf);