Commit Diff


commit - e2308af98f7d01e81f6173b9c264b1c21190a24a
commit + cb41003816bd48d421962c958a4dede3560118a4
blob - 6f1ab86e6bb284e7bd1520334604392068bf8022
blob + 65cddbd86f134477f1ea182a4097014b17686200
--- lib/worktree.c
+++ lib/worktree.c
@@ -3688,7 +3688,7 @@ status_old(void *arg, struct got_fileindex_entry *ie, 
 {
 	const struct got_error *err;
 	struct diff_dir_cb_arg *a = arg;
-	struct got_object_id blob_id, commit_id;
+	struct got_object_id blob_id, commit_id, staged_blob_id;
 	unsigned char status;
 
 	if (a->cancel_cb) {
@@ -3702,12 +3702,13 @@ status_old(void *arg, struct got_fileindex_entry *ie, 
 
 	got_fileindex_entry_get_blob_id(&blob_id, ie);
 	got_fileindex_entry_get_commit_id(&commit_id, ie);
+	got_fileindex_entry_get_staged_blob_id(&staged_blob_id, ie);
 	if (got_fileindex_entry_has_file_on_disk(ie))
 		status = GOT_STATUS_MISSING;
 	else
 		status = GOT_STATUS_DELETE;
 	return (*a->status_cb)(a->status_arg, status, get_staged_status(ie),
-	    ie->path, &blob_id, NULL, &commit_id, -1, NULL);
+	    ie->path, &blob_id, &staged_blob_id, &commit_id, -1, NULL);
 }
 
 static void
@@ -9807,6 +9808,12 @@ unstage_path(void *arg, unsigned char status,
 			break;
 		/* fall through */
 	case GOT_STATUS_ADD:
+		if (status == GOT_STATUS_MISSING) {
+			/* Cannot merge changes into missing files. */
+			err = (*a->progress_cb)(a->progress_arg, status,
+			    relpath);
+			goto done;
+		}
 		if (a->patch_cb) {
 			if (staged_status == GOT_STATUS_ADD) {
 				int choice = GOT_PATCH_CHOICE_NONE;
blob - 5f9b7bb3b3a19f838ac5afc1984ab0cc09919ed9
blob + 797487d03ec67c7d78cb9ee815c911e4a58cbfe6
--- regress/cmdline/unstage.sh
+++ regress/cmdline/unstage.sh
@@ -179,7 +179,76 @@ test_unstage_nonexistent() {
 	ret=$?
 	if [ $ret -ne 0 ]; then
 		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
 	fi
+
+	cat > $testroot/stdout.expected <<EOF
+ M alpha
+ D beta
+ A foo
+EOF
+	(cd $testroot/wt && got status > $testroot/stdout)
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	# removing a staged file from disk and then unstaging
+	# all changes in the work tree would trigger a segfault
+	rm $testroot/wt/alpha
+
+	cat > $testroot/stdout.expected <<EOF
+!M alpha
+ D beta
+ A foo
+EOF
+	(cd $testroot/wt && got status > $testroot/stdout)
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	(cd $testroot/wt && got unstage > $testroot/stdout)
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		echo "got unstage command failed unexpectedly" >&2
+		test_done "$testroot" "1"
+		return 1
+	fi
+
+	cat > $testroot/stdout.expected <<EOF
+!  alpha
+D  beta
+G  foo
+Files which had incoming changes but could not be found in the work tree: 1
+EOF
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	cat > $testroot/stdout.expected <<EOF
+!M alpha
+D  beta
+A  foo
+EOF
+	(cd $testroot/wt && got status > $testroot/stdout)
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+	fi
+
 	test_done "$testroot" "$ret"
 }