summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java39
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java107
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java42
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java101
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java4
5 files changed, 290 insertions, 3 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
index b1cac3a54d..a51a8b4697 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
@@ -61,6 +61,8 @@ import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
@@ -236,4 +238,41 @@ public class CheckoutCommandTest extends RepositoryTestCase {
assertFalse(head.isSymbolic());
assertSame(head, head.getTarget());
}
+
+ @Test
+ public void testUpdateSmudgedEntries() throws Exception {
+ git.branchCreate().setName("test2").call();
+ RefUpdate rup = db.updateRef(Constants.HEAD);
+ rup.link("refs/heads/test2");
+
+ File file = new File(db.getWorkTree(), "Test.txt");
+ long size = file.length();
+ long mTime = file.lastModified() - 5000L;
+ assertTrue(file.setLastModified(mTime));
+
+ DirCache cache = DirCache.lock(db.getIndexFile(), db.getFS());
+ DirCacheEntry entry = cache.getEntry("Test.txt");
+ assertNotNull(entry);
+ entry.setLength(0);
+ entry.setLastModified(0);
+ cache.write();
+ assertTrue(cache.commit());
+
+ cache = DirCache.read(db.getIndexFile(), db.getFS());
+ entry = cache.getEntry("Test.txt");
+ assertNotNull(entry);
+ assertEquals(0, entry.getLength());
+ assertEquals(0, entry.getLastModified());
+
+ db.getIndexFile().setLastModified(
+ db.getIndexFile().lastModified() - 5000);
+
+ assertNotNull(git.checkout().setName("test").call());
+
+ cache = DirCache.read(db.getIndexFile(), db.getFS());
+ entry = cache.getEntry("Test.txt");
+ assertNotNull(entry);
+ assertEquals(size, entry.getLength());
+ assertEquals(mTime, entry.getLastModified());
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
index b9f5882d50..3aec611f44 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
@@ -50,6 +50,7 @@ import java.io.File;
import java.util.List;
import org.eclipse.jgit.diff.DiffEntry;
+import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
@@ -258,4 +259,110 @@ public class CommitCommandTest extends RepositoryTestCase {
assertEquals(path, subDiff.getNewPath());
assertEquals(path, subDiff.getOldPath());
}
+
+ @Test
+ public void commitUpdatesSmudgedEntries() throws Exception {
+ Git git = new Git(db);
+
+ File file1 = writeTrashFile("file1.txt", "content1");
+ assertTrue(file1.setLastModified(file1.lastModified() - 5000));
+ File file2 = writeTrashFile("file2.txt", "content2");
+ assertTrue(file2.setLastModified(file2.lastModified() - 5000));
+ File file3 = writeTrashFile("file3.txt", "content3");
+ assertTrue(file3.setLastModified(file3.lastModified() - 5000));
+
+ assertNotNull(git.add().addFilepattern("file1.txt")
+ .addFilepattern("file2.txt").addFilepattern("file3.txt").call());
+ RevCommit commit = git.commit().setMessage("add files").call();
+ assertNotNull(commit);
+
+ DirCache cache = DirCache.read(db.getIndexFile(), db.getFS());
+ int file1Size = cache.getEntry("file1.txt").getLength();
+ int file2Size = cache.getEntry("file2.txt").getLength();
+ int file3Size = cache.getEntry("file3.txt").getLength();
+ ObjectId file2Id = cache.getEntry("file2.txt").getObjectId();
+ ObjectId file3Id = cache.getEntry("file3.txt").getObjectId();
+ assertTrue(file1Size > 0);
+ assertTrue(file2Size > 0);
+ assertTrue(file3Size > 0);
+
+ // Smudge entries
+ cache = DirCache.lock(db.getIndexFile(), db.getFS());
+ cache.getEntry("file1.txt").setLength(0);
+ cache.getEntry("file2.txt").setLength(0);
+ cache.getEntry("file3.txt").setLength(0);
+ cache.write();
+ assertTrue(cache.commit());
+
+ // Verify entries smudged
+ cache = DirCache.read(db.getIndexFile(), db.getFS());
+ assertEquals(0, cache.getEntry("file1.txt").getLength());
+ assertEquals(0, cache.getEntry("file2.txt").getLength());
+ assertEquals(0, cache.getEntry("file3.txt").getLength());
+
+ long indexTime = db.getIndexFile().lastModified();
+ db.getIndexFile().setLastModified(indexTime - 5000);
+
+ write(file1, "content4");
+ assertTrue(file1.setLastModified(file1.lastModified() + 1000));
+ assertNotNull(git.commit().setMessage("edit file").setOnly("file1.txt")
+ .call());
+
+ cache = db.readDirCache();
+ assertEquals(file1Size, cache.getEntry("file1.txt").getLength());
+ assertEquals(file2Size, cache.getEntry("file2.txt").getLength());
+ assertEquals(file3Size, cache.getEntry("file3.txt").getLength());
+ assertEquals(file2Id, cache.getEntry("file2.txt").getObjectId());
+ assertEquals(file3Id, cache.getEntry("file3.txt").getObjectId());
+ }
+
+ @Test
+ public void commitIgnoresSmudgedEntryWithDifferentId() throws Exception {
+ Git git = new Git(db);
+
+ File file1 = writeTrashFile("file1.txt", "content1");
+ assertTrue(file1.setLastModified(file1.lastModified() - 5000));
+ File file2 = writeTrashFile("file2.txt", "content2");
+ assertTrue(file2.setLastModified(file2.lastModified() - 5000));
+
+ assertNotNull(git.add().addFilepattern("file1.txt")
+ .addFilepattern("file2.txt").call());
+ RevCommit commit = git.commit().setMessage("add files").call();
+ assertNotNull(commit);
+
+ DirCache cache = DirCache.read(db.getIndexFile(), db.getFS());
+ int file1Size = cache.getEntry("file1.txt").getLength();
+ int file2Size = cache.getEntry("file2.txt").getLength();
+ assertTrue(file1Size > 0);
+ assertTrue(file2Size > 0);
+
+ writeTrashFile("file2.txt", "content3");
+ assertNotNull(git.add().addFilepattern("file2.txt").call());
+ writeTrashFile("file2.txt", "content4");
+
+ // Smudge entries
+ cache = DirCache.lock(db.getIndexFile(), db.getFS());
+ cache.getEntry("file1.txt").setLength(0);
+ cache.getEntry("file2.txt").setLength(0);
+ cache.write();
+ assertTrue(cache.commit());
+
+ // Verify entries smudged
+ cache = db.readDirCache();
+ assertEquals(0, cache.getEntry("file1.txt").getLength());
+ assertEquals(0, cache.getEntry("file2.txt").getLength());
+
+ long indexTime = db.getIndexFile().lastModified();
+ db.getIndexFile().setLastModified(indexTime - 5000);
+
+ write(file1, "content5");
+ assertTrue(file1.setLastModified(file1.lastModified() + 1000));
+
+ assertNotNull(git.commit().setMessage("edit file").setOnly("file1.txt")
+ .call());
+
+ cache = db.readDirCache();
+ assertEquals(file1Size, cache.getEntry("file1.txt").getLength());
+ assertEquals(0, cache.getEntry("file2.txt").getLength());
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
index 27c3549be3..3087ca829b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
@@ -220,6 +220,48 @@ public class ResetCommandTest extends RepositoryTestCase {
}
@Test
+ public void testMixedResetRetainsSizeAndModifiedTime() throws Exception {
+ git = new Git(db);
+
+ writeTrashFile("a.txt", "a").setLastModified(
+ System.currentTimeMillis() - 60 * 1000);
+ assertNotNull(git.add().addFilepattern("a.txt").call());
+ assertNotNull(git.commit().setMessage("a commit").call());
+
+ writeTrashFile("b.txt", "b").setLastModified(
+ System.currentTimeMillis() - 60 * 1000);
+ assertNotNull(git.add().addFilepattern("b.txt").call());
+ RevCommit commit2 = git.commit().setMessage("b commit").call();
+ assertNotNull(commit2);
+
+ DirCache cache = db.readDirCache();
+
+ DirCacheEntry aEntry = cache.getEntry("a.txt");
+ assertNotNull(aEntry);
+ assertTrue(aEntry.getLength() > 0);
+ assertTrue(aEntry.getLastModified() > 0);
+
+ DirCacheEntry bEntry = cache.getEntry("b.txt");
+ assertNotNull(bEntry);
+ assertTrue(bEntry.getLength() > 0);
+ assertTrue(bEntry.getLastModified() > 0);
+
+ git.reset().setMode(ResetType.MIXED).setRef(commit2.getName()).call();
+
+ cache = db.readDirCache();
+
+ DirCacheEntry mixedAEntry = cache.getEntry("a.txt");
+ assertNotNull(mixedAEntry);
+ assertEquals(aEntry.getLastModified(), mixedAEntry.getLastModified());
+ assertEquals(aEntry.getLastModified(), mixedAEntry.getLastModified());
+
+ DirCacheEntry mixedBEntry = cache.getEntry("b.txt");
+ assertNotNull(mixedBEntry);
+ assertEquals(bEntry.getLastModified(), mixedBEntry.getLastModified());
+ assertEquals(bEntry.getLastModified(), mixedBEntry.getLastModified());
+ }
+
+ @Test
public void testPathsReset() throws Exception {
setupRepository();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
index 0d5952df24..9108d9235d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
@@ -69,8 +69,11 @@ import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileSnapshot;
import org.eclipse.jgit.storage.file.LockFile;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.MutableInteger;
@@ -145,6 +148,30 @@ public class DirCache {
* failures are reported as exceptions and therefore prevent the method from
* returning a partially populated index.
*
+ * @param repository
+ * repository containing the index to read
+ * @return a cache representing the contents of the specified index file (if
+ * it exists) or an empty cache if the file does not exist.
+ * @throws IOException
+ * the index file is present but could not be read.
+ * @throws CorruptObjectException
+ * the index file is using a format or extension that this
+ * library does not support.
+ */
+ public static DirCache read(final Repository repository)
+ throws CorruptObjectException, IOException {
+ final DirCache c = read(repository.getIndexFile(), repository.getFS());
+ c.repository = repository;
+ return c;
+ }
+
+ /**
+ * Create a new in-core index representation and read an index from disk.
+ * <p>
+ * The new index will be read before it is returned to the caller. Read
+ * failures are reported as exceptions and therefore prevent the method from
+ * returning a partially populated index.
+ *
* @param indexLocation
* location of the index file on disk.
* @param fs
@@ -217,6 +244,37 @@ public class DirCache {
* the method from returning a partially populated index. On read failure,
* the lock is released.
*
+ * @param repository
+ * repository containing the index to lock and read
+ * @param indexChangedListener
+ * listener to be informed when DirCache is committed
+ * @return a cache representing the contents of the specified index file (if
+ * it exists) or an empty cache if the file does not exist.
+ * @throws IOException
+ * the index file is present but could not be read, or the lock
+ * could not be obtained.
+ * @throws CorruptObjectException
+ * the index file is using a format or extension that this
+ * library does not support.
+ * @since 2.0
+ */
+ public static DirCache lock(final Repository repository,
+ final IndexChangedListener indexChangedListener)
+ throws CorruptObjectException, IOException {
+ DirCache c = lock(repository.getIndexFile(), repository.getFS(),
+ indexChangedListener);
+ c.repository = repository;
+ return c;
+ }
+
+ /**
+ * Create a new in-core index representation, lock it, and read from disk.
+ * <p>
+ * The new index will be locked and then read before it is returned to the
+ * caller. Read failures are reported as exceptions and therefore prevent
+ * the method from returning a partially populated index. On read failure,
+ * the lock is released.
+ *
* @param indexLocation
* location of the index file on disk.
* @param fs
@@ -272,6 +330,9 @@ public class DirCache {
/** listener to be informed on commit */
private IndexChangedListener indexChangedListener;
+ /** Repository containing this index */
+ private Repository repository;
+
/**
* Create a new in-core index representation.
* <p>
@@ -591,6 +652,13 @@ public class DirCache {
smudge_s = 0;
}
+ // Check if tree is non-null here since calling updateSmudgedEntries
+ // will automatically build it via creating a DirCacheIterator
+ final boolean writeTree = tree != null;
+
+ if (repository != null && entryCnt > 0)
+ updateSmudgedEntries();
+
for (int i = 0; i < entryCnt; i++) {
final DirCacheEntry e = sortedEntries[i];
if (e.mightBeRacilyClean(smudge_s, smudge_ns))
@@ -598,7 +666,7 @@ public class DirCache {
e.write(dos);
}
- if (tree != null) {
+ if (writeTree) {
final TemporaryBuffer bb = new TemporaryBuffer.LocalFile();
tree.write(tmp, bb);
bb.close();
@@ -865,4 +933,35 @@ public class DirCache {
private void registerIndexChangedListener(IndexChangedListener listener) {
this.indexChangedListener = listener;
}
+
+ /**
+ * Update any smudged entries with information from the working tree.
+ *
+ * @throws IOException
+ */
+ private void updateSmudgedEntries() throws IOException {
+ TreeWalk walk = new TreeWalk(repository);
+ try {
+ DirCacheIterator iIter = new DirCacheIterator(this);
+ FileTreeIterator fIter = new FileTreeIterator(repository);
+ walk.addTree(iIter);
+ walk.addTree(fIter);
+ walk.setRecursive(true);
+ while (walk.next()) {
+ iIter = walk.getTree(0, DirCacheIterator.class);
+ if (iIter == null)
+ continue;
+ fIter = walk.getTree(1, FileTreeIterator.class);
+ if (fIter == null)
+ continue;
+ DirCacheEntry entry = iIter.getDirCacheEntry();
+ if (entry.isSmudged() && iIter.idEqual(fIter)) {
+ entry.setLength(fIter.getEntryLength());
+ entry.setLastModified(fIter.getEntryLastModified());
+ }
+ }
+ } finally {
+ walk.release();
+ }
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
index c70c9b0f85..5d9488ae95 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -871,7 +871,7 @@ public abstract class Repository {
*/
public DirCache readDirCache() throws NoWorkTreeException,
CorruptObjectException, IOException {
- return DirCache.read(getIndexFile(), getFS());
+ return DirCache.read(this);
}
/**
@@ -903,7 +903,7 @@ public abstract class Repository {
notifyIndexChanged();
}
};
- return DirCache.lock(getIndexFile(), getFS(), l);
+ return DirCache.lock(this, l);
}
static byte[] gitInternalSlash(byte[] bytes) {