diff options
Diffstat (limited to 'builtin/merge.c')
| -rw-r--r-- | builtin/merge.c | 1292 | 
1 files changed, 1292 insertions, 0 deletions
| diff --git a/builtin/merge.c b/builtin/merge.c new file mode 100644 index 0000000000..c043066845 --- /dev/null +++ b/builtin/merge.c @@ -0,0 +1,1292 @@ +/* + * Builtin "git merge" + * + * Copyright (c) 2008 Miklos Vajna <vmiklos@frugalware.org> + * + * Based on git-merge.sh by Junio C Hamano. + */ + +#include "cache.h" +#include "parse-options.h" +#include "builtin.h" +#include "run-command.h" +#include "diff.h" +#include "refs.h" +#include "commit.h" +#include "diffcore.h" +#include "revision.h" +#include "unpack-trees.h" +#include "cache-tree.h" +#include "dir.h" +#include "utf8.h" +#include "log-tree.h" +#include "color.h" +#include "rerere.h" +#include "help.h" +#include "merge-recursive.h" +#include "resolve-undo.h" + +#define DEFAULT_TWOHEAD (1<<0) +#define DEFAULT_OCTOPUS (1<<1) +#define NO_FAST_FORWARD (1<<2) +#define NO_TRIVIAL      (1<<3) + +struct strategy { +	const char *name; +	unsigned attr; +}; + +static const char * const builtin_merge_usage[] = { +	"git merge [options] <remote>...", +	"git merge [options] <msg> HEAD <remote>", +	NULL +}; + +static int show_diffstat = 1, option_log, squash; +static int option_commit = 1, allow_fast_forward = 1; +static int fast_forward_only; +static int allow_trivial = 1, have_message; +static struct strbuf merge_msg; +static struct commit_list *remoteheads; +static unsigned char head[20], stash[20]; +static struct strategy **use_strategies; +static size_t use_strategies_nr, use_strategies_alloc; +static const char **xopts; +static size_t xopts_nr, xopts_alloc; +static const char *branch; +static int verbosity; +static int allow_rerere_auto; + +static struct strategy all_strategy[] = { +	{ "recursive",  DEFAULT_TWOHEAD | NO_TRIVIAL }, +	{ "octopus",    DEFAULT_OCTOPUS }, +	{ "resolve",    0 }, +	{ "ours",       NO_FAST_FORWARD | NO_TRIVIAL }, +	{ "subtree",    NO_FAST_FORWARD | NO_TRIVIAL }, +}; + +static const char *pull_twohead, *pull_octopus; + +static int option_parse_message(const struct option *opt, +				const char *arg, int unset) +{ +	struct strbuf *buf = opt->value; + +	if (unset) +		strbuf_setlen(buf, 0); +	else if (arg) { +		strbuf_addf(buf, "%s%s", buf->len ? "\n\n" : "", arg); +		have_message = 1; +	} else +		return error("switch `m' requires a value"); +	return 0; +} + +static struct strategy *get_strategy(const char *name) +{ +	int i; +	struct strategy *ret; +	static struct cmdnames main_cmds, other_cmds; +	static int loaded; + +	if (!name) +		return NULL; + +	for (i = 0; i < ARRAY_SIZE(all_strategy); i++) +		if (!strcmp(name, all_strategy[i].name)) +			return &all_strategy[i]; + +	if (!loaded) { +		struct cmdnames not_strategies; +		loaded = 1; + +		memset(¬_strategies, 0, sizeof(struct cmdnames)); +		load_command_list("git-merge-", &main_cmds, &other_cmds); +		for (i = 0; i < main_cmds.cnt; i++) { +			int j, found = 0; +			struct cmdname *ent = main_cmds.names[i]; +			for (j = 0; j < ARRAY_SIZE(all_strategy); j++) +				if (!strncmp(ent->name, all_strategy[j].name, ent->len) +						&& !all_strategy[j].name[ent->len]) +					found = 1; +			if (!found) +				add_cmdname(¬_strategies, ent->name, ent->len); +		} +		exclude_cmds(&main_cmds, ¬_strategies); +	} +	if (!is_in_cmdlist(&main_cmds, name) && !is_in_cmdlist(&other_cmds, name)) { +		fprintf(stderr, "Could not find merge strategy '%s'.\n", name); +		fprintf(stderr, "Available strategies are:"); +		for (i = 0; i < main_cmds.cnt; i++) +			fprintf(stderr, " %s", main_cmds.names[i]->name); +		fprintf(stderr, ".\n"); +		if (other_cmds.cnt) { +			fprintf(stderr, "Available custom strategies are:"); +			for (i = 0; i < other_cmds.cnt; i++) +				fprintf(stderr, " %s", other_cmds.names[i]->name); +			fprintf(stderr, ".\n"); +		} +		exit(1); +	} + +	ret = xcalloc(1, sizeof(struct strategy)); +	ret->name = xstrdup(name); +	return ret; +} + +static void append_strategy(struct strategy *s) +{ +	ALLOC_GROW(use_strategies, use_strategies_nr + 1, use_strategies_alloc); +	use_strategies[use_strategies_nr++] = s; +} + +static int option_parse_strategy(const struct option *opt, +				 const char *name, int unset) +{ +	if (unset) +		return 0; + +	append_strategy(get_strategy(name)); +	return 0; +} + +static int option_parse_x(const struct option *opt, +			  const char *arg, int unset) +{ +	if (unset) +		return 0; + +	ALLOC_GROW(xopts, xopts_nr + 1, xopts_alloc); +	xopts[xopts_nr++] = xstrdup(arg); +	return 0; +} + +static int option_parse_n(const struct option *opt, +			  const char *arg, int unset) +{ +	show_diffstat = unset; +	return 0; +} + +static struct option builtin_merge_options[] = { +	{ OPTION_CALLBACK, 'n', NULL, NULL, NULL, +		"do not show a diffstat at the end of the merge", +		PARSE_OPT_NOARG, option_parse_n }, +	OPT_BOOLEAN(0, "stat", &show_diffstat, +		"show a diffstat at the end of the merge"), +	OPT_BOOLEAN(0, "summary", &show_diffstat, "(synonym to --stat)"), +	OPT_BOOLEAN(0, "log", &option_log, +		"add list of one-line log to merge commit message"), +	OPT_BOOLEAN(0, "squash", &squash, +		"create a single commit instead of doing a merge"), +	OPT_BOOLEAN(0, "commit", &option_commit, +		"perform a commit if the merge succeeds (default)"), +	OPT_BOOLEAN(0, "ff", &allow_fast_forward, +		"allow fast-forward (default)"), +	OPT_BOOLEAN(0, "ff-only", &fast_forward_only, +		"abort if fast-forward is not possible"), +	OPT_RERERE_AUTOUPDATE(&allow_rerere_auto), +	OPT_CALLBACK('s', "strategy", &use_strategies, "strategy", +		"merge strategy to use", option_parse_strategy), +	OPT_CALLBACK('X', "strategy-option", &xopts, "option=value", +		"option for selected merge strategy", option_parse_x), +	OPT_CALLBACK('m', "message", &merge_msg, "message", +		"message to be used for the merge commit (if any)", +		option_parse_message), +	OPT__VERBOSITY(&verbosity), +	OPT_END() +}; + +/* Cleans up metadata that is uninteresting after a succeeded merge. */ +static void drop_save(void) +{ +	unlink(git_path("MERGE_HEAD")); +	unlink(git_path("MERGE_MSG")); +	unlink(git_path("MERGE_MODE")); +} + +static void save_state(void) +{ +	int len; +	struct child_process cp; +	struct strbuf buffer = STRBUF_INIT; +	const char *argv[] = {"stash", "create", NULL}; + +	memset(&cp, 0, sizeof(cp)); +	cp.argv = argv; +	cp.out = -1; +	cp.git_cmd = 1; + +	if (start_command(&cp)) +		die("could not run stash."); +	len = strbuf_read(&buffer, cp.out, 1024); +	close(cp.out); + +	if (finish_command(&cp) || len < 0) +		die("stash failed"); +	else if (!len) +		return; +	strbuf_setlen(&buffer, buffer.len-1); +	if (get_sha1(buffer.buf, stash)) +		die("not a valid object: %s", buffer.buf); +} + +static void reset_hard(unsigned const char *sha1, int verbose) +{ +	int i = 0; +	const char *args[6]; + +	args[i++] = "read-tree"; +	if (verbose) +		args[i++] = "-v"; +	args[i++] = "--reset"; +	args[i++] = "-u"; +	args[i++] = sha1_to_hex(sha1); +	args[i] = NULL; + +	if (run_command_v_opt(args, RUN_GIT_CMD)) +		die("read-tree failed"); +} + +static void restore_state(void) +{ +	struct strbuf sb = STRBUF_INIT; +	const char *args[] = { "stash", "apply", NULL, NULL }; + +	if (is_null_sha1(stash)) +		return; + +	reset_hard(head, 1); + +	args[2] = sha1_to_hex(stash); + +	/* +	 * It is OK to ignore error here, for example when there was +	 * nothing to restore. +	 */ +	run_command_v_opt(args, RUN_GIT_CMD); + +	strbuf_release(&sb); +	refresh_cache(REFRESH_QUIET); +} + +/* This is called when no merge was necessary. */ +static void finish_up_to_date(const char *msg) +{ +	if (verbosity >= 0) +		printf("%s%s\n", squash ? " (nothing to squash)" : "", msg); +	drop_save(); +} + +static void squash_message(void) +{ +	struct rev_info rev; +	struct commit *commit; +	struct strbuf out = STRBUF_INIT; +	struct commit_list *j; +	int fd; +	struct pretty_print_context ctx = {0}; + +	printf("Squash commit -- not updating HEAD\n"); +	fd = open(git_path("SQUASH_MSG"), O_WRONLY | O_CREAT, 0666); +	if (fd < 0) +		die_errno("Could not write to '%s'", git_path("SQUASH_MSG")); + +	init_revisions(&rev, NULL); +	rev.ignore_merges = 1; +	rev.commit_format = CMIT_FMT_MEDIUM; + +	commit = lookup_commit(head); +	commit->object.flags |= UNINTERESTING; +	add_pending_object(&rev, &commit->object, NULL); + +	for (j = remoteheads; j; j = j->next) +		add_pending_object(&rev, &j->item->object, NULL); + +	setup_revisions(0, NULL, &rev, NULL); +	if (prepare_revision_walk(&rev)) +		die("revision walk setup failed"); + +	ctx.abbrev = rev.abbrev; +	ctx.date_mode = rev.date_mode; + +	strbuf_addstr(&out, "Squashed commit of the following:\n"); +	while ((commit = get_revision(&rev)) != NULL) { +		strbuf_addch(&out, '\n'); +		strbuf_addf(&out, "commit %s\n", +			sha1_to_hex(commit->object.sha1)); +		pretty_print_commit(rev.commit_format, commit, &out, &ctx); +	} +	if (write(fd, out.buf, out.len) < 0) +		die_errno("Writing SQUASH_MSG"); +	if (close(fd)) +		die_errno("Finishing SQUASH_MSG"); +	strbuf_release(&out); +} + +static void finish(const unsigned char *new_head, const char *msg) +{ +	struct strbuf reflog_message = STRBUF_INIT; + +	if (!msg) +		strbuf_addstr(&reflog_message, getenv("GIT_REFLOG_ACTION")); +	else { +		if (verbosity >= 0) +			printf("%s\n", msg); +		strbuf_addf(&reflog_message, "%s: %s", +			getenv("GIT_REFLOG_ACTION"), msg); +	} +	if (squash) { +		squash_message(); +	} else { +		if (verbosity >= 0 && !merge_msg.len) +			printf("No merge message -- not updating HEAD\n"); +		else { +			const char *argv_gc_auto[] = { "gc", "--auto", NULL }; +			update_ref(reflog_message.buf, "HEAD", +				new_head, head, 0, +				DIE_ON_ERR); +			/* +			 * We ignore errors in 'gc --auto', since the +			 * user should see them. +			 */ +			run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); +		} +	} +	if (new_head && show_diffstat) { +		struct diff_options opts; +		diff_setup(&opts); +		opts.output_format |= +			DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; +		opts.detect_rename = DIFF_DETECT_RENAME; +		if (diff_use_color_default > 0) +			DIFF_OPT_SET(&opts, COLOR_DIFF); +		if (diff_setup_done(&opts) < 0) +			die("diff_setup_done failed"); +		diff_tree_sha1(head, new_head, "", &opts); +		diffcore_std(&opts); +		diff_flush(&opts); +	} + +	/* Run a post-merge hook */ +	run_hook(NULL, "post-merge", squash ? "1" : "0", NULL); + +	strbuf_release(&reflog_message); +} + +/* Get the name for the merge commit's message. */ +static void merge_name(const char *remote, struct strbuf *msg) +{ +	struct object *remote_head; +	unsigned char branch_head[20], buf_sha[20]; +	struct strbuf buf = STRBUF_INIT; +	struct strbuf bname = STRBUF_INIT; +	const char *ptr; +	char *found_ref; +	int len, early; + +	strbuf_branchname(&bname, remote); +	remote = bname.buf; + +	memset(branch_head, 0, sizeof(branch_head)); +	remote_head = peel_to_type(remote, 0, NULL, OBJ_COMMIT); +	if (!remote_head) +		die("'%s' does not point to a commit", remote); + +	if (dwim_ref(remote, strlen(remote), branch_head, &found_ref) > 0) { +		if (!prefixcmp(found_ref, "refs/heads/")) { +			strbuf_addf(msg, "%s\t\tbranch '%s' of .\n", +				    sha1_to_hex(branch_head), remote); +			goto cleanup; +		} +		if (!prefixcmp(found_ref, "refs/remotes/")) { +			strbuf_addf(msg, "%s\t\tremote branch '%s' of .\n", +				    sha1_to_hex(branch_head), remote); +			goto cleanup; +		} +	} + +	/* See if remote matches <name>^^^.. or <name>~<number> */ +	for (len = 0, ptr = remote + strlen(remote); +	     remote < ptr && ptr[-1] == '^'; +	     ptr--) +		len++; +	if (len) +		early = 1; +	else { +		early = 0; +		ptr = strrchr(remote, '~'); +		if (ptr) { +			int seen_nonzero = 0; + +			len++; /* count ~ */ +			while (*++ptr && isdigit(*ptr)) { +				seen_nonzero |= (*ptr != '0'); +				len++; +			} +			if (*ptr) +				len = 0; /* not ...~<number> */ +			else if (seen_nonzero) +				early = 1; +			else if (len == 1) +				early = 1; /* "name~" is "name~1"! */ +		} +	} +	if (len) { +		struct strbuf truname = STRBUF_INIT; +		strbuf_addstr(&truname, "refs/heads/"); +		strbuf_addstr(&truname, remote); +		strbuf_setlen(&truname, truname.len - len); +		if (resolve_ref(truname.buf, buf_sha, 0, NULL)) { +			strbuf_addf(msg, +				    "%s\t\tbranch '%s'%s of .\n", +				    sha1_to_hex(remote_head->sha1), +				    truname.buf + 11, +				    (early ? " (early part)" : "")); +			strbuf_release(&truname); +			goto cleanup; +		} +	} + +	if (!strcmp(remote, "FETCH_HEAD") && +			!access(git_path("FETCH_HEAD"), R_OK)) { +		FILE *fp; +		struct strbuf line = STRBUF_INIT; +		char *ptr; + +		fp = fopen(git_path("FETCH_HEAD"), "r"); +		if (!fp) +			die_errno("could not open '%s' for reading", +				  git_path("FETCH_HEAD")); +		strbuf_getline(&line, fp, '\n'); +		fclose(fp); +		ptr = strstr(line.buf, "\tnot-for-merge\t"); +		if (ptr) +			strbuf_remove(&line, ptr-line.buf+1, 13); +		strbuf_addbuf(msg, &line); +		strbuf_release(&line); +		goto cleanup; +	} +	strbuf_addf(msg, "%s\t\tcommit '%s'\n", +		sha1_to_hex(remote_head->sha1), remote); +cleanup: +	strbuf_release(&buf); +	strbuf_release(&bname); +} + +static int git_merge_config(const char *k, const char *v, void *cb) +{ +	if (branch && !prefixcmp(k, "branch.") && +		!prefixcmp(k + 7, branch) && +		!strcmp(k + 7 + strlen(branch), ".mergeoptions")) { +		const char **argv; +		int argc; +		char *buf; + +		buf = xstrdup(v); +		argc = split_cmdline(buf, &argv); +		if (argc < 0) +			die("Bad branch.%s.mergeoptions string", branch); +		argv = xrealloc(argv, sizeof(*argv) * (argc + 2)); +		memmove(argv + 1, argv, sizeof(*argv) * (argc + 1)); +		argc++; +		parse_options(argc, argv, NULL, builtin_merge_options, +			      builtin_merge_usage, 0); +		free(buf); +	} + +	if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat")) +		show_diffstat = git_config_bool(k, v); +	else if (!strcmp(k, "pull.twohead")) +		return git_config_string(&pull_twohead, k, v); +	else if (!strcmp(k, "pull.octopus")) +		return git_config_string(&pull_octopus, k, v); +	else if (!strcmp(k, "merge.log") || !strcmp(k, "merge.summary")) +		option_log = git_config_bool(k, v); +	return git_diff_ui_config(k, v, cb); +} + +static int read_tree_trivial(unsigned char *common, unsigned char *head, +			     unsigned char *one) +{ +	int i, nr_trees = 0; +	struct tree *trees[MAX_UNPACK_TREES]; +	struct tree_desc t[MAX_UNPACK_TREES]; +	struct unpack_trees_options opts; + +	memset(&opts, 0, sizeof(opts)); +	opts.head_idx = 2; +	opts.src_index = &the_index; +	opts.dst_index = &the_index; +	opts.update = 1; +	opts.verbose_update = 1; +	opts.trivial_merges_only = 1; +	opts.merge = 1; +	trees[nr_trees] = parse_tree_indirect(common); +	if (!trees[nr_trees++]) +		return -1; +	trees[nr_trees] = parse_tree_indirect(head); +	if (!trees[nr_trees++]) +		return -1; +	trees[nr_trees] = parse_tree_indirect(one); +	if (!trees[nr_trees++]) +		return -1; +	opts.fn = threeway_merge; +	cache_tree_free(&active_cache_tree); +	for (i = 0; i < nr_trees; i++) { +		parse_tree(trees[i]); +		init_tree_desc(t+i, trees[i]->buffer, trees[i]->size); +	} +	if (unpack_trees(nr_trees, t, &opts)) +		return -1; +	return 0; +} + +static void write_tree_trivial(unsigned char *sha1) +{ +	if (write_cache_as_tree(sha1, 0, NULL)) +		die("git write-tree failed to write a tree"); +} + +static int try_merge_strategy(const char *strategy, struct commit_list *common, +			      const char *head_arg) +{ +	const char **args; +	int i = 0, x = 0, ret; +	struct commit_list *j; +	struct strbuf buf = STRBUF_INIT; +	int index_fd; +	struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); + +	index_fd = hold_locked_index(lock, 1); +	refresh_cache(REFRESH_QUIET); +	if (active_cache_changed && +			(write_cache(index_fd, active_cache, active_nr) || +			 commit_locked_index(lock))) +		return error("Unable to write index."); +	rollback_lock_file(lock); + +	if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) { +		int clean; +		struct commit *result; +		struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); +		int index_fd; +		struct commit_list *reversed = NULL; +		struct merge_options o; + +		if (remoteheads->next) { +			error("Not handling anything other than two heads merge."); +			return 2; +		} + +		init_merge_options(&o); +		if (!strcmp(strategy, "subtree")) +			o.subtree_shift = ""; + +		for (x = 0; x < xopts_nr; x++) { +			if (!strcmp(xopts[x], "ours")) +				o.recursive_variant = MERGE_RECURSIVE_OURS; +			else if (!strcmp(xopts[x], "theirs")) +				o.recursive_variant = MERGE_RECURSIVE_THEIRS; +			else if (!strcmp(xopts[x], "subtree")) +				o.subtree_shift = ""; +			else if (!prefixcmp(xopts[x], "subtree=")) +				o.subtree_shift = xopts[x]+8; +			else +				die("Unknown option for merge-recursive: -X%s", xopts[x]); +		} + +		o.branch1 = head_arg; +		o.branch2 = remoteheads->item->util; + +		for (j = common; j; j = j->next) +			commit_list_insert(j->item, &reversed); + +		index_fd = hold_locked_index(lock, 1); +		clean = merge_recursive(&o, lookup_commit(head), +				remoteheads->item, reversed, &result); +		if (active_cache_changed && +				(write_cache(index_fd, active_cache, active_nr) || +				 commit_locked_index(lock))) +			die ("unable to write %s", get_index_file()); +		rollback_lock_file(lock); +		return clean ? 0 : 1; +	} else { +		args = xmalloc((4 + xopts_nr + commit_list_count(common) + +					commit_list_count(remoteheads)) * sizeof(char *)); +		strbuf_addf(&buf, "merge-%s", strategy); +		args[i++] = buf.buf; +		for (x = 0; x < xopts_nr; x++) { +			char *s = xmalloc(strlen(xopts[x])+2+1); +			strcpy(s, "--"); +			strcpy(s+2, xopts[x]); +			args[i++] = s; +		} +		for (j = common; j; j = j->next) +			args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); +		args[i++] = "--"; +		args[i++] = head_arg; +		for (j = remoteheads; j; j = j->next) +			args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); +		args[i] = NULL; +		ret = run_command_v_opt(args, RUN_GIT_CMD); +		strbuf_release(&buf); +		i = 1; +		for (x = 0; x < xopts_nr; x++) +			free((void *)args[i++]); +		for (j = common; j; j = j->next) +			free((void *)args[i++]); +		i += 2; +		for (j = remoteheads; j; j = j->next) +			free((void *)args[i++]); +		free(args); +		discard_cache(); +		if (read_cache() < 0) +			die("failed to read the cache"); +		resolve_undo_clear(); +		return ret; +	} +} + +static void count_diff_files(struct diff_queue_struct *q, +			     struct diff_options *opt, void *data) +{ +	int *count = data; + +	(*count) += q->nr; +} + +static int count_unmerged_entries(void) +{ +	int i, ret = 0; + +	for (i = 0; i < active_nr; i++) +		if (ce_stage(active_cache[i])) +			ret++; + +	return ret; +} + +int checkout_fast_forward(const unsigned char *head, const unsigned char *remote) +{ +	struct tree *trees[MAX_UNPACK_TREES]; +	struct unpack_trees_options opts; +	struct tree_desc t[MAX_UNPACK_TREES]; +	int i, fd, nr_trees = 0; +	struct dir_struct dir; +	struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); + +	refresh_cache(REFRESH_QUIET); + +	fd = hold_locked_index(lock_file, 1); + +	memset(&trees, 0, sizeof(trees)); +	memset(&opts, 0, sizeof(opts)); +	memset(&t, 0, sizeof(t)); +	memset(&dir, 0, sizeof(dir)); +	dir.flags |= DIR_SHOW_IGNORED; +	dir.exclude_per_dir = ".gitignore"; +	opts.dir = &dir; + +	opts.head_idx = 1; +	opts.src_index = &the_index; +	opts.dst_index = &the_index; +	opts.update = 1; +	opts.verbose_update = 1; +	opts.merge = 1; +	opts.fn = twoway_merge; +	opts.msgs = get_porcelain_error_msgs(); + +	trees[nr_trees] = parse_tree_indirect(head); +	if (!trees[nr_trees++]) +		return -1; +	trees[nr_trees] = parse_tree_indirect(remote); +	if (!trees[nr_trees++]) +		return -1; +	for (i = 0; i < nr_trees; i++) { +		parse_tree(trees[i]); +		init_tree_desc(t+i, trees[i]->buffer, trees[i]->size); +	} +	if (unpack_trees(nr_trees, t, &opts)) +		return -1; +	if (write_cache(fd, active_cache, active_nr) || +		commit_locked_index(lock_file)) +		die("unable to write new index file"); +	return 0; +} + +static void split_merge_strategies(const char *string, struct strategy **list, +				   int *nr, int *alloc) +{ +	char *p, *q, *buf; + +	if (!string) +		return; + +	buf = xstrdup(string); +	q = buf; +	for (;;) { +		p = strchr(q, ' '); +		if (!p) { +			ALLOC_GROW(*list, *nr + 1, *alloc); +			(*list)[(*nr)++].name = xstrdup(q); +			free(buf); +			return; +		} else { +			*p = '\0'; +			ALLOC_GROW(*list, *nr + 1, *alloc); +			(*list)[(*nr)++].name = xstrdup(q); +			q = ++p; +		} +	} +} + +static void add_strategies(const char *string, unsigned attr) +{ +	struct strategy *list = NULL; +	int list_alloc = 0, list_nr = 0, i; + +	memset(&list, 0, sizeof(list)); +	split_merge_strategies(string, &list, &list_nr, &list_alloc); +	if (list) { +		for (i = 0; i < list_nr; i++) +			append_strategy(get_strategy(list[i].name)); +		return; +	} +	for (i = 0; i < ARRAY_SIZE(all_strategy); i++) +		if (all_strategy[i].attr & attr) +			append_strategy(&all_strategy[i]); + +} + +static int merge_trivial(void) +{ +	unsigned char result_tree[20], result_commit[20]; +	struct commit_list *parent = xmalloc(sizeof(*parent)); + +	write_tree_trivial(result_tree); +	printf("Wonderful.\n"); +	parent->item = lookup_commit(head); +	parent->next = xmalloc(sizeof(*parent->next)); +	parent->next->item = remoteheads->item; +	parent->next->next = NULL; +	commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL); +	finish(result_commit, "In-index merge"); +	drop_save(); +	return 0; +} + +static int finish_automerge(struct commit_list *common, +			    unsigned char *result_tree, +			    const char *wt_strategy) +{ +	struct commit_list *parents = NULL, *j; +	struct strbuf buf = STRBUF_INIT; +	unsigned char result_commit[20]; + +	free_commit_list(common); +	if (allow_fast_forward) { +		parents = remoteheads; +		commit_list_insert(lookup_commit(head), &parents); +		parents = reduce_heads(parents); +	} else { +		struct commit_list **pptr = &parents; + +		pptr = &commit_list_insert(lookup_commit(head), +				pptr)->next; +		for (j = remoteheads; j; j = j->next) +			pptr = &commit_list_insert(j->item, pptr)->next; +	} +	free_commit_list(remoteheads); +	strbuf_addch(&merge_msg, '\n'); +	commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL); +	strbuf_addf(&buf, "Merge made by %s.", wt_strategy); +	finish(result_commit, buf.buf); +	strbuf_release(&buf); +	drop_save(); +	return 0; +} + +static int suggest_conflicts(void) +{ +	FILE *fp; +	int pos; + +	fp = fopen(git_path("MERGE_MSG"), "a"); +	if (!fp) +		die_errno("Could not open '%s' for writing", +			  git_path("MERGE_MSG")); +	fprintf(fp, "\nConflicts:\n"); +	for (pos = 0; pos < active_nr; pos++) { +		struct cache_entry *ce = active_cache[pos]; + +		if (ce_stage(ce)) { +			fprintf(fp, "\t%s\n", ce->name); +			while (pos + 1 < active_nr && +					!strcmp(ce->name, +						active_cache[pos + 1]->name)) +				pos++; +		} +	} +	fclose(fp); +	rerere(allow_rerere_auto); +	printf("Automatic merge failed; " +			"fix conflicts and then commit the result.\n"); +	return 1; +} + +static struct commit *is_old_style_invocation(int argc, const char **argv) +{ +	struct commit *second_token = NULL; +	if (argc > 2) { +		unsigned char second_sha1[20]; + +		if (get_sha1(argv[1], second_sha1)) +			return NULL; +		second_token = lookup_commit_reference_gently(second_sha1, 0); +		if (!second_token) +			die("'%s' is not a commit", argv[1]); +		if (hashcmp(second_token->object.sha1, head)) +			return NULL; +	} +	return second_token; +} + +static int evaluate_result(void) +{ +	int cnt = 0; +	struct rev_info rev; + +	/* Check how many files differ. */ +	init_revisions(&rev, ""); +	setup_revisions(0, NULL, &rev, NULL); +	rev.diffopt.output_format |= +		DIFF_FORMAT_CALLBACK; +	rev.diffopt.format_callback = count_diff_files; +	rev.diffopt.format_callback_data = &cnt; +	run_diff_files(&rev, 0); + +	/* +	 * Check how many unmerged entries are +	 * there. +	 */ +	cnt += count_unmerged_entries(); + +	return cnt; +} + +int cmd_merge(int argc, const char **argv, const char *prefix) +{ +	unsigned char result_tree[20]; +	struct strbuf buf = STRBUF_INIT; +	const char *head_arg; +	int flag, head_invalid = 0, i; +	int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0; +	struct commit_list *common = NULL; +	const char *best_strategy = NULL, *wt_strategy = NULL; +	struct commit_list **remotes = &remoteheads; + +	if (read_cache_unmerged()) { +		die_resolve_conflict("merge"); +	} +	if (file_exists(git_path("MERGE_HEAD"))) { +		/* +		 * There is no unmerged entry, don't advise 'git +		 * add/rm <file>', just 'git commit'. +		 */ +		if (advice_resolve_conflict) +			die("You have not concluded your merge (MERGE_HEAD exists).\n" +			    "Please, commit your changes before you can merge."); +		else +			die("You have not concluded your merge (MERGE_HEAD exists)."); +	} + +	resolve_undo_clear(); +	/* +	 * Check if we are _not_ on a detached HEAD, i.e. if there is a +	 * current branch. +	 */ +	branch = resolve_ref("HEAD", head, 0, &flag); +	if (branch && !prefixcmp(branch, "refs/heads/")) +		branch += 11; +	if (is_null_sha1(head)) +		head_invalid = 1; + +	git_config(git_merge_config, NULL); + +	/* for color.ui */ +	if (diff_use_color_default == -1) +		diff_use_color_default = git_use_color_default; + +	argc = parse_options(argc, argv, prefix, builtin_merge_options, +			builtin_merge_usage, 0); +	if (verbosity < 0) +		show_diffstat = 0; + +	if (squash) { +		if (!allow_fast_forward) +			die("You cannot combine --squash with --no-ff."); +		option_commit = 0; +	} + +	if (!allow_fast_forward && fast_forward_only) +		die("You cannot combine --no-ff with --ff-only."); + +	if (!argc) +		usage_with_options(builtin_merge_usage, +			builtin_merge_options); + +	/* +	 * This could be traditional "merge <msg> HEAD <commit>..."  and +	 * the way we can tell it is to see if the second token is HEAD, +	 * but some people might have misused the interface and used a +	 * committish that is the same as HEAD there instead. +	 * Traditional format never would have "-m" so it is an +	 * additional safety measure to check for it. +	 */ + +	if (!have_message && is_old_style_invocation(argc, argv)) { +		strbuf_addstr(&merge_msg, argv[0]); +		head_arg = argv[1]; +		argv += 2; +		argc -= 2; +	} else if (head_invalid) { +		struct object *remote_head; +		/* +		 * If the merged head is a valid one there is no reason +		 * to forbid "git merge" into a branch yet to be born. +		 * We do the same for "git pull". +		 */ +		if (argc != 1) +			die("Can merge only exactly one commit into " +				"empty head"); +		if (squash) +			die("Squash commit into empty head not supported yet"); +		if (!allow_fast_forward) +			die("Non-fast-forward commit does not make sense into " +			    "an empty head"); +		remote_head = peel_to_type(argv[0], 0, NULL, OBJ_COMMIT); +		if (!remote_head) +			die("%s - not something we can merge", argv[0]); +		update_ref("initial pull", "HEAD", remote_head->sha1, NULL, 0, +				DIE_ON_ERR); +		reset_hard(remote_head->sha1, 0); +		return 0; +	} else { +		struct strbuf msg = STRBUF_INIT; + +		/* We are invoked directly as the first-class UI. */ +		head_arg = "HEAD"; + +		/* +		 * All the rest are the commits being merged; +		 * prepare the standard merge summary message to +		 * be appended to the given message.  If remote +		 * is invalid we will die later in the common +		 * codepath so we discard the error in this +		 * loop. +		 */ +		if (!have_message) { +			for (i = 0; i < argc; i++) +				merge_name(argv[i], &msg); +			fmt_merge_msg(option_log, &msg, &merge_msg); +			if (merge_msg.len) +				strbuf_setlen(&merge_msg, merge_msg.len-1); +		} +	} + +	if (head_invalid || !argc) +		usage_with_options(builtin_merge_usage, +			builtin_merge_options); + +	strbuf_addstr(&buf, "merge"); +	for (i = 0; i < argc; i++) +		strbuf_addf(&buf, " %s", argv[i]); +	setenv("GIT_REFLOG_ACTION", buf.buf, 0); +	strbuf_reset(&buf); + +	for (i = 0; i < argc; i++) { +		struct object *o; +		struct commit *commit; + +		o = peel_to_type(argv[i], 0, NULL, OBJ_COMMIT); +		if (!o) +			die("%s - not something we can merge", argv[i]); +		commit = lookup_commit(o->sha1); +		commit->util = (void *)argv[i]; +		remotes = &commit_list_insert(commit, remotes)->next; + +		strbuf_addf(&buf, "GITHEAD_%s", sha1_to_hex(o->sha1)); +		setenv(buf.buf, argv[i], 1); +		strbuf_reset(&buf); +	} + +	if (!use_strategies) { +		if (!remoteheads->next) +			add_strategies(pull_twohead, DEFAULT_TWOHEAD); +		else +			add_strategies(pull_octopus, DEFAULT_OCTOPUS); +	} + +	for (i = 0; i < use_strategies_nr; i++) { +		if (use_strategies[i]->attr & NO_FAST_FORWARD) +			allow_fast_forward = 0; +		if (use_strategies[i]->attr & NO_TRIVIAL) +			allow_trivial = 0; +	} + +	if (!remoteheads->next) +		common = get_merge_bases(lookup_commit(head), +				remoteheads->item, 1); +	else { +		struct commit_list *list = remoteheads; +		commit_list_insert(lookup_commit(head), &list); +		common = get_octopus_merge_bases(list); +		free(list); +	} + +	update_ref("updating ORIG_HEAD", "ORIG_HEAD", head, NULL, 0, +		DIE_ON_ERR); + +	if (!common) +		; /* No common ancestors found. We need a real merge. */ +	else if (!remoteheads->next && !common->next && +			common->item == remoteheads->item) { +		/* +		 * If head can reach all the merge then we are up to date. +		 * but first the most common case of merging one remote. +		 */ +		finish_up_to_date("Already up-to-date."); +		return 0; +	} else if (allow_fast_forward && !remoteheads->next && +			!common->next && +			!hashcmp(common->item->object.sha1, head)) { +		/* Again the most common case of merging one remote. */ +		struct strbuf msg = STRBUF_INIT; +		struct object *o; +		char hex[41]; + +		strcpy(hex, find_unique_abbrev(head, DEFAULT_ABBREV)); + +		if (verbosity >= 0) +			printf("Updating %s..%s\n", +				hex, +				find_unique_abbrev(remoteheads->item->object.sha1, +				DEFAULT_ABBREV)); +		strbuf_addstr(&msg, "Fast-forward"); +		if (have_message) +			strbuf_addstr(&msg, +				" (no commit created; -m option ignored)"); +		o = peel_to_type(sha1_to_hex(remoteheads->item->object.sha1), +			0, NULL, OBJ_COMMIT); +		if (!o) +			return 1; + +		if (checkout_fast_forward(head, remoteheads->item->object.sha1)) +			return 1; + +		finish(o->sha1, msg.buf); +		drop_save(); +		return 0; +	} else if (!remoteheads->next && common->next) +		; +		/* +		 * We are not doing octopus and not fast-forward.  Need +		 * a real merge. +		 */ +	else if (!remoteheads->next && !common->next && option_commit) { +		/* +		 * We are not doing octopus, not fast-forward, and have +		 * only one common. +		 */ +		refresh_cache(REFRESH_QUIET); +		if (allow_trivial && !fast_forward_only) { +			/* See if it is really trivial. */ +			git_committer_info(IDENT_ERROR_ON_NO_NAME); +			printf("Trying really trivial in-index merge...\n"); +			if (!read_tree_trivial(common->item->object.sha1, +					head, remoteheads->item->object.sha1)) +				return merge_trivial(); +			printf("Nope.\n"); +		} +	} else { +		/* +		 * An octopus.  If we can reach all the remote we are up +		 * to date. +		 */ +		int up_to_date = 1; +		struct commit_list *j; + +		for (j = remoteheads; j; j = j->next) { +			struct commit_list *common_one; + +			/* +			 * Here we *have* to calculate the individual +			 * merge_bases again, otherwise "git merge HEAD^ +			 * HEAD^^" would be missed. +			 */ +			common_one = get_merge_bases(lookup_commit(head), +				j->item, 1); +			if (hashcmp(common_one->item->object.sha1, +				j->item->object.sha1)) { +				up_to_date = 0; +				break; +			} +		} +		if (up_to_date) { +			finish_up_to_date("Already up-to-date. Yeeah!"); +			return 0; +		} +	} + +	if (fast_forward_only) +		die("Not possible to fast-forward, aborting."); + +	/* We are going to make a new commit. */ +	git_committer_info(IDENT_ERROR_ON_NO_NAME); + +	/* +	 * At this point, we need a real merge.  No matter what strategy +	 * we use, it would operate on the index, possibly affecting the +	 * working tree, and when resolved cleanly, have the desired +	 * tree in the index -- this means that the index must be in +	 * sync with the head commit.  The strategies are responsible +	 * to ensure this. +	 */ +	if (use_strategies_nr != 1) { +		/* +		 * Stash away the local changes so that we can try more +		 * than one. +		 */ +		save_state(); +	} else { +		memcpy(stash, null_sha1, 20); +	} + +	for (i = 0; i < use_strategies_nr; i++) { +		int ret; +		if (i) { +			printf("Rewinding the tree to pristine...\n"); +			restore_state(); +		} +		if (use_strategies_nr != 1) +			printf("Trying merge strategy %s...\n", +				use_strategies[i]->name); +		/* +		 * Remember which strategy left the state in the working +		 * tree. +		 */ +		wt_strategy = use_strategies[i]->name; + +		ret = try_merge_strategy(use_strategies[i]->name, +			common, head_arg); +		if (!option_commit && !ret) { +			merge_was_ok = 1; +			/* +			 * This is necessary here just to avoid writing +			 * the tree, but later we will *not* exit with +			 * status code 1 because merge_was_ok is set. +			 */ +			ret = 1; +		} + +		if (ret) { +			/* +			 * The backend exits with 1 when conflicts are +			 * left to be resolved, with 2 when it does not +			 * handle the given merge at all. +			 */ +			if (ret == 1) { +				int cnt = evaluate_result(); + +				if (best_cnt <= 0 || cnt <= best_cnt) { +					best_strategy = use_strategies[i]->name; +					best_cnt = cnt; +				} +			} +			if (merge_was_ok) +				break; +			else +				continue; +		} + +		/* Automerge succeeded. */ +		write_tree_trivial(result_tree); +		automerge_was_ok = 1; +		break; +	} + +	/* +	 * If we have a resulting tree, that means the strategy module +	 * auto resolved the merge cleanly. +	 */ +	if (automerge_was_ok) +		return finish_automerge(common, result_tree, wt_strategy); + +	/* +	 * Pick the result from the best strategy and have the user fix +	 * it up. +	 */ +	if (!best_strategy) { +		restore_state(); +		if (use_strategies_nr > 1) +			fprintf(stderr, +				"No merge strategy handled the merge.\n"); +		else +			fprintf(stderr, "Merge with strategy %s failed.\n", +				use_strategies[0]->name); +		return 2; +	} else if (best_strategy == wt_strategy) +		; /* We already have its result in the working tree. */ +	else { +		printf("Rewinding the tree to pristine...\n"); +		restore_state(); +		printf("Using the %s to prepare resolving by hand.\n", +			best_strategy); +		try_merge_strategy(best_strategy, common, head_arg); +	} + +	if (squash) +		finish(NULL, NULL); +	else { +		int fd; +		struct commit_list *j; + +		for (j = remoteheads; j; j = j->next) +			strbuf_addf(&buf, "%s\n", +				sha1_to_hex(j->item->object.sha1)); +		fd = open(git_path("MERGE_HEAD"), O_WRONLY | O_CREAT, 0666); +		if (fd < 0) +			die_errno("Could not open '%s' for writing", +				  git_path("MERGE_HEAD")); +		if (write_in_full(fd, buf.buf, buf.len) != buf.len) +			die_errno("Could not write to '%s'", git_path("MERGE_HEAD")); +		close(fd); +		strbuf_addch(&merge_msg, '\n'); +		fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666); +		if (fd < 0) +			die_errno("Could not open '%s' for writing", +				  git_path("MERGE_MSG")); +		if (write_in_full(fd, merge_msg.buf, merge_msg.len) != +			merge_msg.len) +			die_errno("Could not write to '%s'", git_path("MERGE_MSG")); +		close(fd); +		fd = open(git_path("MERGE_MODE"), O_WRONLY | O_CREAT | O_TRUNC, 0666); +		if (fd < 0) +			die_errno("Could not open '%s' for writing", +				  git_path("MERGE_MODE")); +		strbuf_reset(&buf); +		if (!allow_fast_forward) +			strbuf_addf(&buf, "no-ff"); +		if (write_in_full(fd, buf.buf, buf.len) != buf.len) +			die_errno("Could not write to '%s'", git_path("MERGE_MODE")); +		close(fd); +	} + +	if (merge_was_ok) { +		fprintf(stderr, "Automatic merge went well; " +			"stopped before committing as requested\n"); +		return 0; +	} else +		return suggest_conflicts(); +} | 
