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