diff --git a/attr.c b/attr.c
index 7435d927a9..ed4db01a89 100644
--- a/attr.c
+++ b/attr.c
@@ -378,3 +378,21 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)
 		rem = fill(path, pathlen, stk, check, num, rem);
 	return 0;
 }
+
+static void setup_binary_check(struct git_attr_check *check)
+{
+	static struct git_attr *attr_binary;
+
+	if (!attr_binary)
+		attr_binary = git_attr("binary", 6);
+	check->attr = attr_binary;
+}
+
+int git_path_is_binary(const char *path)
+{
+	struct git_attr_check attr_binary_check;
+
+	setup_binary_check(&attr_binary_check);
+	return (!git_checkattr(path, 1, &attr_binary_check) &&
+		(0 < attr_binary_check.isset));
+}
diff --git a/convert.c b/convert.c
index 898bfe3eb2..20c744aa23 100644
--- a/convert.c
+++ b/convert.c
@@ -1,4 +1,6 @@
 #include "cache.h"
+#include "attr.h"
+
 /*
  * convert.c - convert a file when checking it out and checking it in.
  *
@@ -72,17 +74,12 @@ static int is_binary(unsigned long size, struct text_stat *stats)
 	return 0;
 }
 
-int convert_to_git(const char *path, char **bufp, unsigned long *sizep)
+static int autocrlf_to_git(const char *path, char **bufp, unsigned long *sizep)
 {
 	char *buffer, *nbuf;
 	unsigned long size, nsize;
 	struct text_stat stats;
 
-	/*
-	 * FIXME! Other pluggable conversions should go here,
-	 * based on filename patterns. Right now we just do the
-	 * stupid auto-CRLF one.
-	 */
 	if (!auto_crlf)
 		return 0;
 
@@ -128,7 +125,7 @@ int convert_to_git(const char *path, char **bufp, unsigned long *sizep)
 	return 1;
 }
 
-int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep)
+static int autocrlf_to_working_tree(const char *path, char **bufp, unsigned long *sizep)
 {
 	char *buffer, *nbuf;
 	unsigned long size, nsize;
@@ -184,3 +181,41 @@ int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep)
 
 	return 1;
 }
+
+static void setup_crlf_check(struct git_attr_check *check)
+{
+	static struct git_attr *attr_crlf;
+
+	if (!attr_crlf)
+		attr_crlf = git_attr("crlf", 4);
+	check->attr = attr_crlf;
+}
+
+static int git_path_is_binary(const char *path)
+{
+	struct git_attr_check attr_crlf_check;
+
+	setup_crlf_check(&attr_crlf_check);
+
+	/*
+	 * If crlf is not mentioned, default to autocrlf;
+	 * disable autocrlf only when crlf attribute is explicitly
+	 * unset.
+	 */
+	return (!git_checkattr(path, 1, &attr_crlf_check) &&
+		(0 == attr_crlf_check.isset));
+}
+
+int convert_to_git(const char *path, char **bufp, unsigned long *sizep)
+{
+	if (git_path_is_binary(path))
+		return 0;
+	return autocrlf_to_git(path, bufp, sizep);
+}
+
+int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep)
+{
+	if (git_path_is_binary(path))
+		return 0;
+	return autocrlf_to_working_tree(path, bufp, sizep);
+}
diff --git a/t/t0020-crlf.sh b/t/t0020-crlf.sh
index 723b29ad17..600dcd30a0 100755
--- a/t/t0020-crlf.sh
+++ b/t/t0020-crlf.sh
@@ -214,4 +214,28 @@ test_expect_success 'apply patch --index (autocrlf=true)' '
 	}
 '
 
+test_expect_success '.gitattributes says two is binary' '
+
+	echo "two !crlf" >.gitattributes &&
+	rm -f tmp one dir/two &&
+	git repo-config core.autocrlf true &&
+	git read-tree --reset -u HEAD &&
+
+	if remove_cr dir/two >/dev/null
+	then
+		echo "Huh?"
+		false
+	else
+		: happy
+	fi &&
+
+	if remove_cr one >/dev/null
+	then
+		: happy
+	else
+		echo "Huh?"
+		false
+	fi
+'
+
 test_done