summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cache.h3
-rw-r--r--diff.c23
-rw-r--r--read-cache.c16
3 files changed, 32 insertions, 10 deletions
diff --git a/cache.h b/cache.h
index 9eaffdefd0..3a47cdc9d2 100644
--- a/cache.h
+++ b/cache.h
@@ -130,6 +130,7 @@ struct cache_entry {
/* In-memory only */
#define CE_UPDATE (0x10000)
#define CE_REMOVE (0x20000)
+#define CE_UPTODATE (0x40000)
static inline unsigned create_ce_flags(size_t len, unsigned stage)
{
@@ -149,6 +150,8 @@ static inline size_t ce_namelen(const struct cache_entry *ce)
#define ce_size(ce) cache_entry_size(ce_namelen(ce))
#define ondisk_ce_size(ce) ondisk_cache_entry_size(ce_namelen(ce))
#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
+#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
+#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
static inline unsigned int create_ce_mode(unsigned int mode)
diff --git a/diff.c b/diff.c
index 5b8afdcb05..d464fe3b20 100644
--- a/diff.c
+++ b/diff.c
@@ -1510,17 +1510,22 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
if (pos < 0)
return 0;
ce = active_cache[pos];
- if ((lstat(name, &st) < 0) ||
- !S_ISREG(st.st_mode) || /* careful! */
- ce_match_stat(ce, &st, 0) ||
- hashcmp(sha1, ce->sha1))
+
+ /*
+ * This is not the sha1 we are looking for, or
+ * unreusable because it is not a regular file.
+ */
+ if (hashcmp(sha1, ce->sha1) || !S_ISREG(ce->ce_mode))
return 0;
- /* we return 1 only when we can stat, it is a regular file,
- * stat information matches, and sha1 recorded in the cache
- * matches. I.e. we know the file in the work tree really is
- * the same as the <name, sha1> pair.
+
+ /*
+ * If ce matches the file in the work tree, we can reuse it.
*/
- return 1;
+ if (ce_uptodate(ce) ||
+ (!lstat(name, &st) && !ce_match_stat(ce, &st, 0)))
+ return 1;
+
+ return 0;
}
static int populate_from_stdin(struct diff_filespec *s)
diff --git a/read-cache.c b/read-cache.c
index 528f697f59..8ba8f0f88f 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -40,6 +40,9 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
if (assume_unchanged)
ce->ce_flags |= CE_VALID;
+
+ if (S_ISREG(st->st_mode))
+ ce_mark_uptodate(ce);
}
static int ce_compare_data(struct cache_entry *ce, struct stat *st)
@@ -412,6 +415,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
!ie_match_stat(istate, istate->cache[pos], &st, ce_option)) {
/* Nothing changed, really */
free(ce);
+ ce_mark_uptodate(istate->cache[pos]);
return 0;
}
@@ -779,6 +783,9 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
int changed, size;
int ignore_valid = options & CE_MATCH_IGNORE_VALID;
+ if (ce_uptodate(ce))
+ return ce;
+
if (lstat(ce->name, &st) < 0) {
if (err)
*err = errno;
@@ -797,8 +804,15 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
if (ignore_valid && assume_unchanged &&
!(ce->ce_flags & CE_VALID))
; /* mark this one VALID again */
- else
+ else {
+ /*
+ * We do not mark the index itself "modified"
+ * because CE_UPTODATE flag is in-core only;
+ * we are not going to write this change out.
+ */
+ ce_mark_uptodate(ce);
return ce;
+ }
}
if (ie_modified(istate, ce, &st, options)) {