@matheusbsbs / matheus-bagliano / commits / 73eb40eeaa
Fork 0

git-merge-file --ours, --theirs

Sometimes people want their conflicting merges autoresolved by favouring upstream changes. The standard answer they are given is to run "git diff --name-only | xargs git checkout MERGE_HEAD --" in such a case. This is to accept automerge results for the paths that are fully resolved automatically, while taking their version of the file in full for paths that have conflicts. This is problematic on two counts. One is that this is not exactly what these people want. It discards all changes they did on their branch for any paths that conflicted. They usually want to salvage as much automerge result as possible in a conflicted file, and want to take the upstream change only in the conflicted part. This patch teaches two new modes of operation to the lowest-lever merge machinery, xdl_merge(). Instead of leaving the conflicted lines from both sides enclosed in <<<, ===, and >>> markers, the conflicts are resolved favouring our side or their side of changes. A larger problem is that this tends to encourage a bad workflow by allowing people to record such a mixed up half-merged result as a full commit without auditing. This commit does not tackle this issue at all. In git, we usually give long enough rope to users with strange wishes as long as the risky features are not enabled by default, and this is such a risky feature. Signed-off-by: Avery Pennarun <apenwarr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Jun 20, 2008 at 00:17 UTC 73eb40eeaaebc5ebae283c06286b96b4aea00143
4 files changed +34 -10
Documentation/git-merge-file.txt
+10 -2
@@ -10,7 +10,8 @@ SYNOPSIS
10 --------
11 [verse]
12 'git merge-file' [-L <current-name> [-L <base-name> [-L <other-name>]]]
13 - [-p|--stdout] [-q|--quiet] <current-file> <base-file> <other-file>
13 + [--ours|--theirs] [-p|--stdout] [-q|--quiet]
14 + <current-file> <base-file> <other-file>
15
16
17 DESCRIPTION
@@ -34,7 +35,9 @@ normally outputs a warning and brackets the conflict with lines containing
35 >>>>>>> B
36
37 If there are conflicts, the user should edit the result and delete one of
37 -the alternatives.
38 +the alternatives. When `--ours` or `--theirs` option is in effect, however,
39 +these conflicts are resolved favouring lines from `<current-file>` or
40 +lines from `<other-file>` respectively.
41
42 The exit value of this program is negative on error, and the number of
43 conflicts otherwise. If the merge was clean, the exit value is 0.
@@ -62,6 +65,11 @@ OPTIONS
65 -q::
66 Quiet; do not warn about conflicts.
67
68 +--ours::
69 +--theirs::
70 + Instead of leaving conflicts in the file, resolve conflicts
71 + favouring our (or their) side of the lines.
72 +
73
74 EXAMPLES
75 --------
builtin-merge-file.c
+10 -5
@@ -27,13 +27,18 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
27 mmbuffer_t result = {NULL, 0};
28 xpparam_t xpp = {XDF_NEED_MINIMAL};
29 int ret = 0, i = 0, to_stdout = 0;
30 - int merge_level = XDL_MERGE_ZEALOUS_ALNUM;
31 - int merge_style = 0, quiet = 0;
30 + int level = XDL_MERGE_ZEALOUS_ALNUM;
31 + int style = 0, quiet = 0;
32 + int favor = 0;
33 int nongit;
34
35 struct option options[] = {
36 OPT_BOOLEAN('p', "stdout", &to_stdout, "send results to standard output"),
36 - OPT_SET_INT(0, "diff3", &merge_style, "use a diff3 based merge", XDL_MERGE_DIFF3),
37 + OPT_SET_INT(0, "diff3", &style, "use a diff3 based merge", XDL_MERGE_DIFF3),
38 + OPT_SET_INT(0, "ours", &favor, "for conflicts, use our version",
39 + XDL_MERGE_FAVOR_OURS),
40 + OPT_SET_INT(0, "theirs", &favor, "for conflicts, use their version",
41 + XDL_MERGE_FAVOR_THEIRS),
42 OPT__QUIET(&quiet),
43 OPT_CALLBACK('L', NULL, names, "name",
44 "set labels for file1/orig_file/file2", &label_cb),
@@ -45,7 +50,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
50 /* Read the configuration file */
51 git_config(git_xmerge_config, NULL);
52 if (0 <= git_xmerge_style)
48 - merge_style = git_xmerge_style;
53 + style = git_xmerge_style;
54 }
55
56 argc = parse_options(argc, argv, prefix, options, merge_file_usage, 0);
@@ -68,7 +73,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
73 }
74
75 ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
71 - &xpp, merge_level | merge_style, &result);
76 + &xpp, XDL_MERGE_FLAGS(level, style, favor), &result);
77
78 for (i = 0; i < 3; i++)
79 free(mmfs[i].ptr);
xdiff/xdiff.h
+7 -1
@@ -58,6 +58,12 @@ extern "C" {
58 #define XDL_MERGE_ZEALOUS_ALNUM 3
59 #define XDL_MERGE_LEVEL_MASK 0x0f
60
61 +/* merge favor modes */
62 +#define XDL_MERGE_FAVOR_OURS 1
63 +#define XDL_MERGE_FAVOR_THEIRS 2
64 +#define XDL_MERGE_FAVOR(flags) (((flags)>>4) & 3)
65 +#define XDL_MERGE_FLAGS(level, style, favor) ((level)|(style)|((favor)<<4))
66 +
67 /* merge output styles */
68 #define XDL_MERGE_DIFF3 0x8000
69 #define XDL_MERGE_STYLE_MASK 0x8000
@@ -110,7 +116,7 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
116
117 int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
118 mmfile_t *mf2, const char *name2,
113 - xpparam_t const *xpp, int level, mmbuffer_t *result);
119 + xpparam_t const *xpp, int flags, mmbuffer_t *result);
120
121 #ifdef __cplusplus
122 }
xdiff/xmerge.c
+7 -2
@@ -214,11 +214,15 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
214
215 static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
216 xdfenv_t *xe2, const char *name2,
217 + int favor,
218 xdmerge_t *m, char *dest, int style)
219 {
220 int size, i;
221
222 for (size = i = 0; m; m = m->next) {
223 + if (favor && !m->mode)
224 + m->mode = favor;
225 +
226 if (m->mode == 0)
227 size = fill_conflict_hunk(xe1, name1, xe2, name2,
228 size, i, style, m, dest);
@@ -391,6 +395,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
395 int i0, i1, i2, chg0, chg1, chg2;
396 int level = flags & XDL_MERGE_LEVEL_MASK;
397 int style = flags & XDL_MERGE_STYLE_MASK;
398 + int favor = XDL_MERGE_FAVOR(flags);
399
400 if (style == XDL_MERGE_DIFF3) {
401 /*
@@ -523,14 +528,14 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
528 /* output */
529 if (result) {
530 int size = xdl_fill_merge_buffer(xe1, name1, xe2, name2,
526 - changes, NULL, style);
531 + favor, changes, NULL, style);
532 result->ptr = xdl_malloc(size);
533 if (!result->ptr) {
534 xdl_cleanup_merge(changes);
535 return -1;
536 }
537 result->size = size;
533 - xdl_fill_merge_buffer(xe1, name1, xe2, name2, changes,
538 + xdl_fill_merge_buffer(xe1, name1, xe2, name2, favor, changes,
539 result->ptr, style);
540 }
541 return xdl_cleanup_merge(changes);