Commit Diff


commit - 24278f3006b96a0d8ff909454e8fa5ea4fc73ed3
commit + d3e7c587d4fa8caef61be4b2bbc9c388b95e7bb9
blob - 8450cbba950e2cfad6e7250c3bb2987c2599c8cf
blob + 462aba4ce38cf417465bd97d2f372b539d4aed41
--- include/got_error.h
+++ include/got_error.h
@@ -115,6 +115,7 @@
 #define GOT_ERR_NO_MERGED_PATHS 99
 #define GOT_ERR_COMMIT_BRANCH	100
 #define GOT_ERR_FILE_STAGED	101
+#define GOT_ERR_STAGE_NO_CHANGE	102
 
 static const struct got_error {
 	int code;
@@ -232,6 +233,7 @@ static const struct got_error {
 	{ GOT_ERR_COMMIT_BRANCH, "will not commit to a branch outside the "
 	    "\"refs/heads/\" reference namespace" },
 	{ GOT_ERR_FILE_STAGED, "file is staged" },
+	{ GOT_ERR_STAGE_NO_CHANGE, "no changes to stage" },
 };
 
 /*
blob - 08c378a8a6ac617975161686767d71afe16c3550
blob + 67da6f9503e2bf8e19e977686131c7b17312f4b0
--- lib/worktree.c
+++ lib/worktree.c
@@ -4924,20 +4924,19 @@ stage_path(const char *relpath, const char *ondisk_pat
 {
 	const struct got_error *err = NULL;
 	struct got_fileindex_entry *ie;
-	unsigned char status;
+	unsigned char status, staged_status;
 	struct stat sb;
 	struct got_object_id blob_id, *staged_blob_id = NULL;
 	uint32_t stage;
 
 	ie = got_fileindex_entry_get(fileindex, relpath, strlen(relpath));
-	if (ie == NULL) {
-		err = got_error_path(relpath, GOT_ERR_FILE_STATUS);
-		goto done;
-	}
+	if (ie == NULL)
+		return got_error_path(relpath, GOT_ERR_FILE_STATUS);
 
 	err = get_file_status(&status, &sb, ie, ondisk_path, repo);
 	if (err)
-		goto done;
+		return err;
+	staged_status = get_staged_status(ie);
 
 	switch (status) {
 	case GOT_STATUS_ADD:
@@ -4949,7 +4948,7 @@ stage_path(const char *relpath, const char *ondisk_pat
 		memcpy(&blob_id.sha1, ie->blob_sha1, SHA1_DIGEST_LENGTH);
 		memcpy(ie->staged_blob_sha1, staged_blob_id->sha1,
 		    SHA1_DIGEST_LENGTH);
-		if (status == GOT_STATUS_ADD)
+		if (status == GOT_STATUS_ADD || staged_status == GOT_STATUS_ADD)
 			stage = GOT_FILEIDX_STAGE_ADD;
 		else
 			stage = GOT_FILEIDX_STAGE_MODIFY;
@@ -4959,11 +4958,16 @@ stage_path(const char *relpath, const char *ondisk_pat
 		    staged_blob_id, NULL);
 		break;
 	case GOT_STATUS_DELETE:
+		if (staged_status == GOT_STATUS_DELETE)
+			break;
 		stage = GOT_FILEIDX_STAGE_DELETE;
 		got_fileindex_entry_stage_set(ie, stage);
 		err = (*status_cb)(status_arg, GOT_STATUS_NO_CHANGE,
 		    get_staged_status(ie), relpath, NULL, NULL, NULL);
 		break;
+	case GOT_STATUS_NO_CHANGE:
+		err = got_error_path(relpath, GOT_ERR_STAGE_NO_CHANGE);
+		break;
 	default:
 		err = got_error_path(relpath, GOT_ERR_FILE_STATUS);
 		break;
blob - 8cd9094ad29913c485a3282d63f6fa6b048b4879
blob + 9eee79563e1a7280759ad39096b5687b450f2709
--- regress/cmdline/stage.sh
+++ regress/cmdline/stage.sh
@@ -33,9 +33,86 @@ function test_stage_basic {
 
 	echo ' M alpha' > $testroot/stdout.expected
 	echo ' D beta' >> $testroot/stdout.expected
+	echo ' A foo' >> $testroot/stdout.expected
+	(cd $testroot/wt && got stage alpha beta foo > $testroot/stdout)
+
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+	fi
+	test_done "$testroot" "$ret"
+}
+
+function test_double_stage {
+	local testroot=`test_init double_stage`
+
+	got checkout $testroot/repo $testroot/wt > /dev/null
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+	echo "modified file" > $testroot/wt/alpha
+	(cd $testroot/wt && got rm beta > /dev/null)
+	echo "new file" > $testroot/wt/foo
+	(cd $testroot/wt && got add foo > /dev/null)
+	(cd $testroot/wt && got stage alpha beta foo > /dev/null)
+
+	echo "got: alpha: no changes to stage" > $testroot/stderr.expected
+	(cd $testroot/wt && got stage alpha 2> $testroot/stderr)
+	cmp -s $testroot/stderr.expected $testroot/stderr
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stderr.expected $testroot/stderr
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	(cd $testroot/wt && got stage beta > $testroot/stdout)
+	if [ "$ret" != "0" ]; then
+		echo "got stage command failed unexpectedly" >&2
+		test_done "$testroot" "1"
+		return 1
+	fi
+	echo -n > $testroot/stdout.expected
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo "got: foo: no changes to stage" > $testroot/stderr.expected
+	(cd $testroot/wt && got stage foo 2> $testroot/stderr)
+	cmp -s $testroot/stderr.expected $testroot/stderr
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stderr.expected $testroot/stderr
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo "modified file again" > $testroot/wt/alpha
+	echo "modified new file" > $testroot/wt/foo
+
+	echo ' M alpha' > $testroot/stdout.expected
 	echo ' A foo' >> $testroot/stdout.expected
 	(cd $testroot/wt && got stage alpha beta foo > $testroot/stdout)
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo ' M alpha' > $testroot/stdout.expected
+	echo ' D beta' >> $testroot/stdout.expected
+	echo ' A foo' >> $testroot/stdout.expected
 
+	(cd $testroot/wt && got status > $testroot/stdout)
 	cmp -s $testroot/stdout.expected $testroot/stdout
 	ret="$?"
 	if [ "$ret" != "0" ]; then
@@ -440,6 +517,7 @@ function test_stage_revert {
 }
 
 run_test test_stage_basic
+run_test test_double_stage
 run_test test_stage_status
 run_test test_stage_add_already_staged_file
 run_test test_stage_rm_already_staged_file