{"thread":{"id":"5010","subject":"[PATCH] Cumulative update of merge-recursive in C","startedAt":"2006-07-27T11:17:07Z","lastAt":"2006-07-27T11:17:07Z","messageCount":1,"participants":["Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"24193","messageId":"Pine.LNX.4.63.0607271315440.29667@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"5010","inReplyTo":null,"subject":"[PATCH] Cumulative update of merge-recursive in C","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-07-27T11:17:07Z","receivedAt":"2006-07-27T11:17:07Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThis contains mainly three sorts of fixes:\n\n- get rid of small wrapper functions\n- reuse the diff_filespec structure when sha1, mode & path are needed\n- Junio's pedantic updates\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n\n---\n\n\tSorry for the big patch; it seemed to be tiny each\n\ttime I committed.\n\n merge-recursive.c |  894 ++++++++++++++++++++++-------------------------------\n 1 files changed, 366 insertions(+), 528 deletions(-)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 8d30519..85bb47a 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -25,9 +25,9 @@ #include \"path-list.h\"\n /*#define DEBUG*/\n \n #ifdef DEBUG\n-#define debug(args, ...) fprintf(stderr, args, ## __VA_ARGS__)\n+#define debug(...) fprintf(stderr, __VA_ARGS__)\n #else\n-#define debug(args, ...)\n+#define debug(...) do { ; /* nothing */ } while (0)\n #endif\n \n #ifdef DEBUG\n@@ -61,13 +61,14 @@ static void show_ce_entry(const char *ta\n \tfputc('\\n', stderr);\n }\n \n-static void ls_files() {\n+static void ls_files(void) {\n \tint i;\n \tfor (i = 0; i < active_nr; i++) {\n \t\tstruct cache_entry *ce = active_cache[i];\n \t\tshow_ce_entry(\"\", ce);\n \t}\n \tfprintf(stderr, \"---\\n\");\n+\tif (0) ls_files(); /* avoid \"unused\" warning */\n }\n #endif\n \n@@ -76,41 +77,6 @@ #endif\n  * - (const char *)commit->util set to the name, and\n  * - *(int *)commit->object.sha1 set to the virtual id.\n  */\n-static const char *commit_title(struct commit *commit, int *len)\n-{\n-\tconst char *s = \"(null commit)\";\n-\t*len = strlen(s);\n-\n-\tif ( commit->util ) {\n-\t\ts = commit->util;\n-\t\t*len = strlen(s);\n-\t} else {\n-\t\tif ( parse_commit(commit) != 0 ) {\n-\t\t\ts = \"(bad commit)\";\n-\t\t\t*len = strlen(s);\n-\t\t} else {\n-\t\t\ts = commit->buffer;\n-\t\t\tchar prev = '\\0';\n-\t\t\twhile ( *s ) {\n-\t\t\t\tif ( '\\n' == prev && '\\n' == *s ) {\n-\t\t\t\t\t++s;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t\tprev = *s++;\n-\t\t\t}\n-\t\t\t*len = 0;\n-\t\t\twhile ( s[*len] && '\\n' != s[*len] )\n-\t\t\t\t++(*len);\n-\t\t}\n-\t}\n-\treturn s;\n-}\n-\n-static const char *commit_hex_sha1(const struct commit *commit)\n-{\n-\treturn commit->util ? \"virtual\" : commit ?\n-\t\tsha1_to_hex(commit->object.sha1) : \"undefined\";\n-}\n \n static unsigned commit_list_count(const struct commit_list *l)\n {\n@@ -136,41 +102,11 @@ static struct commit *make_virtual_commi\n  */\n static int sha_eq(const unsigned char *a, const unsigned char *b)\n {\n-\tif ( !a && !b )\n+\tif (!a && !b)\n \t\treturn 2;\n \treturn a && b && memcmp(a, b, 20) == 0;\n }\n \n-static void memswp(void *p1, void *p2, unsigned n)\n-{\n-\tunsigned char *a = p1, *b = p2;\n-\twhile ( n-- ) {\n-\t\t*a ^= *b;\n-\t\t*b ^= *a;\n-\t\t*a ^= *b;\n-\t\t++a;\n-\t\t++b;\n-\t}\n-}\n-\n-/*\n- * TODO: we should convert the merge_result users to\n- * \tint blabla(..., struct commit **result)\n- * like everywhere else in git.\n- * Same goes for merge_tree_result and merge_file_info.\n- */\n-struct merge_result\n-{\n-\tstruct commit *commit;\n-\tunsigned clean:1;\n-};\n-\n-struct merge_tree_result\n-{\n-\tstruct tree *tree;\n-\tunsigned clean:1;\n-};\n-\n /*\n  * TODO: check if we can just reuse the active_cache structure: it is already\n  * sorted (by name, stage).\n@@ -195,7 +131,7 @@ static void output(const char *fmt, ...)\n {\n \tva_list args;\n \tint i;\n-\tfor ( i = output_indent; i--; )\n+\tfor (i = output_indent; i--;)\n \t\tfputs(\"  \", stdout);\n \tva_start(args, fmt);\n \tvfprintf(stdout, fmt, args);\n@@ -203,11 +139,37 @@ static void output(const char *fmt, ...)\n \tfputc('\\n', stdout);\n }\n \n+static void output_commit_title(struct commit *commit)\n+{\n+\tint i;\n+\tfor (i = output_indent; i--;)\n+\t\tfputs(\"  \", stdout);\n+\tif (commit->util)\n+\t\tprintf(\"virtual %s\\n\", (char *)commit->util);\n+\telse {\n+\t\tprintf(\"%s \", sha1_to_hex(commit->object.sha1));\n+\t\tif (parse_commit(commit) != 0)\n+\t\t\tprintf(\"(bad commit)\\n\");\n+\t\telse {\n+\t\t\tconst char *s;\n+\t\t\tint len;\n+\t\t\tfor (s = commit->buffer; *s; s++)\n+\t\t\t\tif (*s == '\\n' && s[1] == '\\n') {\n+\t\t\t\t\ts += 2;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\tfor (len = 0; s[len] && '\\n' != s[len]; len++)\n+\t\t\t\t; /* do nothing */\n+\t\t\tprintf(\"%.*s\\n\", len, s);\n+\t\t}\n+\t}\n+}\n+\n static const char *original_index_file;\n static const char *temporary_index_file;\n static int cache_dirty = 0;\n \n-static int flush_cache()\n+static int flush_cache(void)\n {\n \t/* flush temporary index */\n \tstruct lock_file *lock = xcalloc(1, sizeof(struct lock_file));\n@@ -290,11 +252,12 @@ #if 0\n \t\tgetenv(\"GIT_INDEX_FILE\"),\n \t\tsha1_to_hex(tree->object.sha1));\n #endif\n+\tint rc;\n \tconst char *argv[] = { \"git-read-tree\", NULL, NULL, };\n \tif (cache_dirty)\n \t\tdie(\"read-tree with dirty cache\");\n \targv[1] = sha1_to_hex(tree->object.sha1);\n-\tint rc = run_command_v(2, argv);\n+\trc = run_command_v(2, argv);\n \treturn rc < 0 ? -1: rc;\n }\n \n@@ -314,6 +277,7 @@ #if 0\n \t\tsha1_to_hex(head->object.sha1),\n \t\tsha1_to_hex(merge->object.sha1));\n #endif\n+\tint rc;\n \tconst char *argv[] = {\n \t\t\"git-read-tree\", NULL, \"-m\", NULL, NULL, NULL,\n \t\tNULL,\n@@ -324,50 +288,42 @@ #endif\n \targv[3] = sha1_to_hex(common->object.sha1);\n \targv[4] = sha1_to_hex(head->object.sha1);\n \targv[5] = sha1_to_hex(merge->object.sha1);\n-\tint rc = run_command_v(6, argv);\n+\trc = run_command_v(6, argv);\n \treturn rc < 0 ? -1: rc;\n }\n \n /*\n  * TODO: this can be streamlined by refactoring builtin-write-tree.c\n  */\n-static struct tree *git_write_tree()\n+static struct tree *git_write_tree(void)\n {\n #if 0\n \tfprintf(stderr, \"GIT_INDEX_FILE='%s' git-write-tree\\n\",\n \t\tgetenv(\"GIT_INDEX_FILE\"));\n #endif\n-\tif (cache_dirty)\n-\t\tflush_cache();\n-\tFILE *fp = popen(\"git-write-tree 2>/dev/null\", \"r\");\n+\tFILE *fp;\n+\tint rc;\n \tchar buf[41];\n \tunsigned char sha1[20];\n \tint ch;\n \tunsigned i = 0;\n-\twhile ( (ch = fgetc(fp)) != EOF )\n-\t\tif ( i < sizeof(buf)-1 && ch >= '0' && ch <= 'f' )\n+\tif (cache_dirty)\n+\t\tflush_cache();\n+\tfp = popen(\"git-write-tree 2>/dev/null\", \"r\");\n+\twhile ((ch = fgetc(fp)) != EOF)\n+\t\tif (i < sizeof(buf)-1 && ch >= '0' && ch <= 'f')\n \t\t\tbuf[i++] = ch;\n \t\telse\n \t\t\tbreak;\n-\tint rc = pclose(fp);\n-\tif ( rc == -1 || WEXITSTATUS(rc) )\n+\trc = pclose(fp);\n+\tif (rc == -1 || WEXITSTATUS(rc))\n \t\treturn NULL;\n \tbuf[i] = '\\0';\n-\tif ( get_sha1(buf, sha1) != 0 )\n+\tif (get_sha1(buf, sha1) != 0)\n \t\treturn NULL;\n \treturn lookup_tree(sha1);\n }\n \n-/*\n- * TODO: get rid of files_and_dirs; we do not use it except for\n- * current_file_set and current_dir_set, which are global already.\n- */\n-static struct\n-{\n-\tstruct path_list *files;\n-\tstruct path_list *dirs;\n-} files_and_dirs;\n-\n static int save_files_dirs(const unsigned char *sha1,\n \t\tconst char *base, int baselen, const char *path,\n \t\tunsigned int mode, int stage)\n@@ -379,70 +335,36 @@ static int save_files_dirs(const unsigne\n \tnewpath[baselen + len] = '\\0';\n \n \tif (S_ISDIR(mode))\n-\t\tpath_list_insert(newpath, files_and_dirs.dirs);\n+\t\tpath_list_insert(newpath, &currentDirectorySet);\n \telse\n-\t\tpath_list_insert(newpath, files_and_dirs.files);\n+\t\tpath_list_insert(newpath, &currentFileSet);\n \tfree(newpath);\n \n \treturn READ_TREE_RECURSIVE;\n }\n \n-static int get_files_dirs(struct tree *tree,\n-\t\t\t  struct path_list *files,\n-\t\t\t  struct path_list *dirs)\n+static int get_files_dirs(struct tree *tree)\n {\n \tint n;\n-\tfiles_and_dirs.files = files;\n-\tfiles_and_dirs.dirs = dirs;\n \tdebug(\"get_files_dirs ...\\n\");\n \tif (read_tree_recursive(tree, \"\", 0, 0, NULL, save_files_dirs) != 0) {\n \t\tdebug(\"  get_files_dirs done (0)\\n\");\n \t\treturn 0;\n \t}\n-\tn = files->nr + dirs->nr;\n+\tn = currentFileSet.nr + currentDirectorySet.nr;\n \tdebug(\"  get_files_dirs done (%d)\\n\", n);\n \treturn n;\n }\n \n /*\n- * TODO: this wrapper is so small, we can use path_list_lookup directly.\n- * Same goes for index_entry_get(), free_index_entries(), find_rename_bysrc(),\n- * free_rename_entries().\n- */\n-static struct stage_data *index_entry_find(struct path_list *ents,\n-\t\t\t\t\t    const char *path)\n-{\n-\tstruct path_list_item *item = path_list_lookup(path, ents);\n-\tif (item)\n-\t\treturn item->util;\n-\treturn NULL;\n-}\n-\n-static struct stage_data *index_entry_get(struct path_list *ents,\n-\t\t\t\t\t   const char *path)\n-{\n-\tstruct path_list_item *item = path_list_lookup(path, ents);\n-\n-\tif (item == NULL) {\n-\t\titem = path_list_insert(path, ents);\n-\t\titem->util = xcalloc(1, sizeof(struct stage_data));\n-\t}\n-\treturn item->util;\n-}\n-\n-/*\n- * TODO: since the result of index_entry_from_db() is tucked into a\n- * path_list anyway, this helper can do that already.\n- */\n-/*\n  * Returns a index_entry instance which doesn't have to correspond to\n  * a real cache entry in Git's index.\n  */\n-static struct stage_data *index_entry_from_db(const char *path,\n-\t\t\t\t\t       struct tree *o,\n-\t\t\t\t\t       struct tree *a,\n-\t\t\t\t\t       struct tree *b)\n+static struct stage_data *insert_stage_data(const char *path,\n+\t\tstruct tree *o, struct tree *a, struct tree *b,\n+\t\tstruct path_list *entries)\n {\n+\tstruct path_list_item *item;\n \tstruct stage_data *e = xcalloc(1, sizeof(struct stage_data));\n \tget_tree_entry(o->object.sha1, path,\n \t\t\te->stages[1].sha, &e->stages[1].mode);\n@@ -450,24 +372,16 @@ static struct stage_data *index_entry_fr\n \t\t\te->stages[2].sha, &e->stages[2].mode);\n \tget_tree_entry(b->object.sha1, path,\n \t\t\te->stages[3].sha, &e->stages[3].mode);\n+\titem = path_list_insert(path, entries);\n+\titem->util = e;\n \treturn e;\n }\n \n-static void free_index_entries(struct path_list **ents)\n-{\n-\tif (!*ents)\n-\t\treturn;\n-\n-\tpath_list_clear(*ents, 1);\n-\tfree(*ents);\n-\t*ents = NULL;\n-}\n-\n /*\n  * Create a dictionary mapping file names to CacheEntry objects. The\n  * dictionary contains one entry for every path with a non-zero stage entry.\n  */\n-static struct path_list *get_unmerged()\n+static struct path_list *get_unmerged(void)\n {\n \tstruct path_list *unmerged = xcalloc(1, sizeof(struct path_list));\n \tint i;\n@@ -478,16 +392,22 @@ static struct path_list *get_unmerged()\n \t\tcache_dirty++;\n \t}\n \tfor (i = 0; i < active_nr; i++) {\n+\t\tstruct path_list_item *item;\n+\t\tstruct stage_data *e;\n \t\tstruct cache_entry *ce = active_cache[i];\n \t\tif (!ce_stage(ce))\n \t\t\tcontinue;\n \n-\t\tstruct stage_data *e = index_entry_get(unmerged, ce->name);\n+\t\titem = path_list_lookup(ce->name, unmerged);\n+\t\tif (!item) {\n+\t\t\titem = path_list_insert(ce->name, unmerged);\n+\t\t\titem->util = xcalloc(1, sizeof(struct stage_data));\n+\t\t}\n+\t\te = item->util;\n \t\te->stages[ce_stage(ce)].mode = ntohl(ce->ce_mode);\n \t\tmemcpy(e->stages[ce_stage(ce)].sha, ce->sha1, 20);\n \t}\n \n-\tdebug(\"  get_unmerged done\\n\");\n \treturn unmerged;\n }\n \n@@ -499,25 +419,6 @@ struct rename\n \tunsigned processed:1;\n };\n \n-static struct rename *find_rename_bysrc(struct path_list *e,\n-\t\t\t\t\t      const char *name)\n-{\n-\tstruct path_list_item *item = path_list_lookup(name, e);\n-\tif (item)\n-\t\treturn item->util;\n-\treturn NULL;\n-}\n-\n-static void free_rename_entries(struct path_list **list)\n-{\n-\tif (!*list)\n-\t\treturn;\n-\n-\tpath_list_clear(*list, 0);\n-\tfree(*list);\n-\t*list = NULL;\n-}\n-\n /*\n  * Get information of all renames which occured between 'oTree' and\n  * 'tree'. We need the three trees in the merge ('oTree', 'aTree' and\n@@ -530,13 +431,16 @@ static struct path_list *get_renames(str\n \t\t\t\t\tstruct tree *bTree,\n \t\t\t\t\tstruct path_list *entries)\n {\n+\tint i;\n+\tstruct path_list *renames;\n+\tstruct diff_options opts;\n #ifdef DEBUG\n \ttime_t t = time(0);\n+\n \tdebug(\"getRenames ...\\n\");\n #endif\n-\tint i;\n-\tstruct path_list *renames = xcalloc(1, sizeof(struct path_list));\n-\tstruct diff_options opts;\n+\n+\trenames = xcalloc(1, sizeof(struct path_list));\n \tdiff_setup(&opts);\n \topts.recursive = 1;\n \topts.detect_rename = DIFF_DETECT_RENAME;\n@@ -546,6 +450,7 @@ #endif\n \tdiff_tree_sha1(oTree->object.sha1, tree->object.sha1, \"\", &opts);\n \tdiffcore_std(&opts);\n \tfor (i = 0; i < diff_queued_diff.nr; ++i) {\n+\t\tstruct path_list_item *item;\n \t\tstruct rename *re;\n \t\tstruct diff_filepair *pair = diff_queued_diff.queue[i];\n \t\tif (pair->status != 'R') {\n@@ -555,78 +460,66 @@ #endif\n \t\tre = xmalloc(sizeof(*re));\n \t\tre->processed = 0;\n \t\tre->pair = pair;\n-\t\tre->src_entry = index_entry_find(entries, re->pair->one->path);\n-\t\t/* TODO: should it not be an error, if src_entry was found? */\n-\t\tif ( !re->src_entry ) {\n-\t\t\tre->src_entry = index_entry_from_db(re->pair->one->path,\n-\t\t\t\t\toTree, aTree, bTree);\n-\t\t\tstruct path_list_item *item =\n-\t\t\t\tpath_list_insert(re->pair->one->path, entries);\n-\t\t\titem->util = re->src_entry;\n-\t\t}\n-\t\tre->dst_entry = index_entry_find(entries, re->pair->two->path);\n-\t\tif ( !re->dst_entry ) {\n-\t\t\tre->dst_entry = index_entry_from_db(re->pair->two->path,\n-\t\t\t\t\toTree, aTree, bTree);\n-\t\t\tstruct path_list_item *item =\n-\t\t\t\tpath_list_insert(re->pair->two->path, entries);\n-\t\t\titem->util = re->dst_entry;\n-\t\t}\n-\t\tstruct path_list_item *item = path_list_insert(pair->one->path, renames);\n+\t\titem = path_list_lookup(re->pair->one->path, entries);\n+\t\tif (!item)\n+\t\t\tre->src_entry = insert_stage_data(re->pair->one->path,\n+\t\t\t\t\toTree, aTree, bTree, entries);\n+\t\telse\n+\t\t\tre->src_entry = item->util;\n+\n+\t\titem = path_list_lookup(re->pair->two->path, entries);\n+\t\tif (!item)\n+\t\t\tre->dst_entry = insert_stage_data(re->pair->two->path,\n+\t\t\t\t\toTree, aTree, bTree, entries);\n+\t\telse\n+\t\t\tre->dst_entry = item->util;\n+\t\titem = path_list_insert(pair->one->path, renames);\n \t\titem->util = re;\n \t}\n \topts.output_format = DIFF_FORMAT_NO_OUTPUT;\n \tdiff_queued_diff.nr = 0;\n \tdiff_flush(&opts);\n+#ifdef DEBUG\n \tdebug(\"  getRenames done in %ld\\n\", time(0)-t);\n+#endif\n \treturn renames;\n }\n \n-/*\n- * TODO: the code would be way nicer, if we had a struct containing just sha1 and mode.\n- * In this particular case, we might get away reusing stage_data, no?\n- */\n-int update_stages(const char *path,\n-\t\t   unsigned char *osha, unsigned omode,\n-\t\t   unsigned char *asha, unsigned amode,\n-\t\t   unsigned char *bsha, unsigned bmode,\n-\t\t   int clear /* =True */)\n+int update_stages(const char *path, struct diff_filespec *o,\n+\t\tstruct diff_filespec *a, struct diff_filespec *b, int clear)\n {\n \tint options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE;\n-\tif ( clear )\n-\t\tif (add_cacheinfo(0, null_sha1, path, 0, 0, options))\n+\tif (clear) \n+\t\tif (remove_file_from_cache(path))\n \t\t\treturn -1;\n-\tif ( omode )\n-\t\tif (add_cacheinfo(omode, osha, path, 1, 0, options))\n+\tif (o)\n+\t\tif (add_cacheinfo(o->mode, o->sha1, path, 1, 0, options))\n \t\t\treturn -1;\n-\tif ( amode )\n-\t\tif (add_cacheinfo(omode, osha, path, 2, 0, options))\n+\tif (a)\n+\t\tif (add_cacheinfo(a->mode, a->sha1, path, 2, 0, options))\n \t\t\treturn -1;\n-\tif ( bmode )\n-\t\tif (add_cacheinfo(omode, osha, path, 3, 0, options))\n+\tif (b)\n+\t\tif (add_cacheinfo(b->mode, b->sha1, path, 3, 0, options))\n \t\t\treturn -1;\n \treturn 0;\n }\n \n-/*\n- * TODO: there has to be a function in libgit doing this exact thing.\n- */\n static int remove_path(const char *name)\n {\n-\tint ret;\n-\tchar *slash;\n+\tint ret, len;\n+\tchar *slash, *dirs;\n \n \tret = unlink(name);\n-\tif ( ret )\n+\tif (ret)\n \t\treturn ret;\n-\tint len = strlen(name);\n-\tchar *dirs = malloc(len+1);\n+\tlen = strlen(name);\n+\tdirs = malloc(len+1);\n \tmemcpy(dirs, name, len);\n \tdirs[len] = '\\0';\n-\twhile ( (slash = strrchr(name, '/')) ) {\n+\twhile ((slash = strrchr(name, '/'))) {\n \t\t*slash = '\\0';\n \t\tlen = slash - name;\n-\t\tif ( rmdir(name) != 0 )\n+\t\tif (rmdir(name) != 0)\n \t\t\tbreak;\n \t}\n \tfree(dirs);\n@@ -636,7 +529,7 @@ static int remove_path(const char *name)\n /* General TODO: unC99ify the code: no declaration after code */\n /* General TODO: no javaIfiCation: rename updateCache to update_cache */\n /*\n- * TODO: once we no longer call external programs, we'd probably be better of\n+ * TODO: once we no longer call external programs, we'd probably be better off\n  * not setting / getting the environment variable GIT_INDEX_FILE all the time.\n  */\n int remove_file(int clean, const char *path)\n@@ -644,17 +537,17 @@ int remove_file(int clean, const char *p\n \tint updateCache = index_only || clean;\n \tint updateWd = !index_only;\n \n-\tif ( updateCache ) {\n+\tif (updateCache) {\n \t\tif (!cache_dirty)\n \t\t\tread_cache_from(getenv(\"GIT_INDEX_FILE\"));\n \t\tcache_dirty++;\n \t\tif (remove_file_from_cache(path))\n \t\t\treturn -1;\n \t}\n-\tif ( updateWd )\n+\tif (updateWd)\n \t{\n \t\tunlink(path);\n-\t\tif ( errno != ENOENT || errno != EISDIR )\n+\t\tif (errno != ENOENT || errno != EISDIR)\n \t\t\treturn -1;\n \t\tremove_path(path);\n \t}\n@@ -664,55 +557,31 @@ int remove_file(int clean, const char *p\n static char *unique_path(const char *path, const char *branch)\n {\n \tchar *newpath = xmalloc(strlen(path) + 1 + strlen(branch) + 8 + 1);\n+\tint suffix = 0;\n+\tstruct stat st;\n+\tchar *p = newpath + strlen(newpath);\n \tstrcpy(newpath, path);\n \tstrcat(newpath, \"~\");\n-\tchar *p = newpath + strlen(newpath);\n \tstrcpy(p, branch);\n-\tfor ( ; *p; ++p )\n-\t\tif ( '/' == *p )\n+\tfor (; *p; ++p)\n+\t\tif ('/' == *p)\n \t\t\t*p = '_';\n-\tint suffix = 0;\n-\tstruct stat st;\n-\twhile ( path_list_has_path(&currentFileSet, newpath) ||\n-\t\tpath_list_has_path(&currentDirectorySet, newpath) ||\n-\t\tlstat(newpath, &st) == 0 ) {\n+\twhile (path_list_has_path(&currentFileSet, newpath) ||\n+\t       path_list_has_path(&currentDirectorySet, newpath) ||\n+\t       lstat(newpath, &st) == 0)\n \t\tsprintf(p, \"_%d\", suffix++);\n-\t}\n+\n \tpath_list_insert(newpath, &currentFileSet);\n \treturn newpath;\n }\n \n-/*\n- * TODO: except for create_last, this so looks like\n- * safe_create_leading_directories().\n- */\n-static int mkdir_p(const char *path, unsigned long mode, int create_last)\n+static int mkdir_p(const char *path, unsigned long mode)\n {\n+\t/* path points to cache entries, so strdup before messing with it */\n \tchar *buf = strdup(path);\n-\tchar *p;\n-\n-\tfor ( p = buf; *p; ++p ) {\n-\t\tif ( *p != '/' )\n-\t\t\tcontinue;\n-\t\t*p = '\\0';\n-\t\tif (mkdir(buf, mode)) {\n-\t\t\tint e = errno;\n-\t\t\tif ( e == EEXIST ) {\n-\t\t\t\tstruct stat st;\n-\t\t\t\tif ( !stat(buf, &st) && S_ISDIR(st.st_mode) )\n-\t\t\t\t\tgoto next; /* ok */\n-\t\t\t\terrno = e;\n-\t\t\t}\n-\t\t\tfree(buf);\n-\t\t\treturn -1;\n-\t\t}\n-\tnext:\n-\t\t*p = '/';\n-\t}\n+\tint result = safe_create_leading_directories(buf);\n \tfree(buf);\n-\tif ( create_last && mkdir(path, mode) )\n-\t\treturn -1;\n-\treturn 0;\n+\treturn result;\n }\n \n static void flush_buffer(int fd, const char *buf, unsigned long size)\n@@ -732,17 +601,16 @@ static void flush_buffer(int fd, const c\n \t}\n }\n \n-/* General TODO: reindent according to guide lines (no if ( blabla )) */\n void update_file_flags(const unsigned char *sha,\n-\t\t   unsigned mode,\n-\t\t   const char *path,\n-\t\t   int updateCache,\n-\t\t   int updateWd)\n+\t\t       unsigned mode,\n+\t\t       const char *path,\n+\t\t       int update_cache,\n+\t\t       int update_wd)\n {\n-\tif ( index_only )\n-\t\tupdateWd = 0;\n+\tif (index_only)\n+\t\tupdate_wd = 0;\n \n-\tif ( updateWd ) {\n+\tif (update_wd) {\n \t\tchar type[20];\n \t\tvoid *buf;\n \t\tunsigned long size;\n@@ -750,37 +618,38 @@ void update_file_flags(const unsigned ch\n \t\tbuf = read_sha1_file(sha, type, &size);\n \t\tif (!buf)\n \t\t\tdie(\"cannot read object %s '%s'\", sha1_to_hex(sha), path);\n-\t\tif ( strcmp(type, blob_type) != 0 )\n+\t\tif (strcmp(type, blob_type) != 0)\n \t\t\tdie(\"blob expected for %s '%s'\", sha1_to_hex(sha), path);\n \n-\t\tif ( S_ISREG(mode) ) {\n-\t\t\tif ( mkdir_p(path, 0777, 0 /* don't create last element */) )\n+\t\tif (S_ISREG(mode)) {\n+\t\t\tint fd;\n+\t\t\tif (mkdir_p(path, 0777))\n \t\t\t\tdie(\"failed to create path %s: %s\", path, strerror(errno));\n \t\t\tunlink(path);\n-\t\t\tif ( mode & 0100 )\n+\t\t\tif (mode & 0100)\n \t\t\t\tmode = 0777;\n \t\t\telse\n \t\t\t\tmode = 0666;\n-\t\t\tint fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);\n-\t\t\tif ( fd < 0 )\n+\t\t\tfd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);\n+\t\t\tif (fd < 0)\n \t\t\t\tdie(\"failed to open %s: %s\", path, strerror(errno));\n \t\t\tflush_buffer(fd, buf, size);\n \t\t\tclose(fd);\n-\t\t} else if ( S_ISLNK(mode) ) {\n-\t\t\tchar *linkTarget = malloc(size + 1);\n-\t\t\tmemcpy(linkTarget, buf, size);\n-\t\t\tlinkTarget[size] = '\\0';\n-\t\t\tmkdir_p(path, 0777, 0);\n-\t\t\tsymlink(linkTarget, path);\n+\t\t} else if (S_ISLNK(mode)) {\n+\t\t\tchar *lnk = malloc(size + 1);\n+\t\t\tmemcpy(lnk, buf, size);\n+\t\t\tlnk[size] = '\\0';\n+\t\t\tmkdir_p(path, 0777);\n+\t\t\tunlink(lnk);\n+\t\t\tsymlink(lnk, path);\n \t\t} else\n \t\t\tdie(\"do not know what to do with %06o %s '%s'\",\n \t\t\t    mode, sha1_to_hex(sha), path);\n \t}\n-\tif ( updateCache )\n-\t\tadd_cacheinfo(mode, sha, path, 0, updateWd, ADD_CACHE_OK_TO_ADD);\n+\tif (update_cache)\n+\t\tadd_cacheinfo(mode, sha, path, 0, update_wd, ADD_CACHE_OK_TO_ADD);\n }\n \n-/* TODO: is this often used? if not, do direct call */\n void update_file(int clean,\n \t\tconst unsigned char *sha,\n \t\tunsigned mode,\n@@ -819,64 +688,53 @@ static char *git_unpack_file(const unsig\n \treturn path;\n }\n \n-/*\n- * TODO: the signature would be much more efficient using stage_data\n- */\n-static struct merge_file_info merge_file(const char *oPath,\n-\t\t\t\t\t const unsigned char *oSha,\n-\t\t\t\t\t unsigned oMode,\n-\t\t\t\t\t const char *aPath,\n-\t\t\t\t\t const unsigned char *aSha,\n-\t\t\t\t\t unsigned aMode,\n-\t\t\t\t\t const char *bPath,\n-\t\t\t\t\t const unsigned char *bSha,\n-\t\t\t\t\t unsigned bMode,\n-\t\t\t\t\t const char *branch1Name,\n-\t\t\t\t\t const char *branch2Name)\n+static struct merge_file_info merge_file(struct diff_filespec *o,\n+\t\tstruct diff_filespec *a, struct diff_filespec *b,\n+\t\tconst char *branch1Name, const char *branch2Name)\n {\n \tstruct merge_file_info result;\n \tresult.merge = 0;\n \tresult.clean = 1;\n \n-\tif ( (S_IFMT & aMode) != (S_IFMT & bMode) ) {\n+\tif ((S_IFMT & a->mode) != (S_IFMT & b->mode)) {\n \t\tresult.clean = 0;\n-\t\tif ( S_ISREG(aMode) ) {\n-\t\t\tresult.mode = aMode;\n-\t\t\tmemcpy(result.sha, aSha, 20);\n+\t\tif (S_ISREG(a->mode)) {\n+\t\t\tresult.mode = a->mode;\n+\t\t\tmemcpy(result.sha, a->sha1, 20);\n \t\t} else {\n-\t\t\tresult.mode = bMode;\n-\t\t\tmemcpy(result.sha, bSha, 20);\n+\t\t\tresult.mode = b->mode;\n+\t\t\tmemcpy(result.sha, b->sha1, 20);\n \t\t}\n \t} else {\n-\t\tif ( memcmp(aSha, oSha, 20) != 0 && memcmp(bSha, oSha, 20) != 0 )\n+\t\tif (!sha_eq(a->sha1, o->sha1) && !sha_eq(b->sha1, o->sha1))\n \t\t\tresult.merge = 1;\n \n-\t\tresult.mode = aMode == oMode ? bMode: aMode;\n-\n-\t\tif ( memcmp(aSha, oSha, 20) == 0 )\n-\t\t\tmemcpy(result.sha, bSha, 20);\n-\t\telse if ( memcmp(bSha, oSha, 20) == 0 )\n-\t\t\tmemcpy(result.sha, aSha, 20);\n-\t\telse if ( S_ISREG(aMode) ) {\n+\t\tresult.mode = a->mode == o->mode ? b->mode: a->mode;\n \n-\t\t\tint code = 1;\n+\t\tif (sha_eq(a->sha1, o->sha1))\n+\t\t\tmemcpy(result.sha, b->sha1, 20);\n+\t\telse if (sha_eq(b->sha1, o->sha1))\n+\t\t\tmemcpy(result.sha, a->sha1, 20);\n+\t\telse if (S_ISREG(a->mode)) {\n+\t\t\tint code = 1, fd;\n+\t\t\tstruct stat st;\n \t\t\tchar orig[PATH_MAX];\n \t\t\tchar src1[PATH_MAX];\n \t\t\tchar src2[PATH_MAX];\n-\n-\t\t\tgit_unpack_file(oSha, orig);\n-\t\t\tgit_unpack_file(aSha, src1);\n-\t\t\tgit_unpack_file(bSha, src2);\n-\n \t\t\tconst char *argv[] = {\n \t\t\t\t\"merge\", \"-L\", NULL, \"-L\", NULL, \"-L\", NULL,\n \t\t\t\tsrc1, orig, src2,\n \t\t\t\tNULL\n \t\t\t};\n \t\t\tchar *la, *lb, *lo;\n-\t\t\targv[2] = la = strdup(mkpath(\"%s/%s\", branch1Name, aPath));\n-\t\t\targv[6] = lb = strdup(mkpath(\"%s/%s\", branch2Name, bPath));\n-\t\t\targv[4] = lo = strdup(mkpath(\"orig/%s\", oPath));\n+\n+\t\t\tgit_unpack_file(o->sha1, orig);\n+\t\t\tgit_unpack_file(a->sha1, src1);\n+\t\t\tgit_unpack_file(b->sha1, src2);\n+\n+\t\t\targv[2] = la = strdup(mkpath(\"%s/%s\", branch1Name, a->path));\n+\t\t\targv[6] = lb = strdup(mkpath(\"%s/%s\", branch2Name, b->path));\n+\t\t\targv[4] = lo = strdup(mkpath(\"orig/%s\", o->path));\n \n #if 0\n \t\t\tprintf(\"%s %s %s %s %s %s %s %s %s %s\\n\",\n@@ -888,17 +746,15 @@ #endif\n \t\t\tfree(la);\n \t\t\tfree(lb);\n \t\t\tfree(lo);\n-\t\t\tif ( code && code < -256 ) {\n+\t\t\tif (code && code < -256) {\n \t\t\t\tdie(\"Failed to execute 'merge'. merge(1) is used as the \"\n \t\t\t\t    \"file-level merge tool. Is 'merge' in your path?\");\n \t\t\t}\n-\t\t\tstruct stat st;\n-\t\t\tint fd = open(src1, O_RDONLY);\n+\t\t\tfd = open(src1, O_RDONLY);\n \t\t\tif (fd < 0 || fstat(fd, &st) < 0 ||\n \t\t\t\t\tindex_fd(result.sha, fd, &st, 1,\n \t\t\t\t\t\t\"blob\"))\n \t\t\t\tdie(\"Unable to add %s to database\", src1);\n-\t\t\tclose(fd);\n \n \t\t\tunlink(orig);\n \t\t\tunlink(src1);\n@@ -906,12 +762,12 @@ #endif\n \n \t\t\tresult.clean = WEXITSTATUS(code) == 0;\n \t\t} else {\n-\t\t\tif ( !(S_ISLNK(aMode) || S_ISLNK(bMode)) )\n+\t\t\tif (!(S_ISLNK(a->mode) || S_ISLNK(b->mode)))\n \t\t\t\tdie(\"cannot merge modes?\");\n \n-\t\t\tmemcpy(result.sha, aSha, 20);\n+\t\t\tmemcpy(result.sha, a->sha1, 20);\n \n-\t\t\tif ( memcmp(aSha, bSha, 20) != 0 )\n+\t\t\tif (!sha_eq(a->sha1, b->sha1))\n \t\t\t\tresult.clean = 0;\n \t\t}\n \t}\n@@ -942,17 +798,9 @@ static void conflict_rename_rename(struc\n \t\t       ren2_dst, branch1, dstName2);\n \t\tremove_file(0, ren2_dst);\n \t}\n-\tupdate_stages(dstName1,\n-\t\t      NULL, 0,\n-\t\t      ren1->pair->two->sha1, ren1->pair->two->mode,\n-\t\t      NULL, 0,\n-\t\t      1 /* clear */);\n-\tupdate_stages(dstName2,\n-\t\t      NULL, 0,\n-\t\t      NULL, 0,\n-\t\t      ren2->pair->two->sha1, ren2->pair->two->mode,\n-\t\t      1 /* clear */);\n-\twhile ( delp-- )\n+\tupdate_stages(dstName1, NULL, ren1->pair->two, NULL, 1);\n+\tupdate_stages(dstName2, NULL, NULL, ren2->pair->two, 1);\n+\twhile (delp--)\n \t\tfree(del[delp]);\n }\n \n@@ -989,66 +837,73 @@ static int process_renames(struct path_l\n \t\t\t   const char *branchNameA,\n \t\t\t   const char *branchNameB)\n {\n-\tint cleanMerge = 1, i;\n-\tstruct path_list srcNames = {NULL, 0, 0, 0}, byDstA = {NULL, 0, 0, 0}, byDstB = {NULL, 0, 0, 0};\n+\tint cleanMerge = 1, i, j;\n+\tstruct path_list byDstA = {NULL, 0, 0, 0}, byDstB = {NULL, 0, 0, 0};\n \tconst struct rename *sre;\n \n-\t/*\n-\t * TODO: think about a saner way to do this.\n-\t * Since both renamesA and renamesB are sorted, it should\n-\t * be much more efficient to traverse both simultaneously,\n-\t * only byDstA and byDstB should be needed.\n-\t */\n-\tdebug(\"processRenames...\\n\");\n \tfor (i = 0; i < renamesA->nr; i++) {\n \t\tsre = renamesA->items[i].util;\n-\t\tpath_list_insert(sre->pair->one->path, &srcNames);\n \t\tpath_list_insert(sre->pair->two->path, &byDstA)->util\n \t\t\t= sre->dst_entry;\n \t}\n \tfor (i = 0; i < renamesB->nr; i++) {\n \t\tsre = renamesB->items[i].util;\n-\t\tpath_list_insert(sre->pair->one->path, &srcNames);\n \t\tpath_list_insert(sre->pair->two->path, &byDstB)->util\n \t\t\t= sre->dst_entry;\n \t}\n \n-\tfor (i = 0; i < srcNames.nr; i++) {\n-\t\tchar *src = srcNames.items[i].path;\n+\tfor (i = 0, j = 0; i < renamesA->nr || j < renamesB->nr;) {\n+\t\tint compare;\n+\t\tchar *src;\n \t\tstruct path_list *renames1, *renames2, *renames2Dst;\n-\t\tstruct rename *ren1, *ren2;\n+\t\tstruct rename *ren1 = NULL, *ren2 = NULL;\n \t\tconst char *branchName1, *branchName2;\n-\t\tren1 = find_rename_bysrc(renamesA, src);\n-\t\tren2 = find_rename_bysrc(renamesB, src);\n+\t\tconst char *ren1_src, *ren1_dst;\n+\n+\t\tif (i >= renamesA->nr) {\n+\t\t\tcompare = 1;\n+\t\t\tren2 = renamesB->items[j++].util;\n+\t\t} else if (j >= renamesB->nr) {\n+\t\t\tcompare = -1;\n+\t\t\tren1 = renamesA->items[i++].util;\n+\t\t} else {\n+\t\t\tcompare = strcmp(renamesA->items[i].path,\n+\t\t\t\t\trenamesB->items[j].path);\n+\t\t\tren1 = renamesA->items[i++].util;\n+\t\t\tren2 = renamesB->items[j++].util;\n+\t\t}\n+\n \t\t/* TODO: refactor, so that 1/2 are not needed */\n-\t\tif ( ren1 ) {\n+\t\tif (ren1) {\n \t\t\trenames1 = renamesA;\n \t\t\trenames2 = renamesB;\n \t\t\trenames2Dst = &byDstB;\n \t\t\tbranchName1 = branchNameA;\n \t\t\tbranchName2 = branchNameB;\n \t\t} else {\n+\t\t\tstruct rename *tmp;\n \t\t\trenames1 = renamesB;\n \t\t\trenames2 = renamesA;\n \t\t\trenames2Dst = &byDstA;\n \t\t\tbranchName1 = branchNameB;\n \t\t\tbranchName2 = branchNameA;\n-\t\t\tstruct rename *tmp = ren2;\n+\t\t\ttmp = ren2;\n \t\t\tren2 = ren1;\n \t\t\tren1 = tmp;\n \t\t}\n+\t\tsrc = ren1->pair->one->path;\n \n \t\tren1->dst_entry->processed = 1;\n \t\tren1->src_entry->processed = 1;\n \n-\t\tif ( ren1->processed )\n+\t\tif (ren1->processed)\n \t\t\tcontinue;\n \t\tren1->processed = 1;\n \n-\t\tconst char *ren1_src = ren1->pair->one->path;\n-\t\tconst char *ren1_dst = ren1->pair->two->path;\n+\t\tren1_src = ren1->pair->one->path;\n+\t\tren1_dst = ren1->pair->two->path;\n \n-\t\tif ( ren2 ) {\n+\t\tif (ren2) {\n \t\t\tconst char *ren2_src = ren2->pair->one->path;\n \t\t\tconst char *ren2_dst = ren2->pair->two->path;\n \t\t\t/* Renamed in 1 and renamed in 2 */\n@@ -1067,57 +922,48 @@ static int process_renames(struct path_l\n \t\t\t} else {\n \t\t\t\tremove_file(1, ren1_src);\n \t\t\t\tstruct merge_file_info mfi;\n-\t\t\t\tmfi = merge_file(ren1_src,\n-\t\t\t\t\t\t ren1->pair->one->sha1,\n-\t\t\t\t\t\t ren1->pair->one->mode,\n-\t\t\t\t\t\t ren1_dst,\n-\t\t\t\t\t\t ren1->pair->two->sha1,\n-\t\t\t\t\t\t ren1->pair->two->mode,\n-\t\t\t\t\t\t ren2_dst,\n-\t\t\t\t\t\t ren2->pair->two->sha1,\n-\t\t\t\t\t\t ren2->pair->two->mode,\n+\t\t\t\tmfi = merge_file(ren1->pair->one,\n+\t\t\t\t\t\t ren1->pair->two,\n+\t\t\t\t\t\t ren2->pair->two,\n \t\t\t\t\t\t branchName1,\n \t\t\t\t\t\t branchName2);\n-\t\t\t\tif ( mfi.merge || !mfi.clean )\n+\t\t\t\tif (mfi.merge || !mfi.clean)\n \t\t\t\t\toutput(\"Renaming %s->%s\", src, ren1_dst);\n \n-\t\t\t\tif ( mfi.merge )\n+\t\t\t\tif (mfi.merge)\n \t\t\t\t\toutput(\"Auto-merging %s\", ren1_dst);\n \n-\t\t\t\tif ( !mfi.clean ) {\n+\t\t\t\tif (!mfi.clean) {\n \t\t\t\t\toutput(\"CONFLICT (content): merge conflict in %s\",\n \t\t\t\t\t       ren1_dst);\n \t\t\t\t\tcleanMerge = 0;\n \n-\t\t\t\t\tif ( !index_only )\n+\t\t\t\t\tif (!index_only)\n \t\t\t\t\t\tupdate_stages(ren1_dst,\n-\t\t\t\t\t\t\t      ren1->pair->one->sha1,\n-\t\t\t\t\t\t\t      ren1->pair->one->mode,\n-\t\t\t\t\t\t\t      ren1->pair->two->sha1,\n-\t\t\t\t\t\t\t      ren1->pair->two->mode,\n-\t\t\t\t\t\t\t      ren2->pair->two->sha1,\n-\t\t\t\t\t\t\t      ren2->pair->two->mode,\n+\t\t\t\t\t\t\t      ren1->pair->one,\n+\t\t\t\t\t\t\t      ren1->pair->two,\n+\t\t\t\t\t\t\t      ren2->pair->two,\n \t\t\t\t\t\t\t      1 /* clear */);\n \t\t\t\t}\n \t\t\t\tupdate_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst);\n \t\t\t}\n \t\t} else {\n \t\t\t/* Renamed in 1, maybe changed in 2 */\n-\t\t\tremove_file(1, ren1_src);\n-\n-\t\t\tunsigned char srcShaOtherBranch[20], dstShaOtherBranch[20];\n-\t\t\tunsigned srcModeOtherBranch, dstModeOtherBranch;\n-\n-\t\t\tint stage = renamesA == renames1 ? 3: 2;\n+\t\t\tstruct path_list_item *item;\n+\t\t\t/* we only use sha1 and mode of these */\n+\t\t\tstruct diff_filespec src_other, dst_other;\n+\t\t\tint tryMerge, stage = renamesA == renames1 ? 3: 2;\n \n-\t\t\tmemcpy(srcShaOtherBranch, ren1->src_entry->stages[stage].sha, 20);\n-\t\t\tsrcModeOtherBranch = ren1->src_entry->stages[stage].mode;\n+\t\t\tremove_file(1, ren1_src);\n \n-\t\t\tmemcpy(dstShaOtherBranch, ren1->dst_entry->stages[stage].sha, 20);\n-\t\t\tdstModeOtherBranch = ren1->dst_entry->stages[stage].mode;\n+\t\t\tmemcpy(src_other.sha1,\n+\t\t\t\t\tren1->src_entry->stages[stage].sha, 20);\n+\t\t\tsrc_other.mode = ren1->src_entry->stages[stage].mode;\n+\t\t\tmemcpy(dst_other.sha1,\n+\t\t\t\t\tren1->dst_entry->stages[stage].sha, 20);\n+\t\t\tdst_other.mode = ren1->dst_entry->stages[stage].mode;\n \n-\t\t\tint tryMerge = 0;\n-\t\t\tchar *newPath;\n+\t\t\ttryMerge = 0;\n \n \t\t\tif (path_list_has_path(&currentDirectorySet, ren1_dst)) {\n \t\t\t\tcleanMerge = 0;\n@@ -1126,14 +972,15 @@ static int process_renames(struct path_l\n \t\t\t\t       ren1_src, ren1_dst, branchName1,\n \t\t\t\t       ren1_dst, branchName2);\n \t\t\t\tconflict_rename_dir(ren1, branchName1);\n-\t\t\t} else if ( memcmp(srcShaOtherBranch, null_sha1, 20) == 0 ) {\n+\t\t\t} else if (sha_eq(src_other.sha1, null_sha1)) {\n \t\t\t\tcleanMerge = 0;\n \t\t\t\toutput(\"CONFLICT (rename/delete): Rename %s->%s in %s \"\n \t\t\t\t       \"and deleted in %s\",\n \t\t\t\t       ren1_src, ren1_dst, branchName1,\n \t\t\t\t       branchName2);\n \t\t\t\tupdate_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst);\n-\t\t\t} else if ( memcmp(dstShaOtherBranch, null_sha1, 20) != 0 ) {\n+\t\t\t} else if (!sha_eq(dst_other.sha1, null_sha1)) {\n+\t\t\t\tconst char *newPath;\n \t\t\t\tcleanMerge = 0;\n \t\t\t\ttryMerge = 1;\n \t\t\t\toutput(\"CONFLICT (rename/add): Rename %s->%s in %s. \"\n@@ -1142,8 +989,9 @@ static int process_renames(struct path_l\n \t\t\t\t       ren1_dst, branchName2);\n \t\t\t\tnewPath = unique_path(ren1_dst, branchName2);\n \t\t\t\toutput(\"Adding as %s instead\", newPath);\n-\t\t\t\tupdate_file(0, dstShaOtherBranch, dstModeOtherBranch, newPath);\n-\t\t\t} else if ( (ren2 = find_rename_bysrc(renames2Dst, ren1_dst)) ) {\n+\t\t\t\tupdate_file(0, dst_other.sha1, dst_other.mode, newPath);\n+\t\t\t} else if ((item = path_list_lookup(ren1_dst, renames2Dst))) {\n+\t\t\t\tren2 = item->util;\n \t\t\t\tcleanMerge = 0;\n \t\t\t\tren2->processed = 1;\n \t\t\t\toutput(\"CONFLICT (rename/rename): Rename %s->%s in %s. \"\n@@ -1154,53 +1002,41 @@ static int process_renames(struct path_l\n \t\t\t} else\n \t\t\t\ttryMerge = 1;\n \n-\t\t\tif ( tryMerge ) {\n-\t\t\t\tconst char *oname = ren1_src;\n-\t\t\t\tconst char *aname = ren1_dst;\n-\t\t\t\tconst char *bname = ren1_src;\n-\t\t\t\tunsigned char osha[20], asha[20], bsha[20];\n-\t\t\t\tunsigned omode = ren1->pair->one->mode;\n-\t\t\t\tunsigned amode = ren1->pair->two->mode;\n-\t\t\t\tunsigned bmode = srcModeOtherBranch;\n-\t\t\t\tmemcpy(osha, ren1->pair->one->sha1, 20);\n-\t\t\t\tmemcpy(asha, ren1->pair->two->sha1, 20);\n-\t\t\t\tmemcpy(bsha, srcShaOtherBranch, 20);\n-\t\t\t\tconst char *aBranch = branchName1;\n-\t\t\t\tconst char *bBranch = branchName2;\n-\n-\t\t\t\tif ( renamesA != renames1 ) {\n-\t\t\t\t\tmemswp(&aname, &bname, sizeof(aname));\n-\t\t\t\t\tmemswp(asha, bsha, 20);\n-\t\t\t\t\tmemswp(&aBranch, &bBranch, sizeof(aBranch));\n-\t\t\t\t}\n+\t\t\tif (tryMerge) {\n+\t\t\t\tstruct diff_filespec *o, *a, *b;\n \t\t\t\tstruct merge_file_info mfi;\n-\t\t\t\tmfi = merge_file(oname, osha, omode,\n-\t\t\t\t\t\t aname, asha, amode,\n-\t\t\t\t\t\t bname, bsha, bmode,\n-\t\t\t\t\t\t aBranch, bBranch);\n+\t\t\t\tsrc_other.path = (char *)ren1_src;\n+\n+\t\t\t\to = ren1->pair->one;\n+\t\t\t\tif (renamesA == renames1) {\n+\t\t\t\t\ta = ren1->pair->two;\n+\t\t\t\t\tb = &src_other;\n+\t\t\t\t} else {\n+\t\t\t\t\tb = ren1->pair->two;\n+\t\t\t\t\ta = &src_other;\n+\t\t\t\t}\n+\t\t\t\tmfi = merge_file(o, a, b,\n+\t\t\t\t\t\tbranchNameA, branchNameB);\n \n-\t\t\t\tif ( mfi.merge || !mfi.clean )\n+\t\t\t\tif (mfi.merge || !mfi.clean)\n \t\t\t\t\toutput(\"Renaming %s => %s\", ren1_src, ren1_dst);\n-\t\t\t\tif ( mfi.merge )\n+\t\t\t\tif (mfi.merge)\n \t\t\t\t\toutput(\"Auto-merging %s\", ren1_dst);\n-\t\t\t\tif ( !mfi.clean ) {\n+\t\t\t\tif (!mfi.clean) {\n \t\t\t\t\toutput(\"CONFLICT (rename/modify): Merge conflict in %s\",\n \t\t\t\t\t       ren1_dst);\n \t\t\t\t\tcleanMerge = 0;\n \n-\t\t\t\t\tif ( !index_only )\n+\t\t\t\t\tif (!index_only)\n \t\t\t\t\t\tupdate_stages(ren1_dst,\n-\t\t\t\t\t\t\t      osha, omode,\n-\t\t\t\t\t\t\t      asha, amode,\n-\t\t\t\t\t\t\t      bsha, bmode,\n-\t\t\t\t\t\t\t      1 /* clear */);\n+\t\t\t\t\t\t\t\to, a, b, 1);\n \t\t\t\t}\n \t\t\t\tupdate_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst);\n \t\t\t}\n \t\t}\n \t}\n-\tpath_list_clear(&srcNames, 0);\n-\tdebug(\"  processRenames done\\n\");\n+\tpath_list_clear(&byDstA, 0);\n+\tpath_list_clear(&byDstB, 0);\n \n \tif (cache_dirty)\n \t\tflush_cache();\n@@ -1229,20 +1065,20 @@ static int process_entry(const char *pat\n \tunsigned aMode = entry->stages[2].mode;\n \tunsigned bMode = entry->stages[3].mode;\n \n-\tif ( oSha && (!aSha || !bSha) ) {\n+\tif (oSha && (!aSha || !bSha)) {\n \t\t/* Case A: Deleted in one */\n-\t\tif ( (!aSha && !bSha) ||\n-\t\t     (sha_eq(aSha, oSha) && !bSha) ||\n-\t\t     (!aSha && sha_eq(bSha, oSha)) ) {\n+\t\tif ((!aSha && !bSha) ||\n+\t\t    (sha_eq(aSha, oSha) && !bSha) ||\n+\t\t    (!aSha && sha_eq(bSha, oSha))) {\n \t\t\t/* Deleted in both or deleted in one and\n \t\t\t * unchanged in the other */\n-\t\t\tif ( aSha )\n+\t\t\tif (aSha)\n \t\t\t\toutput(\"Removing %s\", path);\n \t\t\tremove_file(1, path);\n \t\t} else {\n \t\t\t/* Deleted in one and changed in the other */\n \t\t\tcleanMerge = 0;\n-\t\t\tif ( !aSha ) {\n+\t\t\tif (!aSha) {\n \t\t\t\toutput(\"CONFLICT (delete/modify): %s deleted in %s \"\n \t\t\t\t       \"and modified in %s. Version %s of %s left in tree.\",\n \t\t\t\t       path, branch1Name,\n@@ -1257,8 +1093,8 @@ static int process_entry(const char *pat\n \t\t\t}\n \t\t}\n \n-\t} else if ( (!oSha && aSha && !bSha) ||\n-\t\t    (!oSha && !aSha && bSha) ) {\n+\t} else if ((!oSha && aSha && !bSha) ||\n+\t\t   (!oSha && !aSha && bSha)) {\n \t\t/* Case B: Added in one. */\n \t\tconst char *addBranch;\n \t\tconst char *otherBranch;\n@@ -1266,7 +1102,7 @@ static int process_entry(const char *pat\n \t\tconst unsigned char *sha;\n \t\tconst char *conf;\n \n-\t\tif ( aSha ) {\n+\t\tif (aSha) {\n \t\t\taddBranch = branch1Name;\n \t\t\totherBranch = branch2Name;\n \t\t\tmode = aMode;\n@@ -1279,9 +1115,9 @@ static int process_entry(const char *pat\n \t\t\tsha = bSha;\n \t\t\tconf = \"directory/file\";\n \t\t}\n-\t\tif ( path_list_has_path(&currentDirectorySet, path) ) {\n-\t\t\tcleanMerge = 0;\n+\t\tif (path_list_has_path(&currentDirectorySet, path)) {\n \t\t\tconst char *newPath = unique_path(path, addBranch);\n+\t\t\tcleanMerge = 0;\n \t\t\toutput(\"CONFLICT (%s): There is a directory with name %s in %s. \"\n \t\t\t       \"Adding %s as %s\",\n \t\t\t       conf, path, otherBranch, path, newPath);\n@@ -1291,10 +1127,10 @@ static int process_entry(const char *pat\n \t\t\toutput(\"Adding %s\", path);\n \t\t\tupdate_file(1, sha, mode, path);\n \t\t}\n-\t} else if ( !oSha && aSha && bSha ) {\n+\t} else if (!oSha && aSha && bSha) {\n \t\t/* Case C: Added in both (check for same permissions). */\n-\t\tif ( sha_eq(aSha, bSha) ) {\n-\t\t\tif ( aMode != bMode ) {\n+\t\tif (sha_eq(aSha, bSha)) {\n+\t\t\tif (aMode != bMode) {\n \t\t\t\tcleanMerge = 0;\n \t\t\t\toutput(\"CONFLICT: File %s added identically in both branches, \"\n \t\t\t\t       \"but permissions conflict %06o->%06o\",\n@@ -1306,9 +1142,10 @@ static int process_entry(const char *pat\n \t\t\t\tassert(0 && \"This case must be handled by git-read-tree\");\n \t\t\t}\n \t\t} else {\n+\t\t\tconst char *newPath1, *newPath2;\n \t\t\tcleanMerge = 0;\n-\t\t\tconst char *newPath1 = unique_path(path, branch1Name);\n-\t\t\tconst char *newPath2 = unique_path(path, branch2Name);\n+\t\t\tnewPath1 = unique_path(path, branch1Name);\n+\t\t\tnewPath2 = unique_path(path, branch2Name);\n \t\t\toutput(\"CONFLICT (add/add): File %s added non-identically \"\n \t\t\t       \"in both branches. Adding as %s and %s instead.\",\n \t\t\t       path, newPath1, newPath2);\n@@ -1317,22 +1154,30 @@ static int process_entry(const char *pat\n \t\t\tupdate_file(0, bSha, bMode, newPath2);\n \t\t}\n \n-\t} else if ( oSha && aSha && bSha ) {\n+\t} else if (oSha && aSha && bSha) {\n \t\t/* case D: Modified in both, but differently. */\n-\t\toutput(\"Auto-merging %s\", path);\n \t\tstruct merge_file_info mfi;\n-\t\tmfi = merge_file(path, oSha, oMode,\n-\t\t\t\t path, aSha, aMode,\n-\t\t\t\t path, bSha, bMode,\n+\t\tstruct diff_filespec o, a, b;\n+\n+\t\toutput(\"Auto-merging %s\", path);\n+\t\to.path = a.path = b.path = (char *)path;\n+\t\tmemcpy(o.sha1, oSha, 20);\n+\t\to.mode = oMode;\n+\t\tmemcpy(a.sha1, aSha, 20);\n+\t\ta.mode = aMode;\n+\t\tmemcpy(b.sha1, bSha, 20);\n+\t\tb.mode = bMode;\n+\t\t\n+\t\tmfi = merge_file(&o, &a, &b,\n \t\t\t\t branch1Name, branch2Name);\n \n-\t\tif ( mfi.clean )\n+\t\tif (mfi.clean)\n \t\t\tupdate_file(1, mfi.sha, mfi.mode, path);\n \t\telse {\n \t\t\tcleanMerge = 0;\n \t\t\toutput(\"CONFLICT (content): Merge conflict in %s\", path);\n \n-\t\t\tif ( index_only )\n+\t\t\tif (index_only)\n \t\t\t\tupdate_file(0, mfi.sha, mfi.mode, path);\n \t\t\telse\n \t\t\t\tupdate_file_flags(mfi.sha, mfi.mode, path,\n@@ -1347,73 +1192,68 @@ static int process_entry(const char *pat\n \treturn cleanMerge;\n }\n \n-static struct merge_tree_result merge_trees(struct tree *head,\n-\t\t\t\t\t    struct tree *merge,\n-\t\t\t\t\t    struct tree *common,\n-\t\t\t\t\t    const char *branch1Name,\n-\t\t\t\t\t    const char *branch2Name)\n+static int merge_trees(struct tree *head,\n+\t\t       struct tree *merge,\n+\t\t       struct tree *common,\n+\t\t       const char *branch1Name,\n+\t\t       const char *branch2Name,\n+\t\t       struct tree **result)\n {\n-\tint code;\n-\tstruct merge_tree_result result = { NULL, 0 };\n-\tif ( !memcmp(common->object.sha1, merge->object.sha1, 20) ) {\n+\tint code, clean;\n+\tif (sha_eq(common->object.sha1, merge->object.sha1)) {\n \t\toutput(\"Already uptodate!\");\n-\t\tresult.tree = head;\n-\t\tresult.clean = 1;\n-\t\treturn result;\n+\t\t*result = head;\n+\t\treturn 1;\n \t}\n \n-\tdebug(\"merge_trees ...\\n\");\n \tcode = git_merge_trees(index_only ? \"-i\": \"-u\", common, head, merge);\n \n-\tif ( code != 0 )\n+\tif (code != 0)\n \t\tdie(\"merging of trees %s and %s failed\",\n \t\t    sha1_to_hex(head->object.sha1),\n \t\t    sha1_to_hex(merge->object.sha1));\n \n-\tresult.tree = git_write_tree();\n+\t*result = git_write_tree();\n \n-\tif ( !result.tree ) {\n+\tif (!*result) {\n+\t\tstruct path_list *entries, *re_head, *re_merge;\n+\t\tint i;\n \t\tpath_list_clear(&currentFileSet, 1);\n \t\tpath_list_clear(&currentDirectorySet, 1);\n-\t\tget_files_dirs(head, &currentFileSet, &currentDirectorySet);\n-\t\tget_files_dirs(merge, &currentFileSet, &currentDirectorySet);\n+\t\tget_files_dirs(head);\n+\t\tget_files_dirs(merge);\n \n-\t\tstruct path_list *entries = get_unmerged();\n-\t\tstruct path_list *re_head, *re_merge;\n+\t\tentries = get_unmerged();\n \t\tre_head  = get_renames(head, common, head, merge, entries);\n \t\tre_merge = get_renames(merge, common, head, merge, entries);\n-\t\tresult.clean = process_renames(re_head, re_merge,\n-\t\t\t\t\t       branch1Name, branch2Name);\n-\t\tdebug(\"\\tprocessing entries...\\n\");\n-\t\tint i;\n+\t\tclean = process_renames(re_head, re_merge,\n+\t\t\t\tbranch1Name, branch2Name);\n \t\tfor (i = 0; i < entries->nr; i++) {\n \t\t\tconst char *path = entries->items[i].path;\n \t\t\tstruct stage_data *e = entries->items[i].util;\n \t\t\tif (e->processed)\n \t\t\t\tcontinue;\n \t\t\tif (!process_entry(path, e, branch1Name, branch2Name))\n-\t\t\t\tresult.clean = 0;\n+\t\t\t\tclean = 0;\n \t\t}\n \n-\t\tfree_rename_entries(&re_merge);\n-\t\tfree_rename_entries(&re_head);\n-\t\tfree_index_entries(&entries);\n+\t\tpath_list_clear(re_merge, 0);\n+\t\tpath_list_clear(re_head, 0);\n+\t\tpath_list_clear(entries, 1);\n \n-\t\tif (result.clean || index_only)\n-\t\t\tresult.tree = git_write_tree();\n+\t\tif (clean || index_only)\n+\t\t\t*result = git_write_tree();\n \t\telse\n-\t\t\tresult.tree = NULL;\n-\t\tdebug(\"\\t  processing entries done\\n\");\n+\t\t\t*result = NULL;\n \t} else {\n-\t\tresult.clean = 1;\n+\t\tclean = 1;\n \t\tprintf(\"merging of trees %s and %s resulted in %s\\n\",\n \t\t       sha1_to_hex(head->object.sha1),\n \t\t       sha1_to_hex(merge->object.sha1),\n-\t\t       sha1_to_hex(result.tree->object.sha1));\n+\t\t       sha1_to_hex((*result)->object.sha1));\n \t}\n \n-\tdebug(\"  merge_trees done\\n\");\n-\treturn result;\n+\treturn clean;\n }\n \n /*\n@@ -1421,87 +1261,86 @@ static struct merge_tree_result merge_tr\n  * commit object and a flag indicating the cleaness of the merge.\n  */\n static\n-struct merge_result merge(struct commit *h1,\n+int merge(struct commit *h1,\n \t\t\t  struct commit *h2,\n \t\t\t  const char *branch1Name,\n \t\t\t  const char *branch2Name,\n \t\t\t  int callDepth /* =0 */,\n-\t\t\t  struct commit *ancestor /* =None */)\n+\t\t\t  struct commit *ancestor /* =None */,\n+\t\t\t  struct commit **result)\n {\n-\tstruct merge_result result = { NULL, 0 };\n-\tconst char *msg;\n-\tint msglen;\n \tstruct commit_list *ca = NULL, *iter;\n \tstruct commit *mergedCA;\n-\tstruct merge_tree_result mtr;\n+\tstruct tree *mrtree;\n+\tint clean;\n \n \toutput(\"Merging:\");\n-\tmsg = commit_title(h1, &msglen);\n-\t/* TODO: refactor. we always show the sha1 with the title */\n-\toutput(\"%s %.*s\", commit_hex_sha1(h1), msglen, msg);\n-\tmsg = commit_title(h2, &msglen);\n-\toutput(\"%s %.*s\", commit_hex_sha1(h2), msglen, msg);\n+\toutput_commit_title(h1);\n+\toutput_commit_title(h2);\n \n-\tif ( ancestor )\n+\tif (ancestor)\n \t\tcommit_list_insert(ancestor, &ca);\n \telse\n \t\tca = get_merge_bases(h1, h2, 1);\n \n \toutput(\"found %u common ancestor(s):\", commit_list_count(ca));\n-\tfor (iter = ca; iter; iter = iter->next) {\n-\t\tmsg = commit_title(iter->item, &msglen);\n-\t\toutput(\"%s %.*s\", commit_hex_sha1(iter->item), msglen, msg);\n-\t}\n+\tfor (iter = ca; iter; iter = iter->next)\n+\t\toutput_commit_title(iter->item);\n \n \tmergedCA = pop_commit(&ca);\n \n-\t/* TODO: what happens when merge with virtual commits fails? */\n \tfor (iter = ca; iter; iter = iter->next) {\n \t\toutput_indent = callDepth + 1;\n-\t\tresult = merge(mergedCA, iter->item,\n-\t\t\t       \"Temporary merge branch 1\",\n-\t\t\t       \"Temporary merge branch 2\",\n-\t\t\t       callDepth + 1,\n-\t\t\t       NULL);\n-\t\tmergedCA = result.commit;\n+\t\t/*\n+\t\t * When the merge fails, the result contains files\n+\t\t * with conflict markers. The cleanness flag is\n+\t\t * ignored, it was never acutally used, as result of\n+\t\t * merge_trees has always overwritten it: the commited\n+\t\t * \"conflicts\" were already resolved. \n+\t\t */\n+\t\tmerge(mergedCA, iter->item,\n+\t\t      \"Temporary merge branch 1\",\n+\t\t      \"Temporary merge branch 2\",\n+\t\t      callDepth + 1,\n+\t\t      NULL,\n+\t\t      &mergedCA);\n \t\toutput_indent = callDepth;\n \n-\t\tif ( !mergedCA )\n+\t\tif (!mergedCA)\n \t\t\tdie(\"merge returned no commit\");\n \t}\n \n-\tif ( callDepth == 0 ) {\n-\t\tsetup_index(0);\n+\tif (callDepth == 0) {\n+\t\tsetup_index(0 /* $GIT_DIR/index */);\n \t\tindex_only = 0;\n \t} else {\n-\t\tsetup_index(1);\n+\t\tsetup_index(1 /* temporary index */);\n \t\tgit_read_tree(h1->tree);\n \t\tindex_only = 1;\n \t}\n \n-\tmtr = merge_trees(h1->tree, h2->tree,\n-\t\t\t  mergedCA->tree, branch1Name, branch2Name);\n+\tclean = merge_trees(h1->tree, h2->tree, mergedCA->tree,\n+\t\t\t    branch1Name, branch2Name, &mrtree);\n \n-\tif ( !ancestor && (mtr.clean || index_only) ) {\n-\t\tresult.commit = make_virtual_commit(mtr.tree, \"merged tree\");\n-\t\tcommit_list_insert(h1, &result.commit->parents);\n-\t\tcommit_list_insert(h2, &result.commit->parents->next);\n+\tif (!ancestor && (clean || index_only)) {\n+\t\t*result = make_virtual_commit(mrtree, \"merged tree\");\n+\t\tcommit_list_insert(h1, &(*result)->parents);\n+\t\tcommit_list_insert(h2, &(*result)->parents->next);\n \t} else\n-\t\tresult.commit = NULL;\n+\t\t*result = NULL;\n \n-\tresult.clean = mtr.clean;\n-\treturn result;\n+\treturn clean;\n }\n \n static struct commit *get_ref(const char *ref)\n {\n \tunsigned char sha1[20];\n \tstruct object *object;\n-\n+\t\n \tif (get_sha1(ref, sha1))\n \t\tdie(\"Could not resolve ref '%s'\", ref);\n \tobject = deref_tag(parse_object(sha1), ref, strlen(ref));\n-\tif (object->type != OBJ_COMMIT)\n+\tif (object->type != TYPE_COMMIT)\n \t\treturn NULL;\n \tif (parse_commit((struct commit *)object))\n \t\tdie(\"Could not parse commit '%s'\", sha1_to_hex(object->sha1));\n@@ -1512,6 +1351,9 @@ int main(int argc, char *argv[])\n {\n \tstatic const char *bases[2];\n \tstatic unsigned bases_count = 0;\n+\tint i, clean;\n+\tconst char *branch1, *branch2;\n+\tstruct commit *result, *h1, *h2;\n \n \toriginal_index_file = getenv(\"GIT_INDEX_FILE\");\n \n@@ -1523,7 +1365,6 @@ int main(int argc, char *argv[])\n \tif (argc < 4)\n \t\tdie(\"Usage: %s <base>... -- <head> <remote> ...\\n\", argv[0]);\n \n-\tint i;\n \tfor (i = 1; i < argc; ++i) {\n \t\tif (!strcmp(argv[i], \"--\"))\n \t\t\tbreak;\n@@ -1533,26 +1374,23 @@ int main(int argc, char *argv[])\n \tif (argc - i != 3) /* \"--\" \"<head>\" \"<remote>\" */\n \t\tdie(\"Not handling anything other than two heads merge.\");\n \n-\tconst char *branch1, *branch2;\n-\n \tbranch1 = argv[++i];\n \tbranch2 = argv[++i];\n \tprintf(\"Merging %s with %s\\n\", branch1, branch2);\n \n-\tstruct merge_result result;\n-\tstruct commit *h1 = get_ref(branch1);\n-\tstruct commit *h2 = get_ref(branch2);\n+\th1 = get_ref(branch1);\n+\th2 = get_ref(branch2);\n \n \tif (bases_count == 1) {\n \t\tstruct commit *ancestor = get_ref(bases[0]);\n-\t\tresult = merge(h1, h2, branch1, branch2, 0, ancestor);\n+\t\tclean = merge(h1, h2, branch1, branch2, 0, ancestor, &result);\n \t} else\n-\t\tresult = merge(h1, h2, branch1, branch2, 0, NULL);\n+\t\tclean = merge(h1, h2, branch1, branch2, 0, NULL, &result);\n \n \tif (cache_dirty)\n \t\tflush_cache();\n \n-\treturn result.clean ? 0: 1;\n+\treturn clean ? 0: 1;\n }\n \n /*\n"}]}