Commit Diff


commit - ad4a7050395834da81cd5e4715df04ebd5f06b6f
commit + af0328d61e5353fc867c1731a5dcb969f805aaba
blob - 66eeb4616f118b7eb6f6efe9724d0bc49cb3f838
blob + 5af05544443feda9e6394c57a8d8dbe7db88e27b
--- lib/worktree.c
+++ lib/worktree.c
@@ -3685,7 +3685,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) {
@@ -3699,12 +3699,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
@@ -9804,6 +9805,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"
 }