]> source.dussan.org Git - jgit.git/commitdiff
Update smudged entries when writing index 37/6137/1
authorKevin Sawicki <kevin@github.com>
Mon, 21 May 2012 22:00:23 +0000 (15:00 -0700)
committerKevin Sawicki <kevin@github.com>
Mon, 28 May 2012 21:01:14 +0000 (14:01 -0700)
Overload DirCache.lock to take a repository that is
used for updating smudged index entries with information
from the repository's working tree.

New unit tests are also added for updating smudged index
entries on reset, checkout, and commit.

Change-Id: I88689f26000e4e57e77931e5ace7c804d92af1b6

org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java

index b1cac3a54d25a907a1e0af1a9b0b036e759eb7f1..a51a8b4697a7d036e5c844623eaee8ee8e9df93f 100644 (file)
@@ -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());
+       }
 }
index b9f5882d50687d8392ca1642e7bb9c20913dc25f..3aec611f44f05757690fb9e3a85f90d7211c9e4a 100644 (file)
@@ -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());
+       }
 }
index 27c3549be3c00a88d812e904bd32ddaed6c4052c..3087ca829bf4a4ebdda4ac55fc090c21a7a8cd86 100644 (file)
@@ -219,6 +219,48 @@ public class ResetCommandTest extends RepositoryTestCase {
                assertReflog(prevHead, head);
        }
 
+       @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();
index 0d5952df2441964bb622f6157b441bff1f994304..9108d9235d806e9650076b9b284afcc96d0f639f 100644 (file)
@@ -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;
@@ -138,6 +141,30 @@ public class DirCache {
                return new DirCache(null, null);
        }
 
+       /**
+        * 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 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>
@@ -209,6 +236,37 @@ public class DirCache {
                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 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>
@@ -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();
+               }
+       }
 }
index c70c9b0f85cb79ff50675976e5e634083ace98a2..5d9488ae95e600cb05a096caf90b791809d392e1 100644 (file)
@@ -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) {