prevent 'got commit' on branches outside "refs/heads/" (the only exception is the work tree's temporary histedit branch)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
diff --git a/got/got.1 b/got/got.1
index 3412f52..fb33529 100644
--- a/got/got.1
+++ b/got/got.1
@@ -522,6 +522,9 @@ opens a temporary file in an editor where a log message can be written.
.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,
diff --git a/got/got.c b/got/got.c
index dc2cda4..7c2acec 100644
--- a/got/got.c
+++ b/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,
diff --git a/include/got_error.h b/include/got_error.h
index 37595c5..f37c253 100644
--- a/include/got_error.h
+++ b/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" },
};
/*
diff --git a/regress/cmdline/commit.sh b/regress/cmdline/commit.sh
index 579f23d..55bad57 100755
--- a/regress/cmdline/commit.sh
+++ b/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