--- merge-recursive.c | 295 +++++++++++++++++++++++++++++------------------------ 1 files changed, 162 insertions(+), 133 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index abceb30..9a18e06 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -579,26 +579,17 @@ struct rename_entry { struct rename_entry *next; - unsigned char src_sha[20]; - unsigned src_mode; + struct diff_filepair *pair; struct index_entry *src_entry; - - unsigned char dst_sha[20]; - unsigned dst_mode; struct index_entry *dst_entry; - - unsigned score:16, - processed:1; - - char *src; /* dst + strlen(dst) + 1 */ - char dst[1]; + unsigned processed:1; }; static struct rename_entry *find_rename_bysrc(struct rename_entry *e, const char *name) { while ( e ) { - if ( strcmp(e->src, name) == 0 ) + if ( strcmp(e->pair->one->path, name) == 0 ) break; e = e->next; } @@ -609,7 +600,7 @@ static struct rename_entry *find_rename_ const char *name) { while ( e ) { - if ( strcmp(e->dst, name) == 0 ) + if ( strcmp(e->pair->two->path, name) == 0 ) break; e = e->next; } @@ -620,6 +611,7 @@ static void free_rename_entries(struct r { while (*list) { struct rename_entry *next = (*list)->next; + diff_free_filepair((*list)->pair); free(*list); *list = next; } @@ -656,29 +648,23 @@ static struct rename_entry *get_renames( struct diff_filepair *pair = diff_queued_diff.queue[i]; if (pair->status != 'R') continue; - size_t l1 = strlen(pair->one->path); - size_t l2 = strlen(pair->two->path); - re = xmalloc(sizeof(*re) + l1 + l2 + 2); - re->src = re->dst + l2; + diff_queued_diff.queue[i] = NULL; + re = xmalloc(sizeof(*re)); re->next = NULL; re->processed = 0; - re->score = pair->score; - memcpy(re->src_sha, pair->one->sha1, 20); - memcpy(re->src, pair->one->path, ++l1); - re->src_mode = pair->one->mode; - memcpy(re->dst_sha, pair->two->sha1, 20); - memcpy(re->dst, pair->two->path, ++l2); - re->dst_mode = pair->two->mode; + re->pair = pair; // TODO: optimize index_entry_find - re->src_entry = index_entry_find(*entries, re->src); + re->src_entry = index_entry_find(*entries, re->pair->one->path); if ( !re->src_entry ) { - re->src_entry = index_entry_from_db(re->src, oTree, aTree, bTree); + re->src_entry = index_entry_from_db(re->pair->one->path, + oTree, aTree, bTree); re->src_entry->next = *entries; *entries = re->src_entry; } - re->dst_entry = index_entry_find(*entries, re->dst); + re->dst_entry = index_entry_find(*entries, re->pair->two->path); if ( !re->dst_entry ) { - re->dst_entry = index_entry_from_db(re->dst, oTree, aTree, bTree); + re->dst_entry = index_entry_from_db(re->pair->two->path, + oTree, aTree, bTree); re->dst_entry->next = *entries; *entries = re->dst_entry; } @@ -688,7 +674,6 @@ static struct rename_entry *get_renames( opts.output_format = DIFF_FORMAT_NO_OUTPUT; diff_flush(&opts); debug(" getRenames done in %ld\n", time(0)-t); - die("PROFILING"); return renames; } @@ -979,12 +964,9 @@ static struct merge_file_info merge_file NULL }; char *la, *lb, *lo; - argv[2] = la = malloc(strlen(branch1Name) + 2 + strlen(aPath)); - strcat(strcat(strcpy(la, branch1Name), "/"), aPath); - argv[6] = lb = malloc(strlen(branch2Name) + 2 + strlen(bPath)); - strcat(strcat(strcpy(lb, branch2Name), "/"), bPath); - argv[4] = lo = malloc(7 + strlen(oPath)); - strcat(strcpy(lo, "orig/"), oPath); + argv[2] = la = strdup(mkpath("%s/%s", branch1Name, aPath)); + argv[6] = lb = strdup(mkpath("%s/%s", branch2Name, bPath)); + argv[4] = lo = strdup(mkpath("orig/%s", oPath)); #if 0 printf("%s %s %s %s %s %s %s %s %s %s\n", @@ -1029,6 +1011,75 @@ #endif return result; } +static void conflict_rename_rename(FILE *up_index, + struct rename_entry *ren1, + const char *branch1, + struct rename_entry *ren2, + const char *branch2) +{ + char *del[2]; + int delp = 0; + const char *ren1_dst = ren1->pair->two->path; + const char *ren2_dst = ren2->pair->two->path; + const char *dstName1 = ren1_dst; + const char *dstName2 = ren2_dst; + if (path_list_has_path(¤tDirectorySet, ren1_dst)) { + dstName1 = del[delp++] = unique_path(ren1_dst, branch1); + output("%s is a directory in %s adding as %s instead", + ren1_dst, branch2, dstName1); + remove_file(up_index, 0, ren1_dst); + } + if (path_list_has_path(¤tDirectorySet, ren2_dst)) { + dstName2 = del[delp++] = unique_path(ren2_dst, branch2); + output("%s is a directory in %s adding as %s instead", + ren2_dst, branch1, dstName2); + remove_file(up_index, 0, ren2_dst); + } + update_stages(up_index, dstName1, + NULL, 0, + ren1->pair->two->sha1, ren1->pair->two->mode, + NULL, 0, + 1 /* clear */); + update_stages(up_index, dstName2, + NULL, 0, + NULL, 0, + ren2->pair->two->sha1, ren2->pair->two->mode, + 1 /* clear */); + while ( delp-- ) + free(del[delp]); +} + +static void conflict_rename_dir(FILE *up_index, + struct rename_entry *ren1, + const char *branch1) +{ + char *newPath = unique_path(ren1->pair->two->path, branch1); + output("Renaming %s to %s instead", ren1->pair->one->path, newPath); + remove_file(up_index, 0, ren1->pair->two->path); + update_file(up_index, 0, ren1->pair->two->sha1, ren1->pair->two->mode, newPath); + free(newPath); +} + +static void conflict_rename_rename_2(FILE *up_index, + struct rename_entry *ren1, + const char *branch1, + struct rename_entry *ren2, + const char *branch2) +{ + char *newPath1 = unique_path(ren1->pair->two->path, branch1); + char *newPath2 = unique_path(ren2->pair->two->path, branch2); + output("Renaming %s to %s and %s to %s instead", + ren1->pair->one->path, newPath1, + ren2->pair->one->path, newPath2); + remove_file(up_index, 0, ren1->pair->two->path); + update_file(up_index, 0, + ren1->pair->two->sha1, ren1->pair->two->mode, newPath1); + update_file(up_index, 0, + ren2->pair->two->sha1, ren2->pair->two->mode, newPath2); + free(newPath2); + free(newPath1); +} + static int process_renames(struct rename_entry *renamesA, struct rename_entry *renamesB, const char *branchNameA, @@ -1042,9 +1093,9 @@ static int process_renames(struct rename char **src; for (sre = renamesA; sre; sre = sre->next) - path_list_insert(sre->src, &srcNames); + path_list_insert(sre->pair->one->path, &srcNames); for (sre = renamesB; sre; sre = sre->next) - path_list_insert(sre->src, &srcNames); + path_list_insert(sre->pair->one->path, &srcNames); FILE *fp = git_update_index_pipe(); for_each_path(src,&srcNames) { @@ -1074,80 +1125,66 @@ static int process_renames(struct rename continue; ren1->processed = 1; + const char *ren1_src = ren1->pair->one->path; + const char *ren1_dst = ren1->pair->two->path; + if ( ren2 ) { + const char *ren2_src = ren2->pair->one->path; + const char *ren2_dst = ren2->pair->two->path; /* Renamed in 1 and renamed in 2 */ - if ( strcmp(ren1->src, ren2->src) != 0 ) - die("ren1.srcName != ren2.srcName"); + if (strcmp(ren1_src, ren2_src) != 0) + die("ren1.src != ren2.src"); ren2->dst_entry->processed = 1; ren2->processed = 1; - if ( strcmp(ren1->dst, ren2->dst) != 0 ) { + if (strcmp(ren1_dst, ren2_dst) != 0) { + cleanMerge = 0; output("CONFLICT (rename/rename): " "Rename %s->%s in branch %s " "rename %s->%s in %s", - *src, ren1->dst, branchName1, - *src, ren2->dst, branchName2); - cleanMerge = 0; - char *dstName1 = ren1->dst, *dstName2 = ren2->dst; - if ( path_list_has_path(¤tDirectorySet, ren1->dst) ) { - dstName1 = unique_path(ren1->dst, branchName1); - output("%s is a directory in %s adding as %s instead", - ren1->dst, branchName2, dstName1); - remove_file(fp, 0, ren1->dst); - } - if ( path_list_has_path(¤tDirectorySet, ren2->dst) ) { - dstName2 = unique_path(ren2->dst, branchName2); - output("%s is a directory in %s adding as %s instead", - ren2->dst, branchName1, dstName2); - remove_file(fp, 0, ren2->dst); - } - update_stages(fp, dstName1, - NULL, 0, - ren1->dst_sha, ren1->dst_mode, - NULL, 0, - 1 /* clear */); - update_stages(fp, dstName2, - NULL, 0, - NULL, 0, - ren2->dst_sha, ren2->dst_mode, - 1 /* clear */); + *src, ren1_dst, branchName1, + *src, ren2_dst, branchName2); + conflict_rename_rename(fp, ren1, branchName1, ren2, branchName2); } else { - remove_file(fp, 1, ren1->src); + remove_file(fp, 1, ren1_src); struct merge_file_info mfi; - mfi = merge_file(ren1->src, - ren1->src_sha, - ren1->src_mode, - ren1->dst, - ren1->dst_sha, - ren1->dst_mode, - ren2->dst, - ren2->dst_sha, - ren2->dst_mode, + mfi = merge_file(ren1_src, + ren1->pair->one->sha1, + ren1->pair->one->mode, + ren1_dst, + ren1->pair->two->sha1, + ren1->pair->two->mode, + ren2_dst, + ren2->pair->two->sha1, + ren2->pair->two->mode, branchName1, branchName2); if ( mfi.merge || !mfi.clean ) - output("Renaming %s->%s", *src, ren1->dst); + output("Renaming %s->%s", *src, ren1_dst); if ( mfi.merge ) - output("Auto-merging %s", ren1->dst); + output("Auto-merging %s", ren1_dst); if ( !mfi.clean ) { output("CONFLICT (content): merge conflict in %s", - ren1->dst); + ren1_dst); cleanMerge = 0; if ( !index_only ) update_stages(fp, - ren1->dst, - ren1->src_sha, ren1->src_mode, - ren1->dst_sha, ren1->dst_mode, - ren2->dst_sha, ren2->dst_mode, - 1 /* clear */); + ren1_dst, + ren1->pair->one->sha1, + ren1->pair->one->mode, + ren1->pair->two->sha1, + ren1->pair->two->mode, + ren2->pair->two->sha1, + ren2->pair->two->mode, + 1 /* clear */); } - update_file(fp, mfi.clean, mfi.sha, mfi.mode, ren1->dst); + update_file(fp, mfi.clean, mfi.sha, mfi.mode, ren1_dst); } } else { /* Renamed in 1, maybe changed in 2 */ - remove_file(fp, 1, ren1->src); + remove_file(fp, 1, ren1_src); unsigned char srcShaOtherBranch[20], dstShaOtherBranch[20]; unsigned srcModeOtherBranch, dstModeOtherBranch; @@ -1162,62 +1199,52 @@ static int process_renames(struct rename int tryMerge = 0; char *newPath; - struct rename_entry *dst2; - if ( path_list_has_path(¤tDirectorySet, ren1->dst) ) { - newPath = unique_path(ren1->dst, branchName1); + if (path_list_has_path(¤tDirectorySet, ren1_dst)) { + cleanMerge = 0; output("CONFLICT (rename/directory): Rename %s->%s in %s " " directory %s added in %s", - ren1->src, ren1->dst, branchName1, - ren1->dst, branchName2); - output("Renaming %s to %s instead", ren1->src, newPath); - cleanMerge = 0; - remove_file(fp, 0, ren1->dst); - update_file(fp, 0, ren1->dst_sha, ren1->dst_mode, newPath); + ren1_src, ren1_dst, branchName1, + ren1_dst, branchName2); + conflict_rename_dir(fp, ren1, branchName1); } else if ( memcmp(srcShaOtherBranch, null_sha1, 20) == 0 ) { + cleanMerge = 0; output("CONFLICT (rename/delete): Rename %s->%s in %s " "and deleted in %s", - ren1->src, ren1->dst, branchName1, + ren1_src, ren1_dst, branchName1, branchName2); - cleanMerge = 0; - update_file(fp, 0, ren1->dst_sha, ren1->dst_mode, ren1->dst); + update_file(fp, 0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst); } else if ( memcmp(dstShaOtherBranch, null_sha1, 20) != 0 ) { - newPath = unique_path(ren1->dst, branchName2); + cleanMerge = 0; + tryMerge = 1; output("CONFLICT (rename/add): Rename %s->%s in %s. " "%s added in %s", - ren1->src, ren1->dst, branchName1, - ren1->dst, branchName2); + ren1_src, ren1_dst, branchName1, + ren1_dst, branchName2); + newPath = unique_path(ren1_dst, branchName2); output("Adding as %s instead", newPath); update_file(fp, 0, dstShaOtherBranch, dstModeOtherBranch, newPath); + } else if ( (ren2 = find_rename_bydst(renames2, ren1_dst)) ) { cleanMerge = 0; - tryMerge = 1; - } else if ( (dst2 = find_rename_bydst(renames2, ren1->dst)) ) { - char *newPath1 = unique_path(ren1->dst, branchName1); - char *newPath2 = unique_path(dst2->dst, branchName2); + ren2->processed = 1; output("CONFLICT (rename/rename): Rename %s->%s in %s. " "Rename %s->%s in %s", - ren1->src, ren1->dst, branchName1, - dst2->src, dst2->dst, branchName2); - output("Renaming %s to %s and %s to %s instead", - ren1->src, newPath1, dst2->src, newPath2); - remove_file(fp, 0, ren1->dst); - update_file(fp, 0, ren1->dst_sha, ren1->dst_mode, newPath1); - update_file(fp, 0, dst2->dst_sha, dst2->dst_mode, newPath2); - dst2->processed = 1; - cleanMerge = 0; + ren1_src, ren1_dst, branchName1, + ren2->pair->one->path, ren2->pair->two->path, branchName2); + conflict_rename_rename_2(fp, ren1, branchName1, ren2, branchName2); } else tryMerge = 1; if ( tryMerge ) { - char *oname = ren1->src; - char *aname = ren1->dst; - char *bname = ren1->src; + const char *oname = ren1_src; + const char *aname = ren1_dst; + const char *bname = ren1_src; unsigned char osha[20], asha[20], bsha[20]; - unsigned omode = ren1->src_mode; - unsigned amode = ren1->dst_mode; + unsigned omode = ren1->pair->one->mode; + unsigned amode = ren1->pair->two->mode; unsigned bmode = srcModeOtherBranch; - memcpy(osha, ren1->src_sha, 20); - memcpy(asha, ren1->dst_sha, 20); + memcpy(osha, ren1->pair->one->sha1, 20); + memcpy(asha, ren1->pair->two->sha1, 20); memcpy(bsha, srcShaOtherBranch, 20); const char *aBranch = branchName1; const char *bBranch = branchName2; @@ -1234,23 +1261,23 @@ static int process_renames(struct rename aBranch, bBranch); if ( mfi.merge || !mfi.clean ) - output("Renaming %s => %s", ren1->src, ren1->dst); + output("Renaming %s => %s", ren1_src, ren1_dst); if ( mfi.merge ) - output("Auto-merging %s", ren1->dst); + output("Auto-merging %s", ren1_dst); if ( !mfi.clean ) { output("CONFLICT (rename/modify): Merge conflict in %s", - ren1->dst); + ren1_dst); cleanMerge = 0; if ( !index_only ) update_stages(fp, - ren1->dst, - osha, omode, - asha, amode, - bsha, bmode, - 1 /* clear */); + ren1_dst, + osha, omode, + asha, amode, + bsha, bmode, + 1 /* clear */); } - update_file(fp, mfi.clean, mfi.sha, mfi.mode, ren1->dst); + update_file(fp, mfi.clean, mfi.sha, mfi.mode, ren1_dst); } } } @@ -1451,16 +1478,18 @@ static struct merge_tree_result merge_tr if (!process_entry(fp, e, branch1Name, branch2Name)) result.clean = 0; } + free_rename_entries(&re_merge); + free_rename_entries(&re_head); + free_index_entries(&entries); + if (pclose(fp)) die("updating entry failed in git update-index"); + if (result.clean || index_only) result.tree = git_write_tree(); else result.tree = NULL; debug("\t processing entries done\n"); - free_rename_entries(&re_merge); - free_rename_entries(&re_head); - free_index_entries(&entries); } else { result.clean = 1; printf("merging of trees %s and %s resulted in %s\n", -- 1.4.1.rc1.g17dc - : send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html