summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--read-cache.c17
-rwxr-xr-xt/t7001-mv.sh19
2 files changed, 34 insertions, 2 deletions
diff --git a/read-cache.c b/read-cache.c
index 3e0e7d4183..4df97e185e 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -134,7 +134,7 @@ static void replace_index_entry(struct index_state *istate, int nr, struct cache
void rename_index_entry_at(struct index_state *istate, int nr, const char *new_name)
{
- struct cache_entry *old_entry = istate->cache[nr], *new_entry;
+ struct cache_entry *old_entry = istate->cache[nr], *new_entry, *refreshed;
int namelen = strlen(new_name);
new_entry = make_empty_cache_entry(istate, namelen);
@@ -147,7 +147,20 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
cache_tree_invalidate_path(istate, old_entry->name);
untracked_cache_remove_from_index(istate, old_entry->name);
remove_index_entry_at(istate, nr);
- add_index_entry(istate, new_entry, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
+
+ /*
+ * Refresh the new index entry. Using 'refresh_cache_entry' ensures
+ * we only update stat info if the entry is otherwise up-to-date (i.e.,
+ * the contents/mode haven't changed). This ensures that we reflect the
+ * 'ctime' of the rename in the index without (incorrectly) updating
+ * the cached stat info to reflect unstaged changes on disk.
+ */
+ refreshed = refresh_cache_entry(istate, new_entry, CE_MATCH_REFRESH);
+ if (refreshed && refreshed != new_entry) {
+ add_index_entry(istate, refreshed, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
+ discard_cache_entry(new_entry);
+ } else
+ add_index_entry(istate, new_entry, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
}
void fill_stat_data(struct stat_data *sd, struct stat *st)
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index 963356ba5f..a402908142 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -4,6 +4,25 @@ test_description='git mv in subdirs'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff-data.sh
+test_expect_success 'mv -f refreshes updated index entry' '
+ echo test >bar &&
+ git add bar &&
+ git commit -m test &&
+
+ echo foo >foo &&
+ git add foo &&
+
+ # Wait one second to ensure ctime of rename will differ from original
+ # file creation ctime.
+ sleep 1 &&
+ git mv -f foo bar &&
+ git reset --merge HEAD &&
+
+ # Verify the index has been reset
+ git diff-files >out &&
+ test_must_be_empty out
+'
+
test_expect_success 'prepare reference tree' '
mkdir path0 path1 &&
COPYING_test_data >path0/COPYING &&