Commit 9fdde394b8229cc24073709050d2ef7a1443b0a9

Omar Polo 2022-06-04T14:13:46

got stage: implicitly unstage when staging the reverse of the staged diff otherwise we end up with a staged empty edit for that file. ok stsp@

diff --git a/lib/worktree.c b/lib/worktree.c
index c8e98cc..0fefe75 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -8088,6 +8088,17 @@ stage_path(void *arg, unsigned char status,
 		err = (*a->status_cb)(a->status_arg, GOT_STATUS_NO_CHANGE,
 		    get_staged_status(ie), relpath, blob_id,
 		    new_staged_blob_id, NULL, dirfd, de_name);
+		if (err)
+			break;
+		/*
+		 * When staging the reverse of the staged diff,
+		 * implicitly unstage the file.
+		 */
+		if (memcmp(ie->staged_blob_sha1, ie->blob_sha1,
+		    sizeof(ie->blob_sha1)) == 0) {
+			got_fileindex_entry_stage_set(ie,
+			    GOT_FILEIDX_STAGE_NONE);
+		}
 		break;
 	case GOT_STATUS_DELETE:
 		if (staged_status == GOT_STATUS_DELETE)
diff --git a/regress/cmdline/stage.sh b/regress/cmdline/stage.sh
index 701e5bd..de1799d 100755
--- a/regress/cmdline/stage.sh
+++ b/regress/cmdline/stage.sh
@@ -2154,6 +2154,59 @@ test_stage_patch_removed_twice() {
 	test_done "$testroot" "$ret"
 }
 
+test_stage_patch_reversed() {
+	local testroot=`test_init stage_patch_reversed`
+
+	got checkout $testroot/repo $testroot/wt > /dev/null
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo 'ALPHA' > $testroot/wt/alpha
+	(cd $testroot/wt && got stage alpha > $testroot/stdout)
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo ' M alpha' > $testroot/stdout.expected
+	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
+
+	echo 'alpha' > $testroot/wt/alpha
+	(cd $testroot/wt && got stage alpha > $testroot/stdout)
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo ' M alpha' > $testroot/stdout.expected
+	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 status > $testroot/stdout)
+	cmp -s /dev/null $testroot/stdout
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u /dev/null $testroot/stdout
+	fi
+	test_done "$testroot" "$ret"
+}
+
 test_stage_patch_quit() {
 	local testroot=`test_init stage_patch_quit`
 
@@ -2987,6 +3040,7 @@ run_test test_stage_patch_added
 run_test test_stage_patch_added_twice
 run_test test_stage_patch_removed
 run_test test_stage_patch_removed_twice
+run_test test_stage_patch_reversed
 run_test test_stage_patch_quit
 run_test test_stage_patch_incomplete_script
 run_test test_stage_symlink