Add clean.requireForce option, and add -f option to git-clean to override it
[gitweb.git] / builtin-rerere.c
index d064bd8bf0218feb7d4ad01b39be6a143757499e..8c2c8bdc18a69e4dff7386548e5f7ea78a133f7b 100644 (file)
@@ -51,9 +51,11 @@ static int write_rr(struct path_list *rr, int out_fd)
        int i;
        for (i = 0; i < rr->nr; i++) {
                const char *path = rr->items[i].path;
-               write(out_fd, rr->items[i].util, 40);
-               write(out_fd, "\t", 1);
-               write(out_fd, path, strlen(path) + 1);
+               int length = strlen(path) + 1;
+               if (write_in_full(out_fd, rr->items[i].util, 40) != 40 ||
+                   write_in_full(out_fd, "\t", 1) != 1 ||
+                   write_in_full(out_fd, path, length) != length)
+                       die("unable to write rerere record");
        }
        close(out_fd);
        return commit_lock_file(&write_lock);
@@ -76,6 +78,13 @@ static void append_line(struct buffer *buffer, const char *line)
        buffer->nr += len;
 }
 
+static void clear_buffer(struct buffer *buffer)
+{
+       free(buffer->ptr);
+       buffer->ptr = NULL;
+       buffer->nr = buffer->alloc = 0;
+}
+
 static int handle_file(const char *path,
         unsigned char *sha1, const char *output)
 {
@@ -103,15 +112,18 @@ static int handle_file(const char *path,
                SHA1_Init(&ctx);
 
        while (fgets(buf, sizeof(buf), f)) {
-               if (!strncmp("<<<<<<< ", buf, 8))
+               if (!prefixcmp(buf, "<<<<<<< "))
                        hunk = 1;
-               else if (!strncmp("=======", buf, 7))
+               else if (!prefixcmp(buf, "======="))
                        hunk = 2;
-               else if (!strncmp(">>>>>>> ", buf, 8)) {
+               else if (!prefixcmp(buf, ">>>>>>> ")) {
+                       int one_is_longer = (one->nr > two->nr);
+                       int common_len = one_is_longer ? two->nr : one->nr;
+                       int cmp = memcmp(one->ptr, two->ptr, common_len);
+
                        hunk_no++;
                        hunk = 0;
-                       if (memcmp(one->ptr, two->ptr, one->nr < two->nr ?
-                                               one->nr : two->nr) > 0) {
+                       if ((cmp > 0) || ((cmp == 0) && one_is_longer)) {
                                struct buffer *swap = one;
                                one = two;
                                two = swap;
@@ -129,6 +141,8 @@ static int handle_file(const char *path,
                                SHA1_Update(&ctx, two->ptr, two->nr);
                                SHA1_Update(&ctx, "\0", 1);
                        }
+                       clear_buffer(one);
+                       clear_buffer(two);
                } else if (hunk == 1)
                        append_line(one, buf);
                else if (hunk == 2)
@@ -152,13 +166,17 @@ static int find_conflict(struct path_list *conflict)
                return error("Could not read index");
        for (i = 0; i + 2 < active_nr; i++) {
                struct cache_entry *e1 = active_cache[i];
-               struct cache_entry *e2 = active_cache[i + 1];
-               struct cache_entry *e3 = active_cache[i + 2];
-               if (ce_stage(e1) == 1 && ce_stage(e2) == 2 &&
-                               ce_stage(e3) == 3 && ce_same_name(e1, e2) &&
-                               ce_same_name(e1, e3)) {
+               struct cache_entry *e2 = active_cache[i+1];
+               struct cache_entry *e3 = active_cache[i+2];
+               if (ce_stage(e1) == 1 &&
+                   ce_stage(e2) == 2 &&
+                   ce_stage(e3) == 3 &&
+                   ce_same_name(e1, e2) && ce_same_name(e1, e3) &&
+                   S_ISREG(ntohl(e1->ce_mode)) &&
+                   S_ISREG(ntohl(e2->ce_mode)) &&
+                   S_ISREG(ntohl(e3->ce_mode))) {
                        path_list_insert((const char *)e1->name, conflict);
-                       i += 3;
+                       i += 2;
                }
        }
        return 0;
@@ -244,7 +262,8 @@ static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)
 {
        int i;
        for (i = 0; i < nbuf; i++)
-               write(1, ptr[i].ptr, ptr[i].size);
+               if (write_in_full(1, ptr[i].ptr, ptr[i].size) != ptr[i].size)
+                       return -1;
        return 0;
 }
 
@@ -350,11 +369,10 @@ static int do_plain_rerere(struct path_list *rr, int fd)
                fprintf(stderr, "Recorded resolution for '%s'.\n", path);
                copy_file(path, rr_path(name, "postimage"));
 tail_optimization:
-               if (i < rr->nr - 1) {
+               if (i < rr->nr - 1)
                        memmove(rr->items + i,
-                                       rr->items + i + 1,
-                                       rr->nr - i - 1);
-               }
+                               rr->items + i + 1,
+                               sizeof(rr->items[0]) * (rr->nr - i - 1));
                rr->nr--;
                i--;
        }
@@ -362,6 +380,17 @@ static int do_plain_rerere(struct path_list *rr, int fd)
        return write_rr(rr, fd);
 }
 
+static int git_rerere_config(const char *var, const char *value)
+{
+       if (!strcmp(var, "gc.rerereresolved"))
+               cutoff_resolve = git_config_int(var, value);
+       else if (!strcmp(var, "gc.rerereunresolved"))
+               cutoff_noresolve = git_config_int(var, value);
+       else
+               return git_default_config(var, value);
+       return 0;
+}
+
 int cmd_rerere(int argc, const char **argv, const char *prefix)
 {
        struct path_list merge_rr = { NULL, 0, 0, 1 };
@@ -371,6 +400,8 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
        if (stat(git_path("rr-cache"), &st) || !S_ISDIR(st.st_mode))
                return 0;
 
+       git_config(git_rerere_config);
+
        merge_rr_path = xstrdup(git_path("rr-cache/MERGE_RR"));
        fd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1);
        read_rr(&merge_rr);