Commit f032f1f7ee503b7aa2577cf836c485f96620e772

Stefan Sperling 2019-08-04T14:10:07

fix and test interaction of rebase/histedit -c and 'got stage'

diff --git a/include/got_error.h b/include/got_error.h
index cbf9d06..bd4cd93 100644
--- a/include/got_error.h
+++ b/include/got_error.h
@@ -119,6 +119,7 @@
 #define GOT_ERR_STAGE_CONFLICT	103
 #define GOT_ERR_STAGE_OUT_OF_DATE 104
 #define GOT_ERR_FILE_NOT_STAGED 105
+#define GOT_ERR_STAGED_PATHS	106
 
 static const struct got_error {
 	int code;
@@ -241,6 +242,8 @@ static const struct got_error {
 	{ GOT_ERR_STAGE_OUT_OF_DATE, "work tree must be updated before "
 	    "changes can be staged" },
 	{ GOT_ERR_FILE_NOT_STAGED, "file is not staged" },
+	{ GOT_ERR_STAGED_PATHS, "work tree contains files with staged "
+	    "changes; these changes must be committed or unstaged first" },
 };
 
 /*
diff --git a/lib/worktree.c b/lib/worktree.c
index b1367b4..86889ab 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -3945,6 +3945,7 @@ got_worktree_rebase_continue(struct got_object_id **commit_id,
 	char *tmp_branch_name = NULL, *branch_ref_name = NULL;
 	struct got_reference *commit_ref = NULL, *branch_ref = NULL;
 	char *fileindex_path = NULL;
+	int have_staged_files = 0;
 
 	*commit_id = NULL;
 	*new_base_branch = NULL;
@@ -3960,9 +3961,18 @@ got_worktree_rebase_continue(struct got_object_id **commit_id,
 	if (err)
 		goto done;
 
+	err = got_fileindex_for_each_entry_safe(*fileindex, check_staged_file,
+	    &have_staged_files);
+	if (err && err->code != GOT_ERR_CANCELLED)
+		goto done;
+	if (have_staged_files) {
+		err = got_error(GOT_ERR_STAGED_PATHS);
+		goto done;
+	}
+
 	err = get_rebase_tmp_ref_name(&tmp_branch_name, worktree);
 	if (err)
-		return err;
+		goto done;
 
 	err = get_rebase_branch_symref_name(&branch_ref_name, worktree);
 	if (err)
@@ -4793,6 +4803,7 @@ got_worktree_histedit_continue(struct got_object_id **commit_id,
 	struct got_reference *commit_ref = NULL;
 	struct got_reference *base_commit_ref = NULL;
 	char *fileindex_path = NULL;
+	int have_staged_files = 0;
 
 	*commit_id = NULL;
 	*tmp_branch = NULL;
@@ -4807,9 +4818,18 @@ got_worktree_histedit_continue(struct got_object_id **commit_id,
 	if (err)
 		goto done;
 
+	err = got_fileindex_for_each_entry_safe(*fileindex, check_staged_file,
+	    &have_staged_files);
+	if (err && err->code != GOT_ERR_CANCELLED)
+		goto done;
+	if (have_staged_files) {
+		err = got_error(GOT_ERR_STAGED_PATHS);
+		goto done;
+	}
+
 	err = get_histedit_tmp_ref_name(&tmp_branch_name, worktree);
 	if (err)
-		return err;
+		goto done;
 
 	err = get_histedit_branch_symref_name(&branch_ref_name, worktree);
 	if (err)
diff --git a/regress/cmdline/histedit.sh b/regress/cmdline/histedit.sh
index a859ac4..5aa888a 100755
--- a/regress/cmdline/histedit.sh
+++ b/regress/cmdline/histedit.sh
@@ -525,6 +525,29 @@ function test_histedit_edit {
 
 	echo "edited modified alpha on master" > $testroot/wt/alpha
 
+	# test interaction of 'got stage' and histedit -c
+	(cd $testroot/wt && got stage alpha > /dev/null)
+	(cd $testroot/wt && got histedit -c > $testroot/stdout \
+		2> $testroot/stderr)
+	ret="$?"
+	if [ "$ret" == "0" ]; then
+		echo "histedit succeeded unexpectedly" >&2
+		test_done "$testroot" "1"
+		return 1
+	fi
+	echo -n "got: work tree contains files with staged changes; " \
+		> $testroot/stderr.expected
+	echo "these changes must be committed or unstaged first" \
+		>> $testroot/stderr.expected
+	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 unstage alpha > /dev/null)
 	(cd $testroot/wt && got histedit -c > $testroot/stdout)
 
 	local new_commit1=`git_show_parent_commit $testroot/repo`
diff --git a/regress/cmdline/rebase.sh b/regress/cmdline/rebase.sh
index 3ffba83..fb98c2f 100755
--- a/regress/cmdline/rebase.sh
+++ b/regress/cmdline/rebase.sh
@@ -244,6 +244,29 @@ function test_rebase_continue {
 	# resolve the conflict
 	echo "modified alpha on branch and master" > $testroot/wt/alpha
 
+	# test interaction of 'got stage' and rebase -c
+	(cd $testroot/wt && got stage alpha > /dev/null)
+	(cd $testroot/wt && got rebase -c > $testroot/stdout \
+		2> $testroot/stderr)
+	ret="$?"
+	if [ "$ret" == "0" ]; then
+		echo "rebase succeeded unexpectedly" >&2
+		test_done "$testroot" "1"
+		return 1
+	fi
+	echo -n "got: work tree contains files with staged changes; " \
+		> $testroot/stderr.expected
+	echo "these changes must be committed or unstaged first" \
+		>> $testroot/stderr.expected
+	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 unstage alpha > /dev/null)
 	(cd $testroot/wt && got rebase -c > $testroot/stdout)
 
 	(cd $testroot/repo && git checkout -q newbranch)