@matheusbsbs / matheus-bagliano / commits / 5b2fd95606
Fork 0

rerere: Separate libgit and builtin functions

This patch moves rerere()-related functions into a newly created rerere.c file. The setup_rerere() function is needed by both rerere() and cmd_rerere(), so this function is moved to rerere.c and declared non-static (and "extern") in newly created rerere.h file. Signed-off-by: Stephan Beyer <s-beyer@gmx.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Stephan Beyer committed Jul 9, 2008 at 14:58 UTC 5b2fd95606cd6d564f96d9d253e7cd19263bc352
6 files changed +390 -355
Makefile
+2
@@ -363,6 +363,7 @@ LIB_H += quote.h
363 LIB_H += reflog-walk.h
364 LIB_H += refs.h
365 LIB_H += remote.h
366 +LIB_H += rerere.h
367 LIB_H += revision.h
368 LIB_H += run-command.h
369 LIB_H += sha1-lookup.h
@@ -447,6 +448,7 @@ LIB_OBJS += read-cache.o
448 LIB_OBJS += reflog-walk.o
449 LIB_OBJS += refs.o
450 LIB_OBJS += remote.o
451 +LIB_OBJS += rerere.o
452 LIB_OBJS += revision.o
453 LIB_OBJS += run-command.o
454 LIB_OBJS += server-info.o
builtin-commit.c
+1
@@ -22,6 +22,7 @@
22 #include "utf8.h"
23 #include "parse-options.h"
24 #include "path-list.h"
25 +#include "rerere.h"
26 #include "unpack-trees.h"
27
28 static const char * const builtin_commit_usage[] = {
builtin-rerere.c
+18 -354
@@ -1,11 +1,10 @@
1 #include "builtin.h"
2 #include "cache.h"
3 #include "path-list.h"
4 +#include "rerere.h"
5 #include "xdiff/xdiff.h"
6 #include "xdiff-interface.h"
7
7 -#include <time.h>
8 -
8 static const char git_rerere_usage[] =
9 "git-rerere [clear | status | diff | gc]";
10
@@ -13,14 +12,6 @@ static const char git_rerere_usage[] =
12 static int cutoff_noresolve = 15;
13 static int cutoff_resolve = 60;
14
16 -/* if rerere_enabled == -1, fall back to detection of .git/rr-cache */
17 -static int rerere_enabled = -1;
18 -
19 -/* automatically update cleanly resolved paths to the index */
20 -static int rerere_autoupdate;
21 -
22 -static char *merge_rr_path;
23 -
15 static const char *rr_path(const char *name, const char *file)
16 {
17 return git_path("rr-cache/%s/%s", name, file);
@@ -38,189 +29,6 @@ static int has_resolution(const char *name)
29 return !stat(rr_path(name, "postimage"), &st);
30 }
31
41 -static void read_rr(struct path_list *rr)
42 -{
43 - unsigned char sha1[20];
44 - char buf[PATH_MAX];
45 - FILE *in = fopen(merge_rr_path, "r");
46 - if (!in)
47 - return;
48 - while (fread(buf, 40, 1, in) == 1) {
49 - int i;
50 - char *name;
51 - if (get_sha1_hex(buf, sha1))
52 - die("corrupt MERGE_RR");
53 - buf[40] = '\0';
54 - name = xstrdup(buf);
55 - if (fgetc(in) != '\t')
56 - die("corrupt MERGE_RR");
57 - for (i = 0; i < sizeof(buf) && (buf[i] = fgetc(in)); i++)
58 - ; /* do nothing */
59 - if (i == sizeof(buf))
60 - die("filename too long");
61 - path_list_insert(buf, rr)->util = name;
62 - }
63 - fclose(in);
64 -}
65 -
66 -static struct lock_file write_lock;
67 -
68 -static int write_rr(struct path_list *rr, int out_fd)
69 -{
70 - int i;
71 - for (i = 0; i < rr->nr; i++) {
72 - const char *path;
73 - int length;
74 - if (!rr->items[i].util)
75 - continue;
76 - path = rr->items[i].path;
77 - length = strlen(path) + 1;
78 - if (write_in_full(out_fd, rr->items[i].util, 40) != 40 ||
79 - write_in_full(out_fd, "\t", 1) != 1 ||
80 - write_in_full(out_fd, path, length) != length)
81 - die("unable to write rerere record");
82 - }
83 - if (commit_lock_file(&write_lock) != 0)
84 - die("unable to write rerere record");
85 - return 0;
86 -}
87 -
88 -static int handle_file(const char *path,
89 - unsigned char *sha1, const char *output)
90 -{
91 - SHA_CTX ctx;
92 - char buf[1024];
93 - int hunk = 0, hunk_no = 0;
94 - struct strbuf one, two;
95 - FILE *f = fopen(path, "r");
96 - FILE *out = NULL;
97 -
98 - if (!f)
99 - return error("Could not open %s", path);
100 -
101 - if (output) {
102 - out = fopen(output, "w");
103 - if (!out) {
104 - fclose(f);
105 - return error("Could not write %s", output);
106 - }
107 - }
108 -
109 - if (sha1)
110 - SHA1_Init(&ctx);
111 -
112 - strbuf_init(&one, 0);
113 - strbuf_init(&two, 0);
114 - while (fgets(buf, sizeof(buf), f)) {
115 - if (!prefixcmp(buf, "<<<<<<< ")) {
116 - if (hunk)
117 - goto bad;
118 - hunk = 1;
119 - } else if (!prefixcmp(buf, "=======") && isspace(buf[7])) {
120 - if (hunk != 1)
121 - goto bad;
122 - hunk = 2;
123 - } else if (!prefixcmp(buf, ">>>>>>> ")) {
124 - if (hunk != 2)
125 - goto bad;
126 - if (strbuf_cmp(&one, &two) > 0)
127 - strbuf_swap(&one, &two);
128 - hunk_no++;
129 - hunk = 0;
130 - if (out) {
131 - fputs("<<<<<<<\n", out);
132 - fwrite(one.buf, one.len, 1, out);
133 - fputs("=======\n", out);
134 - fwrite(two.buf, two.len, 1, out);
135 - fputs(">>>>>>>\n", out);
136 - }
137 - if (sha1) {
138 - SHA1_Update(&ctx, one.buf ? one.buf : "",
139 - one.len + 1);
140 - SHA1_Update(&ctx, two.buf ? two.buf : "",
141 - two.len + 1);
142 - }
143 - strbuf_reset(&one);
144 - strbuf_reset(&two);
145 - } else if (hunk == 1)
146 - strbuf_addstr(&one, buf);
147 - else if (hunk == 2)
148 - strbuf_addstr(&two, buf);
149 - else if (out)
150 - fputs(buf, out);
151 - continue;
152 - bad:
153 - hunk = 99; /* force error exit */
154 - break;
155 - }
156 - strbuf_release(&one);
157 - strbuf_release(&two);
158 -
159 - fclose(f);
160 - if (out)
161 - fclose(out);
162 - if (sha1)
163 - SHA1_Final(sha1, &ctx);
164 - if (hunk) {
165 - if (output)
166 - unlink(output);
167 - return error("Could not parse conflict hunks in %s", path);
168 - }
169 - return hunk_no;
170 -}
171 -
172 -static int find_conflict(struct path_list *conflict)
173 -{
174 - int i;
175 - if (read_cache() < 0)
176 - return error("Could not read index");
177 - for (i = 0; i+1 < active_nr; i++) {
178 - struct cache_entry *e2 = active_cache[i];
179 - struct cache_entry *e3 = active_cache[i+1];
180 - if (ce_stage(e2) == 2 &&
181 - ce_stage(e3) == 3 &&
182 - ce_same_name(e2, e3) &&
183 - S_ISREG(e2->ce_mode) &&
184 - S_ISREG(e3->ce_mode)) {
185 - path_list_insert((const char *)e2->name, conflict);
186 - i++; /* skip over both #2 and #3 */
187 - }
188 - }
189 - return 0;
190 -}
191 -
192 -static int merge(const char *name, const char *path)
193 -{
194 - int ret;
195 - mmfile_t cur, base, other;
196 - mmbuffer_t result = {NULL, 0};
197 - xpparam_t xpp = {XDF_NEED_MINIMAL};
198 -
199 - if (handle_file(path, NULL, rr_path(name, "thisimage")) < 0)
200 - return 1;
201 -
202 - if (read_mmfile(&cur, rr_path(name, "thisimage")) ||
203 - read_mmfile(&base, rr_path(name, "preimage")) ||
204 - read_mmfile(&other, rr_path(name, "postimage")))
205 - return 1;
206 - ret = xdl_merge(&base, &cur, "", &other, "",
207 - &xpp, XDL_MERGE_ZEALOUS, &result);
208 - if (!ret) {
209 - FILE *f = fopen(path, "w");
210 - if (!f)
211 - return error("Could not write to %s", path);
212 - fwrite(result.ptr, result.size, 1, f);
213 - fclose(f);
214 - }
215 -
216 - free(cur.ptr);
217 - free(base.ptr);
218 - free(other.ptr);
219 - free(result.ptr);
220 -
221 - return ret;
222 -}
223 -
32 static void unlink_rr_item(const char *name)
33 {
34 unlink(rr_path(name, "thisimage"));
@@ -229,6 +37,17 @@ static void unlink_rr_item(const char *name)
37 rmdir(git_path("rr-cache/%s", name));
38 }
39
40 +static int git_rerere_gc_config(const char *var, const char *value, void *cb)
41 +{
42 + if (!strcmp(var, "gc.rerereresolved"))
43 + cutoff_resolve = git_config_int(var, value);
44 + else if (!strcmp(var, "gc.rerereunresolved"))
45 + cutoff_noresolve = git_config_int(var, value);
46 + else
47 + return git_default_config(var, value, cb);
48 + return 0;
49 +}
50 +
51 static void garbage_collect(struct path_list *rr)
52 {
53 struct path_list to_remove = { NULL, 0, 0, 1 };
@@ -237,6 +56,7 @@ static void garbage_collect(struct path_list *rr)
56 int i, cutoff;
57 time_t now = time(NULL), then;
58
59 + git_config(git_rerere_gc_config, NULL);
60 dir = opendir(git_path("rr-cache"));
61 while ((e = readdir(dir))) {
62 const char *name = e->d_name;
@@ -289,181 +109,25 @@ static int diff_two(const char *file1, const char *label1,
109 return 0;
110 }
111
292 -static struct lock_file index_lock;
293 -
294 -static int update_paths(struct path_list *update)
295 -{
296 - int i;
297 - int fd = hold_locked_index(&index_lock, 0);
298 - int status = 0;
299 -
300 - if (fd < 0)
301 - return -1;
302 -
303 - for (i = 0; i < update->nr; i++) {
304 - struct path_list_item *item = &update->items[i];
305 - if (add_file_to_cache(item->path, ADD_CACHE_IGNORE_ERRORS))
306 - status = -1;
307 - }
308 -
309 - if (!status && active_cache_changed) {
310 - if (write_cache(fd, active_cache, active_nr) ||
311 - commit_locked_index(&index_lock))
312 - die("Unable to write new index file");
313 - } else if (fd >= 0)
314 - rollback_lock_file(&index_lock);
315 - return status;
316 -}
317 -
318 -static int do_plain_rerere(struct path_list *rr, int fd)
319 -{
320 - struct path_list conflict = { NULL, 0, 0, 1 };
321 - struct path_list update = { NULL, 0, 0, 1 };
322 - int i;
323 -
324 - find_conflict(&conflict);
325 -
326 - /*
327 - * MERGE_RR records paths with conflicts immediately after merge
328 - * failed. Some of the conflicted paths might have been hand resolved
329 - * in the working tree since then, but the initial run would catch all
330 - * and register their preimages.
331 - */
332 -
333 - for (i = 0; i < conflict.nr; i++) {
334 - const char *path = conflict.items[i].path;
335 - if (!path_list_has_path(rr, path)) {
336 - unsigned char sha1[20];
337 - char *hex;
338 - int ret;
339 - ret = handle_file(path, sha1, NULL);
340 - if (ret < 1)
341 - continue;
342 - hex = xstrdup(sha1_to_hex(sha1));
343 - path_list_insert(path, rr)->util = hex;
344 - if (mkdir(git_path("rr-cache/%s", hex), 0755))
345 - continue;;
346 - handle_file(path, NULL, rr_path(hex, "preimage"));
347 - fprintf(stderr, "Recorded preimage for '%s'\n", path);
348 - }
349 - }
350 -
351 - /*
352 - * Now some of the paths that had conflicts earlier might have been
353 - * hand resolved. Others may be similar to a conflict already that
354 - * was resolved before.
355 - */
356 -
357 - for (i = 0; i < rr->nr; i++) {
358 - int ret;
359 - const char *path = rr->items[i].path;
360 - const char *name = (const char *)rr->items[i].util;
361 -
362 - if (has_resolution(name)) {
363 - if (!merge(name, path)) {
364 - fprintf(stderr, "Resolved '%s' using "
365 - "previous resolution.\n", path);
366 - if (rerere_autoupdate)
367 - path_list_insert(path, &update);
368 - goto mark_resolved;
369 - }
370 - }
371 -
372 - /* Let's see if we have resolved it. */
373 - ret = handle_file(path, NULL, NULL);
374 - if (ret)
375 - continue;
376 -
377 - fprintf(stderr, "Recorded resolution for '%s'.\n", path);
378 - copy_file(rr_path(name, "postimage"), path, 0666);
379 - mark_resolved:
380 - rr->items[i].util = NULL;
381 - }
382 -
383 - if (update.nr)
384 - update_paths(&update);
385 -
386 - return write_rr(rr, fd);
387 -}
388 -
389 -static int git_rerere_config(const char *var, const char *value, void *cb)
390 -{
391 - if (!strcmp(var, "gc.rerereresolved"))
392 - cutoff_resolve = git_config_int(var, value);
393 - else if (!strcmp(var, "gc.rerereunresolved"))
394 - cutoff_noresolve = git_config_int(var, value);
395 - else if (!strcmp(var, "rerere.enabled"))
396 - rerere_enabled = git_config_bool(var, value);
397 - else if (!strcmp(var, "rerere.autoupdate"))
398 - rerere_autoupdate = git_config_bool(var, value);
399 - else
400 - return git_default_config(var, value, cb);
401 - return 0;
402 -}
403 -
404 -static int is_rerere_enabled(void)
405 -{
406 - struct stat st;
407 - const char *rr_cache;
408 - int rr_cache_exists;
409 -
410 - if (!rerere_enabled)
411 - return 0;
412 -
413 - rr_cache = git_path("rr-cache");
414 - rr_cache_exists = !stat(rr_cache, &st) && S_ISDIR(st.st_mode);
415 - if (rerere_enabled < 0)
416 - return rr_cache_exists;
417 -
418 - if (!rr_cache_exists &&
419 - (mkdir(rr_cache, 0777) || adjust_shared_perm(rr_cache)))
420 - die("Could not create directory %s", rr_cache);
421 - return 1;
422 -}
423 -
424 -static int setup_rerere(struct path_list *merge_rr)
425 -{
426 - int fd;
427 -
428 - git_config(git_rerere_config, NULL);
429 - if (!is_rerere_enabled())
430 - return -1;
431 -
432 - merge_rr_path = xstrdup(git_path("rr-cache/MERGE_RR"));
433 - fd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1);
434 - read_rr(merge_rr);
435 - return fd;
436 -}
437 -
438 -int rerere(void)
439 -{
440 - struct path_list merge_rr = { NULL, 0, 0, 1 };
441 - int fd;
442 -
443 - fd = setup_rerere(&merge_rr);
444 - if (fd < 0)
445 - return 0;
446 - return do_plain_rerere(&merge_rr, fd);
447 -}
448 -
112 int cmd_rerere(int argc, const char **argv, const char *prefix)
113 {
114 struct path_list merge_rr = { NULL, 0, 0, 1 };
115 int i, fd;
116
117 + if (argc < 2)
118 + return rerere();
119 +
120 fd = setup_rerere(&merge_rr);
121 if (fd < 0)
122 return 0;
123
458 - if (argc < 2)
459 - return do_plain_rerere(&merge_rr, fd);
460 - else if (!strcmp(argv[1], "clear")) {
124 + if (!strcmp(argv[1], "clear")) {
125 for (i = 0; i < merge_rr.nr; i++) {
126 const char *name = (const char *)merge_rr.items[i].util;
127 if (!has_resolution(name))
128 unlink_rr_item(name);
129 }
466 - unlink(merge_rr_path);
130 + unlink(git_path("rr-cache/MERGE_RR"));
131 } else if (!strcmp(argv[1], "gc"))
132 garbage_collect(&merge_rr);
133 else if (!strcmp(argv[1], "status"))
commit.h
-1
@@ -131,7 +131,6 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,
131 int in_merge_bases(struct commit *, struct commit **, int);
132
133 extern int interactive_add(int argc, const char **argv, const char *prefix);
134 -extern int rerere(void);
134
135 static inline int single_parent(struct commit *commit)
136 {
rerere.c new
+360
@@ -0,0 +1,360 @@
1 +#include "cache.h"
2 +#include "path-list.h"
3 +#include "rerere.h"
4 +#include "xdiff/xdiff.h"
5 +#include "xdiff-interface.h"
6 +
7 +/* if rerere_enabled == -1, fall back to detection of .git/rr-cache */
8 +static int rerere_enabled = -1;
9 +
10 +/* automatically update cleanly resolved paths to the index */
11 +static int rerere_autoupdate;
12 +
13 +static char *merge_rr_path;
14 +
15 +static const char *rr_path(const char *name, const char *file)
16 +{
17 + return git_path("rr-cache/%s/%s", name, file);
18 +}
19 +
20 +static int has_resolution(const char *name)
21 +{
22 + struct stat st;
23 + return !stat(rr_path(name, "postimage"), &st);
24 +}
25 +
26 +static void read_rr(struct path_list *rr)
27 +{
28 + unsigned char sha1[20];
29 + char buf[PATH_MAX];
30 + FILE *in = fopen(merge_rr_path, "r");
31 + if (!in)
32 + return;
33 + while (fread(buf, 40, 1, in) == 1) {
34 + int i;
35 + char *name;
36 + if (get_sha1_hex(buf, sha1))
37 + die("corrupt MERGE_RR");
38 + buf[40] = '\0';
39 + name = xstrdup(buf);
40 + if (fgetc(in) != '\t')
41 + die("corrupt MERGE_RR");
42 + for (i = 0; i < sizeof(buf) && (buf[i] = fgetc(in)); i++)
43 + ; /* do nothing */
44 + if (i == sizeof(buf))
45 + die("filename too long");
46 + path_list_insert(buf, rr)->util = name;
47 + }
48 + fclose(in);
49 +}
50 +
51 +static struct lock_file write_lock;
52 +
53 +static int write_rr(struct path_list *rr, int out_fd)
54 +{
55 + int i;
56 + for (i = 0; i < rr->nr; i++) {
57 + const char *path;
58 + int length;
59 + if (!rr->items[i].util)
60 + continue;
61 + path = rr->items[i].path;
62 + length = strlen(path) + 1;
63 + if (write_in_full(out_fd, rr->items[i].util, 40) != 40 ||
64 + write_in_full(out_fd, "\t", 1) != 1 ||
65 + write_in_full(out_fd, path, length) != length)
66 + die("unable to write rerere record");
67 + }
68 + if (commit_lock_file(&write_lock) != 0)
69 + die("unable to write rerere record");
70 + return 0;
71 +}
72 +
73 +static int handle_file(const char *path,
74 + unsigned char *sha1, const char *output)
75 +{
76 + SHA_CTX ctx;
77 + char buf[1024];
78 + int hunk = 0, hunk_no = 0;
79 + struct strbuf one, two;
80 + FILE *f = fopen(path, "r");
81 + FILE *out = NULL;
82 +
83 + if (!f)
84 + return error("Could not open %s", path);
85 +
86 + if (output) {
87 + out = fopen(output, "w");
88 + if (!out) {
89 + fclose(f);
90 + return error("Could not write %s", output);
91 + }
92 + }
93 +
94 + if (sha1)
95 + SHA1_Init(&ctx);
96 +
97 + strbuf_init(&one, 0);
98 + strbuf_init(&two, 0);
99 + while (fgets(buf, sizeof(buf), f)) {
100 + if (!prefixcmp(buf, "<<<<<<< ")) {
101 + if (hunk)
102 + goto bad;
103 + hunk = 1;
104 + } else if (!prefixcmp(buf, "=======") && isspace(buf[7])) {
105 + if (hunk != 1)
106 + goto bad;
107 + hunk = 2;
108 + } else if (!prefixcmp(buf, ">>>>>>> ")) {
109 + if (hunk != 2)
110 + goto bad;
111 + if (strbuf_cmp(&one, &two) > 0)
112 + strbuf_swap(&one, &two);
113 + hunk_no++;
114 + hunk = 0;
115 + if (out) {
116 + fputs("<<<<<<<\n", out);
117 + fwrite(one.buf, one.len, 1, out);
118 + fputs("=======\n", out);
119 + fwrite(two.buf, two.len, 1, out);
120 + fputs(">>>>>>>\n", out);
121 + }
122 + if (sha1) {
123 + SHA1_Update(&ctx, one.buf ? one.buf : "",
124 + one.len + 1);
125 + SHA1_Update(&ctx, two.buf ? two.buf : "",
126 + two.len + 1);
127 + }
128 + strbuf_reset(&one);
129 + strbuf_reset(&two);
130 + } else if (hunk == 1)
131 + strbuf_addstr(&one, buf);
132 + else if (hunk == 2)
133 + strbuf_addstr(&two, buf);
134 + else if (out)
135 + fputs(buf, out);
136 + continue;
137 + bad:
138 + hunk = 99; /* force error exit */
139 + break;
140 + }
141 + strbuf_release(&one);
142 + strbuf_release(&two);
143 +
144 + fclose(f);
145 + if (out)
146 + fclose(out);
147 + if (sha1)
148 + SHA1_Final(sha1, &ctx);
149 + if (hunk) {
150 + if (output)
151 + unlink(output);
152 + return error("Could not parse conflict hunks in %s", path);
153 + }
154 + return hunk_no;
155 +}
156 +
157 +static int find_conflict(struct path_list *conflict)
158 +{
159 + int i;
160 + if (read_cache() < 0)
161 + return error("Could not read index");
162 + for (i = 0; i+1 < active_nr; i++) {
163 + struct cache_entry *e2 = active_cache[i];
164 + struct cache_entry *e3 = active_cache[i+1];
165 + if (ce_stage(e2) == 2 &&
166 + ce_stage(e3) == 3 &&
167 + ce_same_name(e2, e3) &&
168 + S_ISREG(e2->ce_mode) &&
169 + S_ISREG(e3->ce_mode)) {
170 + path_list_insert((const char *)e2->name, conflict);
171 + i++; /* skip over both #2 and #3 */
172 + }
173 + }
174 + return 0;
175 +}
176 +
177 +static int merge(const char *name, const char *path)
178 +{
179 + int ret;
180 + mmfile_t cur, base, other;
181 + mmbuffer_t result = {NULL, 0};
182 + xpparam_t xpp = {XDF_NEED_MINIMAL};
183 +
184 + if (handle_file(path, NULL, rr_path(name, "thisimage")) < 0)
185 + return 1;
186 +
187 + if (read_mmfile(&cur, rr_path(name, "thisimage")) ||
188 + read_mmfile(&base, rr_path(name, "preimage")) ||
189 + read_mmfile(&other, rr_path(name, "postimage")))
190 + return 1;
191 + ret = xdl_merge(&base, &cur, "", &other, "",
192 + &xpp, XDL_MERGE_ZEALOUS, &result);
193 + if (!ret) {
194 + FILE *f = fopen(path, "w");
195 + if (!f)
196 + return error("Could not write to %s", path);
197 + fwrite(result.ptr, result.size, 1, f);
198 + fclose(f);
199 + }
200 +
201 + free(cur.ptr);
202 + free(base.ptr);
203 + free(other.ptr);
204 + free(result.ptr);
205 +
206 + return ret;
207 +}
208 +
209 +static struct lock_file index_lock;
210 +
211 +static int update_paths(struct path_list *update)
212 +{
213 + int i;
214 + int fd = hold_locked_index(&index_lock, 0);
215 + int status = 0;
216 +
217 + if (fd < 0)
218 + return -1;
219 +
220 + for (i = 0; i < update->nr; i++) {
221 + struct path_list_item *item = &update->items[i];
222 + if (add_file_to_cache(item->path, ADD_CACHE_IGNORE_ERRORS))
223 + status = -1;
224 + }
225 +
226 + if (!status && active_cache_changed) {
227 + if (write_cache(fd, active_cache, active_nr) ||
228 + commit_locked_index(&index_lock))
229 + die("Unable to write new index file");
230 + } else if (fd >= 0)
231 + rollback_lock_file(&index_lock);
232 + return status;
233 +}
234 +
235 +static int do_plain_rerere(struct path_list *rr, int fd)
236 +{
237 + struct path_list conflict = { NULL, 0, 0, 1 };
238 + struct path_list update = { NULL, 0, 0, 1 };
239 + int i;
240 +
241 + find_conflict(&conflict);
242 +
243 + /*
244 + * MERGE_RR records paths with conflicts immediately after merge
245 + * failed. Some of the conflicted paths might have been hand resolved
246 + * in the working tree since then, but the initial run would catch all
247 + * and register their preimages.
248 + */
249 +
250 + for (i = 0; i < conflict.nr; i++) {
251 + const char *path = conflict.items[i].path;
252 + if (!path_list_has_path(rr, path)) {
253 + unsigned char sha1[20];
254 + char *hex;
255 + int ret;
256 + ret = handle_file(path, sha1, NULL);
257 + if (ret < 1)
258 + continue;
259 + hex = xstrdup(sha1_to_hex(sha1));
260 + path_list_insert(path, rr)->util = hex;
261 + if (mkdir(git_path("rr-cache/%s", hex), 0755))
262 + continue;;
263 + handle_file(path, NULL, rr_path(hex, "preimage"));
264 + fprintf(stderr, "Recorded preimage for '%s'\n", path);
265 + }
266 + }
267 +
268 + /*
269 + * Now some of the paths that had conflicts earlier might have been
270 + * hand resolved. Others may be similar to a conflict already that
271 + * was resolved before.
272 + */
273 +
274 + for (i = 0; i < rr->nr; i++) {
275 + int ret;
276 + const char *path = rr->items[i].path;
277 + const char *name = (const char *)rr->items[i].util;
278 +
279 + if (has_resolution(name)) {
280 + if (!merge(name, path)) {
281 + fprintf(stderr, "Resolved '%s' using "
282 + "previous resolution.\n", path);
283 + if (rerere_autoupdate)
284 + path_list_insert(path, &update);
285 + goto mark_resolved;
286 + }
287 + }
288 +
289 + /* Let's see if we have resolved it. */
290 + ret = handle_file(path, NULL, NULL);
291 + if (ret)
292 + continue;
293 +
294 + fprintf(stderr, "Recorded resolution for '%s'.\n", path);
295 + copy_file(rr_path(name, "postimage"), path, 0666);
296 + mark_resolved:
297 + rr->items[i].util = NULL;
298 + }
299 +
300 + if (update.nr)
301 + update_paths(&update);
302 +
303 + return write_rr(rr, fd);
304 +}
305 +
306 +static int git_rerere_config(const char *var, const char *value, void *cb)
307 +{
308 + if (!strcmp(var, "rerere.enabled"))
309 + rerere_enabled = git_config_bool(var, value);
310 + else if (!strcmp(var, "rerere.autoupdate"))
311 + rerere_autoupdate = git_config_bool(var, value);
312 + else
313 + return git_default_config(var, value, cb);
314 + return 0;
315 +}
316 +
317 +static int is_rerere_enabled(void)
318 +{
319 + struct stat st;
320 + const char *rr_cache;
321 + int rr_cache_exists;
322 +
323 + if (!rerere_enabled)
324 + return 0;
325 +
326 + rr_cache = git_path("rr-cache");
327 + rr_cache_exists = !stat(rr_cache, &st) && S_ISDIR(st.st_mode);
328 + if (rerere_enabled < 0)
329 + return rr_cache_exists;
330 +
331 + if (!rr_cache_exists &&
332 + (mkdir(rr_cache, 0777) || adjust_shared_perm(rr_cache)))
333 + die("Could not create directory %s", rr_cache);
334 + return 1;
335 +}
336 +
337 +int setup_rerere(struct path_list *merge_rr)
338 +{
339 + int fd;
340 +
341 + git_config(git_rerere_config, NULL);
342 + if (!is_rerere_enabled())
343 + return -1;
344 +
345 + merge_rr_path = xstrdup(git_path("rr-cache/MERGE_RR"));
346 + fd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1);
347 + read_rr(merge_rr);
348 + return fd;
349 +}
350 +
351 +int rerere(void)
352 +{
353 + struct path_list merge_rr = { NULL, 0, 0, 1 };
354 + int fd;
355 +
356 + fd = setup_rerere(&merge_rr);
357 + if (fd < 0)
358 + return 0;
359 + return do_plain_rerere(&merge_rr, fd);
360 +}
rerere.h new
+9
@@ -0,0 +1,9 @@
1 +#ifndef RERERE_H
2 +#define RERERE_H
3 +
4 +#include "path-list.h"
5 +
6 +extern int setup_rerere(struct path_list *);
7 +extern int rerere(void);
8 +
9 +#endif