Commit Diff


commit - 455ae1c8c7b36f824266bd2701e931004f626875
commit + cdc669650695cff64baae8dfcccf30a57d751f82
blob - df89f493b283c3c8957846b5f60994c98756d8ae
blob + 71a215359b98caf08ed6fafa8841fdd8dbd4caac
--- lib/worktree.c
+++ lib/worktree.c
@@ -1839,8 +1839,22 @@ get_file_status(unsigned char *status, struct stat *sb
 		goto done;
 	}
 	fd = -1;
+
+	if (staged_status == GOT_STATUS_NO_CHANGE &&
+	    S_ISREG(sb->st_mode) &&
+	    got_fileindex_entry_filetype_get(ie) ==
+	    GOT_FILEIDX_MODE_REGULAR_FILE &&
+	    ie->size != (sb->st_size & 0xffffffff)) {
+		/*
+		 * The size of regular files differs. We can skip the full
+		 * content comparison loop below but still need to check
+		 * for conflict markers.
+		 */
+		*status = GOT_STATUS_MODIFY;
+	}
+
 	hdrlen = got_object_blob_get_hdrlen(blob);
-	for (;;) {
+	while (*status == GOT_STATUS_NO_CHANGE) {
 		const uint8_t *bbuf = got_object_blob_get_read_buf(blob);
 		err = got_object_blob_read_block(&blen, blob);
 		if (err)
@@ -5355,6 +5369,11 @@ revert_file(void *arg, unsigned char status, unsigned 
 					goto done;
 				}
 			}
+			err = got_fileindex_entry_update(ie,
+			    a->worktree->root_fd, relpath,
+			    &blob->id, &ie->commit, 0);
+			if (err)
+				goto done;
 		} else {
 			int is_bad_symlink = 0;
 			if (te && S_ISLNK(te->mode)) {
@@ -5372,14 +5391,11 @@ revert_file(void *arg, unsigned char status, unsigned 
 			}
 			if (err)
 				goto done;
-			if (status == GOT_STATUS_DELETE ||
-			    status == GOT_STATUS_MODE_CHANGE) {
-				err = got_fileindex_entry_update(ie,
-				    a->worktree->root_fd, relpath,
-				    &blob->id, a->worktree->base_commit_id, 1);
-				if (err)
-					goto done;
-			}
+			err = got_fileindex_entry_update(ie,
+			    a->worktree->root_fd, relpath,
+			    &blob->id, &ie->commit, 0);
+			if (err)
+				goto done;
 			if (is_bad_symlink) {
 				got_fileindex_entry_filetype_set(ie,
 				    GOT_FILEIDX_MODE_BAD_SYMLINK);