merge-recursive: use handle_file_collision for add/add conflicts
[gitweb.git] / rerere.c
index 2d622519431fc83091dbd3dfb5fea5a8ef178c01..2fd3181f7beb7e2b19e4ca7ae26a50d703b60728 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -9,6 +9,7 @@
 #include "ll-merge.h"
 #include "attr.h"
 #include "pathspec.h"
+#include "object-store.h"
 #include "sha1-lookup.h"
 
 #define RESOLVED 0
@@ -200,7 +201,7 @@ static struct rerere_id *new_rerere_id(unsigned char *sha1)
 static void read_rr(struct string_list *rr)
 {
        struct strbuf buf = STRBUF_INIT;
-       FILE *in = fopen_or_warn(git_path_merge_rr(), "r");
+       FILE *in = fopen_or_warn(git_path_merge_rr(the_repository), "r");
 
        if (!in)
                return;
@@ -302,38 +303,6 @@ static void rerere_io_putstr(const char *str, struct rerere_io *io)
                ferr_puts(str, io->output, &io->wrerror);
 }
 
-/*
- * Write a conflict marker to io->output (if defined).
- */
-static void rerere_io_putconflict(int ch, int size, struct rerere_io *io)
-{
-       char buf[64];
-
-       while (size) {
-               if (size <= sizeof(buf) - 2) {
-                       memset(buf, ch, size);
-                       buf[size] = '\n';
-                       buf[size + 1] = '\0';
-                       size = 0;
-               } else {
-                       int sz = sizeof(buf) - 1;
-
-                       /*
-                        * Make sure we will not write everything out
-                        * in this round by leaving at least 1 byte
-                        * for the next round, giving the next round
-                        * a chance to add the terminating LF.  Yuck.
-                        */
-                       if (size <= sz)
-                               sz -= (sz - size) + 1;
-                       memset(buf, ch, sz);
-                       buf[sz] = '\0';
-                       size -= sz;
-               }
-               rerere_io_putstr(buf, io);
-       }
-}
-
 static void rerere_io_putmem(const char *mem, size_t sz, struct rerere_io *io)
 {
        if (io->output)
@@ -384,18 +353,31 @@ static int is_cmarker(char *buf, int marker_char, int marker_size)
        return isspace(*buf);
 }
 
-static int handle_conflict(struct rerere_io *io, int marker_size, git_SHA_CTX *ctx)
+static void rerere_strbuf_putconflict(struct strbuf *buf, int ch, size_t size)
+{
+       strbuf_addchars(buf, ch, size);
+       strbuf_addch(buf, '\n');
+}
+
+static int handle_conflict(struct strbuf *out, struct rerere_io *io,
+                          int marker_size, git_SHA_CTX *ctx)
 {
        enum {
                RR_SIDE_1 = 0, RR_SIDE_2, RR_ORIGINAL
        } hunk = RR_SIDE_1;
        struct strbuf one = STRBUF_INIT, two = STRBUF_INIT;
-       struct strbuf buf = STRBUF_INIT;
+       struct strbuf buf = STRBUF_INIT, conflict = STRBUF_INIT;
        int has_conflicts = -1;
 
        while (!io->getline(&buf, io)) {
                if (is_cmarker(buf.buf, '<', marker_size)) {
-                       break;
+                       if (handle_conflict(&conflict, io, marker_size, NULL) < 0)
+                               break;
+                       if (hunk == RR_SIDE_1)
+                               strbuf_addbuf(&one, &conflict);
+                       else
+                               strbuf_addbuf(&two, &conflict);
+                       strbuf_release(&conflict);
                } else if (is_cmarker(buf.buf, '|', marker_size)) {
                        if (hunk != RR_SIDE_1)
                                break;
@@ -410,11 +392,11 @@ static int handle_conflict(struct rerere_io *io, int marker_size, git_SHA_CTX *c
                        if (strbuf_cmp(&one, &two) > 0)
                                strbuf_swap(&one, &two);
                        has_conflicts = 1;
-                       rerere_io_putconflict('<', marker_size, io);
-                       rerere_io_putmem(one.buf, one.len, io);
-                       rerere_io_putconflict('=', marker_size, io);
-                       rerere_io_putmem(two.buf, two.len, io);
-                       rerere_io_putconflict('>', marker_size, io);
+                       rerere_strbuf_putconflict(out, '<', marker_size);
+                       strbuf_addbuf(out, &one);
+                       rerere_strbuf_putconflict(out, '=', marker_size);
+                       strbuf_addbuf(out, &two);
+                       rerere_strbuf_putconflict(out, '>', marker_size);
                        if (ctx) {
                                git_SHA1_Update(ctx, one.buf ? one.buf : "",
                                            one.len + 1);
@@ -451,21 +433,24 @@ static int handle_conflict(struct rerere_io *io, int marker_size, git_SHA_CTX *c
 static int handle_path(unsigned char *sha1, struct rerere_io *io, int marker_size)
 {
        git_SHA_CTX ctx;
-       struct strbuf buf = STRBUF_INIT;
+       struct strbuf buf = STRBUF_INIT, out = STRBUF_INIT;
        int has_conflicts = 0;
        if (sha1)
                git_SHA1_Init(&ctx);
 
        while (!io->getline(&buf, io)) {
                if (is_cmarker(buf.buf, '<', marker_size)) {
-                       has_conflicts = handle_conflict(io, marker_size,
+                       has_conflicts = handle_conflict(&out, io, marker_size,
                                                        sha1 ? &ctx : NULL);
                        if (has_conflicts < 0)
                                break;
+                       rerere_io_putmem(out.buf, out.len, io);
+                       strbuf_reset(&out);
                } else
                        rerere_io_putstr(buf.buf, io);
        }
        strbuf_release(&buf);
+       strbuf_release(&out);
 
        if (sha1)
                git_SHA1_Final(sha1, &ctx);
@@ -831,7 +816,7 @@ static int do_plain_rerere(struct string_list *rr, int fd)
                struct rerere_id *id;
                unsigned char sha1[20];
                const char *path = conflict.items[i].string;
-               int ret, has_string;
+               int ret;
 
                /*
                 * Ask handle_file() to scan and assign a
@@ -839,12 +824,11 @@ static int do_plain_rerere(struct string_list *rr, int fd)
                 * yet.
                 */
                ret = handle_file(path, sha1, NULL);
-               has_string = string_list_has_string(rr, path);
-               if (ret < 0 && has_string) {
+               if (ret != 0 && string_list_has_string(rr, path)) {
                        remove_variant(string_list_lookup(rr, path)->util);
                        string_list_remove(rr, path, 1);
                }
-               if (ret < 1 || has_string)
+               if (ret < 1)
                        continue;
 
                id = new_rerere_id(sha1);
@@ -901,7 +885,8 @@ int setup_rerere(struct string_list *merge_rr, int flags)
        if (flags & RERERE_READONLY)
                fd = 0;
        else
-               fd = hold_lock_file_for_update(&write_lock, git_path_merge_rr(),
+               fd = hold_lock_file_for_update(&write_lock,
+                                              git_path_merge_rr(the_repository),
                                               LOCK_DIE_ON_ERROR);
        read_rr(merge_rr);
        return fd;
@@ -1124,7 +1109,7 @@ int rerere_forget(struct pathspec *pathspec)
        find_conflict(&conflict);
        for (i = 0; i < conflict.nr; i++) {
                struct string_list_item *it = &conflict.items[i];
-               if (!match_pathspec(pathspec, it->string,
+               if (!match_pathspec(&the_index, pathspec, it->string,
                                    strlen(it->string), 0, NULL, 0))
                        continue;
                rerere_forget_one_path(it->string, &merge_rr);
@@ -1251,6 +1236,6 @@ void rerere_clear(struct string_list *merge_rr)
                        rmdir(rerere_path(id, NULL));
                }
        }
-       unlink_or_warn(git_path_merge_rr());
+       unlink_or_warn(git_path_merge_rr(the_repository));
        rollback_lock_file(&write_lock);
 }