Previously, MERGE_RR entries that rerere detected as resolved were removed from MERGE_RR so that it contained only entries for files that still had conflicts. This changes the "database" format to also keep the entries about files for which resolutions have been recorded. The purpose is to allow that resolved conflicts can be unresolved. To do that it is necessary to have a mapping from the file name to the conflict hash. The new format of MERGE_RR is: 1. Entries about unresolved conflicts. 2. An all-zeros SHA1 as boundary marker. 3. Entries about resolved conflicts. Signed-off-by: Johannes Sixt <j6t@xxxxxxxx> --- builtin-rerere.c | 4 +++- rerere.c | 49 ++++++++++++++++++++++++++++++++++++++++--------- rerere.h | 2 +- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/builtin-rerere.c b/builtin-rerere.c index adfb7b5..275827d 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -101,12 +101,13 @@ static int diff_two(const char *file1, const char *label1, int cmd_rerere(int argc, const char **argv, const char *prefix) { struct string_list merge_rr = { NULL, 0, 0, 1 }; + struct string_list merge_rr_done = { NULL, 0, 0, 1 }; int i, fd; if (argc < 2) return rerere(); - fd = setup_rerere(&merge_rr); + fd = setup_rerere(&merge_rr, &merge_rr_done); if (fd < 0) return 0; @@ -132,5 +133,6 @@ int cmd_rerere(int argc, const char **argv, const char *prefix) usage(git_rerere_usage); string_list_clear(&merge_rr, 1); + string_list_clear(&merge_rr_done, 1); return 0; } diff --git a/rerere.c b/rerere.c index 29f95f6..84d0bb7 100644 --- a/rerere.c +++ b/rerere.c @@ -23,8 +23,20 @@ int has_rerere_resolution(const char *hex) return !stat(rerere_path(hex, "postimage"), &st); } -static void read_rr(struct string_list *rr) +/* + * If MERGE_RR is read and rewritten by an old version, the section bound + * would not be preserved, and file names from both sections would be + * interleaved. We must make sure that the section marker does not end up + * in an arbitrary position. In particular, the safest result is that all + * paths are now in the first ("not done") section. Therefore, we choose + * a file name that sorts last (for all practical purposes). + */ +static const char section_mark[] = + "0000000000000000000000000000000000000000\t\377\377\377\377"; + +static void read_rr(struct string_list *rr, struct string_list *rr_done) { + struct string_list *section = rr; unsigned char sha1[20]; char buf[PATH_MAX]; FILE *in = fopen(merge_rr_path, "r"); @@ -43,14 +55,19 @@ static void read_rr(struct string_list *rr) ; /* do nothing */ if (i == sizeof(buf)) die("filename too long"); - string_list_insert(buf, rr)->util = name; + if (prefixcmp(section_mark, name)) { + string_list_insert(buf, section)->util = name; + } else { + free(name); + section = rr_done; + } } fclose(in); } static struct lock_file write_lock; -static int write_rr(struct string_list *rr, int out_fd) +static void write_rr_section(struct string_list *rr, int out_fd) { int i; for (i = 0; i < rr->nr; i++) { @@ -65,6 +82,17 @@ static int write_rr(struct string_list *rr, int out_fd) write_in_full(out_fd, path, length) != length) die("unable to write rerere record"); } +} + +static int write_rr(struct string_list *rr, + struct string_list *rr_done, int out_fd) +{ + int length = strlen(section_mark)+1; + + write_rr_section(rr, out_fd); + if (write_in_full(out_fd, section_mark, length) != length) + die("unable to write rerere record"); + write_rr_section(rr_done, out_fd); if (commit_lock_file(&write_lock) != 0) die("unable to write rerere record"); return 0; @@ -263,7 +291,8 @@ static int update_paths(struct string_list *update) return status; } -static int do_plain_rerere(struct string_list *rr, int fd) +static int do_plain_rerere(struct string_list *rr, + struct string_list *rr_done, int fd) { struct string_list conflict = { NULL, 0, 0, 1 }; struct string_list update = { NULL, 0, 0, 1 }; @@ -328,13 +357,14 @@ static int do_plain_rerere(struct string_list *rr, int fd) fprintf(stderr, "Recorded resolution for '%s'.\n", path); copy_file(rerere_path(name, "postimage"), path, 0666); mark_resolved: + string_list_insert(path, rr_done)->util = rr->items[i].util; rr->items[i].util = NULL; } if (update.nr) update_paths(&update); - return write_rr(rr, fd); + return write_rr(rr, rr_done, fd); } static int git_rerere_config(const char *var, const char *value, void *cb) @@ -367,7 +397,7 @@ static int is_rerere_enabled(void) return 1; } -int setup_rerere(struct string_list *merge_rr) +int setup_rerere(struct string_list *merge_rr, struct string_list *merge_rr_done) { int fd; @@ -378,17 +408,18 @@ int setup_rerere(struct string_list *merge_rr) merge_rr_path = git_pathdup("MERGE_RR"); fd = hold_lock_file_for_update(&write_lock, merge_rr_path, LOCK_DIE_ON_ERROR); - read_rr(merge_rr); + read_rr(merge_rr, merge_rr_done); return fd; } int rerere(void) { struct string_list merge_rr = { NULL, 0, 0, 1 }; + struct string_list merge_rr_done = { NULL, 0, 0, 1 }; int fd; - fd = setup_rerere(&merge_rr); + fd = setup_rerere(&merge_rr, &merge_rr_done); if (fd < 0) return 0; - return do_plain_rerere(&merge_rr, fd); + return do_plain_rerere(&merge_rr, &merge_rr_done, fd); } diff --git a/rerere.h b/rerere.h index 13313f3..9bb2f13 100644 --- a/rerere.h +++ b/rerere.h @@ -3,7 +3,7 @@ #include "string-list.h" -extern int setup_rerere(struct string_list *); +extern int setup_rerere(struct string_list *, struct string_list *); extern int rerere(void); extern const char *rerere_path(const char *hex, const char *file); extern int has_rerere_resolution(const char *hex); -- 1.6.5.2.182.ge039a -- To unsubscribe from this list: 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