1 #define USE_THE_REPOSITORY_VARIABLE
6 #include "object-name.h"
7 #include "object-store.h"
11 #include "xdiff/xdiff.h"
12 #include "xdiff-interface.h"
13 #include "parse-options.h"
15 static const char *const merge_file_usage
[] = {
16 N_("git merge-file [<options>] [-L <name1> [-L <orig> [-L <name2>]]] <file1> <orig-file> <file2>"),
20 static int label_cb(const struct option
*opt
, const char *arg
, int unset
)
22 static int label_count
= 0;
23 const char **names
= (const char **)opt
->value
;
25 BUG_ON_OPT_NEG(unset
);
28 return error("too many labels on the command line");
29 names
[label_count
++] = arg
;
33 static int set_diff_algorithm(xpparam_t
*xpp
,
36 long diff_algorithm
= parse_algorithm_value(alg
);
37 if (diff_algorithm
< 0)
39 xpp
->flags
= (xpp
->flags
& ~XDF_DIFF_ALGORITHM_MASK
) | diff_algorithm
;
43 static int diff_algorithm_cb(const struct option
*opt
,
44 const char *arg
, int unset
)
46 xpparam_t
*xpp
= opt
->value
;
48 BUG_ON_OPT_NEG(unset
);
50 if (set_diff_algorithm(xpp
, arg
))
51 return error(_("option diff-algorithm accepts \"myers\", "
52 "\"minimal\", \"patience\" and \"histogram\""));
57 int cmd_merge_file(int argc
,
60 struct repository
*repo UNUSED
)
62 const char *names
[3] = { 0 };
63 mmfile_t mmfs
[3] = { 0 };
64 mmbuffer_t result
= { 0 };
65 xmparam_t xmp
= { 0 };
66 int ret
= 0, i
= 0, to_stdout
= 0, object_id
= 0;
68 struct option options
[] = {
69 OPT_BOOL('p', "stdout", &to_stdout
, N_("send results to standard output")),
70 OPT_BOOL(0, "object-id", &object_id
, N_("use object IDs instead of filenames")),
71 OPT_SET_INT(0, "diff3", &xmp
.style
, N_("use a diff3 based merge"), XDL_MERGE_DIFF3
),
72 OPT_SET_INT(0, "zdiff3", &xmp
.style
, N_("use a zealous diff3 based merge"),
73 XDL_MERGE_ZEALOUS_DIFF3
),
74 OPT_SET_INT(0, "ours", &xmp
.favor
, N_("for conflicts, use our version"),
75 XDL_MERGE_FAVOR_OURS
),
76 OPT_SET_INT(0, "theirs", &xmp
.favor
, N_("for conflicts, use their version"),
77 XDL_MERGE_FAVOR_THEIRS
),
78 OPT_SET_INT(0, "union", &xmp
.favor
, N_("for conflicts, use a union version"),
79 XDL_MERGE_FAVOR_UNION
),
80 OPT_CALLBACK_F(0, "diff-algorithm", &xmp
.xpp
, N_("<algorithm>"),
81 N_("choose a diff algorithm"),
82 PARSE_OPT_NONEG
, diff_algorithm_cb
),
83 OPT_INTEGER(0, "marker-size", &xmp
.marker_size
,
84 N_("for conflicts, use this marker size")),
85 OPT__QUIET(&quiet
, N_("do not warn about conflicts")),
86 OPT_CALLBACK('L', NULL
, names
, N_("name"),
87 N_("set labels for file1/orig-file/file2"), &label_cb
),
91 xmp
.level
= XDL_MERGE_ZEALOUS_ALNUM
;
95 if (startup_info
->have_repository
) {
96 /* Read the configuration file */
97 git_config(git_xmerge_config
, NULL
);
98 if (0 <= git_xmerge_style
)
99 xmp
.style
= git_xmerge_style
;
102 argc
= parse_options(argc
, argv
, prefix
, options
, merge_file_usage
, 0);
104 usage_with_options(merge_file_usage
, options
);
106 if (!freopen("/dev/null", "w", stderr
))
107 return error_errno("failed to redirect stderr to /dev/null");
111 setup_git_directory();
113 for (i
= 0; i
< 3; i
++) {
115 struct object_id oid
;
116 mmfile_t
*mmf
= mmfs
+ i
;
121 fname
= prefix_filename(prefix
, argv
[i
]);
124 if (repo_get_oid(the_repository
, argv
[i
], &oid
))
125 ret
= error(_("object '%s' does not exist"),
127 else if (!oideq(&oid
, the_hash_algo
->empty_blob
))
128 read_mmblob(mmf
, &oid
);
130 read_mmfile(mmf
, "/dev/null");
131 } else if (read_mmfile(mmf
, fname
)) {
134 if (ret
!= -1 && (mmf
->size
> MAX_XDIFF_SIZE
||
135 buffer_is_binary(mmf
->ptr
, mmf
->size
))) {
136 ret
= error("Cannot merge binary files: %s",
146 xmp
.ancestor
= names
[1];
147 xmp
.file1
= names
[0];
148 xmp
.file2
= names
[2];
149 ret
= xdl_merge(mmfs
+ 1, mmfs
+ 0, mmfs
+ 2, &xmp
, &result
);
152 if (object_id
&& !to_stdout
) {
153 struct object_id oid
;
155 if (write_object_file(result
.ptr
, result
.size
, OBJ_BLOB
, &oid
) < 0)
156 ret
= error(_("Could not write object file"));
158 oidcpy(&oid
, the_hash_algo
->empty_blob
);
161 printf("%s\n", oid_to_hex(&oid
));
163 const char *filename
= argv
[0];
164 char *fpath
= prefix_filename(prefix
, argv
[0]);
165 FILE *f
= to_stdout
? stdout
: fopen(fpath
, "wb");
168 ret
= error_errno("Could not open %s for writing",
170 else if (result
.size
&&
171 fwrite(result
.ptr
, result
.size
, 1, f
) != 1)
172 ret
= error_errno("Could not write to %s", filename
);
174 ret
= error_errno("Could not close %s", filename
);
184 for (i
= 0; i
< 3; i
++)