/* * The path indicated by rr_item may still have conflict for which we * have a recorded resolution, in which case replay it and optionally * update it. Or it may have been resolved by the user and we may * only have the preimage for that conflict, in which case the result * needs to be recorded as a resolution in a postimage file. */ static void do_rerere_one_path(struct string_list_item *rr_item, struct string_list *update) { const char *path = rr_item->string; const struct rerere_id *id = rr_item->util; /* Is there a recorded resolution we could attempt to apply? */ if (has_rerere_resolution(id)) { if (merge(id, path)) return; /* failed to replay */ if (rerere_autoupdate) string_list_insert(update, path); else fprintf(stderr, "Resolved '%s' using previous resolution.\n", path); } else if (!handle_file(path, NULL, NULL)) { /* The user has resolved it. */ copy_file(rerere_path(id, "postimage"), path, 0666); fprintf(stderr, "Recorded resolution for '%s'.\n", path); } else { return; } free_rerere_id(rr_item); rr_item->util = NULL; }
void rerere_clear(struct string_list *merge_rr) { int i; for (i = 0; i < merge_rr->nr; i++) { const char *name = (const char *)merge_rr->items[i].util; if (!has_rerere_resolution(name)) unlink_rr_item(name); } unlink_or_warn(git_path("MERGE_RR")); }
/* * During a conflict resolution, after "rerere" recorded the * preimages, abandon them if the user did not resolve them or * record their resolutions. And drop $GIT_DIR/MERGE_RR. * * NEEDSWORK: shouldn't we be calling this from "reset --hard"? */ void rerere_clear(struct string_list *merge_rr) { int i; if (setup_rerere(merge_rr, 0) < 0) return; for (i = 0; i < merge_rr->nr; i++) { struct rerere_id *id = merge_rr->items[i].util; if (!has_rerere_resolution(id)) unlink_rr_item(id); } unlink_or_warn(git_path_merge_rr()); rollback_lock_file(&write_lock); }
static int rerere_forget_one_path(const char *path, struct string_list *rr) { const char *filename; struct rerere_id *id; unsigned char sha1[20]; int ret; struct string_list_item *item; /* * Recreate the original conflict from the stages in the * index and compute the conflict ID */ ret = handle_cache(path, sha1, NULL); if (ret < 1) return error(_("could not parse conflict hunks in '%s'"), path); /* Nuke the recorded resolution for the conflict */ id = new_rerere_id(sha1); for (id->variant = 0; id->variant < id->collection->status_nr; id->variant++) { mmfile_t cur = { NULL, 0 }; mmbuffer_t result = {NULL, 0}; int cleanly_resolved; if (!has_rerere_resolution(id)) continue; handle_cache(path, sha1, rerere_path(id, "thisimage")); if (read_mmfile(&cur, rerere_path(id, "thisimage"))) { free(cur.ptr); error(_("failed to update conflicted state in '%s'"), path); goto fail_exit; } cleanly_resolved = !try_merge(id, path, &cur, &result); free(result.ptr); free(cur.ptr); if (cleanly_resolved) break; } if (id->collection->status_nr <= id->variant) { error(_("no remembered resolution for '%s'"), path); goto fail_exit; } filename = rerere_path(id, "postimage"); if (unlink(filename)) { if (errno == ENOENT) error(_("no remembered resolution for '%s'"), path); else error_errno(_("cannot unlink '%s'"), filename); goto fail_exit; } /* * Update the preimage so that the user can resolve the * conflict in the working tree, run us again to record * the postimage. */ handle_cache(path, sha1, rerere_path(id, "preimage")); fprintf_ln(stderr, _("Updated preimage for '%s'"), path); /* * And remember that we can record resolution for this * conflict when the user is done. */ item = string_list_insert(rr, path); free_rerere_id(item); item->util = id; fprintf(stderr, _("Forgot resolution for '%s'\n"), path); return 0; fail_exit: free(id); return -1; }
static int do_plain_rerere(struct string_list *rr, int fd) { struct string_list conflict = STRING_LIST_INIT_DUP; struct string_list update = STRING_LIST_INIT_DUP; int i; find_conflict(&conflict); /* * MERGE_RR records paths with conflicts immediately after merge * failed. Some of the conflicted paths might have been hand resolved * in the working tree since then, but the initial run would catch all * and register their preimages. */ for (i = 0; i < conflict.nr; i++) { const char *path = conflict.items[i].string; if (!string_list_has_string(rr, path)) { unsigned char sha1[20]; char *hex; int ret; ret = handle_file(path, sha1, NULL); if (ret < 1) continue; hex = xstrdup(sha1_to_hex(sha1)); string_list_insert(rr, path)->util = hex; if (mkdir_in_gitdir(git_path("rr-cache/%s", hex))) continue; handle_file(path, NULL, rerere_path(hex, "preimage")); fprintf(stderr, "Recorded preimage for '%s'\n", path); } } /* * Now some of the paths that had conflicts earlier might have been * hand resolved. Others may be similar to a conflict already that * was resolved before. */ for (i = 0; i < rr->nr; i++) { int ret; const char *path = rr->items[i].string; const char *name = (const char *)rr->items[i].util; if (has_rerere_resolution(name)) { if (!merge(name, path)) { const char *msg; if (rerere_autoupdate) { string_list_insert(&update, path); msg = "Staged '%s' using previous resolution.\n"; } else msg = "Resolved '%s' using previous resolution.\n"; fprintf(stderr, msg, path); goto mark_resolved; } } /* Let's see if we have resolved it. */ ret = handle_file(path, NULL, NULL); if (ret) continue; fprintf(stderr, "Recorded resolution for '%s'.\n", path); copy_file(rerere_path(name, "postimage"), path, 0666); mark_resolved: rr->items[i].util = NULL; } if (update.nr) update_paths(&update); return write_rr(rr, fd); }