merge-tree.c: add --merge-base=<commit> option
This patch will give our callers more flexibility to use `git merge-tree`, such as: git merge-tree --write-tree --merge-base=branch^ HEAD branch This does a merge of HEAD and branch, but uses branch^ as the merge-base. And the reason why using an option flag instead of a positional argument is to allow additional commits passed to merge-tree to be handled via an octopus merge in the future. Signed-off-by: Kyle Zhao <kylezhao@tencent.com> Signed-off-by: Taylor Blau <me@ttaylorr.com>
This commit is contained in:
@ -3,6 +3,7 @@
|
||||
#include "tree-walk.h"
|
||||
#include "xdiff-interface.h"
|
||||
#include "help.h"
|
||||
#include "commit.h"
|
||||
#include "commit-reach.h"
|
||||
#include "merge-ort.h"
|
||||
#include "object-store.h"
|
||||
@ -406,6 +407,7 @@ struct merge_tree_options {
|
||||
};
|
||||
|
||||
static int real_merge(struct merge_tree_options *o,
|
||||
const char *merge_base,
|
||||
const char *branch1, const char *branch2,
|
||||
const char *prefix)
|
||||
{
|
||||
@ -432,16 +434,31 @@ static int real_merge(struct merge_tree_options *o,
|
||||
opt.branch1 = branch1;
|
||||
opt.branch2 = branch2;
|
||||
|
||||
/*
|
||||
* Get the merge bases, in reverse order; see comment above
|
||||
* merge_incore_recursive in merge-ort.h
|
||||
*/
|
||||
merge_bases = get_merge_bases(parent1, parent2);
|
||||
if (!merge_bases && !o->allow_unrelated_histories)
|
||||
die(_("refusing to merge unrelated histories"));
|
||||
merge_bases = reverse_commit_list(merge_bases);
|
||||
if (merge_base) {
|
||||
struct commit *base_commit;
|
||||
struct tree *base_tree, *parent1_tree, *parent2_tree;
|
||||
|
||||
base_commit = lookup_commit_reference_by_name(merge_base);
|
||||
if (!base_commit)
|
||||
die(_("could not lookup commit %s"), merge_base);
|
||||
|
||||
opt.ancestor = merge_base;
|
||||
base_tree = get_commit_tree(base_commit);
|
||||
parent1_tree = get_commit_tree(parent1);
|
||||
parent2_tree = get_commit_tree(parent2);
|
||||
merge_incore_nonrecursive(&opt, base_tree, parent1_tree, parent2_tree, &result);
|
||||
} else {
|
||||
/*
|
||||
* Get the merge bases, in reverse order; see comment above
|
||||
* merge_incore_recursive in merge-ort.h
|
||||
*/
|
||||
merge_bases = get_merge_bases(parent1, parent2);
|
||||
if (!merge_bases && !o->allow_unrelated_histories)
|
||||
die(_("refusing to merge unrelated histories"));
|
||||
merge_bases = reverse_commit_list(merge_bases);
|
||||
merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
|
||||
}
|
||||
|
||||
merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
|
||||
if (result.clean < 0)
|
||||
die(_("failure to merge"));
|
||||
|
||||
@ -487,6 +504,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
|
||||
struct merge_tree_options o = { .show_messages = -1 };
|
||||
int expected_remaining_argc;
|
||||
int original_argc;
|
||||
const char *merge_base = NULL;
|
||||
|
||||
const char * const merge_tree_usage[] = {
|
||||
N_("git merge-tree [--write-tree] [<options>] <branch1> <branch2>"),
|
||||
@ -515,6 +533,10 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
|
||||
&o.use_stdin,
|
||||
N_("perform multiple merges, one per line of input"),
|
||||
PARSE_OPT_NONEG),
|
||||
OPT_STRING(0, "merge-base",
|
||||
&merge_base,
|
||||
N_("commit"),
|
||||
N_("specify a merge-base for the merge")),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
@ -529,6 +551,8 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
|
||||
|
||||
if (o.mode == MODE_TRIVIAL)
|
||||
die(_("--trivial-merge is incompatible with all other options"));
|
||||
if (merge_base)
|
||||
die(_("--merge-base is incompatible with --stdin"));
|
||||
line_termination = '\0';
|
||||
while (strbuf_getline_lf(&buf, stdin) != EOF) {
|
||||
struct strbuf **split;
|
||||
@ -538,7 +562,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
|
||||
if (!split[0] || !split[1] || split[2])
|
||||
die(_("malformed input line: '%s'."), buf.buf);
|
||||
strbuf_rtrim(split[0]);
|
||||
result = real_merge(&o, split[0]->buf, split[1]->buf, prefix);
|
||||
result = real_merge(&o, merge_base, split[0]->buf, split[1]->buf, prefix);
|
||||
if (result < 0)
|
||||
die(_("merging cannot continue; got unclean result of %d"), result);
|
||||
strbuf_list_free(split);
|
||||
@ -581,7 +605,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
|
||||
|
||||
/* Do the relevant type of merge */
|
||||
if (o.mode == MODE_REAL)
|
||||
return real_merge(&o, argv[0], argv[1], prefix);
|
||||
return real_merge(&o, merge_base, argv[0], argv[1], prefix);
|
||||
else
|
||||
return trivial_merge(argv[0], argv[1], argv[2]);
|
||||
}
|
||||
|
Reference in New Issue
Block a user