]> git.ipfire.org Git - thirdparty/git.git/blame - builtin/merge-file.c
Merge branch 'ms/send-email-validate-fix'
[thirdparty/git.git] / builtin / merge-file.c
CommitLineData
baffc0e7 1#include "builtin.h"
0b027f6c 2#include "abspath.h"
b2141fc1 3#include "config.h"
f394e093 4#include "gettext.h"
e38da487 5#include "setup.h"
ba1f5f35 6#include "xdiff/xdiff.h"
7cab5883 7#include "xdiff-interface.h"
d2496107 8#include "parse-options.h"
ba1f5f35 9
d2496107 10static const char *const merge_file_usage[] = {
9c9b4f2f 11 N_("git merge-file [<options>] [-L <name1> [-L <orig> [-L <name2>]]] <file1> <orig-file> <file2>"),
d2496107
PH
12 NULL
13};
14
15static int label_cb(const struct option *opt, const char *arg, int unset)
16{
17 static int label_count = 0;
18 const char **names = (const char **)opt->value;
19
517fe807
JK
20 BUG_ON_OPT_NEG(unset);
21
d2496107
PH
22 if (label_count >= 3)
23 return error("too many labels on the command line");
24 names[label_count++] = arg;
25 return 0;
26}
ba1f5f35 27
baffc0e7 28int cmd_merge_file(int argc, const char **argv, const char *prefix)
ba1f5f35 29{
480a0e30
ÆAB
30 const char *names[3] = { 0 };
31 mmfile_t mmfs[3] = { 0 };
32 mmbuffer_t result = { 0 };
33 xmparam_t xmp = { 0 };
fbe0b24c 34 int ret = 0, i = 0, to_stdout = 0;
560119b9 35 int quiet = 0;
d2496107 36 struct option options[] = {
d5d09d47 37 OPT_BOOL('p', "stdout", &to_stdout, N_("send results to standard output")),
c7d93da3 38 OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3),
4496526f
PW
39 OPT_SET_INT(0, "zdiff3", &xmp.style, N_("use a zealous diff3 based merge"),
40 XDL_MERGE_ZEALOUS_DIFF3),
c7d93da3 41 OPT_SET_INT(0, "ours", &xmp.favor, N_("for conflicts, use our version"),
73eb40ee 42 XDL_MERGE_FAVOR_OURS),
c7d93da3 43 OPT_SET_INT(0, "theirs", &xmp.favor, N_("for conflicts, use their version"),
73eb40ee 44 XDL_MERGE_FAVOR_THEIRS),
c7d93da3 45 OPT_SET_INT(0, "union", &xmp.favor, N_("for conflicts, use a union version"),
3a15048d 46 XDL_MERGE_FAVOR_UNION),
11f3aa23 47 OPT_INTEGER(0, "marker-size", &xmp.marker_size,
c7d93da3
NTND
48 N_("for conflicts, use this marker size")),
49 OPT__QUIET(&quiet, N_("do not warn about conflicts")),
50 OPT_CALLBACK('L', NULL, names, N_("name"),
9c9b4f2f 51 N_("set labels for file1/orig-file/file2"), &label_cb),
d2496107
PH
52 OPT_END(),
53 };
54
560119b9
BW
55 xmp.level = XDL_MERGE_ZEALOUS_ALNUM;
56 xmp.style = 0;
57 xmp.favor = 0;
58
3668d423 59 if (startup_info->have_repository) {
b5412484
JH
60 /* Read the configuration file */
61 git_config(git_xmerge_config, NULL);
62 if (0 <= git_xmerge_style)
560119b9 63 xmp.style = git_xmerge_style;
b5412484 64 }
ba1f5f35 65
37782920 66 argc = parse_options(argc, argv, prefix, options, merge_file_usage, 0);
d2496107
PH
67 if (argc != 3)
68 usage_with_options(merge_file_usage, options);
4deba8b7
RS
69 if (quiet) {
70 if (!freopen("/dev/null", "w", stderr))
62f94d54 71 return error_errno("failed to redirect stderr to /dev/null");
4deba8b7 72 }
ba1f5f35 73
5771907a 74 for (i = 0; i < 3; i++) {
e4da43b1 75 char *fname;
480a0e30 76 mmfile_t *mmf = mmfs + i;
e4da43b1 77
d2496107
PH
78 if (!names[i])
79 names[i] = argv[i];
e4da43b1
JK
80
81 fname = prefix_filename(prefix, argv[i]);
480a0e30
ÆAB
82
83 if (read_mmfile(mmf, fname))
84 ret = -1;
85 else if (mmf->size > MAX_XDIFF_SIZE ||
86 buffer_is_binary(mmf->ptr, mmf->size))
87 ret = error("Cannot merge binary files: %s",
88 argv[i]);
89
e4da43b1
JK
90 free(fname);
91 if (ret)
e72e12cc
ÆAB
92 goto cleanup;
93
5771907a 94 }
ba1f5f35 95
4bb09362 96 xmp.ancestor = names[1];
a4b5e91c
JN
97 xmp.file1 = names[0];
98 xmp.file2 = names[2];
99 ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result);
ba1f5f35 100
ba1f5f35 101 if (ret >= 0) {
d2496107 102 const char *filename = argv[0];
e4da43b1 103 char *fpath = prefix_filename(prefix, argv[0]);
204a8ffe 104 FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
ba1f5f35
JS
105
106 if (!f)
62f94d54
NTND
107 ret = error_errno("Could not open %s for writing",
108 filename);
381b851c
JS
109 else if (result.size &&
110 fwrite(result.ptr, result.size, 1, f) != 1)
62f94d54 111 ret = error_errno("Could not write to %s", filename);
ba1f5f35 112 else if (fclose(f))
62f94d54 113 ret = error_errno("Could not close %s", filename);
ba1f5f35 114 free(result.ptr);
e4da43b1 115 free(fpath);
ba1f5f35
JS
116 }
117
e34f8027
JK
118 if (ret > 127)
119 ret = 127;
120
e72e12cc
ÆAB
121cleanup:
122 for (i = 0; i < 3; i++)
123 free(mmfs[i].ptr);
124
ba1f5f35
JS
125 return ret;
126}