Commit 02c0700795c2aee56eaff4d72d82287aa84100ce

Stefan Sperling 2019-02-10T12:46:14

don't update cached timestamps of already modified files

diff --git a/lib/fileindex.c b/lib/fileindex.c
index 0f460ce..69121f8 100644
--- a/lib/fileindex.c
+++ b/lib/fileindex.c
@@ -41,17 +41,20 @@ struct got_fileindex {
 
 const struct got_error *
 got_fileindex_entry_update(struct got_fileindex_entry *entry,
-    const char *ondisk_path, uint8_t *blob_sha1, uint8_t *commit_sha1)
+    const char *ondisk_path, uint8_t *blob_sha1, uint8_t *commit_sha1,
+    int update_timestamps)
 {
 	struct stat sb;
 
 	if (lstat(ondisk_path, &sb) != 0)
 		return got_error_from_errno();
 
-	entry->ctime_sec = sb.st_ctime;
-	entry->ctime_nsec = sb.st_ctimensec;
-	entry->mtime_sec = sb.st_mtime;
-	entry->mtime_nsec = sb.st_mtimensec;
+	if (update_timestamps) {
+		entry->ctime_sec = sb.st_ctime;
+		entry->ctime_nsec = sb.st_ctimensec;
+		entry->mtime_sec = sb.st_mtime;
+		entry->mtime_nsec = sb.st_mtimensec;
+	}
 	entry->uid = sb.st_uid;
 	entry->gid = sb.st_gid;
 	entry->size = (sb.st_size & 0xffffffff);
@@ -92,7 +95,7 @@ got_fileindex_entry_alloc(struct got_fileindex_entry **entry,
 	(*entry)->flags |= len;
 
 	return got_fileindex_entry_update(*entry, ondisk_path, blob_sha1,
-	    commit_sha1);
+	    commit_sha1, 1);
 }
 
 void
diff --git a/lib/got_lib_fileindex.h b/lib/got_lib_fileindex.h
index 64bfc70..bb4a77a 100644
--- a/lib/got_lib_fileindex.h
+++ b/lib/got_lib_fileindex.h
@@ -95,7 +95,7 @@ struct got_fileindex_hdr {
 };
 
 const struct got_error *got_fileindex_entry_update(struct got_fileindex_entry *,
-    const char *, uint8_t *, uint8_t *);
+    const char *, uint8_t *, uint8_t *, int);
 const struct got_error *got_fileindex_entry_alloc(struct got_fileindex_entry **,
     const char *, const char *, uint8_t *, uint8_t *);
 void got_fileindex_entry_free(struct got_fileindex_entry *);
diff --git a/lib/worktree.c b/lib/worktree.c
index 2761439..f8449d3 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -665,8 +665,12 @@ merge_blob(struct got_worktree *worktree, struct got_fileindex *fileindex,
 		goto done;
 	}
 
+	/*
+	 * Do not update timestamps of already modified files. Otherwise,
+	 * the status walk would treat them as unmodified files again.
+	 */
 	err = got_fileindex_entry_update(ie, ondisk_path,
-	    blob1->id.sha1, worktree->base_commit_id->sha1);
+	    blob1->id.sha1, worktree->base_commit_id->sha1, 0);
 done:
 	if (merged_fd != -1)
 		close(merged_fd);
@@ -792,7 +796,7 @@ install_blob(struct got_worktree *worktree, struct got_fileindex *fileindex,
 		entry = got_fileindex_entry_get(fileindex, path);
 	if (entry)
 		err = got_fileindex_entry_update(entry, ondisk_path,
-		    blob->id.sha1, worktree->base_commit_id->sha1);
+		    blob->id.sha1, worktree->base_commit_id->sha1, 1);
 	else {
 		err = got_fileindex_entry_alloc(&entry, ondisk_path,
 		    path, blob->id.sha1, worktree->base_commit_id->sha1);
diff --git a/regress/cmdline/status.sh b/regress/cmdline/status.sh
index c74933d..26ddd6d 100755
--- a/regress/cmdline/status.sh
+++ b/regress/cmdline/status.sh
@@ -152,7 +152,65 @@ function test_status_obstructed {
 	test_done "$testroot" "0"
 }
 
+function test_status_shows_local_mods_after_update {
+	local testroot=`test_init status_shows_local_mods_after_update 1`
+
+	echo "1" > $testroot/repo/numbers
+	echo "2" >> $testroot/repo/numbers
+	echo "3" >> $testroot/repo/numbers
+	echo "4" >> $testroot/repo/numbers
+	echo "5" >> $testroot/repo/numbers
+	echo "6" >> $testroot/repo/numbers
+	echo "7" >> $testroot/repo/numbers
+	echo "8" >> $testroot/repo/numbers
+	(cd $testroot/repo && git add numbers)
+	git_commit $testroot/repo -m "added numbers file"
+
+	got checkout $testroot/repo $testroot/wt > /dev/null
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	sed -i 's/2/22/' $testroot/repo/numbers
+	git_commit $testroot/repo -m "modified line 2"
+
+	# modify line 7; both changes should merge cleanly
+	sed -i 's/7/77/' $testroot/wt/numbers
+
+	echo "G  numbers" > $testroot/stdout.expected
+	echo -n "Updated to commit " >> $testroot/stdout.expected
+	git_show_head $testroot/repo >> $testroot/stdout.expected
+	echo >> $testroot/stdout.expected
+
+	(cd $testroot/wt && got update > $testroot/stdout)
+
+	cmp $testroot/stdout.expected $testroot/stdout
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo 'M  numbers' > $testroot/stdout.expected
+
+	(cd $testroot/wt && got status > $testroot/stdout)
+
+	cmp $testroot/stdout.expected $testroot/stdout
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	test_done "$testroot" "0"
+}
+
 run_test test_status_basic
 run_test test_status_subdir_no_mods
 run_test test_status_subdir_no_mods2
 run_test test_status_obstructed
+run_test test_status_shows_local_mods_after_update