DirCacheEntry: Do not treat gitlink entries as smudged

DirCacheEntry.isSmudged() returns true whenever getLength() == 0 and the
object ID is not Constants.EMPTY_BLOB_ID.

However, a submodule gitlink entry (FileMode.GITLINK, mode 160000)
represents a commit reference rather than a blob: its length in the
index is always 0 and its object ID is the submodule commit SHA (never
EMPTY_BLOB_ID). Consequently, isSmudged() returns true for every
gitlink entry, causing DirCache.writeTo() to run updateSmudgedEntries()
and scan the working tree on every index write when submodules are
present.

Exclude FileMode.GITLINK entries in DirCacheEntry.isSmudged().

Google-Bug-Id: b/573880998
Change-Id: I9b415a7852b63f57388099800000000000000002
Signed-off-by: Enrico Mrass <emrass@google.com>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
index 158d9de..009556a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java
@@ -365,4 +365,14 @@ public void testNotRacilyCleanWhenSmudgeIsAfter() {
 		final Instant smudge = entryTime.plus(Duration.ofNanos(1));
 		assertFalse(entry.mightBeRacilyClean(smudge));
 	}
+
+	@Test
+	public void testGitlinkIsNotSmudged() {
+		DirCacheEntry entry = new DirCacheEntry("submodule");
+		entry.setFileMode(FileMode.GITLINK);
+		entry.setObjectId(ObjectId
+				.fromString("0123456789012345678901234567890123456789"));
+		assertEquals(0, entry.getLength());
+		assertFalse(entry.isSmudged());
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
index aebea7a..6ebde79 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
@@ -454,7 +454,9 @@ public final void smudgeRacilyClean() {
 	 */
 	public final boolean isSmudged() {
 		final int base = infoOffset + P_OBJECTID;
-		return (getLength() == 0) && (Constants.EMPTY_BLOB_ID.compareTo(info, base) != 0);
+		return (getLength() == 0)
+				&& !FileMode.GITLINK.equals(getFileMode())
+				&& (Constants.EMPTY_BLOB_ID.compareTo(info, base) != 0);
 	}
 
 	final byte[] idBuffer() {