diff options
author | Junio C Hamano <gitster@pobox.com> | 2016-03-14 15:49:35 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2016-03-21 15:17:13 -0700 |
commit | a29b6f28cc15b6f07fc95d932eca23a0923a3524 (patch) | |
tree | 077c2c15a01a3deea31f75ffd19267346f849c7e | |
parent | df186bec7dc195762fca9de0d34ff687fda37c45 (diff) | |
download | git-jc/rerere-multi-wip.tar.gz |
WIP forgetjc/rerere-multi-wip
-rw-r--r-- | rerere.c | 96 |
1 files changed, 69 insertions, 27 deletions
@@ -930,6 +930,7 @@ int rerere(int flags) struct rerere_io_mem { struct rerere_io io; struct strbuf input; + size_t input_pos; }; /* @@ -942,20 +943,21 @@ static int rerere_mem_getline(struct strbuf *sb, struct rerere_io *io_) size_t len; strbuf_release(sb); - if (!io->input.len) + if (io->input.len <= io->input_pos) return -1; - ep = memchr(io->input.buf, '\n', io->input.len); + ep = memchr(io->input.buf + io->input_pos, '\n', io->input.len); if (!ep) ep = io->input.buf + io->input.len; else if (*ep == '\n') ep++; - len = ep - io->input.buf; - strbuf_add(sb, io->input.buf, len); - strbuf_remove(&io->input, 0, len); + len = ep - (io->input.buf + io->input_pos); + strbuf_add(sb, io->input.buf + io->input_pos, len); + io->input_pos += len; return 0; } -static int handle_cache(const char *path, unsigned char *sha1, const char *output) +static int handle_cache(const char *path, unsigned char *sha1, + struct strbuf *thisimage) { mmfile_t mmfile[3] = {{NULL}}; mmbuffer_t result = {NULL, 0}; @@ -1002,10 +1004,7 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu memset(&io, 0, sizeof(io)); io.io.getline = rerere_mem_getline; - if (output) - io.io.output = fopen(output, "w"); - else - io.io.output = NULL; + io.io.output = NULL; strbuf_init(&io.input, 0); strbuf_attach(&io.input, result.ptr, result.size, result.size); @@ -1014,43 +1013,86 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu * contents with conflict markers out. */ hunk_no = handle_path(sha1, (struct rerere_io *)&io, marker_size); + strbuf_swap(&io.input, thisimage); strbuf_release(&io.input); - if (io.io.output) - fclose(io.io.output); return hunk_no; } static int rerere_forget_one_path(const char *path, struct string_list *rr) { - const char *filename; + const unsigned both = RR_HAS_PREIMAGE | RR_HAS_POSTIMAGE; struct rerere_id *id; unsigned char sha1[20]; int ret; struct string_list_item *item; + struct strbuf thisimage = STRBUF_INIT; + int found_variant = -1; + int marker_size = ll_merge_marker_size(path); + struct rerere_io_mem io; /* * Recreate the original conflict from the stages in the * index and compute the conflict ID */ - ret = handle_cache(path, sha1, NULL); - if (ret < 1) + ret = handle_cache(path, sha1, &thisimage); + if (ret < 1) { + strbuf_release(&thisimage); return error("Could not parse conflict hunks in '%s'", path); + } - /* Nuke the recorded resolution for the conflict */ + /* + * Find which existing resolution would match the conflicted + * result (i.e. thisimage), so that we can nuke it. + */ id = new_rerere_id(sha1); - id->variant = 0; /* for now */ - filename = rerere_path(id, "postimage"); - if (unlink(filename)) - return (errno == ENOENT - ? error("no remembered resolution for %s", path) - : error("cannot unlink %s: %s", filename, strerror(errno))); + for (id->variant = 0; + id->variant < id->collection->status_nr; + id->variant++) { + mmfile_t cur = { thisimage.buf, thisimage.len }; + mmbuffer_t result = { NULL, 0 }; + + if ((id->collection->status[id->variant] & both) != both) + continue; + + /* Successful replay of recorded resolution? */ + if (!try_merge(id, path, &cur, &result)) { + remove_variant(id); + if (found_variant < 0) + found_variant = id->variant; + } + free(result.ptr); + } + + if (found_variant < 0) { + strbuf_release(&thisimage); + return error("no remembered resolution for %s", path); + } /* - * Update the preimage so that the user can resolve the - * conflict in the working tree, run us again to record - * the postimage. + * Write out "preimage". Do not touch the working tree file + * (which has the result of applying the recorded resolution + * we are about to forget). The user wants to record it as + * the "postimage" after refining it by running "rerere" + * later. */ - handle_cache(path, sha1, rerere_path(id, "preimage")); + + id->variant = found_variant; + id->collection->status[id->variant] = RR_HAS_PREIMAGE; + + memset(&io, 0, sizeof(io)); + strbuf_init(&io.input, 0); + strbuf_swap(&io.input, &thisimage); + io.io.getline = rerere_mem_getline; + io.io.output = fopen(rerere_path(id, "preimage"), "w"); + if (!io.io.output) { + strbuf_release(&thisimage); + return error("failed to fopen '%s'", + rerere_path(id, "preimage")); + } + handle_path(sha1, (struct rerere_io *)&io, marker_size); + fclose(io.io.output); + strbuf_release(&io.input); + fprintf(stderr, "Updated preimage for '%s'\n", path); /* @@ -1060,7 +1102,7 @@ static int rerere_forget_one_path(const char *path, struct string_list *rr) item = string_list_insert(rr, path); free_rerere_id(item); item->util = id; - fprintf(stderr, "Forgot resolution for %s\n", path); + fprintf(stderr, "Forgot resolution for '%s'\n", path); return 0; } |