Merge "Revert "Adds FilteredRevCommit that can overwrites its parents in the DAG.""
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java
index f807889..204c89d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java
@@ -301,4 +301,25 @@ public void testFilesShouldBeCleanedInSubSubFolders()
writeTrashFile("this_is/not_ok/more/subdirs/file.txt", "2");
git.clean().setCleanDirectories(true).setIgnore(false).call();
}
+
+ @Test
+ public void testPrefix() throws Exception {
+ File a = writeTrashFile("a.txt", "a");
+ File b = writeTrashFile("a/a.txt", "sub a");
+ File dir = b.getParentFile();
+ git.clean().call();
+ assertFalse(a.exists());
+ assertTrue(dir.exists());
+ assertTrue(b.exists());
+ }
+
+ @Test
+ public void testPrefixWithDir() throws Exception {
+ File a = writeTrashFile("a.txt", "a");
+ File b = writeTrashFile("a/a.txt", "sub a");
+ File dir = b.getParentFile();
+ git.clean().setCleanDirectories(true).call();
+ assertFalse(a.exists());
+ assertFalse(dir.exists());
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java
index f47f447..b175ead 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java
@@ -13,50 +13,88 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import java.util.Iterator;
+
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.blame.BlameGenerator;
import org.eclipse.jgit.blame.BlameResult;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.merge.MergeStrategy;
+import org.eclipse.jgit.revwalk.FilteredRevCommit;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
import org.junit.Test;
/** Unit tests of {@link BlameGenerator}. */
public class BlameGeneratorTest extends RepositoryTestCase {
+
+ public static final String OTHER_FILE = "other_file.txt";
+
+ public static final String INTERESTING_FILE = "interesting_file.txt";
+
@Test
- public void testBoundLineDelete() throws Exception {
- try (Git git = new Git(db)) {
- String[] content1 = new String[] { "first", "second" };
- writeTrashFile("file.txt", join(content1));
- git.add().addFilepattern("file.txt").call();
+ public void testSingleBlame() throws Exception {
+
+ /**
+ * <pre>
+ * (ts) OTHER_FILE INTERESTING_FILE
+ * 1 a
+ * 2 a, b
+ * 3 1, 2 c1 <--
+ * 4 a, b, c |
+ * 5 1, 2, 3 c2---
+ * </pre>
+ */
+ try (Git git = new Git(db);
+ RevWalk revWalk = new RevWalk(git.getRepository())) {
+ writeTrashFile(OTHER_FILE, join("a"));
+ git.add().addFilepattern(OTHER_FILE).call();
+ git.commit().setMessage("create file").call();
+
+ writeTrashFile(OTHER_FILE, join("a", "b"));
+ git.add().addFilepattern(OTHER_FILE).call();
+ git.commit().setMessage("amend file").call();
+
+ writeTrashFile(INTERESTING_FILE, join("1", "2"));
+ git.add().addFilepattern(INTERESTING_FILE).call();
RevCommit c1 = git.commit().setMessage("create file").call();
- String[] content2 = new String[] { "third", "first", "second" };
- writeTrashFile("file.txt", join(content2));
- git.add().addFilepattern("file.txt").call();
- RevCommit c2 = git.commit().setMessage("create file").call();
+ writeTrashFile(OTHER_FILE, join("a", "b", "c"));
+ git.add().addFilepattern(OTHER_FILE).call();
+ git.commit().setMessage("amend file").call();
- try (BlameGenerator generator = new BlameGenerator(db, "file.txt")) {
- generator.push(null, db.resolve(Constants.HEAD));
+ writeTrashFile(INTERESTING_FILE, join("1", "2", "3"));
+ git.add().addFilepattern(INTERESTING_FILE).call();
+ RevCommit c2 = git.commit().setMessage("amend file").call();
+
+ RevCommit filteredC1 = new FilteredRevCommit(c1);
+ RevCommit filteredC2 = new FilteredRevCommit(c2, filteredC1);
+
+ revWalk.parseHeaders(filteredC2);
+
+ try (BlameGenerator generator = new BlameGenerator(db,
+ INTERESTING_FILE)) {
+ generator.push(filteredC2);
assertEquals(3, generator.getResultContents().size());
assertTrue(generator.next());
assertEquals(c2, generator.getSourceCommit());
assertEquals(1, generator.getRegionLength());
- assertEquals(0, generator.getResultStart());
- assertEquals(1, generator.getResultEnd());
- assertEquals(0, generator.getSourceStart());
- assertEquals(1, generator.getSourceEnd());
- assertEquals("file.txt", generator.getSourcePath());
+ assertEquals(2, generator.getResultStart());
+ assertEquals(3, generator.getResultEnd());
+ assertEquals(2, generator.getSourceStart());
+ assertEquals(3, generator.getSourceEnd());
+ assertEquals(INTERESTING_FILE, generator.getSourcePath());
assertTrue(generator.next());
assertEquals(c1, generator.getSourceCommit());
assertEquals(2, generator.getRegionLength());
- assertEquals(1, generator.getResultStart());
- assertEquals(3, generator.getResultEnd());
+ assertEquals(0, generator.getResultStart());
+ assertEquals(2, generator.getResultEnd());
assertEquals(0, generator.getSourceStart());
assertEquals(2, generator.getSourceEnd());
- assertEquals("file.txt", generator.getSourcePath());
+ assertEquals(INTERESTING_FILE, generator.getSourcePath());
assertFalse(generator.next());
}
@@ -64,6 +102,242 @@ public void testBoundLineDelete() throws Exception {
}
@Test
+ public void testMergeSingleBlame() throws Exception {
+ try (Git git = new Git(db);
+ RevWalk revWalk = new RevWalk(git.getRepository())) {
+
+ /**
+ *
+ *
+ * <pre>
+ * refs/heads/master
+ * A
+ * / \ refs/heads/side
+ * / ----------------> side
+ * / |
+ * merge <-------------------
+ * </pre>
+ */
+
+ writeTrashFile(INTERESTING_FILE, join("1", "2"));
+ git.add().addFilepattern(INTERESTING_FILE).call();
+ RevCommit c1 = git.commit().setMessage("create file").call();
+
+ createBranch(c1, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+ writeTrashFile(INTERESTING_FILE, join("1", "2", "3", "4"));
+ git.add().addFilepattern(INTERESTING_FILE).call();
+ RevCommit sideCommit = git.commit()
+ .setMessage("amend file in another branch").call();
+
+ checkoutBranch("refs/heads/master");
+ git.merge().setMessage("merge").include(sideCommit)
+ .setStrategy(MergeStrategy.RESOLVE).call();
+
+ Iterator<RevCommit> it = git.log().call().iterator();
+ RevCommit mergeCommit = it.next();
+
+ RevCommit filteredC1 = new FilteredRevCommit(c1);
+ RevCommit filteredSide = new FilteredRevCommit(sideCommit,
+ filteredC1);
+ RevCommit filteredMerge = new FilteredRevCommit(mergeCommit,
+ filteredSide, filteredC1);
+
+ revWalk.parseHeaders(filteredMerge);
+
+ try (BlameGenerator generator = new BlameGenerator(db,
+ INTERESTING_FILE)) {
+ generator.push(filteredMerge);
+ assertEquals(4, generator.getResultContents().size());
+
+ assertTrue(generator.next());
+ assertEquals(mergeCommit, generator.getSourceCommit());
+ assertEquals(2, generator.getRegionLength());
+ assertEquals(2, generator.getResultStart());
+ assertEquals(4, generator.getResultEnd());
+ assertEquals(2, generator.getSourceStart());
+ assertEquals(4, generator.getSourceEnd());
+ assertEquals(INTERESTING_FILE, generator.getSourcePath());
+
+ assertTrue(generator.next());
+ assertEquals(filteredC1, generator.getSourceCommit());
+ assertEquals(2, generator.getRegionLength());
+ assertEquals(0, generator.getResultStart());
+ assertEquals(2, generator.getResultEnd());
+ assertEquals(0, generator.getSourceStart());
+ assertEquals(2, generator.getSourceEnd());
+ assertEquals(INTERESTING_FILE, generator.getSourcePath());
+
+ assertFalse(generator.next());
+ }
+ }
+ }
+
+ @Test
+ public void testMergeBlame() throws Exception {
+ try (Git git = new Git(db);
+ RevWalk revWalk = new RevWalk(git.getRepository())) {
+
+ /**
+ *
+ *
+ * <pre>
+ * refs/heads/master
+ * A
+ * / \ refs/heads/side
+ * B ----------------> side
+ * / |
+ * merge <-------------------
+ * </pre>
+ */
+ writeTrashFile(INTERESTING_FILE, join("1", "2"));
+ git.add().addFilepattern(INTERESTING_FILE).call();
+ RevCommit c1 = git.commit().setMessage("create file").call();
+
+ createBranch(c1, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+ writeTrashFile(INTERESTING_FILE, join("1", "2", "3"));
+ git.add().addFilepattern(INTERESTING_FILE).call();
+ RevCommit sideCommit = git.commit().setMessage("amend file").call();
+
+ checkoutBranch("refs/heads/master");
+ writeTrashFile(INTERESTING_FILE, join("1", "2", "4"));
+ git.add().addFilepattern(INTERESTING_FILE).call();
+ RevCommit c2 = git.commit().setMessage("delete and amend file")
+ .call();
+
+ git.merge().setMessage("merge").include(sideCommit)
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ writeTrashFile(INTERESTING_FILE, join("1", "2", "3", "4"));
+ git.add().addFilepattern(INTERESTING_FILE).call();
+ RevCommit mergeCommit = git.commit().setMessage("merge commit")
+ .call();
+
+ RevCommit filteredC1 = new FilteredRevCommit(c1);
+ RevCommit filteredSide = new FilteredRevCommit(sideCommit,
+ filteredC1);
+ RevCommit filteredC2 = new FilteredRevCommit(c2, filteredC1);
+
+ RevCommit filteredMerge = new FilteredRevCommit(mergeCommit,
+ filteredSide, filteredC2);
+
+ revWalk.parseHeaders(filteredMerge);
+
+ try (BlameGenerator generator = new BlameGenerator(db,
+ INTERESTING_FILE)) {
+ generator.push(filteredMerge);
+ assertEquals(4, generator.getResultContents().size());
+
+ assertTrue(generator.next());
+ assertEquals(filteredC2, generator.getSourceCommit());
+ assertEquals(1, generator.getRegionLength());
+ assertEquals(3, generator.getResultStart());
+ assertEquals(4, generator.getResultEnd());
+ assertEquals(2, generator.getSourceStart());
+ assertEquals(3, generator.getSourceEnd());
+ assertEquals(INTERESTING_FILE, generator.getSourcePath());
+
+ assertTrue(generator.next());
+ assertEquals(filteredSide, generator.getSourceCommit());
+ assertEquals(1, generator.getRegionLength());
+ assertEquals(2, generator.getResultStart());
+ assertEquals(3, generator.getResultEnd());
+ assertEquals(2, generator.getSourceStart());
+ assertEquals(3, generator.getSourceEnd());
+ assertEquals(INTERESTING_FILE, generator.getSourcePath());
+
+ assertTrue(generator.next());
+ assertEquals(filteredC1, generator.getSourceCommit());
+ assertEquals(2, generator.getRegionLength());
+ assertEquals(0, generator.getResultStart());
+ assertEquals(2, generator.getResultEnd());
+ assertEquals(0, generator.getSourceStart());
+ assertEquals(2, generator.getSourceEnd());
+ assertEquals(INTERESTING_FILE, generator.getSourcePath());
+
+ assertFalse(generator.next());
+ }
+ }
+ }
+
+ @Test
+ public void testSingleBlame_compareWithWalk() throws Exception {
+ /**
+ * <pre>
+ * (ts) OTHER_FILE INTERESTING_FILE
+ * 1 a
+ * 2 a, b
+ * 3 1, 2 c1 <--
+ * 4 a, b, c |
+ * 6 3, 1, 2 c2---
+ * </pre>
+ */
+ try (Git git = new Git(db);
+ RevWalk revWalk = new RevWalk(git.getRepository())) {
+ writeTrashFile(OTHER_FILE, join("a"));
+ git.add().addFilepattern(OTHER_FILE).call();
+ git.commit().setMessage("create file").call();
+
+ writeTrashFile(OTHER_FILE, join("a", "b"));
+ git.add().addFilepattern(OTHER_FILE).call();
+ git.commit().setMessage("amend file").call();
+
+ writeTrashFile(INTERESTING_FILE, join("1", "2"));
+ git.add().addFilepattern(INTERESTING_FILE).call();
+ RevCommit c1 = git.commit().setMessage("create file").call();
+
+ writeTrashFile(OTHER_FILE, join("a", "b", "c"));
+ git.add().addFilepattern(OTHER_FILE).call();
+ git.commit().setMessage("amend file").call();
+
+ writeTrashFile(INTERESTING_FILE, join("3", "1", "2"));
+ git.add().addFilepattern(INTERESTING_FILE).call();
+ RevCommit c2 = git.commit().setMessage("prepend").call();
+
+ RevCommit filteredC1 = new FilteredRevCommit(c1);
+ RevCommit filteredC2 = new FilteredRevCommit(c2, filteredC1);
+
+ revWalk.parseHeaders(filteredC2);
+
+ try (BlameGenerator g1 = new BlameGenerator(db, INTERESTING_FILE);
+ BlameGenerator g2 = new BlameGenerator(db,
+ INTERESTING_FILE)) {
+ g1.push(null, c2);
+ g2.push(null, filteredC2);
+
+ assertEquals(g1.getResultContents().size(),
+ g2.getResultContents().size()); // 3
+
+ assertTrue(g1.next());
+ assertTrue(g2.next());
+
+ assertEquals(g1.getSourceCommit(), g2.getSourceCommit()); // c2
+ assertEquals(INTERESTING_FILE, g1.getSourcePath());
+ assertEquals(g1.getRegionLength(), g2.getRegionLength()); // 1
+ assertEquals(g1.getResultStart(), g2.getResultStart()); // 0
+ assertEquals(g1.getResultEnd(), g2.getResultEnd()); // 1
+ assertEquals(g1.getSourceStart(), g2.getSourceStart()); // 0
+ assertEquals(g1.getSourceEnd(), g2.getSourceEnd()); // 1
+ assertEquals(g1.getSourcePath(), g2.getSourcePath()); // INTERESTING_FILE
+
+ assertTrue(g1.next());
+ assertTrue(g2.next());
+
+ assertEquals(g1.getSourceCommit(), g2.getSourceCommit()); // c1
+ assertEquals(g1.getRegionLength(), g2.getRegionLength()); // 2
+ assertEquals(g1.getResultStart(), g2.getResultStart()); // 1
+ assertEquals(g1.getResultEnd(), g2.getResultEnd()); // 3
+ assertEquals(g1.getSourceStart(), g2.getSourceStart()); // 0
+ assertEquals(g1.getSourceEnd(), g2.getSourceEnd()); // 2
+ assertEquals(g1.getSourcePath(), g2.getSourcePath()); // INTERESTING_FILE
+
+ assertFalse(g1.next());
+ assertFalse(g2.next());
+ }
+ }
+ }
+
+ @Test
public void testRenamedBoundLineDelete() throws Exception {
try (Git git = new Git(db)) {
final String FILENAME_1 = "subdir/file1.txt";
@@ -87,7 +361,8 @@ public void testRenamedBoundLineDelete() throws Exception {
git.add().addFilepattern(FILENAME_2).call();
RevCommit c2 = git.commit().setMessage("change file2").call();
- try (BlameGenerator generator = new BlameGenerator(db, FILENAME_2)) {
+ try (BlameGenerator generator = new BlameGenerator(db,
+ FILENAME_2)) {
generator.push(null, db.resolve(Constants.HEAD));
assertEquals(3, generator.getResultContents().size());
@@ -113,7 +388,8 @@ public void testRenamedBoundLineDelete() throws Exception {
}
// and test again with other BlameGenerator API:
- try (BlameGenerator generator = new BlameGenerator(db, FILENAME_2)) {
+ try (BlameGenerator generator = new BlameGenerator(db,
+ FILENAME_2)) {
generator.push(null, db.resolve(Constants.HEAD));
BlameResult result = generator.computeBlameResult();
@@ -136,21 +412,22 @@ public void testLinesAllDeletedShortenedWalk() throws Exception {
try (Git git = new Git(db)) {
String[] content1 = new String[] { "first", "second", "third" };
- writeTrashFile("file.txt", join(content1));
- git.add().addFilepattern("file.txt").call();
+ writeTrashFile(INTERESTING_FILE, join(content1));
+ git.add().addFilepattern(INTERESTING_FILE).call();
git.commit().setMessage("create file").call();
String[] content2 = new String[] { "" };
- writeTrashFile("file.txt", join(content2));
- git.add().addFilepattern("file.txt").call();
+ writeTrashFile(INTERESTING_FILE, join(content2));
+ git.add().addFilepattern(INTERESTING_FILE).call();
git.commit().setMessage("create file").call();
- writeTrashFile("file.txt", join(content1));
- git.add().addFilepattern("file.txt").call();
+ writeTrashFile(INTERESTING_FILE, join(content1));
+ git.add().addFilepattern(INTERESTING_FILE).call();
RevCommit c3 = git.commit().setMessage("create file").call();
- try (BlameGenerator generator = new BlameGenerator(db, "file.txt")) {
+ try (BlameGenerator generator = new BlameGenerator(db,
+ INTERESTING_FILE)) {
generator.push(null, db.resolve(Constants.HEAD));
assertEquals(3, generator.getResultContents().size());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/PathsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/PathsTest.java
index c697688..2fae909 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/PathsTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/PathsTest.java
@@ -13,7 +13,9 @@
import static org.eclipse.jgit.util.Paths.compare;
import static org.eclipse.jgit.util.Paths.compareSameName;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
@@ -32,6 +34,23 @@ public void testStripTrailingSeparator() {
}
@Test
+ public void testPrefix() {
+ assertTrue(Paths.isEqualOrPrefix("a", "a"));
+ assertTrue(Paths.isEqualOrPrefix("a", "a/b"));
+ assertTrue(Paths.isEqualOrPrefix("a", "a/a.txt"));
+ assertFalse(Paths.isEqualOrPrefix("a", "ab"));
+ assertFalse(Paths.isEqualOrPrefix("a", "a.txt"));
+ assertFalse(Paths.isEqualOrPrefix("a", "b/a.txt"));
+ assertFalse(Paths.isEqualOrPrefix("a", "b/a"));
+ assertFalse(Paths.isEqualOrPrefix("a", "ab/a.txt"));
+ assertFalse(Paths.isEqualOrPrefix("", "a"));
+ assertTrue(Paths.isEqualOrPrefix("", ""));
+ assertTrue(Paths.isEqualOrPrefix("a/b", "a/b"));
+ assertTrue(Paths.isEqualOrPrefix("a/b", "a/b/c"));
+ assertFalse(Paths.isEqualOrPrefix("a/b", "a/bc"));
+ }
+
+ @Test
public void testPathCompare() {
byte[] a = Constants.encode("afoo/bar.c");
byte[] b = Constants.encode("bfoo/bar.c");
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index 8aa84f3..4af7adc 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -83,4 +83,11 @@
</message_arguments>
</filter>
</resource>
+ <resource path="src/org/eclipse/jgit/util/Paths.java" type="org.eclipse.jgit.util.Paths">
+ <filter id="337768515">
+ <message_arguments>
+ <message_argument value="org.eclipse.jgit.util.Paths"/>
+ </message_arguments>
+ </filter>
+ </resource>
</component>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java
index 69272b7..36ca97d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java
@@ -25,6 +25,7 @@
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.Paths;
/**
* Remove untracked files from the working tree
@@ -91,15 +92,16 @@ public Set<String> call() throws NoWorkTreeException, GitAPIException {
Set<String> notIgnoredDirs = filterIgnorePaths(untrackedDirs,
status.getIgnoredNotInIndex(), false);
- for (String file : notIgnoredFiles)
+ for (String file : notIgnoredFiles) {
if (paths.isEmpty() || paths.contains(file)) {
files = cleanPath(file, files);
}
-
- for (String dir : notIgnoredDirs)
+ }
+ for (String dir : notIgnoredDirs) {
if (paths.isEmpty() || paths.contains(dir)) {
files = cleanPath(dir, files);
}
+ }
} catch (IOException e) {
throw new JGitInternalException(e.getMessage(), e);
} finally {
@@ -142,14 +144,14 @@ private Set<String> cleanPath(String path, Set<String> inFiles)
FileUtils.delete(curFile, FileUtils.RECURSIVE
| FileUtils.SKIP_MISSING);
}
- inFiles.add(path + "/"); //$NON-NLS-1$
+ inFiles.add(path + '/');
}
} else {
if (!dryRun) {
FileUtils.delete(curFile,
FileUtils.RECURSIVE | FileUtils.SKIP_MISSING);
}
- inFiles.add(path + "/"); //$NON-NLS-1$
+ inFiles.add(path + '/');
}
}
} else {
@@ -166,14 +168,16 @@ private Set<String> filterIgnorePaths(Set<String> inputPaths,
Set<String> ignoredNotInIndex, boolean exact) {
if (ignore) {
Set<String> filtered = new TreeSet<>(inputPaths);
- for (String path : inputPaths)
- for (String ignored : ignoredNotInIndex)
+ for (String path : inputPaths) {
+ for (String ignored : ignoredNotInIndex) {
if ((exact && path.equals(ignored))
- || (!exact && path.startsWith(ignored))) {
+ || (!exact
+ && Paths.isEqualOrPrefix(ignored, path))) {
filtered.remove(path);
break;
}
-
+ }
+ }
return filtered;
}
return inputPaths;
@@ -182,14 +186,14 @@ private Set<String> filterIgnorePaths(Set<String> inputPaths,
private Set<String> filterFolders(Set<String> untracked,
Set<String> untrackedFolders) {
Set<String> filtered = new TreeSet<>(untracked);
- for (String file : untracked)
- for (String folder : untrackedFolders)
- if (file.startsWith(folder)) {
+ for (String file : untracked) {
+ for (String folder : untrackedFolders) {
+ if (Paths.isEqualOrPrefix(folder, file)) {
filtered.remove(file);
break;
}
-
-
+ }
+ }
return filtered;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java
index 77967df..93ddfc6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java
@@ -129,6 +129,7 @@ public class BlameGenerator implements AutoCloseable {
/** Blame is currently assigned to this source. */
private Candidate outCandidate;
+
private Region outRegion;
/**
@@ -403,6 +404,35 @@ private List<RevCommit> getHeads(Repository repo, ObjectId head)
* revision (if the index is interesting), and finally the working tree copy
* (if the working tree is interesting).
*
+ * @param blameCommit
+ * ordered commits to use instead of RevWalk.
+ * @return {@code this}
+ * @throws java.io.IOException
+ * the repository cannot be read.
+ * @since 6.3
+ */
+ public BlameGenerator push(RevCommit blameCommit) throws IOException {
+ if (!find(blameCommit, resultPath)) {
+ return this;
+ }
+
+ Candidate c = new Candidate(getRepository(), blameCommit, resultPath);
+ c.sourceBlob = idBuf.toObjectId();
+ c.loadText(reader);
+ c.regionList = new Region(0, 0, c.sourceText.size());
+ remaining = c.sourceText.size();
+ push(c);
+ return this;
+ }
+
+ /**
+ * Push a candidate object onto the generator's traversal stack.
+ * <p>
+ * Candidates should be pushed in history order from oldest-to-newest.
+ * Applications should push the starting commit first, then the index
+ * revision (if the index is interesting), and finally the working tree copy
+ * (if the working tree is interesting).
+ *
* @param description
* description of the blob revision, such as "Working Tree".
* @param id
@@ -428,16 +458,7 @@ public BlameGenerator push(String description, AnyObjectId id)
}
RevCommit commit = revPool.parseCommit(id);
- if (!find(commit, resultPath))
- return this;
-
- Candidate c = new Candidate(getRepository(), commit, resultPath);
- c.sourceBlob = idBuf.toObjectId();
- c.loadText(reader);
- c.regionList = new Region(0, 0, c.sourceText.size());
- remaining = c.sourceText.size();
- push(c);
- return this;
+ return push(commit);
}
/**
@@ -605,7 +626,7 @@ public boolean next() throws IOException {
// Do not generate a tip of a reverse. The region
// survives and should not appear to be deleted.
- } else /* if (pCnt == 0) */{
+ } else /* if (pCnt == 0) */ {
// Root commit, with at least one surviving region.
// Assign the remaining blame here.
return result(n);
@@ -846,8 +867,8 @@ private boolean processMerge(Candidate n) throws IOException {
editList = new EditList(0);
} else {
p.loadText(reader);
- editList = diffAlgorithm.diff(textComparator,
- p.sourceText, n.sourceText);
+ editList = diffAlgorithm.diff(textComparator, p.sourceText,
+ n.sourceText);
}
if (editList.isEmpty()) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/Paths.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/Paths.java
index 5a39f95..ae13ef7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/Paths.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/Paths.java
@@ -18,7 +18,8 @@
*
* @since 4.2
*/
-public class Paths {
+public final class Paths {
+
/**
* Remove trailing {@code '/'} if present.
*
@@ -43,6 +44,33 @@ public static String stripTrailingSeparator(String path) {
}
/**
+ * Determines whether a git path {@code folder} is a prefix of another git
+ * path {@code path}, or the same as {@code path}. An empty {@code folder}
+ * is <em>not</em> not considered a prefix and matches only if {@code path}
+ * is also empty.
+ *
+ * @param folder
+ * a git path for a directory, without trailing slash
+ * @param path
+ * a git path
+ * @return {@code true} if {@code folder} is a directory prefix of
+ * {@code path}, or is equal to {@code path}, {@code false}
+ * otherwise
+ * @since 6.3
+ */
+ public static boolean isEqualOrPrefix(String folder, String path) {
+ if (folder.isEmpty()) {
+ return path.isEmpty();
+ }
+ boolean isPrefix = path.startsWith(folder);
+ if (isPrefix) {
+ int length = folder.length();
+ return path.length() == length || path.charAt(length) == '/';
+ }
+ return false;
+ }
+
+ /**
* Compare two paths according to Git path sort ordering rules.
*
* @param aPath
@@ -63,9 +91,8 @@ public static String stripTrailingSeparator(String path) {
* @param bMode
* mode of the second file. Trees are sorted as though
* {@code bPath[bEnd] == '/'}, even if bEnd does not exist.
- * @return <0 if {@code aPath} sorts before {@code bPath};
- * 0 if the paths are the same;
- * >0 if {@code aPath} sorts after {@code bPath}.
+ * @return <0 if {@code aPath} sorts before {@code bPath}; 0 if the paths
+ * are the same; >0 if {@code aPath} sorts after {@code bPath}.
*/
public static int compare(byte[] aPath, int aPos, int aEnd, int aMode,
byte[] bPath, int bPos, int bEnd, int bMode) {