1#include "builtin.h"2#include "cache.h"3#include "config.h"4#include "dir.h"5#include "parse-options.h"6#include "string-list.h"7#include "rerere.h"8#include "xdiff/xdiff.h"9#include "xdiff-interface.h"10#include "pathspec.h"1112static const char * const rerere_usage[] = {13N_("git rerere [clear | forget <path>... | status | remaining | diff | gc]"),14NULL,15};1617static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)18{19int i;20for (i = 0; i < nbuf; i++)21if (write_in_full(1, ptr[i].ptr, ptr[i].size) < 0)22return -1;23return 0;24}2526static int diff_two(const char *file1, const char *label1,27const char *file2, const char *label2)28{29xpparam_t xpp;30xdemitconf_t xecfg;31xdemitcb_t ecb;32mmfile_t minus, plus;33int ret;3435if (read_mmfile(&minus, file1) || read_mmfile(&plus, file2))36return -1;3738printf("--- a/%s\n+++ b/%s\n", label1, label2);39fflush(stdout);40memset(&xpp, 0, sizeof(xpp));41xpp.flags = 0;42memset(&xecfg, 0, sizeof(xecfg));43xecfg.ctxlen = 3;44ecb.out_hunk = NULL;45ecb.out_line = outf;46ret = xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);4748free(minus.ptr);49free(plus.ptr);50return ret;51}5253int cmd_rerere(int argc, const char **argv, const char *prefix)54{55struct string_list merge_rr = STRING_LIST_INIT_DUP;56int i, autoupdate = -1, flags = 0;5758struct option options[] = {59OPT_SET_INT(0, "rerere-autoupdate", &autoupdate,60N_("register clean resolutions in index"), 1),61OPT_END(),62};6364argc = parse_options(argc, argv, prefix, options, rerere_usage, 0);6566git_config(git_xmerge_config, NULL);6768if (autoupdate == 1)69flags = RERERE_AUTOUPDATE;70if (autoupdate == 0)71flags = RERERE_NOAUTOUPDATE;7273if (argc < 1)74return repo_rerere(the_repository, flags);7576if (!strcmp(argv[0], "forget")) {77struct pathspec pathspec;78if (argc < 2)79warning(_("'git rerere forget' without paths is deprecated"));80parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD,81prefix, argv + 1);82return rerere_forget(the_repository, &pathspec);83}8485if (!strcmp(argv[0], "clear")) {86rerere_clear(the_repository, &merge_rr);87} else if (!strcmp(argv[0], "gc"))88rerere_gc(the_repository, &merge_rr);89else if (!strcmp(argv[0], "status")) {90if (setup_rerere(the_repository, &merge_rr,91flags | RERERE_READONLY) < 0)92return 0;93for (i = 0; i < merge_rr.nr; i++)94printf("%s\n", merge_rr.items[i].string);95} else if (!strcmp(argv[0], "remaining")) {96rerere_remaining(the_repository, &merge_rr);97for (i = 0; i < merge_rr.nr; i++) {98if (merge_rr.items[i].util != RERERE_RESOLVED)99printf("%s\n", merge_rr.items[i].string);100else101/* prepare for later call to102* string_list_clear() */103merge_rr.items[i].util = NULL;104}105} else if (!strcmp(argv[0], "diff")) {106if (setup_rerere(the_repository, &merge_rr,107flags | RERERE_READONLY) < 0)108return 0;109for (i = 0; i < merge_rr.nr; i++) {110const char *path = merge_rr.items[i].string;111const struct rerere_id *id = merge_rr.items[i].util;112if (diff_two(rerere_path(id, "preimage"), path, path, path))113die(_("unable to generate diff for '%s'"), rerere_path(id, NULL));114}115} else116usage_with_options(rerere_usage, options);117118string_list_clear(&merge_rr, 1);119return 0;120}