Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java10
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java6
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Version.java5
-rw-r--r--org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java4
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java244
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java34
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java31
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java23
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java191
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryTestCase.java155
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/FileHeaderTest.java84
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcTest.java12
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchErrorTest.java10
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchTest.java18
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorWithTimeControl.java108
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java55
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java54
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java53
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java38
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java62
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java12
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java16
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityRenameDetector.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java186
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/WorkDirCheckout.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java28
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java19
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteTreeFilter.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/storage/file/UnpackedObject.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java35
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java38
35 files changed, 1245 insertions, 310 deletions
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
index 77ed73048d..ebdb74f3c7 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
@@ -153,22 +153,22 @@ class Diff extends TextBuiltin {
for (DiffEntry ent : files) {
switch (ent.getChangeType()) {
case ADD:
- out.println("A\t" + ent.getNewName());
+ out.println("A\t" + ent.getNewPath());
break;
case DELETE:
- out.println("D\t" + ent.getOldName());
+ out.println("D\t" + ent.getOldPath());
break;
case MODIFY:
- out.println("M\t" + ent.getNewName());
+ out.println("M\t" + ent.getNewPath());
break;
case COPY:
out.format("C%1$03d\t%2$s\t%3$s", ent.getScore(), //
- ent.getOldName(), ent.getNewName());
+ ent.getOldPath(), ent.getNewPath());
out.println();
break;
case RENAME:
out.format("R%1$03d\t%2$s\t%3$s", ent.getScore(), //
- ent.getOldName(), ent.getNewName());
+ ent.getOldPath(), ent.getNewPath());
out.println();
break;
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
index 48a05915e4..fbc019fa24 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
@@ -242,7 +242,7 @@ class Log extends RevWalkTextBuiltin {
String oldPath = ((FollowFilter) pathFilter).getPath();
for (DiffEntry ent : files) {
if (ent.getChangeType() == ChangeType.ADD
- && ent.getNewName().equals(oldPath))
+ && ent.getNewPath().equals(oldPath))
return true;
}
return false;
@@ -251,8 +251,8 @@ class Log extends RevWalkTextBuiltin {
private List<DiffEntry> updateFollowFilter(List<DiffEntry> files) {
String oldPath = ((FollowFilter) pathFilter).getPath();
for (DiffEntry ent : files) {
- if (isRename(ent) && ent.getNewName().equals(oldPath)) {
- pathFilter = FollowFilter.create(ent.getOldName());
+ if (isRename(ent) && ent.getNewPath().equals(oldPath)) {
+ pathFilter = FollowFilter.create(ent.getOldPath());
return Collections.singletonList(ent);
}
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Version.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Version.java
index 5bad4ef98c..9b51b871fc 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Version.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Version.java
@@ -55,4 +55,9 @@ class Version extends TextBuiltin {
out.println(MessageFormat.format(CLIText.get().jgitVersion, pkg.getImplementationVersion()));
}
+
+ @Override
+ protected final boolean requiresRepository() {
+ return false;
+ }
}
diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java
index ae9fb0ef50..ff442b6188 100644
--- a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java
+++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java
@@ -108,9 +108,9 @@ public class EGitPatchHistoryTest extends TestCase {
for (final FileHeader fh : p.getFiles()) {
final String fileName;
if (fh.getChangeType() != FileHeader.ChangeType.DELETE)
- fileName = fh.getNewName();
+ fileName = fh.getNewPath();
else
- fileName = fh.getOldName();
+ fileName = fh.getOldPath();
final StatInfo s = files.remove(fileName);
final String nid = fileName + " in " + cid;
assertNotNull("No " + nid, s);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
index 9e195b4974..a7d0984689 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
@@ -44,15 +44,17 @@
package org.eclipse.jgit.api;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectWriter;
+import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.RepositoryTestCase;
public class AddCommandTest extends RepositoryTestCase {
@@ -86,15 +88,11 @@ public class AddCommandTest extends RepositoryTestCase {
Git git = new Git(db);
- DirCache dc = git.add().addFilepattern("a.txt").call();
+ git.add().addFilepattern("a.txt").call();
- assertEquals(1, dc.getEntryCount());
- assertEquals("a.txt", dc.getEntry(0).getPathString());
- assertNotNull(dc.getEntry(0).getObjectId());
- assertEquals(file.lastModified(), dc.getEntry(0).getLastModified());
- assertEquals(file.length(), dc.getEntry(0).getLength());
- assertEquals(FileMode.REGULAR_FILE, dc.getEntry(0).getFileMode());
- assertEquals(0, dc.getEntry(0).getStage());
+ assertEquals(
+ "[a.txt, mode:100644, sha1:6b584e8ece562ebffc15d38808cd6b98fc3d97ea]",
+ indexState(CONTENT_ID));
}
public void testAddExistingSingleFileInSubDir() throws IOException, NoFilepatternException {
@@ -107,15 +105,11 @@ public class AddCommandTest extends RepositoryTestCase {
Git git = new Git(db);
- DirCache dc = git.add().addFilepattern("sub/a.txt").call();
+ git.add().addFilepattern("sub/a.txt").call();
- assertEquals(1, dc.getEntryCount());
- assertEquals("sub/a.txt", dc.getEntry(0).getPathString());
- assertNotNull(dc.getEntry(0).getObjectId());
- assertEquals(file.lastModified(), dc.getEntry(0).getLastModified());
- assertEquals(file.length(), dc.getEntry(0).getLength());
- assertEquals(FileMode.REGULAR_FILE, dc.getEntry(0).getFileMode());
- assertEquals(0, dc.getEntry(0).getStage());
+ assertEquals(
+ "[sub/a.txt, mode:100644, sha1:6b584e8ece562ebffc15d38808cd6b98fc3d97ea]",
+ indexState(CONTENT_ID));
}
public void testAddExistingSingleFileTwice() throws IOException, NoFilepatternException {
@@ -128,7 +122,7 @@ public class AddCommandTest extends RepositoryTestCase {
Git git = new Git(db);
DirCache dc = git.add().addFilepattern("a.txt").call();
- ObjectId id1 = dc.getEntry(0).getObjectId();
+ dc.getEntry(0).getObjectId();
writer = new PrintWriter(file);
writer.print("other content");
@@ -136,10 +130,9 @@ public class AddCommandTest extends RepositoryTestCase {
dc = git.add().addFilepattern("a.txt").call();
- assertEquals(1, dc.getEntryCount());
- assertEquals("a.txt", dc.getEntry(0).getPathString());
- assertNotSame(id1, dc.getEntry(0).getObjectId());
- assertEquals(0, dc.getEntry(0).getStage());
+ assertEquals(
+ "[a.txt, mode:100644, sha1:4f41554f6e0045ef53848fc0c3f33b6a9abc24a9]",
+ indexState(CONTENT_ID));
}
public void testAddExistingSingleFileTwiceWithCommit() throws Exception {
@@ -152,7 +145,7 @@ public class AddCommandTest extends RepositoryTestCase {
Git git = new Git(db);
DirCache dc = git.add().addFilepattern("a.txt").call();
- ObjectId id1 = dc.getEntry(0).getObjectId();
+ dc.getEntry(0).getObjectId();
git.commit().setMessage("commit a.txt").call();
@@ -162,10 +155,9 @@ public class AddCommandTest extends RepositoryTestCase {
dc = git.add().addFilepattern("a.txt").call();
- assertEquals(1, dc.getEntryCount());
- assertEquals("a.txt", dc.getEntry(0).getPathString());
- assertNotSame(id1, dc.getEntry(0).getObjectId());
- assertEquals(0, dc.getEntry(0).getStage());
+ assertEquals(
+ "[a.txt, mode:100644, sha1:4f41554f6e0045ef53848fc0c3f33b6a9abc24a9]",
+ indexState(CONTENT_ID));
}
public void testAddRemovedFile() throws Exception {
@@ -178,16 +170,15 @@ public class AddCommandTest extends RepositoryTestCase {
Git git = new Git(db);
DirCache dc = git.add().addFilepattern("a.txt").call();
- ObjectId id1 = dc.getEntry(0).getObjectId();
+ dc.getEntry(0).getObjectId();
file.delete();
// is supposed to do nothing
dc = git.add().addFilepattern("a.txt").call();
- assertEquals(1, dc.getEntryCount());
- assertEquals("a.txt", dc.getEntry(0).getPathString());
- assertEquals(id1, dc.getEntry(0).getObjectId());
- assertEquals(0, dc.getEntry(0).getStage());
+ assertEquals(
+ "[a.txt, mode:100644, sha1:6b584e8ece562ebffc15d38808cd6b98fc3d97ea]",
+ indexState(CONTENT_ID));
}
public void testAddRemovedCommittedFile() throws Exception {
@@ -202,16 +193,15 @@ public class AddCommandTest extends RepositoryTestCase {
git.commit().setMessage("commit a.txt").call();
- ObjectId id1 = dc.getEntry(0).getObjectId();
+ dc.getEntry(0).getObjectId();
file.delete();
// is supposed to do nothing
dc = git.add().addFilepattern("a.txt").call();
- assertEquals(1, dc.getEntryCount());
- assertEquals("a.txt", dc.getEntry(0).getPathString());
- assertEquals(id1, dc.getEntry(0).getObjectId());
- assertEquals(0, dc.getEntry(0).getStage());
+ assertEquals(
+ "[a.txt, mode:100644, sha1:6b584e8ece562ebffc15d38808cd6b98fc3d97ea]",
+ indexState(CONTENT_ID));
}
public void testAddWithConflicts() throws Exception {
@@ -229,38 +219,42 @@ public class AddCommandTest extends RepositoryTestCase {
writer.print("content b");
writer.close();
- ObjectWriter ow = new ObjectWriter(db);
+ ObjectInserter newObjectInserter = db.newObjectInserter();
DirCache dc = db.lockDirCache();
DirCacheBuilder builder = dc.builder();
- addEntryToBuilder("b.txt", file2, ow, builder, 0);
- addEntryToBuilder("a.txt", file, ow, builder, 1);
+ addEntryToBuilder("b.txt", file2, newObjectInserter, builder, 0);
+ addEntryToBuilder("a.txt", file, newObjectInserter, builder, 1);
writer = new PrintWriter(file);
writer.print("other content");
writer.close();
- addEntryToBuilder("a.txt", file, ow, builder, 3);
+ addEntryToBuilder("a.txt", file, newObjectInserter, builder, 3);
writer = new PrintWriter(file);
writer.print("our content");
writer.close();
- ObjectId id1 = addEntryToBuilder("a.txt", file, ow, builder, 2)
+ addEntryToBuilder("a.txt", file, newObjectInserter, builder, 2)
.getObjectId();
builder.commit();
- assertEquals(4, dc.getEntryCount());
+ assertEquals(
+ "[a.txt, mode:100644, stage:1, sha1:6b584e8ece562ebffc15d38808cd6b98fc3d97ea]" +
+ "[a.txt, mode:100644, stage:2, sha1:b9f89ff733bdaf49e02711535867bb821f9db55e]" +
+ "[a.txt, mode:100644, stage:3, sha1:4f41554f6e0045ef53848fc0c3f33b6a9abc24a9]" +
+ "[b.txt, mode:100644, sha1:50e9cdb03f9719261dd39d7f2920b906db3711a3]",
+ indexState(CONTENT_ID));
// now the test begins
Git git = new Git(db);
dc = git.add().addFilepattern("a.txt").call();
- assertEquals(2, dc.getEntryCount());
- assertEquals("a.txt", dc.getEntry("a.txt").getPathString());
- assertEquals(id1, dc.getEntry("a.txt").getObjectId());
- assertEquals(0, dc.getEntry("a.txt").getStage());
- assertEquals(0, dc.getEntry("b.txt").getStage());
+ assertEquals(
+ "[a.txt, mode:100644, sha1:b9f89ff733bdaf49e02711535867bb821f9db55e]" +
+ "[b.txt, mode:100644, sha1:50e9cdb03f9719261dd39d7f2920b906db3711a3]",
+ indexState(CONTENT_ID));
}
public void testAddTwoFiles() throws Exception {
@@ -277,13 +271,11 @@ public class AddCommandTest extends RepositoryTestCase {
writer.close();
Git git = new Git(db);
- DirCache dc = git.add().addFilepattern("a.txt").addFilepattern("b.txt").call();
- assertEquals("a.txt", dc.getEntry("a.txt").getPathString());
- assertEquals("b.txt", dc.getEntry("b.txt").getPathString());
- assertNotNull(dc.getEntry("a.txt").getObjectId());
- assertNotNull(dc.getEntry("b.txt").getObjectId());
- assertEquals(0, dc.getEntry("a.txt").getStage());
- assertEquals(0, dc.getEntry("b.txt").getStage());
+ git.add().addFilepattern("a.txt").addFilepattern("b.txt").call();
+ assertEquals(
+ "[a.txt, mode:100644, sha1:6b584e8ece562ebffc15d38808cd6b98fc3d97ea]" +
+ "[b.txt, mode:100644, sha1:50e9cdb03f9719261dd39d7f2920b906db3711a3]",
+ indexState(CONTENT_ID));
}
public void testAddFolder() throws Exception {
@@ -301,13 +293,11 @@ public class AddCommandTest extends RepositoryTestCase {
writer.close();
Git git = new Git(db);
- DirCache dc = git.add().addFilepattern("sub").call();
- assertEquals("sub/a.txt", dc.getEntry("sub/a.txt").getPathString());
- assertEquals("sub/b.txt", dc.getEntry("sub/b.txt").getPathString());
- assertNotNull(dc.getEntry("sub/a.txt").getObjectId());
- assertNotNull(dc.getEntry("sub/b.txt").getObjectId());
- assertEquals(0, dc.getEntry("sub/a.txt").getStage());
- assertEquals(0, dc.getEntry("sub/b.txt").getStage());
+ git.add().addFilepattern("sub").call();
+ assertEquals(
+ "[sub/a.txt, mode:100644, sha1:6b584e8ece562ebffc15d38808cd6b98fc3d97ea]" +
+ "[sub/b.txt, mode:100644, sha1:50e9cdb03f9719261dd39d7f2920b906db3711a3]",
+ indexState(CONTENT_ID));
}
public void testAddIgnoredFile() throws Exception {
@@ -331,11 +321,11 @@ public class AddCommandTest extends RepositoryTestCase {
writer.close();
Git git = new Git(db);
- DirCache dc = git.add().addFilepattern("sub").call();
- assertEquals("sub/a.txt", dc.getEntry("sub/a.txt").getPathString());
- assertNull(dc.getEntry("sub/b.txt"));
- assertNotNull(dc.getEntry("sub/a.txt").getObjectId());
- assertEquals(0, dc.getEntry("sub/a.txt").getStage());
+ git.add().addFilepattern("sub").call();
+
+ assertEquals(
+ "[sub/a.txt, mode:100644, sha1:6b584e8ece562ebffc15d38808cd6b98fc3d97ea]",
+ indexState(CONTENT_ID));
}
public void testAddWholeRepo() throws Exception {
@@ -353,15 +343,125 @@ public class AddCommandTest extends RepositoryTestCase {
writer.close();
Git git = new Git(db);
- DirCache dc = git.add().addFilepattern(".").call();
- assertEquals("sub/a.txt", dc.getEntry("sub/a.txt").getPathString());
- assertEquals("sub/b.txt", dc.getEntry("sub/b.txt").getPathString());
+ git.add().addFilepattern(".").call();
+ assertEquals(
+ "[sub/a.txt, mode:100644, sha1:6b584e8ece562ebffc15d38808cd6b98fc3d97ea]" +
+ "[sub/b.txt, mode:100644, sha1:50e9cdb03f9719261dd39d7f2920b906db3711a3]",
+ indexState(CONTENT_ID));
+ }
+
+ // the same three cases as in testAddWithParameterUpdate
+ // file a exists in workdir and in index -> added
+ // file b exists not in workdir but in index -> unchanged
+ // file c exists in workdir but not in index -> added
+ public void testAddWithoutParameterUpdate() throws Exception {
+ new File(db.getWorkTree(), "sub").mkdir();
+ File file = new File(db.getWorkTree(), "sub/a.txt");
+ file.createNewFile();
+ PrintWriter writer = new PrintWriter(file);
+ writer.print("content");
+ writer.close();
+
+ File file2 = new File(db.getWorkTree(), "sub/b.txt");
+ file2.createNewFile();
+ writer = new PrintWriter(file2);
+ writer.print("content b");
+ writer.close();
+
+ Git git = new Git(db);
+ git.add().addFilepattern("sub").call();
+
+ assertEquals(
+ "[sub/a.txt, mode:100644, sha1:6b584e8ece562ebffc15d38808cd6b98fc3d97ea]" +
+ "[sub/b.txt, mode:100644, sha1:50e9cdb03f9719261dd39d7f2920b906db3711a3]",
+ indexState(CONTENT_ID));
+
+ git.commit().setMessage("commit").call();
+
+ // new unstaged file sub/c.txt
+ File file3 = new File(db.getWorkTree(), "sub/c.txt");
+ file3.createNewFile();
+ writer = new PrintWriter(file3);
+ writer.print("content c");
+ writer.close();
+
+ // file sub/a.txt is modified
+ writer = new PrintWriter(file);
+ writer.print("modified content");
+ writer.close();
+
+ // file sub/b.txt is deleted
+ file2.delete();
+
+ git.add().addFilepattern("sub").call();
+ // change in sub/a.txt is staged
+ // deletion of sub/b.txt is not staged
+ // sub/c.txt is staged
+ assertEquals(
+ "[sub/a.txt, mode:100644, sha1:268af4e306cfcf6e79edd50fed9c553d211f68e3]" +
+ "[sub/b.txt, mode:100644, sha1:50e9cdb03f9719261dd39d7f2920b906db3711a3]" +
+ "[sub/c.txt, mode:100644, sha1:fa08654474ae2ddc4f61ee3a43d017ba65a439c3]",
+ indexState(CONTENT_ID));
+ }
+
+ // file a exists in workdir and in index -> added
+ // file b exists not in workdir but in index -> deleted
+ // file c exists in workdir but not in index -> unchanged
+ public void testAddWithParameterUpdate() throws Exception {
+ new File(db.getWorkTree(), "sub").mkdir();
+ File file = new File(db.getWorkTree(), "sub/a.txt");
+ file.createNewFile();
+ PrintWriter writer = new PrintWriter(file);
+ writer.print("content");
+ writer.close();
+
+ File file2 = new File(db.getWorkTree(), "sub/b.txt");
+ file2.createNewFile();
+ writer = new PrintWriter(file2);
+ writer.print("content b");
+ writer.close();
+
+ Git git = new Git(db);
+ git.add().addFilepattern("sub").call();
+
+ assertEquals(
+ "[sub/a.txt, mode:100644, sha1:6b584e8ece562ebffc15d38808cd6b98fc3d97ea]" +
+ "[sub/b.txt, mode:100644, sha1:50e9cdb03f9719261dd39d7f2920b906db3711a3]",
+ indexState(CONTENT_ID));
+
+ git.commit().setMessage("commit").call();
+
+ // new unstaged file sub/c.txt
+ File file3 = new File(db.getWorkTree(), "sub/c.txt");
+ file3.createNewFile();
+ writer = new PrintWriter(file3);
+ writer.print("content c");
+ writer.close();
+
+ // file sub/a.txt is modified
+ writer = new PrintWriter(file);
+ writer.print("modified content");
+ writer.close();
+
+ file2.delete();
+
+ // change in sub/a.txt is staged
+ // deletion of sub/b.txt is staged
+ // sub/c.txt is not staged
+ git.add().addFilepattern("sub").setUpdate(true).call();
+ // change in sub/a.txt is staged
+ assertEquals(
+ "[sub/a.txt, mode:100644, sha1:268af4e306cfcf6e79edd50fed9c553d211f68e3]",
+ indexState(CONTENT_ID));
}
private DirCacheEntry addEntryToBuilder(String path, File file,
- ObjectWriter ow, DirCacheBuilder builder, int stage)
+ ObjectInserter newObjectInserter, DirCacheBuilder builder, int stage)
throws IOException {
- ObjectId id = ow.writeBlob(file);
+ FileInputStream inputStream = new FileInputStream(file);
+ ObjectId id = newObjectInserter.insert(
+ Constants.OBJ_BLOB, file.length(), inputStream);
+ inputStream.close();
DirCacheEntry entry = new DirCacheEntry(path, stage);
entry.setObjectId(id);
entry.setFileMode(FileMode.REGULAR_FILE);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java
index a62045dc9f..cf30039ab7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java
@@ -45,6 +45,7 @@ package org.eclipse.jgit.api;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
+import java.io.PrintWriter;
import org.eclipse.jgit.errors.UnmergedPathException;
import org.eclipse.jgit.lib.Constants;
@@ -53,6 +54,7 @@ import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.treewalk.TreeWalk;
public class CommitAndLogCommandTests extends RepositoryTestCase {
public void testSomeCommits() throws NoHeadException, NoMessageException,
@@ -151,4 +153,36 @@ public class CommitAndLogCommandTests extends RepositoryTestCase {
assertEquals(parents[1], second);
assertTrue(parents.length==2);
}
+
+ public void testAddUnstagedChanges() throws IOException, NoHeadException,
+ NoMessageException, ConcurrentRefUpdateException,
+ JGitInternalException, WrongRepositoryStateException,
+ NoFilepatternException {
+ File file = new File(db.getWorkTree(), "a.txt");
+ file.createNewFile();
+ PrintWriter writer = new PrintWriter(file);
+ writer.print("content");
+ writer.close();
+
+ Git git = new Git(db);
+ git.add().addFilepattern("a.txt").call();
+ RevCommit commit = git.commit().setMessage("initial commit").call();
+ TreeWalk tw = TreeWalk.forPath(db, "a.txt", commit.getTree());
+ assertEquals("6b584e8ece562ebffc15d38808cd6b98fc3d97ea",
+ tw.getObjectId(0).getName());
+
+ writer = new PrintWriter(file);
+ writer.print("content2");
+ writer.close();
+ commit = git.commit().setMessage("second commit").call();
+ tw = TreeWalk.forPath(db, "a.txt", commit.getTree());
+ assertEquals("6b584e8ece562ebffc15d38808cd6b98fc3d97ea",
+ tw.getObjectId(0).getName());
+
+ commit = git.commit().setAll(true).setMessage("third commit")
+ .setAll(true).call();
+ tw = TreeWalk.forPath(db, "a.txt", commit.getTree());
+ assertEquals("db00fd65b218578127ea51f3dffac701f12f486a",
+ tw.getObjectId(0).getName());
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java
index eb965cf601..26116d2504 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java
@@ -275,6 +275,21 @@ public class RenameDetectorTest extends RepositoryTestCase {
assertRename(b, a, 74, entries.get(0));
}
+ public void testInexactRename_SameContentMultipleTimes() throws Exception {
+ ObjectId aId = blob("a\na\na\na\n");
+ ObjectId bId = blob("a\na\na\n");
+
+ DiffEntry a = DiffEntry.add(PATH_A, aId);
+ DiffEntry b = DiffEntry.delete(PATH_Q, bId);
+
+ rd.add(a);
+ rd.add(b);
+
+ List<DiffEntry> entries = rd.compute();
+ assertEquals(1, entries.size());
+ assertRename(b, a, 74, entries.get(0));
+ }
+
public void testInexactRenames_OnePair2() throws Exception {
ObjectId aId = blob("ab\nab\nab\nac\nad\nae\n");
ObjectId bId = blob("ac\nab\nab\nab\naa\na0\na1\n");
@@ -483,10 +498,10 @@ public class RenameDetectorTest extends RepositoryTestCase {
assertEquals(1, entries.size());
DiffEntry modify = entries.get(0);
- assertEquals(m.oldName, modify.oldName);
+ assertEquals(m.oldPath, modify.oldPath);
assertEquals(m.oldId, modify.oldId);
assertEquals(m.oldMode, modify.oldMode);
- assertEquals(m.newName, modify.newName);
+ assertEquals(m.newPath, modify.newPath);
assertEquals(m.newId, modify.newId);
assertEquals(m.newMode, modify.newMode);
assertEquals(m.changeType, modify.changeType);
@@ -545,8 +560,8 @@ public class RenameDetectorTest extends RepositoryTestCase {
DiffEntry rename) {
assertEquals(ChangeType.RENAME, rename.getChangeType());
- assertEquals(o.getOldName(), rename.getOldName());
- assertEquals(n.getNewName(), rename.getNewName());
+ assertEquals(o.getOldPath(), rename.getOldPath());
+ assertEquals(n.getNewPath(), rename.getNewPath());
assertEquals(o.getOldMode(), rename.getOldMode());
assertEquals(n.getNewMode(), rename.getNewMode());
@@ -561,8 +576,8 @@ public class RenameDetectorTest extends RepositoryTestCase {
DiffEntry copy) {
assertEquals(ChangeType.COPY, copy.getChangeType());
- assertEquals(o.getOldName(), copy.getOldName());
- assertEquals(n.getNewName(), copy.getNewName());
+ assertEquals(o.getOldPath(), copy.getOldPath());
+ assertEquals(n.getNewPath(), copy.getNewPath());
assertEquals(o.getOldMode(), copy.getOldMode());
assertEquals(n.getNewMode(), copy.getNewMode());
@@ -575,11 +590,11 @@ public class RenameDetectorTest extends RepositoryTestCase {
private static void assertAdd(String newName, ObjectId newId,
FileMode newMode, DiffEntry add) {
- assertEquals(DiffEntry.DEV_NULL, add.oldName);
+ assertEquals(DiffEntry.DEV_NULL, add.oldPath);
assertEquals(DiffEntry.A_ZERO, add.oldId);
assertEquals(FileMode.MISSING, add.oldMode);
assertEquals(ChangeType.ADD, add.changeType);
- assertEquals(newName, add.newName);
+ assertEquals(newName, add.newPath);
assertEquals(AbbreviatedObjectId.fromObjectId(newId), add.newId);
assertEquals(newMode, add.newMode);
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
index ac7ce5bd48..c439baccf6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
@@ -48,16 +48,21 @@ package org.eclipse.jgit.lib;
import java.io.File;
import java.io.IOException;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+
public class IndexDiffTest extends RepositoryTestCase {
public void testAdded() throws IOException {
GitIndex index = new GitIndex(db);
writeTrashFile("file1", "file1");
writeTrashFile("dir/subfile", "dir/subfile");
Tree tree = new Tree(db);
+ tree.setId(new ObjectWriter(db).writeTree(tree));
index.add(trash, new File(trash, "file1"));
index.add(trash, new File(trash, "dir/subfile"));
- IndexDiff diff = new IndexDiff(tree, index);
+ index.write();
+ FileTreeIterator iterator = new FileTreeIterator(db);
+ IndexDiff diff = new IndexDiff(db, tree.getId(), iterator);
diff.diff();
assertEquals(2, diff.getAdded().size());
assertTrue(diff.getAdded().contains("file1"));
@@ -68,7 +73,6 @@ public class IndexDiffTest extends RepositoryTestCase {
}
public void testRemoved() throws IOException {
- GitIndex index = new GitIndex(db);
writeTrashFile("file2", "file2");
writeTrashFile("dir/file3", "dir/file3");
@@ -82,7 +86,8 @@ public class IndexDiffTest extends RepositoryTestCase {
tree2.setId(new ObjectWriter(db).writeTree(tree2));
tree.setId(new ObjectWriter(db).writeTree(tree));
- IndexDiff diff = new IndexDiff(tree, index);
+ FileTreeIterator iterator = new FileTreeIterator(db);
+ IndexDiff diff = new IndexDiff(db, tree.getId(), iterator);
diff.diff();
assertEquals(2, diff.getRemoved().size());
assertTrue(diff.getRemoved().contains("file2"));
@@ -98,6 +103,7 @@ public class IndexDiffTest extends RepositoryTestCase {
index.add(trash, writeTrashFile("file2", "file2"));
index.add(trash, writeTrashFile("dir/file3", "dir/file3"));
+ index.write();
writeTrashFile("dir/file3", "changed");
@@ -109,7 +115,8 @@ public class IndexDiffTest extends RepositoryTestCase {
Tree tree2 = (Tree) tree.findTreeMember("dir");
tree2.setId(new ObjectWriter(db).writeTree(tree2));
tree.setId(new ObjectWriter(db).writeTree(tree));
- IndexDiff diff = new IndexDiff(tree, index);
+ FileTreeIterator iterator = new FileTreeIterator(db);
+ IndexDiff diff = new IndexDiff(db, tree.getId(), iterator);
diff.diff();
assertEquals(2, diff.getChanged().size());
assertTrue(diff.getChanged().contains("file2"));
@@ -128,6 +135,7 @@ public class IndexDiffTest extends RepositoryTestCase {
index.add(trash, writeTrashFile("a.c", "a.c"));
index.add(trash, writeTrashFile("a=c", "a=c"));
index.add(trash, writeTrashFile("a=d", "a=d"));
+ index.write();
Tree tree = new Tree(db);
// got the hash id'd from the data using echo -n a.b|git hash-object -t blob --stdin
@@ -138,7 +146,8 @@ public class IndexDiffTest extends RepositoryTestCase {
tree.setId(new ObjectWriter(db).writeTree(tree));
- IndexDiff diff = new IndexDiff(tree, index);
+ FileTreeIterator iterator = new FileTreeIterator(db);
+ IndexDiff diff = new IndexDiff(db, tree.getId(), iterator);
diff.diff();
assertEquals(0, diff.getChanged().size());
assertEquals(0, diff.getAdded().size());
@@ -163,6 +172,7 @@ public class IndexDiffTest extends RepositoryTestCase {
index.add(trash, writeTrashFile("a/c", "a/c"));
index.add(trash, writeTrashFile("a=c", "a=c"));
index.add(trash, writeTrashFile("a=d", "a=d"));
+ index.write();
Tree tree = new Tree(db);
// got the hash id'd from the data using echo -n a.b|git hash-object -t blob --stdin
@@ -180,7 +190,8 @@ public class IndexDiffTest extends RepositoryTestCase {
tree2.setId(new ObjectWriter(db).writeTree(tree2));
tree.setId(new ObjectWriter(db).writeTree(tree));
- IndexDiff diff = new IndexDiff(tree, index);
+ FileTreeIterator iterator = new FileTreeIterator(db);
+ IndexDiff diff = new IndexDiff(db, tree.getId(), iterator);
diff.diff();
assertEquals(0, diff.getChanged().size());
assertEquals(0, diff.getAdded().size());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
new file mode 100644
index 0000000000..e208b27e6b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RacyGitTests.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.TreeSet;
+
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.FileTreeIteratorWithTimeControl;
+import org.eclipse.jgit.treewalk.NameConflictTreeWalk;
+
+public class RacyGitTests extends RepositoryTestCase {
+ public void testIterator() throws IllegalStateException, IOException,
+ InterruptedException {
+ TreeSet<Long> modTimes = new TreeSet<Long>();
+ File lastFile = null;
+ for (int i = 0; i < 10; i++) {
+ lastFile = new File(db.getWorkTree(), "0." + i);
+ lastFile.createNewFile();
+ if (i == 5)
+ fsTick(lastFile);
+ }
+ modTimes.add(fsTick(lastFile));
+ for (int i = 0; i < 10; i++) {
+ lastFile = new File(db.getWorkTree(), "1." + i);
+ lastFile.createNewFile();
+ }
+ modTimes.add(fsTick(lastFile));
+ for (int i = 0; i < 10; i++) {
+ lastFile = new File(db.getWorkTree(), "2." + i);
+ lastFile.createNewFile();
+ if (i % 4 == 0)
+ fsTick(lastFile);
+ }
+ FileTreeIteratorWithTimeControl fileIt = new FileTreeIteratorWithTimeControl(
+ db, modTimes);
+ NameConflictTreeWalk tw = new NameConflictTreeWalk(db);
+ tw.reset();
+ tw.addTree(fileIt);
+ tw.setRecursive(true);
+ FileTreeIterator t;
+ long t0 = 0;
+ for (int i = 0; i < 10; i++) {
+ assertTrue(tw.next());
+ t = tw.getTree(0, FileTreeIterator.class);
+ if (i == 0)
+ t0 = t.getEntryLastModified();
+ else
+ assertEquals(t0, t.getEntryLastModified());
+ }
+ long t1 = 0;
+ for (int i = 0; i < 10; i++) {
+ assertTrue(tw.next());
+ t = tw.getTree(0, FileTreeIterator.class);
+ if (i == 0) {
+ t1 = t.getEntryLastModified();
+ assertTrue(t1 > t0);
+ } else
+ assertEquals(t1, t.getEntryLastModified());
+ }
+ long t2 = 0;
+ for (int i = 0; i < 10; i++) {
+ assertTrue(tw.next());
+ t = tw.getTree(0, FileTreeIterator.class);
+ if (i == 0) {
+ t2 = t.getEntryLastModified();
+ assertTrue(t2 > t1);
+ } else
+ assertEquals(t2, t.getEntryLastModified());
+ }
+ }
+
+ public void testRacyGitDetection() throws IOException,
+ IllegalStateException, InterruptedException {
+ TreeSet<Long> modTimes = new TreeSet<Long>();
+ File lastFile;
+
+ // wait to ensure that modtimes of the file doesn't match last index
+ // file modtime
+ modTimes.add(fsTick(db.getIndexFile()));
+
+ // create two files
+ addToWorkDir("a", "a");
+ lastFile = addToWorkDir("b", "b");
+
+ // wait to ensure that file-modTimes and therefore index entry modTime
+ // doesn't match the modtime of index-file after next persistance
+ modTimes.add(fsTick(lastFile));
+
+ // now add both files to the index. No racy git expected
+ addToIndex(modTimes);
+
+ assertEquals(
+ "[a, mode:100644, time:t0, length:1, sha1:2e65efe2a145dda7ee51d1741299f848e5bf752e]" +
+ "[b, mode:100644, time:t0, length:1, sha1:63d8dbd40c23542e740659a7168a0ce3138ea748]",
+ indexState(SMUDGE | MOD_TIME | LENGTH | CONTENT_ID));
+
+ // Remember the last modTime of index file. All modifications times of
+ // further modification are translated to this value so it looks that
+ // files have been modified in the same time slot as the index file
+ modTimes.add(Long.valueOf(db.getIndexFile().lastModified()));
+
+ // modify one file
+ addToWorkDir("a", "a2");
+ // now update the index the index. 'a' has to be racily clean -- because
+ // it's modification time is exactly the same as the previous index file
+ // mod time.
+ addToIndex(modTimes);
+
+ db.readDirCache();
+ // although racily clean a should not be reported as being dirty
+ assertEquals(
+ "[a, mode:100644, time:t1, smudged, length:0]" +
+ "[b, mode:100644, time:t0, length:1]",
+ indexState(SMUDGE|MOD_TIME|LENGTH));
+ }
+
+ private void addToIndex(TreeSet<Long> modTimes)
+ throws FileNotFoundException, IOException {
+ DirCacheBuilder builder = db.lockDirCache().builder();
+ FileTreeIterator fIt = new FileTreeIteratorWithTimeControl(
+ db, modTimes);
+ DirCacheEntry dce;
+ while (!fIt.eof()) {
+ dce = new DirCacheEntry(fIt.getEntryPathString());
+ dce.setFileMode(fIt.getEntryFileMode());
+ dce.setLastModified(fIt.getEntryLastModified());
+ dce.setLength((int) fIt.getEntryLength());
+ dce.setObjectId(fIt.getEntryObjectId());
+ builder.add(dce);
+ fIt.next(1);
+ }
+ builder.commit();
+ }
+
+ private File addToWorkDir(String path, String content) throws IOException {
+ File f = new File(db.getWorkTree(), path);
+ FileOutputStream fos = new FileOutputStream(f);
+ try {
+ fos.write(content.getBytes(Constants.CHARACTER_ENCODING));
+ return f;
+ } finally {
+ fos.close();
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryTestCase.java
index e78f8512a2..963c9d039d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryTestCase.java
@@ -52,9 +52,14 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
+import java.util.Map;
+import java.util.TreeSet;
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.storage.file.FileRepository;
+import org.eclipse.jgit.treewalk.NameConflictTreeWalk;
/**
* Base class for most JGit unit tests.
@@ -114,4 +119,154 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase {
db = createWorkRepository();
trash = db.getWorkTree();
}
+
+ public static final int MOD_TIME = 1;
+
+ public static final int SMUDGE = 2;
+
+ public static final int LENGTH = 4;
+
+ public static final int CONTENT_ID = 8;
+
+ /**
+ * Represent the state of the index in one String. This representation is
+ * useful when writing tests which do assertions on the state of the index.
+ * By default information about path, mode, stage (if different from 0) is
+ * included. A bitmask controls which additional info about
+ * modificationTimes, smudge state and length is included.
+ * <p>
+ * The format of the returned string is described with this BNF:
+ *
+ * <pre>
+ * result = ( "[" path mode stage? time? smudge? length? sha1? "]" )* .
+ * mode = ", mode:" number .
+ * stage = ", stage:" number .
+ * time = ", time:t" timestamp-index .
+ * smudge = "" | ", smudged" .
+ * length = ", length:" number .
+ * sha1 = ", sha1:" hex-sha1 .
+ *
+ * 'stage' is only presented when the stage is different from 0. All
+ * reported time stamps are mapped to strings like "t0", "t1", ... "tn". The
+ * smallest reported time-stamp will be called "t0". This allows to write
+ * assertions against the string although the concrete value of the
+ * time stamps is unknown.
+ *
+ * @param includedOptions
+ * a bitmask constructed out of the constants {@link #MOD_TIME},
+ * {@link #SMUDGE}, {@link #LENGTH} and {@link #CONTENT_ID}
+ * controlling which info is present in the resulting string.
+ * @return a string encoding the index state
+ * @throws IllegalStateException
+ * @throws IOException
+ */
+ public String indexState(int includedOptions)
+ throws IllegalStateException, IOException {
+ DirCache dc = db.readDirCache();
+ StringBuilder sb = new StringBuilder();
+ TreeSet<Long> timeStamps = null;
+
+ // iterate once over the dircache just to collect all time stamps
+ if (0 != (includedOptions & MOD_TIME)) {
+ timeStamps = new TreeSet<Long>();
+ for (int i=0; i<dc.getEntryCount(); ++i)
+ timeStamps.add(Long.valueOf(dc.getEntry(i).getLastModified()));
+ }
+
+ // iterate again, now produce the result string
+ NameConflictTreeWalk tw = new NameConflictTreeWalk(db);
+ tw.setRecursive(true);
+ tw.reset();
+ tw.addTree(new DirCacheIterator(dc));
+ while (tw.next()) {
+ DirCacheIterator dcIt = tw.getTree(0, DirCacheIterator.class);
+ sb.append("["+tw.getPathString()+", mode:" + dcIt.getEntryFileMode());
+ int stage = dcIt.getDirCacheEntry().getStage();
+ if (stage != 0)
+ sb.append(", stage:" + stage);
+ if (0 != (includedOptions & MOD_TIME)) {
+ sb.append(", time:t"+
+ timeStamps.headSet(Long.valueOf(dcIt.getDirCacheEntry().getLastModified())).size());
+ }
+ if (0 != (includedOptions & SMUDGE))
+ if (dcIt.getDirCacheEntry().isSmudged())
+ sb.append(", smudged");
+ if (0 != (includedOptions & LENGTH))
+ sb.append(", length:"
+ + Integer.toString(dcIt.getDirCacheEntry().getLength()));
+ if (0 != (includedOptions & CONTENT_ID))
+ sb.append(", sha1:" + ObjectId.toString(dcIt
+ .getEntryObjectId()));
+ sb.append("]");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Helper method to map arbitrary objects to user-defined names. This can be
+ * used create short names for objects to produce small and stable debug
+ * output. It is guaranteed that when you lookup the same object multiple
+ * times even with different nameTemplates this method will always return
+ * the same name which was derived from the first nameTemplate.
+ * nameTemplates can contain "%n" which will be replaced by a running number
+ * before used as a name.
+ *
+ * @param l
+ * the object to lookup
+ * @param nameTemplate
+ * the name for that object. Can contain "%n" which will be
+ * replaced by a running number before used as a name. If the
+ * lookup table already contains the object this parameter will
+ * be ignored
+ * @param lookupTable
+ * a table storing object-name mappings.
+ * @return a name of that object. Is not guaranteed to be unique. Use
+ * nameTemplates containing "%n" to always have unique names
+ */
+ public static String lookup(Object l, String nameTemplate,
+ Map<Object, String> lookupTable) {
+ String name = lookupTable.get(l);
+ if (name == null) {
+ name = nameTemplate.replaceAll("%n",
+ Integer.toString(lookupTable.size()));
+ lookupTable.put(l, name);
+ }
+ return name;
+ }
+
+ /**
+ * Waits until it is guaranteed that a subsequent file modification has a
+ * younger modification timestamp than the modification timestamp of the
+ * given file. This is done by touching a temporary file, reading the
+ * lastmodified attribute and, if needed, sleeping. After sleeping this loop
+ * starts again until the filesystem timer has advanced enough.
+ *
+ * @param lastFile
+ * the file on which we want to wait until the filesystem timer
+ * has advanced more than the lastmodification timestamp of this
+ * file
+ * @return return the last measured value of the filesystem timer which is
+ * greater than then the lastmodification time of lastfile.
+ * @throws InterruptedException
+ * @throws IOException
+ */
+ public static long fsTick(File lastFile) throws InterruptedException,
+ IOException {
+ long sleepTime = 1;
+ File tmp = File.createTempFile("FileTreeIteratorWithTimeControl", null);
+ try {
+ long startTime = (lastFile == null) ? tmp.lastModified() : lastFile
+ .lastModified();
+ long actTime = tmp.lastModified();
+ while (actTime <= startTime) {
+ Thread.sleep(sleepTime);
+ sleepTime *= 5;
+ tmp.setLastModified(System.currentTimeMillis());
+ actTime = tmp.lastModified();
+ }
+ return actTime;
+ } finally {
+ tmp.delete();
+ }
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/FileHeaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/FileHeaderTest.java
index 17e99779cf..813a701eaf 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/FileHeaderTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/FileHeaderTest.java
@@ -79,16 +79,16 @@ public class FileHeaderTest extends TestCase {
final FileHeader fh = header(name);
assertEquals(gitLine(name).length(), fh.parseGitFileName(0,
fh.buf.length));
- assertEquals(name, fh.getOldName());
- assertSame(fh.getOldName(), fh.getNewName());
+ assertEquals(name, fh.getOldPath());
+ assertSame(fh.getOldPath(), fh.getNewPath());
assertFalse(fh.hasMetaDataChanges());
}
public void testParseGitFileName_FailFooBar() {
final FileHeader fh = data("a/foo b/bar\n-");
assertTrue(fh.parseGitFileName(0, fh.buf.length) > 0);
- assertNull(fh.getOldName());
- assertNull(fh.getNewName());
+ assertNull(fh.getOldPath());
+ assertNull(fh.getNewPath());
assertFalse(fh.hasMetaDataChanges());
}
@@ -97,8 +97,8 @@ public class FileHeaderTest extends TestCase {
final FileHeader fh = header(name);
assertEquals(gitLine(name).length(), fh.parseGitFileName(0,
fh.buf.length));
- assertEquals(name, fh.getOldName());
- assertSame(fh.getOldName(), fh.getNewName());
+ assertEquals(name, fh.getOldPath());
+ assertSame(fh.getOldPath(), fh.getNewPath());
assertFalse(fh.hasMetaDataChanges());
}
@@ -108,8 +108,8 @@ public class FileHeaderTest extends TestCase {
final FileHeader fh = dqHeader(dqName);
assertEquals(dqGitLine(dqName).length(), fh.parseGitFileName(0,
fh.buf.length));
- assertEquals(name, fh.getOldName());
- assertSame(fh.getOldName(), fh.getNewName());
+ assertEquals(name, fh.getOldPath());
+ assertSame(fh.getOldPath(), fh.getNewPath());
assertFalse(fh.hasMetaDataChanges());
}
@@ -119,8 +119,8 @@ public class FileHeaderTest extends TestCase {
final FileHeader fh = dqHeader(dqName);
assertEquals(dqGitLine(dqName).length(), fh.parseGitFileName(0,
fh.buf.length));
- assertEquals(name, fh.getOldName());
- assertSame(fh.getOldName(), fh.getNewName());
+ assertEquals(name, fh.getOldPath());
+ assertSame(fh.getOldPath(), fh.getNewPath());
assertFalse(fh.hasMetaDataChanges());
}
@@ -129,8 +129,8 @@ public class FileHeaderTest extends TestCase {
final FileHeader fh = header(name);
assertEquals(gitLine(name).length(), fh.parseGitFileName(0,
fh.buf.length));
- assertEquals(name, fh.getOldName());
- assertSame(fh.getOldName(), fh.getNewName());
+ assertEquals(name, fh.getOldPath());
+ assertSame(fh.getOldPath(), fh.getNewPath());
assertFalse(fh.hasMetaDataChanges());
}
@@ -139,8 +139,8 @@ public class FileHeaderTest extends TestCase {
final String header = "project-v-1.0/" + name + " mydev/" + name + "\n";
final FileHeader fh = data(header + "-");
assertEquals(header.length(), fh.parseGitFileName(0, fh.buf.length));
- assertEquals(name, fh.getOldName());
- assertSame(fh.getOldName(), fh.getNewName());
+ assertEquals(name, fh.getOldPath());
+ assertSame(fh.getOldPath(), fh.getNewPath());
assertFalse(fh.hasMetaDataChanges());
}
@@ -153,9 +153,9 @@ public class FileHeaderTest extends TestCase {
+ "@@ -0,0 +1 @@\n" + "+a\n");
assertParse(fh);
- assertEquals("/dev/null", fh.getOldName());
- assertSame(DiffEntry.DEV_NULL, fh.getOldName());
- assertEquals("\u00c5ngstr\u00f6m", fh.getNewName());
+ assertEquals("/dev/null", fh.getOldPath());
+ assertSame(DiffEntry.DEV_NULL, fh.getOldPath());
+ assertEquals("\u00c5ngstr\u00f6m", fh.getNewPath());
assertSame(FileHeader.ChangeType.ADD, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
@@ -178,9 +178,9 @@ public class FileHeaderTest extends TestCase {
+ "@@ -1 +0,0 @@\n" + "-a\n");
assertParse(fh);
- assertEquals("\u00c5ngstr\u00f6m", fh.getOldName());
- assertEquals("/dev/null", fh.getNewName());
- assertSame(DiffEntry.DEV_NULL, fh.getNewName());
+ assertEquals("\u00c5ngstr\u00f6m", fh.getOldPath());
+ assertEquals("/dev/null", fh.getNewPath());
+ assertSame(DiffEntry.DEV_NULL, fh.getNewPath());
assertSame(FileHeader.ChangeType.DELETE, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
@@ -198,8 +198,8 @@ public class FileHeaderTest extends TestCase {
final FileHeader fh = data("diff --git a/a b b/a b\n"
+ "old mode 100644\n" + "new mode 100755\n");
assertParse(fh);
- assertEquals("a b", fh.getOldName());
- assertEquals("a b", fh.getNewName());
+ assertEquals("a b", fh.getOldPath());
+ assertEquals("a b", fh.getNewPath());
assertSame(FileHeader.ChangeType.MODIFY, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
@@ -220,14 +220,14 @@ public class FileHeaderTest extends TestCase {
+ "rename to \" c/\\303\\205ngstr\\303\\266m\"\n");
int ptr = fh.parseGitFileName(0, fh.buf.length);
assertTrue(ptr > 0);
- assertNull(fh.getOldName()); // can't parse names on a rename
- assertNull(fh.getNewName());
+ assertNull(fh.getOldPath()); // can't parse names on a rename
+ assertNull(fh.getNewPath());
ptr = fh.parseGitHeaders(ptr, fh.buf.length);
assertTrue(ptr > 0);
- assertEquals("a", fh.getOldName());
- assertEquals(" c/\u00c5ngstr\u00f6m", fh.getNewName());
+ assertEquals("a", fh.getOldPath());
+ assertEquals(" c/\u00c5ngstr\u00f6m", fh.getNewPath());
assertSame(FileHeader.ChangeType.RENAME, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
@@ -249,14 +249,14 @@ public class FileHeaderTest extends TestCase {
+ "rename new \" c/\\303\\205ngstr\\303\\266m\"\n");
int ptr = fh.parseGitFileName(0, fh.buf.length);
assertTrue(ptr > 0);
- assertNull(fh.getOldName()); // can't parse names on a rename
- assertNull(fh.getNewName());
+ assertNull(fh.getOldPath()); // can't parse names on a rename
+ assertNull(fh.getNewPath());
ptr = fh.parseGitHeaders(ptr, fh.buf.length);
assertTrue(ptr > 0);
- assertEquals("a", fh.getOldName());
- assertEquals(" c/\u00c5ngstr\u00f6m", fh.getNewName());
+ assertEquals("a", fh.getOldPath());
+ assertEquals(" c/\u00c5ngstr\u00f6m", fh.getNewPath());
assertSame(FileHeader.ChangeType.RENAME, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
@@ -278,14 +278,14 @@ public class FileHeaderTest extends TestCase {
+ "copy to \" c/\\303\\205ngstr\\303\\266m\"\n");
int ptr = fh.parseGitFileName(0, fh.buf.length);
assertTrue(ptr > 0);
- assertNull(fh.getOldName()); // can't parse names on a copy
- assertNull(fh.getNewName());
+ assertNull(fh.getOldPath()); // can't parse names on a copy
+ assertNull(fh.getNewPath());
ptr = fh.parseGitHeaders(ptr, fh.buf.length);
assertTrue(ptr > 0);
- assertEquals("a", fh.getOldName());
- assertEquals(" c/\u00c5ngstr\u00f6m", fh.getNewName());
+ assertEquals("a", fh.getOldPath());
+ assertEquals(" c/\u00c5ngstr\u00f6m", fh.getNewPath());
assertSame(FileHeader.ChangeType.COPY, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
@@ -307,8 +307,8 @@ public class FileHeaderTest extends TestCase {
+ ".." + nid + " 100644\n" + "--- a/a\n" + "+++ b/a\n");
assertParse(fh);
- assertEquals("a", fh.getOldName());
- assertEquals("a", fh.getNewName());
+ assertEquals("a", fh.getOldPath());
+ assertEquals("a", fh.getNewPath());
assertSame(FileMode.REGULAR_FILE, fh.getOldMode());
assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
@@ -331,8 +331,8 @@ public class FileHeaderTest extends TestCase {
+ ".." + nid + "\n" + "--- a/a\n" + "+++ b/a\n");
assertParse(fh);
- assertEquals("a", fh.getOldName());
- assertEquals("a", fh.getNewName());
+ assertEquals("a", fh.getOldPath());
+ assertEquals("a", fh.getNewPath());
assertFalse(fh.hasMetaDataChanges());
assertNull(fh.getOldMode());
@@ -357,8 +357,8 @@ public class FileHeaderTest extends TestCase {
+ " 100644\n" + "--- a/a\n" + "+++ b/a\n");
assertParse(fh);
- assertEquals("a", fh.getOldName());
- assertEquals("a", fh.getNewName());
+ assertEquals("a", fh.getOldPath());
+ assertEquals("a", fh.getNewPath());
assertSame(FileMode.REGULAR_FILE, fh.getOldMode());
assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
@@ -386,8 +386,8 @@ public class FileHeaderTest extends TestCase {
+ "\n" + "--- a/a\n" + "+++ b/a\n");
assertParse(fh);
- assertEquals("a", fh.getOldName());
- assertEquals("a", fh.getNewName());
+ assertEquals("a", fh.getOldPath());
+ assertEquals("a", fh.getNewPath());
assertNull(fh.getOldMode());
assertNull(fh.getNewMode());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcTest.java
index 1d879cba67..cef13f5f16 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcTest.java
@@ -60,8 +60,8 @@ public class PatchCcTest extends TestCase {
final CombinedFileHeader cfh = (CombinedFileHeader) p.getFiles().get(0);
assertEquals("org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java",
- cfh.getNewName());
- assertEquals(cfh.getNewName(), cfh.getOldName());
+ cfh.getNewPath());
+ assertEquals(cfh.getNewPath(), cfh.getOldPath());
assertEquals(98, cfh.startOffset);
@@ -114,8 +114,8 @@ public class PatchCcTest extends TestCase {
final CombinedFileHeader cfh = (CombinedFileHeader) p.getFiles().get(0);
- assertSame(DiffEntry.DEV_NULL, cfh.getOldName());
- assertEquals("d", cfh.getNewName());
+ assertSame(DiffEntry.DEV_NULL, cfh.getOldPath());
+ assertEquals("d", cfh.getNewPath());
assertEquals(187, cfh.startOffset);
@@ -168,8 +168,8 @@ public class PatchCcTest extends TestCase {
final CombinedFileHeader cfh = (CombinedFileHeader) p.getFiles().get(0);
- assertEquals("a", cfh.getOldName());
- assertSame(DiffEntry.DEV_NULL, cfh.getNewName());
+ assertEquals("a", cfh.getOldPath());
+ assertSame(DiffEntry.DEV_NULL, cfh.getNewPath());
assertEquals(187, cfh.startOffset);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchErrorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchErrorTest.java
index 62a107130e..67b3f5c589 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchErrorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchErrorTest.java
@@ -56,7 +56,7 @@ public class PatchErrorTest extends TestCase {
final FileHeader fh = p.getFiles().get(0);
assertEquals(
"org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java",
- fh.getNewName());
+ fh.getNewPath());
assertEquals(1, fh.getHunks().size());
}
@@ -114,14 +114,14 @@ public class PatchErrorTest extends TestCase {
final FileHeader fh = p.getFiles().get(0);
assertEquals(
"org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java",
- fh.getNewName());
+ fh.getNewPath());
assertEquals(1, fh.getHunks().size());
}
{
final FileHeader fh = p.getFiles().get(1);
assertEquals(
"org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java",
- fh.getNewName());
+ fh.getNewPath());
assertEquals(1, fh.getHunks().size());
}
@@ -139,7 +139,7 @@ public class PatchErrorTest extends TestCase {
{
final FileHeader fh = p.getFiles().get(0);
assertEquals("org.spearce.egit.ui/icons/toolbar/fetchd.png", fh
- .getNewName());
+ .getNewPath());
assertSame(FileHeader.PatchType.GIT_BINARY, fh.getPatchType());
assertTrue(fh.getHunks().isEmpty());
assertNull(fh.getForwardBinaryHunk());
@@ -147,7 +147,7 @@ public class PatchErrorTest extends TestCase {
{
final FileHeader fh = p.getFiles().get(1);
assertEquals("org.spearce.egit.ui/icons/toolbar/fetche.png", fh
- .getNewName());
+ .getNewPath());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
assertTrue(fh.getHunks().isEmpty());
assertNull(fh.getForwardBinaryHunk());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchTest.java
index 52d6e27ca8..dd76251385 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchTest.java
@@ -68,11 +68,11 @@ public class PatchTest extends TestCase {
assertEquals(
"org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java",
- fRepositoryConfigTest.getNewName());
+ fRepositoryConfigTest.getNewPath());
assertEquals(
"org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java",
- fRepositoryConfig.getNewName());
+ fRepositoryConfig.getNewPath());
assertEquals(572, fRepositoryConfigTest.startOffset);
assertEquals(1490, fRepositoryConfig.startOffset);
@@ -168,7 +168,7 @@ public class PatchTest extends TestCase {
assertEquals("0000000", fh.getOldId().name());
assertSame(FileMode.MISSING, fh.getOldMode());
assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
- assertTrue(fh.getNewName().startsWith(
+ assertTrue(fh.getNewPath().startsWith(
"org.spearce.egit.ui/icons/toolbar/"));
assertSame(FileHeader.PatchType.BINARY, fh.getPatchType());
assertTrue(fh.getHunks().isEmpty());
@@ -179,7 +179,7 @@ public class PatchTest extends TestCase {
}
final FileHeader fh = p.getFiles().get(4);
- assertEquals("org.spearce.egit.ui/plugin.xml", fh.getNewName());
+ assertEquals("org.spearce.egit.ui/plugin.xml", fh.getNewPath());
assertSame(FileHeader.ChangeType.MODIFY, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
assertFalse(fh.hasMetaDataChanges());
@@ -203,7 +203,7 @@ public class PatchTest extends TestCase {
assertNotNull(fh.getNewId());
assertEquals(ObjectId.zeroId().name(), fh.getOldId().name());
assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
- assertTrue(fh.getNewName().startsWith(
+ assertTrue(fh.getNewPath().startsWith(
"org.spearce.egit.ui/icons/toolbar/"));
assertSame(FileHeader.PatchType.GIT_BINARY, fh.getPatchType());
assertTrue(fh.getHunks().isEmpty());
@@ -224,7 +224,7 @@ public class PatchTest extends TestCase {
}
final FileHeader fh = p.getFiles().get(4);
- assertEquals("org.spearce.egit.ui/plugin.xml", fh.getNewName());
+ assertEquals("org.spearce.egit.ui/plugin.xml", fh.getNewPath());
assertSame(FileHeader.ChangeType.MODIFY, fh.getChangeType());
assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
assertFalse(fh.hasMetaDataChanges());
@@ -241,7 +241,7 @@ public class PatchTest extends TestCase {
assertTrue(p.getErrors().isEmpty());
final FileHeader fh = p.getFiles().get(0);
- assertTrue(fh.getNewName().startsWith("zero.bin"));
+ assertTrue(fh.getNewPath().startsWith("zero.bin"));
assertSame(FileHeader.ChangeType.MODIFY, fh.getChangeType());
assertSame(FileHeader.PatchType.GIT_BINARY, fh.getPatchType());
assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
@@ -279,7 +279,7 @@ public class PatchTest extends TestCase {
final FileHeader f = p.getFiles().get(0);
- assertEquals("a", f.getNewName());
+ assertEquals("a", f.getNewPath());
assertEquals(252, f.startOffset);
assertEquals("2e65efe", f.getOldId().name());
@@ -313,7 +313,7 @@ public class PatchTest extends TestCase {
final FileHeader f = p.getFiles().get(0);
- assertEquals("a", f.getNewName());
+ assertEquals("a", f.getNewPath());
assertEquals(256, f.startOffset);
assertEquals("f2ad6c7", f.getOldId().name());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorWithTimeControl.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorWithTimeControl.java
new file mode 100644
index 0000000000..bb76d0075d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorWithTimeControl.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.treewalk;
+
+import java.io.File;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.FS;
+
+/**
+ * A {@link FileTreeIterator} used in tests which allows to specify explicitly
+ * what will be returned by {@link #getEntryLastModified()}. This allows to
+ * write tests where certain files have to have the same modification time.
+ * <p>
+ * This iterator is configured by a list of strictly increasing long values
+ * t(0), t(1), ..., t(n). For each file with a modification between t(x) and
+ * t(x+1) [ t(x) <= time < t(x+1) ] this iterator will report t(x). For files
+ * with a modification time smaller t(0) a modification time of 0 is returned.
+ * For files with a modification time greater or equal t(n) t(n) will be
+ * returned.
+ * <p>
+ * This class was written especially to test racy-git problems
+ */
+public class FileTreeIteratorWithTimeControl extends FileTreeIterator {
+ private TreeSet<Long> modTimes;
+
+ public FileTreeIteratorWithTimeControl(FileTreeIterator p, Repository repo,
+ TreeSet<Long> modTimes) {
+ super(p, repo.getWorkTree(), repo.getFS());
+ this.modTimes = modTimes;
+ }
+
+ public FileTreeIteratorWithTimeControl(FileTreeIterator p, File f, FS fs,
+ TreeSet<Long> modTimes) {
+ super(p, f, fs);
+ this.modTimes = modTimes;
+ }
+
+ public FileTreeIteratorWithTimeControl(Repository repo,
+ TreeSet<Long> modTimes) {
+ super(repo);
+ this.modTimes = modTimes;
+ }
+
+ public FileTreeIteratorWithTimeControl(File f, FS fs,
+ TreeSet<Long> modTimes) {
+ super(f, fs);
+ this.modTimes = modTimes;
+ }
+
+ @Override
+ public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader) {
+ return new FileTreeIteratorWithTimeControl(this,
+ ((FileEntry) current()).file, fs, modTimes);
+ }
+
+ @Override
+ public long getEntryLastModified() {
+ if (modTimes == null)
+ return 0;
+ Long cutOff = Long.valueOf(super.getEntryLastModified() + 1);
+ SortedSet<Long> head = modTimes.headSet(cutOff);
+ return head.isEmpty() ? 0 : head.last().longValue();
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java
index 675331baf4..e59b7c18d3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java
@@ -120,11 +120,15 @@ public class NameConflictTreeWalkTest extends RepositoryTestCase {
tw.addTree(new DirCacheIterator(tree1));
assertModes("a", REGULAR_FILE, TREE, tw);
+ assertTrue(tw.isDirectoryFileConflict());
assertTrue(tw.isSubtree());
tw.enterSubtree();
assertModes("a/b", MISSING, REGULAR_FILE, tw);
+ assertTrue(tw.isDirectoryFileConflict());
assertModes("a.b", EXECUTABLE_FILE, MISSING, tw);
+ assertFalse(tw.isDirectoryFileConflict());
assertModes("a0b", SYMLINK, MISSING, tw);
+ assertFalse(tw.isDirectoryFileConflict());
}
public void testDF_GapByOne() throws Exception {
@@ -153,10 +157,14 @@ public class NameConflictTreeWalkTest extends RepositoryTestCase {
assertModes("a", REGULAR_FILE, TREE, tw);
assertTrue(tw.isSubtree());
+ assertTrue(tw.isDirectoryFileConflict());
tw.enterSubtree();
assertModes("a/b", MISSING, REGULAR_FILE, tw);
+ assertTrue(tw.isDirectoryFileConflict());
assertModes("a.b", EXECUTABLE_FILE, EXECUTABLE_FILE, tw);
+ assertFalse(tw.isDirectoryFileConflict());
assertModes("a0b", SYMLINK, MISSING, tw);
+ assertFalse(tw.isDirectoryFileConflict());
}
public void testDF_SkipsSeenSubtree() throws Exception {
@@ -185,10 +193,57 @@ public class NameConflictTreeWalkTest extends RepositoryTestCase {
assertModes("a", REGULAR_FILE, TREE, tw);
assertTrue(tw.isSubtree());
+ assertTrue(tw.isDirectoryFileConflict());
tw.enterSubtree();
assertModes("a/b", MISSING, REGULAR_FILE, tw);
+ assertTrue(tw.isDirectoryFileConflict());
assertModes("a.b", MISSING, EXECUTABLE_FILE, tw);
+ assertFalse(tw.isDirectoryFileConflict());
assertModes("a0b", SYMLINK, SYMLINK, tw);
+ assertFalse(tw.isDirectoryFileConflict());
+ }
+
+ public void testDF_DetectConflict() throws Exception {
+ final DirCache tree0 = db.readDirCache();
+ final DirCache tree1 = db.readDirCache();
+ {
+ final DirCacheBuilder b0 = tree0.builder();
+ final DirCacheBuilder b1 = tree1.builder();
+
+ b0.add(makeEntry("0", REGULAR_FILE));
+ b0.add(makeEntry("a", REGULAR_FILE));
+ b1.add(makeEntry("0", REGULAR_FILE));
+ b1.add(makeEntry("a.b", REGULAR_FILE));
+ b1.add(makeEntry("a/b", REGULAR_FILE));
+ b1.add(makeEntry("a/c/e", REGULAR_FILE));
+
+ b0.finish();
+ b1.finish();
+ assertEquals(2, tree0.getEntryCount());
+ assertEquals(4, tree1.getEntryCount());
+ }
+
+ final NameConflictTreeWalk tw = new NameConflictTreeWalk(db);
+ tw.reset();
+ tw.addTree(new DirCacheIterator(tree0));
+ tw.addTree(new DirCacheIterator(tree1));
+
+ assertModes("0", REGULAR_FILE, REGULAR_FILE, tw);
+ assertFalse(tw.isDirectoryFileConflict());
+ assertModes("a", REGULAR_FILE, TREE, tw);
+ assertTrue(tw.isSubtree());
+ assertTrue(tw.isDirectoryFileConflict());
+ tw.enterSubtree();
+ assertModes("a/b", MISSING, REGULAR_FILE, tw);
+ assertTrue(tw.isDirectoryFileConflict());
+ assertModes("a/c", MISSING, TREE, tw);
+ assertTrue(tw.isDirectoryFileConflict());
+ tw.enterSubtree();
+ assertModes("a/c/e", MISSING, REGULAR_FILE, tw);
+ assertTrue(tw.isDirectoryFileConflict());
+
+ assertModes("a.b", MISSING, REGULAR_FILE, tw);
+ assertFalse(tw.isDirectoryFileConflict());
}
private DirCacheEntry makeEntry(final String path, final FileMode mode)
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java
index 3b1584612d..a15cadfbda 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/ChangeIdUtilTest.java
@@ -123,6 +123,13 @@ public class ChangeIdUtilTest extends TestCase {
call("has changeid\n\nBug: 33\nmore text\nSigned-off-by: me@you.too\nChange-Id: I0123456789012345678901234567890123456789\nAnd then some\n"));
}
+ public void testHasChangeidWithReplacement() throws Exception {
+ assertEquals(
+ "has changeid\n\nBug: 33\nmore text\nSigned-off-by: me@you.too\nChange-Id: I988d2d7a6f2c0578fccabd4ebd3cec0768bc7f9f\nAnd then some\n",
+ call("has changeid\n\nBug: 33\nmore text\nSigned-off-by: me@you.too\nChange-Id: I0123456789012345678901234567890123456789\nAnd then some\n",
+ true));
+ }
+
public void testOneliner() throws Exception {
assertEquals(
"oneliner\n\nChange-Id: I3a98091ce4470de88d52ae317fcd297e2339f063\n",
@@ -236,6 +243,47 @@ public class ChangeIdUtilTest extends TestCase {
"Change-Id: I4f4e2e1e8568ddc1509baecb8c1270a1fb4b6da7\n");
}
+ public void testChangeIdAlreadySetWithReplacement() throws Exception {
+ // If a Change-Id is already present in the footer, the hook
+ // replaces the Change-Id with the new value..
+ //
+ assertEquals("a\n" + //
+ "\n" + //
+ "Change-Id: Ifa324efa85bfb3c8696a46a0f67fa70c35be5f5f\n",
+ call("a\n" + //
+ "\n" + //
+ "Change-Id: Iaeac9b4149291060228ef0154db2985a31111335\n",
+ true));
+ assertEquals("fix: this thing\n" + //
+ "\n" + //
+ "Change-Id: Ib63e4990a06412a3f24bd93bb160e98ac1bd412b\n",
+ call("fix: this thing\n" + //
+ "\n" + //
+ "Change-Id: I388bdaf52ed05b55e62a22d0a20d2c1ae0d33e7e\n",
+ true));
+ assertEquals("fix-a-widget: this thing\n" + //
+ "\n" + //
+ "Change-Id: If0444e4d0cabcf41b3d3b46b7e9a7a64a82117af\n",
+ call("fix-a-widget: this thing\n" + //
+ "\n" + //
+ "Change-Id: Id3bc5359d768a6400450283e12bdfb6cd135ea4b\n",
+ true));
+ assertEquals("FIX: this thing\n" + //
+ "\n" + //
+ "Change-Id: Iba5a3b2d5e5df46448f6daf362b6bfa775c6491d\n",
+ call("FIX: this thing\n" + //
+ "\n" + //
+ "Change-Id: I1b55098b5a2cce0b3f3da783dda50d5f79f873fa\n",
+ true));
+ assertEquals("Fix-A-Widget: this thing\n" + //
+ "\n" + //
+ "Change-Id: I2573d47c62c42429fbe424d70cfba931f8f87848\n",
+ call("Fix-A-Widget: this thing\n" + //
+ "\n" + //
+ "Change-Id: I4f4e2e1e8568ddc1509baecb8c1270a1fb4b6da7\n",
+ true));
+ }
+
public void testTimeAltersId() throws Exception {
assertEquals("a\n" + //
"\n" + //
@@ -513,11 +561,15 @@ public class ChangeIdUtilTest extends TestCase {
}
private String call(final String body) throws Exception {
+ return call(body, false);
+ }
+
+ private String call(final String body, boolean replaceExisting) throws Exception {
ObjectId computeChangeId = ChangeIdUtil.computeChangeId(treeId1,
parentId1, author, committer, body);
if (computeChangeId == null)
return body;
- return ChangeIdUtil.insertId(body, computeChangeId);
+ return ChangeIdUtil.insertId(body, computeChangeId, replaceExisting);
}
}
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
index 1b2b81fce3..a9878f8d29 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
@@ -335,6 +335,7 @@ sourceRefNotSpecifiedForRefspec=Source ref not specified for refspec: {0}
staleRevFlagsOn=Stale RevFlags on {0}
startingReadStageWithoutWrittenRequestDataPendingIsNotSupported=Starting read stage without written request data pending is not supported
statelessRPCRequiresOptionToBeEnabled=stateless RPC requires {0} to be enabled
+submodulesNotSupported=Submodules are not supported
symlinkCannotBeWrittenAsTheLinkTarget=Symlink "{0}" cannot be written as the link target cannot be read from within Java.
tSizeMustBeGreaterOrEqual1=tSize must be >= 1
theFactoryMustNotBeNull=The factory must not be null
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
index 9d1e2cd808..461242cb27 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
@@ -394,6 +394,7 @@ public class JGitText extends TranslationBundle {
/***/ public String staleRevFlagsOn;
/***/ public String startingReadStageWithoutWrittenRequestDataPendingIsNotSupported;
/***/ public String statelessRPCRequiresOptionToBeEnabled;
+ /***/ public String submodulesNotSupported;
/***/ public String symlinkCannotBeWrittenAsTheLinkTarget;
/***/ public String tSizeMustBeGreaterOrEqual1;
/***/ public String theFactoryMustNotBeNull;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
index e41ab580bb..f7d4da4d5a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java
@@ -76,6 +76,8 @@ public class AddCommand extends GitCommand<DirCache> {
private WorkingTreeIterator workingTreeIterator;
+ private boolean update = false;
+
/**
*
* @param repo
@@ -158,18 +160,20 @@ public class AddCommand extends GitCommand<DirCache> {
// this path, we however want to add only one
// new DirCacheEntry per path.
else if (!(path.equals(lastAddedFile))) {
- if (f != null) { // the file exists
- DirCacheEntry entry = new DirCacheEntry(path);
- entry.setLength((int)f.getEntryLength());
- entry.setLastModified(f.getEntryLastModified());
- entry.setFileMode(f.getEntryFileMode());
- entry.setObjectId(ow.writeBlob(file));
-
- builder.add(entry);
- lastAddedFile = path;
- } else {
- c = tw.getTree(0, DirCacheIterator.class);
- builder.add(c.getDirCacheEntry());
+ if (!(update && tw.getTree(0, DirCacheIterator.class) == null)) {
+ if (f != null) { // the file exists
+ DirCacheEntry entry = new DirCacheEntry(path);
+ entry.setLength((int)f.getEntryLength());
+ entry.setLastModified(f.getEntryLastModified());
+ entry.setFileMode(f.getEntryFileMode());
+ entry.setObjectId(ow.writeBlob(file));
+
+ builder.add(entry);
+ lastAddedFile = path;
+ } else if (!update){
+ c = tw.getTree(0, DirCacheIterator.class);
+ builder.add(c.getDirCacheEntry());
+ }
}
}
}
@@ -186,4 +190,29 @@ public class AddCommand extends GitCommand<DirCache> {
return dc;
}
+ /**
+ * @param update
+ * If set to true, the command only matches {@code filepattern}
+ * against already tracked files in the index rather than the
+ * working tree. That means that it will never stage new files,
+ * but that it will stage modified new contents of tracked files
+ * and that it will remove files from the index if the
+ * corresponding files in the working tree have been removed.
+ * In contrast to the git command line a {@code filepattern} must
+ * exist also if update is set to true as there is no
+ * concept of a working directory here.
+ *
+ * @return {@code this}
+ */
+ public AddCommand setUpdate(boolean update) {
+ this.update = update;
+ return this;
+ }
+
+ /**
+ * @return is the parameter update is set
+ */
+ public boolean isUpdate() {
+ return update;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
index 17b7113470..ae4b33477b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -42,7 +42,6 @@
*/
package org.eclipse.jgit.api;
-import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.LinkedList;
@@ -80,6 +79,8 @@ public class CommitCommand extends GitCommand<RevCommit> {
private String message;
+ private boolean all;
+
/**
* parents this commit should have. The current HEAD will be in this list
* and also all commits mentioned in .git/MERGE_HEAD
@@ -128,6 +129,18 @@ public class CommitCommand extends GitCommand<RevCommit> {
processOptions(state);
try {
+ if (all && !repo.isBare() && repo.getWorkTree() != null) {
+ Git git = new Git(repo);
+ try {
+ git.add()
+ .addFilepattern(".")
+ .setUpdate(true).call();
+ } catch (NoFilepatternException e) {
+ // should really not happen
+ throw new JGitInternalException(e.getMessage(), e);
+ }
+ }
+
Ref head = repo.getRef(Constants.HEAD);
if (head == null)
throw new NoHeadException(
@@ -174,13 +187,11 @@ public class CommitCommand extends GitCommand<RevCommit> {
case NEW:
case FAST_FORWARD: {
setCallable(false);
- File meta = repo.getDirectory();
- if (state == RepositoryState.MERGING_RESOLVED
- && meta != null) {
+ if (state == RepositoryState.MERGING_RESOLVED) {
// Commit was successful. Now delete the files
// used for merge commits
- new File(meta, Constants.MERGE_HEAD).delete();
- new File(meta, Constants.MERGE_MSG).delete();
+ repo.writeMergeCommitMsg(null);
+ repo.writeMergeHeads(null);
}
return revCommit;
}
@@ -356,4 +367,19 @@ public class CommitCommand extends GitCommand<RevCommit> {
public PersonIdent getAuthor() {
return author;
}
+
+ /**
+ * If set to true the Commit command automatically stages files that have
+ * been modified and deleted, but new files you not known by the repository
+ * are not affected. This corresponds to the parameter -a on the command
+ * line.
+ *
+ * @param all
+ * @return {@code this}
+ */
+ public CommitCommand setAll(boolean all) {
+ this.all = all;
+ return this;
+ }
+
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java
index 7dbcdaa6d9..55ecc4e22a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffEntry.java
@@ -112,15 +112,15 @@ public class DiffEntry {
entry.oldMode = walk.getFileMode(0);
entry.newMode = walk.getFileMode(1);
- entry.newName = entry.oldName = walk.getPathString();
+ entry.newPath = entry.oldPath = walk.getPathString();
if (entry.oldMode == FileMode.MISSING) {
- entry.oldName = DiffEntry.DEV_NULL;
+ entry.oldPath = DiffEntry.DEV_NULL;
entry.changeType = ChangeType.ADD;
r.add(entry);
} else if (entry.newMode == FileMode.MISSING) {
- entry.newName = DiffEntry.DEV_NULL;
+ entry.newPath = DiffEntry.DEV_NULL;
entry.changeType = ChangeType.DELETE;
r.add(entry);
@@ -139,11 +139,11 @@ public class DiffEntry {
DiffEntry e = new DiffEntry();
e.oldId = A_ZERO;
e.oldMode = FileMode.MISSING;
- e.oldName = DEV_NULL;
+ e.oldPath = DEV_NULL;
e.newId = AbbreviatedObjectId.fromObjectId(id);
e.newMode = FileMode.REGULAR_FILE;
- e.newName = path;
+ e.newPath = path;
e.changeType = ChangeType.ADD;
return e;
}
@@ -152,11 +152,11 @@ public class DiffEntry {
DiffEntry e = new DiffEntry();
e.oldId = AbbreviatedObjectId.fromObjectId(id);
e.oldMode = FileMode.REGULAR_FILE;
- e.oldName = path;
+ e.oldPath = path;
e.newId = A_ZERO;
e.newMode = FileMode.MISSING;
- e.newName = DEV_NULL;
+ e.newPath = DEV_NULL;
e.changeType = ChangeType.DELETE;
return e;
}
@@ -164,10 +164,10 @@ public class DiffEntry {
static DiffEntry modify(String path) {
DiffEntry e = new DiffEntry();
e.oldMode = FileMode.REGULAR_FILE;
- e.oldName = path;
+ e.oldPath = path;
e.newMode = FileMode.REGULAR_FILE;
- e.newName = path;
+ e.newPath = path;
e.changeType = ChangeType.MODIFY;
return e;
}
@@ -185,21 +185,21 @@ public class DiffEntry {
DiffEntry del = new DiffEntry();
del.oldId = entry.getOldId();
del.oldMode = entry.getOldMode();
- del.oldName = entry.getOldName();
+ del.oldPath = entry.getOldPath();
del.newId = A_ZERO;
del.newMode = FileMode.MISSING;
- del.newName = DiffEntry.DEV_NULL;
+ del.newPath = DiffEntry.DEV_NULL;
del.changeType = ChangeType.DELETE;
DiffEntry add = new DiffEntry();
add.oldId = A_ZERO;
add.oldMode = FileMode.MISSING;
- add.oldName = DiffEntry.DEV_NULL;
+ add.oldPath = DiffEntry.DEV_NULL;
add.newId = entry.getNewId();
add.newMode = entry.getNewMode();
- add.newName = entry.getNewName();
+ add.newPath = entry.getNewPath();
add.changeType = ChangeType.ADD;
return Arrays.asList(del, add);
}
@@ -210,11 +210,11 @@ public class DiffEntry {
r.oldId = src.oldId;
r.oldMode = src.oldMode;
- r.oldName = src.oldName;
+ r.oldPath = src.oldPath;
r.newId = dst.newId;
r.newMode = dst.newMode;
- r.newName = dst.newName;
+ r.newPath = dst.newPath;
r.changeType = changeType;
r.score = score;
@@ -223,10 +223,10 @@ public class DiffEntry {
}
/** File name of the old (pre-image). */
- protected String oldName;
+ protected String oldPath;
/** File name of the new (post-image). */
- protected String newName;
+ protected String newPath;
/** Old mode of the file, if described by the patch, else null. */
protected FileMode oldMode;
@@ -253,7 +253,7 @@ public class DiffEntry {
* of this patch:
* <ul>
* <li><i>file add</i>: always <code>/dev/null</code></li>
- * <li><i>file modify</i>: always {@link #getNewName()}</li>
+ * <li><i>file modify</i>: always {@link #getNewPath()}</li>
* <li><i>file delete</i>: always the file being deleted</li>
* <li><i>file copy</i>: source file the copy originates from</li>
* <li><i>file rename</i>: source file the rename originates from</li>
@@ -261,8 +261,8 @@ public class DiffEntry {
*
* @return old name for this file.
*/
- public String getOldName() {
- return oldName;
+ public String getOldPath() {
+ return oldPath;
}
/**
@@ -272,7 +272,7 @@ public class DiffEntry {
* of this patch:
* <ul>
* <li><i>file add</i>: always the file being created</li>
- * <li><i>file modify</i>: always {@link #getOldName()}</li>
+ * <li><i>file modify</i>: always {@link #getOldPath()}</li>
* <li><i>file delete</i>: always <code>/dev/null</code></li>
* <li><i>file copy</i>: destination file the copy ends up at</li>
* <li><i>file rename</i>: destination file the rename ends up at/li>
@@ -280,8 +280,8 @@ public class DiffEntry {
*
* @return new name for this file.
*/
- public String getNewName() {
- return newName;
+ public String getNewPath() {
+ return newPath;
}
/** @return the old file mode, if described in the patch */
@@ -294,14 +294,14 @@ public class DiffEntry {
return newMode;
}
- /** @return the type of change this patch makes on {@link #getNewName()} */
+ /** @return the type of change this patch makes on {@link #getNewPath()} */
public ChangeType getChangeType() {
return changeType;
}
/**
- * @return similarity score between {@link #getOldName()} and
- * {@link #getNewName()} if {@link #getChangeType()} is
+ * @return similarity score between {@link #getOldPath()} and
+ * {@link #getNewPath()} if {@link #getChangeType()} is
* {@link ChangeType#COPY} or {@link ChangeType#RENAME}.
*/
public int getScore() {
@@ -334,19 +334,19 @@ public class DiffEntry {
buf.append(" ");
switch (changeType) {
case ADD:
- buf.append(newName);
+ buf.append(newPath);
break;
case COPY:
- buf.append(oldName + "->" + newName);
+ buf.append(oldPath + "->" + newPath);
break;
case DELETE:
- buf.append(oldName);
+ buf.append(oldPath);
break;
case MODIFY:
- buf.append(oldName);
+ buf.append(oldPath);
break;
case RENAME:
- buf.append(oldName + "->" + newName);
+ buf.append(oldPath + "->" + newPath);
break;
}
buf.append("]");
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
index 4ee742ae16..bb4a77c427 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
@@ -246,8 +246,8 @@ public class DiffFormatter {
private void writeDiffHeader(OutputStream o, DiffEntry ent)
throws IOException {
- String oldName = quotePath("a/" + ent.getOldName());
- String newName = quotePath("b/" + ent.getNewName());
+ String oldName = quotePath("a/" + ent.getOldPath());
+ String newName = quotePath("b/" + ent.getNewPath());
o.write(encode("diff --git " + oldName + " " + newName + "\n"));
switch (ent.getChangeType()) {
@@ -267,10 +267,10 @@ public class DiffFormatter {
o.write(encodeASCII("similarity index " + ent.getScore() + "%"));
o.write('\n');
- o.write(encode("rename from " + quotePath(ent.getOldName())));
+ o.write(encode("rename from " + quotePath(ent.getOldPath())));
o.write('\n');
- o.write(encode("rename to " + quotePath(ent.getNewName())));
+ o.write(encode("rename to " + quotePath(ent.getNewPath())));
o.write('\n');
break;
@@ -278,10 +278,10 @@ public class DiffFormatter {
o.write(encodeASCII("similarity index " + ent.getScore() + "%"));
o.write('\n');
- o.write(encode("copy from " + quotePath(ent.getOldName())));
+ o.write(encode("copy from " + quotePath(ent.getOldPath())));
o.write('\n');
- o.write(encode("copy to " + quotePath(ent.getNewName())));
+ o.write(encode("copy to " + quotePath(ent.getNewPath())));
o.write('\n');
if (!ent.getOldMode().equals(ent.getNewMode())) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java
index fedd7cda15..3ae3dc422c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java
@@ -80,8 +80,8 @@ public class RenameDetector {
// the old name.
//
if (ent.changeType == ChangeType.DELETE)
- return ent.oldName;
- return ent.newName;
+ return ent.oldPath;
+ return ent.newPath;
}
private int sortOf(ChangeType changeType) {
@@ -369,18 +369,18 @@ public class RenameDetector {
+ deleted.size());
for (DiffEntry src : deleted) {
- nameMap.put(src.oldName, src);
+ nameMap.put(src.oldPath, src);
pm.update(1);
}
for (DiffEntry dst : added) {
- DiffEntry src = nameMap.remove(dst.newName);
+ DiffEntry src = nameMap.remove(dst.newPath);
if (src != null) {
if (sameType(src.oldMode, dst.newMode)) {
entries.add(DiffEntry.pair(ChangeType.MODIFY, src, dst,
src.score));
} else {
- nameMap.put(src.oldName, src);
+ nameMap.put(src.oldPath, src);
newAdded.add(dst);
}
} else {
@@ -509,10 +509,10 @@ public class RenameDetector {
long[] matrix = new long[dels.size() * adds.size()];
int mNext = 0;
for (int addIdx = 0; addIdx < adds.size(); addIdx++) {
- String addedName = adds.get(addIdx).newName;
+ String addedName = adds.get(addIdx).newPath;
for (int delIdx = 0; delIdx < dels.size(); delIdx++) {
- String deletedName = dels.get(delIdx).oldName;
+ String deletedName = dels.get(delIdx).oldPath;
int score = SimilarityRenameDetector.nameScore(addedName, deletedName);
matrix[mNext] = SimilarityRenameDetector.encode(score, addIdx, delIdx);
@@ -625,7 +625,7 @@ public class RenameDetector {
}
private static String path(DiffEntry de) {
- return de.changeType == ChangeType.DELETE ? de.oldName : de.newName;
+ return de.changeType == ChangeType.DELETE ? de.oldPath : de.newPath;
}
private static FileMode mode(DiffEntry de) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
index 22b74f461c..39bcebb4c3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityIndex.java
@@ -216,7 +216,8 @@ class SimilarityIndex {
for (;;) {
if (srcKey == dstKey) {
- common += countOf(dstHash[dstIdx]);
+ common += Math.min(countOf(srcHash[srcIdx]),
+ countOf(dstHash[dstIdx]));
if (++srcIdx == srcHash.length)
break;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityRenameDetector.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityRenameDetector.java
index d05fc2a313..643ac01525 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityRenameDetector.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/SimilarityRenameDetector.java
@@ -266,7 +266,7 @@ class SimilarityRenameDetector {
// nameScore returns a value between 0 and 100, but we want it
// to be in the same range as the content score. This allows it
// to be dropped into the pretty formula for the final score.
- int nameScore = nameScore(srcEnt.oldName, dstEnt.newName) * 100;
+ int nameScore = nameScore(srcEnt.oldPath, dstEnt.newPath) * 100;
int score = (contentScore * 99 + nameScore * 1) / 10000;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
index db0f942b07..d4e6ac9824 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
* Copyright (C) 2007-2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2010, Jens Baumgart <jens.baumgart@sap.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -44,97 +45,163 @@
package org.eclipse.jgit.lib;
-import java.io.File;
import java.io.IOException;
import java.util.HashSet;
-import org.eclipse.jgit.lib.GitIndex.Entry;
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheIterator;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.AbstractTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.WorkingTreeIterator;
+import org.eclipse.jgit.treewalk.filter.TreeFilter;
/**
- * Compares the Index, a Tree, and the working directory
- *
- * @deprecated Use {@link org.eclipse.jgit.treewalk.TreeWalk} instead, with at
- * least the {@link org.eclipse.jgit.dircache.DirCacheIterator} and
- * {@link org.eclipse.jgit.treewalk.FileTreeIterator} iterators, and setting
- * the filter {@link org.eclipse.jgit.treewalk.filter.TreeFilter#ANY_DIFF}.
+ * Compares the index, a tree, and the working directory
+ * Ignored files are not taken into account.
+ * The following information is retrieved:
+ * <li> added files
+ * <li> changed files
+ * <li> removed files
+ * <li> missing files
+ * <li> modified files
+ * <li> untracked files
*/
-@Deprecated
public class IndexDiff {
- private GitIndex index;
- private Tree tree;
+
+ private final static int TREE = 0;
+
+ private final static int INDEX = 1;
+
+ private final static int WORKDIR = 2;
+
+ private final Repository repository;
+
+ private final RevTree tree;
+
+ private final WorkingTreeIterator initialWorkingTreeIterator;
+
+ private HashSet<String> added = new HashSet<String>();
+
+ private HashSet<String> changed = new HashSet<String>();
+
+ private HashSet<String> removed = new HashSet<String>();
+
+ private HashSet<String> missing = new HashSet<String>();
+
+ private HashSet<String> modified = new HashSet<String>();
+
+ private HashSet<String> untracked = new HashSet<String>();
/**
- * Construct an indexdiff for diffing the workdir against
- * the index.
+ * Construct an IndexDiff
*
* @param repository
+ * @param revstr
+ * symbolic name e.g. HEAD
+ * @param workingTreeIterator
+ * iterator for working directory
* @throws IOException
*/
- public IndexDiff(Repository repository) throws IOException {
- this.tree = repository.mapTree(Constants.HEAD);
- this.index = repository.getIndex();
+ public IndexDiff(Repository repository, String revstr,
+ WorkingTreeIterator workingTreeIterator) throws IOException {
+ this.repository = repository;
+ ObjectId objectId = repository.resolve(revstr);
+ tree = new RevWalk(repository).parseTree(objectId);
+ this.initialWorkingTreeIterator = workingTreeIterator;
}
/**
- * Construct an indexdiff for diffing the workdir against both
- * the index and a tree.
+ * Construct an Indexdiff
*
- * @param tree
- * @param index
+ * @param repository
+ * @param objectId
+ * tree id
+ * @param workingTreeIterator
+ * iterator for working directory
+ * @throws IOException
*/
- public IndexDiff(Tree tree, GitIndex index) {
- this.tree = tree;
- this.index = index;
+ public IndexDiff(Repository repository, ObjectId objectId,
+ WorkingTreeIterator workingTreeIterator) throws IOException {
+ this.repository = repository;
+ tree = new RevWalk(repository).parseTree(objectId);
+ this.initialWorkingTreeIterator = workingTreeIterator;
}
- boolean anyChanges = false;
-
/**
* Run the diff operation. Until this is called, all lists will be empty
+ *
* @return if anything is different between index, tree, and workdir
* @throws IOException
*/
public boolean diff() throws IOException {
- final File root = index.getRepository().getWorkTree();
- new IndexTreeWalker(index, tree, root, new AbstractIndexTreeVisitor() {
- public void visitEntry(TreeEntry treeEntry, Entry indexEntry, File file) {
- if (treeEntry == null) {
- added.add(indexEntry.getName());
- anyChanges = true;
- } else if (indexEntry == null) {
- if (!(treeEntry instanceof Tree))
- removed.add(treeEntry.getFullName());
- anyChanges = true;
+ boolean changesExist = false;
+ DirCache dirCache = repository.readDirCache();
+ TreeWalk treeWalk = new TreeWalk(repository);
+ treeWalk.reset();
+ treeWalk.setRecursive(true);
+ // add the trees (tree, dirchache, workdir)
+ treeWalk.addTree(tree);
+ treeWalk.addTree(new DirCacheIterator(dirCache));
+ treeWalk.addTree(initialWorkingTreeIterator);
+ treeWalk.setFilter(TreeFilter.ANY_DIFF);
+ while (treeWalk.next()) {
+ AbstractTreeIterator treeIterator = treeWalk.getTree(TREE,
+ AbstractTreeIterator.class);
+ DirCacheIterator dirCacheIterator = treeWalk.getTree(INDEX,
+ DirCacheIterator.class);
+ WorkingTreeIterator workingTreeIterator = treeWalk.getTree(WORKDIR,
+ WorkingTreeIterator.class);
+ FileMode fileModeTree = treeWalk.getFileMode(TREE);
+
+ if (treeIterator != null) {
+ if (dirCacheIterator != null) {
+ if (!treeIterator.getEntryObjectId().equals(
+ dirCacheIterator.getEntryObjectId())) {
+ // in repo, in index, content diff => changed
+ changed.add(dirCacheIterator.getEntryPathString());
+ changesExist = true;
+ }
} else {
- if (!treeEntry.getId().equals(indexEntry.getObjectId())) {
- changed.add(indexEntry.getName());
- anyChanges = true;
+ // in repo, not in index => removed
+ if (!fileModeTree.equals(FileMode.TYPE_TREE)) {
+ removed.add(treeIterator.getEntryPathString());
+ changesExist = true;
}
}
-
- if (indexEntry != null) {
- if (!file.exists()) {
- missing.add(indexEntry.getName());
- anyChanges = true;
- } else {
- if (indexEntry.isModified(root, true)) {
- modified.add(indexEntry.getName());
- anyChanges = true;
- }
+ } else {
+ if (dirCacheIterator != null) {
+ // not in repo, in index => added
+ added.add(dirCacheIterator.getEntryPathString());
+ changesExist = true;
+ } else {
+ // not in repo, not in index => untracked
+ if (workingTreeIterator != null
+ && !workingTreeIterator.isEntryIgnored()) {
+ untracked.add(workingTreeIterator.getEntryPathString());
+ changesExist = true;
}
}
}
- }).walk();
- return anyChanges;
+ if (dirCacheIterator != null) {
+ if (workingTreeIterator == null) {
+ // in index, not in workdir => missing
+ missing.add(dirCacheIterator.getEntryPathString());
+ changesExist = true;
+ } else {
+ if (!dirCacheIterator.idEqual(workingTreeIterator)) {
+ // in index, in workdir, content differs => modified
+ modified.add(dirCacheIterator.getEntryPathString());
+ changesExist = true;
+ }
+ }
+ }
+ }
+ return changesExist;
}
- HashSet<String> added = new HashSet<String>();
- HashSet<String> changed = new HashSet<String>();
- HashSet<String> removed = new HashSet<String>();
- HashSet<String> missing = new HashSet<String>();
- HashSet<String> modified = new HashSet<String>();
-
/**
* @return list of files added to the index, not in the tree
*/
@@ -169,4 +236,11 @@ public class IndexDiff {
public HashSet<String> getModified() {
return modified;
}
+
+ /**
+ * @return list of files on modified on disk relative to the index
+ */
+ public HashSet<String> getUntracked() {
+ return untracked;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/WorkDirCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/WorkDirCheckout.java
index ef3d7840f7..beab61abe2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/WorkDirCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/WorkDirCheckout.java
@@ -165,6 +165,10 @@ public class WorkDirCheckout {
private void checkoutOutIndexNoHead() throws IOException {
new IndexTreeWalker(index, merge, root, new AbstractIndexTreeVisitor() {
public void visitEntry(TreeEntry m, Entry i, File f) throws IOException {
+ // TODO remove this once we support submodules
+ if (f.getName().equals(".gitmodules"))
+ throw new UnsupportedOperationException(
+ JGitText.get().submodulesNotSupported);
if (m == null) {
index.remove(root, f);
return;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java b/org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java
index 0c24fc6be2..eae1040f09 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/patch/FileHeader.java
@@ -385,12 +385,12 @@ public class FileHeader extends DiffEntry {
if (buf[sp - 2] != '"') {
return eol;
}
- oldName = QuotedString.GIT_PATH.dequote(buf, bol, sp - 1);
- oldName = p1(oldName);
+ oldPath = QuotedString.GIT_PATH.dequote(buf, bol, sp - 1);
+ oldPath = p1(oldPath);
} else {
- oldName = decode(Constants.CHARSET, buf, aStart, sp - 1);
+ oldPath = decode(Constants.CHARSET, buf, aStart, sp - 1);
}
- newName = oldName;
+ newPath = oldPath;
return eol;
}
@@ -431,27 +431,27 @@ public class FileHeader extends DiffEntry {
parseNewFileMode(ptr, eol);
} else if (match(buf, ptr, COPY_FROM) >= 0) {
- oldName = parseName(oldName, ptr + COPY_FROM.length, eol);
+ oldPath = parseName(oldPath, ptr + COPY_FROM.length, eol);
changeType = ChangeType.COPY;
} else if (match(buf, ptr, COPY_TO) >= 0) {
- newName = parseName(newName, ptr + COPY_TO.length, eol);
+ newPath = parseName(newPath, ptr + COPY_TO.length, eol);
changeType = ChangeType.COPY;
} else if (match(buf, ptr, RENAME_OLD) >= 0) {
- oldName = parseName(oldName, ptr + RENAME_OLD.length, eol);
+ oldPath = parseName(oldPath, ptr + RENAME_OLD.length, eol);
changeType = ChangeType.RENAME;
} else if (match(buf, ptr, RENAME_NEW) >= 0) {
- newName = parseName(newName, ptr + RENAME_NEW.length, eol);
+ newPath = parseName(newPath, ptr + RENAME_NEW.length, eol);
changeType = ChangeType.RENAME;
} else if (match(buf, ptr, RENAME_FROM) >= 0) {
- oldName = parseName(oldName, ptr + RENAME_FROM.length, eol);
+ oldPath = parseName(oldPath, ptr + RENAME_FROM.length, eol);
changeType = ChangeType.RENAME;
} else if (match(buf, ptr, RENAME_TO) >= 0) {
- newName = parseName(newName, ptr + RENAME_TO.length, eol);
+ newPath = parseName(newPath, ptr + RENAME_TO.length, eol);
changeType = ChangeType.RENAME;
} else if (match(buf, ptr, SIMILARITY_INDEX) >= 0) {
@@ -474,14 +474,14 @@ public class FileHeader extends DiffEntry {
}
void parseOldName(int ptr, final int eol) {
- oldName = p1(parseName(oldName, ptr + OLD_NAME.length, eol));
- if (oldName == DEV_NULL)
+ oldPath = p1(parseName(oldPath, ptr + OLD_NAME.length, eol));
+ if (oldPath == DEV_NULL)
changeType = ChangeType.ADD;
}
void parseNewName(int ptr, final int eol) {
- newName = p1(parseName(newName, ptr + NEW_NAME.length, eol));
- if (newName == DEV_NULL)
+ newPath = p1(parseName(newPath, ptr + NEW_NAME.length, eol));
+ if (newPath == DEV_NULL)
changeType = ChangeType.DELETE;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java
index a068943fbc..dc9e0321f5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java
@@ -65,19 +65,16 @@ public class PlotCommit<L extends PlotLane> extends RevCommit {
PlotCommit[] children;
- final Ref[] refs;
+ Ref[] refs;
/**
* Create a new commit.
*
* @param id
* the identity of this commit.
- * @param tags
- * the tags associated with this commit, null for no tags
*/
- protected PlotCommit(final AnyObjectId id, final Ref[] tags) {
+ protected PlotCommit(final AnyObjectId id) {
super(id);
- this.refs = tags;
passingLanes = NO_LANES;
children = NO_CHILDREN;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java
index 476592f5d9..c69e66cb8c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotWalk.java
@@ -52,6 +52,8 @@ import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.JGitText;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
@@ -94,14 +96,19 @@ public class PlotWalk extends RevWalk {
@Override
protected RevCommit createCommit(final AnyObjectId id) {
- return new PlotCommit(id, getTags(id));
+ return new PlotCommit(id);
}
- /**
- * @param commitId
- * @return return the list of knows tags referring to this commit
- */
- protected Ref[] getTags(final AnyObjectId commitId) {
+ @Override
+ public RevCommit next() throws MissingObjectException,
+ IncorrectObjectTypeException, IOException {
+ PlotCommit<?> pc = (PlotCommit) super.next();
+ if (pc != null)
+ pc.refs = getTags(pc);
+ return pc;
+ }
+
+ private Ref[] getTags(final AnyObjectId commitId) {
Collection<Ref> list = reverseRefMap.get(commitId);
Ref[] tags;
if (list == null)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteTreeFilter.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteTreeFilter.java
index 8ec2d2b091..41cfcf8691 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteTreeFilter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteTreeFilter.java
@@ -245,8 +245,8 @@ class RewriteTreeFilter extends RevFilter {
TreeFilter newFilter = oldFilter;
for (DiffEntry ent : files) {
- if (isRename(ent) && ent.getNewName().equals(oldFilter.getPath())) {
- newFilter = FollowFilter.create(ent.getOldName());
+ if (isRename(ent) && ent.getNewPath().equals(oldFilter.getPath())) {
+ newFilter = FollowFilter.create(ent.getOldPath());
break;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/UnpackedObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/UnpackedObject.java
index 59f9c82670..78e7b10a7d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/UnpackedObject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/UnpackedObject.java
@@ -296,9 +296,9 @@ public class UnpackedObject {
try {
if (remaining <= 0)
checkValidEndOfStream(in, inf, id, new byte[64]);
- super.close();
} finally {
InflaterCache.release(inf);
+ super.close();
}
}
};
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
index 99126e8615..2d6acbddf0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java
@@ -87,6 +87,8 @@ public class NameConflictTreeWalk extends TreeWalk {
private boolean fastMinHasMatch;
+ private AbstractTreeIterator dfConflict;
+
/**
* Create a new tree walker for a given repository.
*
@@ -141,6 +143,7 @@ public class NameConflictTreeWalk extends TreeWalk {
if (minRef.eof())
return minRef;
+ boolean hasConflict = false;
minRef.matches = minRef;
while (++i < trees.length) {
final AbstractTreeIterator t = trees[i];
@@ -156,6 +159,7 @@ public class NameConflictTreeWalk extends TreeWalk {
// tree anyway.
//
t.matches = minRef;
+ hasConflict = true;
} else {
fastMinHasMatch = false;
t.matches = t;
@@ -182,10 +186,13 @@ public class NameConflictTreeWalk extends TreeWalk {
}
t.matches = t;
minRef = t;
+ hasConflict = true;
} else
fastMinHasMatch = false;
}
+ if (hasConflict && fastMinHasMatch && dfConflict == null)
+ dfConflict = minRef;
return minRef;
}
@@ -281,6 +288,10 @@ public class NameConflictTreeWalk extends TreeWalk {
for (final AbstractTreeIterator t : trees)
if (t.matches == minRef)
t.matches = treeMatch;
+
+ if (dfConflict == null)
+ dfConflict = treeMatch;
+
return treeMatch;
}
@@ -302,6 +313,9 @@ public class NameConflictTreeWalk extends TreeWalk {
t.matches = null;
}
}
+
+ if (ch == dfConflict)
+ dfConflict = null;
}
@Override
@@ -319,5 +333,26 @@ public class NameConflictTreeWalk extends TreeWalk {
t.matches = null;
}
}
+
+ if (ch == dfConflict)
+ dfConflict = null;
+ }
+
+ /**
+ * True if the current entry is covered by a directory/file conflict.
+ *
+ * This means that for some prefix of the current entry's path, this walk
+ * has detected a directory/file conflict. Also true if the current entry
+ * itself is a directory/file conflict.
+ *
+ * Example: If this TreeWalk points to foo/bar/a.txt and this method returns
+ * true then you know that either for path foo or for path foo/bar files and
+ * folders were detected.
+ *
+ * @return <code>true</code> if the current entry is covered by a
+ * directory/file conflict, <code>false</code> otherwise
+ */
+ public boolean isDirectoryFileConflict() {
+ return dfConflict != null;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
index 2ffcbed9f1..a8e505d6e5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/ChangeIdUtil.java
@@ -61,6 +61,8 @@ import org.eclipse.jgit.lib.PersonIdent;
*/
public class ChangeIdUtil {
+ static final String CHANGE_ID = "Change-Id:";
+
// package-private so the unit test can test this part only
static String clean(String msg) {
return msg.//
@@ -136,8 +138,39 @@ public class ChangeIdUtil {
* @return a commit message with an inserted Change-Id line
*/
public static String insertId(String message, ObjectId changeId) {
- if (message.indexOf("\nChange-Id:") > 0)
+ return insertId(message, changeId, false);
+ }
+
+ /**
+ * Find the right place to insert a Change-Id and return it.
+ * <p>
+ * If no Change-Id is found the Change-Id is inserted before
+ * the first footer line but after a Bug line.
+ *
+ * If Change-Id is found and replaceExisting is set to false,
+ * the message is unchanged.
+ *
+ * If Change-Id is found and replaceExisting is set to true,
+ * the Change-Id is replaced with {@code changeId}.
+ *
+ * @param message
+ * @param changeId
+ * @param replaceExisting
+ * @return a commit message with an inserted Change-Id line
+ */
+ public static String insertId(String message, ObjectId changeId,
+ boolean replaceExisting) {
+ if (message.indexOf(CHANGE_ID) > 0) {
+ if (replaceExisting) {
+ int i = message.indexOf(CHANGE_ID) + 10;
+ while (message.charAt(i) == ' ')
+ i++;
+ String oldId = message.length() == (i + 40) ?
+ message.substring(i) : message.substring(i, i + 41);
+ message = message.replace(oldId, "I" + changeId.getName());
+ }
return message;
+ }
String[] lines = message.split("\n");
int footerFirstLine = lines.length;
@@ -173,7 +206,8 @@ public class ChangeIdUtil {
}
if (insertAfter == lines.length && insertAfter == footerFirstLine)
ret.append("\n");
- ret.append("Change-Id: I");
+ ret.append(CHANGE_ID);
+ ret.append(" I");
ret.append(ObjectId.toString(changeId));
ret.append("\n");
for (; i < lines.length; ++i) {

Back to the top