|
3 | 3 | #include "rerere.h"
|
4 | 4 | #include "xdiff/xdiff.h"
|
5 | 5 | #include "xdiff-interface.h"
|
| 6 | +#include "dir.h" |
| 7 | +#include "resolve-undo.h" |
| 8 | +#include "ll-merge.h" |
6 | 9 |
|
7 | 10 | /* if rerere_enabled == -1, fall back to detection of .git/rr-cache */
|
8 | 11 | static int rerere_enabled = -1;
|
@@ -223,6 +226,87 @@ static int handle_file(const char *path, unsigned char *sha1, const char *output
|
223 | 226 | return hunk_no;
|
224 | 227 | }
|
225 | 228 |
|
| 229 | +struct rerere_io_mem { |
| 230 | + struct rerere_io io; |
| 231 | + struct strbuf input; |
| 232 | +}; |
| 233 | + |
| 234 | +static int rerere_mem_getline(struct strbuf *sb, struct rerere_io *io_) |
| 235 | +{ |
| 236 | + struct rerere_io_mem *io = (struct rerere_io_mem *)io_; |
| 237 | + char *ep; |
| 238 | + size_t len; |
| 239 | + |
| 240 | + strbuf_release(sb); |
| 241 | + if (!io->input.len) |
| 242 | + return -1; |
| 243 | + ep = strchrnul(io->input.buf, '\n'); |
| 244 | + if (*ep == '\n') |
| 245 | + ep++; |
| 246 | + len = ep - io->input.buf; |
| 247 | + strbuf_add(sb, io->input.buf, len); |
| 248 | + strbuf_remove(&io->input, 0, len); |
| 249 | + return 0; |
| 250 | +} |
| 251 | + |
| 252 | +static int handle_cache(const char *path, unsigned char *sha1, const char *output) |
| 253 | +{ |
| 254 | + mmfile_t mmfile[3]; |
| 255 | + mmbuffer_t result = {NULL, 0}; |
| 256 | + struct cache_entry *ce; |
| 257 | + int pos, len, i, hunk_no; |
| 258 | + struct rerere_io_mem io; |
| 259 | + |
| 260 | + /* |
| 261 | + * Reproduce the conflicted merge in-core |
| 262 | + */ |
| 263 | + len = strlen(path); |
| 264 | + pos = cache_name_pos(path, len); |
| 265 | + if (0 <= pos) |
| 266 | + return -1; |
| 267 | + pos = -pos - 1; |
| 268 | + |
| 269 | + for (i = 0; i < 3; i++) { |
| 270 | + enum object_type type; |
| 271 | + unsigned long size; |
| 272 | + |
| 273 | + mmfile[i].size = 0; |
| 274 | + mmfile[i].ptr = NULL; |
| 275 | + if (active_nr <= pos) |
| 276 | + break; |
| 277 | + ce = active_cache[pos++]; |
| 278 | + if (ce_namelen(ce) != len || memcmp(ce->name, path, len) |
| 279 | + || ce_stage(ce) != i + 1) |
| 280 | + break; |
| 281 | + mmfile[i].ptr = read_sha1_file(ce->sha1, &type, &size); |
| 282 | + mmfile[i].size = size; |
| 283 | + } |
| 284 | + for (i = 0; i < 3; i++) { |
| 285 | + if (!mmfile[i].ptr && !mmfile[i].size) |
| 286 | + mmfile[i].ptr = xstrdup(""); |
| 287 | + } |
| 288 | + ll_merge(&result, path, &mmfile[0], |
| 289 | + &mmfile[1], "ours", |
| 290 | + &mmfile[2], "theirs", 0); |
| 291 | + for (i = 0; i < 3; i++) |
| 292 | + free(mmfile[i].ptr); |
| 293 | + |
| 294 | + memset(&io, 0, sizeof(&io)); |
| 295 | + io.io.getline = rerere_mem_getline; |
| 296 | + if (output) |
| 297 | + io.io.output = fopen(output, "w"); |
| 298 | + else |
| 299 | + io.io.output = NULL; |
| 300 | + strbuf_init(&io.input, 0); |
| 301 | + strbuf_attach(&io.input, result.ptr, result.size, result.size); |
| 302 | + |
| 303 | + hunk_no = handle_path(sha1, (struct rerere_io *)&io); |
| 304 | + strbuf_release(&io.input); |
| 305 | + if (io.io.output) |
| 306 | + fclose(io.io.output); |
| 307 | + return hunk_no; |
| 308 | +} |
| 309 | + |
226 | 310 | static int find_conflict(struct string_list *conflict)
|
227 | 311 | {
|
228 | 312 | int i;
|
@@ -434,3 +518,52 @@ int rerere(void)
|
434 | 518 | return 0;
|
435 | 519 | return do_plain_rerere(&merge_rr, fd);
|
436 | 520 | }
|
| 521 | + |
| 522 | +static int rerere_forget_one_path(const char *path, struct string_list *rr) |
| 523 | +{ |
| 524 | + const char *filename; |
| 525 | + char *hex; |
| 526 | + unsigned char sha1[20]; |
| 527 | + int ret; |
| 528 | + |
| 529 | + ret = handle_cache(path, sha1, NULL); |
| 530 | + if (ret < 1) |
| 531 | + return error("Could not parse conflict hunks in '%s'", path); |
| 532 | + hex = xstrdup(sha1_to_hex(sha1)); |
| 533 | + filename = rerere_path(hex, "postimage"); |
| 534 | + if (unlink(filename)) |
| 535 | + return (errno == ENOENT |
| 536 | + ? error("no remembered resolution for %s", path) |
| 537 | + : error("cannot unlink %s: %s", filename, strerror(errno))); |
| 538 | + |
| 539 | + handle_cache(path, sha1, rerere_path(hex, "preimage")); |
| 540 | + fprintf(stderr, "Updated preimage for '%s'\n", path); |
| 541 | + |
| 542 | + |
| 543 | + string_list_insert(path, rr)->util = hex; |
| 544 | + fprintf(stderr, "Forgot resolution for %s\n", path); |
| 545 | + return 0; |
| 546 | +} |
| 547 | + |
| 548 | +int rerere_forget(const char **pathspec) |
| 549 | +{ |
| 550 | + int i, fd; |
| 551 | + struct string_list conflict = { NULL, 0, 0, 1 }; |
| 552 | + struct string_list merge_rr = { NULL, 0, 0, 1 }; |
| 553 | + |
| 554 | + if (read_cache() < 0) |
| 555 | + return error("Could not read index"); |
| 556 | + |
| 557 | + fd = setup_rerere(&merge_rr); |
| 558 | + |
| 559 | + unmerge_cache(pathspec); |
| 560 | + find_conflict(&conflict); |
| 561 | + for (i = 0; i < conflict.nr; i++) { |
| 562 | + struct string_list_item *it = &conflict.items[i]; |
| 563 | + if (!match_pathspec(pathspec, it->string, strlen(it->string), |
| 564 | + 0, NULL)) |
| 565 | + continue; |
| 566 | + rerere_forget_one_path(it->string, &merge_rr); |
| 567 | + } |
| 568 | + return write_rr(&merge_rr, fd); |
| 569 | +} |
0 commit comments