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 ca456b3c8..50d020c57 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 @@ public void testCyclicMacros() throws Exception { 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 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 3bf4179e7..8d928e374 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 @@ public Attributes getAttributes() throws IOException { 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 @@ private void mergeInfoAttributes(String entryPath, boolean isDirectory, * 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 @@ private void mergeInfoAttributes(String entryPath, boolean isDirectory, * @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 @@ private void mergePerDirectoryEntryAttributes(String entryPath, 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); }