diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
index cd06c2498..65e660750 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -398,20 +398,20 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
if (entry.isUpdateNeeded())
return true;
- if (getEntryLength() != entry.getLength())
+ if (!entry.isSmudged() && (getEntryLength() != entry.getLength()))
return true;
- // determine difference in mode-bits of file and index-entry. In the
+ // Determine difference in mode-bits of file and index-entry. In the
// bitwise presentation of modeDiff we'll have a '1' when the two modes
// differ at this position.
int modeDiff = getEntryRawMode() ^ entry.getRawMode();
- // ignore the executable file bits if checkFilemode tells me to do so.
+ // Ignore the executable file bits if checkFilemode tells me to do so.
// Ignoring is done by setting the bits representing a EXECUTABLE_FILE
// to '0' in modeDiff
if (!checkFilemode)
modeDiff &= ~FileMode.EXECUTABLE_FILE.getBits();
if (modeDiff != 0)
- // report a modification if the modes still (after potentially
+ // Report a modification if the modes still (after potentially
// ignoring EXECUTABLE_FILE bits) differ
return true;
@@ -422,14 +422,58 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
long fileLastModified = getEntryLastModified();
if (cacheLastModified % 1000 == 0)
fileLastModified = fileLastModified - fileLastModified % 1000;
- if (forceContentCheck) {
- if (fileLastModified == cacheLastModified)
- return false; // Same time, don't check content.
- else
- return !getEntryObjectId().equals(entry.getObjectId());
+
+ if (fileLastModified != cacheLastModified) {
+ // The file is dirty by timestamps
+ if (forceContentCheck) {
+ // But we are told to look at content even though timestamps
+ // tell us about modification
+ return contentCheck(entry);
+ } else {
+ // We are told to assume a modification if timestamps differs
+ return true;
+ }
} else {
- // No content check forced, assume dirty if stat differs.
- return fileLastModified != cacheLastModified;
+ // The file is clean when you look at timestamps.
+ if (entry.isSmudged()) {
+ // The file is clean by timestamps but the entry was smudged.
+ // Lets do a content check
+ return contentCheck(entry);
+ } else {
+ // The file is clean by timestamps and the entry is not
+ // smudged: Can't get any cleaner!
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Compares the entries content with the content in the filesystem.
+ * Unsmudges the entry when it is detected that it is clean.
+ *
+ * @param entry
+ * the entry to be checked
+ * @return true
if the content matches, false
+ * otherwise
+ */
+ private boolean contentCheck(DirCacheEntry entry) {
+ if (getEntryObjectId().equals(entry.getObjectId())) {
+ // Content has not changed
+
+ // We know the entry can't be racily clean because it's still clean.
+ // Therefore we unsmudge the entry!
+ // If by any chance we now unsmudge although we are still in the
+ // same time-slot as the last modification to the index file the
+ // next index write operation will smudge again.
+ // Caution: we are unsmudging just by setting the length of the
+ // in-memory entry object. It's the callers task to detect that we
+ // have modified the entry and to persist the modified index.
+ entry.setLength((int) getEntryLength());
+
+ return false;
+ } else {
+ // Content differs: that's a real change!
+ return true;
}
}