blob: 09e19412859b3edb7be4142947d3967fc76520cc [file] [log] [blame]
Elijah Newrenbc5c5ec2023-05-16 06:33:57 +00001#include "git-compat-util.h"
Elijah Newren0b027f62023-03-21 06:25:58 +00002#include "abspath.h"
Brandon Williamsb2141fc2017-06-14 11:07:36 -07003#include "config.h"
Elijah Newrend5fff462023-04-22 20:17:12 +00004#include "copy.h"
Elijah Newrenf394e092023-03-21 06:25:54 +00005#include "gettext.h"
Elijah Newren41771fa2023-02-24 00:09:27 +00006#include "hex.h"
Michael Haggerty697cc8e2014-10-01 12:28:42 +02007#include "lockfile.h"
Johannes Schindelinc455c872008-07-21 19:03:49 +01008#include "string-list.h"
Elijah Newren08c46a42023-05-16 06:33:56 +00009#include "read-cache-ll.h"
Stephan Beyer5b2fd952008-07-09 14:58:57 +020010#include "rerere.h"
Stephan Beyer5b2fd952008-07-09 14:58:57 +020011#include "xdiff-interface.h"
Junio C Hamanodea45622009-12-25 15:51:32 -080012#include "dir.h"
13#include "resolve-undo.h"
Elijah Newren67238992023-05-16 06:34:04 +000014#include "merge-ll.h"
Junio C Hamano85885672010-01-16 23:28:46 -080015#include "attr.h"
Elijah Newrenc3399322023-05-16 06:33:59 +000016#include "path.h"
Nguyễn Thái Ngọc Duy01a10b02013-07-14 15:35:40 +070017#include "pathspec.h"
Elijah Newren87bed172023-04-11 00:41:53 -070018#include "object-file.h"
Elijah Newrena034e912023-05-16 06:34:06 +000019#include "object-store-ll.h"
Martin Ågrenbc626922020-12-31 12:56:23 +010020#include "hash-lookup.h"
Jeff King680ff912021-01-28 01:34:31 -050021#include "strmap.h"
Stephan Beyer5b2fd952008-07-09 14:58:57 +020022
Martin von Zweigbergkac49f5c2011-02-16 05:47:44 -050023#define RESOLVED 0
24#define PUNTED 1
25#define THREE_STAGED 2
26void *RERERE_RESOLVED = &RERERE_RESOLVED;
27
Stephan Beyer5b2fd952008-07-09 14:58:57 +020028/* if rerere_enabled == -1, fall back to detection of .git/rr-cache */
29static int rerere_enabled = -1;
30
31/* automatically update cleanly resolved paths to the index */
32static int rerere_autoupdate;
33
Junio C Hamano2c7929b2015-07-16 15:47:13 -070034#define RR_HAS_POSTIMAGE 1
35#define RR_HAS_PREIMAGE 2
Jeff King680ff912021-01-28 01:34:31 -050036struct rerere_dir {
Junio C Hamanoa13d1372015-07-23 14:23:24 -070037 int status_alloc, status_nr;
38 unsigned char *status;
Jeff King680ff912021-01-28 01:34:31 -050039 char name[FLEX_ARRAY];
40};
41
42static struct strmap rerere_dirs = STRMAP_INIT;
Junio C Hamano1869bbe2015-07-16 14:50:05 -070043
44static void free_rerere_dirs(void)
45{
Jeff King680ff912021-01-28 01:34:31 -050046 struct hashmap_iter iter;
47 struct strmap_entry *ent;
48
49 strmap_for_each_entry(&rerere_dirs, &iter, ent) {
50 struct rerere_dir *rr_dir = ent->value;
51 free(rr_dir->status);
52 free(rr_dir);
Junio C Hamanoa13d1372015-07-23 14:23:24 -070053 }
Jeff King680ff912021-01-28 01:34:31 -050054 strmap_clear(&rerere_dirs, 0);
Junio C Hamano1869bbe2015-07-16 14:50:05 -070055}
56
Junio C Hamano1d51ece2015-07-04 17:38:34 -070057static void free_rerere_id(struct string_list_item *item)
Stephan Beyer5b2fd952008-07-09 14:58:57 +020058{
Junio C Hamano1d51ece2015-07-04 17:38:34 -070059 free(item->util);
Stephan Beyer5b2fd952008-07-09 14:58:57 +020060}
61
Junio C Hamano1d51ece2015-07-04 17:38:34 -070062static const char *rerere_id_hex(const struct rerere_id *id)
63{
Jeff King680ff912021-01-28 01:34:31 -050064 return id->collection->name;
Junio C Hamano1d51ece2015-07-04 17:38:34 -070065}
66
Junio C Hamanoa13d1372015-07-23 14:23:24 -070067static void fit_variant(struct rerere_dir *rr_dir, int variant)
68{
69 variant++;
70 ALLOC_GROW(rr_dir->status, variant, rr_dir->status_alloc);
71 if (rr_dir->status_nr < variant) {
72 memset(rr_dir->status + rr_dir->status_nr,
73 '\0', variant - rr_dir->status_nr);
74 rr_dir->status_nr = variant;
75 }
76}
77
78static void assign_variant(struct rerere_id *id)
79{
80 int variant;
81 struct rerere_dir *rr_dir = id->collection;
82
83 variant = id->variant;
84 if (variant < 0) {
Junio C Hamano629716d2015-07-30 15:49:18 -070085 for (variant = 0; variant < rr_dir->status_nr; variant++)
86 if (!rr_dir->status[variant])
87 break;
Junio C Hamanoa13d1372015-07-23 14:23:24 -070088 }
89 fit_variant(rr_dir, variant);
90 id->variant = variant;
Junio C Hamano1d51ece2015-07-04 17:38:34 -070091}
92
93const char *rerere_path(const struct rerere_id *id, const char *file)
94{
95 if (!file)
96 return git_path("rr-cache/%s", rerere_id_hex(id));
97
Junio C Hamanoa13d1372015-07-23 14:23:24 -070098 if (id->variant <= 0)
99 return git_path("rr-cache/%s/%s", rerere_id_hex(id), file);
100
101 return git_path("rr-cache/%s/%s.%d",
102 rerere_id_hex(id), file, id->variant);
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700103}
104
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700105static int is_rr_file(const char *name, const char *filename, int *variant)
Junio C Hamano2c7929b2015-07-16 15:47:13 -0700106{
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700107 const char *suffix;
108 char *ep;
109
110 if (!strcmp(name, filename)) {
111 *variant = 0;
112 return 1;
113 }
114 if (!skip_prefix(name, filename, &suffix) || *suffix != '.')
115 return 0;
116
117 errno = 0;
118 *variant = strtol(suffix + 1, &ep, 10);
119 if (errno || *ep)
120 return 0;
121 return 1;
Junio C Hamano2c7929b2015-07-16 15:47:13 -0700122}
123
124static void scan_rerere_dir(struct rerere_dir *rr_dir)
125{
126 struct dirent *de;
Jeff King680ff912021-01-28 01:34:31 -0500127 DIR *dir = opendir(git_path("rr-cache/%s", rr_dir->name));
Junio C Hamano2c7929b2015-07-16 15:47:13 -0700128
129 if (!dir)
130 return;
131 while ((de = readdir(dir)) != NULL) {
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700132 int variant;
133
134 if (is_rr_file(de->d_name, "postimage", &variant)) {
135 fit_variant(rr_dir, variant);
136 rr_dir->status[variant] |= RR_HAS_POSTIMAGE;
137 } else if (is_rr_file(de->d_name, "preimage", &variant)) {
138 fit_variant(rr_dir, variant);
139 rr_dir->status[variant] |= RR_HAS_PREIMAGE;
140 }
Junio C Hamano2c7929b2015-07-16 15:47:13 -0700141 }
142 closedir(dir);
143}
144
Junio C Hamano1869bbe2015-07-16 14:50:05 -0700145static struct rerere_dir *find_rerere_dir(const char *hex)
146{
Junio C Hamano1869bbe2015-07-16 14:50:05 -0700147 struct rerere_dir *rr_dir;
Junio C Hamano1869bbe2015-07-16 14:50:05 -0700148
Jeff King680ff912021-01-28 01:34:31 -0500149 rr_dir = strmap_get(&rerere_dirs, hex);
150 if (!rr_dir) {
151 FLEX_ALLOC_STR(rr_dir, name, hex);
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700152 rr_dir->status = NULL;
153 rr_dir->status_nr = 0;
154 rr_dir->status_alloc = 0;
Jeff King680ff912021-01-28 01:34:31 -0500155 strmap_put(&rerere_dirs, hex, rr_dir);
Junio C Hamano1869bbe2015-07-16 14:50:05 -0700156
Junio C Hamano2c7929b2015-07-16 15:47:13 -0700157 scan_rerere_dir(rr_dir);
Junio C Hamano1869bbe2015-07-16 14:50:05 -0700158 }
Jeff King680ff912021-01-28 01:34:31 -0500159 return rr_dir;
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700160}
161
162static int has_rerere_resolution(const struct rerere_id *id)
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200163{
Junio C Hamano05dd9f12015-07-17 13:28:31 -0700164 const int both = RR_HAS_POSTIMAGE|RR_HAS_PREIMAGE;
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700165 int variant = id->variant;
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700166
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700167 if (variant < 0)
168 return 0;
169 return ((id->collection->status[variant] & both) == both);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200170}
171
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700172static struct rerere_id *new_rerere_id_hex(char *hex)
173{
174 struct rerere_id *id = xmalloc(sizeof(*id));
Junio C Hamano1869bbe2015-07-16 14:50:05 -0700175 id->collection = find_rerere_dir(hex);
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700176 id->variant = -1; /* not known yet */
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700177 return id;
178}
179
brian m. carlson3f34d702019-08-18 20:04:25 +0000180static struct rerere_id *new_rerere_id(unsigned char *hash)
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700181{
brian m. carlson3f34d702019-08-18 20:04:25 +0000182 return new_rerere_id_hex(hash_to_hex(hash));
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700183}
184
Junio C Hamano4b68c2a2015-06-30 22:36:35 -0700185/*
186 * $GIT_DIR/MERGE_RR file is a collection of records, each of which is
187 * "conflict ID", a HT and pathname, terminated with a NUL, and is
188 * used to keep track of the set of paths that "rerere" may need to
189 * work on (i.e. what is left by the previous invocation of "git
190 * rerere" during the current conflict resolution session).
191 */
Nguyễn Thái Ngọc Duy55e6b352018-11-10 06:49:09 +0100192static void read_rr(struct repository *r, struct string_list *rr)
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200193{
Junio C Hamanof5800f62015-06-28 15:51:59 -0700194 struct strbuf buf = STRBUF_INIT;
Nguyễn Thái Ngọc Duy55e6b352018-11-10 06:49:09 +0100195 FILE *in = fopen_or_warn(git_path_merge_rr(r), "r");
Junio C Hamanof5800f62015-06-28 15:51:59 -0700196
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200197 if (!in)
198 return;
Junio C Hamanof5800f62015-06-28 15:51:59 -0700199 while (!strbuf_getwholeline(&buf, in, '\0')) {
200 char *path;
brian m. carlson0d7c4192018-10-15 00:02:02 +0000201 unsigned char hash[GIT_MAX_RAWSZ];
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700202 struct rerere_id *id;
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700203 int variant;
brian m. carlson0d7c4192018-10-15 00:02:02 +0000204 const unsigned hexsz = the_hash_algo->hexsz;
Junio C Hamanof5800f62015-06-28 15:51:59 -0700205
206 /* There has to be the hash, tab, path and then NUL */
Junio C Hamano08e5fb12023-07-24 16:11:03 -0700207 if (buf.len < hexsz + 2 || get_hash_hex(buf.buf, hash))
Thomas Gummerer2373b652018-08-05 18:20:30 +0100208 die(_("corrupt MERGE_RR"));
Junio C Hamanof5800f62015-06-28 15:51:59 -0700209
brian m. carlson0d7c4192018-10-15 00:02:02 +0000210 if (buf.buf[hexsz] != '.') {
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700211 variant = 0;
brian m. carlson0d7c4192018-10-15 00:02:02 +0000212 path = buf.buf + hexsz;
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700213 } else {
214 errno = 0;
brian m. carlson0d7c4192018-10-15 00:02:02 +0000215 variant = strtol(buf.buf + hexsz + 1, &path, 10);
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700216 if (errno)
Thomas Gummerer2373b652018-08-05 18:20:30 +0100217 die(_("corrupt MERGE_RR"));
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700218 }
219 if (*(path++) != '\t')
Thomas Gummerer2373b652018-08-05 18:20:30 +0100220 die(_("corrupt MERGE_RR"));
brian m. carlson0d7c4192018-10-15 00:02:02 +0000221 buf.buf[hexsz] = '\0';
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700222 id = new_rerere_id_hex(buf.buf);
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700223 id->variant = variant;
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700224 string_list_insert(rr, path)->util = id;
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200225 }
Junio C Hamanof5800f62015-06-28 15:51:59 -0700226 strbuf_release(&buf);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200227 fclose(in);
228}
229
230static struct lock_file write_lock;
231
Johannes Schindelinc455c872008-07-21 19:03:49 +0100232static int write_rr(struct string_list *rr, int out_fd)
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200233{
234 int i;
235 for (i = 0; i < rr->nr; i++) {
Junio C Hamanoe2cb6a92015-06-28 16:28:00 -0700236 struct strbuf buf = STRBUF_INIT;
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700237 struct rerere_id *id;
Junio C Hamanoe2cb6a92015-06-28 16:28:00 -0700238
239 assert(rr->items[i].util != RERERE_RESOLVED);
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700240
241 id = rr->items[i].util;
242 if (!id)
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200243 continue;
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700244 assert(id->variant >= 0);
245 if (0 < id->variant)
246 strbuf_addf(&buf, "%s.%d\t%s%c",
247 rerere_id_hex(id), id->variant,
248 rr->items[i].string, 0);
249 else
250 strbuf_addf(&buf, "%s\t%s%c",
251 rerere_id_hex(id),
252 rr->items[i].string, 0);
253
Jeff King06f46f22017-09-13 13:16:03 -0400254 if (write_in_full(out_fd, buf.buf, buf.len) < 0)
Thomas Gummerer2373b652018-08-05 18:20:30 +0100255 die(_("unable to write rerere record"));
Junio C Hamanoe2cb6a92015-06-28 16:28:00 -0700256
257 strbuf_release(&buf);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200258 }
259 if (commit_lock_file(&write_lock) != 0)
Thomas Gummerer2373b652018-08-05 18:20:30 +0100260 die(_("unable to write rerere record"));
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200261 return 0;
262}
263
Junio C Hamanoa96847c2015-06-30 22:33:19 -0700264/*
265 * "rerere" interacts with conflicted file contents using this I/O
266 * abstraction. It reads a conflicted contents from one place via
267 * "getline()" method, and optionally can write it out after
268 * normalizing the conflicted hunks to the "output". Subclasses of
269 * rerere_io embed this structure at the beginning of their own
270 * rerere_io object.
271 */
272struct rerere_io {
273 int (*getline)(struct strbuf *, struct rerere_io *);
274 FILE *output;
275 int wrerror;
276 /* some more stuff */
277};
278
Alex Riesen47d32af2008-12-05 01:35:48 +0100279static void ferr_write(const void *p, size_t count, FILE *fp, int *err)
280{
281 if (!count || *err)
282 return;
283 if (fwrite(p, count, 1, fp) != 1)
284 *err = errno;
285}
286
287static inline void ferr_puts(const char *s, FILE *fp, int *err)
288{
289 ferr_write(s, strlen(s), fp, err);
290}
291
Junio C Hamano27d6b082009-12-25 14:34:53 -0800292static void rerere_io_putstr(const char *str, struct rerere_io *io)
293{
294 if (io->output)
295 ferr_puts(str, io->output, &io->wrerror);
296}
297
298static void rerere_io_putmem(const char *mem, size_t sz, struct rerere_io *io)
299{
300 if (io->output)
301 ferr_write(mem, sz, io->output, &io->wrerror);
302}
303
Junio C Hamanoa96847c2015-06-30 22:33:19 -0700304/*
305 * Subclass of rerere_io that reads from an on-disk file
306 */
Junio C Hamano27d6b082009-12-25 14:34:53 -0800307struct rerere_io_file {
308 struct rerere_io io;
309 FILE *input;
310};
311
Junio C Hamanoa96847c2015-06-30 22:33:19 -0700312/*
313 * ... and its getline() method implementation
314 */
Junio C Hamano27d6b082009-12-25 14:34:53 -0800315static int rerere_file_getline(struct strbuf *sb, struct rerere_io *io_)
316{
317 struct rerere_io_file *io = (struct rerere_io_file *)io_;
318 return strbuf_getwholeline(sb, io->input, '\n');
319}
320
Junio C Hamano67711cd2015-06-29 15:05:24 -0700321/*
322 * Require the exact number of conflict marker letters, no more, no
323 * less, followed by SP or any whitespace
324 * (including LF).
325 */
326static int is_cmarker(char *buf, int marker_char, int marker_size)
Junio C Hamano191f24172010-01-16 23:06:45 -0800327{
Junio C Hamano67711cd2015-06-29 15:05:24 -0700328 int want_sp;
329
330 /*
331 * The beginning of our version and the end of their version
332 * always are labeled like "<<<<< ours" or ">>>>> theirs",
333 * hence we set want_sp for them. Note that the version from
334 * the common ancestor in diff3-style output is not always
335 * labelled (e.g. "||||| common" is often seen but "|||||"
336 * alone is also valid), so we do not set want_sp.
337 */
338 want_sp = (marker_char == '<') || (marker_char == '>');
339
Junio C Hamano191f24172010-01-16 23:06:45 -0800340 while (marker_size--)
341 if (*buf++ != marker_char)
342 return 0;
343 if (want_sp && *buf != ' ')
344 return 0;
345 return isspace(*buf);
346}
347
Thomas Gummerer5ebbdad2018-08-05 18:20:35 +0100348static void rerere_strbuf_putconflict(struct strbuf *buf, int ch, size_t size)
349{
350 strbuf_addchars(buf, ch, size);
351 strbuf_addch(buf, '\n');
352}
353
354static int handle_conflict(struct strbuf *out, struct rerere_io *io,
brian m. carlson0d7c4192018-10-15 00:02:02 +0000355 int marker_size, git_hash_ctx *ctx)
Thomas Gummererc0f16f82018-08-05 18:20:34 +0100356{
357 enum {
358 RR_SIDE_1 = 0, RR_SIDE_2, RR_ORIGINAL
359 } hunk = RR_SIDE_1;
360 struct strbuf one = STRBUF_INIT, two = STRBUF_INIT;
Thomas Gummerer4af32202018-08-05 18:20:36 +0100361 struct strbuf buf = STRBUF_INIT, conflict = STRBUF_INIT;
Thomas Gummererc0f16f82018-08-05 18:20:34 +0100362 int has_conflicts = -1;
363
364 while (!io->getline(&buf, io)) {
365 if (is_cmarker(buf.buf, '<', marker_size)) {
Thomas Gummerer4af32202018-08-05 18:20:36 +0100366 if (handle_conflict(&conflict, io, marker_size, NULL) < 0)
367 break;
368 if (hunk == RR_SIDE_1)
369 strbuf_addbuf(&one, &conflict);
370 else
371 strbuf_addbuf(&two, &conflict);
372 strbuf_release(&conflict);
Thomas Gummererc0f16f82018-08-05 18:20:34 +0100373 } else if (is_cmarker(buf.buf, '|', marker_size)) {
374 if (hunk != RR_SIDE_1)
375 break;
376 hunk = RR_ORIGINAL;
377 } else if (is_cmarker(buf.buf, '=', marker_size)) {
378 if (hunk != RR_SIDE_1 && hunk != RR_ORIGINAL)
379 break;
380 hunk = RR_SIDE_2;
381 } else if (is_cmarker(buf.buf, '>', marker_size)) {
382 if (hunk != RR_SIDE_2)
383 break;
384 if (strbuf_cmp(&one, &two) > 0)
385 strbuf_swap(&one, &two);
386 has_conflicts = 1;
Thomas Gummerer5ebbdad2018-08-05 18:20:35 +0100387 rerere_strbuf_putconflict(out, '<', marker_size);
388 strbuf_addbuf(out, &one);
389 rerere_strbuf_putconflict(out, '=', marker_size);
390 strbuf_addbuf(out, &two);
391 rerere_strbuf_putconflict(out, '>', marker_size);
Thomas Gummererc0f16f82018-08-05 18:20:34 +0100392 if (ctx) {
brian m. carlson0d7c4192018-10-15 00:02:02 +0000393 the_hash_algo->update_fn(ctx, one.buf ?
394 one.buf : "",
395 one.len + 1);
396 the_hash_algo->update_fn(ctx, two.buf ?
397 two.buf : "",
398 two.len + 1);
Thomas Gummererc0f16f82018-08-05 18:20:34 +0100399 }
400 break;
401 } else if (hunk == RR_SIDE_1)
402 strbuf_addbuf(&one, &buf);
403 else if (hunk == RR_ORIGINAL)
404 ; /* discard */
405 else if (hunk == RR_SIDE_2)
406 strbuf_addbuf(&two, &buf);
407 }
408 strbuf_release(&one);
409 strbuf_release(&two);
410 strbuf_release(&buf);
411
412 return has_conflicts;
413}
414
Junio C Hamanocc899ec2015-06-30 22:40:35 -0700415/*
416 * Read contents a file with conflicts, normalize the conflicts
417 * by (1) discarding the common ancestor version in diff3-style,
418 * (2) reordering our side and their side so that whichever sorts
419 * alphabetically earlier comes before the other one, while
420 * computing the "conflict ID", which is just an SHA-1 hash of
421 * one side of the conflict, NUL, the other side of the conflict,
422 * and NUL concatenated together.
423 *
Thomas Gummerer221444f2018-08-05 18:20:33 +0100424 * Return 1 if conflict hunks are found, 0 if there are no conflict
Elijah Newren15beaaa2019-11-05 17:07:23 +0000425 * hunks and -1 if an error occurred.
Junio C Hamanocc899ec2015-06-30 22:40:35 -0700426 */
brian m. carlson0d7c4192018-10-15 00:02:02 +0000427static int handle_path(unsigned char *hash, struct rerere_io *io, int marker_size)
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200428{
brian m. carlson0d7c4192018-10-15 00:02:02 +0000429 git_hash_ctx ctx;
Thomas Gummerer5ebbdad2018-08-05 18:20:35 +0100430 struct strbuf buf = STRBUF_INIT, out = STRBUF_INIT;
Thomas Gummererc0f16f82018-08-05 18:20:34 +0100431 int has_conflicts = 0;
brian m. carlson0d7c4192018-10-15 00:02:02 +0000432 if (hash)
433 the_hash_algo->init_fn(&ctx);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200434
Junio C Hamano27d6b082009-12-25 14:34:53 -0800435 while (!io->getline(&buf, io)) {
Junio C Hamano67711cd2015-06-29 15:05:24 -0700436 if (is_cmarker(buf.buf, '<', marker_size)) {
Thomas Gummerer5ebbdad2018-08-05 18:20:35 +0100437 has_conflicts = handle_conflict(&out, io, marker_size,
brian m. carlson0d7c4192018-10-15 00:02:02 +0000438 hash ? &ctx : NULL);
Thomas Gummererc0f16f82018-08-05 18:20:34 +0100439 if (has_conflicts < 0)
440 break;
Thomas Gummerer5ebbdad2018-08-05 18:20:35 +0100441 rerere_io_putmem(out.buf, out.len, io);
442 strbuf_reset(&out);
Thomas Gummererc0f16f82018-08-05 18:20:34 +0100443 } else
Junio C Hamano27d6b082009-12-25 14:34:53 -0800444 rerere_io_putstr(buf.buf, io);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200445 }
Junio C Hamanod58ee6d2009-12-25 13:55:29 -0800446 strbuf_release(&buf);
Thomas Gummerer5ebbdad2018-08-05 18:20:35 +0100447 strbuf_release(&out);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200448
brian m. carlson0d7c4192018-10-15 00:02:02 +0000449 if (hash)
450 the_hash_algo->final_fn(hash, &ctx);
Thomas Gummererc0f16f82018-08-05 18:20:34 +0100451
Thomas Gummerer221444f2018-08-05 18:20:33 +0100452 return has_conflicts;
Junio C Hamano27d6b082009-12-25 14:34:53 -0800453}
454
Junio C Hamanocc899ec2015-06-30 22:40:35 -0700455/*
456 * Scan the path for conflicts, do the "handle_path()" thing above, and
457 * return the number of conflict hunks found.
458 */
Junio C Hamanod829d492018-10-30 15:43:42 +0900459static int handle_file(struct index_state *istate,
460 const char *path, unsigned char *hash, const char *output)
Junio C Hamano27d6b082009-12-25 14:34:53 -0800461{
Thomas Gummerer221444f2018-08-05 18:20:33 +0100462 int has_conflicts = 0;
Junio C Hamano27d6b082009-12-25 14:34:53 -0800463 struct rerere_io_file io;
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200464 int marker_size = ll_merge_marker_size(istate, path);
Junio C Hamano27d6b082009-12-25 14:34:53 -0800465
466 memset(&io, 0, sizeof(io));
467 io.io.getline = rerere_file_getline;
468 io.input = fopen(path, "r");
469 io.io.wrerror = 0;
470 if (!io.input)
Thomas Gummerer2373b652018-08-05 18:20:30 +0100471 return error_errno(_("could not open '%s'"), path);
Junio C Hamano27d6b082009-12-25 14:34:53 -0800472
473 if (output) {
474 io.io.output = fopen(output, "w");
475 if (!io.io.output) {
Thomas Gummerer2373b652018-08-05 18:20:30 +0100476 error_errno(_("could not write '%s'"), output);
Junio C Hamano27d6b082009-12-25 14:34:53 -0800477 fclose(io.input);
Nguyễn Thái Ngọc Duyf7566f02017-05-09 17:11:33 +0700478 return -1;
Junio C Hamano27d6b082009-12-25 14:34:53 -0800479 }
480 }
481
brian m. carlson0d7c4192018-10-15 00:02:02 +0000482 has_conflicts = handle_path(hash, (struct rerere_io *)&io, marker_size);
Junio C Hamano27d6b082009-12-25 14:34:53 -0800483
484 fclose(io.input);
485 if (io.io.wrerror)
Thomas Gummerer2373b652018-08-05 18:20:30 +0100486 error(_("there were errors while writing '%s' (%s)"),
Junio C Hamano27d6b082009-12-25 14:34:53 -0800487 path, strerror(io.io.wrerror));
488 if (io.io.output && fclose(io.io.output))
Thomas Gummerer2373b652018-08-05 18:20:30 +0100489 io.io.wrerror = error_errno(_("failed to flush '%s'"), path);
Junio C Hamano27d6b082009-12-25 14:34:53 -0800490
Thomas Gummerer221444f2018-08-05 18:20:33 +0100491 if (has_conflicts < 0) {
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200492 if (output)
Alex Riesen691f1a22009-04-29 23:22:56 +0200493 unlink_or_warn(output);
Thomas Gummerer2373b652018-08-05 18:20:30 +0100494 return error(_("could not parse conflict hunks in '%s'"), path);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200495 }
Junio C Hamano27d6b082009-12-25 14:34:53 -0800496 if (io.io.wrerror)
Alex Riesen47d32af2008-12-05 01:35:48 +0100497 return -1;
Thomas Gummerer221444f2018-08-05 18:20:33 +0100498 return has_conflicts;
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200499}
500
Junio C Hamanoa96847c2015-06-30 22:33:19 -0700501/*
Junio C Hamano4b68c2a2015-06-30 22:36:35 -0700502 * Look at a cache entry at "i" and see if it is not conflicting,
503 * conflicting and we are willing to handle, or conflicting and
504 * we are unable to handle, and return the determination in *type.
505 * Return the cache index to be looked at next, by skipping the
506 * stages we have already looked at in this invocation of this
507 * function.
508 */
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200509static int check_one_conflict(struct index_state *istate, int i, int *type)
Martin von Zweigbergkac49f5c2011-02-16 05:47:44 -0500510{
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200511 const struct cache_entry *e = istate->cache[i];
Martin von Zweigbergkac49f5c2011-02-16 05:47:44 -0500512
513 if (!ce_stage(e)) {
514 *type = RESOLVED;
515 return i + 1;
516 }
517
518 *type = PUNTED;
Junio C Hamano11877b92018-10-19 13:34:02 +0900519 while (i < istate->cache_nr && ce_stage(istate->cache[i]) == 1)
Junio C Hamanofb70a062015-06-28 14:35:13 -0700520 i++;
Martin von Zweigbergkac49f5c2011-02-16 05:47:44 -0500521
522 /* Only handle regular files with both stages #2 and #3 */
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200523 if (i + 1 < istate->cache_nr) {
524 const struct cache_entry *e2 = istate->cache[i];
525 const struct cache_entry *e3 = istate->cache[i + 1];
Martin von Zweigbergkac49f5c2011-02-16 05:47:44 -0500526 if (ce_stage(e2) == 2 &&
527 ce_stage(e3) == 3 &&
528 ce_same_name(e, e3) &&
529 S_ISREG(e2->ce_mode) &&
530 S_ISREG(e3->ce_mode))
531 *type = THREE_STAGED;
532 }
533
534 /* Skip the entries with the same name */
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200535 while (i < istate->cache_nr && ce_same_name(e, istate->cache[i]))
Martin von Zweigbergkac49f5c2011-02-16 05:47:44 -0500536 i++;
537 return i;
538}
539
Junio C Hamano4b68c2a2015-06-30 22:36:35 -0700540/*
541 * Scan the index and find paths that have conflicts that rerere can
542 * handle, i.e. the ones that has both stages #2 and #3.
543 *
544 * NEEDSWORK: we do not record or replay a previous "resolve by
545 * deletion" for a delete-modify conflict, as that is inherently risky
546 * without knowing what modification is being discarded. The only
547 * safe case, i.e. both side doing the deletion and modification that
548 * are identical to the previous round, might want to be handled,
549 * though.
550 */
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200551static int find_conflict(struct repository *r, struct string_list *conflict)
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200552{
553 int i;
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200554
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +0700555 if (repo_read_index(r) < 0)
Thomas Gummerer2373b652018-08-05 18:20:30 +0100556 return error(_("index file corrupt"));
Martin von Zweigbergkac49f5c2011-02-16 05:47:44 -0500557
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200558 for (i = 0; i < r->index->cache_nr;) {
Martin von Zweigbergkac49f5c2011-02-16 05:47:44 -0500559 int conflict_type;
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200560 const struct cache_entry *e = r->index->cache[i];
561 i = check_one_conflict(r->index, i, &conflict_type);
Martin von Zweigbergkac49f5c2011-02-16 05:47:44 -0500562 if (conflict_type == THREE_STAGED)
563 string_list_insert(conflict, (const char *)e->name);
564 }
565 return 0;
566}
567
Junio C Hamano4b68c2a2015-06-30 22:36:35 -0700568/*
569 * The merge_rr list is meant to hold outstanding conflicted paths
570 * that rerere could handle. Abuse the list by adding other types of
571 * entries to allow the caller to show "rerere remaining".
572 *
573 * - Conflicted paths that rerere does not handle are added
574 * - Conflicted paths that have been resolved are marked as such
575 * by storing RERERE_RESOLVED to .util field (where conflict ID
576 * is expected to be stored).
577 *
578 * Do *not* write MERGE_RR file out after calling this function.
579 *
580 * NEEDSWORK: we may want to fix the caller that implements "rerere
581 * remaining" to do this without abusing merge_rr.
582 */
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200583int rerere_remaining(struct repository *r, struct string_list *merge_rr)
Martin von Zweigbergkac49f5c2011-02-16 05:47:44 -0500584{
585 int i;
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200586
Nguyễn Thái Ngọc Duy55e6b352018-11-10 06:49:09 +0100587 if (setup_rerere(r, merge_rr, RERERE_READONLY))
Jeff King9dd330e2015-09-01 18:14:09 -0400588 return 0;
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +0700589 if (repo_read_index(r) < 0)
Thomas Gummerer2373b652018-08-05 18:20:30 +0100590 return error(_("index file corrupt"));
Martin von Zweigbergkac49f5c2011-02-16 05:47:44 -0500591
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200592 for (i = 0; i < r->index->cache_nr;) {
Martin von Zweigbergkac49f5c2011-02-16 05:47:44 -0500593 int conflict_type;
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200594 const struct cache_entry *e = r->index->cache[i];
595 i = check_one_conflict(r->index, i, &conflict_type);
Martin von Zweigbergkac49f5c2011-02-16 05:47:44 -0500596 if (conflict_type == PUNTED)
597 string_list_insert(merge_rr, (const char *)e->name);
598 else if (conflict_type == RESOLVED) {
599 struct string_list_item *it;
600 it = string_list_lookup(merge_rr, (const char *)e->name);
Junio C Hamanoafe8a902022-05-02 09:50:37 -0700601 if (it) {
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700602 free_rerere_id(it);
Martin von Zweigbergkac49f5c2011-02-16 05:47:44 -0500603 it->util = RERERE_RESOLVED;
604 }
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200605 }
606 }
607 return 0;
608}
609
Junio C Hamanocc899ec2015-06-30 22:40:35 -0700610/*
Junio C Hamano0ce02b32016-03-11 14:53:05 -0800611 * Try using the given conflict resolution "ID" to see
612 * if that recorded conflict resolves cleanly what we
613 * got in the "cur".
614 */
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200615static int try_merge(struct index_state *istate,
616 const struct rerere_id *id, const char *path,
Junio C Hamano0ce02b32016-03-11 14:53:05 -0800617 mmfile_t *cur, mmbuffer_t *result)
618{
Elijah Newren35f69672022-02-02 02:37:30 +0000619 enum ll_merge_result ret;
Junio C Hamano0ce02b32016-03-11 14:53:05 -0800620 mmfile_t base = {NULL, 0}, other = {NULL, 0};
621
622 if (read_mmfile(&base, rerere_path(id, "preimage")) ||
Elijah Newren35f69672022-02-02 02:37:30 +0000623 read_mmfile(&other, rerere_path(id, "postimage"))) {
624 ret = LL_MERGE_CONFLICT;
625 } else {
Junio C Hamano0ce02b32016-03-11 14:53:05 -0800626 /*
627 * A three-way merge. Note that this honors user-customizable
628 * low-level merge driver settings.
629 */
Nguyễn Thái Ngọc Duy32eaa462018-09-21 17:57:27 +0200630 ret = ll_merge(result, path, &base, NULL, cur, "", &other, "",
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200631 istate, NULL);
Elijah Newren35f69672022-02-02 02:37:30 +0000632 }
Junio C Hamano0ce02b32016-03-11 14:53:05 -0800633
634 free(base.ptr);
635 free(other.ptr);
636
637 return ret;
638}
639
640/*
Junio C Hamano18bb9932015-07-06 14:45:55 -0700641 * Find the conflict identified by "id"; the change between its
Junio C Hamanocc899ec2015-06-30 22:40:35 -0700642 * "preimage" (i.e. a previous contents with conflict markers) and its
643 * "postimage" (i.e. the corresponding contents with conflicts
644 * resolved) may apply cleanly to the contents stored in "path", i.e.
645 * the conflict this time around.
646 *
647 * Returns 0 for successful replay of recorded resolution, or non-zero
648 * for failure.
649 */
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200650static int merge(struct index_state *istate, const struct rerere_id *id, const char *path)
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200651{
Junio C Hamano15ed07d2015-07-06 15:32:53 -0700652 FILE *f;
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200653 int ret;
Junio C Hamano0ce02b32016-03-11 14:53:05 -0800654 mmfile_t cur = {NULL, 0};
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200655 mmbuffer_t result = {NULL, 0};
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200656
Junio C Hamanocc899ec2015-06-30 22:40:35 -0700657 /*
658 * Normalize the conflicts in path and write it out to
659 * "thisimage" temporary file.
660 */
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200661 if ((handle_file(istate, path, NULL, rerere_path(id, "thisimage")) < 0) ||
Junio C Hamano0ce02b32016-03-11 14:53:05 -0800662 read_mmfile(&cur, rerere_path(id, "thisimage"))) {
Bert Wesarg689b8c22010-02-23 21:11:53 +0100663 ret = 1;
664 goto out;
665 }
SZEDER Gábor7d7ff152010-07-13 01:42:04 +0200666
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200667 ret = try_merge(istate, id, path, &cur, &result);
Junio C Hamano15ed07d2015-07-06 15:32:53 -0700668 if (ret)
669 goto out;
SZEDER Gábor7d7ff152010-07-13 01:42:04 +0200670
Junio C Hamano15ed07d2015-07-06 15:32:53 -0700671 /*
672 * A successful replay of recorded resolution.
673 * Mark that "postimage" was used to help gc.
674 */
675 if (utime(rerere_path(id, "postimage"), NULL) < 0)
Thomas Gummerer2373b652018-08-05 18:20:30 +0100676 warning_errno(_("failed utime() on '%s'"),
Nguyễn Thái Ngọc Duy033e0112016-05-08 16:47:52 +0700677 rerere_path(id, "postimage"));
Junio C Hamanocc899ec2015-06-30 22:40:35 -0700678
Junio C Hamano15ed07d2015-07-06 15:32:53 -0700679 /* Update "path" with the resolution */
680 f = fopen(path, "w");
681 if (!f)
Thomas Gummerer2373b652018-08-05 18:20:30 +0100682 return error_errno(_("could not open '%s'"), path);
Junio C Hamano15ed07d2015-07-06 15:32:53 -0700683 if (fwrite(result.ptr, result.size, 1, f) != 1)
Thomas Gummerer2373b652018-08-05 18:20:30 +0100684 error_errno(_("could not write '%s'"), path);
Junio C Hamano15ed07d2015-07-06 15:32:53 -0700685 if (fclose(f))
Thomas Gummerer2373b652018-08-05 18:20:30 +0100686 return error_errno(_("writing '%s' failed"), path);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200687
Bert Wesarg689b8c22010-02-23 21:11:53 +0100688out:
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200689 free(cur.ptr);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200690 free(result.ptr);
691
692 return ret;
693}
694
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200695static void update_paths(struct repository *r, struct string_list *update)
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200696{
Martin Ågren0fa5a2e2018-05-09 22:55:39 +0200697 struct lock_file index_lock = LOCK_INIT;
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200698 int i;
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200699
Nguyễn Thái Ngọc Duy3a95f312019-01-12 09:13:24 +0700700 repo_hold_locked_index(r, &index_lock, LOCK_DIE_ON_ERROR);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200701
702 for (i = 0; i < update->nr; i++) {
Johannes Schindelinc455c872008-07-21 19:03:49 +0100703 struct string_list_item *item = &update->items[i];
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200704 if (add_file_to_index(r->index, item->string, 0))
Jonathan Nieder89ea9032014-12-02 20:20:49 -0800705 exit(128);
Thomas Gummerer2373b652018-08-05 18:20:30 +0100706 fprintf_ln(stderr, _("Staged '%s' using previous resolution."),
Junio C Hamanoa14c7ab2015-06-28 21:13:24 -0700707 item->string);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200708 }
709
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200710 if (write_locked_index(r->index, &index_lock,
Martin Ågren61000812018-03-01 21:40:20 +0100711 COMMIT_LOCK | SKIP_IF_UNCHANGED))
Thomas Gummerer2373b652018-08-05 18:20:30 +0100712 die(_("unable to write new index file"));
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200713}
714
Junio C Hamano629716d2015-07-30 15:49:18 -0700715static void remove_variant(struct rerere_id *id)
716{
717 unlink_or_warn(rerere_path(id, "postimage"));
718 unlink_or_warn(rerere_path(id, "preimage"));
719 id->collection->status[id->variant] = 0;
720}
721
Junio C Hamano8e7768b2015-06-30 19:36:24 -0700722/*
723 * The path indicated by rr_item may still have conflict for which we
724 * have a recorded resolution, in which case replay it and optionally
725 * update it. Or it may have been resolved by the user and we may
726 * only have the preimage for that conflict, in which case the result
727 * needs to be recorded as a resolution in a postimage file.
728 */
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200729static void do_rerere_one_path(struct index_state *istate,
730 struct string_list_item *rr_item,
Junio C Hamano8e7768b2015-06-30 19:36:24 -0700731 struct string_list *update)
732{
733 const char *path = rr_item->string;
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700734 struct rerere_id *id = rr_item->util;
Junio C Hamano629716d2015-07-30 15:49:18 -0700735 struct rerere_dir *rr_dir = id->collection;
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700736 int variant;
Junio C Hamano8e7768b2015-06-30 19:36:24 -0700737
Junio C Hamanoa13d1372015-07-23 14:23:24 -0700738 variant = id->variant;
Junio C Hamano8e7768b2015-06-30 19:36:24 -0700739
Junio C Hamano629716d2015-07-30 15:49:18 -0700740 /* Has the user resolved it already? */
741 if (variant >= 0) {
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200742 if (!handle_file(istate, path, NULL, NULL)) {
Junio C Hamano629716d2015-07-30 15:49:18 -0700743 copy_file(rerere_path(id, "postimage"), path, 0666);
744 id->collection->status[variant] |= RR_HAS_POSTIMAGE;
Thomas Gummerer2373b652018-08-05 18:20:30 +0100745 fprintf_ln(stderr, _("Recorded resolution for '%s'."), path);
Junio C Hamano629716d2015-07-30 15:49:18 -0700746 free_rerere_id(rr_item);
747 rr_item->util = NULL;
748 return;
Junio C Hamanoc0a54232015-07-20 15:19:44 -0700749 }
Junio C Hamano629716d2015-07-30 15:49:18 -0700750 /*
751 * There may be other variants that can cleanly
752 * replay. Try them and update the variant number for
753 * this one.
754 */
755 }
756
757 /* Does any existing resolution apply cleanly? */
758 for (variant = 0; variant < rr_dir->status_nr; variant++) {
759 const int both = RR_HAS_PREIMAGE | RR_HAS_POSTIMAGE;
760 struct rerere_id vid = *id;
761
762 if ((rr_dir->status[variant] & both) != both)
763 continue;
764
765 vid.variant = variant;
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200766 if (merge(istate, &vid, path))
Junio C Hamano629716d2015-07-30 15:49:18 -0700767 continue; /* failed to replay */
768
769 /*
770 * If there already is a different variant that applies
771 * cleanly, there is no point maintaining our own variant.
772 */
773 if (0 <= id->variant && id->variant != variant)
774 remove_variant(id);
Junio C Hamano8e7768b2015-06-30 19:36:24 -0700775
776 if (rerere_autoupdate)
777 string_list_insert(update, path);
778 else
Thomas Gummerer2373b652018-08-05 18:20:30 +0100779 fprintf_ln(stderr,
780 _("Resolved '%s' using previous resolution."),
781 path);
Junio C Hamano629716d2015-07-30 15:49:18 -0700782 free_rerere_id(rr_item);
783 rr_item->util = NULL;
Junio C Hamano925d73c2015-07-06 14:18:09 -0700784 return;
Junio C Hamano8e7768b2015-06-30 19:36:24 -0700785 }
Junio C Hamano629716d2015-07-30 15:49:18 -0700786
787 /* None of the existing one applies; we need a new variant */
788 assign_variant(id);
789
790 variant = id->variant;
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200791 handle_file(istate, path, NULL, rerere_path(id, "preimage"));
Junio C Hamano629716d2015-07-30 15:49:18 -0700792 if (id->collection->status[variant] & RR_HAS_POSTIMAGE) {
793 const char *path = rerere_path(id, "postimage");
794 if (unlink(path))
Thomas Gummerer2373b652018-08-05 18:20:30 +0100795 die_errno(_("cannot unlink stray '%s'"), path);
Junio C Hamano629716d2015-07-30 15:49:18 -0700796 id->collection->status[variant] &= ~RR_HAS_POSTIMAGE;
797 }
798 id->collection->status[variant] |= RR_HAS_PREIMAGE;
Thomas Gummerer2373b652018-08-05 18:20:30 +0100799 fprintf_ln(stderr, _("Recorded preimage for '%s'"), path);
Junio C Hamano8e7768b2015-06-30 19:36:24 -0700800}
801
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200802static int do_plain_rerere(struct repository *r,
803 struct string_list *rr, int fd)
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200804{
Thiago Farina183113a2010-07-04 16:46:19 -0300805 struct string_list conflict = STRING_LIST_INIT_DUP;
806 struct string_list update = STRING_LIST_INIT_DUP;
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200807 int i;
808
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200809 find_conflict(r, &conflict);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200810
811 /*
Junio C Hamanocc899ec2015-06-30 22:40:35 -0700812 * MERGE_RR records paths with conflicts immediately after
813 * merge failed. Some of the conflicted paths might have been
814 * hand resolved in the working tree since then, but the
815 * initial run would catch all and register their preimages.
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200816 */
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200817 for (i = 0; i < conflict.nr; i++) {
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700818 struct rerere_id *id;
brian m. carlson0d7c4192018-10-15 00:02:02 +0000819 unsigned char hash[GIT_MAX_RAWSZ];
Johannes Schindelinc455c872008-07-21 19:03:49 +0100820 const char *path = conflict.items[i].string;
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200821 int ret;
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200822
Junio C Hamanoc7a25d32015-07-04 17:17:38 -0700823 /*
824 * Ask handle_file() to scan and assign a
825 * conflict ID. No need to write anything out
826 * yet.
827 */
Junio C Hamanod829d492018-10-30 15:43:42 +0900828 ret = handle_file(r->index, path, hash, NULL);
Thomas Gummererbd7dfa52018-08-05 18:20:37 +0100829 if (ret != 0 && string_list_has_string(rr, path)) {
Thomas Gummerer93406a22018-08-05 18:20:32 +0100830 remove_variant(string_list_lookup(rr, path)->util);
831 string_list_remove(rr, path, 1);
832 }
Junio C Hamanoc7a25d32015-07-04 17:17:38 -0700833 if (ret < 1)
834 continue;
Junio C Hamano1d51ece2015-07-04 17:38:34 -0700835
brian m. carlson0d7c4192018-10-15 00:02:02 +0000836 id = new_rerere_id(hash);
Junio C Hamano18bb9932015-07-06 14:45:55 -0700837 string_list_insert(rr, path)->util = id;
Junio C Hamanocc899ec2015-06-30 22:40:35 -0700838
Junio C Hamanoc0a54232015-07-20 15:19:44 -0700839 /* Ensure that the directory exists. */
840 mkdir_in_gitdir(rerere_path(id, NULL));
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200841 }
842
Junio C Hamano8e7768b2015-06-30 19:36:24 -0700843 for (i = 0; i < rr->nr; i++)
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200844 do_rerere_one_path(r->index, &rr->items[i], &update);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200845
846 if (update.nr)
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200847 update_paths(r, &update);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200848
849 return write_rr(rr, fd);
850}
851
Tanay Abhra633e5ad2014-08-07 09:21:21 -0700852static void git_rerere_config(void)
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200853{
Tanay Abhra633e5ad2014-08-07 09:21:21 -0700854 git_config_get_bool("rerere.enabled", &rerere_enabled);
855 git_config_get_bool("rerere.autoupdate", &rerere_autoupdate);
856 git_config(git_default_config, NULL);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200857}
858
Jeff Kingf9327292015-08-10 05:38:57 -0400859static GIT_PATH_FUNC(git_path_rr_cache, "rr-cache")
860
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200861static int is_rerere_enabled(void)
862{
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200863 int rr_cache_exists;
864
865 if (!rerere_enabled)
866 return 0;
867
Jeff Kingf9327292015-08-10 05:38:57 -0400868 rr_cache_exists = is_directory(git_path_rr_cache());
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200869 if (rerere_enabled < 0)
870 return rr_cache_exists;
871
Jeff Kingf9327292015-08-10 05:38:57 -0400872 if (!rr_cache_exists && mkdir_in_gitdir(git_path_rr_cache()))
Thomas Gummerer2373b652018-08-05 18:20:30 +0100873 die(_("could not create directory '%s'"), git_path_rr_cache());
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200874 return 1;
875}
876
Nguyễn Thái Ngọc Duy55e6b352018-11-10 06:49:09 +0100877int setup_rerere(struct repository *r, struct string_list *merge_rr, int flags)
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200878{
879 int fd;
880
Tanay Abhra633e5ad2014-08-07 09:21:21 -0700881 git_rerere_config();
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200882 if (!is_rerere_enabled())
883 return -1;
884
Junio C Hamanocb6020b2009-12-04 00:20:48 -0800885 if (flags & (RERERE_AUTOUPDATE|RERERE_NOAUTOUPDATE))
886 rerere_autoupdate = !!(flags & RERERE_AUTOUPDATE);
Jeff King9dd330e2015-09-01 18:14:09 -0400887 if (flags & RERERE_READONLY)
888 fd = 0;
889 else
Stefan Beller102de882018-05-17 15:51:51 -0700890 fd = hold_lock_file_for_update(&write_lock,
Nguyễn Thái Ngọc Duy55e6b352018-11-10 06:49:09 +0100891 git_path_merge_rr(r),
Jeff King9dd330e2015-09-01 18:14:09 -0400892 LOCK_DIE_ON_ERROR);
Nguyễn Thái Ngọc Duy55e6b352018-11-10 06:49:09 +0100893 read_rr(r, merge_rr);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200894 return fd;
895}
896
Junio C Hamanocc899ec2015-06-30 22:40:35 -0700897/*
898 * The main entry point that is called internally from codepaths that
899 * perform mergy operations, possibly leaving conflicted index entries
900 * and working tree files.
901 */
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200902int repo_rerere(struct repository *r, int flags)
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200903{
Thiago Farina183113a2010-07-04 16:46:19 -0300904 struct string_list merge_rr = STRING_LIST_INIT_DUP;
Junio C Hamano1869bbe2015-07-16 14:50:05 -0700905 int fd, status;
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200906
Nguyễn Thái Ngọc Duy55e6b352018-11-10 06:49:09 +0100907 fd = setup_rerere(r, &merge_rr, flags);
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200908 if (fd < 0)
909 return 0;
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200910 status = do_plain_rerere(r, &merge_rr, fd);
Junio C Hamano1869bbe2015-07-16 14:50:05 -0700911 free_rerere_dirs();
912 return status;
Stephan Beyer5b2fd952008-07-09 14:58:57 +0200913}
Junio C Hamanodea45622009-12-25 15:51:32 -0800914
Junio C Hamano3d730ed2016-03-14 15:10:39 -0700915/*
916 * Subclass of rerere_io that reads from an in-core buffer that is a
917 * strbuf
918 */
919struct rerere_io_mem {
920 struct rerere_io io;
921 struct strbuf input;
922};
923
924/*
925 * ... and its getline() method implementation
926 */
927static int rerere_mem_getline(struct strbuf *sb, struct rerere_io *io_)
928{
929 struct rerere_io_mem *io = (struct rerere_io_mem *)io_;
930 char *ep;
931 size_t len;
932
933 strbuf_release(sb);
934 if (!io->input.len)
935 return -1;
936 ep = memchr(io->input.buf, '\n', io->input.len);
937 if (!ep)
938 ep = io->input.buf + io->input.len;
939 else if (*ep == '\n')
940 ep++;
941 len = ep - io->input.buf;
942 strbuf_add(sb, io->input.buf, len);
943 strbuf_remove(&io->input, 0, len);
944 return 0;
945}
946
Junio C Hamanod829d492018-10-30 15:43:42 +0900947static int handle_cache(struct index_state *istate,
948 const char *path, unsigned char *hash, const char *output)
Junio C Hamano3d730ed2016-03-14 15:10:39 -0700949{
950 mmfile_t mmfile[3] = {{NULL}};
951 mmbuffer_t result = {NULL, 0};
952 const struct cache_entry *ce;
Thomas Gummerer221444f2018-08-05 18:20:33 +0100953 int pos, len, i, has_conflicts;
Junio C Hamano3d730ed2016-03-14 15:10:39 -0700954 struct rerere_io_mem io;
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200955 int marker_size = ll_merge_marker_size(istate, path);
Junio C Hamano3d730ed2016-03-14 15:10:39 -0700956
957 /*
958 * Reproduce the conflicted merge in-core
959 */
960 len = strlen(path);
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200961 pos = index_name_pos(istate, path, len);
Junio C Hamano3d730ed2016-03-14 15:10:39 -0700962 if (0 <= pos)
963 return -1;
964 pos = -pos - 1;
965
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200966 while (pos < istate->cache_nr) {
Junio C Hamano3d730ed2016-03-14 15:10:39 -0700967 enum object_type type;
968 unsigned long size;
969
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200970 ce = istate->cache[pos++];
Junio C Hamano3d730ed2016-03-14 15:10:39 -0700971 if (ce_namelen(ce) != len || memcmp(ce->name, path, len))
972 break;
973 i = ce_stage(ce) - 1;
974 if (!mmfile[i].ptr) {
Ævar Arnfjörð Bjarmasonbc726bd2023-03-28 15:58:50 +0200975 mmfile[i].ptr = repo_read_object_file(the_repository,
976 &ce->oid, &type,
977 &size);
Junio C Hamano3d730ed2016-03-14 15:10:39 -0700978 mmfile[i].size = size;
979 }
980 }
981 for (i = 0; i < 3; i++)
982 if (!mmfile[i].ptr && !mmfile[i].size)
983 mmfile[i].ptr = xstrdup("");
984
985 /*
986 * NEEDSWORK: handle conflicts from merges with
987 * merge.renormalize set, too?
988 */
989 ll_merge(&result, path, &mmfile[0], NULL,
990 &mmfile[1], "ours",
Nguyễn Thái Ngọc Duy32eaa462018-09-21 17:57:27 +0200991 &mmfile[2], "theirs",
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +0200992 istate, NULL);
Junio C Hamano3d730ed2016-03-14 15:10:39 -0700993 for (i = 0; i < 3; i++)
994 free(mmfile[i].ptr);
995
996 memset(&io, 0, sizeof(io));
997 io.io.getline = rerere_mem_getline;
998 if (output)
999 io.io.output = fopen(output, "w");
1000 else
1001 io.io.output = NULL;
1002 strbuf_init(&io.input, 0);
1003 strbuf_attach(&io.input, result.ptr, result.size, result.size);
1004
1005 /*
1006 * Grab the conflict ID and optionally write the original
1007 * contents with conflict markers out.
1008 */
brian m. carlson0d7c4192018-10-15 00:02:02 +00001009 has_conflicts = handle_path(hash, (struct rerere_io *)&io, marker_size);
Junio C Hamano3d730ed2016-03-14 15:10:39 -07001010 strbuf_release(&io.input);
1011 if (io.io.output)
1012 fclose(io.io.output);
Thomas Gummerer221444f2018-08-05 18:20:33 +01001013 return has_conflicts;
Stephan Beyer5b2fd952008-07-09 14:58:57 +02001014}
Junio C Hamanodea45622009-12-25 15:51:32 -08001015
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +02001016static int rerere_forget_one_path(struct index_state *istate,
1017 const char *path,
1018 struct string_list *rr)
Junio C Hamanodea45622009-12-25 15:51:32 -08001019{
1020 const char *filename;
Junio C Hamano1d51ece2015-07-04 17:38:34 -07001021 struct rerere_id *id;
brian m. carlson0d7c4192018-10-15 00:02:02 +00001022 unsigned char hash[GIT_MAX_RAWSZ];
Junio C Hamanodea45622009-12-25 15:51:32 -08001023 int ret;
Junio C Hamano8d9b5a42015-06-30 13:03:36 -07001024 struct string_list_item *item;
Junio C Hamanodea45622009-12-25 15:51:32 -08001025
Junio C Hamano963ec002015-06-30 22:42:34 -07001026 /*
1027 * Recreate the original conflict from the stages in the
1028 * index and compute the conflict ID
1029 */
Junio C Hamanod829d492018-10-30 15:43:42 +09001030 ret = handle_cache(istate, path, hash, NULL);
Junio C Hamanodea45622009-12-25 15:51:32 -08001031 if (ret < 1)
Thomas Gummerer2373b652018-08-05 18:20:30 +01001032 return error(_("could not parse conflict hunks in '%s'"), path);
Junio C Hamano963ec002015-06-30 22:42:34 -07001033
1034 /* Nuke the recorded resolution for the conflict */
brian m. carlson0d7c4192018-10-15 00:02:02 +00001035 id = new_rerere_id(hash);
Junio C Hamano890fca82016-03-28 14:48:13 -07001036
1037 for (id->variant = 0;
1038 id->variant < id->collection->status_nr;
1039 id->variant++) {
1040 mmfile_t cur = { NULL, 0 };
1041 mmbuffer_t result = {NULL, 0};
1042 int cleanly_resolved;
1043
1044 if (!has_rerere_resolution(id))
1045 continue;
1046
Junio C Hamanod829d492018-10-30 15:43:42 +09001047 handle_cache(istate, path, hash, rerere_path(id, "thisimage"));
Junio C Hamano890fca82016-03-28 14:48:13 -07001048 if (read_mmfile(&cur, rerere_path(id, "thisimage"))) {
1049 free(cur.ptr);
Thomas Gummerer2373b652018-08-05 18:20:30 +01001050 error(_("failed to update conflicted state in '%s'"), path);
Junio C Hamano8f449612016-05-11 16:19:17 -07001051 goto fail_exit;
Junio C Hamano890fca82016-03-28 14:48:13 -07001052 }
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +02001053 cleanly_resolved = !try_merge(istate, id, path, &cur, &result);
Junio C Hamano890fca82016-03-28 14:48:13 -07001054 free(result.ptr);
1055 free(cur.ptr);
1056 if (cleanly_resolved)
1057 break;
1058 }
1059
Junio C Hamano8f449612016-05-11 16:19:17 -07001060 if (id->collection->status_nr <= id->variant) {
Thomas Gummerer2373b652018-08-05 18:20:30 +01001061 error(_("no remembered resolution for '%s'"), path);
Junio C Hamano8f449612016-05-11 16:19:17 -07001062 goto fail_exit;
1063 }
Junio C Hamano890fca82016-03-28 14:48:13 -07001064
Junio C Hamano18bb9932015-07-06 14:45:55 -07001065 filename = rerere_path(id, "postimage");
Junio C Hamano8f449612016-05-11 16:19:17 -07001066 if (unlink(filename)) {
1067 if (errno == ENOENT)
Thomas Gummerer2373b652018-08-05 18:20:30 +01001068 error(_("no remembered resolution for '%s'"), path);
Junio C Hamano8f449612016-05-11 16:19:17 -07001069 else
Thomas Gummerer2373b652018-08-05 18:20:30 +01001070 error_errno(_("cannot unlink '%s'"), filename);
Junio C Hamano8f449612016-05-11 16:19:17 -07001071 goto fail_exit;
Junio C Hamanod9d501b2016-05-19 12:51:22 -07001072 }
Junio C Hamanodea45622009-12-25 15:51:32 -08001073
Junio C Hamano963ec002015-06-30 22:42:34 -07001074 /*
1075 * Update the preimage so that the user can resolve the
1076 * conflict in the working tree, run us again to record
1077 * the postimage.
1078 */
Junio C Hamanod829d492018-10-30 15:43:42 +09001079 handle_cache(istate, path, hash, rerere_path(id, "preimage"));
Thomas Gummerer2373b652018-08-05 18:20:30 +01001080 fprintf_ln(stderr, _("Updated preimage for '%s'"), path);
Junio C Hamanodea45622009-12-25 15:51:32 -08001081
Junio C Hamano963ec002015-06-30 22:42:34 -07001082 /*
1083 * And remember that we can record resolution for this
1084 * conflict when the user is done.
1085 */
Junio C Hamano8d9b5a42015-06-30 13:03:36 -07001086 item = string_list_insert(rr, path);
Junio C Hamano1d51ece2015-07-04 17:38:34 -07001087 free_rerere_id(item);
Junio C Hamano18bb9932015-07-06 14:45:55 -07001088 item->util = id;
Thomas Gummerer2373b652018-08-05 18:20:30 +01001089 fprintf(stderr, _("Forgot resolution for '%s'\n"), path);
Junio C Hamanodea45622009-12-25 15:51:32 -08001090 return 0;
Junio C Hamano8f449612016-05-11 16:19:17 -07001091
1092fail_exit:
1093 free(id);
1094 return -1;
Junio C Hamanodea45622009-12-25 15:51:32 -08001095}
1096
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +02001097int rerere_forget(struct repository *r, struct pathspec *pathspec)
Junio C Hamanodea45622009-12-25 15:51:32 -08001098{
1099 int i, fd;
Thiago Farina183113a2010-07-04 16:46:19 -03001100 struct string_list conflict = STRING_LIST_INIT_DUP;
1101 struct string_list merge_rr = STRING_LIST_INIT_DUP;
Junio C Hamanodea45622009-12-25 15:51:32 -08001102
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 09:13:26 +07001103 if (repo_read_index(r) < 0)
Thomas Gummerer2373b652018-08-05 18:20:30 +01001104 return error(_("index file corrupt"));
Junio C Hamanodea45622009-12-25 15:51:32 -08001105
Nguyễn Thái Ngọc Duy55e6b352018-11-10 06:49:09 +01001106 fd = setup_rerere(r, &merge_rr, RERERE_NOAUTOUPDATE);
Jeff King05445742015-05-14 15:20:52 -04001107 if (fd < 0)
1108 return 0;
Junio C Hamanodea45622009-12-25 15:51:32 -08001109
Junio C Hamano963ec002015-06-30 22:42:34 -07001110 /*
1111 * The paths may have been resolved (incorrectly);
1112 * recover the original conflicted state and then
1113 * find the conflicted paths.
1114 */
Junio C Hamano5bdedac2023-07-31 15:44:09 -07001115 unmerge_index(r->index, pathspec, 0);
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +02001116 find_conflict(r, &conflict);
Junio C Hamanodea45622009-12-25 15:51:32 -08001117 for (i = 0; i < conflict.nr; i++) {
1118 struct string_list_item *it = &conflict.items[i];
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +02001119 if (!match_pathspec(r->index, pathspec, it->string,
Nguyễn Thái Ngọc Duyae8d0822014-01-24 20:40:33 +07001120 strlen(it->string), 0, NULL, 0))
Junio C Hamanodea45622009-12-25 15:51:32 -08001121 continue;
Nguyễn Thái Ngọc Duy35843b12018-09-21 17:57:32 +02001122 rerere_forget_one_path(r->index, it->string, &merge_rr);
Junio C Hamanodea45622009-12-25 15:51:32 -08001123 }
1124 return write_rr(&merge_rr, fd);
1125}
Junio C Hamano0f891e72011-05-08 12:55:34 -07001126
Junio C Hamanoe828de82015-06-30 22:43:37 -07001127/*
1128 * Garbage collection support
1129 */
Junio C Hamano1d51ece2015-07-04 17:38:34 -07001130
Junio C Hamano5ea82272017-08-19 11:16:01 -07001131static timestamp_t rerere_created_at(struct rerere_id *id)
Junio C Hamano0f891e72011-05-08 12:55:34 -07001132{
1133 struct stat st;
Junio C Hamano1d51ece2015-07-04 17:38:34 -07001134
Junio C Hamano18bb9932015-07-06 14:45:55 -07001135 return stat(rerere_path(id, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
Junio C Hamano0f891e72011-05-08 12:55:34 -07001136}
1137
Junio C Hamano5ea82272017-08-19 11:16:01 -07001138static timestamp_t rerere_last_used_at(struct rerere_id *id)
Junio C Hamano0f891e72011-05-08 12:55:34 -07001139{
Junio C Hamano0f891e72011-05-08 12:55:34 -07001140 struct stat st;
Junio C Hamano1d51ece2015-07-04 17:38:34 -07001141
Junio C Hamano18bb9932015-07-06 14:45:55 -07001142 return stat(rerere_path(id, "postimage"), &st) ? (time_t) 0 : st.st_mtime;
Junio C Hamano0f891e72011-05-08 12:55:34 -07001143}
1144
Junio C Hamanoe828de82015-06-30 22:43:37 -07001145/*
1146 * Remove the recorded resolution for a given conflict ID
1147 */
Junio C Hamano1d51ece2015-07-04 17:38:34 -07001148static void unlink_rr_item(struct rerere_id *id)
Junio C Hamano0f891e72011-05-08 12:55:34 -07001149{
Junio C Hamano1be1e852016-03-08 12:11:00 -08001150 unlink_or_warn(rerere_path(id, "thisimage"));
1151 remove_variant(id);
1152 id->collection->status[id->variant] = 0;
1153}
1154
Junio C Hamano5ea82272017-08-19 11:16:01 -07001155static void prune_one(struct rerere_id *id,
1156 timestamp_t cutoff_resolve, timestamp_t cutoff_noresolve)
Junio C Hamano1be1e852016-03-08 12:11:00 -08001157{
Junio C Hamano5ea82272017-08-19 11:16:01 -07001158 timestamp_t then;
1159 timestamp_t cutoff;
Junio C Hamano1be1e852016-03-08 12:11:00 -08001160
1161 then = rerere_last_used_at(id);
1162 if (then)
1163 cutoff = cutoff_resolve;
1164 else {
1165 then = rerere_created_at(id);
1166 if (!then)
1167 return;
1168 cutoff = cutoff_noresolve;
1169 }
Junio C Hamano5ea82272017-08-19 11:16:01 -07001170 if (then < cutoff)
Junio C Hamano1be1e852016-03-08 12:11:00 -08001171 unlink_rr_item(id);
Junio C Hamano0f891e72011-05-08 12:55:34 -07001172}
1173
Jeff King2bc1a872021-01-28 01:14:11 -05001174/* Does the basename in "path" look plausibly like an rr-cache entry? */
1175static int is_rr_cache_dirname(const char *path)
1176{
Jeff King098c1732021-01-28 01:16:50 -05001177 struct object_id oid;
1178 const char *end;
1179 return !parse_oid_hex(path, &oid, &end) && !*end;
Jeff King2bc1a872021-01-28 01:14:11 -05001180}
1181
Nguyễn Thái Ngọc Duy55e6b352018-11-10 06:49:09 +01001182void rerere_gc(struct repository *r, struct string_list *rr)
Junio C Hamano0f891e72011-05-08 12:55:34 -07001183{
1184 struct string_list to_remove = STRING_LIST_INIT_DUP;
1185 DIR *dir;
1186 struct dirent *e;
Junio C Hamano1be1e852016-03-08 12:11:00 -08001187 int i;
Junio C Hamano5ea82272017-08-19 11:16:01 -07001188 timestamp_t now = time(NULL);
1189 timestamp_t cutoff_noresolve = now - 15 * 86400;
1190 timestamp_t cutoff_resolve = now - 60 * 86400;
Junio C Hamano0f891e72011-05-08 12:55:34 -07001191
Nguyễn Thái Ngọc Duy55e6b352018-11-10 06:49:09 +01001192 if (setup_rerere(r, rr, 0) < 0)
Jeff King9dd330e2015-09-01 18:14:09 -04001193 return;
1194
Junio C Hamano6e96cb52017-08-19 11:43:39 -07001195 git_config_get_expiry_in_days("gc.rerereresolved", &cutoff_resolve, now);
1196 git_config_get_expiry_in_days("gc.rerereunresolved", &cutoff_noresolve, now);
Tanay Abhra633e5ad2014-08-07 09:21:21 -07001197 git_config(git_default_config, NULL);
Junio C Hamano0f891e72011-05-08 12:55:34 -07001198 dir = opendir(git_path("rr-cache"));
1199 if (!dir)
Thomas Gummerer2373b652018-08-05 18:20:30 +01001200 die_errno(_("unable to open rr-cache directory"));
Junio C Hamanoe828de82015-06-30 22:43:37 -07001201 /* Collect stale conflict IDs ... */
Elijah Newrenb548f0f2021-05-12 17:28:22 +00001202 while ((e = readdir_skip_dot_and_dotdot(dir))) {
Junio C Hamano1be1e852016-03-08 12:11:00 -08001203 struct rerere_dir *rr_dir;
1204 struct rerere_id id;
1205 int now_empty;
1206
Jeff King2bc1a872021-01-28 01:14:11 -05001207 if (!is_rr_cache_dirname(e->d_name))
Junio C Hamano1be1e852016-03-08 12:11:00 -08001208 continue; /* or should we remove e->d_name? */
Junio C Hamano0f891e72011-05-08 12:55:34 -07001209
Jeff King2bc1a872021-01-28 01:14:11 -05001210 rr_dir = find_rerere_dir(e->d_name);
1211
Junio C Hamano1be1e852016-03-08 12:11:00 -08001212 now_empty = 1;
1213 for (id.variant = 0, id.collection = rr_dir;
1214 id.variant < id.collection->status_nr;
1215 id.variant++) {
Junio C Hamano5ea82272017-08-19 11:16:01 -07001216 prune_one(&id, cutoff_resolve, cutoff_noresolve);
Junio C Hamano1be1e852016-03-08 12:11:00 -08001217 if (id.collection->status[id.variant])
1218 now_empty = 0;
Junio C Hamano0f891e72011-05-08 12:55:34 -07001219 }
Junio C Hamano1be1e852016-03-08 12:11:00 -08001220 if (now_empty)
Junio C Hamano0f891e72011-05-08 12:55:34 -07001221 string_list_append(&to_remove, e->d_name);
1222 }
Jim Meyeringa9930e32011-05-26 15:55:50 +02001223 closedir(dir);
Junio C Hamano1be1e852016-03-08 12:11:00 -08001224
1225 /* ... and then remove the empty directories */
Junio C Hamano0f891e72011-05-08 12:55:34 -07001226 for (i = 0; i < to_remove.nr; i++)
Junio C Hamano1be1e852016-03-08 12:11:00 -08001227 rmdir(git_path("rr-cache/%s", to_remove.items[i].string));
Junio C Hamano0f891e72011-05-08 12:55:34 -07001228 string_list_clear(&to_remove, 0);
Jeff King9dd330e2015-09-01 18:14:09 -04001229 rollback_lock_file(&write_lock);
Junio C Hamano0f891e72011-05-08 12:55:34 -07001230}
1231
Junio C Hamanoe828de82015-06-30 22:43:37 -07001232/*
1233 * During a conflict resolution, after "rerere" recorded the
1234 * preimages, abandon them if the user did not resolve them or
1235 * record their resolutions. And drop $GIT_DIR/MERGE_RR.
1236 *
1237 * NEEDSWORK: shouldn't we be calling this from "reset --hard"?
1238 */
Nguyễn Thái Ngọc Duy55e6b352018-11-10 06:49:09 +01001239void rerere_clear(struct repository *r, struct string_list *merge_rr)
Junio C Hamano0f891e72011-05-08 12:55:34 -07001240{
1241 int i;
1242
Nguyễn Thái Ngọc Duy55e6b352018-11-10 06:49:09 +01001243 if (setup_rerere(r, merge_rr, 0) < 0)
Jeff King9dd330e2015-09-01 18:14:09 -04001244 return;
1245
Junio C Hamano0f891e72011-05-08 12:55:34 -07001246 for (i = 0; i < merge_rr->nr; i++) {
Junio C Hamano1d51ece2015-07-04 17:38:34 -07001247 struct rerere_id *id = merge_rr->items[i].util;
Junio C Hamano1be1e852016-03-08 12:11:00 -08001248 if (!has_rerere_resolution(id)) {
Junio C Hamano18bb9932015-07-06 14:45:55 -07001249 unlink_rr_item(id);
Junio C Hamano1be1e852016-03-08 12:11:00 -08001250 rmdir(rerere_path(id, NULL));
1251 }
Junio C Hamano0f891e72011-05-08 12:55:34 -07001252 }
Nguyễn Thái Ngọc Duy55e6b352018-11-10 06:49:09 +01001253 unlink_or_warn(git_path_merge_rr(r));
Jeff King9dd330e2015-09-01 18:14:09 -04001254 rollback_lock_file(&write_lock);
Junio C Hamano0f891e72011-05-08 12:55:34 -07001255}