{"thread":{"id":"14238","subject":"[PATCH 08/14] Add new test to ensure git-merge handles more than 25 refs.","startedAt":"2008-07-01T02:37:47Z","lastAt":"2008-07-08T01:41:09Z","messageCount":26,"participants":["Miklos Vajna","Junio C Hamano","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":14},"messages":[{"id":"81820","messageId":"cover.1214879690.git.vmiklos@frugalware.org","threadId":"14238","inReplyTo":"0ed87f20b5fa79f4a16f23a522cfc7c52f77ce0e.1214878711.git.vmiklos@frugalware.org","subject":"[PATCH 00/14] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-01T02:37:47Z","receivedAt":"2008-07-01T02:37:47Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Sorry for the resend, but I again squashed an unrelated hunk to the last\npatch, so I'm sending the changed patches:\n\n08: Add new test to ensure git-merge handles more than 25 refs.\n13: git-commit-tree: make it usable from other builtins\n14: Build in merge\n\nI really hope I won't overlook this next time.\n\nThe interdiff from the previous version is empty, I just moved that\nunrelated hunk from patch 13 to patch 08.\n\nJunio C Hamano (2):\n  Introduce get_merge_bases_many()\n  Introduce reduce_heads()\n\nMiklos Vajna (12):\n  Move split_cmdline() to alias.c\n  Move commit_list_count() to commit.c\n  Move parse-options's skip_prefix() to git-compat-util.h\n  Add new test to ensure git-merge handles pull.twohead and\n    pull.octopus\n  Move read_cache_unmerged() to read-cache.c\n  git-fmt-merge-msg: make it usable from other builtins\n  Introduce get_octopus_merge_bases() in commit.c\n  Add new test to ensure git-merge handles more than 25 refs.\n  Add new test case to ensure git-merge reduces octopus parents when\n    possible\n  Add new test case to ensure git-merge prepends the custom merge\n    message\n  git-commit-tree: make it usable from other builtins\n  Build in merge\n\n Makefile                                      |    2 +-\n alias.c                                       |   54 ++\n builtin-commit-tree.c                         |   71 +-\n builtin-fmt-merge-msg.c                       |  155 ++--\n builtin-merge-recursive.c                     |    8 -\n builtin-merge.c                               | 1148 +++++++++++++++++++++++++\n builtin-read-tree.c                           |   24 -\n builtin-remote.c                              |   39 +-\n builtin.h                                     |    8 +\n cache.h                                       |    3 +\n commit.c                                      |  136 +++-\n commit.h                                      |    4 +\n git-merge.sh => contrib/examples/git-merge.sh |    0 \n git-compat-util.h                             |    6 +\n git.c                                         |   54 +--\n parse-options.c                               |    6 -\n read-cache.c                                  |   31 +\n t/t7601-merge-pull-config.sh                  |  129 +++\n t/t7602-merge-octopus-many.sh                 |   52 ++\n t/t7603-merge-reduce-heads.sh                 |   63 ++\n t/t7604-merge-custom-message.sh               |   37 +\n 21 files changed, 1811 insertions(+), 219 deletions(-)\n create mode 100644 builtin-merge.c\n rename git-merge.sh => contrib/examples/git-merge.sh (100%)\n create mode 100755 t/t7601-merge-pull-config.sh\n create mode 100755 t/t7602-merge-octopus-many.sh\n create mode 100755 t/t7603-merge-reduce-heads.sh\n create mode 100755 t/t7604-merge-custom-message.sh\n"},{"id":"81819","messageId":"9201d4e13e574c10b1674cf1f6da23a44a73f8b2.1214879690.git.vmiklos@frugalware.org","threadId":"14238","inReplyTo":"cover.1214879690.git.vmiklos@frugalware.org","subject":"[PATCH 08/14] Add new test to ensure git-merge handles more than 25 refs.","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-01T02:37:48Z","receivedAt":"2008-07-01T02:37:48Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"The old shell version handled only 25 refs but we no longer have this\nlimitation. Add a test to make sure this limitation will not be\nintroduced again in the future.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n t/t7602-merge-octopus-many.sh |   52 +++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 52 insertions(+), 0 deletions(-)\n create mode 100755 t/t7602-merge-octopus-many.sh\n\ndiff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh\nnew file mode 100755\nindex 0000000..fcb8285\n--- /dev/null\n+++ b/t/t7602-merge-octopus-many.sh\n@@ -0,0 +1,52 @@\n+#!/bin/sh\n+\n+test_description='git-merge\n+\n+Testing octopus merge with more than 25 refs.'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\techo c0 > c0.c &&\n+\tgit add c0.c &&\n+\tgit commit -m c0 &&\n+\tgit tag c0 &&\n+\ti=1 &&\n+\twhile test $i -le 30\n+\tdo\n+\t\tgit reset --hard c0 &&\n+\t\techo c$i > c$i.c &&\n+\t\tgit add c$i.c &&\n+\t\tgit commit -m c$i &&\n+\t\tgit tag c$i &&\n+\t\ti=`expr $i + 1` || return 1\n+\tdone\n+'\n+\n+test_expect_success 'merge c1 with c2, c3, c4, ... c29' '\n+\tgit reset --hard c1 &&\n+\ti=2 &&\n+\trefs=\"\" &&\n+\twhile test $i -le 30\n+\tdo\n+\t\trefs=\"$refs c$i\"\n+\t\ti=`expr $i + 1`\n+\tdone\n+\tgit merge $refs &&\n+\ttest \"$(git rev-parse c1)\" != \"$(git rev-parse HEAD)\" &&\n+\ti=1 &&\n+\twhile test $i -le 30\n+\tdo\n+\t\ttest \"$(git rev-parse c$i)\" = \"$(git rev-parse HEAD^$i)\" &&\n+\t\ti=`expr $i + 1` || return 1\n+\tdone &&\n+\tgit diff --exit-code &&\n+\ti=1 &&\n+\twhile test $i -le 30\n+\tdo\n+\t\ttest -f c$i.c &&\n+\t\ti=`expr $i + 1` || return 1\n+\tdone\n+'\n+\n+test_done\n-- \n1.5.6.1\n"},{"id":"81821","messageId":"1b74bb93e518a906b0067d182fb29279baff3b25.1214879690.git.vmiklos@frugalware.org","threadId":"14238","inReplyTo":"9201d4e13e574c10b1674cf1f6da23a44a73f8b2.1214879690.git.vmiklos@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:37:49Z","receivedAt":"2008-07-01T02:37:49Z","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 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":"81822","messageId":"5e65b37998d1fdd9d314e48cea2cf67fd73ba8cd.1214879690.git.vmiklos@frugalware.org","threadId":"14238","inReplyTo":"1b74bb93e518a906b0067d182fb29279baff3b25.1214879690.git.vmiklos@frugalware.org","subject":"[PATCH 14/14] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-01T02:37:50Z","receivedAt":"2008-07-01T02:37:50Z","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 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 5 files changed, 1151 insertions(+), 1 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 },\n-- \n1.5.6.1\n"},{"id":"81842","messageId":"7vtzfaqg16.fsf@gitster.siamese.dyndns.org","threadId":"14238","inReplyTo":"5e65b37998d1fdd9d314e48cea2cf67fd73ba8cd.1214879690.git.vmiklos@frugalware.org","subject":"Re: [PATCH 14/14] Build in merge","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-01T06:23:17Z","receivedAt":"2008-07-01T06:23:17Z","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> +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\nDo you still need this assignment here?\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\nWait a minute...  Are you calling a detached HEAD as head_invalid here?  I\nam not too much worried about variable naming, but you later do ...\n\n> +\tif (!have_message && is_old_style_invocation(argc, argv)) {\n> ...\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\nWhich is about HEAD pointing at a branch that isn't born yet.  They are\ntwo very different concepts.\n\nEither the above \"else if (head_invalid)\" is wrong, or more likely the\nsetting of head_invalid we saw earlier is wrong.\n\nProbably what you meant was:\n\n\t- \"char *branch\" points at either \"HEAD\" (when detached) or\n          the name of the branch (e.g. \"master\" when \"refs/heads/master\");\n\n\t- \"unsigned char head[]\" stores the commit object name of the\n          current HEAD (or 0{40} if the current branch is unborn);\n\n        - set head_invalid to true only when the current branch is unborn.\n\nSo perhaps...\n\n\tbranch = resolve_ref(\"HEAD\", head, 0, &flag);\n        if (branch && (flag & REF_ISSYMREF) && !prefixcmp(branch, \"refs/heads/\"))\n\t\tbranch += 11;\n        head_invalid = is_null_sha1(head);\n\nAnd probably we can even drop (flag & REF_ISSYMREF) from the above safely.\nDo we even care if the head is detached in this program?  I doubt it.\n\n> ...\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\nNot exiting with 0 status from around here upon error is an improvement,\nbut does the user see sensible error messages in addition to the exit\nstatus?\n\nGetting warmer ;-)\n"},{"id":"81843","messageId":"7vzlp2oyh7.fsf@gitster.siamese.dyndns.org","threadId":"14238","inReplyTo":"5e65b37998d1fdd9d314e48cea2cf67fd73ba8cd.1214879690.git.vmiklos@frugalware.org","subject":"Re: [PATCH 14/14] Build in merge","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-01T07:27:48Z","receivedAt":"2008-07-01T07:27:48Z","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> +\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\nI still have problems with the above.  I'd write it this way:\n\n\tint len, early;\n\t...\n\t/* See if remote matches <name>^^^.. or <name>~<number> */\n\tfor (len = 0, ptr = remote + strlen(remote);\n\t     remote < ptr && ptr[-1] == '^';\n\t     ptr--)\n\t\tlen++;\n\tif (len)\n\t\tearly = 1;\n\telse {\n\t\tearly = 0;\n\t\tptr = strrchr(remote, '~');\n\t\tif (ptr) {\n\t\t\tint seen_nonzero = 0;\n\n\t\t\tlen++; /* count ~ */\n\t\t\twhile (*++ptr && isdigit(*ptr)) {\n\t\t\t\tseen_nonzero |= (*ptr != '0');\n\t\t\t\tlen++;\n\t\t\t}\n\t\t\tif (*ptr)\n\t\t\t\tlen = 0; /* not ...~<number> */\n\t\t\telse if (seen_nonzero)\n\t\t\t\tearly = 1;\n\t\t\telse if (len == 1)\n\t\t\t\tearly = 1; /* \"name~\" is \"name~1\"! */\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'%s of .\\n\",\n\t\t\t\t    sha1_to_hex(remote_head->sha1),\n\t\t\t\t    truname.buf,\n\t\t\t\t    (early ? \" (early part)\" : \"\"));\n\t\t\treturn;\n\t\t}\n\t}\n\n\nThe first loop is obvious.  If the tail end is ^, we set \"len\" and see if\nthe remainder is a branch name (and if that is the case we are always\ntalking about an early part of it of the branch).\n\nOtherwise, we do want to say \"early part\" if \"$name~<number>\" is given,\nand another special case is \"$name~\" which is \"$name~1\" these days.  As\nlong as number is not zero we would want to say \"early part\".  Otherwise\nwe would want to say it is a branch itself, not its early part.\n\nI'll queue the fixed-up result in 'pu', but I have to tend to other topics\nbefore I can actually publish.  Together with the fix to \"head_invalid\"\nconfusion I mentioned in another message squashed in to this commit, all\nthe tests now finally seem to pass on the topic branch.\n\nOh, by the way, you sent this and the previous round without marking them\nas RFC nor WIP, even though they obviously did not even pass the test\nsuite.  For example, without the head_invalid fix, anything that runs\nmerge on detached head, most notably \"git rebase -i\", would not work at\nall.\n"},{"id":"81871","messageId":"20080701125023.GW4729@genesis.frugalware.org","threadId":"14238","inReplyTo":"7vtzfaqg16.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 14/14] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-01T12:50:23Z","receivedAt":"2008-07-01T12:50:23Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Mon, Jun 30, 2008 at 11:23:17PM -0700, Junio C Hamano <gitster@pobox.com> wrote:\n> Miklos Vajna <vmiklos@frugalware.org> writes:\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> \n> Do you still need this assignment here?\n\nNo, it was duplicated.\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> Wait a minute...  Are you calling a detached HEAD as head_invalid here?  I\n> am not too much worried about variable naming, but you later do ...\n> \n> > +\tif (!have_message && is_old_style_invocation(argc, argv)) {\n> > ...\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> \n> Which is about HEAD pointing at a branch that isn't born yet.  They are\n> two very different concepts.\n> \n> Either the above \"else if (head_invalid)\" is wrong, or more likely the\n> setting of head_invalid we saw earlier is wrong.\n> \n> Probably what you meant was:\n> \n> \t- \"char *branch\" points at either \"HEAD\" (when detached) or\n>           the name of the branch (e.g. \"master\" when \"refs/heads/master\");\n> \n> \t- \"unsigned char head[]\" stores the commit object name of the\n>           current HEAD (or 0{40} if the current branch is unborn);\n> \n>         - set head_invalid to true only when the current branch is unborn.\n> \n> So perhaps...\n> \n> \tbranch = resolve_ref(\"HEAD\", head, 0, &flag);\n>         if (branch && (flag & REF_ISSYMREF) && !prefixcmp(branch, \"refs/heads/\"))\n> \t\tbranch += 11;\n>         head_invalid = is_null_sha1(head);\n> \n> And probably we can even drop (flag & REF_ISSYMREF) from the above safely.\n> Do we even care if the head is detached in this program?  I doubt it.\n\nYou are right. I though we care about it, but now I realized such a\ncomment was only in git-merge.annotated (in Dscho's fork), not in\ngit-merge.sh. And yes, I mixed up head_invalid for two purposes. Thanks\nfor clearing the situation.\n\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> Not exiting with 0 status from around here upon error is an improvement,\n> but does the user see sensible error messages in addition to the exit\n> status?\n\nNow he/she does. :-)\n\n(I updated my working branch on repo.or.cz, will send a patch soon, as\nwell.)\n"},{"id":"81872","messageId":"20080701125518.GX4729@genesis.frugalware.org","threadId":"14238","inReplyTo":"7vzlp2oyh7.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 14/14] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-01T12:55:18Z","receivedAt":"2008-07-01T12:55:18Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Tue, Jul 01, 2008 at 12:27:48AM -0700, Junio C Hamano <gitster@pobox.com> wrote:\n> I'll queue the fixed-up result in 'pu', but I have to tend to other topics\n> before I can actually publish.  Together with the fix to \"head_invalid\"\n> confusion I mentioned in another message squashed in to this commit, all\n> the tests now finally seem to pass on the topic branch.\n> \n> Oh, by the way, you sent this and the previous round without marking them\n> as RFC nor WIP, even though they obviously did not even pass the test\n> suite.  For example, without the head_invalid fix, anything that runs\n> merge on detached head, most notably \"git rebase -i\", would not work at\n> all.\n\nThanks for pointing that out. I remember I used to run 'make test'\nbefore sending a patch, but that took a lot of time and then I used to\nrun only t*merge*.sh, which - it turns out - was a bad idea, since I\nhaven't noticed breaking t3404.\n\nI'm now running a full 'make test' before I send the patch.\n"},{"id":"81876","messageId":"0cde1e7c930589364318b2d0344b345453e23586.1214918017.git.vmiklos@frugalware.org","threadId":"14238","inReplyTo":"20080701125023.GW4729@genesis.frugalware.org","subject":"[PATCH 14/14] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-01T13:18:18Z","receivedAt":"2008-07-01T13:18:18Z","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: git diff 01a7dae..7709df7\n\nIndividual commits (there is only one change this time): git log 7709df7\n\nAh and please don't forget to apply the testsuite fix I sent in\n$gmane/86981. (Or is it easier if I resend the whole series?)\n\n Makefile                                      |    2 +-\n builtin-merge.c                               | 1158 +++++++++++++++++++++++++\n builtin.h                                     |    1 +\n git-merge.sh => contrib/examples/git-merge.sh |    0 \n git.c                                         |    1 +\n 5 files changed, 1161 insertions(+), 1 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..b261993\n--- /dev/null\n+++ b/builtin-merge.c\n@@ -0,0 +1,1158 @@\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, early;\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+\n+\t/* See if remote matches <name>^^^.. or <name>~<number> */\n+\tfor (len = 0, ptr = remote + strlen(remote);\n+\t     remote < ptr && ptr[-1] == '^';\n+\t     ptr--)\n+\t\tlen++;\n+\tif (len)\n+\t\tearly = 1;\n+\telse {\n+\t\tearly = 0;\n+\t\tptr = strrchr(remote, '~');\n+\t\tif (ptr) {\n+\t\t\tint seen_nonzero = 0;\n+\n+\t\t\tlen++; /* count ~ */\n+\t\t\twhile (*++ptr && isdigit(*ptr)) {\n+\t\t\t\tseen_nonzero |= (*ptr != '0');\n+\t\t\t\tlen++;\n+\t\t\t}\n+\t\t\tif (*ptr)\n+\t\t\t\tlen = 0; /* not ...~<number> */\n+\t\t\telse if (seen_nonzero)\n+\t\t\t\tearly = 1;\n+\t\t\telse if (len == 1)\n+\t\t\t\tearly = 1; /* \"name~\" is \"name~1\"! */\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'%s of .\\n\",\n+\t\t\t\t    sha1_to_hex(remote_head->sha1),\n+\t\t\t\t    truname.buf,\n+\t\t\t\t    (early ? \" (early part)\" : \"\"));\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+\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 && !prefixcmp(branch, \"refs/heads/\"))\n+\t\tbranch += 11;\n+\tif (is_null_sha1(head))\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(remoteheads->item->object.sha1,\n+\t\t\tDEFAULT_ABBREV));\n+\n+\t\tprintf(\"Updating %s..%s\\n\",\n+\t\t\tfind_unique_abbrev(head, DEFAULT_ABBREV),\n+\t\t\thex);\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\terror(\"%s is not a commit\", hex);\n+\t\t\treturn 1;\n+\t\t}\n+\n+\t\tif (checkout_fast_forward(head, remoteheads->item->object.sha1)) {\n+\t\t\terror(\"failed to fast-forward to %s\", hex);\n+\t\t\treturn 1;\n+\t\t}\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 },\n-- \n1.5.6.1\n"},{"id":"81908","messageId":"7v63rpkvme.fsf@gitster.siamese.dyndns.org","threadId":"14238","inReplyTo":"0cde1e7c930589364318b2d0344b345453e23586.1214918017.git.vmiklos@frugalware.org","subject":"Re: [PATCH 14/14] Build in merge","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-01T23:55:21Z","receivedAt":"2008-07-01T23:55:21Z","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> Mentored-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n> Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>\n> ---\n>\n> Interdiff: git diff 01a7dae..7709df7\n>\n> Individual commits (there is only one change this time): git log 7709df7\n>\n> Ah and please don't forget to apply the testsuite fix I sent in\n> $gmane/86981. (Or is it easier if I resend the whole series?)\n\nAre you sure about that?  I've been deliberately fixing that patch.\n\nAs far as I understand it, your series:\n\n - starts out building infrastructure;\n - adds tests;\n - finally replaces git-merge with the new implementation.\n\nand the test in question comes when git-merge built from that version is\nstill the scripted version with limitation.\n\nSo if you build and test after applying individual steps (you sure do\nthat, don't you?), the test has to start with expecting failure (from the\nscripted git-merge that has the octopus limitation) and then later changed\nto expect success when git-merge is replaced.\n\nHave you looked at the series I fixed up before pushing out in 'pu' last\nnight, specifically 5948e2a and 01a7dae?  If you actually built and tested\n5948e2a, you'd notice that the test in that commit *must* expect failure.\n"},{"id":"81931","messageId":"20080702074310.GG4729@genesis.frugalware.org","threadId":"14238","inReplyTo":"7v63rpkvme.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 14/14] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-02T07:43:10Z","receivedAt":"2008-07-02T07:43:10Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Tue, Jul 01, 2008 at 04:55:21PM -0700, Junio C Hamano <gitster@pobox.com> wrote:\n> Have you looked at the series I fixed up before pushing out in 'pu' last\n> night, specifically 5948e2a and 01a7dae?  If you actually built and tested\n> 5948e2a, you'd notice that the test in that commit *must* expect failure.\n\nAah. Now I see the point, thanks for explaining! :-)\n"},{"id":"82345","messageId":"7vej67jt1e.fsf@gitster.siamese.dyndns.org","threadId":"14238","inReplyTo":"0cde1e7c930589364318b2d0344b345453e23586.1214918017.git.vmiklos@frugalware.org","subject":"Re: [PATCH 14/14] Build in merge","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-06T08:50:05Z","receivedAt":"2008-07-06T08:50:05Z","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> diff --git a/builtin-merge.c b/builtin-merge.c\n> new file mode 100644\n> index 0000000..b261993\n> --- /dev/null\n> +++ b/builtin-merge.c\n> @@ -0,0 +1,1158 @@\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\nUsually \"enum foo\" consists of possible values of \"foo\".  But this is\nnot a list of strategies.  These are possible attributes to strategies.\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\nThis declaration is funnily line-wrapped.\n\n        static struct path_list strategies = {\n                strategy_items, ARRAY_SIZE(strategy_items), 0, 0,\n        };\n\nBut more problematic is that a path_list is inherently a dynamic data\nstructure (you can add and it reallocs), and this use of relying on the\nknowledge that you happen to never add anything (nor subtract anything)\nfrom the list is a mere hack.  If on the other hand you (and more\nimportantly other people who touch this implementation later) will never\nadd or remove items from this \"strategies\" array, you should make sure at\nthe interface level that nobody can -- one way to do so is not to abuse\npath_list for something like this.\n\nCome to think of it, wasn't the reason why the earlier \"Why do you need\nsuch distracting casts all over the place?\" issue came up in another patch\nbecause of this kind of (ab)use of path_list, which is an inappropriate\ndata structure for the job?\n\nYou would perhaps define:\n\n\t#define DEFAULT_TWOHEAD (1<<0)\n\t#define DEFAULT_OCTOPUS (1<<1)\n\t#define NO_FAST_FORWARD (1<<2)\n\t#define NO_TRIVIAL\t(1<<3)\n\n\tstatic struct strategy {\n        \tchar *name;\n                unsigned attr;\n\t} all_strategy[] = {\n                { \"octopus\",    DEFAULT_OCTOPUS },\n                { \"ours\",       (NO_FAST_FORWARD | NO_TRIVIAL) },\n                { \"recur\",      NO_TRIVIAL },\n                { \"recursive\",  (DEFAULT_TWOHEAD | NO_TRIVIAL) },\n                { \"resolve\",    0 },\n                { \"stupid\",     0 },\n                { \"subtree\",    (NO_FAST_FORWARD | NO_TRIVIAL) },\n        };\n\nAnd \"unsorted_path_list_lookup()\" can now become much more natural,\nperhaps:\n\n\tstatic struct strategy *get_strategy(const char *name);\n\nwhich has a more natural function signature and much better name.\n\nThen, you would keep an array of pointers into all_strategy[] array to\nrepresent the list of \"-s strategy\" given by the user:\n\n\tstatic struct strategy *use_strategy;\n\tstatic int use_strategy_alloc, use_strategy_nr;\n\nand have a function that use s the standard ALLOC_GROW() and friends to\ngrow this.  The function will be named and written more naturally\n(i.e. path_list_append_strategy() can go) --- this does not have anything\nto do with path_list, but it is about \"merge strategy\".\n\nBut 99.9% of the time you would not have more than one elements ;-).\n"},{"id":"82348","messageId":"7v4p73gxf6.fsf@gitster.siamese.dyndns.org","threadId":"14238","inReplyTo":"7vej67jt1e.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 14/14] Build in merge","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-06T09:43:41Z","receivedAt":"2008-07-06T09:43:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> You would perhaps define:\n>\n> \t#define DEFAULT_TWOHEAD (1<<0)\n> \t#define DEFAULT_OCTOPUS (1<<1)\n> \t#define NO_FAST_FORWARD (1<<2)\n> \t#define NO_TRIVIAL\t(1<<3)\n>\n> \tstatic struct strategy {\n>         \tchar *name;\n>                 unsigned attr;\n> \t} all_strategy[] = {\n>                 { \"octopus\",    DEFAULT_OCTOPUS },\n>                 { \"ours\",       (NO_FAST_FORWARD | NO_TRIVIAL) },\n>                 { \"recur\",      NO_TRIVIAL },\n>                 { \"recursive\",  (DEFAULT_TWOHEAD | NO_TRIVIAL) },\n>                 { \"resolve\",    0 },\n>                 { \"stupid\",     0 },\n>                 { \"subtree\",    (NO_FAST_FORWARD | NO_TRIVIAL) },\n>         };\n>\n> And \"unsorted_path_list_lookup()\" can now become much more natural,\n> perhaps:\n>\n> \tstatic struct strategy *get_strategy(const char *name);\n>\n> which has a more natural function signature and much better name.\n>\n> Then, you would keep an array of pointers into all_strategy[] array to\n> represent the list of \"-s strategy\" given by the user:\n>\n> \tstatic struct strategy *use_strategy;\n> \tstatic int use_strategy_alloc, use_strategy_nr;\n\nSorry, I have an obvious typo here.  \"use_strategy\" will be dynamic array\nof pointers into all_strategy[] so its definition would be:\n\n\tstatic struct strategy **use_strategy;\n\n> and have a function that use s the standard ALLOC_GROW() and friends to\n> grow this.  The function will be named and written more naturally\n> (i.e. path_list_append_strategy() can go) --- this does not have anything\n> to do with path_list, but it is about \"merge strategy\".\n"},{"id":"82360","messageId":"alpine.LSU.1.00.0807061433480.3486@wbgn129.biozentrum.uni-wuerzburg.de","threadId":"14238","inReplyTo":"7vej67jt1e.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 14/14] Build in merge","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-06T12:38:23Z","receivedAt":"2008-07-06T12:38:23Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 6 Jul 2008, Junio C Hamano wrote:\n\n> Miklos Vajna <vmiklos@frugalware.org> writes:\n> \n> > diff --git a/builtin-merge.c b/builtin-merge.c\n> > new file mode 100644\n> > index 0000000..b261993\n> > --- /dev/null\n> > +++ b/builtin-merge.c\n> > @@ -0,0 +1,1158 @@\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> Usually \"enum foo\" consists of possible values of \"foo\".  But this is\n> not a list of strategies.  These are possible attributes to strategies.\n\nMy fault.  I avoid ugly #defines, so I suggested using an enum.\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> This declaration is funnily line-wrapped.\n> \n>         static struct path_list strategies = {\n>                 strategy_items, ARRAY_SIZE(strategy_items), 0, 0,\n>         };\n> \n> But more problematic is that a path_list is inherently a dynamic data \n> structure (you can add and it reallocs), and this use of relying on the \n> knowledge that you happen to never add anything (nor subtract anything) \n> from the list is a mere hack.  If on the other hand you (and more \n> importantly other people who touch this implementation later) will never \n> add or remove items from this \"strategies\" array, you should make sure \n> at the interface level that nobody can -- one way to do so is not to \n> abuse path_list for something like this.\n> \n> Come to think of it, wasn't the reason why the earlier \"Why do you need \n> such distracting casts all over the place?\" issue came up in another \n> patch because of this kind of (ab)use of path_list, which is an \n> inappropriate data structure for the job?\n\nWell, it is not really an abuse if you think of path_list as a \nstring_list, which it really is, and which should have happened a long \ntime ago, but I gave up.\n\nAnyway, the use of string_list here was originally to make lookup slightly \nmore convenient, using an API, instead of reinventing the wheel over and \nover and over again, as can be seen nicely in some parts of Git's source \ncode.\n\nGiven that we want to be able to add other strategies, I would have rather \nsuggested fixing string_list to heed \"alloc == 0\" and _not_ realloc() in \nthat case.\n\nBut given that you seem so sick and tired of string_list, and rather have \na code duplication, I will not argue to that end anymore.\n\nTired,\nDscho\n"},{"id":"82385","messageId":"7v8wweer9m.fsf@gitster.siamese.dyndns.org","threadId":"14238","inReplyTo":"alpine.LSU.1.00.0807061433480.3486@wbgn129.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 14/14] Build in merge","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-06T19:39:33Z","receivedAt":"2008-07-06T19:39:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> But given that you seem so sick and tired of string_list, and rather have \n> a code duplication, I will not argue to that end anymore.\n\nYou are probably very confused if you think I am saying I'd rather have\nduplication.\n\nLook at \"unsorted_path_list_lookup()\" in builtin-merge.c and think again.\nLook at \"path_list_append_strategy()\" in builtin-merge.c and think again.\n\nIf you are adding the same amount of code _anyway_, why not write using\nmore appropriate data structure for the job?\n\nThe path_list has its uses.  It's wonderful when you have existing\nstructures that you would need to keep in core anyway and being able to\nlook them up via string keys.  But that does not mean it is (nor should be\n\"improved\" to be) a good match for other forms of (ab)uses.\n\nThe way it was used by initializing with pointer to a static array\nlocation is clearly a misuse.  When using ->util field to store things\nother than pointers to preexisting structures, the use of the API becomes\nclunky and we discussed this issue about another patch.  That's all I was\nsaying.\n"},{"id":"82470","messageId":"20080707171721.GT4729@genesis.frugalware.org","threadId":"14238","inReplyTo":"7v4p73gxf6.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 14/14] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-07T17:17:21Z","receivedAt":"2008-07-07T17:17:21Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Sun, Jul 06, 2008 at 02:43:41AM -0700, Junio C Hamano <gitster@pobox.com> wrote:\n> > Then, you would keep an array of pointers into all_strategy[] array to\n> > represent the list of \"-s strategy\" given by the user:\n> >\n> > \tstatic struct strategy *use_strategy;\n> > \tstatic int use_strategy_alloc, use_strategy_nr;\n> \n> Sorry, I have an obvious typo here.  \"use_strategy\" will be dynamic array\n> of pointers into all_strategy[] so its definition would be:\n> \n> \tstatic struct strategy **use_strategy;\n\nI think there are two possibilities here:\n\n1) Append custom strategies to all_strategy and have only pointers in\nuse_strategy.\n\nThis is what you suggest in your second mail.\n\n2) Copy the names and attributes from all_strategy to use_strategies and\nappend custom strategies there.\n\nThis is what I do at the moment.\n\nI think it's better not to modify all_strategy, it serves as a\nreference, for example later this would allow us to check if the used\nmerge strategy is a predefined or a custom one.\n\nOr is there any strong reason introducing all_strategy_alloc,\nall_strategy_nr and using ALLOC_GROW() with all_strategy instead of with\nuse_strategy?\n\nThanks.\n"},{"id":"82472","messageId":"1215451460-1681-1-git-send-email-vmiklos@frugalware.org","threadId":"14238","inReplyTo":"7vej67jt1e.fsf@gitster.siamese.dyndns.org","subject":"[PATCH] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-07T17:24:20Z","receivedAt":"2008-07-07T17:24:20Z","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\nOn Sun, Jul 06, 2008 at 01:50:05AM -0700, Junio C Hamano <gitster@pobox.com> wrote:\n> But more problematic is that a path_list is inherently a dynamic data\n> structure (you can add and it reallocs), and this use of relying on\n> the\n> knowledge that you happen to never add anything (nor subtract\n> anything)\n> from the list is a mere hack.  If on the other hand you (and more\n> importantly other people who touch this implementation later) will\n> never\n> add or remove items from this \"strategies\" array, you should make sure\n> at\n> the interface level that nobody can -- one way to do so is not to\n> abuse\n> path_list for something like this.\n>\n> Come to think of it, wasn't the reason why the earlier \"Why do you\n> need\n> such distracting casts all over the place?\" issue came up in another\n> patch\n> because of this kind of (ab)use of path_list, which is an\n> inappropriate\n> data structure for the job?\n\nHere is an updated version without using path_list at all.\n\n Makefile                                      |    2 +-\n builtin-merge.c                               | 1153 +++++++++++++++++++++++++\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, 1157 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..7312997\n--- /dev/null\n+++ b/builtin-merge.c\n@@ -0,0 +1,1153 @@\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 \"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+#define DEFAULT_TWOHEAD (1<<0)\n+#define DEFAULT_OCTOPUS (1<<1)\n+#define NO_FAST_FORWARD (1<<2)\n+#define NO_TRIVIAL      (1<<3)\n+\n+struct strategy {\n+\tconst char *name;\n+\tunsigned attr;\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 strategy *use_strategies;\n+static size_t use_strategies_nr, use_strategies_alloc;\n+static const char *branch;\n+\n+static struct strategy all_strategy[] = {\n+\t{ \"recur\",      NO_TRIVIAL },\n+\t{ \"recursive\",  DEFAULT_TWOHEAD | NO_TRIVIAL },\n+\t{ \"octopus\",    DEFAULT_OCTOPUS },\n+\t{ \"resolve\",    0 },\n+\t{ \"stupid\",     0 },\n+\t{ \"ours\",       NO_FAST_FORWARD | NO_TRIVIAL },\n+\t{ \"subtree\",    NO_FAST_FORWARD | NO_TRIVIAL },\n+};\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 int strategy_lookup(const char *path)\n+{\n+\tint i;\n+\n+\tif (!path)\n+\t\treturn -1;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n+\t\tif (!strcmp(path, all_strategy[i].name))\n+\t\t\treturn all_strategy[i].attr;\n+\treturn -1;\n+}\n+\n+static inline void append_strategy(const char *name, unsigned attr)\n+{\n+\tALLOC_GROW(use_strategies, use_strategies_nr + 1, use_strategies_alloc);\n+\tuse_strategies[use_strategies_nr].name = name;\n+\tuse_strategies[use_strategies_nr++].attr = attr;\n+}\n+\n+static int option_parse_strategy(const struct option *opt,\n+\tconst char *arg, int unset)\n+{\n+\tint i, attr;\n+\n+\tif (unset)\n+\t\treturn 0;\n+\n+\tattr = strategy_lookup(arg);\n+\n+\tif (attr >= 0)\n+\t\tappend_strategy(arg, attr);\n+\telse {\n+\t\tstruct strbuf err;\n+\t\tstrbuf_init(&err, 0);\n+\t\tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n+\t\t\tstrbuf_addf(&err, \" %s\", all_strategy[i].name);\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, early;\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+\n+\t/* See if remote matches <name>^^^.. or <name>~<number> */\n+\tfor (len = 0, ptr = remote + strlen(remote);\n+\t     remote < ptr && ptr[-1] == '^';\n+\t     ptr--)\n+\t\tlen++;\n+\tif (len)\n+\t\tearly = 1;\n+\telse {\n+\t\tearly = 0;\n+\t\tptr = strrchr(remote, '~');\n+\t\tif (ptr) {\n+\t\t\tint seen_nonzero = 0;\n+\n+\t\t\tlen++; /* count ~ */\n+\t\t\twhile (*++ptr && isdigit(*ptr)) {\n+\t\t\t\tseen_nonzero |= (*ptr != '0');\n+\t\t\t\tlen++;\n+\t\t\t}\n+\t\t\tif (*ptr)\n+\t\t\t\tlen = 0; /* not ...~<number> */\n+\t\t\telse if (seen_nonzero)\n+\t\t\t\tearly = 1;\n+\t\t\telse if (len == 1)\n+\t\t\t\tearly = 1; /* \"name~\" is \"name~1\"! */\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'%s of .\\n\",\n+\t\t\t\t    sha1_to_hex(remote_head->sha1),\n+\t\t\t\t    truname.buf,\n+\t\t\t\t    (early ? \" (early part)\" : \"\"));\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+\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(const 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 strategy **list,\n+\t\tint *nr, int *alloc)\n+{\n+\tchar *p, *q, *buf;\n+\n+\tif (!string)\n+\t\treturn;\n+\n+\tbuf = xstrdup(string);\n+\tq = buf;\n+\tfor (;;) {\n+\t\tp = strchr(q, ' ');\n+\t\tif (!p) {\n+\t\t\tALLOC_GROW(*list, *nr + 1, *alloc);\n+\t\t\t(*list)[(*nr)++].name = xstrdup(q);\n+\t\t\tfree(buf);\n+\t\t\treturn;\n+\t\t} else {\n+\t\t\t*p = '\\0';\n+\t\t\tALLOC_GROW(*list, *nr + 1, *alloc);\n+\t\t\t(*list)[(*nr)++].name = xstrdup(q);\n+\t\t\tq = ++p;\n+\t\t}\n+\t}\n+}\n+\n+static void add_strategies(const char *string, unsigned attr)\n+{\n+\tstruct strategy *list = NULL;\n+\tint list_alloc = 0, list_nr = 0, i;\n+\n+\tmemset(&list, 0, sizeof(list));\n+\tsplit_merge_strategies(string, &list, &list_nr, &list_alloc);\n+\tif (list != NULL) {\n+\t\tfor (i = 0; i < list_nr; i++) {\n+\t\t\tint attr;\n+\n+\t\t\tattr = strategy_lookup(list[i].name);\n+\t\t\tif (attr >= 0)\n+\t\t\t\tappend_strategy(list[i].name, attr);\n+\t\t}\n+\t\treturn;\n+\t}\n+\tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n+\t\tif (all_strategy[i].attr & attr)\n+\t\t\tappend_strategy(all_strategy[i].name,\n+\t\t\t\tall_strategy[i].attr);\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+\tconst char *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);\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 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+\tconst char *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 && !prefixcmp(branch, \"refs/heads/\"))\n+\t\tbranch += 11;\n+\tif (is_null_sha1(head))\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) {\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 (use_strategies[i].attr & NO_FAST_FORWARD)\n+\t\t\tallow_fast_forward = 0;\n+\t\tif (use_strategies[i].attr & 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[i].name);\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[i].name;\n+\n+\t\tret = try_merge_strategy(use_strategies[i].name,\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 = use_strategies[i].name;\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[0].name);\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);\n+\t\ttry_merge_strategy(best_strategy, 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.322.ge904b.dirty\n"},{"id":"82473","messageId":"20080707173559.GU4729@genesis.frugalware.org","threadId":"14238","inReplyTo":"1215451460-1681-1-git-send-email-vmiklos@frugalware.org","subject":"Re: [PATCH] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-07T17:35:59Z","receivedAt":"2008-07-07T17:35:59Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Mon, Jul 07, 2008 at 07:24:20PM +0200, Miklos Vajna <vmiklos@frugalware.org> wrote:\n> Here is an updated version without using path_list at all.\n\nSorry forgot the interdiff and the log:\n\n- interdiff: git diff 2ed1884..10d5724\n\n- log: git log c255d12 (1 commit)\n\n$ git grep -c path.list builtin-merge.c\n0\n"},{"id":"82476","messageId":"7vhcb14l3m.fsf@gitster.siamese.dyndns.org","threadId":"14238","inReplyTo":"20080707171721.GT4729@genesis.frugalware.org","subject":"Re: [PATCH 14/14] Build in merge","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-07T18:15:09Z","receivedAt":"2008-07-07T18:15:09Z","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> I think it's better not to modify all_strategy, it serves as a\n> reference, for example later this would allow us to check if the used\n> merge strategy is a predefined or a custom one.\n\nI do not get you on this point.  Which one is nicer?\n\n (1) Have two lists, perhaps all_* and user_*.  The logic that finds a\n     strategy searches in two lists.  The logic that checks if a given\n     strategy is built-in checks if it is on all_* list.\n\n (2) Have a single list, but add a boolean \"unsigned is_builtin:1\" to each\n     element of it.  The logic that finds a strategy looks in this single\n     list.  The logic that checks if a given strategy is built-in looks at\n     the strategy instance and it has the bit already.\n\nYou seem to be advocating (1) but I do not understand why...\n"},{"id":"82504","messageId":"1215474140-11220-1-git-send-email-vmiklos@frugalware.org","threadId":"14238","inReplyTo":"7vhcb14l3m.fsf@gitster.siamese.dyndns.org","subject":"[PATCH] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-07T23:42:20Z","receivedAt":"2008-07-07T23:42:20Z","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\nOn Mon, Jul 07, 2008 at 11:15:09AM -0700, Junio C Hamano <gitster@pobox.com> wrote:\n> I do not get you on this point.  Which one is nicer?\n>\n>  (1) Have two lists, perhaps all_* and user_*.  The logic that finds a\n>      strategy searches in two lists.  The logic that checks if a given\n>      strategy is built-in checks if it is on all_* list.\n>\n>  (2) Have a single list, but add a boolean \"unsigned is_builtin:1\" to\n>  each\n>      element of it.  The logic that finds a strategy looks in this\n>      single\n>      list.  The logic that checks if a given strategy is built-in\n>      looks at\n>      the strategy instance and it has the bit already.\n>\n> You seem to be advocating (1) but I do not understand why...\n\nAh, OK. For now, I just added an \"unsigned enabled:1;\". Later we can add\nan \"unsigned is_buildin:1;\" as well, but currently we die with earlier\nwith a \"Could not find merge strategy\" error message, so is_builtin\nwould be always true.\n\nSo here is a version, this time without the use_strategies list.\n\nInterdiff: git diff 638c51f..1e74660\n\n Makefile                                      |    2 +-\n builtin-merge.c                               | 1142 +++++++++++++++++++++++++\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, 1146 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..6d801dd\n--- /dev/null\n+++ b/builtin-merge.c\n@@ -0,0 +1,1142 @@\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 \"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+#define DEFAULT_TWOHEAD (1<<0)\n+#define DEFAULT_OCTOPUS (1<<1)\n+#define NO_FAST_FORWARD (1<<2)\n+#define NO_TRIVIAL      (1<<3)\n+\n+struct strategy {\n+\tconst char *name;\n+\tunsigned attr;\n+\tunsigned enabled:1;\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 const char *branch;\n+\n+static struct strategy all_strategy[] = {\n+\t{ \"recur\",      NO_TRIVIAL, 0 },\n+\t{ \"recursive\",  DEFAULT_TWOHEAD | NO_TRIVIAL, 0 },\n+\t{ \"octopus\",    DEFAULT_OCTOPUS, 0 },\n+\t{ \"resolve\",    0, 0 },\n+\t{ \"stupid\",     0, 0 },\n+\t{ \"ours\",       NO_FAST_FORWARD | NO_TRIVIAL, 0 },\n+\t{ \"subtree\",    NO_FAST_FORWARD | NO_TRIVIAL, 0 },\n+};\n+/*\n+ * This contains the number of enabled variables, so you don't have to\n+ * scan through all_strategies all the time.\n+ */\n+static int enabled_strategies;\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 void enable_strategy(const char *name)\n+{\n+\tint i;\n+\tstruct strbuf err;\n+\n+\tenabled_strategies++;\n+\tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n+\t\tif (!strcmp(all_strategy[i].name, name)) {\n+\t\t\tall_strategy[i].enabled = 1;\n+\t\t\treturn;\n+\t\t}\n+\n+\tstrbuf_init(&err, 0);\n+\tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n+\t\tstrbuf_addf(&err, \" %s\", all_strategy[i].name);\n+\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\", name);\n+\tfprintf(stderr, \"Available strategies are:%s.\\n\", err.buf);\n+\texit(1);\n+}\n+\n+static int option_parse_strategy(const struct option *opt,\n+\tconst char *arg, int unset)\n+{\n+\tif (unset)\n+\t\treturn 0;\n+\n+\tenable_strategy(arg);\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\", &all_strategy, \"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, early;\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+\n+\t/* See if remote matches <name>^^^.. or <name>~<number> */\n+\tfor (len = 0, ptr = remote + strlen(remote);\n+\t     remote < ptr && ptr[-1] == '^';\n+\t     ptr--)\n+\t\tlen++;\n+\tif (len)\n+\t\tearly = 1;\n+\telse {\n+\t\tearly = 0;\n+\t\tptr = strrchr(remote, '~');\n+\t\tif (ptr) {\n+\t\t\tint seen_nonzero = 0;\n+\n+\t\t\tlen++; /* count ~ */\n+\t\t\twhile (*++ptr && isdigit(*ptr)) {\n+\t\t\t\tseen_nonzero |= (*ptr != '0');\n+\t\t\t\tlen++;\n+\t\t\t}\n+\t\t\tif (*ptr)\n+\t\t\t\tlen = 0; /* not ...~<number> */\n+\t\t\telse if (seen_nonzero)\n+\t\t\t\tearly = 1;\n+\t\t\telse if (len == 1)\n+\t\t\t\tearly = 1; /* \"name~\" is \"name~1\"! */\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'%s of .\\n\",\n+\t\t\t\t    sha1_to_hex(remote_head->sha1),\n+\t\t\t\t    truname.buf,\n+\t\t\t\t    (early ? \" (early part)\" : \"\"));\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+\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(const 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 strategy **list,\n+\t\tint *nr, int *alloc)\n+{\n+\tchar *p, *q, *buf;\n+\n+\tif (!string)\n+\t\treturn;\n+\n+\tbuf = xstrdup(string);\n+\tq = buf;\n+\tfor (;;) {\n+\t\tp = strchr(q, ' ');\n+\t\tif (!p) {\n+\t\t\tALLOC_GROW(*list, *nr + 1, *alloc);\n+\t\t\t(*list)[(*nr)++].name = xstrdup(q);\n+\t\t\tfree(buf);\n+\t\t\treturn;\n+\t\t} else {\n+\t\t\t*p = '\\0';\n+\t\t\tALLOC_GROW(*list, *nr + 1, *alloc);\n+\t\t\t(*list)[(*nr)++].name = xstrdup(q);\n+\t\t\tq = ++p;\n+\t\t}\n+\t}\n+}\n+\n+static void add_strategies(const char *string, unsigned attr)\n+{\n+\tstruct strategy *list = NULL;\n+\tint list_alloc = 0, list_nr = 0, i;\n+\n+\tmemset(&list, 0, sizeof(list));\n+\tsplit_merge_strategies(string, &list, &list_nr, &list_alloc);\n+\tif (list != NULL) {\n+\t\tfor (i = 0; i < list_nr; i++)\n+\t\t\tenable_strategy(list[i].name);\n+\t\treturn;\n+\t}\n+\tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n+\t\tif (all_strategy[i].attr & attr)\n+\t\t\tenable_strategy(all_strategy[i].name);\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+\tconst char *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);\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 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, first_strategy = 1;\n+\tint best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;\n+\tstruct commit_list *common = NULL;\n+\tconst char *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 && !prefixcmp(branch, \"refs/heads/\"))\n+\t\tbranch += 11;\n+\tif (is_null_sha1(head))\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 (!enabled_strategies) {\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 < ARRAY_SIZE(all_strategy); i++) {\n+\t\tif (!all_strategy[i].enabled)\n+\t\t\tcontinue;\n+\t\tif (all_strategy[i].attr & NO_FAST_FORWARD)\n+\t\t\tallow_fast_forward = 0;\n+\t\tif (all_strategy[i].attr & 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 (enabled_strategies != 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 < ARRAY_SIZE(all_strategy); i++) {\n+\t\tint ret;\n+\t\tif (!all_strategy[i].enabled)\n+\t\t\tcontinue;\n+\t\tif (first_strategy) {\n+\t\t\tfirst_strategy = 0;\n+\t\t\tprintf(\"Rewinding the tree to pristine...\\n\");\n+\t\t\trestore_state();\n+\t\t}\n+\t\tif (enabled_strategies != 1)\n+\t\t\tprintf(\"Trying merge strategy %s...\\n\",\n+\t\t\t\tall_strategy[i].name);\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 = all_strategy[i].name;\n+\n+\t\tret = try_merge_strategy(all_strategy[i].name,\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 = all_strategy[i].name;\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 (enabled_strategies > 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\twt_strategy);\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);\n+\t\ttry_merge_strategy(best_strategy, 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.322.ge904b.dirty\n"},{"id":"82509","messageId":"7v63rhz03x.fsf@gitster.siamese.dyndns.org","threadId":"14238","inReplyTo":"1215474140-11220-1-git-send-email-vmiklos@frugalware.org","subject":"Re: [PATCH] Build in merge","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-08T00:32:50Z","receivedAt":"2008-07-08T00:32:50Z","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> Mentored-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n> Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>\n> ---\n>\n> On Mon, Jul 07, 2008 at 11:15:09AM -0700, Junio C Hamano <gitster@pobox.com> wrote:\n>> I do not get you on this point.  Which one is nicer?\n>>\n>>  (1) Have two lists, perhaps all_* and user_*.  The logic that finds a\n>>      strategy searches in two lists.  The logic that checks if a given\n>>      strategy is built-in checks if it is on all_* list.\n>>\n>>  (2) Have a single list, but add a boolean \"unsigned is_builtin:1\" to\n>>  each\n>>      element of it.  The logic that finds a strategy looks in this\n>>      single\n>>      list.  The logic that checks if a given strategy is built-in\n>>      looks at\n>>      the strategy instance and it has the bit already.\n>>\n>> You seem to be advocating (1) but I do not understand why...\n>\n> Ah, OK. For now, I just added an \"unsigned enabled:1;\". Later we can add\n> an \"unsigned is_buildin:1;\" as well, but currently we die with earlier\n> with a \"Could not find merge strategy\" error message, so is_builtin\n> would be always true.\n>\n> So here is a version, this time without the use_strategies list.\n\nThat is not what I meant.  I am afraid perhaps I misunderstood what you\nwere talking about.\n\nWhen/if you allow user defined new strategies, then you have a choice:\n\n (1) find \"git-merge-*\" in path, add them to the single all_strategies[]\n     list (but you will do the ALLOC_GROW() business so you would need to\n     use the one you currently have as static form to prime the real list),\n     and look for \"foo\" strategy when \"-s foo\" is given from that single\n     list, or\n\n (2) find \"git-merge-*\" in path, add them to a separate user_strategies[]\n     list, and look for \"foo\" strategy when \"-s foo\" is given from the\n     user_strategies[] list and all_strategies[] list (all_strategies[]\n     should perhaps be renamed to builtin_strategies[] if you go that\n     route).\n\nThe comparison I gave was between the above two.  But the change you are\ntalking about is completely different, isn't it?\n\nThe part that records which strategies were specified from the command\nline *in what order* via \"-s foo\" switches should remain list of pointers\ninto \"struct strategy\", which is called \"struct strategy **use_strategies\"\nin the code and corresponds to the $use_strategies variable in the\nscripted version.  The order of these is important, as that defines in\nwhich order the strategies are tried [*1*].  If you go route (1), these\npointers will all be pointing at elements in all_strategies[]; with route\n(2) they may be pointing at either all_strageties[] element or\nuser_strategies[] element.\n\nIf you are never going to say \"available strategies are these\" after you\nstart supporting user-defined strategy, then you do not necessarily need\nto do the \"find 'git-merge-*' in path, add them to ...\" step above, in\nwhich case it would be Ok not to scan the path and add them to\nall_strategies[] (in route (1)) nor user_strategies[] (in route (2)).\nInstead, you would just create a new \"struct strategy\" instance lazily\nwhen the user gave \"-s foo\" and \"foo\" is not one of the built-in strategy.\nYou would put that at the tail of \"struct strategy **use_strategy\" array,\nand iterate over use_strategy in the order they are given on the command\nline.\n\n\n[Footnote]\n\n*1* Personally, I find the importance of this dubious in practice, as I\nsaid earlier, I do not think it would work well to try different\nstrategies and pick the best one --- evaluating which result is the *best*\nis difficult.  If you want to stay compatible with the scripted version,\nhowever, you cannot just mark entries in all_strategies[] with boolean and\niterate over them in the order that all_strageties[] define them.  You\nneed to try them in the order the user specified.\n"},{"id":"82512","messageId":"7v1w25yz5o.fsf@gitster.siamese.dyndns.org","threadId":"14238","inReplyTo":"7v63rhz03x.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] Build in merge","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-08T00:53:23Z","receivedAt":"2008-07-08T00:53:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> That is not what I meant.  I am afraid perhaps I misunderstood what you\n> were talking about.\n> ...\n> The comparison I gave was between the above two.  But the change you are\n> talking about is completely different, isn't it?\n>\n> The part that records which strategies were specified from the command\n> line *in what order* via \"-s foo\" switches should remain list of pointers\n> into \"struct strategy\", which is called \"struct strategy **use_strategies\"\n> in the code and corresponds to the $use_strategies variable in the\n> scripted version.\n\nHere is what I meant to suggest; sorry for confusing you with an initial\ntypo of having only one pointer in front of use_strategies \"array of\npointers\".  Applies on top of your previous round.\n\n--\n\n builtin-merge.c |   58 +++++++++++++++++++++++++++---------------------------\n 1 files changed, 29 insertions(+), 29 deletions(-)\n\ndiff --git a/builtin-merge.c b/builtin-merge.c\nindex 7312997..b2e702a 100644\n--- a/builtin-merge.c\n+++ b/builtin-merge.c\n@@ -44,7 +44,7 @@ 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 strategy *use_strategies;\n+static struct strategy **use_strategies;\n static size_t use_strategies_nr, use_strategies_alloc;\n static const char *branch;\n \n@@ -74,44 +74,44 @@ static int option_parse_message(const struct option *opt,\n \treturn 0;\n }\n \n-static int strategy_lookup(const char *path)\n+static struct strategy *get_strategy(const char *name)\n {\n \tint i;\n \n-\tif (!path)\n-\t\treturn -1;\n+\tif (!name)\n+\t\treturn NULL;\n \n \tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n-\t\tif (!strcmp(path, all_strategy[i].name))\n-\t\t\treturn all_strategy[i].attr;\n-\treturn -1;\n+\t\tif (!strcmp(name, all_strategy[i].name))\n+\t\t\treturn &all_strategy[i];\n+\treturn NULL;\n }\n \n-static inline void append_strategy(const char *name, unsigned attr)\n+static void append_strategy(struct strategy *s)\n {\n \tALLOC_GROW(use_strategies, use_strategies_nr + 1, use_strategies_alloc);\n-\tuse_strategies[use_strategies_nr].name = name;\n-\tuse_strategies[use_strategies_nr++].attr = attr;\n+\tuse_strategies[use_strategies_nr++] = s;\n }\n \n static int option_parse_strategy(const struct option *opt,\n-\tconst char *arg, int unset)\n+\t\t\t\t const char *name, int unset)\n {\n-\tint i, attr;\n+\tint i;\n+\tstruct strategy *s;\n \n \tif (unset)\n \t\treturn 0;\n \n-\tattr = strategy_lookup(arg);\n+\ts = get_strategy(name);\n \n-\tif (attr >= 0)\n-\t\tappend_strategy(arg, attr);\n+\tif (s)\n+\t\tappend_strategy(s);\n \telse {\n \t\tstruct strbuf err;\n \t\tstrbuf_init(&err, 0);\n \t\tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n \t\t\tstrbuf_addf(&err, \" %s\", all_strategy[i].name);\n-\t\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\", arg);\n+\t\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\", name);\n \t\tfprintf(stderr, \"Available strategies are:%s.\\n\", err.buf);\n \t\texit(1);\n \t}\n@@ -643,18 +643,18 @@ static void add_strategies(const char *string, unsigned attr)\n \tsplit_merge_strategies(string, &list, &list_nr, &list_alloc);\n \tif (list != NULL) {\n \t\tfor (i = 0; i < list_nr; i++) {\n-\t\t\tint attr;\n+\t\t\tstruct strategy *s;\n \n-\t\t\tattr = strategy_lookup(list[i].name);\n-\t\t\tif (attr >= 0)\n-\t\t\t\tappend_strategy(list[i].name, attr);\n+\t\t\ts = get_strategy(list[i].name);\n+\t\t\tif (s)\n+\t\t\t\tappend_strategy(s);\n \t\t}\n \t\treturn;\n \t}\n \tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n \t\tif (all_strategy[i].attr & attr)\n-\t\t\tappend_strategy(all_strategy[i].name,\n-\t\t\t\tall_strategy[i].attr);\n+\t\t\tappend_strategy(&all_strategy[i]);\n+\n }\n \n static int merge_trivial(void)\n@@ -903,9 +903,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t}\n \n \tfor (i = 0; i < use_strategies_nr; i++) {\n-\t\tif (use_strategies[i].attr & NO_FAST_FORWARD)\n+\t\tif (use_strategies[i]->attr & NO_FAST_FORWARD)\n \t\t\tallow_fast_forward = 0;\n-\t\tif (use_strategies[i].attr & NO_TRIVIAL)\n+\t\tif (use_strategies[i]->attr & NO_TRIVIAL)\n \t\t\tallow_trivial = 0;\n \t}\n \n@@ -1043,14 +1043,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\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[i].name);\n+\t\t\t\tuse_strategies[i]->name);\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[i].name;\n+\t\twt_strategy = use_strategies[i]->name;\n \n-\t\tret = try_merge_strategy(use_strategies[i].name,\n+\t\tret = try_merge_strategy(use_strategies[i]->name,\n \t\t\tcommon, head_arg);\n \t\tif (!option_commit && !ret) {\n \t\t\tmerge_was_ok = 1;\n@@ -1072,7 +1072,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\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 = use_strategies[i].name;\n+\t\t\t\t\tbest_strategy = use_strategies[i]->name;\n \t\t\t\t\tbest_cnt = cnt;\n \t\t\t\t}\n \t\t\t}\n@@ -1106,7 +1106,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\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[0].name);\n+\t\t\t\tuse_strategies[0]->name);\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"},{"id":"82514","messageId":"20080708010007.GA10347@genesis.frugalware.org","threadId":"14238","inReplyTo":"7v63rhz03x.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-08T01:00:07Z","receivedAt":"2008-07-08T01:00:07Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Mon, Jul 07, 2008 at 05:32:50PM -0700, Junio C Hamano <gitster@pobox.com> wrote:\n> > So here is a version, this time without the use_strategies list.\n> \n> That is not what I meant.  I am afraid perhaps I misunderstood what you\n> were talking about.\n> \n> When/if you allow user defined new strategies, then you have a choice:\n> \n>  (1) find \"git-merge-*\" in path, add them to the single all_strategies[]\n>      list (but you will do the ALLOC_GROW() business so you would need to\n>      use the one you currently have as static form to prime the real list),\n>      and look for \"foo\" strategy when \"-s foo\" is given from that single\n>      list, or\n> \n>  (2) find \"git-merge-*\" in path, add them to a separate user_strategies[]\n>      list, and look for \"foo\" strategy when \"-s foo\" is given from the\n>      user_strategies[] list and all_strategies[] list (all_strategies[]\n>      should perhaps be renamed to builtin_strategies[] if you go that\n>      route).\n\nOK, I see now. Actually I think the primary problem with a custom\nstrategy is that we do not know its flags, IOW if it handles an octopus,\netc. So I think there are two questions here:\n\n1) How to tell git-merge the flags of a custom strategy? Or: is it\nnecessary at all?\n\nI could imagine the following situations:\n\n1) A project has code in a repo, some documentation and po files.\n\nThe first two can be merged with builtin strategies, the later probably\nneeds a custom merge driver.\n\nSo, in most cases recursive is fine, but sometimes the maintainer wants\nto say 'git pull -s po'.\n\nIn this case the flags of 'po' does not really matter.\n\n2) Someone is not happy with the current recursive strategy and writes\nfrom scratch a new one. He/she puts it to pull.twohead, so it will be\ntried before recursive.\n\nTo sum up: I am not sure what would be the benefit of being able to\nspecify flags for strategies. However, if we want so, it would be good\nto discuss how it should be done.\n\n> The part that records which strategies were specified from the command\n> line *in what order* via \"-s foo\" switches should remain list of pointers\n> into \"struct strategy\", which is called \"struct strategy **use_strategies\"\n> in the code and corresponds to the $use_strategies variable in the\n> scripted version.  The order of these is important, as that defines in\n> which order the strategies are tried [*1*].  If you go route (1), these\n> pointers will all be pointing at elements in all_strategies[]; with route\n> (2) they may be pointing at either all_strageties[] element or\n> user_strategies[] element.\n\nI see the problem, I lost the order at the moment.\n\n> If you are never going to say \"available strategies are these\" after you\n> start supporting user-defined strategy, then you do not necessarily need\n> to do the \"find 'git-merge-*' in path, add them to ...\" step above, in\n> which case it would be Ok not to scan the path and add them to\n> all_strategies[] (in route (1)) nor user_strategies[] (in route (2)).\n> Instead, you would just create a new \"struct strategy\" instance lazily\n> when the user gave \"-s foo\" and \"foo\" is not one of the built-in strategy.\n> You would put that at the tail of \"struct strategy **use_strategy\" array,\n> and iterate over use_strategy in the order they are given on the command\n> line.\n\nI guess it would be nice to adjust the error message and scanning path,\nbut that's something - I guess - that should be done after the rewrite\nis complete and there are no more issues with it.\n"},{"id":"82516","messageId":"7vskulxk0o.fsf@gitster.siamese.dyndns.org","threadId":"14238","inReplyTo":"20080708010007.GA10347@genesis.frugalware.org","subject":"Re: [PATCH] Build in merge","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-07-08T01:05:43Z","receivedAt":"2008-07-08T01:05:43Z","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> I could imagine the following situations:\n>\n> 1) A project has code in a repo, some documentation and po files.\n>\n> The first two can be merged with builtin strategies, the later probably\n> needs a custom merge driver.\n\nPer-path merge is probably better handled with custom ll-merge driver\nanyway.  See gitattributes(5).\n\n> 2) Someone is not happy with the current recursive strategy and writes\n> from scratch a new one. He/she puts it to pull.twohead, so it will be\n> tried before recursive.\n\nThat is fine.\n\n> To sum up: I am not sure what would be the benefit of being able to\n> specify flags for strategies. However, if we want so, it would be good\n> to discuss how it should be done.\n\nIt wasn't *me* ;-) who wanted to add these \"flags\".\n\nI think it does not matter what \"my-strategy\" does unless \"-s my-strategy\"\n(or pull.twohead) is explicitly given by the user, and at that time,\nDEFAULT_* options should not matter.  It probably is Ok to allow fast\nforward and trivial merges to them.  We'll see.\n\n>> The part that records which strategies were specified from the command\n>> line *in what order* via \"-s foo\" switches should remain list of pointers\n>> into \"struct strategy\", which is called \"struct strategy **use_strategies\"\n>> in the code and corresponds to the $use_strategies variable in the\n>> scripted version.  The order of these is important, as that defines in\n>> which order the strategies are tried [*1*].  If you go route (1), these\n>> pointers will all be pointing at elements in all_strategies[]; with route\n>> (2) they may be pointing at either all_strageties[] element or\n>> user_strategies[] element.\n>\n> I see the problem, I lost the order at the moment.\n\nThat's Ok.  See the other patch on top of your previous one.\n"},{"id":"82520","messageId":"1215479888-31492-1-git-send-email-vmiklos@frugalware.org","threadId":"14238","inReplyTo":"7v1w25yz5o.fsf@gitster.siamese.dyndns.org","subject":"[PATCH] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-08T01:18:08Z","receivedAt":"2008-07-08T01:18:08Z","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\nOn Mon, Jul 07, 2008 at 05:53:23PM -0700, Junio C Hamano <gitster@pobox.com> wrote:\n> Here is what I meant to suggest; sorry for confusing you with an\n> initial\n> typo of having only one pointer in front of use_strategies \"array of\n> pointers\".  Applies on top of your previous round.\n\nFunny enough, I just did almost the same before reading your mail,\nexcept that I did not do the suggested strategy_lookup() ->\nget_strategy() rename and such.\n\nHere is a squashed patch. (Previous round + your patch.)\n\n Makefile                                      |    2 +-\n builtin-merge.c                               | 1153 +++++++++++++++++++++++++\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, 1157 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..d6bd144\n--- /dev/null\n+++ b/builtin-merge.c\n@@ -0,0 +1,1153 @@\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 \"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+#define DEFAULT_TWOHEAD (1<<0)\n+#define DEFAULT_OCTOPUS (1<<1)\n+#define NO_FAST_FORWARD (1<<2)\n+#define NO_TRIVIAL      (1<<3)\n+\n+struct strategy {\n+\tconst char *name;\n+\tunsigned attr;\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 strategy **use_strategies;\n+static size_t use_strategies_nr, use_strategies_alloc;\n+static const char *branch;\n+\n+static struct strategy all_strategy[] = {\n+\t{ \"recur\",      NO_TRIVIAL },\n+\t{ \"recursive\",  DEFAULT_TWOHEAD | NO_TRIVIAL },\n+\t{ \"octopus\",    DEFAULT_OCTOPUS },\n+\t{ \"resolve\",    0 },\n+\t{ \"stupid\",     0 },\n+\t{ \"ours\",       NO_FAST_FORWARD | NO_TRIVIAL },\n+\t{ \"subtree\",    NO_FAST_FORWARD | NO_TRIVIAL },\n+};\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 strategy *get_strategy(const char *name)\n+{\n+\tint i;\n+\n+\tif (!name)\n+\t\treturn NULL;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n+\t\tif (!strcmp(name, all_strategy[i].name))\n+\t\t\treturn &all_strategy[i];\n+\treturn NULL;\n+}\n+\n+static void append_strategy(struct strategy *s)\n+{\n+\tALLOC_GROW(use_strategies, use_strategies_nr + 1, use_strategies_alloc);\n+\tuse_strategies[use_strategies_nr++] = s;\n+}\n+\n+static int option_parse_strategy(const struct option *opt,\n+\t\t\t\t const char *name, int unset)\n+{\n+\tint i;\n+\tstruct strategy *s;\n+\n+\tif (unset)\n+\t\treturn 0;\n+\n+\ts = get_strategy(name);\n+\n+\tif (s)\n+\t\tappend_strategy(s);\n+\telse {\n+\t\tstruct strbuf err;\n+\t\tstrbuf_init(&err, 0);\n+\t\tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n+\t\t\tstrbuf_addf(&err, \" %s\", all_strategy[i].name);\n+\t\tfprintf(stderr, \"Could not find merge strategy '%s'.\\n\", name);\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, early;\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+\n+\t/* See if remote matches <name>^^^.. or <name>~<number> */\n+\tfor (len = 0, ptr = remote + strlen(remote);\n+\t     remote < ptr && ptr[-1] == '^';\n+\t     ptr--)\n+\t\tlen++;\n+\tif (len)\n+\t\tearly = 1;\n+\telse {\n+\t\tearly = 0;\n+\t\tptr = strrchr(remote, '~');\n+\t\tif (ptr) {\n+\t\t\tint seen_nonzero = 0;\n+\n+\t\t\tlen++; /* count ~ */\n+\t\t\twhile (*++ptr && isdigit(*ptr)) {\n+\t\t\t\tseen_nonzero |= (*ptr != '0');\n+\t\t\t\tlen++;\n+\t\t\t}\n+\t\t\tif (*ptr)\n+\t\t\t\tlen = 0; /* not ...~<number> */\n+\t\t\telse if (seen_nonzero)\n+\t\t\t\tearly = 1;\n+\t\t\telse if (len == 1)\n+\t\t\t\tearly = 1; /* \"name~\" is \"name~1\"! */\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'%s of .\\n\",\n+\t\t\t\t    sha1_to_hex(remote_head->sha1),\n+\t\t\t\t    truname.buf,\n+\t\t\t\t    (early ? \" (early part)\" : \"\"));\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+\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(const 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 strategy **list,\n+\t\tint *nr, int *alloc)\n+{\n+\tchar *p, *q, *buf;\n+\n+\tif (!string)\n+\t\treturn;\n+\n+\tbuf = xstrdup(string);\n+\tq = buf;\n+\tfor (;;) {\n+\t\tp = strchr(q, ' ');\n+\t\tif (!p) {\n+\t\t\tALLOC_GROW(*list, *nr + 1, *alloc);\n+\t\t\t(*list)[(*nr)++].name = xstrdup(q);\n+\t\t\tfree(buf);\n+\t\t\treturn;\n+\t\t} else {\n+\t\t\t*p = '\\0';\n+\t\t\tALLOC_GROW(*list, *nr + 1, *alloc);\n+\t\t\t(*list)[(*nr)++].name = xstrdup(q);\n+\t\t\tq = ++p;\n+\t\t}\n+\t}\n+}\n+\n+static void add_strategies(const char *string, unsigned attr)\n+{\n+\tstruct strategy *list = NULL;\n+\tint list_alloc = 0, list_nr = 0, i;\n+\n+\tmemset(&list, 0, sizeof(list));\n+\tsplit_merge_strategies(string, &list, &list_nr, &list_alloc);\n+\tif (list != NULL) {\n+\t\tfor (i = 0; i < list_nr; i++) {\n+\t\t\tstruct strategy *s;\n+\n+\t\t\ts = get_strategy(list[i].name);\n+\t\t\tif (s)\n+\t\t\t\tappend_strategy(s);\n+\t\t}\n+\t\treturn;\n+\t}\n+\tfor (i = 0; i < ARRAY_SIZE(all_strategy); i++)\n+\t\tif (all_strategy[i].attr & attr)\n+\t\t\tappend_strategy(&all_strategy[i]);\n+\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+\tconst char *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);\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 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+\tconst char *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 && !prefixcmp(branch, \"refs/heads/\"))\n+\t\tbranch += 11;\n+\tif (is_null_sha1(head))\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) {\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 (use_strategies[i]->attr & NO_FAST_FORWARD)\n+\t\t\tallow_fast_forward = 0;\n+\t\tif (use_strategies[i]->attr & 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[i]->name);\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[i]->name;\n+\n+\t\tret = try_merge_strategy(use_strategies[i]->name,\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 = use_strategies[i]->name;\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[0]->name);\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);\n+\t\ttry_merge_strategy(best_strategy, 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.322.ge904b.dirty\n"},{"id":"82522","messageId":"20080708014109.GC10347@genesis.frugalware.org","threadId":"14238","inReplyTo":"7vskulxk0o.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-07-08T01:41:09Z","receivedAt":"2008-07-08T01:41:09Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Mon, Jul 07, 2008 at 06:05:43PM -0700, Junio C Hamano <gitster@pobox.com> wrote:\n> > 1) A project has code in a repo, some documentation and po files.\n> >\n> > The first two can be merged with builtin strategies, the later probably\n> > needs a custom merge driver.\n> \n> Per-path merge is probably better handled with custom ll-merge driver\n> anyway.  See gitattributes(5).\n\nAh, thanks. I did not know ll-merge supports custom drivers as well.\n\n> It wasn't *me* ;-) who wanted to add these \"flags\".\n> \n> I think it does not matter what \"my-strategy\" does unless \"-s my-strategy\"\n> (or pull.twohead) is explicitly given by the user, and at that time,\n> DEFAULT_* options should not matter.  It probably is Ok to allow fast\n> forward and trivial merges to them.  We'll see.\n\nOK, so at first round I think we could avoid flags for custom\nstrategies.\n\nFor the error message, I think the output could be something like git\nhelp --all, which splits commands based on being in\nGIT_EXEC_PATH or somewhere else in PATH.\n\nAlso, currently (the shell version and the C one as well) we silently\nignore the config setting if it's set to semething invalid. What about\nchanging that to a similar error message as well?\n"}]}