Our import of xdiff has two identical buffer structures: mmfile_t and
mmbuffer_t. In upstream xdiff these were actually different, but the
import in 3443546f6e (Use a *real* built-in diff generator, 2006-03-24)
simplified mmfile_t to a simple buffer.
In xdiff we usually use mmfile_t for input and mmbuffer_t for output,
but they are really both just a ptr/len pair. I don't think that having
different types is buying us anything in terms of type safety or
semantics, and having two makes it awkward to use the same helpers for
both. In particular, an external merge driver's output is read from a
file, but we can't easily use read_mmfile(), since we want the result in
an mmbuffer_t.
Let's use mmfile_t for both cases and drop mmbuffer_t. The latter is
probably a more descriptive name, but we have many more uses of
mmfile_t (and helpers like read_mmfile). So let's consolidate using that
name; we can always change it to something more sensible later.
There should be no behavior change here; this is just consolidating the
types.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
137 lines
3.4 KiB
C
137 lines
3.4 KiB
C
#define USE_THE_REPOSITORY_VARIABLE
|
|
|
|
#include "builtin.h"
|
|
#include "config.h"
|
|
#include "gettext.h"
|
|
#include "parse-options.h"
|
|
#include "rerere.h"
|
|
#include "strbuf.h"
|
|
#include "string-list.h"
|
|
#include "xdiff/xdiff.h"
|
|
#include "xdiff-interface.h"
|
|
#include "pathspec.h"
|
|
|
|
static const char * const rerere_usage[] = {
|
|
N_("git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"),
|
|
NULL,
|
|
};
|
|
|
|
static int outf(void *dummy UNUSED, mmfile_t *ptr, int nbuf)
|
|
{
|
|
int i;
|
|
for (i = 0; i < nbuf; i++)
|
|
if (write_in_full(1, ptr[i].ptr, ptr[i].size) < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static int diff_two(const char *file1, const char *label1,
|
|
const char *file2, const char *label2)
|
|
{
|
|
xpparam_t xpp;
|
|
xdemitconf_t xecfg;
|
|
xdemitcb_t ecb = { .out_line = outf };
|
|
mmfile_t minus, plus;
|
|
int ret;
|
|
|
|
if (read_mmfile(&minus, file1))
|
|
return -1;
|
|
if (read_mmfile(&plus, file2)) {
|
|
free(minus.ptr);
|
|
return -1;
|
|
}
|
|
|
|
printf("--- a/%s\n+++ b/%s\n", label1, label2);
|
|
fflush(stdout);
|
|
memset(&xpp, 0, sizeof(xpp));
|
|
xpp.flags = 0;
|
|
memset(&xecfg, 0, sizeof(xecfg));
|
|
xecfg.ctxlen = 3;
|
|
ret = xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
|
|
|
|
free(minus.ptr);
|
|
free(plus.ptr);
|
|
return ret;
|
|
}
|
|
|
|
int cmd_rerere(int argc,
|
|
const char **argv,
|
|
const char *prefix,
|
|
struct repository *repo UNUSED)
|
|
{
|
|
struct string_list merge_rr = STRING_LIST_INIT_DUP;
|
|
int autoupdate = -1, flags = 0;
|
|
|
|
struct option options[] = {
|
|
OPT_SET_INT(0, "rerere-autoupdate", &autoupdate,
|
|
N_("register clean resolutions in index"), 1),
|
|
OPT_END(),
|
|
};
|
|
|
|
argc = parse_options(argc, argv, prefix, options, rerere_usage, 0);
|
|
|
|
repo_config(the_repository, git_xmerge_config, NULL);
|
|
|
|
if (autoupdate == 1)
|
|
flags = RERERE_AUTOUPDATE;
|
|
if (autoupdate == 0)
|
|
flags = RERERE_NOAUTOUPDATE;
|
|
|
|
if (argc < 1)
|
|
return repo_rerere(the_repository, flags);
|
|
|
|
if (!strcmp(argv[0], "forget")) {
|
|
struct pathspec pathspec;
|
|
int ret;
|
|
|
|
if (argc < 2)
|
|
warning(_("'git rerere forget' without paths is deprecated"));
|
|
parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD,
|
|
prefix, argv + 1);
|
|
|
|
ret = rerere_forget(the_repository, &pathspec);
|
|
|
|
clear_pathspec(&pathspec);
|
|
return ret;
|
|
}
|
|
|
|
if (!strcmp(argv[0], "clear")) {
|
|
rerere_clear(the_repository, &merge_rr);
|
|
} else if (!strcmp(argv[0], "gc"))
|
|
rerere_gc(the_repository, &merge_rr);
|
|
else if (!strcmp(argv[0], "status")) {
|
|
if (setup_rerere(the_repository, &merge_rr,
|
|
flags | RERERE_READONLY) < 0)
|
|
return 0;
|
|
for (size_t i = 0; i < merge_rr.nr; i++)
|
|
printf("%s\n", merge_rr.items[i].string);
|
|
} else if (!strcmp(argv[0], "remaining")) {
|
|
rerere_remaining(the_repository, &merge_rr);
|
|
for (size_t i = 0; i < merge_rr.nr; i++) {
|
|
if (merge_rr.items[i].util != RERERE_RESOLVED)
|
|
printf("%s\n", merge_rr.items[i].string);
|
|
else
|
|
/* prepare for later call to
|
|
* string_list_clear() */
|
|
merge_rr.items[i].util = NULL;
|
|
}
|
|
} else if (!strcmp(argv[0], "diff")) {
|
|
struct strbuf buf = STRBUF_INIT;
|
|
if (setup_rerere(the_repository, &merge_rr,
|
|
flags | RERERE_READONLY) < 0)
|
|
return 0;
|
|
for (size_t i = 0; i < merge_rr.nr; i++) {
|
|
const char *path = merge_rr.items[i].string;
|
|
const struct rerere_id *id = merge_rr.items[i].util;
|
|
if (diff_two(rerere_path(&buf, id, "preimage"), path, path, path))
|
|
die(_("unable to generate diff for '%s'"), rerere_path(&buf, id, NULL));
|
|
}
|
|
|
|
strbuf_release(&buf);
|
|
} else
|
|
usage_with_options(rerere_usage, options);
|
|
|
|
string_list_clear(&merge_rr, 1);
|
|
return 0;
|
|
}
|