summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2016-03-14 15:49:35 -0700
committerJunio C Hamano <gitster@pobox.com>2016-03-21 15:17:13 -0700
commita29b6f28cc15b6f07fc95d932eca23a0923a3524 (patch)
tree077c2c15a01a3deea31f75ffd19267346f849c7e
parentdf186bec7dc195762fca9de0d34ff687fda37c45 (diff)
downloadgit-jc/rerere-multi-wip.tar.gz
-rw-r--r--rerere.c96
1 files changed, 69 insertions, 27 deletions
diff --git a/rerere.c b/rerere.c
index e636d4b0fb..4d28129578 100644
--- a/rerere.c
+++ b/rerere.c
@@ -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;
}