"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Omar Polo <op@omarpolo.com>
Subject:
staging the reverse of the staged diff
To:
gameoftrees@openbsd.org
Date:
Fri, 03 Jun 2022 11:34:48 +0200

Download raw body.

Thread
found this by chance; i've staged a debug printf somewhere by accident,
then removed, staged the removal and... the file was still staged but
with an empty diff!  (it was the only edit to that file)

patch below tries to make stage_path slightly more clever by checking
the staged blob and the file blob: if they're the same we've effectively
unstaged a file.

does this makes sense?  am i trying to make 'got stage' too much clever?

on the other hand, this 'got stage' trick can be used to make empty
commits:

	$ echo clobber > got/got.c
	$ got stage got/got.c
	$ got diff -s | got patch -R
	$ got stage got/got.c
	$ got commit -m "I'm an empty commit!"

but feels hackish :)

(some project sometimes requires the contributor to make an "empty
commit" for copyright stuff, see for e.g.
https://github.com/mawww/kakoune/blob/master/CONTRIBUTING, but this is
probably a separate issue.)

diff ce2bf7b7c9058374563c6db8608dbab9df2bba7d /home/op/w/got
blob - ca8e4d6a6ba63c5f3e16487196a7a3bf16fa888b
file + lib/worktree.c
--- lib/worktree.c
+++ lib/worktree.c
@@ -8068,6 +8068,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)
blob - e16d9854340821bff1be14c3086fbe1a59b26843
file + regress/cmdline/stage.sh
--- regress/cmdline/stage.sh
+++ 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