Merge "Use relative paths for attribute rule matching"
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java
index ca456b3..50d020c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java
@@ -254,6 +254,33 @@
 		endWalk();
 	}
 
+	@Test
+	public void testRelativePaths() throws Exception {
+		setupRepo("sub/ global", "sub/** init",
+				"sub/** top_sub\n*.txt top",
+				"sub/** subsub\nsub/ subsub2\n*.txt foo");
+		// The last two sub/** and sub/ rules are in sub/.gitattributes. They
+		// must not apply to any of the files here. They would match for a
+		// further subdirectory sub/sub.
+		walk = beginWalk();
+		assertIteration(F, ".gitattributes");
+		assertIteration(D, "sub", attrs("global"));
+		assertIteration(F, "sub/.gitattributes", attrs("init top_sub global"));
+		assertIteration(F, "sub/a.txt", attrs("init foo top top_sub global"));
+		endWalk();
+		// All right, let's see that they *do* apply in sub/sub:
+		writeTrashFile("sub/sub/b.txt", "b");
+		walk = beginWalk();
+		assertIteration(F, ".gitattributes");
+		assertIteration(D, "sub", attrs("global"));
+		assertIteration(F, "sub/.gitattributes", attrs("init top_sub global"));
+		assertIteration(F, "sub/a.txt", attrs("init foo top top_sub global"));
+		assertIteration(D, "sub/sub", attrs("init subsub2 top_sub global"));
+		assertIteration(F, "sub/sub/b.txt",
+				attrs("init foo subsub2 subsub top top_sub global"));
+		endWalk();
+	}
+
 	private static Collection<Attribute> attrs(String s) {
 		return new AttributesRule("*", s).getAttributes();
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java
index 3bf4179..8d928e3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/attributes/AttributesHandler.java
@@ -144,7 +144,8 @@
 		mergeInfoAttributes(entryPath, isDirectory, attributes);
 
 		// Gets the attributes located on the current entry path
-		mergePerDirectoryEntryAttributes(entryPath, isDirectory,
+		mergePerDirectoryEntryAttributes(entryPath, entryPath.lastIndexOf('/'),
+				isDirectory,
 				treeWalk.getTree(WorkingTreeIterator.class),
 				treeWalk.getTree(DirCacheIterator.class),
 				treeWalk.getTree(CanonicalTreeParser.class),
@@ -206,6 +207,8 @@
 	 *            the path to test. The path must be relative to this attribute
 	 *            node's own repository path, and in repository path format
 	 *            (uses '/' and not '\').
+	 * @param nameRoot
+	 *            index of the '/' preceeding the current level, or -1 if none
 	 * @param isDirectory
 	 *            true if the target item is a directory.
 	 * @param workingTreeIterator
@@ -217,7 +220,7 @@
 	 * @throws IOException
 	 */
 	private void mergePerDirectoryEntryAttributes(String entryPath,
-			boolean isDirectory,
+			int nameRoot, boolean isDirectory,
 			@Nullable WorkingTreeIterator workingTreeIterator,
 			@Nullable DirCacheIterator dirCacheIterator,
 			@Nullable CanonicalTreeParser otherTree, Attributes result)
@@ -228,9 +231,12 @@
 			AttributesNode attributesNode = attributesNode(
 					treeWalk, workingTreeIterator, dirCacheIterator, otherTree);
 			if (attributesNode != null) {
-				mergeAttributes(attributesNode, entryPath, isDirectory, result);
+				mergeAttributes(attributesNode,
+						entryPath.substring(nameRoot + 1), isDirectory,
+						result);
 			}
-			mergePerDirectoryEntryAttributes(entryPath, isDirectory,
+			mergePerDirectoryEntryAttributes(entryPath,
+					entryPath.lastIndexOf('/', nameRoot - 1), isDirectory,
 					parentOf(workingTreeIterator), parentOf(dirCacheIterator),
 					parentOf(otherTree), result);
 		}