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.outf = outf;45ret = xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);4647free(minus.ptr);48free(plus.ptr);49return ret;50}5152int cmd_rerere(int argc, const char **argv, const char *prefix)53{54struct string_list merge_rr = STRING_LIST_INIT_DUP;55int i, autoupdate = -1, flags = 0;5657struct option options[] = {58OPT_SET_INT(0, "rerere-autoupdate", &autoupdate,59N_("register clean resolutions in index"), 1),60OPT_END(),61};6263argc = parse_options(argc, argv, prefix, options, rerere_usage, 0);6465git_config(git_xmerge_config, NULL);6667if (autoupdate == 1)68flags = RERERE_AUTOUPDATE;69if (autoupdate == 0)70flags = RERERE_NOAUTOUPDATE;7172if (argc < 1)73return rerere(flags);7475if (!strcmp(argv[0], "forget")) {76struct pathspec pathspec;77if (argc < 2)78warning("'git rerere forget' without paths is deprecated");79parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD,80prefix, argv + 1);81return rerere_forget(&pathspec);82}8384if (!strcmp(argv[0], "clear")) {85rerere_clear(&merge_rr);86} else if (!strcmp(argv[0], "gc"))87rerere_gc(&merge_rr);88else if (!strcmp(argv[0], "status")) {89if (setup_rerere(&merge_rr, flags | RERERE_READONLY) < 0)90return 0;91for (i = 0; i < merge_rr.nr; i++)92printf("%s\n", merge_rr.items[i].string);93} else if (!strcmp(argv[0], "remaining")) {94rerere_remaining(&merge_rr);95for (i = 0; i < merge_rr.nr; i++) {96if (merge_rr.items[i].util != RERERE_RESOLVED)97printf("%s\n", merge_rr.items[i].string);98else99/* prepare for later call to100* string_list_clear() */101merge_rr.items[i].util = NULL;102}103} else if (!strcmp(argv[0], "diff")) {104if (setup_rerere(&merge_rr, flags | RERERE_READONLY) < 0)105return 0;106for (i = 0; i < merge_rr.nr; i++) {107const char *path = merge_rr.items[i].string;108const struct rerere_id *id = merge_rr.items[i].util;109if (diff_two(rerere_path(id, "preimage"), path, path, path))110die("unable to generate diff for %s", rerere_path(id, NULL));111}112} else113usage_with_options(rerere_usage, options);114115string_list_clear(&merge_rr, 1);116return 0;117}