Code

Merge branch 'jc/diff-mark'
[git.git] / builtin-rerere.c
index b8867ab4add83dee4ab99108e96949bcd65290a0..c25b3d5586ff08061295350b5ceae01246931037 100644 (file)
@@ -12,6 +12,9 @@ static const char git_rerere_usage[] =
 static int cutoff_noresolve = 15;
 static int cutoff_resolve = 60;
 
+/* if rerere_enabled == -1, fall back to detection of .git/rr-cache */
+static int rerere_enabled = -1;
+
 static char *merge_rr_path;
 
 static const char *rr_path(const char *name, const char *file)
@@ -57,7 +60,8 @@ static int write_rr(struct path_list *rr, int out_fd)
                    write_in_full(out_fd, path, length) != length)
                        die("unable to write rerere record");
        }
-       close(out_fd);
+       if (close(out_fd) != 0)
+               die("unable to write rerere record");
        return commit_lock_file(&write_lock);
 }
 
@@ -78,6 +82,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)
 {
@@ -110,10 +121,13 @@ static int handle_file(const char *path,
                else if (!prefixcmp(buf, "======="))
                        hunk = 2;
                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;
@@ -131,6 +145,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)
@@ -269,8 +285,8 @@ static int diff_two(const char *file1, const char *label1,
        printf("--- a/%s\n+++ b/%s\n", label1, label2);
        fflush(stdout);
        xpp.flags = XDF_NEED_MINIMAL;
+       memset(&xecfg, 0, sizeof(xecfg));
        xecfg.ctxlen = 3;
-       xecfg.flags = 0;
        ecb.outf = outf;
        xdl_diff(&minus, &plus, &xpp, &xecfg, &ecb);
 
@@ -374,21 +390,41 @@ static int git_rerere_config(const char *var, const char *value)
                cutoff_resolve = git_config_int(var, value);
        else if (!strcmp(var, "gc.rerereunresolved"))
                cutoff_noresolve = git_config_int(var, value);
+       else if (!strcmp(var, "rerere.enabled"))
+               rerere_enabled = git_config_bool(var, value);
        else
                return git_default_config(var, value);
        return 0;
 }
 
-int cmd_rerere(int argc, const char **argv, const char *prefix)
+static int is_rerere_enabled(void)
 {
-       struct path_list merge_rr = { NULL, 0, 0, 1 };
-       int i, fd = -1;
        struct stat st;
+       const char *rr_cache;
+       int rr_cache_exists;
 
-       if (stat(git_path("rr-cache"), &st) || !S_ISDIR(st.st_mode))
+       if (!rerere_enabled)
                return 0;
 
+       rr_cache = git_path("rr-cache");
+       rr_cache_exists = !stat(rr_cache, &st) && S_ISDIR(st.st_mode);
+       if (rerere_enabled < 0)
+               return rr_cache_exists;
+
+       if (!rr_cache_exists &&
+           (mkdir(rr_cache, 0777) || adjust_shared_perm(rr_cache)))
+               die("Could not create directory %s", rr_cache);
+       return 1;
+}
+
+int cmd_rerere(int argc, const char **argv, const char *prefix)
+{
+       struct path_list merge_rr = { NULL, 0, 0, 1 };
+       int i, fd = -1;
+
        git_config(git_rerere_config);
+       if (!is_rerere_enabled())
+               return 0;
 
        merge_rr_path = xstrdup(git_path("rr-cache/MERGE_RR"));
        fd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1);
@@ -398,6 +434,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
                return do_plain_rerere(&merge_rr, fd);
        else if (!strcmp(argv[1], "clear")) {
                for (i = 0; i < merge_rr.nr; i++) {
+                       struct stat st;
                        const char *name = (const char *)merge_rr.items[i].util;
                        if (!stat(git_path("rr-cache/%s", name), &st) &&
                                        S_ISDIR(st.st_mode) &&
@@ -422,4 +459,3 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
        path_list_clear(&merge_rr, 1);
        return 0;
 }
-