rerere: allow multiple variants to exist
The shape of the conflict in a path determines the conflict ID. The preimage and postimage pair that was recorded for the conflict ID previously may or may not replay well for the conflict we just saw. Currently, we punt when the previous resolution does not cleanly replay, but ideally we should then be able to record the currently conflicted path by assigning a new 'variant', and then record the resolution the user is going to make. Introduce a mechanism to have more than one variant for a given conflict ID; we do not actually assign any variant other than 0th variant yet at this step. Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Jul 23, 2015 at 14:23 UTC
a13d13700b05442855447670d7c3313f99f5da3c
2 files changed
+106
-22
rerere.c
+105
-22
@@ -30,14 +30,17 @@ static int rerere_dir_alloc;
30
#define RR_HAS_PREIMAGE 2
31
static struct rerere_dir {
32
unsigned char sha1[20];
33
- unsigned char status;
33
+ int status_alloc, status_nr;
34
+ unsigned char *status;
35
} **rerere_dir;
36
37
static void free_rerere_dirs(void)
38
{
39
int i;
39
- for (i = 0; i < rerere_dir_nr; i++)
40
+ for (i = 0; i < rerere_dir_nr; i++) {
41
+ free(rerere_dir[i]->status);
42
free(rerere_dir[i]);
43
+ }
44
free(rerere_dir);
45
rerere_dir_nr = rerere_dir_alloc = 0;
46
rerere_dir = NULL;
@@ -53,17 +56,59 @@ static const char *rerere_id_hex(const struct rerere_id *id)
56
return sha1_to_hex(id->collection->sha1);
57
}
58
59
+static void fit_variant(struct rerere_dir *rr_dir, int variant)
60
+{
61
+ variant++;
62
+ ALLOC_GROW(rr_dir->status, variant, rr_dir->status_alloc);
63
+ if (rr_dir->status_nr < variant) {
64
+ memset(rr_dir->status + rr_dir->status_nr,
65
+ '\0', variant - rr_dir->status_nr);
66
+ rr_dir->status_nr = variant;
67
+ }
68
+}
69
+
70
+static void assign_variant(struct rerere_id *id)
71
+{
72
+ int variant;
73
+ struct rerere_dir *rr_dir = id->collection;
74
+
75
+ variant = id->variant;
76
+ if (variant < 0) {
77
+ variant = 0; /* for now */
78
+ }
79
+ fit_variant(rr_dir, variant);
80
+ id->variant = variant;
81
+}
82
+
83
const char *rerere_path(const struct rerere_id *id, const char *file)
84
{
85
if (!file)
86
return git_path("rr-cache/%s", rerere_id_hex(id));
87
61
- return git_path("rr-cache/%s/%s", rerere_id_hex(id), file);
88
+ if (id->variant <= 0)
89
+ return git_path("rr-cache/%s/%s", rerere_id_hex(id), file);
90
+
91
+ return git_path("rr-cache/%s/%s.%d",
92
+ rerere_id_hex(id), file, id->variant);
93
}
94
64
-static int is_rr_file(const char *name, const char *filename)
95
+static int is_rr_file(const char *name, const char *filename, int *variant)
96
{
66
- return !strcmp(name, filename);
97
+ const char *suffix;
98
+ char *ep;
99
+
100
+ if (!strcmp(name, filename)) {
101
+ *variant = 0;
102
+ return 1;
103
+ }
104
+ if (!skip_prefix(name, filename, &suffix) || *suffix != '.')
105
+ return 0;
106
+
107
+ errno = 0;
108
+ *variant = strtol(suffix + 1, &ep, 10);
109
+ if (errno || *ep)
110
+ return 0;
111
+ return 1;
112
}
113
114
static void scan_rerere_dir(struct rerere_dir *rr_dir)
@@ -74,10 +119,15 @@ static void scan_rerere_dir(struct rerere_dir *rr_dir)
119
if (!dir)
120
return;
121
while ((de = readdir(dir)) != NULL) {
77
- if (is_rr_file(de->d_name, "postimage"))
78
- rr_dir->status |= RR_HAS_POSTIMAGE;
79
- else if (is_rr_file(de->d_name, "preimage"))
80
- rr_dir->status |= RR_HAS_PREIMAGE;
122
+ int variant;
123
+
124
+ if (is_rr_file(de->d_name, "postimage", &variant)) {
125
+ fit_variant(rr_dir, variant);
126
+ rr_dir->status[variant] |= RR_HAS_POSTIMAGE;
127
+ } else if (is_rr_file(de->d_name, "preimage", &variant)) {
128
+ fit_variant(rr_dir, variant);
129
+ rr_dir->status[variant] |= RR_HAS_PREIMAGE;
130
+ }
131
}
132
closedir(dir);
133
}
@@ -100,7 +150,9 @@ static struct rerere_dir *find_rerere_dir(const char *hex)
150
if (pos < 0) {
151
rr_dir = xmalloc(sizeof(*rr_dir));
152
hashcpy(rr_dir->sha1, sha1);
103
- rr_dir->status = 0;
153
+ rr_dir->status = NULL;
154
+ rr_dir->status_nr = 0;
155
+ rr_dir->status_alloc = 0;
156
pos = -1 - pos;
157
158
/* Make sure the array is big enough ... */
@@ -118,19 +170,27 @@ static struct rerere_dir *find_rerere_dir(const char *hex)
170
static int has_rerere_resolution(const struct rerere_id *id)
171
{
172
const int both = RR_HAS_POSTIMAGE|RR_HAS_PREIMAGE;
173
+ int variant = id->variant;
174
122
- return ((id->collection->status & both) == both);
175
+ if (variant < 0)
176
+ return 0;
177
+ return ((id->collection->status[variant] & both) == both);
178
}
179
180
static int has_rerere_preimage(const struct rerere_id *id)
181
{
127
- return (id->collection->status & RR_HAS_PREIMAGE);
182
+ int variant = id->variant;
183
+
184
+ if (variant < 0)
185
+ return 0;
186
+ return (id->collection->status[variant] & RR_HAS_PREIMAGE);
187
}
188
189
static struct rerere_id *new_rerere_id_hex(char *hex)
190
{
191
struct rerere_id *id = xmalloc(sizeof(*id));
192
id->collection = find_rerere_dir(hex);
193
+ id->variant = -1; /* not known yet */
194
return id;
195
}
196
@@ -157,16 +217,26 @@ static void read_rr(struct string_list *rr)
217
char *path;
218
unsigned char sha1[20];
219
struct rerere_id *id;
220
+ int variant;
221
222
/* There has to be the hash, tab, path and then NUL */
223
if (buf.len < 42 || get_sha1_hex(buf.buf, sha1))
224
die("corrupt MERGE_RR");
225
165
- if (buf.buf[40] != '\t')
226
+ if (buf.buf[40] != '.') {
227
+ variant = 0;
228
+ path = buf.buf + 40;
229
+ } else {
230
+ errno = 0;
231
+ variant = strtol(buf.buf + 41, &path, 10);
232
+ if (errno)
233
+ die("corrupt MERGE_RR");
234
+ }
235
+ if (*(path++) != '\t')
236
die("corrupt MERGE_RR");
237
buf.buf[40] = '\0';
168
- path = buf.buf + 41;
238
id = new_rerere_id_hex(buf.buf);
239
+ id->variant = variant;
240
string_list_insert(rr, path)->util = id;
241
}
242
strbuf_release(&buf);
@@ -187,9 +257,16 @@ static int write_rr(struct string_list *rr, int out_fd)
257
id = rr->items[i].util;
258
if (!id)
259
continue;
190
- strbuf_addf(&buf, "%s\t%s%c",
191
- rerere_id_hex(id),
192
- rr->items[i].string, 0);
260
+ assert(id->variant >= 0);
261
+ if (0 < id->variant)
262
+ strbuf_addf(&buf, "%s.%d\t%s%c",
263
+ rerere_id_hex(id), id->variant,
264
+ rr->items[i].string, 0);
265
+ else
266
+ strbuf_addf(&buf, "%s\t%s%c",
267
+ rerere_id_hex(id),
268
+ rr->items[i].string, 0);
269
+
270
if (write_in_full(out_fd, buf.buf, buf.len) != buf.len)
271
die("unable to write rerere record");
272
@@ -752,7 +829,12 @@ static void do_rerere_one_path(struct string_list_item *rr_item,
829
struct string_list *update)
830
{
831
const char *path = rr_item->string;
755
- const struct rerere_id *id = rr_item->util;
832
+ struct rerere_id *id = rr_item->util;
833
+ int variant;
834
+
835
+ if (id->variant < 0)
836
+ assign_variant(id);
837
+ variant = id->variant;
838
839
if (!has_rerere_preimage(id)) {
840
/*
@@ -761,13 +843,13 @@ static void do_rerere_one_path(struct string_list_item *rr_item,
843
* the "preimage" file.
844
*/
845
handle_file(path, NULL, rerere_path(id, "preimage"));
764
- if (id->collection->status & RR_HAS_POSTIMAGE) {
846
+ if (id->collection->status[variant] & RR_HAS_POSTIMAGE) {
847
const char *path = rerere_path(id, "postimage");
848
if (unlink(path))
849
die_errno("cannot unlink stray '%s'", path);
768
- id->collection->status &= ~RR_HAS_POSTIMAGE;
850
+ id->collection->status[variant] &= ~RR_HAS_POSTIMAGE;
851
}
770
- id->collection->status |= RR_HAS_PREIMAGE;
852
+ id->collection->status[variant] |= RR_HAS_PREIMAGE;
853
fprintf(stderr, "Recorded preimage for '%s'\n", path);
854
return;
855
} else if (has_rerere_resolution(id)) {
@@ -784,7 +866,7 @@ static void do_rerere_one_path(struct string_list_item *rr_item,
866
} else if (!handle_file(path, NULL, NULL)) {
867
/* The user has resolved it. */
868
copy_file(rerere_path(id, "postimage"), path, 0666);
787
- id->collection->status |= RR_HAS_POSTIMAGE;
869
+ id->collection->status[variant] |= RR_HAS_POSTIMAGE;
870
fprintf(stderr, "Recorded resolution for '%s'.\n", path);
871
} else {
872
return;
@@ -919,6 +1001,7 @@ static int rerere_forget_one_path(const char *path, struct string_list *rr)
1001
1002
/* Nuke the recorded resolution for the conflict */
1003
id = new_rerere_id(sha1);
1004
+ id->variant = 0; /* for now */
1005
filename = rerere_path(id, "postimage");
1006
if (unlink(filename))
1007
return (errno == ENOENT
rerere.h
+1
@@ -18,6 +18,7 @@ extern void *RERERE_RESOLVED;
18
struct rerere_dir;
19
struct rerere_id {
20
struct rerere_dir *collection;
21
+ int variant;
22
};
23
24
extern int setup_rerere(struct string_list *, int);