/*
  * Built-in low-levels
  */
+static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
+                          const char *path_unused,
+                          mmfile_t *orig,
+                          mmfile_t *src1, const char *name1,
+                          mmfile_t *src2, const char *name2,
+                          mmbuffer_t *result)
+{
+       /*
+        * The tentative merge result is "ours" for the final round,
+        * or common ancestor for an internal merge.  Still return
+        * "conflicted merge" status.
+        */
+       mmfile_t *stolen = index_only ? orig : src1;
+
+       result->ptr = stolen->ptr;
+       result->size = stolen->size;
+       stolen->ptr = NULL;
+       return 1;
+}
+
 static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
                        const char *path_unused,
                        mmfile_t *orig,
        xpparam_t xpp;
 
        if (buffer_is_binary(orig->ptr, orig->size) ||
-                       buffer_is_binary(src1->ptr, src1->size) ||
-                       buffer_is_binary(src2->ptr, src2->size))
-               return error("Cannot merge binary files: %s vs. %s\n",
+           buffer_is_binary(src1->ptr, src1->size) ||
+           buffer_is_binary(src2->ptr, src2->size)) {
+               warning("Cannot merge binary files: %s vs. %s\n",
                        name1, name2);
+               return ll_binary_merge(drv_unused, path_unused,
+                                      orig, src1, name1,
+                                      src2, name2,
+                                      result);
+       }
 
        memset(&xpp, 0, sizeof(xpp));
        return xdl_merge(orig,
        return 0;
 }
 
-static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
-                          const char *path_unused,
-                          mmfile_t *orig,
-                          mmfile_t *src1, const char *name1,
-                          mmfile_t *src2, const char *name2,
-                          mmbuffer_t *result)
-{
-       /*
-        * The tentative merge result is "ours" for the final round,
-        * or common ancestor for an internal merge.  Still return
-        * "conflicted merge" status.
-        */
-       mmfile_t *stolen = index_only ? orig : src1;
-
-       result->ptr = stolen->ptr;
-       result->size = stolen->size;
-       stolen->ptr = NULL;
-       return 1;
-}
-
 #define LL_BINARY_MERGE 0
 #define LL_TEXT_MERGE 1
 #define LL_UNION_MERGE 2
 
--- /dev/null
+#!/bin/sh
+
+test_description='ask merge-recursive to merge binary files'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+       cat ../test4012.png >m &&
+       git add m &&
+       git ls-files -s | sed -e "s/ 0  / 1     /" >E1 &&
+       test_tick &&
+       git commit -m "initial" &&
+
+       git branch side &&
+       echo frotz >a &&
+       git add a &&
+       echo nitfol >>m &&
+       git add a m &&
+       git ls-files -s a >E0 &&
+       git ls-files -s m | sed -e "s/ 0        / 3     /" >E3 &&
+       test_tick &&
+       git commit -m "master adds some" &&
+
+       git checkout side &&
+       echo rezrov >>m &&
+       git add m &&
+       git ls-files -s m | sed -e "s/ 0        / 2     /" >E2 &&
+       test_tick &&
+       git commit -m "side modifies" &&
+
+       git tag anchor &&
+
+       cat E0 E1 E2 E3 >expect
+'
+
+test_expect_success resolve '
+
+       rm -f a* m* &&
+       git reset --hard anchor &&
+
+       if git merge -s resolve master
+       then
+               echo Oops, should not have succeeded
+               false
+       else
+               git ls-files -s >current
+               diff -u current expect
+       fi
+'
+
+test_expect_success recursive '
+
+       rm -f a* m* &&
+       git reset --hard anchor &&
+
+       if git merge -s recursive master
+       then
+               echo Oops, should not have succeeded
+               false
+       else
+               git ls-files -s >current
+               diff -u current expect
+       fi
+'
+
+test_done