123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- #include "builtin.h"
- #include "cache.h"
- #include "config.h"
- #include "xdiff/xdiff.h"
- #include "xdiff-interface.h"
- #include "parse-options.h"
- static const char *const merge_file_usage[] = {
- N_("git merge-file [<options>] [-L <name1> [-L <orig> [-L <name2>]]] <file1> <orig-file> <file2>"),
- NULL
- };
- static int label_cb(const struct option *opt, const char *arg, int unset)
- {
- static int label_count = 0;
- const char **names = (const char **)opt->value;
- BUG_ON_OPT_NEG(unset);
- if (label_count >= 3)
- return error("too many labels on the command line");
- names[label_count++] = arg;
- return 0;
- }
- int cmd_merge_file(int argc, const char **argv, const char *prefix)
- {
- const char *names[3] = { NULL, NULL, NULL };
- mmfile_t mmfs[3];
- mmbuffer_t result = {NULL, 0};
- xmparam_t xmp = {{0}};
- int ret = 0, i = 0, to_stdout = 0;
- int quiet = 0;
- struct option options[] = {
- OPT_BOOL('p', "stdout", &to_stdout, N_("send results to standard output")),
- OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3),
- OPT_SET_INT(0, "ours", &xmp.favor, N_("for conflicts, use our version"),
- XDL_MERGE_FAVOR_OURS),
- OPT_SET_INT(0, "theirs", &xmp.favor, N_("for conflicts, use their version"),
- XDL_MERGE_FAVOR_THEIRS),
- OPT_SET_INT(0, "union", &xmp.favor, N_("for conflicts, use a union version"),
- XDL_MERGE_FAVOR_UNION),
- OPT_INTEGER(0, "marker-size", &xmp.marker_size,
- N_("for conflicts, use this marker size")),
- OPT__QUIET(&quiet, N_("do not warn about conflicts")),
- OPT_CALLBACK('L', NULL, names, N_("name"),
- N_("set labels for file1/orig-file/file2"), &label_cb),
- OPT_END(),
- };
- xmp.level = XDL_MERGE_ZEALOUS_ALNUM;
- xmp.style = 0;
- xmp.favor = 0;
- if (startup_info->have_repository) {
- /* Read the configuration file */
- git_config(git_xmerge_config, NULL);
- if (0 <= git_xmerge_style)
- xmp.style = git_xmerge_style;
- }
- argc = parse_options(argc, argv, prefix, options, merge_file_usage, 0);
- if (argc != 3)
- usage_with_options(merge_file_usage, options);
- if (quiet) {
- if (!freopen("/dev/null", "w", stderr))
- return error_errno("failed to redirect stderr to /dev/null");
- }
- for (i = 0; i < 3; i++) {
- char *fname;
- int ret;
- if (!names[i])
- names[i] = argv[i];
- fname = prefix_filename(prefix, argv[i]);
- ret = read_mmfile(mmfs + i, fname);
- free(fname);
- if (ret)
- return -1;
- if (mmfs[i].size > MAX_XDIFF_SIZE ||
- buffer_is_binary(mmfs[i].ptr, mmfs[i].size))
- return error("Cannot merge binary files: %s",
- argv[i]);
- }
- xmp.ancestor = names[1];
- xmp.file1 = names[0];
- xmp.file2 = names[2];
- ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result);
- for (i = 0; i < 3; i++)
- free(mmfs[i].ptr);
- if (ret >= 0) {
- const char *filename = argv[0];
- char *fpath = prefix_filename(prefix, argv[0]);
- FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
- if (!f)
- ret = error_errno("Could not open %s for writing",
- filename);
- else if (result.size &&
- fwrite(result.ptr, result.size, 1, f) != 1)
- ret = error_errno("Could not write to %s", filename);
- else if (fclose(f))
- ret = error_errno("Could not close %s", filename);
- free(result.ptr);
- free(fpath);
- }
- if (ret > 127)
- ret = 127;
- return ret;
- }
|