aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/gitattributes.txt2
-rw-r--r--Documentation/merge-strategies.txt3
-rw-r--r--attr.c2
-rw-r--r--ll-merge.c32
-rwxr-xr-xt/t6037-merge-ours-theirs.sh14
5 files changed, 41 insertions, 12 deletions
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index e16f3e175..462b79c12 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -927,7 +927,7 @@ file at the toplevel (i.e. not in any subdirectory). The built-in
macro attribute "binary" is equivalent to:
------------
-[attr]binary -diff -text
+[attr]binary -diff -merge -text
------------
diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt
index 595a3cf1a..66db80296 100644
--- a/Documentation/merge-strategies.txt
+++ b/Documentation/merge-strategies.txt
@@ -32,13 +32,14 @@ ours;;
This option forces conflicting hunks to be auto-resolved cleanly by
favoring 'our' version. Changes from the other tree that do not
conflict with our side are reflected to the merge result.
+ For a binary file, the entire contents are taken from our side.
+
This should not be confused with the 'ours' merge strategy, which does not
even look at what the other tree contains at all. It discards everything
the other tree did, declaring 'our' history contains all that happened in it.
theirs;;
- This is opposite of 'ours'.
+ This is the opposite of 'ours'.
patience;;
With this option, 'merge-recursive' spends a little extra time
diff --git a/attr.c b/attr.c
index f12c83f80..3430faf2c 100644
--- a/attr.c
+++ b/attr.c
@@ -306,7 +306,7 @@ static void free_attr_elem(struct attr_stack *e)
}
static const char *builtin_attr[] = {
- "[attr]binary -diff -text",
+ "[attr]binary -diff -merge -text",
NULL,
};
diff --git a/ll-merge.c b/ll-merge.c
index f3f769215..acea33bf1 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -35,7 +35,7 @@ struct ll_merge_driver {
*/
static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
mmbuffer_t *result,
- const char *path_unused,
+ const char *path,
mmfile_t *orig, const char *orig_name,
mmfile_t *src1, const char *name1,
mmfile_t *src2, const char *name2,
@@ -46,16 +46,34 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
assert(opts);
/*
- * The tentative merge result is "ours" for the final round,
- * or common ancestor for an internal merge. Still return
- * "conflicted merge" status.
+ * The tentative merge result is the or common ancestor for an internal merge.
*/
- stolen = opts->virtual_ancestor ? orig : src1;
+ if (opts->virtual_ancestor) {
+ stolen = orig;
+ } else {
+ switch (opts->variant) {
+ default:
+ warning("Cannot merge binary files: %s (%s vs. %s)",
+ path, name1, name2);
+ /* fallthru */
+ case XDL_MERGE_FAVOR_OURS:
+ stolen = src1;
+ break;
+ case XDL_MERGE_FAVOR_THEIRS:
+ stolen = src2;
+ break;
+ }
+ }
result->ptr = stolen->ptr;
result->size = stolen->size;
stolen->ptr = NULL;
- return 1;
+
+ /*
+ * With -Xtheirs or -Xours, we have cleanly merged;
+ * otherwise we got a conflict.
+ */
+ return (opts->variant ? 0 : 1);
}
static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
@@ -73,8 +91,6 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
if (buffer_is_binary(orig->ptr, orig->size) ||
buffer_is_binary(src1->ptr, src1->size) ||
buffer_is_binary(src2->ptr, src2->size)) {
- warning("Cannot merge binary files: %s (%s vs. %s)",
- path, name1, name2);
return ll_binary_merge(drv_unused, result,
path,
orig, orig_name,
diff --git a/t/t6037-merge-ours-theirs.sh b/t/t6037-merge-ours-theirs.sh
index 2cf42c73f..3889eca4a 100755
--- a/t/t6037-merge-ours-theirs.sh
+++ b/t/t6037-merge-ours-theirs.sh
@@ -53,7 +53,19 @@ test_expect_success 'recursive favouring ours' '
! grep 1 file
'
-test_expect_success 'pull with -X' '
+test_expect_success 'binary file with -Xours/-Xtheirs' '
+ echo file binary >.gitattributes &&
+
+ git reset --hard master &&
+ git merge -s recursive -X theirs side &&
+ git diff --exit-code side HEAD -- file &&
+
+ git reset --hard master &&
+ git merge -s recursive -X ours side &&
+ git diff --exit-code master HEAD -- file
+'
+
+test_expect_success 'pull passes -X to underlying merge' '
git reset --hard master && git pull -s recursive -Xours . side &&
git reset --hard master && git pull -s recursive -X ours . side &&
git reset --hard master && git pull -s recursive -Xtheirs . side &&