{"thread":{"id":"14237","subject":"[PATCH 14/14] Build in merge","startedAt":"2008-07-01T02:22:36Z","lastAt":"2008-07-01T12:09:24Z","messageCount":5,"participants":["Miklos Vajna","Johannes Schindelin","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":14},"messages":[{"id":"81818","messageId":"666ec9b342a0c3254ae8f917d5bd2dea36314f08.1214878711.git.vmiklos@frugalware.org","threadId":"14237","inReplyTo":"20080701021317.GS4729@genesis.frugalware.org","subject":"[PATCH 13/14] git-commit-tree: make it usable from other builtins","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-01T02:22:36Z","receivedAt":"2008-07-01T02:22:36Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Move all functionality (except option parsing) from cmd_commit_tree() to\ncommit_tree(), so that other builtins can use it without a child\nprocess.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n\nThis patch is against master, you need to pull from me or first rebase\nmv/merge-in-c against current master.\n\nI did it this way to avoid an unnecessary conflict with Dscho's recent\npatch to commit-tree (ef98c5c).\n\n builtin-commit-tree.c |   71 ++++++++++++++++++++++++++++--------------------\n builtin.h             |    4 +++\n 2 files changed, 45 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin-commit-tree.c b/builtin-commit-tree.c\nindex 3881f6c..7a9a309 100644\n--- a/builtin-commit-tree.c\n+++ b/builtin-commit-tree.c\n@@ -45,41 +45,19 @@ static const char commit_utf8_warn[] =\n \"You may want to amend it after fixing the message, or set the config\\n\"\n \"variable i18n.commitencoding to the encoding your project uses.\\n\";\n \n-int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n+int commit_tree(const char *msg, unsigned char *tree,\n+\t\tstruct commit_list *parents, unsigned char *ret)\n {\n-\tint i;\n-\tstruct commit_list *parents = NULL;\n-\tunsigned char tree_sha1[20];\n-\tunsigned char commit_sha1[20];\n-\tstruct strbuf buffer;\n \tint encoding_is_utf8;\n+\tstruct strbuf buffer;\n \n-\tgit_config(git_default_config, NULL);\n-\n-\tif (argc < 2)\n-\t\tusage(commit_tree_usage);\n-\tif (get_sha1(argv[1], tree_sha1))\n-\t\tdie(\"Not a valid object name %s\", argv[1]);\n-\n-\tcheck_valid(tree_sha1, OBJ_TREE);\n-\tfor (i = 2; i < argc; i += 2) {\n-\t\tunsigned char sha1[20];\n-\t\tconst char *a, *b;\n-\t\ta = argv[i]; b = argv[i+1];\n-\t\tif (!b || strcmp(a, \"-p\"))\n-\t\t\tusage(commit_tree_usage);\n-\n-\t\tif (get_sha1(b, sha1))\n-\t\t\tdie(\"Not a valid object name %s\", b);\n-\t\tcheck_valid(sha1, OBJ_COMMIT);\n-\t\tnew_parent(lookup_commit(sha1), &parents);\n-\t}\n+\tcheck_valid(tree, OBJ_TREE);\n \n \t/* Not having i18n.commitencoding is the same as having utf-8 */\n \tencoding_is_utf8 = is_encoding_utf8(git_commit_encoding);\n \n \tstrbuf_init(&buffer, 8192); /* should avoid reallocs for the headers */\n-\tstrbuf_addf(&buffer, \"tree %s\\n\", sha1_to_hex(tree_sha1));\n+\tstrbuf_addf(&buffer, \"tree %s\\n\", sha1_to_hex(tree));\n \n \t/*\n \t * NOTE! This ordering means that the same exact tree merged with a\n@@ -102,14 +80,47 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n \tstrbuf_addch(&buffer, '\\n');\n \n \t/* And add the comment */\n-\tif (strbuf_read(&buffer, 0, 0) < 0)\n-\t\tdie(\"git-commit-tree: read returned %s\", strerror(errno));\n+\tstrbuf_addstr(&buffer, msg);\n \n \t/* And check the encoding */\n \tif (encoding_is_utf8 && !is_utf8(buffer.buf))\n \t\tfprintf(stderr, commit_utf8_warn);\n \n-\tif (!write_sha1_file(buffer.buf, buffer.len, commit_type, commit_sha1)) {\n+\treturn write_sha1_file(buffer.buf, buffer.len, commit_type, ret);\n+}\n+\n+int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n+{\n+\tint i;\n+\tstruct commit_list *parents = NULL;\n+\tunsigned char tree_sha1[20];\n+\tunsigned char commit_sha1[20];\n+\tstruct strbuf buffer = STRBUF_INIT;\n+\n+\tgit_config(git_default_config, NULL);\n+\n+\tif (argc < 2)\n+\t\tusage(commit_tree_usage);\n+\tif (get_sha1(argv[1], tree_sha1))\n+\t\tdie(\"Not a valid object name %s\", argv[1]);\n+\n+\tfor (i = 2; i < argc; i += 2) {\n+\t\tunsigned char sha1[20];\n+\t\tconst char *a, *b;\n+\t\ta = argv[i]; b = argv[i+1];\n+\t\tif (!b || strcmp(a, \"-p\"))\n+\t\t\tusage(commit_tree_usage);\n+\n+\t\tif (get_sha1(b, sha1))\n+\t\t\tdie(\"Not a valid object name %s\", b);\n+\t\tcheck_valid(sha1, OBJ_COMMIT);\n+\t\tnew_parent(lookup_commit(sha1), &parents);\n+\t}\n+\n+\tif (strbuf_read(&buffer, 0, 0) < 0)\n+\t\tdie(\"git-commit-tree: read returned %s\", strerror(errno));\n+\n+\tif (!commit_tree(buffer.buf, tree_sha1, parents, commit_sha1)) {\n \t\tprintf(\"%s\\n\", sha1_to_hex(commit_sha1));\n \t\treturn 0;\n \t}\ndiff --git a/builtin.h b/builtin.h\nindex 2b01fea..05ee56f 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -3,6 +3,8 @@\n \n #include \"git-compat-util.h\"\n #include \"strbuf.h\"\n+#include \"cache.h\"\n+#include \"commit.h\"\n \n extern const char git_version_string[];\n extern const char git_usage_string[];\n@@ -14,6 +16,8 @@ extern void prune_packed_objects(int);\n extern int read_line_with_nul(char *buf, int size, FILE *file);\n extern int fmt_merge_msg(int merge_summary, struct strbuf *in,\n \tstruct strbuf *out);\n+extern int commit_tree(const char *msg, unsigned char *tree,\n+\t\tstruct commit_list *parents, unsigned char *ret);\n \n extern int cmd_add(int argc, const char **argv, const char *prefix);\n extern int cmd_annotate(int argc, const char **argv, const char *prefix);\n-- \n1.5.6.1\n"},{"id":"81817","messageId":"0ed87f20b5fa79f4a16f23a522cfc7c52f77ce0e.1214878711.git.vmiklos@frugalware.org","threadId":"14237","inReplyTo":"666ec9b342a0c3254ae8f917d5bd2dea36314f08.1214878711.git.vmiklos@frugalware.org","subject":"[PATCH 14/14] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-01T02:22:37Z","receivedAt":"2008-07-01T02:22:37Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Mentored-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n\nInterdiff since the previous version:\n\n        git diff fab9109..b86e8ad\n\nIndividual commits:\n\n        git log b86e8ad\n\n Makefile                                      |    2 +-\n builtin-merge.c                               | 1148 +++++++++++++++++++++++++\n builtin.h                                     |    1 +\n git-merge.sh => contrib/examples/git-merge.sh |    0 \n git.c                                         |    1 +\n t/t7602-merge-octopus-many.sh                 |    2 +-\n 6 files changed, 1152 insertions(+), 2 deletions(-)\n create mode 100644 builtin-merge.c\n rename git-merge.sh => contrib/examples/git-merge.sh (100%)\n\ndiff --git a/Makefile b/Makefile\nindex bf77292..fbc53e9 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -240,7 +240,6 @@ SCRIPT_SH += git-lost-found.sh\n SCRIPT_SH += git-merge-octopus.sh\n SCRIPT_SH += git-merge-one-file.sh\n SCRIPT_SH += git-merge-resolve.sh\n-SCRIPT_SH += git-merge.sh\n SCRIPT_SH += git-merge-stupid.sh\n SCRIPT_SH += git-mergetool.sh\n SCRIPT_SH += git-parse-remote.sh\n@@ -515,6 +514,7 @@ BUILTIN_OBJS += builtin-ls-remote.o\n BUILTIN_OBJS += builtin-ls-tree.o\n BUILTIN_OBJS += builtin-mailinfo.o\n BUILTIN_OBJS += builtin-mailsplit.o\n+BUILTIN_OBJS += builtin-merge.o\n BUILTIN_OBJS += builtin-merge-base.o\n BUILTIN_OBJS += builtin-merge-file.o\n BUILTIN_OBJS += builtin-merge-ours.o\ndiff --git a/builtin-merge.c b/builtin-merge.c\nnew file mode 100644\nindex 0000000..bb8d985\n--- /dev/null\n+++ b/builtin-merge.c\n@@ -0,0 +1,1148 @@\n+/*\n+ * Builtin \"git merge\"\n+ *\n+ * Copyright (c) 2008 Miklos Vajna <vmiklos@frugalware.org>\n+ *\n+ * Based on git-merge.sh by Junio C Hamano.\n+ */\n+\n+#include \"cache.h\"\n+#include \"parse-options.h\"\n+#include \"builtin.h\"\n+#include \"run-command.h\"\n+#include \"path-list.h\"\n+#include \"diff.h\"\n+#include \"refs.h\"\n+#include \"commit.h\"\n+#include \"diffcore.h\"\n+#include \"revision.h\"\n+#include \"unpack-trees.h\"\n+#include \"cache-tree.h\"\n+#include \"dir.h\"\n+#include \"utf8.h\"\n+#include \"log-tree.h\"\n+#include \"color.h\"\n+\n+enum strategy {\n+\tDEFAULT_TWOHEAD = 1,\n+\tDEFAULT_OCTOPUS = 2,\n+\tNO_FAST_FORWARD = 4,\n+\tNO_TRIVIAL = 8\n+};\n+\n+static const char * const builtin_merge_usage[] = {\n+\t\"git-merge [options] <remote>...\",\n+\t\"git-merge [options] <msg> HEAD <remote>\",\n+\tNULL\n+};\n+\n+static int show_diffstat = 1, option_log, squash;\n+static int option_commit = 1, allow_fast_forward = 1;\n+static int allow_trivial = 1, have_message;\n+static struct strbuf merge_msg;\n+static struct commit_list *remoteheads;\n+static unsigned char head[20], stash[20];\n+static struct path_list use_strategies;\n+static const char *branch;\n+\n+static struct path_list_item strategy_items[] = {\n+\t{ \"recur\",      (void *)NO_TRIVIAL },\n+\t{ \"recursive\",  (void *)(DEFAULT_TWOHEAD | NO_TRIVIAL) },\n+\t{ \"octopus\",    (void *)DEFAULT_OCTOPUS },\n+\t{ \"resolve\",    (void *)0 },\n+\t{ \"stupid\",     (void *)0 },\n+\t{ \"ours\",       (void *)(NO_FAST_FORWARD | NO_TRIVIAL) },\n+\t{ \"subtree\",    (void *)(NO_FAST_FORWARD | NO_TRIVIAL) },\n+};\n+static struct path_list strategies = { strategy_items,\n+\tARRAY_SIZE(strategy_items), 0, 0 };\n+\n+static const char *pull_twohead, *pull_octopus;\n+\n+static int option_parse_message(const struct option *opt,\n+\tconst char *arg, int unset)\n+{\n+\tstruct strbuf *buf = opt->value;\n+\n+\tif (unset)\n+\t\tstrbuf_setlen(buf, 0);\n+\telse {\n+\t\tstrbuf_addf(buf, \"%s\\n\\n\", arg);\n+\t\thave_message = 1;\n+\t}\n+\treturn 0;\n+}\n+\n+static struct path_list_item *unsorted_path_list_lookup(const char *path,\n+\tstruct path_list *list)\n+{\n+\tint i;\n+\n+\tif (!path)\n+\t\treturn NULL;\n+\n+\tfor (i = 0; i < list->nr; i++)\n+\t\tif (!strcmp(path, list->items[i].path))\n+\t\t\treturn &list->items[i];\n+\treturn NULL;\n+}\n+\n+static inline void path_list_append_strategy(struct path_list_item *item)\n+{\n+\tpath_list_append(item->path, &use_strategies)->util = item->util;\n+}\n+\n+static int option_parse_strategy(const struct option *opt,\n+\tconst char *arg, int unset)\n+{\n+\tint i;\n+\tstruct path_list_item *item = unsorted_path_list_lookup(arg, &strategies);\n+\n+\tif (unset)\n+\t\treturn 0;\n+\n+\tif (item)\n+\t\tpath_list_append_strategy(item);\n+\telse {\n+\t\tstruct strbuf err;\n+\t\tstrbuf_init(&err, 0);\n+\t\tfor (i = 0; i < strategies.nr; i++)\n+\t\t\tstrbuf_addf(&err, \" %s\", strategies.items[i].path);\n+\t\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\", arg);\n+\t\tfprintf(stderr, \"Available strategies are:%s.\\n\", err.buf);\n+\t\texit(1);\n+\t}\n+\treturn 0;\n+}\n+\n+static int option_parse_n(const struct option *opt,\n+\t\tconst char *arg, int unset)\n+{\n+\tshow_diffstat = unset;\n+\treturn 0;\n+}\n+\n+static struct option builtin_merge_options[] = {\n+\t{ OPTION_CALLBACK, 'n', NULL, NULL, NULL,\n+\t\t\"do not show a diffstat at the end of the merge\",\n+\t\tPARSE_OPT_NOARG, option_parse_n },\n+\tOPT_BOOLEAN(0, \"stat\", &show_diffstat,\n+\t\t\"show a diffstat at the end of the merge\"),\n+\tOPT_BOOLEAN(0, \"summary\", &show_diffstat, \"(synonym to --stat)\"),\n+\tOPT_BOOLEAN(0, \"log\", &option_log,\n+\t\t\"add list of one-line log to merge commit message\"),\n+\tOPT_BOOLEAN(0, \"squash\", &squash,\n+\t\t\"create a single commit instead of doing a merge\"),\n+\tOPT_BOOLEAN(0, \"commit\", &option_commit,\n+\t\t\"perform a commit if the merge succeeds (default)\"),\n+\tOPT_BOOLEAN(0, \"ff\", &allow_fast_forward,\n+\t\t\"allow fast forward (default)\"),\n+\tOPT_CALLBACK('s', \"strategy\", &use_strategies, \"strategy\",\n+\t\t\"merge strategy to use\", option_parse_strategy),\n+\tOPT_CALLBACK('m', \"message\", &merge_msg, \"message\",\n+\t\t\"message to be used for the merge commit (if any)\",\n+\t\toption_parse_message),\n+\tOPT_END()\n+};\n+\n+/* Cleans up metadata that is uninteresting after a succeeded merge. */\n+static void drop_save(void)\n+{\n+\tunlink(git_path(\"MERGE_HEAD\"));\n+\tunlink(git_path(\"MERGE_MSG\"));\n+}\n+\n+static void save_state(void)\n+{\n+\tint len;\n+\tstruct child_process cp;\n+\tstruct strbuf buffer = STRBUF_INIT;\n+\tconst char *argv[] = {\"stash\", \"create\", NULL};\n+\n+\tmemset(&cp, 0, sizeof(cp));\n+\tcp.argv = argv;\n+\tcp.out = -1;\n+\tcp.git_cmd = 1;\n+\n+\tif (start_command(&cp))\n+\t\tdie(\"could not run stash.\");\n+\tlen = strbuf_read(&buffer, cp.out, 1024);\n+\tclose(cp.out);\n+\n+\tif (finish_command(&cp) || len < 0)\n+\t\tdie(\"stash failed\");\n+\telse if (!len)\n+\t\treturn;\n+\tstrbuf_setlen(&buffer, buffer.len-1);\n+\tif (get_sha1(buffer.buf, stash))\n+\t\tdie(\"not a valid object: %s\", buffer.buf);\n+}\n+\n+static void reset_hard(unsigned const char *sha1, int verbose)\n+{\n+\tint i = 0;\n+\tconst char *args[6];\n+\n+\targs[i++] = \"read-tree\";\n+\tif (verbose)\n+\t\targs[i++] = \"-v\";\n+\targs[i++] = \"--reset\";\n+\targs[i++] = \"-u\";\n+\targs[i++] = sha1_to_hex(sha1);\n+\targs[i] = NULL;\n+\n+\tif (run_command_v_opt(args, RUN_GIT_CMD))\n+\t\tdie(\"read-tree failed\");\n+}\n+\n+static void restore_state(void)\n+{\n+\tstruct strbuf sb;\n+\tconst char *args[] = { \"stash\", \"apply\", NULL, NULL };\n+\n+\tif (is_null_sha1(stash))\n+\t\treturn;\n+\n+\treset_hard(head, 1);\n+\n+\tstrbuf_init(&sb, 0);\n+\targs[2] = sha1_to_hex(stash);\n+\n+\t/*\n+\t * It is OK to ignore error here, for example when there was\n+\t * nothing to restore.\n+\t */\n+\trun_command_v_opt(args, RUN_GIT_CMD);\n+\n+\tstrbuf_release(&sb);\n+\trefresh_cache(REFRESH_QUIET);\n+}\n+\n+/* This is called when no merge was necessary. */\n+static void finish_up_to_date(const char *msg)\n+{\n+\tprintf(\"%s%s\\n\", squash ? \" (nothing to squash)\" : \"\", msg);\n+\tdrop_save();\n+}\n+\n+static void squash_message(void)\n+{\n+\tstruct rev_info rev;\n+\tstruct commit *commit;\n+\tstruct strbuf out;\n+\tstruct commit_list *j;\n+\tint fd;\n+\n+\tprintf(\"Squash commit -- not updating HEAD\\n\");\n+\tfd = open(git_path(\"SQUASH_MSG\"), O_WRONLY | O_CREAT, 0666);\n+\tif (fd < 0)\n+\t\tdie(\"Could not write to %s\", git_path(\"SQUASH_MSG\"));\n+\n+\tinit_revisions(&rev, NULL);\n+\trev.ignore_merges = 1;\n+\trev.commit_format = CMIT_FMT_MEDIUM;\n+\n+\tcommit = lookup_commit(head);\n+\tcommit->object.flags |= UNINTERESTING;\n+\tadd_pending_object(&rev, &commit->object, NULL);\n+\n+\tfor (j = remoteheads; j; j = j->next)\n+\t\tadd_pending_object(&rev, &j->item->object, NULL);\n+\n+\tsetup_revisions(0, NULL, &rev, NULL);\n+\tif (prepare_revision_walk(&rev))\n+\t\tdie(\"revision walk setup failed\");\n+\n+\tstrbuf_init(&out, 0);\n+\tstrbuf_addstr(&out, \"Squashed commit of the following:\\n\");\n+\twhile ((commit = get_revision(&rev)) != NULL) {\n+\t\tstrbuf_addch(&out, '\\n');\n+\t\tstrbuf_addf(&out, \"commit %s\\n\",\n+\t\t\tsha1_to_hex(commit->object.sha1));\n+\t\tpretty_print_commit(rev.commit_format, commit, &out, rev.abbrev,\n+\t\t\tNULL, NULL, rev.date_mode, 0);\n+\t}\n+\twrite(fd, out.buf, out.len);\n+\tclose(fd);\n+\tstrbuf_release(&out);\n+}\n+\n+static int run_hook(const char *name)\n+{\n+\tstruct child_process hook;\n+\tconst char *argv[3], *env[2];\n+\tchar index[PATH_MAX];\n+\n+\targv[0] = git_path(\"hooks/%s\", name);\n+\tif (access(argv[0], X_OK) < 0)\n+\t\treturn 0;\n+\n+\tsnprintf(index, sizeof(index), \"GIT_INDEX_FILE=%s\", get_index_file());\n+\tenv[0] = index;\n+\tenv[1] = NULL;\n+\n+\tif (squash)\n+\t\targv[1] = \"1\";\n+\telse\n+\t\targv[1] = \"0\";\n+\targv[2] = NULL;\n+\n+\tmemset(&hook, 0, sizeof(hook));\n+\thook.argv = argv;\n+\thook.no_stdin = 1;\n+\thook.stdout_to_stderr = 1;\n+\thook.env = env;\n+\n+\treturn run_command(&hook);\n+}\n+\n+static void finish(const unsigned char *new_head, const char *msg)\n+{\n+\tstruct strbuf reflog_message;\n+\n+\tstrbuf_init(&reflog_message, 0);\n+\tif (!msg)\n+\t\tstrbuf_addstr(&reflog_message, getenv(\"GIT_REFLOG_ACTION\"));\n+\telse {\n+\t\tprintf(\"%s\\n\", msg);\n+\t\tstrbuf_addf(&reflog_message, \"%s: %s\",\n+\t\t\tgetenv(\"GIT_REFLOG_ACTION\"), msg);\n+\t}\n+\tif (squash) {\n+\t\tsquash_message();\n+\t} else {\n+\t\tif (!merge_msg.len)\n+\t\t\tprintf(\"No merge message -- not updating HEAD\\n\");\n+\t\telse {\n+\t\t\tconst char *argv_gc_auto[] = { \"gc\", \"--auto\", NULL };\n+\t\t\tupdate_ref(reflog_message.buf, \"HEAD\",\n+\t\t\t\tnew_head, head, 0,\n+\t\t\t\tDIE_ON_ERR);\n+\t\t\t/*\n+\t\t\t * We ignore errors in 'gc --auto', since the\n+\t\t\t * user should see them.\n+\t\t\t */\n+\t\t\trun_command_v_opt(argv_gc_auto, RUN_GIT_CMD);\n+\t\t}\n+\t}\n+\tif (new_head && show_diffstat) {\n+\t\tstruct diff_options opts;\n+\t\tdiff_setup(&opts);\n+\t\topts.output_format |=\n+\t\t\tDIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;\n+\t\topts.detect_rename = DIFF_DETECT_RENAME;\n+\t\tif (diff_use_color_default > 0)\n+\t\t\tDIFF_OPT_SET(&opts, COLOR_DIFF);\n+\t\tif (diff_setup_done(&opts) < 0)\n+\t\t\tdie(\"diff_setup_done failed\");\n+\t\tdiff_tree_sha1(head, new_head, \"\", &opts);\n+\t\tdiffcore_std(&opts);\n+\t\tdiff_flush(&opts);\n+\t}\n+\n+\t/* Run a post-merge hook */\n+\trun_hook(\"post-merge\");\n+\n+\tstrbuf_release(&reflog_message);\n+}\n+\n+/* Get the name for the merge commit's message. */\n+static void merge_name(const char *remote, struct strbuf *msg)\n+{\n+\tstruct object *remote_head;\n+\tunsigned char branch_head[20], buf_sha[20];\n+\tstruct strbuf buf;\n+\tconst char *ptr;\n+\tint len = 0;\n+\n+\tmemset(branch_head, 0, sizeof(branch_head));\n+\tremote_head = peel_to_type(remote, 0, NULL, OBJ_COMMIT);\n+\tif (!remote_head)\n+\t\tdie(\"'%s' does not point to a commit\", remote);\n+\n+\tstrbuf_init(&buf, 0);\n+\tstrbuf_addstr(&buf, \"refs/heads/\");\n+\tstrbuf_addstr(&buf, remote);\n+\tresolve_ref(buf.buf, branch_head, 0, 0);\n+\n+\tif (!hashcmp(remote_head->sha1, branch_head)) {\n+\t\tstrbuf_addf(msg, \"%s\\t\\tbranch '%s' of .\\n\",\n+\t\t\tsha1_to_hex(branch_head), remote);\n+\t\treturn;\n+\t}\n+\t/* See if remote matches <name>~<number>, or <name>^ */\n+\tptr = strrchr(remote, '^');\n+\tif (ptr && ptr[1] == '\\0') {\n+\t\tfor (len = 0, ptr = remote + strlen(remote);\n+\t\t\t\tremote < ptr && ptr[-1] == '^';\n+\t\t\t\tptr--)\n+\t\t\tlen++;\n+\t}\n+\telse {\n+\t\tptr = strrchr(remote, '~');\n+\t\tif (ptr && ptr[1] != '0' && isdigit(ptr[1])) {\n+\t\t\tlen = ptr-remote;\n+\t\t\tptr++;\n+\t\t\tfor (ptr++; *ptr; ptr++)\n+\t\t\t\tif (!isdigit(*ptr)) {\n+\t\t\t\t\tlen = 0;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t}\n+\t}\n+\tif (len) {\n+\t\tstruct strbuf truname = STRBUF_INIT;\n+\t\tstrbuf_addstr(&truname, \"refs/heads/\");\n+\t\tstrbuf_addstr(&truname, remote);\n+\t\tstrbuf_setlen(&truname, len+11);\n+\t\tif (resolve_ref(truname.buf, buf_sha, 0, 0)) {\n+\t\t\tstrbuf_addf(msg,\n+\t\t\t\t\"%s\\t\\tbranch '%s' (early part) of .\\n\",\n+\t\t\t\tsha1_to_hex(remote_head->sha1), truname.buf);\n+\t\t\treturn;\n+\t\t}\n+\t}\n+\n+\tif (!strcmp(remote, \"FETCH_HEAD\") &&\n+\t\t\t!access(git_path(\"FETCH_HEAD\"), R_OK)) {\n+\t\tFILE *fp;\n+\t\tstruct strbuf line;\n+\t\tchar *ptr;\n+\n+\t\tstrbuf_init(&line, 0);\n+\t\tfp = fopen(git_path(\"FETCH_HEAD\"), \"r\");\n+\t\tif (!fp)\n+\t\t\tdie(\"could not open %s for reading: %s\",\n+\t\t\t\tgit_path(\"FETCH_HEAD\"), strerror(errno));\n+\t\tstrbuf_getline(&line, fp, '\\n');\n+\t\tfclose(fp);\n+\t\tptr = strstr(line.buf, \"\\tnot-for-merge\\t\");\n+\t\tif (ptr)\n+\t\t\tstrbuf_remove(&line, ptr-line.buf+1, 13);\n+\t\tstrbuf_addbuf(msg, &line);\n+\t\tstrbuf_release(&line);\n+\t\treturn;\n+\t}\n+\tstrbuf_addf(msg, \"%s\\t\\tcommit '%s'\\n\",\n+\t\tsha1_to_hex(remote_head->sha1), remote);\n+}\n+\n+int git_merge_config(const char *k, const char *v, void *cb)\n+{\n+\tif (branch && !prefixcmp(k, \"branch.\") &&\n+\t\t!prefixcmp(k + 7, branch) &&\n+\t\t!strcmp(k + 7 + strlen(branch), \".mergeoptions\")) {\n+\t\tconst char **argv;\n+\t\tint argc;\n+\t\tchar *buf;\n+\n+\t\tbuf = xstrdup(v);\n+\t\targc = split_cmdline(buf, &argv);\n+\t\targv = xrealloc(argv, sizeof(*argv) * (argc + 2));\n+\t\tmemmove(argv + 1, argv, sizeof(*argv) * (argc + 1));\n+\t\targc++;\n+\t\tparse_options(argc, argv, builtin_merge_options,\n+\t\t\t      builtin_merge_usage, 0);\n+\t\tfree(buf);\n+\t}\n+\n+\tif (!strcmp(k, \"merge.diffstat\") || !strcmp(k, \"merge.stat\"))\n+\t\tshow_diffstat = git_config_bool(k, v);\n+\telse if (!strcmp(k, \"pull.twohead\"))\n+\t\treturn git_config_string(&pull_twohead, k, v);\n+\telse if (!strcmp(k, \"pull.octopus\"))\n+\t\treturn git_config_string(&pull_octopus, k, v);\n+\treturn git_diff_ui_config(k, v, cb);\n+}\n+\n+static int read_tree_trivial(unsigned char *common, unsigned char *head,\n+\tunsigned char *one)\n+{\n+\tint i, nr_trees = 0;\n+\tstruct tree *trees[MAX_UNPACK_TREES];\n+\tstruct tree_desc t[MAX_UNPACK_TREES];\n+\tstruct unpack_trees_options opts;\n+\n+\tmemset(&opts, 0, sizeof(opts));\n+\topts.head_idx = 2;\n+\topts.src_index = &the_index;\n+\topts.dst_index = &the_index;\n+\topts.update = 1;\n+\topts.verbose_update = 1;\n+\topts.trivial_merges_only = 1;\n+\topts.merge = 1;\n+\ttrees[nr_trees] = parse_tree_indirect(common);\n+\tif (!trees[nr_trees++])\n+\t\treturn -1;\n+\ttrees[nr_trees] = parse_tree_indirect(head);\n+\tif (!trees[nr_trees++])\n+\t\treturn -1;\n+\ttrees[nr_trees] = parse_tree_indirect(one);\n+\tif (!trees[nr_trees++])\n+\t\treturn -1;\n+\topts.fn = threeway_merge;\n+\tcache_tree_free(&active_cache_tree);\n+\topts.head_idx = 2;\n+\tfor (i = 0; i < nr_trees; i++) {\n+\t\tparse_tree(trees[i]);\n+\t\tinit_tree_desc(t+i, trees[i]->buffer, trees[i]->size);\n+\t}\n+\tif (unpack_trees(nr_trees, t, &opts))\n+\t\treturn -1;\n+\treturn 0;\n+}\n+\n+static void write_tree_trivial(unsigned char *sha1)\n+{\n+\tif (write_cache_as_tree(sha1, 0, NULL))\n+\t\tdie(\"git write-tree failed to write a tree\");\n+}\n+\n+static int try_merge_strategy(char *strategy, struct commit_list *common,\n+\tconst char *head_arg)\n+{\n+\tconst char **args;\n+\tint i = 0, ret;\n+\tstruct commit_list *j;\n+\tstruct strbuf buf;\n+\n+\targs = xmalloc((4 + commit_list_count(common) +\n+\t\t\tcommit_list_count(remoteheads)) * sizeof(char *));\n+\tstrbuf_init(&buf, 0);\n+\tstrbuf_addf(&buf, \"merge-%s\", strategy);\n+\targs[i++] = buf.buf;\n+\tfor (j = common; j; j = j->next)\n+\t\targs[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));\n+\targs[i++] = \"--\";\n+\targs[i++] = head_arg;\n+\tfor (j = remoteheads; j; j = j->next)\n+\t\targs[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));\n+\targs[i] = NULL;\n+\tret = run_command_v_opt(args, RUN_GIT_CMD);\n+\tstrbuf_release(&buf);\n+\ti = 1;\n+\tfor (j = common; j; j = j->next)\n+\t\tfree((void *)args[i++]);\n+\ti += 2;\n+\tfor (j = remoteheads; j; j = j->next)\n+\t\tfree((void *)args[i++]);\n+\tfree(args);\n+\treturn -ret;\n+}\n+\n+static void count_diff_files(struct diff_queue_struct *q,\n+\t\tstruct diff_options *opt, void *data)\n+{\n+\tint *count = data;\n+\n+\t(*count) += q->nr;\n+}\n+\n+static int count_unmerged_entries(void)\n+{\n+\tconst struct index_state *state = &the_index;\n+\tint i, ret = 0;\n+\n+\tfor (i = 0; i < state->cache_nr; i++)\n+\t\tif (ce_stage(state->cache[i]))\n+\t\t\tret++;\n+\n+\treturn ret;\n+}\n+\n+static int checkout_fast_forward(unsigned char *head, unsigned char *remote)\n+{\n+\tstruct tree *trees[MAX_UNPACK_TREES];\n+\tstruct unpack_trees_options opts;\n+\tstruct tree_desc t[MAX_UNPACK_TREES];\n+\tint i, fd, nr_trees = 0;\n+\tstruct dir_struct dir;\n+\tstruct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));\n+\n+\tif (read_cache_unmerged())\n+\t\tdie(\"you need to resolve your current index first\");\n+\n+\tfd = hold_locked_index(lock_file, 1);\n+\n+\tmemset(&trees, 0, sizeof(trees));\n+\tmemset(&opts, 0, sizeof(opts));\n+\tmemset(&t, 0, sizeof(t));\n+\tdir.show_ignored = 1;\n+\tdir.exclude_per_dir = \".gitignore\";\n+\topts.dir = &dir;\n+\n+\topts.head_idx = 1;\n+\topts.src_index = &the_index;\n+\topts.dst_index = &the_index;\n+\topts.update = 1;\n+\topts.verbose_update = 1;\n+\topts.merge = 1;\n+\topts.fn = twoway_merge;\n+\n+\ttrees[nr_trees] = parse_tree_indirect(head);\n+\tif (!trees[nr_trees++])\n+\t\treturn -1;\n+\ttrees[nr_trees] = parse_tree_indirect(remote);\n+\tif (!trees[nr_trees++])\n+\t\treturn -1;\n+\tfor (i = 0; i < nr_trees; i++) {\n+\t\tparse_tree(trees[i]);\n+\t\tinit_tree_desc(t+i, trees[i]->buffer, trees[i]->size);\n+\t}\n+\tif (unpack_trees(nr_trees, t, &opts))\n+\t\treturn -1;\n+\tif (write_cache(fd, active_cache, active_nr) ||\n+\t\tcommit_locked_index(lock_file))\n+\t\tdie(\"unable to write new index file\");\n+\treturn 0;\n+}\n+\n+static void split_merge_strategies(const char *string, struct path_list *list)\n+{\n+\tchar *p, *q, *buf;\n+\n+\tif (!string)\n+\t\treturn;\n+\n+\tlist->strdup_paths = 1;\n+\tbuf = xstrdup(string);\n+\tq = buf;\n+\tfor (;;) {\n+\t\tp = strchr(q, ' ');\n+\t\tif (!p) {\n+\t\t\tpath_list_append(q, list);\n+\t\t\tfree(buf);\n+\t\t\treturn;\n+\t\t} else {\n+\t\t\t*p = '\\0';\n+\t\t\tpath_list_append(q, list);\n+\t\t\tq = ++p;\n+\t\t}\n+\t}\n+}\n+\n+static void add_strategies(const char *string, enum strategy strategy)\n+{\n+\tstruct path_list list;\n+\tint i;\n+\n+\tmemset(&list, 0, sizeof(list));\n+\tsplit_merge_strategies(string, &list);\n+\tif (list.nr) {\n+\t\tfor (i = 0; i < list.nr; i++) {\n+\t\t\tstruct path_list_item *item;\n+\n+\t\t\titem = unsorted_path_list_lookup(list.items[i].path,\n+\t\t\t\t&strategies);\n+\t\t\tif (item)\n+\t\t\t\tpath_list_append_strategy(item);\n+\t\t}\n+\t\treturn;\n+\t}\n+\tfor (i = 0; i < strategies.nr; i++)\n+\t\tif ((enum strategy)strategies.items[i].util & strategy)\n+\t\t\tpath_list_append_strategy(&strategies.items[i]);\n+}\n+\n+static int merge_trivial(void)\n+{\n+\tunsigned char result_tree[20], result_commit[20];\n+\tstruct commit_list parent;\n+\n+\twrite_tree_trivial(result_tree);\n+\tprintf(\"Wonderful.\\n\");\n+\tparent.item = remoteheads->item;\n+\tparent.next = NULL;\n+\tcommit_tree(merge_msg.buf, result_tree, &parent, result_commit);\n+\tfinish(result_commit, \"In-index merge\");\n+\tdrop_save();\n+\treturn 0;\n+}\n+\n+static int finish_automerge(struct commit_list *common,\n+\tunsigned char *result_tree,\n+\tstruct path_list_item *wt_strategy)\n+{\n+\tstruct commit_list *parents = NULL, *j;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tunsigned char result_commit[20];\n+\n+\tfree_commit_list(common);\n+\tif (allow_fast_forward) {\n+\t\tparents = remoteheads;\n+\t\tcommit_list_insert(lookup_commit(head), &parents);\n+\t\tparents = reduce_heads(parents);\n+\t} else {\n+\t\tstruct commit_list **pptr = &parents;\n+\n+\t\tpptr = &commit_list_insert(lookup_commit(head),\n+\t\t\t\tpptr)->next;\n+\t\tfor (j = remoteheads; j; j = j->next)\n+\t\t\tpptr = &commit_list_insert(j->item, pptr)->next;\n+\t}\n+\tfree_commit_list(remoteheads);\n+\tstrbuf_addch(&merge_msg, '\\n');\n+\tcommit_tree(merge_msg.buf, result_tree, parents, result_commit);\n+\tstrbuf_addf(&buf, \"Merge made by %s.\", wt_strategy->path);\n+\tfinish(result_commit, buf.buf);\n+\tstrbuf_release(&buf);\n+\tdrop_save();\n+\treturn 0;\n+}\n+\n+static int suggest_conflicts(void)\n+{\n+\tFILE *fp;\n+\tint pos;\n+\n+\tfp = fopen(git_path(\"MERGE_MSG\"), \"a\");\n+\tif (!fp)\n+\t\tdie(\"Could open %s for writing\", git_path(\"MERGE_MSG\"));\n+\tfprintf(fp, \"\\nConflicts:\\n\");\n+\tfor (pos = 0; pos < active_nr; pos++) {\n+\t\tstruct cache_entry *ce = active_cache[pos];\n+\n+\t\tif (ce_stage(ce)) {\n+\t\t\tfprintf(fp, \"\\t%s\\n\", ce->name);\n+\t\t\twhile (pos + 1 < active_nr &&\n+\t\t\t\t\t!strcmp(ce->name,\n+\t\t\t\t\t\tactive_cache[pos + 1]->name))\n+\t\t\t\tpos++;\n+\t\t}\n+\t}\n+\tfclose(fp);\n+\trerere();\n+\tprintf(\"Automatic merge failed; \"\n+\t\t\t\"fix conflicts and then commit the result.\\n\");\n+\treturn 1;\n+}\n+\n+static inline unsigned nth_strategy_flags(struct path_list *s, int nth)\n+{\n+\treturn (unsigned) s->items[nth].util;\n+}\n+\n+static struct commit *is_old_style_invocation(int argc, const char **argv)\n+{\n+\tstruct commit *second_token = NULL;\n+\tif (argc > 1) {\n+\t\tunsigned char second_sha1[20];\n+\n+\t\tif (get_sha1(argv[1], second_sha1))\n+\t\t\treturn NULL;\n+\t\tsecond_token = lookup_commit_reference_gently(second_sha1, 0);\n+\t\tif (!second_token)\n+\t\t\tdie(\"'%s' is not a commit\", argv[1]);\n+\t\tif (hashcmp(second_token->object.sha1, head))\n+\t\t\treturn NULL;\n+\t}\n+\treturn second_token;\n+}\n+\n+static int evaluate_result(void)\n+{\n+\tint cnt = 0;\n+\tstruct rev_info rev;\n+\n+\tif (read_cache() < 0)\n+\t\tdie(\"failed to read the cache\");\n+\n+\t/* Check how many files differ. */\n+\tinit_revisions(&rev, \"\");\n+\tsetup_revisions(0, NULL, &rev, NULL);\n+\trev.diffopt.output_format |=\n+\t\tDIFF_FORMAT_CALLBACK;\n+\trev.diffopt.format_callback = count_diff_files;\n+\trev.diffopt.format_callback_data = &cnt;\n+\trun_diff_files(&rev, 0);\n+\n+\t/*\n+\t * Check how many unmerged entries are\n+\t * there.\n+\t */\n+\tcnt += count_unmerged_entries();\n+\n+\treturn cnt;\n+}\n+\n+int cmd_merge(int argc, const char **argv, const char *prefix)\n+{\n+\tunsigned char result_tree[20];\n+\tstruct strbuf buf;\n+\tconst char *head_arg;\n+\tint flag, head_invalid = 0, i;\n+\tint best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;\n+\tstruct commit_list *common = NULL;\n+\tstruct path_list_item *best_strategy = NULL, *wt_strategy = NULL;\n+\tstruct commit_list **remotes = &remoteheads;\n+\n+\tsetup_work_tree();\n+\tif (unmerged_cache())\n+\t\tdie(\"You are in the middle of a conflicted merge.\");\n+\n+\t/*\n+\t * Check if we are _not_ on a detached HEAD, i.e. if there is a\n+\t * current branch.\n+\t */\n+\tbranch = resolve_ref(\"HEAD\", head, 0, &flag);\n+\tif (branch && flag & REF_ISSYMREF) {\n+\t\tconst char *ptr = skip_prefix(branch, \"refs/heads/\");\n+\t\tif (ptr)\n+\t\t\tbranch = ptr;\n+\t} else\n+\t\thead_invalid = 1;\n+\n+\tgit_config(git_merge_config, NULL);\n+\n+\t/* for color.ui */\n+\tif (diff_use_color_default == -1)\n+\t\tdiff_use_color_default = git_use_color_default;\n+\n+\targc = parse_options(argc, argv, builtin_merge_options,\n+\t\t\tbuiltin_merge_usage, 0);\n+\n+\tif (squash) {\n+\t\tif (!allow_fast_forward)\n+\t\t\tdie(\"You cannot combine --squash with --no-ff.\");\n+\t\toption_commit = 0;\n+\t}\n+\n+\tif (!argc)\n+\t\tusage_with_options(builtin_merge_usage,\n+\t\t\tbuiltin_merge_options);\n+\n+\t/*\n+\t * This could be traditional \"merge <msg> HEAD <commit>...\"  and\n+\t * the way we can tell it is to see if the second token is HEAD,\n+\t * but some people might have misused the interface and used a\n+\t * committish that is the same as HEAD there instead.\n+\t * Traditional format never would have \"-m\" so it is an\n+\t * additional safety measure to check for it.\n+\t */\n+\tstrbuf_init(&buf, 0);\n+\n+\tif (!have_message && is_old_style_invocation(argc, argv)) {\n+\t\tstrbuf_addstr(&merge_msg, argv[0]);\n+\t\thead_arg = argv[1];\n+\t\targv += 2;\n+\t\targc -= 2;\n+\t} else if (head_invalid) {\n+\t\tstruct object *remote_head;\n+\t\t/*\n+\t\t * If the merged head is a valid one there is no reason\n+\t\t * to forbid \"git merge\" into a branch yet to be born.\n+\t\t * We do the same for \"git pull\".\n+\t\t */\n+\t\tif (argc != 1)\n+\t\t\tdie(\"Can merge only exactly one commit into \"\n+\t\t\t\t\"empty head\");\n+\t\tremote_head = peel_to_type(argv[0], 0, NULL, OBJ_COMMIT);\n+\t\tif (!remote_head)\n+\t\t\tdie(\"%s - not something we can merge\", argv[0]);\n+\t\tupdate_ref(\"initial pull\", \"HEAD\", remote_head->sha1, NULL, 0,\n+\t\t\t\tDIE_ON_ERR);\n+\t\treset_hard(remote_head->sha1, 0);\n+\t\treturn 0;\n+\t} else {\n+\t\tstruct strbuf msg;\n+\n+\t\t/* We are invoked directly as the first-class UI. */\n+\t\thead_arg = \"HEAD\";\n+\n+\t\t/*\n+\t\t * All the rest are the commits being merged;\n+\t\t * prepare the standard merge summary message to\n+\t\t * be appended to the given message.  If remote\n+\t\t * is invalid we will die later in the common\n+\t\t * codepath so we discard the error in this\n+\t\t * loop.\n+\t\t */\n+\t\tstrbuf_init(&msg, 0);\n+\t\tfor (i = 0; i < argc; i++)\n+\t\t\tmerge_name(argv[i], &msg);\n+\t\tfmt_merge_msg(option_log, &msg, &merge_msg);\n+\t\tif (merge_msg.len)\n+\t\t\tstrbuf_setlen(&merge_msg, merge_msg.len-1);\n+\t}\n+\n+\tif (head_invalid || !argc)\n+\t\tusage_with_options(builtin_merge_usage,\n+\t\t\tbuiltin_merge_options);\n+\n+\tstrbuf_addstr(&buf, \"merge\");\n+\tfor (i = 0; i < argc; i++)\n+\t\tstrbuf_addf(&buf, \" %s\", argv[i]);\n+\tsetenv(\"GIT_REFLOG_ACTION\", buf.buf, 0);\n+\tstrbuf_reset(&buf);\n+\n+\tfor (i = 0; i < argc; i++) {\n+\t\tstruct object *o;\n+\n+\t\to = peel_to_type(argv[i], 0, NULL, OBJ_COMMIT);\n+\t\tif (!o)\n+\t\t\tdie(\"%s - not something we can merge\", argv[i]);\n+\t\tremotes = &commit_list_insert(lookup_commit(o->sha1),\n+\t\t\tremotes)->next;\n+\n+\t\tstrbuf_addf(&buf, \"GITHEAD_%s\", sha1_to_hex(o->sha1));\n+\t\tsetenv(buf.buf, argv[i], 1);\n+\t\tstrbuf_reset(&buf);\n+\t}\n+\n+\tif (!use_strategies.nr) {\n+\t\tif (!remoteheads->next)\n+\t\t\tadd_strategies(pull_twohead, DEFAULT_TWOHEAD);\n+\t\telse\n+\t\t\tadd_strategies(pull_octopus, DEFAULT_OCTOPUS);\n+\t}\n+\n+\tfor (i = 0; i < use_strategies.nr; i++) {\n+\t\tif (nth_strategy_flags(&use_strategies, i) & NO_FAST_FORWARD)\n+\t\t\tallow_fast_forward = 0;\n+\t\tif (nth_strategy_flags(&use_strategies, i) & NO_TRIVIAL)\n+\t\t\tallow_trivial = 0;\n+\t}\n+\n+\tif (!remoteheads->next)\n+\t\tcommon = get_merge_bases(lookup_commit(head),\n+\t\t\t\tremoteheads->item, 1);\n+\telse {\n+\t\tstruct commit_list *list = remoteheads;\n+\t\tcommit_list_insert(lookup_commit(head), &list);\n+\t\tcommon = get_octopus_merge_bases(list);\n+\t\tfree(list);\n+\t}\n+\n+\tupdate_ref(\"updating ORIG_HEAD\", \"ORIG_HEAD\", head, NULL, 0,\n+\t\tDIE_ON_ERR);\n+\n+\tif (!common)\n+\t\t; /* No common ancestors found. We need a real merge. */\n+\telse if (!remoteheads->next && !common->next &&\n+\t\t\tcommon->item == remoteheads->item) {\n+\t\t/*\n+\t\t * If head can reach all the merge then we are up to date.\n+\t\t * but first the most common case of merging one remote.\n+\t\t */\n+\t\tfinish_up_to_date(\"Already up-to-date.\");\n+\t\treturn 0;\n+\t} else if (allow_fast_forward && !remoteheads->next &&\n+\t\t\t!common->next &&\n+\t\t\t!hashcmp(common->item->object.sha1, head)) {\n+\t\t/* Again the most common case of merging one remote. */\n+\t\tstruct strbuf msg;\n+\t\tstruct object *o;\n+\t\tchar hex[41];\n+\n+\t\tstrcpy(hex, find_unique_abbrev(head, DEFAULT_ABBREV));\n+\n+\t\tprintf(\"Updating %s..%s\\n\",\n+\t\t\thex,\n+\t\t\tfind_unique_abbrev(remoteheads->item->object.sha1,\n+\t\t\tDEFAULT_ABBREV));\n+\t\trefresh_cache(REFRESH_QUIET);\n+\t\tstrbuf_init(&msg, 0);\n+\t\tstrbuf_addstr(&msg, \"Fast forward\");\n+\t\tif (have_message)\n+\t\t\tstrbuf_addstr(&msg,\n+\t\t\t\t\" (no commit created; -m option ignored)\");\n+\t\to = peel_to_type(sha1_to_hex(remoteheads->item->object.sha1),\n+\t\t\t0, NULL, OBJ_COMMIT);\n+\t\tif (!o)\n+\t\t\treturn 1;\n+\n+\t\tif (checkout_fast_forward(head, remoteheads->item->object.sha1))\n+\t\t\treturn 1;\n+\n+\t\tfinish(o->sha1, msg.buf);\n+\t\tdrop_save();\n+\t\treturn 0;\n+\t} else if (!remoteheads->next && common->next)\n+\t\t;\n+\t\t/*\n+\t\t * We are not doing octopus and not fast forward.  Need\n+\t\t * a real merge.\n+\t\t */\n+\telse if (!remoteheads->next && !common->next && option_commit) {\n+\t\t/*\n+\t\t * We are not doing octopus, not fast forward, and have\n+\t\t * only one common.\n+\t\t */\n+\t\trefresh_cache(REFRESH_QUIET);\n+\t\tif (allow_trivial) {\n+\t\t\t/* See if it is really trivial. */\n+\t\t\tgit_committer_info(IDENT_ERROR_ON_NO_NAME);\n+\t\t\tprintf(\"Trying really trivial in-index merge...\\n\");\n+\t\t\tif (!read_tree_trivial(common->item->object.sha1,\n+\t\t\t\t\thead, remoteheads->item->object.sha1))\n+\t\t\t\treturn merge_trivial();\n+\t\t\tprintf(\"Nope.\\n\");\n+\t\t}\n+\t} else {\n+\t\t/*\n+\t\t * An octopus.  If we can reach all the remote we are up\n+\t\t * to date.\n+\t\t */\n+\t\tint up_to_date = 1;\n+\t\tstruct commit_list *j;\n+\n+\t\tfor (j = remoteheads; j; j = j->next) {\n+\t\t\tstruct commit_list *common_one;\n+\n+\t\t\t/*\n+\t\t\t * Here we *have* to calculate the individual\n+\t\t\t * merge_bases again, otherwise \"git merge HEAD^\n+\t\t\t * HEAD^^\" would be missed.\n+\t\t\t */\n+\t\t\tcommon_one = get_merge_bases(lookup_commit(head),\n+\t\t\t\tj->item, 1);\n+\t\t\tif (hashcmp(common_one->item->object.sha1,\n+\t\t\t\tj->item->object.sha1)) {\n+\t\t\t\tup_to_date = 0;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tif (up_to_date) {\n+\t\t\tfinish_up_to_date(\"Already up-to-date. Yeeah!\");\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\t/* We are going to make a new commit. */\n+\tgit_committer_info(IDENT_ERROR_ON_NO_NAME);\n+\n+\t/*\n+\t * At this point, we need a real merge.  No matter what strategy\n+\t * we use, it would operate on the index, possibly affecting the\n+\t * working tree, and when resolved cleanly, have the desired\n+\t * tree in the index -- this means that the index must be in\n+\t * sync with the head commit.  The strategies are responsible\n+\t * to ensure this.\n+\t */\n+\tif (use_strategies.nr != 1) {\n+\t\t/*\n+\t\t * Stash away the local changes so that we can try more\n+\t\t * than one.\n+\t\t */\n+\t\tsave_state();\n+\t} else {\n+\t\tmemcpy(stash, null_sha1, 20);\n+\t}\n+\n+\tfor (i = 0; i < use_strategies.nr; i++) {\n+\t\tint ret;\n+\t\tif (i) {\n+\t\t\tprintf(\"Rewinding the tree to pristine...\\n\");\n+\t\t\trestore_state();\n+\t\t}\n+\t\tif (use_strategies.nr != 1)\n+\t\t\tprintf(\"Trying merge strategy %s...\\n\",\n+\t\t\t\tuse_strategies.items[i].path);\n+\t\t/*\n+\t\t * Remember which strategy left the state in the working\n+\t\t * tree.\n+\t\t */\n+\t\twt_strategy = &use_strategies.items[i];\n+\n+\t\tret = try_merge_strategy(use_strategies.items[i].path,\n+\t\t\tcommon, head_arg);\n+\t\tif (!option_commit && !ret) {\n+\t\t\tmerge_was_ok = 1;\n+\t\t\t/*\n+\t\t\t * This is necessary here just to avoid writing\n+\t\t\t * the tree, but later we will *not* exit with\n+\t\t\t * status code 1 because merge_was_ok is set.\n+\t\t\t */\n+\t\t\tret = 1;\n+\t\t}\n+\n+\t\tif (ret) {\n+\t\t\t/*\n+\t\t\t * The backend exits with 1 when conflicts are\n+\t\t\t * left to be resolved, with 2 when it does not\n+\t\t\t * handle the given merge at all.\n+\t\t\t */\n+\t\t\tif (ret == 1) {\n+\t\t\t\tint cnt = evaluate_result();\n+\n+\t\t\t\tif (best_cnt <= 0 || cnt <= best_cnt) {\n+\t\t\t\t\tbest_strategy =\n+\t\t\t\t\t\t&use_strategies.items[i];\n+\t\t\t\t\tbest_cnt = cnt;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif (merge_was_ok)\n+\t\t\t\tbreak;\n+\t\t\telse\n+\t\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* Automerge succeeded. */\n+\t\twrite_tree_trivial(result_tree);\n+\t\tautomerge_was_ok = 1;\n+\t\tbreak;\n+\t}\n+\n+\t/*\n+\t * If we have a resulting tree, that means the strategy module\n+\t * auto resolved the merge cleanly.\n+\t */\n+\tif (automerge_was_ok)\n+\t\treturn finish_automerge(common, result_tree, wt_strategy);\n+\n+\t/*\n+\t * Pick the result from the best strategy and have the user fix\n+\t * it up.\n+\t */\n+\tif (!best_strategy) {\n+\t\trestore_state();\n+\t\tif (use_strategies.nr > 1)\n+\t\t\tfprintf(stderr,\n+\t\t\t\t\"No merge strategy handled the merge.\\n\");\n+\t\telse\n+\t\t\tfprintf(stderr, \"Merge with strategy %s failed.\\n\",\n+\t\t\t\tuse_strategies.items[0].path);\n+\t\treturn 2;\n+\t} else if (best_strategy == wt_strategy)\n+\t\t; /* We already have its result in the working tree. */\n+\telse {\n+\t\tprintf(\"Rewinding the tree to pristine...\\n\");\n+\t\trestore_state();\n+\t\tprintf(\"Using the %s to prepare resolving by hand.\\n\",\n+\t\t\tbest_strategy->path);\n+\t\ttry_merge_strategy(best_strategy->path, common, head_arg);\n+\t}\n+\n+\tif (squash)\n+\t\tfinish(NULL, NULL);\n+\telse {\n+\t\tint fd;\n+\t\tstruct commit_list *j;\n+\n+\t\tfor (j = remoteheads; j; j = j->next)\n+\t\t\tstrbuf_addf(&buf, \"%s\\n\",\n+\t\t\t\tsha1_to_hex(j->item->object.sha1));\n+\t\tfd = open(git_path(\"MERGE_HEAD\"), O_WRONLY | O_CREAT, 0666);\n+\t\tif (fd < 0)\n+\t\t\tdie(\"Could open %s for writing\",\n+\t\t\t\tgit_path(\"MERGE_HEAD\"));\n+\t\tif (write_in_full(fd, buf.buf, buf.len) != buf.len)\n+\t\t\tdie(\"Could not write to %s\", git_path(\"MERGE_HEAD\"));\n+\t\tclose(fd);\n+\t\tstrbuf_addch(&merge_msg, '\\n');\n+\t\tfd = open(git_path(\"MERGE_MSG\"), O_WRONLY | O_CREAT, 0666);\n+\t\tif (fd < 0)\n+\t\t\tdie(\"Could open %s for writing\", git_path(\"MERGE_MSG\"));\n+\t\tif (write_in_full(fd, merge_msg.buf, merge_msg.len) !=\n+\t\t\tmerge_msg.len)\n+\t\t\tdie(\"Could not write to %s\", git_path(\"MERGE_MSG\"));\n+\t\tclose(fd);\n+\t}\n+\n+\tif (merge_was_ok) {\n+\t\tfprintf(stderr, \"Automatic merge went well; \"\n+\t\t\t\"stopped before committing as requested\\n\");\n+\t\treturn 0;\n+\t} else\n+\t\treturn suggest_conflicts();\n+}\ndiff --git a/builtin.h b/builtin.h\nindex 05ee56f..0e605d4 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -64,6 +64,7 @@ extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);\n extern int cmd_ls_remote(int argc, const char **argv, const char *prefix);\n extern int cmd_mailinfo(int argc, const char **argv, const char *prefix);\n extern int cmd_mailsplit(int argc, const char **argv, const char *prefix);\n+extern int cmd_merge(int argc, const char **argv, const char *prefix);\n extern int cmd_merge_base(int argc, const char **argv, const char *prefix);\n extern int cmd_merge_ours(int argc, const char **argv, const char *prefix);\n extern int cmd_merge_file(int argc, const char **argv, const char *prefix);\ndiff --git a/git-merge.sh b/contrib/examples/git-merge.sh\nsimilarity index 100%\nrename from git-merge.sh\nrename to contrib/examples/git-merge.sh\ndiff --git a/git.c b/git.c\nindex 2fbe96b..770aadd 100644\n--- a/git.c\n+++ b/git.c\n@@ -271,6 +271,7 @@ static void handle_internal_command(int argc, const char **argv)\n \t\t{ \"ls-remote\", cmd_ls_remote },\n \t\t{ \"mailinfo\", cmd_mailinfo },\n \t\t{ \"mailsplit\", cmd_mailsplit },\n+\t\t{ \"merge\", cmd_merge, RUN_SETUP | NEED_WORK_TREE },\n \t\t{ \"merge-base\", cmd_merge_base, RUN_SETUP },\n \t\t{ \"merge-file\", cmd_merge_file },\n \t\t{ \"merge-ours\", cmd_merge_ours, RUN_SETUP },\ndiff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh\nindex f3a4bb2..fcb8285 100755\n--- a/t/t7602-merge-octopus-many.sh\n+++ b/t/t7602-merge-octopus-many.sh\n@@ -23,7 +23,7 @@ test_expect_success 'setup' '\n \tdone\n '\n \n-test_expect_failure 'merge c1 with c2, c3, c4, ... c29' '\n+test_expect_success 'merge c1 with c2, c3, c4, ... c29' '\n \tgit reset --hard c1 &&\n \ti=2 &&\n \trefs=\"\" &&\n-- \n1.5.6.1\n"},{"id":"81840","messageId":"alpine.DEB.1.00.0807010606470.9925@racer","threadId":"14237","inReplyTo":"666ec9b342a0c3254ae8f917d5bd2dea36314f08.1214878711.git.vmiklos@frugalware.org","subject":"Re: [PATCH 13/14] git-commit-tree: make it usable from other builtins","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-01T05:07:28Z","receivedAt":"2008-07-01T05:07:28Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 1 Jul 2008, Miklos Vajna wrote:\n\n> I did it this way to avoid an unnecessary conflict with Dscho's recent \n> patch to commit-tree (ef98c5c).\n\nOh, sorry!\n\nFunnily enough, I committed and tested this change in my clone of \nbuiltin-merge before I realized that I am in the wrong directory ;-)\n\nCiao,\nDscho\n"},{"id":"81841","messageId":"7vbq1irw3q.fsf@gitster.siamese.dyndns.org","threadId":"14237","inReplyTo":"666ec9b342a0c3254ae8f917d5bd2dea36314f08.1214878711.git.vmiklos@frugalware.org","subject":"Re: [PATCH 13/14] git-commit-tree: make it usable from other builtins","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-01T05:50:49Z","receivedAt":"2008-07-01T05:50:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Miklos Vajna <vmiklos@frugalware.org> writes:\n\n> This patch is against master, you need to pull from me or first rebase\n> mv/merge-in-c against current master.\n\nThat's a bad practice.  It makes it much harder to review the incremental\nchanges from the previous round.\n\nI'll cope, though.\n"},{"id":"81867","messageId":"20080701120924.GV4729@genesis.frugalware.org","threadId":"14237","inReplyTo":"7vbq1irw3q.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 13/14] git-commit-tree: make it usable from other builtins","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-01T12:09:24Z","receivedAt":"2008-07-01T12:09:24Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Mon, Jun 30, 2008 at 10:50:49PM -0700, Junio C Hamano <gitster@pobox.com> wrote:\n> Miklos Vajna <vmiklos@frugalware.org> writes:\n> \n> > This patch is against master, you need to pull from me or first rebase\n> > mv/merge-in-c against current master.\n> \n> That's a bad practice.  It makes it much harder to review the incremental\n> changes from the previous round.\n\nSorry. I just did this way because in my patch I wanted to let\ncmd_commit_tree() use a commit_list and I saw Dscho already did it, and\nI saw that the patch is already in master.\n\n> I'll cope, though.\n\nThanks.\n"}]}