Commit Diff


commit - 085d5bcf0b7635235aeaa2608540072bdc88ae99
commit + 13d9040b96f5ba9ac50c137a9909f824dd5bde20
blob - 3421739139d8ff2c8f0b5051debfd6d9755fd579
blob + 4a33abd6b06c91758f991512a2d7475a06651970
--- lib/fileindex.c
+++ lib/fileindex.c
@@ -57,26 +57,29 @@ got_fileindex_entry_update(struct got_fileindex_entry 
 {
 	struct stat sb;
 
-	if (lstat(ondisk_path, &sb) != 0)
-		return got_error_from_errno();
+	if (lstat(ondisk_path, &sb) != 0) {
+		if ((entry->flags & GOT_FILEIDX_F_NO_FILE_ON_DISK) == 0)
+			return got_error_from_errno();
+	} else
+		entry->flags &= ~GOT_FILEIDX_F_NO_FILE_ON_DISK;
 
-	entry->flags &= ~GOT_FILEIDX_F_NO_FILE_ON_DISK;
-
-	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;
+	if ((entry->flags & GOT_FILEIDX_F_NO_FILE_ON_DISK) == 0) {
+		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);
+		if (sb.st_mode & S_IFLNK)
+			entry->mode = GOT_FILEIDX_MODE_SYMLINK;
+		else
+			entry->mode = GOT_FILEIDX_MODE_REGULAR_FILE;
+		entry->mode |= ((sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) <<
+		    GOT_FILEIDX_MODE_PERMS_SHIFT);
 	}
-	entry->uid = sb.st_uid;
-	entry->gid = sb.st_gid;
-	entry->size = (sb.st_size & 0xffffffff);
-	if (sb.st_mode & S_IFLNK)
-		entry->mode = GOT_FILEIDX_MODE_SYMLINK;
-	else
-		entry->mode = GOT_FILEIDX_MODE_REGULAR_FILE;
-	entry->mode |= ((sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) <<
-	    GOT_FILEIDX_MODE_PERMS_SHIFT);
 
 	if (blob_sha1) {
 		memcpy(entry->blob_sha1, blob_sha1, SHA1_DIGEST_LENGTH);
blob - 442288387b7a34120e7bba5f27c9f45dbfc31768
blob + 3f0523ffaec3bb0f816ab6a98521fbe8d543e3f6
--- lib/worktree.c
+++ lib/worktree.c
@@ -844,11 +844,35 @@ done:
 }
 
 static const struct got_error *
-install_blob(struct got_worktree *worktree, struct got_fileindex *fileindex,
-   struct got_fileindex_entry *entry, const char *ondisk_path, const char *path,
-   uint16_t te_mode, uint16_t st_mode, struct got_blob_object *blob,
-   int restoring_missing_file, struct got_repository *repo,
-   got_worktree_checkout_cb progress_cb, void *progress_arg)
+update_blob_fileindex_entry(struct got_worktree *worktree,
+    struct got_fileindex *fileindex, struct got_fileindex_entry *ie,
+    const char *ondisk_path, const char *path, struct got_blob_object *blob,
+    int update_timestamps)
+{
+	const struct got_error *err = NULL;
+
+	if (ie == NULL)
+		ie = got_fileindex_entry_get(fileindex, path);
+	if (ie)
+		err = got_fileindex_entry_update(ie, ondisk_path,
+		    blob->id.sha1, worktree->base_commit_id->sha1,
+		    update_timestamps);
+	else {
+		struct got_fileindex_entry *new_ie;
+		err = got_fileindex_entry_alloc(&new_ie, ondisk_path,
+		    path, blob->id.sha1, worktree->base_commit_id->sha1);
+		if (!err)
+			err = got_fileindex_entry_add(fileindex, new_ie);
+	}
+	return err;
+}
+
+static const struct got_error *
+install_blob(struct got_worktree *worktree, const char *ondisk_path,
+   const char *path, uint16_t te_mode, uint16_t st_mode,
+   struct got_blob_object *blob, int restoring_missing_file,
+   struct got_repository *repo, got_worktree_checkout_cb progress_cb,
+   void *progress_arg)
 {
 	const struct got_error *err = NULL;
 	int fd = -1;
@@ -938,18 +962,6 @@ install_blob(struct got_worktree *worktree, struct got
 		}
 	}
 
-	if (entry == NULL)
-		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, 1);
-	else {
-		err = got_fileindex_entry_alloc(&entry, ondisk_path,
-		    path, blob->id.sha1, worktree->base_commit_id->sha1);
-		if (err)
-			goto done;
-		err = got_fileindex_entry_add(fileindex, entry);
-	}
 done:
 	if (fd != -1 && close(fd) != 0 && err == NULL)
 		err = got_error_from_errno();
@@ -1150,11 +1162,23 @@ update_blob(struct got_worktree *worktree,
 		err = merge_blob(worktree, fileindex, ie, ondisk_path, path,
 		    te->mode, sb.st_mode, blob, repo, progress_cb,
 		    progress_arg);
-	else
-		err = install_blob(worktree, fileindex, ie, ondisk_path, path,
-		    te->mode, sb.st_mode, blob, status == GOT_STATUS_MISSING,
-		    repo, progress_cb, progress_arg);
-
+	else if (status == GOT_STATUS_DELETE) {
+		(*progress_cb)(progress_arg, GOT_STATUS_MERGE, path);
+		err = update_blob_fileindex_entry(worktree, fileindex, ie,
+		    ondisk_path, path, blob, 0);
+		if (err)
+			goto done;
+	} else {
+		err = install_blob(worktree, ondisk_path, path, te->mode,
+		    sb.st_mode, blob, status == GOT_STATUS_MISSING, repo,
+		    progress_cb, progress_arg);
+		if (err)
+			goto done;
+		err = update_blob_fileindex_entry(worktree, fileindex, ie,
+		    ondisk_path, path, blob, 1);
+		if (err)
+			goto done;
+	}
 	got_object_blob_close(blob);
 done:
 	free(ondisk_path);
blob - d30a87ce41088f62e2a9a1f6aa924eada9cd5d12
blob + 5b27ea3fdd42c59f652befa84aa020bb8f3b7139
--- regress/cmdline/update.sh
+++ regress/cmdline/update.sh
@@ -952,12 +952,73 @@ function test_update_conflict_wt_edit_vs_repo_rm {
 
 	# beta is now an unversioned file... we don't flag tree conflicts yet
 	echo '?  beta' > $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
+	fi
+	test_done "$testroot" "$ret"
+}
+
+function test_update_conflict_wt_rm_vs_repo_edit {
+	local testroot=`test_init update_conflict_wt_rm_vs_repo_edit`
+
+	got checkout $testroot/repo $testroot/wt > /dev/null
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo "modified beta" > $testroot/repo/beta
+	git_commit $testroot/repo -m "modified a file"
+
+	(cd $testroot/wt && got rm beta > /dev/null)
+
+	(cd $testroot/wt && got update > $testroot/stdout)
+
+	echo "G  beta" > $testroot/stdout.expected
+	echo -n "Updated to commit " >> $testroot/stdout.expected
+	git_show_head $testroot/repo >> $testroot/stdout.expected
+	echo >> $testroot/stdout.expected
+	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
+
+	# beta remains a deleted file... we don't flag tree conflicts yet
+	echo 'D  beta' > $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
+
+	# 'got diff' should show post-update contents of beta being deleted
+	local head_rev=`git_show_head $testroot/repo`
+	echo "diff $head_rev $testroot/wt" > $testroot/stdout.expected
+	echo -n 'blob - ' >> $testroot/stdout.expected
+	got tree -r $testroot/repo -i | grep 'beta$' | cut -d' ' -f 1 \
+		>> $testroot/stdout.expected
+	echo 'file + /dev/null' >> $testroot/stdout.expected
+	echo '--- beta' >> $testroot/stdout.expected
+	echo '+++ beta' >> $testroot/stdout.expected
+	echo '@@ -1 +0,0 @@' >> $testroot/stdout.expected
+	echo '-modified beta' >> $testroot/stdout.expected
+
+	(cd $testroot/wt && got diff > $testroot/stdout)
+	cmp $testroot/stdout.expected $testroot/stdout
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+	fi
 	test_done "$testroot" "$ret"
 }
 
@@ -980,3 +1041,4 @@ run_test test_update_clears_xbit
 run_test test_update_restores_missing_file
 run_test test_update_conflict_wt_add_vs_repo_add
 run_test test_update_conflict_wt_edit_vs_repo_rm
+run_test test_update_conflict_wt_rm_vs_repo_edit