Subject: [PATCH 8/8] tree_entry_interesting(): support negative pathspec

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Thu, 9 Sep 2010 01:50:23 +1000

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 t/t9999-test.sh |   44 ++++++++++++++++++++++++++++++++++++++++++++
 tree-walk.c     |   36 +++++++++++++++++++++++++++++++-----
 2 files changed, 75 insertions(+), 5 deletions(-)
 create mode 100755 t/t9999-test.sh

diff --git a/t/t9999-test.sh b/t/t9999-test.sh
new file mode 100755
index 0000000..535386e
--- /dev/null
+++ b/t/t9999-test.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+test_description=f
+
+. ./test-lib.sh
+
+test_expect_success setup '
+	mkdir one one/two &&
+	touch file one/file one/two/file one/zoo &&
+	git add . &&
+	git commit -m 1 &&
+	for i in file one/file one/two/file one/zoo; do echo 1 >>$i;done &&
+	git add . && git commit -m 2
+'
+
+test_expect_success 'diff' '
+	cat >expected <<-\EOF &&
+:100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 d00491fd7e5bb6fa28c517a0bb32b8b506539d4d M	one/file
+:100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 d00491fd7e5bb6fa28c517a0bb32b8b506539d4d M	one/two/file
+:100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 d00491fd7e5bb6fa28c517a0bb32b8b506539d4d M	one/zoo
+EOF
+	git diff-tree -r HEAD^ HEAD -- one >result &&
+	test_cmp expected result
+'
+
+test_expect_success 'diff one ^one/two' '
+	cat >expected <<-\EOF &&
+:100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 d00491fd7e5bb6fa28c517a0bb32b8b506539d4d M	one/file
+:100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 d00491fd7e5bb6fa28c517a0bb32b8b506539d4d M	one/zoo
+EOF
+	git diff-tree -r HEAD^ HEAD -- one ^one/two >result &&
+	test_cmp expected result
+'
+
+test_expect_success 'diff ^one/two' '
+	cat >expected <<-\EOF &&
+:100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 d00491fd7e5bb6fa28c517a0bb32b8b506539d4d M	file
+:100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 d00491fd7e5bb6fa28c517a0bb32b8b506539d4d M	one/file
+:100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 d00491fd7e5bb6fa28c517a0bb32b8b506539d4d M	one/zoo
+EOF
+	git diff-tree -r HEAD^ HEAD -- ^one/two >result &&
+	test_cmp expected result
+'
+
+test_done
diff --git a/tree-walk.c b/tree-walk.c
index a2f4a00..fd19681 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -532,7 +532,7 @@ int tree_entry_interesting(const struct name_entry *entry, const char *base, int
 
 	pathlen = tree_entry_len(entry->path, entry->sha1);
 
-	for (i = 0; i < ps->nr; i++) {
+	for (i = ps->nr-1; i >= 0; i--) {
 		const char *match = ps->info[i].path;
 		int matchlen = ps->info[i].pathlen;
 		int m = -1; /* signals that we haven't called strncmp() */
@@ -548,8 +548,18 @@ int tree_entry_interesting(const struct name_entry *entry, const char *base, int
 			 */
 			if (!matchlen ||
 			    base[matchlen] == '/' ||
-			    match[matchlen - 1] == '/')
-				return 2;
+			    match[matchlen - 1] == '/') {
+				if (!ps->info[i].has_sub_pathspec &&
+				    ps->info[i].to_exclude)
+					return -1;
+				/*
+				 * If has_sub_pathspec is 1, there is
+				 * another sub pathspec that will
+				 * negate the result. Don't return "2"
+				 * in that case.
+				 */
+				return ps->info[i].has_sub_pathspec ? 1 : 2;
+			}
 
 			/* Just a random prefix match */
 			continue;
@@ -615,8 +625,24 @@ int tree_entry_interesting(const struct name_entry *entry, const char *base, int
 		 * because we rejected the case where path is not a
 		 * leading directory and is shorter than match.
 		 */
-		if (!m)
+		if (!m) {
+			/*
+			 * If this is negative pathspec, we exclude
+			 * the path only if it's a perfect
+			 * match. Otherwise assume it's in, because
+			 * there could be a positive subpathspec,
+			 * which includes some trees again.
+			 */
+			if (ps->info[i].to_exclude)
+				return matchlen == pathlen ? 0 : 1;
 			return 1;
+		}
 	}
-	return never_interesting; /* No matches */
+
+	/*
+	 * if include_by_default is 1, all items should be included by
+	 * default, because some of them will be excluded later on by
+	 * negative pathspecs.
+	 */
+	return ps->include_by_default ? 1 : never_interesting; /* No matches */
 }
-- 
1.7.1.rc1.70.g13aff