Merge changes I39bfefee,I47795987,I70d120fb,I58cc5e01,I96bee7b9
* changes:
Enable configuration of non-standard pack settings
Pass PackConfig down to PackWriter when packing
Simplify UploadPack use of options during writing
Move PackWriter configuration to PackConfig
Allow PackWriter callers to manage the thread pool
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 77ed730..ebdb74f 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 @@ static void nameStatus(PrintWriter out, List<DiffEntry> files) {
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 48a0591..fbc019f 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 @@ private boolean isAdd(List<DiffEntry> files) {
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 @@ private boolean isAdd(List<DiffEntry> files) {
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 5bad4ef..9b51b87 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 @@ protected void run() throws Exception {
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 ae9fb0e..ff442b6 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 @@ void onCommit(String cid, byte[] buf) {
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 9e195b4..a7d0984 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 void testAddExistingSingleFile() throws IOException, NoFilepatternExcepti
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 void testAddExistingSingleFileInSubDir() throws IOException, NoFilepatter
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 void testAddExistingSingleFileTwice() throws IOException, NoFilepatternEx
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 void testAddExistingSingleFileTwice() throws IOException, NoFilepatternEx
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 void testAddExistingSingleFileTwiceWithCommit() throws Exception {
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 void testAddExistingSingleFileTwiceWithCommit() throws Exception {
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 void testAddRemovedFile() throws Exception {
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 void testAddRemovedCommittedFile() throws Exception {
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 void testAddWithConflicts() throws Exception {
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 void testAddTwoFiles() throws Exception {
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 void testAddFolder() throws Exception {
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 void testAddIgnoredFile() throws Exception {
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 void testAddWholeRepo() throws Exception {
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 a62045d..cf30039 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 @@
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.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 void testMergeEmptyBranches() throws IOException, NoHeadException,
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 eb965cf..26116d2 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 void testInexactRename_NewlinesOnly() throws Exception {
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 void testBreakModify_RejoinIfUnpaired() throws Exception {
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 @@ private static void assertRename(DiffEntry o, DiffEntry n, int score,
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 @@ private static void assertCopy(DiffEntry o, DiffEntry n, int score,
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 @@ private static void assertCopy(DiffEntry o, DiffEntry n, int score,
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 ac7ce5b..c439bac 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 @@
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 void testAdded() throws IOException {
}
public void testRemoved() throws IOException {
- GitIndex index = new GitIndex(db);
writeTrashFile("file2", "file2");
writeTrashFile("dir/file3", "dir/file3");
@@ -82,7 +86,8 @@ public void testRemoved() throws IOException {
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 void testModified() throws IOException {
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 void testModified() throws IOException {
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 void testUnchangedSimple() throws IOException {
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 void testUnchangedSimple() throws IOException {
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 void testUnchangedComplex() throws IOException {
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 void testUnchangedComplex() throws IOException {
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 0000000..e208b27
--- /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 e78f851..963c9d0 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.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 @@ protected void setUp() throws Exception {
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 17e9977..813a701 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 void testParseGitFileName_Foo() {
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 void testParseGitFileName_FooSpBar() {
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 void testParseGitFileName_DqFooTabBar() {
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 void testParseGitFileName_DqFooSpLfNulBar() {
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 void testParseGitFileName_SrcFooC() {
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 void testParseGitFileName_SrcFooCNonStandardPrefix() {
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 void testParseUnicodeName_NewFile() {
+ "@@ -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 void testParseUnicodeName_DeleteFile() {
+ "@@ -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 void testParseModeChange() {
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 void testParseRename100_NewStyle() {
+ "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 void testParseRename100_OldStyle() {
+ "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 void testParseCopy100() {
+ "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 void testParseFullIndexLine_WithMode() {
+ ".." + 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 void testParseFullIndexLine_NoMode() {
+ ".." + 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 void testParseAbbrIndexLine_WithMode() {
+ " 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 void testParseAbbrIndexLine_NoMode() {
+ "\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 1d879cb..cef13f5 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 void testParse_OneFileCc() throws IOException {
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 void testParse_CcNewFile() throws IOException {
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 void testParse_CcDeleteFile() throws IOException {
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 62a1071..67b3f5c 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 void testError_DisconnectedHunk() throws IOException {
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 void testError_GarbageBetweenFiles() throws IOException {
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 void testError_GitBinaryNoForwardHunk() throws IOException {
{
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 void testError_GitBinaryNoForwardHunk() throws IOException {
{
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 52d6e27..dd76251 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 void testParse_ConfigCaseInsensitive() throws IOException {
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 void testParse_NoBinary() throws IOException {
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 void testParse_NoBinary() throws IOException {
}
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 void testParse_GitBinaryLiteral() throws IOException {
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 void testParse_GitBinaryLiteral() throws IOException {
}
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 void testParse_GitBinaryDelta() throws IOException {
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 void testParse_FixNoNewline() throws IOException {
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 void testParse_AddNoNewline() throws IOException {
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 0000000..bb76d00
--- /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 675331b..e59b7c1 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 void testDF_NoGap() throws Exception {
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 void testDF_GapByOne() throws Exception {
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 void testDF_SkipsSeenSubtree() throws Exception {
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 3b15846..a15cadf 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 void testHasChangeid() throws Exception {
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 void testChangeIdAlreadySet() throws Exception {
"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 @@ private void hookDoesNotModify(final String in) throws Exception {
}
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 1b2b81f..a9878f8 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 @@
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 9d1e2cd..461242c 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 static JGitText get() {
/***/ 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 e41ab58..f7d4da4 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 DirCache call() throws NoFilepatternException {
// 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));
+ 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 {
- c = tw.getTree(0, DirCacheIterator.class);
- builder.add(c.getDirCacheEntry());
+ builder.add(entry);
+ lastAddedFile = path;
+ } else if (!update){
+ c = tw.getTree(0, DirCacheIterator.class);
+ builder.add(c.getDirCacheEntry());
+ }
}
}
}
@@ -186,4 +190,29 @@ else if (!(path.equals(lastAddedFile))) {
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 17b7113..ae4b334 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 RevCommit call() throws NoHeadException, NoMessageException,
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 RevCommit call() throws NoHeadException, NoMessageException,
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 CommitCommand setAuthor(String name, String email) {
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 7dbcdaa..55ecc4e 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 static List<DiffEntry> scan(TreeWalk walk) throws IOException {
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 @@ static DiffEntry add(String path, AnyObjectId id) {
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 @@ static DiffEntry delete(String path, AnyObjectId id) {
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 @@ static DiffEntry delete(String path, AnyObjectId id) {
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 @@ static List<DiffEntry> breakModify(DiffEntry entry) {
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 @@ static DiffEntry pair(ChangeType changeType, DiffEntry src, DiffEntry dst,
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 @@ static DiffEntry pair(ChangeType changeType, DiffEntry src, DiffEntry dst,
}
/** 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 @@ static DiffEntry pair(ChangeType changeType, DiffEntry src, DiffEntry dst,
* 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 @@ static DiffEntry pair(ChangeType changeType, DiffEntry src, DiffEntry dst,
*
* @return old name for this file.
*/
- public String getOldName() {
- return oldName;
+ public String getOldPath() {
+ return oldPath;
}
/**
@@ -272,7 +272,7 @@ public String getOldName() {
* 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 String getOldName() {
*
* @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 FileMode getNewMode() {
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 String toString() {
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 4ee742a..bb4a77c 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 @@ private void writeGitLinkDiffText(OutputStream o, DiffEntry ent)
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 @@ private void writeDiffHeader(OutputStream o, DiffEntry ent)
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 @@ private void writeDiffHeader(OutputStream o, DiffEntry ent)
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 fedd7cd..3ae3dc4 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 @@ private String nameOf(DiffEntry ent) {
// 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 @@ private void rejoinModifies(ProgressMonitor pm) {
+ 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 @@ private void findExactRenames(ProgressMonitor pm) {
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 @@ private HashMap<AbbreviatedObjectId, Object> populateMap(
}
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 22b74f4..39bcebb 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 @@ private static int common(long[] srcHash, int srcIdx, //
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 d05fc2a..643ac01 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 @@ private int buildMatrix(ProgressMonitor pm) throws IOException {
// 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 db0f942..d4e6ac9 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 HashSet<String> getMissing() {
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 ef3d784..beab61a 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 @@ private void checkoutTwoTrees() throws FileNotFoundException, IOException {
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 0c24fc6..eae1040 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 @@ int parseGitFileName(int ptr, final int end) {
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 @@ int parseGitHeaders(int ptr, final int end) {
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 @@ int parseGitHeaders(int ptr, final int end) {
}
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 a068943..dc9e032 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 476592f..c69e66c 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.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 void sort(final RevSort s, final boolean use) {
@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 8ec2d2b..41cfcf8 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 @@ private void updateFollowFilter(ObjectId[] trees)
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 59f9c82..78e7b10 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 void close() throws IOException {
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 99126e8..2d6acbd 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 @@ private AbstractTreeIterator fastMin() {
if (minRef.eof())
return minRef;
+ boolean hasConflict = false;
minRef.matches = minRef;
while (++i < trees.length) {
final AbstractTreeIterator t = trees[i];
@@ -156,6 +159,7 @@ && nameEqual(minRef, t)) {
// tree anyway.
//
t.matches = minRef;
+ hasConflict = true;
} else {
fastMinHasMatch = false;
t.matches = t;
@@ -182,10 +186,13 @@ && nameEqual(t, minRef)) {
}
t.matches = t;
minRef = t;
+ hasConflict = true;
} else
fastMinHasMatch = false;
}
+ if (hasConflict && fastMinHasMatch && dfConflict == null)
+ dfConflict = minRef;
return minRef;
}
@@ -281,6 +288,10 @@ private AbstractTreeIterator combineDF(final AbstractTreeIterator minRef)
for (final AbstractTreeIterator t : trees)
if (t.matches == minRef)
t.matches = treeMatch;
+
+ if (dfConflict == null)
+ dfConflict = treeMatch;
+
return treeMatch;
}
@@ -302,6 +313,9 @@ void popEntriesEqual() throws CorruptObjectException {
t.matches = null;
}
}
+
+ if (ch == dfConflict)
+ dfConflict = null;
}
@Override
@@ -319,5 +333,26 @@ void skipEntriesEqual() throws CorruptObjectException {
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 2ffcbed..a8e505d 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 @@
*/
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 static ObjectId computeChangeId(final ObjectId treeId,
* @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 static String insertId(String message, ObjectId changeId) {
}
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) {