Retain file length and mod time when doing a mixed reset

Previously the index was cleared and updated with a new tree.

Now the commit being reset to and the index are iterated over
in a tree walk and the current index mod time and file length
are copied over to the new dir cache entry being written if
the object ids are the same.

Change-Id: Iaf9e624efb0bf90f9e05fcb0587dde4dec50000c
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
index 422056b..0af684e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
@@ -49,9 +49,10 @@
 
 import org.eclipse.jgit.api.errors.JGitInternalException;
 import org.eclipse.jgit.dircache.DirCache;
-import org.eclipse.jgit.dircache.DirCacheBuilder;
 import org.eclipse.jgit.dircache.DirCacheCheckout;
 import org.eclipse.jgit.dircache.DirCacheEditor;
+import org.eclipse.jgit.dircache.DirCacheEditor.DeletePath;
+import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.dircache.DirCacheIterator;
 import org.eclipse.jgit.internal.JGitText;
@@ -64,6 +65,7 @@
 import org.eclipse.jgit.lib.RepositoryState;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.AbstractTreeIterator;
 import org.eclipse.jgit.treewalk.CanonicalTreeParser;
 import org.eclipse.jgit.treewalk.TreeWalk;
 import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
@@ -313,14 +315,49 @@ public void apply(DirCacheEntry ent) {
 
 	private void resetIndex(RevCommit commit) throws IOException {
 		DirCache dc = repo.lockDirCache();
+		TreeWalk walk = null;
 		try {
-			dc.clear();
-			DirCacheBuilder dcb = dc.builder();
-			dcb.addTree(new byte[0], 0, repo.newObjectReader(),
-					commit.getTree());
-			dcb.commit();
+			DirCacheEditor editor = dc.editor();
+
+			walk = new TreeWalk(repo);
+			walk.addTree(commit.getTree());
+			walk.addTree(new DirCacheIterator(dc));
+			walk.setRecursive(true);
+
+			while (walk.next()) {
+				AbstractTreeIterator cIter = walk.getTree(0,
+						AbstractTreeIterator.class);
+				if (cIter == null) {
+					editor.add(new DeletePath(walk.getPathString()));
+					continue;
+				}
+
+				final DirCacheEntry entry = new DirCacheEntry(walk.getRawPath());
+				entry.setFileMode(cIter.getEntryFileMode());
+				entry.setObjectIdFromRaw(cIter.idBuffer(), cIter.idOffset());
+
+				DirCacheIterator dcIter = walk.getTree(1,
+						DirCacheIterator.class);
+				if (dcIter != null && dcIter.idEqual(cIter)) {
+					DirCacheEntry indexEntry = dcIter.getDirCacheEntry();
+					entry.setLastModified(indexEntry.getLastModified());
+					entry.setLength(indexEntry.getLength());
+				}
+
+				editor.add(new PathEdit(entry) {
+
+					@Override
+					public void apply(DirCacheEntry ent) {
+						ent.copyMetaData(entry);
+					}
+				});
+			}
+
+			editor.commit();
 		} finally {
 			dc.unlock();
+			if (walk != null)
+				walk.release();
 		}
 	}