Commit Diff


commit - fe307c9bac71d85284c7cee8abb80b52a253710b
commit + 916f288c7e2f6e7bcc2643b8287a4b32f518899f
blob - 3412f52f18e3f4bef7e8088a1711149e0abef66f
blob + fb33529afb444edbcd9f9cd91ad331cf2f45bb1b
--- got/got.1
+++ got/got.1
@@ -522,6 +522,9 @@ opens a temporary file in an editor where a log messag
 .Pp
 .Cm got commit
 will refuse to run if certain preconditions are not met.
+If the work tree's current branch is not in the
+.Dq refs/heads/
+reference namespace, new commits may not be created on this branch.
 Local changes may only be committed if they are based on file content
 found in the most recent commit on the work tree's branch.
 If a path is found to be out of date,
blob - dc2cda4ba6b716c5e52b8ec10832a3d71942076e
blob + 7c2acecdb74e15acbad569de791032d408e06416
--- got/got.c
+++ got/got.c
@@ -3228,7 +3228,7 @@ cmd_commit(int argc, char *argv[])
 	const char *got_author = getenv("GOT_AUTHOR");
 	struct collect_commit_logmsg_arg cl_arg;
 	char *editor = NULL;
-	int ch, rebase_in_progress;
+	int ch, rebase_in_progress, histedit_in_progress;
 	struct got_pathlist_head paths;
 
 	TAILQ_INIT(&paths);
@@ -3275,6 +3275,11 @@ cmd_commit(int argc, char *argv[])
 		goto done;
 	}
 
+	error = got_worktree_histedit_in_progress(&histedit_in_progress,
+	    worktree);
+	if (error)
+		goto done;
+
 	error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
 	if (error)
 		goto done;
@@ -3299,10 +3304,13 @@ cmd_commit(int argc, char *argv[])
 	cl_arg.cmdline_log = logmsg;
 	cl_arg.worktree_path = got_worktree_get_root_path(worktree);
 	cl_arg.branch_name = got_worktree_get_head_ref_name(worktree);
-	if (strncmp(cl_arg.branch_name, "refs/", 5) == 0)
-		cl_arg.branch_name += 5;
-	if (strncmp(cl_arg.branch_name, "heads/", 6) == 0)
-		cl_arg.branch_name += 6;
+	if (!histedit_in_progress) {
+		if (strncmp(cl_arg.branch_name, "refs/heads/", 11) != 0) {
+			error = got_error(GOT_ERR_COMMIT_BRANCH);
+			goto done;
+		}
+		cl_arg.branch_name += 11;
+	}
 	cl_arg.repo_path = got_repo_get_path(repo);
 	cl_arg.logmsg_path = NULL;
 	error = got_worktree_commit(&id, worktree, &paths, got_author, NULL,
blob - 37595c5216a30ac7f817772e3493b9b38e9fa5c7
blob + f37c253a3149dc63c7b93bf00c1c3f5906eddc30
--- include/got_error.h
+++ include/got_error.h
@@ -113,6 +113,7 @@
 #define GOT_ERR_HISTEDIT_CMD	97
 #define GOT_ERR_HISTEDIT_PATH	98
 #define GOT_ERR_NO_MERGED_PATHS 99
+#define GOT_ERR_COMMIT_BRANCH	100
 
 static const struct got_error {
 	int code;
@@ -227,6 +228,8 @@ static const struct got_error {
 	{ GOT_ERR_HISTEDIT_PATH, "cannot edit branch history which contains "
 	    "changes outside of this work tree's path prefix" },
 	{ GOT_ERR_NO_MERGED_PATHS, "empty list of merged paths" },
+	{ GOT_ERR_COMMIT_BRANCH, "will not commit to a branch outside the "
+	    "\"refs/heads/\" reference namespace" },
 };
 
 /*
blob - 579f23ddfca6faf4a1e9709eecf9394ab27b2f18
blob + 55bad574818603f55ad63de1e59ea2d528baa75d
--- regress/cmdline/commit.sh
+++ regress/cmdline/commit.sh
@@ -471,6 +471,52 @@ function test_commit_selected_paths {
 	test_done "$testroot" "$ret"
 }
 
+function test_commit_outside_refs_heads {
+	local testroot=`test_init commit_outside_refs_heads`
+
+	got ref -r $testroot/repo refs/remotes/origin/master master
+
+	got checkout -b refs/remotes/origin/master \
+	    $testroot/repo $testroot/wt > /dev/null
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo "modified alpha" > $testroot/wt/alpha
+
+	(cd $testroot/wt && got commit -m 'change alpha' \
+		> $testroot/stdout 2> $testroot/stderr)
+	ret="$?"
+	if [ "$ret" == "0" ]; then
+		echo "commit succeeded 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 -n "got: will not commit to a branch outside the " \
+		> $testroot/stderr.expected
+	echo '"refs/heads/" reference namespace' \
+		>> $testroot/stderr.expected
+	cmp -s $testroot/stderr.expected $testroot/stderr
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stderr.expected $testroot/stderr
+	fi
+	test_done "$testroot" "$ret"
+}
+
+
 run_test test_commit_basic
 run_test test_commit_new_subdir
 run_test test_commit_subdir
@@ -483,3 +529,4 @@ run_test test_commit_added_and_modified_in_same_dir
 run_test test_commit_path_prefix
 run_test test_commit_dir_path
 run_test test_commit_selected_paths
+run_test test_commit_outside_refs_heads