{"thread":{"id":"13647","subject":"[PATCH 3/5] Make verbosity configurable in reset_index_file()","startedAt":"2008-05-24T00:01:03Z","lastAt":"2008-05-27T14:49:19Z","messageCount":10,"participants":["Miklos Vajna","Daniel Barkalow","Kristian Høgsberg"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"77617","messageId":"cover.1211586801.git.vmiklos@frugalware.org","threadId":"13647","inReplyTo":null,"subject":"[WIP PATCH 0/5] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-05-24T00:01:03Z","receivedAt":"2008-05-24T00:01:03Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Hello,\n\nThis is a work in progress patch, reflecting the current status of\nbuiltin-merge I have. As far as I know all the tests pass, but there are\nstill some work to do. In general, a few problems I'm aware of:\n\n 1) There are still TODOs/FIXMEs in the code.\n\n 2) It should be possible to avoid some exec() calls, like write-tree,\n    show-branch and fmt-merge-msg.\n\n 3) Minor memory leaks.\n\nOther than that, comments are welcome.\n\nMiklos Vajna (5):\n  Move reset_index_file() to a new reset.c\n  Move split_cmdline() to libgit\n  Make verbosity configurable in reset_index_file()\n  Move commit_list_count() to commit.c\n  Build in merge\n\n Makefile                                      |    4 +-\n alias.c                                       |   54 ++\n builtin-merge-recursive.c                     |    8 -\n builtin-merge.c                               | 1117 +++++++++++++++++++++++++\n builtin-reset.c                               |   19 +-\n builtin.h                                     |    1 +\n cache.h                                       |    1 +\n commit.c                                      |    8 +\n commit.h                                      |    1 +\n git-merge.sh => contrib/examples/git-merge.sh |    0 \n git.c                                         |   54 +--\n reset.c                                       |   29 +\n reset.h                                       |    6 +\n 13 files changed, 1223 insertions(+), 79 deletions(-)\n create mode 100644 builtin-merge.c\n rename git-merge.sh => contrib/examples/git-merge.sh (100%)\n create mode 100644 reset.c\n create mode 100644 reset.h\n"},{"id":"77618","messageId":"40d6845554a032ef66a20289aea6c7b2f157fed3.1211586801.git.vmiklos@frugalware.org","threadId":"13647","inReplyTo":"cover.1211586801.git.vmiklos@frugalware.org","subject":"[PATCH 1/5] Move reset_index_file() to a new reset.c","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-05-24T00:01:04Z","receivedAt":"2008-05-24T00:01:04Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"This is needed as we want to use it later in builtin-merge.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n Makefile        |    2 ++\n builtin-reset.c |   17 +----------------\n reset.c         |   28 ++++++++++++++++++++++++++++\n reset.h         |    6 ++++++\n 4 files changed, 37 insertions(+), 16 deletions(-)\n create mode 100644 reset.c\n create mode 100644 reset.h\n\ndiff --git a/Makefile b/Makefile\nindex a2de075..91d938a 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -364,6 +364,7 @@ LIB_H += quote.h\n LIB_H += reflog-walk.h\n LIB_H += refs.h\n LIB_H += remote.h\n+LIB_H += reset.h\n LIB_H += revision.h\n LIB_H += run-command.h\n LIB_H += sha1-lookup.h\n@@ -443,6 +444,7 @@ LIB_OBJS += read-cache.o\n LIB_OBJS += reflog-walk.o\n LIB_OBJS += refs.o\n LIB_OBJS += remote.o\n+LIB_OBJS += reset.o\n LIB_OBJS += revision.o\n LIB_OBJS += run-command.o\n LIB_OBJS += server-info.o\ndiff --git a/builtin-reset.c b/builtin-reset.c\nindex 79424bb..6e6e168 100644\n--- a/builtin-reset.c\n+++ b/builtin-reset.c\n@@ -18,6 +18,7 @@\n #include \"tree.h\"\n #include \"branch.h\"\n #include \"parse-options.h\"\n+#include \"reset.h\"\n \n static const char * const git_reset_usage[] = {\n \t\"git-reset [--mixed | --soft | --hard] [-q] [<commit>]\",\n@@ -49,22 +50,6 @@ static inline int is_merge(void)\n \treturn !access(git_path(\"MERGE_HEAD\"), F_OK);\n }\n \n-static int reset_index_file(const unsigned char *sha1, int is_hard_reset)\n-{\n-\tint i = 0;\n-\tconst char *args[6];\n-\n-\targs[i++] = \"read-tree\";\n-\targs[i++] = \"-v\";\n-\targs[i++] = \"--reset\";\n-\tif (is_hard_reset)\n-\t\targs[i++] = \"-u\";\n-\targs[i++] = sha1_to_hex(sha1);\n-\targs[i] = NULL;\n-\n-\treturn run_command_v_opt(args, RUN_GIT_CMD);\n-}\n-\n static void print_new_head_line(struct commit *commit)\n {\n \tconst char *hex, *body;\ndiff --git a/reset.c b/reset.c\nnew file mode 100644\nindex 0000000..a75fec6\n--- /dev/null\n+++ b/reset.c\n@@ -0,0 +1,28 @@\n+/*\n+ * generic fucntion(s) from the \"git reset\" builtin command\n+ *\n+ * Copyright (c) 2007 Carlos Rica\n+ *\n+ * Based on git-reset.sh, which is\n+ *\n+ * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano\n+ */\n+\n+#include \"cache.h\"\n+#include \"run-command.h\"\n+\n+int reset_index_file(const unsigned char *sha1, int is_hard_reset)\n+{\n+\tint i = 0;\n+\tconst char *args[6];\n+\n+\targs[i++] = \"read-tree\";\n+\targs[i++] = \"-v\";\n+\targs[i++] = \"--reset\";\n+\tif (is_hard_reset)\n+\t\targs[i++] = \"-u\";\n+\targs[i++] = sha1_to_hex(sha1);\n+\targs[i] = NULL;\n+\n+\treturn run_command_v_opt(args, RUN_GIT_CMD);\n+}\ndiff --git a/reset.h b/reset.h\nnew file mode 100644\nindex 0000000..4ae235b\n--- /dev/null\n+++ b/reset.h\n@@ -0,0 +1,6 @@\n+#ifndef RESET_H\n+#define RESET_H\n+\n+int reset_index_file(const unsigned char *sha1, int is_hard_reset);\n+\n+#endif\n-- \n1.5.5.1.357.g1af8b.dirty\n"},{"id":"77620","messageId":"28874c24faf45e6e4499c9692cc1de1e93cd4dcf.1211586801.git.vmiklos@frugalware.org","threadId":"13647","inReplyTo":"40d6845554a032ef66a20289aea6c7b2f157fed3.1211586801.git.vmiklos@frugalware.org","subject":"[PATCH 2/5] Move split_cmdline() to libgit","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-05-24T00:01:05Z","receivedAt":"2008-05-24T00:01:05Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"split_cmdline() is currently used for aliases only, but later it can be\nuseful for other builtins as well. Move it to alias.c for now,\nindicating that originally it's for aliases, but we'll have it in libgit\nthis way.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n alias.c |   54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n cache.h |    1 +\n git.c   |   53 -----------------------------------------------------\n 3 files changed, 55 insertions(+), 53 deletions(-)\n\ndiff --git a/alias.c b/alias.c\nindex 116cac8..75bc48a 100644\n--- a/alias.c\n+++ b/alias.c\n@@ -20,3 +20,57 @@ char *alias_lookup(const char *alias)\n \tgit_config(alias_lookup_cb);\n \treturn alias_val;\n }\n+\n+int split_cmdline(char *cmdline, const char ***argv)\n+{\n+\tint src, dst, count = 0, size = 16;\n+\tchar quoted = 0;\n+\n+\t*argv = xmalloc(sizeof(char*) * size);\n+\n+\t/* split alias_string */\n+\t(*argv)[count++] = cmdline;\n+\tfor (src = dst = 0; cmdline[src];) {\n+\t\tchar c = cmdline[src];\n+\t\tif (!quoted && isspace(c)) {\n+\t\t\tcmdline[dst++] = 0;\n+\t\t\twhile (cmdline[++src]\n+\t\t\t\t\t&& isspace(cmdline[src]))\n+\t\t\t\t; /* skip */\n+\t\t\tif (count >= size) {\n+\t\t\t\tsize += 16;\n+\t\t\t\t*argv = xrealloc(*argv, sizeof(char*) * size);\n+\t\t\t}\n+\t\t\t(*argv)[count++] = cmdline + dst;\n+\t\t} else if (!quoted && (c == '\\'' || c == '\"')) {\n+\t\t\tquoted = c;\n+\t\t\tsrc++;\n+\t\t} else if (c == quoted) {\n+\t\t\tquoted = 0;\n+\t\t\tsrc++;\n+\t\t} else {\n+\t\t\tif (c == '\\\\' && quoted != '\\'') {\n+\t\t\t\tsrc++;\n+\t\t\t\tc = cmdline[src];\n+\t\t\t\tif (!c) {\n+\t\t\t\t\tfree(*argv);\n+\t\t\t\t\t*argv = NULL;\n+\t\t\t\t\treturn error(\"cmdline ends with \\\\\");\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tcmdline[dst++] = c;\n+\t\t\tsrc++;\n+\t\t}\n+\t}\n+\n+\tcmdline[dst] = 0;\n+\n+\tif (quoted) {\n+\t\tfree(*argv);\n+\t\t*argv = NULL;\n+\t\treturn error(\"unclosed quote\");\n+\t}\n+\n+\treturn count;\n+}\n+\ndiff --git a/cache.h b/cache.h\nindex 093f04c..5e22b1e 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -814,5 +814,6 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_\n void overlay_tree_on_cache(const char *tree_name, const char *prefix);\n \n char *alias_lookup(const char *alias);\n+int split_cmdline(char *cmdline, const char ***argv);\n \n #endif /* CACHE_H */\ndiff --git a/git.c b/git.c\nindex 89b431f..b8df19e 100644\n--- a/git.c\n+++ b/git.c\n@@ -87,59 +87,6 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)\n \treturn handled;\n }\n \n-static int split_cmdline(char *cmdline, const char ***argv)\n-{\n-\tint src, dst, count = 0, size = 16;\n-\tchar quoted = 0;\n-\n-\t*argv = xmalloc(sizeof(char*) * size);\n-\n-\t/* split alias_string */\n-\t(*argv)[count++] = cmdline;\n-\tfor (src = dst = 0; cmdline[src];) {\n-\t\tchar c = cmdline[src];\n-\t\tif (!quoted && isspace(c)) {\n-\t\t\tcmdline[dst++] = 0;\n-\t\t\twhile (cmdline[++src]\n-\t\t\t\t\t&& isspace(cmdline[src]))\n-\t\t\t\t; /* skip */\n-\t\t\tif (count >= size) {\n-\t\t\t\tsize += 16;\n-\t\t\t\t*argv = xrealloc(*argv, sizeof(char*) * size);\n-\t\t\t}\n-\t\t\t(*argv)[count++] = cmdline + dst;\n-\t\t} else if(!quoted && (c == '\\'' || c == '\"')) {\n-\t\t\tquoted = c;\n-\t\t\tsrc++;\n-\t\t} else if (c == quoted) {\n-\t\t\tquoted = 0;\n-\t\t\tsrc++;\n-\t\t} else {\n-\t\t\tif (c == '\\\\' && quoted != '\\'') {\n-\t\t\t\tsrc++;\n-\t\t\t\tc = cmdline[src];\n-\t\t\t\tif (!c) {\n-\t\t\t\t\tfree(*argv);\n-\t\t\t\t\t*argv = NULL;\n-\t\t\t\t\treturn error(\"cmdline ends with \\\\\");\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tcmdline[dst++] = c;\n-\t\t\tsrc++;\n-\t\t}\n-\t}\n-\n-\tcmdline[dst] = 0;\n-\n-\tif (quoted) {\n-\t\tfree(*argv);\n-\t\t*argv = NULL;\n-\t\treturn error(\"unclosed quote\");\n-\t}\n-\n-\treturn count;\n-}\n-\n static int handle_alias(int *argcp, const char ***argv)\n {\n \tint envchanged = 0, ret = 0, saved_errno = errno;\n-- \n1.5.5.1.357.g1af8b.dirty\n"},{"id":"77616","messageId":"dace39a3a72957bec9a7f4b8528b08fc7fbe3341.1211586801.git.vmiklos@frugalware.org","threadId":"13647","inReplyTo":"28874c24faf45e6e4499c9692cc1de1e93cd4dcf.1211586801.git.vmiklos@frugalware.org","subject":"[PATCH 3/5] Make verbosity configurable in reset_index_file()","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-05-24T00:01:06Z","receivedAt":"2008-05-24T00:01:06Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"Till now reset_index_file() was always verbose. Add a new argument to be\nable to disable this behaviour.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n builtin-reset.c |    2 +-\n reset.c         |    5 +++--\n reset.h         |    2 +-\n 3 files changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin-reset.c b/builtin-reset.c\nindex 6e6e168..179c59c 100644\n--- a/builtin-reset.c\n+++ b/builtin-reset.c\n@@ -216,7 +216,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\tif (is_merge() || read_cache() < 0 || unmerged_cache())\n \t\t\tdie(\"Cannot do a soft reset in the middle of a merge.\");\n \t}\n-\telse if (reset_index_file(sha1, (reset_type == HARD)))\n+\telse if (reset_index_file(sha1, (reset_type == HARD), 1))\n \t\tdie(\"Could not reset index file to revision '%s'.\", rev);\n \n \t/* Any resets update HEAD to the head being switched to,\ndiff --git a/reset.c b/reset.c\nindex a75fec6..baae947 100644\n--- a/reset.c\n+++ b/reset.c\n@@ -11,13 +11,14 @@\n #include \"cache.h\"\n #include \"run-command.h\"\n \n-int reset_index_file(const unsigned char *sha1, int is_hard_reset)\n+int reset_index_file(const unsigned char *sha1, int is_hard_reset, int verbose)\n {\n \tint i = 0;\n \tconst char *args[6];\n \n \targs[i++] = \"read-tree\";\n-\targs[i++] = \"-v\";\n+\tif (verbose)\n+\t\targs[i++] = \"-v\";\n \targs[i++] = \"--reset\";\n \tif (is_hard_reset)\n \t\targs[i++] = \"-u\";\ndiff --git a/reset.h b/reset.h\nindex 4ae235b..c43ae22 100644\n--- a/reset.h\n+++ b/reset.h\n@@ -1,6 +1,6 @@\n #ifndef RESET_H\n #define RESET_H\n \n-int reset_index_file(const unsigned char *sha1, int is_hard_reset);\n+int reset_index_file(const unsigned char *sha1, int is_hard_reset, int verbose);\n \n #endif\n-- \n1.5.5.1.357.g1af8b.dirty\n"},{"id":"77619","messageId":"b2314d0b07976d106e9ac9a9eebceb465f0ec46b.1211586801.git.vmiklos@frugalware.org","threadId":"13647","inReplyTo":"dace39a3a72957bec9a7f4b8528b08fc7fbe3341.1211586801.git.vmiklos@frugalware.org","subject":"[PATCH 4/5] Move commit_list_count() to commit.c","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-05-24T00:01:07Z","receivedAt":"2008-05-24T00:01:07Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"This function is useful outside builtin-merge-recursive, for example in\nbuiltin-merge.\n\nSigned-off-by: Miklos Vajna <vmiklos@frugalware.org>\n---\n builtin-merge-recursive.c |    8 --------\n commit.c                  |    8 ++++++++\n commit.h                  |    1 +\n 3 files changed, 9 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c\nindex 46e636f..7aaa215 100644\n--- a/builtin-merge-recursive.c\n+++ b/builtin-merge-recursive.c\n@@ -42,14 +42,6 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two)\n  * - *(int *)commit->object.sha1 set to the virtual id.\n  */\n \n-static unsigned commit_list_count(const struct commit_list *l)\n-{\n-\tunsigned c = 0;\n-\tfor (; l; l = l->next )\n-\t\tc++;\n-\treturn c;\n-}\n-\n static struct commit *make_virtual_commit(struct tree *tree, const char *comment)\n {\n \tstruct commit *commit = xcalloc(1, sizeof(struct commit));\ndiff --git a/commit.c b/commit.c\nindex 94d5b3d..b45ec9b 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -331,6 +331,14 @@ struct commit_list *commit_list_insert(struct commit *item, struct commit_list *\n \treturn new_list;\n }\n \n+unsigned commit_list_count(const struct commit_list *l)\n+{\n+\tunsigned c = 0;\n+\tfor (; l; l = l->next )\n+\t\tc++;\n+\treturn c;\n+}\n+\n void free_commit_list(struct commit_list *list)\n {\n \twhile (list) {\ndiff --git a/commit.h b/commit.h\nindex 2d94d41..7f8c5ee 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -41,6 +41,7 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size);\n int parse_commit(struct commit *item);\n \n struct commit_list * commit_list_insert(struct commit *item, struct commit_list **list_p);\n+unsigned commit_list_count(const struct commit_list *l);\n struct commit_list * insert_by_date(struct commit *item, struct commit_list **list);\n \n void free_commit_list(struct commit_list *list);\n-- \n1.5.5.1.357.g1af8b.dirty\n"},{"id":"77621","messageId":"b9c1abcb326eafb12ac12138ae064f08eddbca50.1211586801.git.vmiklos@frugalware.org","threadId":"13647","inReplyTo":"b2314d0b07976d106e9ac9a9eebceb465f0ec46b.1211586801.git.vmiklos@frugalware.org","subject":"[PATCH 5/5] Build in merge","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-05-24T00:01:08Z","receivedAt":"2008-05-24T00:01: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 Makefile                                      |    2 +-\n builtin-merge.c                               | 1117 +++++++++++++++++++++++++\n builtin.h                                     |    1 +\n git-merge.sh => contrib/examples/git-merge.sh |    0 \n git.c                                         |    1 +\n 5 files changed, 1120 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 91d938a..9820932 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -241,7 +241,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@@ -509,6 +508,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..ffe6a67\n--- /dev/null\n+++ b/builtin-merge.c\n@@ -0,0 +1,1117 @@\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 \"strbuf.h\"\n+#include \"run-command.h\"\n+#include \"path-list.h\"\n+#include \"diff.h\"\n+#include \"refs.h\"\n+#include \"reset.h\"\n+#include \"commit.h\"\n+#include \"diffcore.h\"\n+#include \"revision.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, hide_diffstat, 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];\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_addstr(buf, 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(const char *path, void *util,\n+\tstruct path_list *list)\n+{\n+\tpath_list_append(path, list)->util = 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 *list = opt->value;\n+\tstruct path_list_item *item =\n+\t\tunsorted_path_list_lookup(arg, &strategies);\n+\n+\tif (unset)\n+\t\treturn 0;\n+\n+\tif (item)\n+\t\tpath_list_append_strategy(arg, item->util, list);\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 struct option builtin_merge_options[] = {\n+\tOPT_BOOLEAN('n', NULL, &hide_diffstat,\n+\t\t\"don't show a diffstat at the end of the merge\"),\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 sucesses (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+/*\n+ * TODO: This is the same as builtin-remote's skip_prefix, but it seems\n+ * we can't move it simply to git-compat-util.h as parse-options.c has\n+ * an other skip_prefix() function as well.\n+ */\n+static inline const char *skip_prefix(const char *name, const char *prefix)\n+{\n+\treturn !name ? \"\" :\n+\t\tprefixcmp(name, prefix) ?  name : name + strlen(prefix);\n+}\n+\n+static const unsigned char *hex_to_sha1(char *hex)\n+{\n+\tstatic unsigned char sha1[20];\n+\n+\tif (get_sha1(hex, sha1))\n+\t\tdie(\"bad revision '%s'\", hex);\n+\treturn sha1;\n+}\n+\n+/* Cleans up metadata that is uninteresting after a succeeded merge. */\n+static void dropsave()\n+{\n+\tunlink(git_path(\"MERGE_HEAD\"));\n+\tunlink(git_path(\"MERGE_MSG\"));\n+\tunlink(git_path(\"MERGE_STASH\"));\n+}\n+\n+static void save_state()\n+{\n+\tint fd;\n+\tstruct child_process stash;\n+\tconst char *argv[] = {\"stash\", \"create\", NULL};\n+\n+\tfd = open(git_path(\"MERGE_STASH\"), O_WRONLY | O_CREAT, 0666);\n+\tif (fd < 0)\n+\t\tdie(\"Could not write to %s\", git_path(\"MERGE_STASH\"));\n+\tmemset(&stash, 0, sizeof(stash));\n+\tstash.argv = argv;\n+\tstash.out = fd;\n+\tstash.git_cmd = 1;\n+\trun_command(&stash);\n+}\n+\n+static void restore_state()\n+{\n+\tstruct strbuf sb;\n+\tconst char *args[] = { \"stash\", \"apply\", NULL, NULL };\n+\n+\tif (access(git_path(\"MERGE_STASH\"), R_OK) < 0)\n+\t\treturn;\n+\n+\treset_index_file(head, 1, 1);\n+\n+\tstrbuf_init(&sb, 0);\n+\tif (strbuf_read_file(&sb, git_path(\"MERGE_STASH\"), 0) < 0)\n+\t\tdie(\"could not read MERGE_STASH: %s\", strerror(errno));\n+\targs[2] = sb.buf;\n+\tif (run_command_v_opt(args, RUN_GIT_CMD))\n+\t\tdie(\"Could not apply stash '%s'\", sb.buf);\n+\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+\tif (squash)\n+\t\tprintf(\"%s (nothing to squash)\\n\", msg);\n+\telse\n+\t\tprintf(\"%s\\n\", msg);\n+\tdropsave();\n+}\n+\n+static void squash_message(int out_fd)\n+{\n+\tconst char **args;\n+\tint i = 0;\n+\t/* TODO: it should be possible to avoid exec here() */\n+\tstruct child_process log;\n+\tstruct strbuf head_buf;\n+\tstruct commit_list *j;\n+\tconst char squash_header[] = \"Squashed commit of the following:\\n\\n\";\n+\n+\twrite(out_fd, squash_header, sizeof(squash_header) - 1);\n+\n+\tstrbuf_init(&head_buf, 0);\n+\tstrbuf_addch(&head_buf, '^');\n+\tstrbuf_addstr(&head_buf, sha1_to_hex(head));\n+\n+\targs = xmalloc((5 + commit_list_count(remoteheads)) * sizeof(char *));\n+\targs[i++] = \"log\";\n+\targs[i++] = \"--no-merges\";\n+\targs[i++] = \"--pretty=medium\";\n+\targs[i++] = head_buf.buf;\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+\tmemset(&log, 0, sizeof(log));\n+\tlog.argv = args;\n+\tlog.out = out_fd;\n+\tlog.git_cmd = 1;\n+\trun_command(&log);\n+\tstrbuf_release(&head_buf);\n+\tfor (i = 4; args[i]; i++)\n+\t\tfree((char *)args[i]);\n+\tfree(args);\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+\tsnprintf(index, sizeof(index), \"GIT_INDEX_FILE=%s\", get_index_file());\n+\tenv[0] = index;\n+\tenv[1] = NULL;\n+\n+\targv[0] = git_path(\"hooks/%s\", name);\n+\tif (squash)\n+\t\targv[1] = \"1\";\n+\telse\n+\t\targv[1] = \"0\";\n+\targv[2] = NULL;\n+\n+\tif (access(argv[0], X_OK) < 0)\n+\t\treturn 0;\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+\tconst char *argv_gc_auto[] = { \"gc\", \"--auto\", NULL };\n+\tstruct diff_options opts;\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\tint fd;\n+\t\tprintf(\"Squash commit -- not updating HEAD\\n\");\n+\t\tfd = open(git_path(\"SQUASH_MSG\"), O_WRONLY | O_CREAT, 0666);\n+\t\tif (fd < 0)\n+\t\t\tdie(\"Could not write to %s\", git_path(\"SQUASH_MSG\"));\n+\t\tsquash_message(fd);\n+\t\tclose(fd);\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\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\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\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+\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+\tchar *ref;\n+\tregex_t reg;\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\treturn;\n+\n+\t/* TODO: maybe here we could just use get_sha1()? */\n+\tstrbuf_init(&buf, 0);\n+\tstrbuf_addstr(&buf, \"refs/heads/\");\n+\tstrbuf_addstr(&buf, remote);\n+\tdwim_ref(buf.buf, buf.len, branch_head, &ref);\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/*\n+\t * TODO: This probably wants to match not only <name>~<number>,\n+\t * but also <name>^\n+\t */\n+\t/* TODO: using regcomp() is not sensible, we could do it by hand\n+\t * just by using strchr(). */\n+\tregcomp(&reg, \"~[1-9][0-9]*$\", 0);\n+\tif (!regexec(&reg, remote, 0, 0, 0)) {\n+\t\tstruct strbuf truname;\n+\t\tstrbuf_addstr(&truname, remote);\n+\t\tstrbuf_setlen(&truname, strrchr(truname.buf, '~')-truname.buf);\n+\t\tif (dwim_ref(truname.buf, truname.len, buf_sha, &ref)) {\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!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 == NULL)\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)\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\tstruct strbuf cmdline;\n+\n+\t\t/* TODO this is indeed a hack, maybe modify\n+\t\t * split_cmdline() and add an option to tell\n+\t\t * where should it start feeding options,\n+\t\t * default to 0, but here to 1? */\n+\t\tstrbuf_init(&cmdline, 0);\n+\t\tstrbuf_addf(&cmdline, \"merge %s\", v);\n+\t\targc = split_cmdline((char *)cmdline.buf, &argv);\n+\t\tparse_options(argc, argv, builtin_merge_options,\n+\t\t\t\tbuiltin_merge_usage, 0);\n+\t\t/* TODO: hack and code duplication */\n+\t\tif (hide_diffstat)\n+\t\t\tshow_diffstat = hide_diffstat = 0;\n+\t\tstrbuf_release(&cmdline);\n+\t}\n+\n+\tif (!strcmp(k, \"merge.diffstat\") || !strcmp(k, \"merge.stat\"))\n+\t\tshow_diffstat = git_config_bool(k, v);\n+\t/* FIXME: This may or may not be a list */\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 0;\n+}\n+\n+static int read_tree_trivial(unsigned char *common, unsigned char *head,\n+\tunsigned char *one)\n+{\n+\tconst char *args[] = {\n+\t\t\"read-tree\", \"--trivial\", \"-m\", \"-u\", \"-v\",\n+\t\tNULL, NULL, NULL, NULL };\n+\n+\targs[5] = sha1_to_hex(common);\n+\targs[6] = sha1_to_hex(head);\n+\targs[7] = sha1_to_hex(one);\n+\n+\treturn run_command_v_opt(args, RUN_GIT_CMD);\n+}\n+\n+static char *commit_tree_trivial(const char *msg, const char *tree,\n+\t\tstruct commit_list *parents)\n+{\n+\tint i = 0, len;\n+\t/* TODO: it should be possible to avoid exec here() */\n+\tstruct child_process ct;\n+\tstruct strbuf result_commit;\n+\tconst char **args;\n+\tstruct commit_list *j;\n+\n+\tmemset(&ct, 0, sizeof(ct));\n+\tstrbuf_init(&result_commit, 0);\n+\targs = xmalloc((3 + 2 * commit_list_count(parents)) * sizeof(char *));\n+\targs[i++] = \"commit-tree\";\n+\targs[i++] = tree;\n+\tfor (j = parents; j; j = j->next) {\n+\t\targs[i++] = \"-p\";\n+\t\targs[i++] = xstrdup(sha1_to_hex(j->item->object.sha1));\n+\t}\n+\targs[i++] = NULL;\n+\tct.argv = args;\n+\tct.in = -1;\n+\tct.out = -1;\n+\tct.git_cmd = 1;\n+\tif (start_command(&ct))\n+\t\tdie(\"could not run git commit-tree\");\n+\tif (write_in_full(ct.in, msg, strlen(msg)) != strlen(msg))\n+\t\tdie(\"git commit-tree did not accept the commit message\");\n+\tclose(ct.in);\n+\tlen = strbuf_read(&result_commit, ct.out, 1024);\n+\tclose(ct.out);\n+\tif (finish_command(&ct) || !len || len < 0)\n+\t\tdie(\"git commit-tree failed to commit the tree\");\n+\tif (result_commit.len)\n+\t\tstrbuf_setlen(&result_commit, result_commit.len-1);\n+\treturn result_commit.buf;\n+}\n+\n+static void write_tree_trivial(struct strbuf *result_tree)\n+{\n+\tconst char *argv_write_tree[] = { \"write-tree\", NULL };\n+\t/* TODO: it should be possible to avoid exec here() */\n+\tstruct child_process wt;\n+\tint len;\n+\n+\tmemset(&wt, 0, sizeof(wt));\n+\tstrbuf_init(result_tree, 0);\n+\twt.argv = argv_write_tree;\n+\twt.out = -1;\n+\twt.git_cmd = 1;\n+\tif (start_command(&wt))\n+\t\tdie(\"could not run git write-tree\");\n+\tlen = strbuf_read(result_tree, wt.out, 1024);\n+\tclose(wt.out);\n+\tif (finish_command(&wt) || !len || len < 0)\n+\t\tdie(\"git write-tree failed to write a tree\");\n+\tstrbuf_setlen(result_tree, result_tree->len-1);\n+}\n+\n+static int try_merge_strategy(char *strategy, struct commit_list *common,\n+\tstruct strbuf *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->buf;\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+\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+struct commit_list *commit_list_append(struct commit *item,\n+\tstruct commit_list **list_p)\n+{\n+\tstruct commit_list *i, *prev = NULL, *list = *list_p;\n+\tstruct commit_list *new_list = xmalloc(sizeof(struct commit_list));\n+\n+\tnew_list->item = item;\n+\tnew_list->next = NULL;\n+\n+\tif (!list)\n+\t\t*list_p = new_list;\n+\telse {\n+\t\tfor (i = list; i; i = i->next)\n+\t\t\tprev = i;\n+\t\tprev->next = new_list;\n+\t}\n+\treturn list;\n+}\n+\n+static void run_show_branch(char *opt, unsigned char *head,\n+\tstruct commit_list **common)\n+{\n+\tstruct child_process show;\n+\tstruct strbuf common_buf;\n+\tconst char **args;\n+\tconst char *ptr;\n+\tint i, len;\n+\tstruct commit_list *j;\n+\tunsigned char sha1[20];\n+\n+\tmemset(&show, 0, sizeof(show));\n+\tstrbuf_init(&common_buf, 0);\n+\targs = xmalloc((4 + commit_list_count(remoteheads)) * sizeof(char *));\n+\ti = 0;\n+\targs[i++] = \"show-branch\";\n+\targs[i++] = opt;\n+\targs[i++] = xstrdup(sha1_to_hex(head));\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+\tshow.argv = args;\n+\tshow.out = -1;\n+\tshow.git_cmd = 1;\n+\tif (start_command(&show))\n+\t\tdie(\"could not run git show-branch\");\n+\tlen = strbuf_read(&common_buf, show.out, 1024);\n+\tclose(show.out);\n+\tif (finish_command(&show) || !len || len < 0)\n+\t\tdie(\"git show-branch failed to produce the list of merge bases\");\n+\tfor (i = 2; args[i]; i++)\n+\t\tfree((char *)args[i]);\n+\tfree(args);\n+\tptr = common_buf.buf;\n+\twhile ((ptr = strchr(ptr, '\\n'))) {\n+\t\tchar hex[41];\n+\t\tmemset(hex, 0, sizeof(hex));\n+\t\tmemcpy(hex, ptr-40, 40);\n+\t\tif (get_sha1(hex, sha1))\n+\t\t\tdie(\"bad revision returned by show-branch: '%s'\", hex);\n+\t\tcommit_list_append(lookup_commit(sha1), common);\n+\t\tptr++;\n+\t}\n+}\n+\n+int cmd_merge(int argc, const char **argv, const char *prefix)\n+{\n+\tunsigned char sha1[20], result_tree[20] = \"\";\n+\tstruct object *second_token = NULL;\n+\tstruct strbuf buf, head_arg;\n+\tint flag, head_invalid, i, single_strategy;\n+\tint best_cnt = -1, merge_was_ok = 0;\n+\tstruct commit_list *common = NULL;\n+\tstruct path_list_item *best_strategy = NULL, *wt_strategy;\n+\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\", sha1, 0, &flag);\n+\tif (branch && flag & REF_ISSYMREF)\n+\t\tbranch = skip_prefix(branch, \"refs/heads/\");\n+\n+\tgit_config(git_merge_config);\n+\n+\targc = parse_options(argc, argv, builtin_merge_options,\n+\t\t\tbuiltin_merge_usage, 0);\n+\t/* TODO: hack */\n+\tif (hide_diffstat)\n+\t\tshow_diffstat = hide_diffstat = 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 == 0)\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+\tstrbuf_init(&head_arg, 0);\n+\tif (argc > 1)\n+\t\tsecond_token = peel_to_type(argv[1], 0, NULL, OBJ_COMMIT);\n+\thead_invalid = get_sha1(\"HEAD\", head);\n+\n+\tif (!have_message && second_token &&\n+\t\t!hashcmp(second_token->sha1, head)) {\n+\t\tstrbuf_addstr(&merge_msg, argv[0]);\n+\t\tstrbuf_addstr(&head_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 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\treturn reset_index_file(hex_to_sha1(\"HEAD\"), 1, 0);\n+\t} else {\n+\t\t/* We are invoked directly as the first-class UI. */\n+\t\tstrbuf_addstr(&head_arg, \"HEAD\");\n+\t\tif (!merge_msg.len) {\n+\t\t\t/*\n+\t\t\t * All the rest are the commits being merged;\n+\t\t\t * prepare the standard merge summary message to\n+\t\t\t * be appended to the given message.  If remote\n+\t\t\t * is invalid we will die later in the common\n+\t\t\t * codepath so we discard the error in this\n+\t\t\t * loop.\n+\t\t\t */\n+\t\t\tint i, len;\n+\t\t\tstruct strbuf msg;\n+\t\t\tstruct child_process fmt;\n+\t\t\tconst char *args[3];\n+\n+\t\t\tstrbuf_init(&msg, 0);\n+\t\t\tfor (i = 0; i < argc; i++)\n+\t\t\t\tmerge_name(argv[i], &msg);\n+\t\t\tmemset(&fmt, 0, sizeof(fmt));\n+\t\t\targs[0] = \"fmt-merge-msg\";\n+\t\t\tif (option_log)\n+\t\t\t\targs[1] = \"--log\";\n+\t\t\telse\n+\t\t\t\targs[1] = \"--no-log\";\n+\t\t\targs[2] = NULL;\n+\t\t\tfmt.argv = args;\n+\t\t\tfmt.in = -1;\n+\t\t\tfmt.out = -1;\n+\t\t\tfmt.git_cmd = 1;\n+\t\t\tif (start_command(&fmt))\n+\t\t\t\tdie(\"could not run git fmt-merge-msg\");\n+\t\t\tif (write_in_full(fmt.in, msg.buf, msg.len) != msg.len)\n+\t\t\t\tdie(\"git fmt-merge-msg did not accept the tag data\");\n+\t\t\tclose(fmt.in);\n+\t\t\tlen = strbuf_read(&merge_msg, fmt.out, 1024);\n+\t\t\tclose(fmt.out);\n+\t\t\tif (finish_command(&fmt) || !len || len < 0)\n+\t\t\t\tdie(\"git fmt-merge-msg failed to produce a merge commit message\");\n+\t\t\tif(merge_msg.len)\n+\t\t\t\tstrbuf_setlen(&merge_msg, merge_msg.len-1);\n+\t\t}\n+\t}\n+\n+\tif (head_invalid || argc == 0)\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\tcommit_list_append(lookup_commit(o->sha1), &remoteheads);\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\tstruct path_list_item *item;\n+\t\t/*\n+\t\t * TODO: there is some code duplication here, it would\n+\t\t * be nice to kill it.\n+\t\t */\n+\t\tif (!remoteheads->next) {\n+\t\t\titem = unsorted_path_list_lookup(pull_twohead,\n+\t\t\t\t&strategies);\n+\t\t\tif (pull_twohead && item) {\n+\t\t\t\tpath_list_append_strategy(pull_twohead,\n+\t\t\t\t\titem->util, &use_strategies);\n+\t\t\t} else {\n+\t\t\t\tfor (i = 0; i < strategies.nr; i++)\n+\t\t\t\t\tif ((enum strategy)strategies.items[i].util & DEFAULT_TWOHEAD)\n+\t\t\t\t\t\tpath_list_append_strategy(strategies.items[i].path,\n+\t\t\t\t\t\t\tstrategies.items[i].util,\n+\t\t\t\t\t\t\t&use_strategies);\n+\t\t\t}\n+\t\t} else {\n+\t\t\titem = unsorted_path_list_lookup(pull_octopus,\n+\t\t\t\t&strategies);\n+\t\t\tif (pull_octopus && item)\n+\t\t\t\tpath_list_append_strategy(pull_octopus,\n+\t\t\t\t\titem->util, &use_strategies);\n+\t\t\telse {\n+\t\t\t\tfor (i = 0; i < strategies.nr; i++)\n+\t\t\t\t\tif ((enum strategy)strategies.items[i].util & DEFAULT_OCTOPUS)\n+\t\t\t\t\t\tpath_list_append_strategy(strategies.items[i].path,\n+\t\t\t\t\t\t\tstrategies.items[i].util,\n+\t\t\t\t\t\t\t&use_strategies);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < use_strategies.nr; i++) {\n+\t\tif ((unsigned int)use_strategies.items[i].util &\n+\t\t\tNO_FAST_FORWARD)\n+\t\t\tallow_fast_forward = 0;\n+\t\tif ((unsigned int)use_strategies.items[i].util & 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\t/*\n+\t\t * TODO: move functionality to commit.c and avoid fork()\n+\t\t * here.\n+\t\t */\n+\t\trun_show_branch(\"--merge-base\", head, &common);\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 &&\n+\t\t!hashcmp(common->item->object.sha1,\n+\t\tremoteheads->item->object.sha1)) {\n+\t\t/*\n+\t\t * If head can reach all the merge then we are up to\n+\t\t * date.\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!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\tconst char *args[7];\n+\t\tstruct object *o;\n+\n+\t\tprintf(\"Updating %s..%s\\n\",\n+\t\t\tfind_unique_abbrev(head, DEFAULT_ABBREV),\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 0;\n+\n+\t\ti = 0;\n+\t\targs[i++] = \"read-tree\";\n+\t\targs[i++] = \"-v\";\n+\t\targs[i++] = \"-m\";\n+\t\targs[i++] = \"-u\";\n+\t\targs[i++] = \"--exclude-per-directory=.gitignore\";\n+\t\targs[i++] = sha1_to_hex(head);\n+\t\targs[i++] = sha1_to_hex(remoteheads->item->object.sha1);\n+\t\targs[i] = NULL;\n+\t\tif (run_command_v_opt(args, RUN_GIT_CMD))\n+\t\t\treturn 0;\n+\t\tfinish(o->sha1, msg.buf);\n+\t\tdropsave();\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 && option_commit) {\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+\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\tstruct strbuf result_tree;\n+\t\t\t\tchar *result_commit;\n+\t\t\t\tstruct commit_list parent;\n+\n+\t\t\t\twrite_tree_trivial(&result_tree);\n+\t\t\t\tprintf(\"Wonderful.\\n\");\n+\t\t\t\tparent.item = remoteheads->item;\n+\t\t\t\tparent.next = NULL;\n+\t\t\t\tresult_commit =\n+\t\t\t\t\tcommit_tree_trivial(merge_msg.buf,\n+\t\t\t\t\tresult_tree.buf, &parent);\n+\t\t\t\tfinish(hex_to_sha1(result_commit),\n+\t\t\t\t\t\t\"In-index merge\");\n+\t\t\t\tdropsave();\n+\t\t\t\treturn 0;\n+\t\t\t}\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\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\tsingle_strategy = 0;\n+\t} else {\n+\t\tunlink(git_path(\"MERGE_STASH\"));\n+\t\tsingle_strategy = 1;\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 (!single_strategy)\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\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 = 0;\n+\t\t\t\tstruct rev_info rev;\n+\n+\t\t\t\tif (read_cache() < 0)\n+\t\t\t\t\tdie(\"failed to read the cache\");\n+\n+\t\t\t\t/* TODO maybe somehow document that\n+\t\t\t\t * these two blocks does the same as\n+\t\t\t\t * diff-files and ls-files? */\n+\t\t\t\tinit_revisions(&rev, \"\");\n+\t\t\t\tsetup_revisions(0, NULL, &rev, NULL);\n+\t\t\t\trev.diffopt.output_format |=\n+\t\t\t\t\tDIFF_FORMAT_CALLBACK;\n+\t\t\t\trev.diffopt.format_callback = count_diff_files;\n+\t\t\t\trev.diffopt.format_callback_data = &cnt;\n+\t\t\t\trun_diff_files(&rev, 0);\n+\n+\t\t\t\tcnt += count_unmerged_entries();\n+\n+\t\t\t\tif (best_cnt <= 0 || cnt <= best_cnt) {\n+\t\t\t\t\tbest_strategy = &use_strategies.items[i];\n+\t\t\t\t\tbest_cnt = cnt;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* Automerge succeeded. */\n+\t\twrite_tree_trivial(&buf);\n+\t\tif (get_sha1(buf.buf, result_tree))\n+\t\t\tdie(\"bad tree '%s'\", buf.buf);\n+\t\tstrbuf_reset(&buf);\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+\t/* TODO: is there a better check? somehow need to determine if\n+\t * we wrote something to result_tree since its declaration */\n+\tif (result_tree[0] != '\\0') {\n+\t\tstruct commit_list *parents = NULL, *j;\n+\t\tchar *result_commit;\n+\n+\t\tif (allow_fast_forward)\n+\t\t\trun_show_branch(\"--independent\", head, &parents);\n+\t\telse {\n+\t\t\tcommit_list_append(lookup_commit(head), &parents);\n+\t\t\tfor (j = remoteheads; j; j = j->next)\n+\t\t\t\tcommit_list_append(j->item, &parents);\n+\t\t}\n+\t\tstrbuf_addch(&merge_msg, '\\n');\n+\t\tresult_commit = commit_tree_trivial(merge_msg.buf,\n+\t\t\tsha1_to_hex(result_tree), parents);\n+\t\tstrbuf_addf(&buf, \"Merge made by %s.\", wt_strategy->path);\n+\t\tfinish(hex_to_sha1(result_commit), buf.buf);\n+\t\tdropsave();\n+\t\treturn 0;\n+\t}\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\tFILE *fp;\n+\t\tint pos;\n+\t\tconst char *argv_rerere[] = { \"rerere\", NULL };\n+\n+\t\tfp = fopen(git_path(\"MERGE_MSG\"), \"a\");\n+\t\tif (!fp)\n+\t\t\tdie(\"Could open %s for writing\", git_path(\"MERGE_MSG\"));\n+\t\tfprintf(fp, \"\\nConflicts:\\n\");\n+\t\tfor (pos = 0; pos < active_nr; pos++) {\n+\t\t\tstruct cache_entry *ce = active_cache[pos];\n+\n+\t\t\tif (ce_stage(ce)) {\n+\t\t\t\tfprintf(fp, \"\\t%s\\n\", ce->name);\n+\t\t\t\twhile (pos + 1 < active_nr &&\n+\t\t\t\t\t!strcmp(ce->name,\n+\t\t\t\t\tactive_cache[pos + 1]->name))\n+\t\t\t\t\tpos++;\n+\t\t\t}\n+\t\t}\n+\t\tfclose(fp);\n+\t\trun_command_v_opt(argv_rerere, RUN_GIT_CMD);\n+\t\tprintf(\"Automatic merge failed; \"\n+\t\t\t\"fix conflicts and then commit the result.\\n\");\n+\t\treturn 1;\n+\t}\n+}\ndiff --git a/builtin.h b/builtin.h\nindex 95126fd..7c26d75 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -54,6 +54,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 b8df19e..fced435 100644\n--- a/git.c\n+++ b/git.c\n@@ -267,6 +267,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.5.1.357.g1af8b.dirty\n"},{"id":"77635","messageId":"alpine.LNX.1.00.0805240016230.19665@iabervon.org","threadId":"13647","inReplyTo":"40d6845554a032ef66a20289aea6c7b2f157fed3.1211586801.git.vmiklos@frugalware.org","subject":"Re: [PATCH 1/5] Move reset_index_file() to a new reset.c","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2008-05-24T04:21:42Z","receivedAt":"2008-05-24T04:21:42Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Sat, 24 May 2008, Miklos Vajna wrote:\n\n> This is needed as we want to use it later in builtin-merge.\n> \n> Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>\n> ---\n>  Makefile        |    2 ++\n>  builtin-reset.c |   17 +----------------\n>  reset.c         |   28 ++++++++++++++++++++++++++++\n>  reset.h         |    6 ++++++\n>  4 files changed, 37 insertions(+), 16 deletions(-)\n>  create mode 100644 reset.c\n>  create mode 100644 reset.h\n> \n> diff --git a/Makefile b/Makefile\n> index a2de075..91d938a 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -364,6 +364,7 @@ LIB_H += quote.h\n>  LIB_H += reflog-walk.h\n>  LIB_H += refs.h\n>  LIB_H += remote.h\n> +LIB_H += reset.h\n>  LIB_H += revision.h\n>  LIB_H += run-command.h\n>  LIB_H += sha1-lookup.h\n> @@ -443,6 +444,7 @@ LIB_OBJS += read-cache.o\n>  LIB_OBJS += reflog-walk.o\n>  LIB_OBJS += refs.o\n>  LIB_OBJS += remote.o\n> +LIB_OBJS += reset.o\n>  LIB_OBJS += revision.o\n>  LIB_OBJS += run-command.o\n>  LIB_OBJS += server-info.o\n> diff --git a/builtin-reset.c b/builtin-reset.c\n> index 79424bb..6e6e168 100644\n> --- a/builtin-reset.c\n> +++ b/builtin-reset.c\n> @@ -18,6 +18,7 @@\n>  #include \"tree.h\"\n>  #include \"branch.h\"\n>  #include \"parse-options.h\"\n> +#include \"reset.h\"\n>  \n>  static const char * const git_reset_usage[] = {\n>  \t\"git-reset [--mixed | --soft | --hard] [-q] [<commit>]\",\n> @@ -49,22 +50,6 @@ static inline int is_merge(void)\n>  \treturn !access(git_path(\"MERGE_HEAD\"), F_OK);\n>  }\n>  \n> -static int reset_index_file(const unsigned char *sha1, int is_hard_reset)\n> -{\n> -\tint i = 0;\n> -\tconst char *args[6];\n> -\n> -\targs[i++] = \"read-tree\";\n> -\targs[i++] = \"-v\";\n> -\targs[i++] = \"--reset\";\n> -\tif (is_hard_reset)\n> -\t\targs[i++] = \"-u\";\n> -\targs[i++] = sha1_to_hex(sha1);\n> -\targs[i] = NULL;\n> -\n> -\treturn run_command_v_opt(args, RUN_GIT_CMD);\n> -}\n> -\n>  static void print_new_head_line(struct commit *commit)\n>  {\n>  \tconst char *hex, *body;\n> diff --git a/reset.c b/reset.c\n> new file mode 100644\n> index 0000000..a75fec6\n> --- /dev/null\n> +++ b/reset.c\n> @@ -0,0 +1,28 @@\n> +/*\n> + * generic fucntion(s) from the \"git reset\" builtin command\n> + *\n> + * Copyright (c) 2007 Carlos Rica\n> + *\n> + * Based on git-reset.sh, which is\n> + *\n> + * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano\n> + */\n> +\n> +#include \"cache.h\"\n> +#include \"run-command.h\"\n> +\n> +int reset_index_file(const unsigned char *sha1, int is_hard_reset)\n> +{\n> +\tint i = 0;\n> +\tconst char *args[6];\n> +\n> +\targs[i++] = \"read-tree\";\n> +\targs[i++] = \"-v\";\n> +\targs[i++] = \"--reset\";\n> +\tif (is_hard_reset)\n> +\t\targs[i++] = \"-u\";\n> +\targs[i++] = sha1_to_hex(sha1);\n> +\targs[i] = NULL;\n> +\n> +\treturn run_command_v_opt(args, RUN_GIT_CMD);\n> +}\n\nYou might as well use unpack_trees() directly here, instead of running a \nseparate command. In fact, you might skip making a function here, and just \ncall unpack_trees() where you'd use it. (And maybe have a function to \ninitialize a struct unpack_tree_options to some common defaults to make it \neasy to see what's being done.)\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"77675","messageId":"20080524215530.GA27724@genesis.frugalware.org","threadId":"13647","inReplyTo":"alpine.LNX.1.00.0805240016230.19665@iabervon.org","subject":"Re: [PATCH 1/5] Move reset_index_file() to a new reset.c","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-05-24T21:55:30Z","receivedAt":"2008-05-24T21:55:30Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Sat, May 24, 2008 at 12:21:42AM -0400, Daniel Barkalow <barkalow@iabervon.org> wrote:\n> You might as well use unpack_trees() directly here, instead of running a \n> separate command. In fact, you might skip making a function here, and just \n> call unpack_trees() where you'd use it. (And maybe have a function to \n> initialize a struct unpack_tree_options to some common defaults to make it \n> easy to see what's being done.)\n\nThanks for the suggestion, I did so; as a result now patch #1 and #3 are\nno longer necessary.\n\n(I haven't sent out a new series yet, but it's in\ngit://repo.or.cz/git/vmiklos.git builtin-merge.)\n\nMaybe builtin-reset could use unpack_trees() directly as well? I don't\nknow if it's just a question of \"nobody did it yet\", or there is some\nreason for not using unpack_trees() there.\n"},{"id":"77859","messageId":"1211897281.13838.1.camel@gaara.bos.redhat.com","threadId":"13647","inReplyTo":"dace39a3a72957bec9a7f4b8528b08fc7fbe3341.1211586801.git.vmiklos@frugalware.org","subject":"Re: [PATCH 3/5] Make verbosity configurable in reset_index_file()","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2008-05-27T14:08:01Z","receivedAt":"2008-05-27T14:08:01Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"On Sat, 2008-05-24 at 02:01 +0200, Miklos Vajna wrote:\n> Till now reset_index_file() was always verbose. Add a new argument to be\n> able to disable this behaviour.\n> \n> Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>\n> ---\n>  builtin-reset.c |    2 +-\n>  reset.c         |    5 +++--\n>  reset.h         |    2 +-\n>  3 files changed, 5 insertions(+), 4 deletions(-)\n> \n> diff --git a/builtin-reset.c b/builtin-reset.c\n> index 6e6e168..179c59c 100644\n> --- a/builtin-reset.c\n> +++ b/builtin-reset.c\n> @@ -216,7 +216,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n>  \t\tif (is_merge() || read_cache() < 0 || unmerged_cache())\n>  \t\t\tdie(\"Cannot do a soft reset in the middle of a merge.\");\n>  \t}\n> -\telse if (reset_index_file(sha1, (reset_type == HARD)))\n> +\telse if (reset_index_file(sha1, (reset_type == HARD), 1))\n>  \t\tdie(\"Could not reset index file to revision '%s'.\", rev);\n>  \n>  \t/* Any resets update HEAD to the head being switched to,\n> diff --git a/reset.c b/reset.c\n> index a75fec6..baae947 100644\n> --- a/reset.c\n> +++ b/reset.c\n> @@ -11,13 +11,14 @@\n>  #include \"cache.h\"\n>  #include \"run-command.h\"\n>  \n> -int reset_index_file(const unsigned char *sha1, int is_hard_reset)\n> +int reset_index_file(const unsigned char *sha1, int is_hard_reset, int verbose)\n\nI would suggest using flags here instead of a bunch of boolean args.\nConsider the readability of\n\n    reset_index_file(sha1, 1, 1);\n\nvs\n\n    reset_index_file(sha1, RESET_HARD | RESET_VERBOSE);\n\ncheers,\nKristian\n"},{"id":"77864","messageId":"20080527144919.GJ27724@genesis.frugalware.org","threadId":"13647","inReplyTo":"1211897281.13838.1.camel@gaara.bos.redhat.com","subject":"Re: [PATCH 3/5] Make verbosity configurable in reset_index_file()","fromName":"Miklos Vajna","fromEmail":"vmiklos@frugalware.org","sentAt":"2008-05-27T14:49:19Z","receivedAt":"2008-05-27T14:49:19Z","isPatch":true,"sender":{"key":"vmiklos@frugalware.org","avatar":"https://gravatar.com/avatar/401c1cbbb3a5d13e650c691a2c71d6fd0b80df1a01bc74d9f1972675dd58f2bd?d=mp&s=160"},"body":"On Tue, May 27, 2008 at 10:08:01AM -0400, Kristian H?gsberg <krh@redhat.com> wrote:\n> > -int reset_index_file(const unsigned char *sha1, int is_hard_reset)\n> > +int reset_index_file(const unsigned char *sha1, int is_hard_reset, int verbose)\n> \n> I would suggest using flags here instead of a bunch of boolean args.\n> Consider the readability of\n> \n>     reset_index_file(sha1, 1, 1);\n> \n> vs\n> \n>     reset_index_file(sha1, RESET_HARD | RESET_VERBOSE);\n\nThanks for the suggestion, but - as Daniel already pointed out - the\nsame functionality can be achieved by using the unpack_trees() API\ndirectly, so the patch is useless.\n"}]}