Skip to content

Commit a13d137

Browse files
committed
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 <[email protected]>
1 parent c0a5423 commit a13d137

File tree

2 files changed

+106
-22
lines changed

2 files changed

+106
-22
lines changed

rerere.c

Lines changed: 105 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,17 @@ static int rerere_dir_alloc;
3030
#define RR_HAS_PREIMAGE 2
3131
static struct rerere_dir {
3232
unsigned char sha1[20];
33-
unsigned char status;
33+
int status_alloc, status_nr;
34+
unsigned char *status;
3435
} **rerere_dir;
3536

3637
static void free_rerere_dirs(void)
3738
{
3839
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);
4042
free(rerere_dir[i]);
43+
}
4144
free(rerere_dir);
4245
rerere_dir_nr = rerere_dir_alloc = 0;
4346
rerere_dir = NULL;
@@ -53,17 +56,59 @@ static const char *rerere_id_hex(const struct rerere_id *id)
5356
return sha1_to_hex(id->collection->sha1);
5457
}
5558

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+
5683
const char *rerere_path(const struct rerere_id *id, const char *file)
5784
{
5885
if (!file)
5986
return git_path("rr-cache/%s", rerere_id_hex(id));
6087

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);
6293
}
6394

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)
6596
{
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;
67112
}
68113

69114
static void scan_rerere_dir(struct rerere_dir *rr_dir)
@@ -74,10 +119,15 @@ static void scan_rerere_dir(struct rerere_dir *rr_dir)
74119
if (!dir)
75120
return;
76121
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+
}
81131
}
82132
closedir(dir);
83133
}
@@ -100,7 +150,9 @@ static struct rerere_dir *find_rerere_dir(const char *hex)
100150
if (pos < 0) {
101151
rr_dir = xmalloc(sizeof(*rr_dir));
102152
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;
104156
pos = -1 - pos;
105157

106158
/* Make sure the array is big enough ... */
@@ -118,19 +170,27 @@ static struct rerere_dir *find_rerere_dir(const char *hex)
118170
static int has_rerere_resolution(const struct rerere_id *id)
119171
{
120172
const int both = RR_HAS_POSTIMAGE|RR_HAS_PREIMAGE;
173+
int variant = id->variant;
121174

122-
return ((id->collection->status & both) == both);
175+
if (variant < 0)
176+
return 0;
177+
return ((id->collection->status[variant] & both) == both);
123178
}
124179

125180
static int has_rerere_preimage(const struct rerere_id *id)
126181
{
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);
128187
}
129188

130189
static struct rerere_id *new_rerere_id_hex(char *hex)
131190
{
132191
struct rerere_id *id = xmalloc(sizeof(*id));
133192
id->collection = find_rerere_dir(hex);
193+
id->variant = -1; /* not known yet */
134194
return id;
135195
}
136196

@@ -157,16 +217,26 @@ static void read_rr(struct string_list *rr)
157217
char *path;
158218
unsigned char sha1[20];
159219
struct rerere_id *id;
220+
int variant;
160221

161222
/* There has to be the hash, tab, path and then NUL */
162223
if (buf.len < 42 || get_sha1_hex(buf.buf, sha1))
163224
die("corrupt MERGE_RR");
164225

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')
166236
die("corrupt MERGE_RR");
167237
buf.buf[40] = '\0';
168-
path = buf.buf + 41;
169238
id = new_rerere_id_hex(buf.buf);
239+
id->variant = variant;
170240
string_list_insert(rr, path)->util = id;
171241
}
172242
strbuf_release(&buf);
@@ -187,9 +257,16 @@ static int write_rr(struct string_list *rr, int out_fd)
187257
id = rr->items[i].util;
188258
if (!id)
189259
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+
193270
if (write_in_full(out_fd, buf.buf, buf.len) != buf.len)
194271
die("unable to write rerere record");
195272

@@ -752,7 +829,12 @@ static void do_rerere_one_path(struct string_list_item *rr_item,
752829
struct string_list *update)
753830
{
754831
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;
756838

757839
if (!has_rerere_preimage(id)) {
758840
/*
@@ -761,13 +843,13 @@ static void do_rerere_one_path(struct string_list_item *rr_item,
761843
* the "preimage" file.
762844
*/
763845
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) {
765847
const char *path = rerere_path(id, "postimage");
766848
if (unlink(path))
767849
die_errno("cannot unlink stray '%s'", path);
768-
id->collection->status &= ~RR_HAS_POSTIMAGE;
850+
id->collection->status[variant] &= ~RR_HAS_POSTIMAGE;
769851
}
770-
id->collection->status |= RR_HAS_PREIMAGE;
852+
id->collection->status[variant] |= RR_HAS_PREIMAGE;
771853
fprintf(stderr, "Recorded preimage for '%s'\n", path);
772854
return;
773855
} else if (has_rerere_resolution(id)) {
@@ -784,7 +866,7 @@ static void do_rerere_one_path(struct string_list_item *rr_item,
784866
} else if (!handle_file(path, NULL, NULL)) {
785867
/* The user has resolved it. */
786868
copy_file(rerere_path(id, "postimage"), path, 0666);
787-
id->collection->status |= RR_HAS_POSTIMAGE;
869+
id->collection->status[variant] |= RR_HAS_POSTIMAGE;
788870
fprintf(stderr, "Recorded resolution for '%s'.\n", path);
789871
} else {
790872
return;
@@ -919,6 +1001,7 @@ static int rerere_forget_one_path(const char *path, struct string_list *rr)
9191001

9201002
/* Nuke the recorded resolution for the conflict */
9211003
id = new_rerere_id(sha1);
1004+
id->variant = 0; /* for now */
9221005
filename = rerere_path(id, "postimage");
9231006
if (unlink(filename))
9241007
return (errno == ENOENT

rerere.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ extern void *RERERE_RESOLVED;
1818
struct rerere_dir;
1919
struct rerere_id {
2020
struct rerere_dir *collection;
21+
int variant;
2122
};
2223

2324
extern int setup_rerere(struct string_list *, int);

0 commit comments

Comments
 (0)