forbid editing the history of branches outside of "refs/heads"
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
diff --git a/got/got.1 b/got/got.1
index a51741e..ee870b0 100644
--- a/got/got.1
+++ b/got/got.1
@@ -769,6 +769,9 @@ when the histedit operation continues.
.Pp
.Cm got histedit
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, the history of the branch may not be edited.
If the work tree contains multiple base commits it must first be updated
to a single base commit with
.Cm got update .
diff --git a/got/got.c b/got/got.c
index e2cf661..5356c71 100644
--- a/got/got.c
+++ b/got/got.c
@@ -4956,6 +4956,13 @@ cmd_histedit(int argc, char *argv[])
if (error != NULL)
goto done;
+ if (strncmp(got_ref_get_name(branch), "refs/heads/", 11) != 0) {
+ error = got_error_msg(GOT_ERR_COMMIT_BRANCH,
+ "will not edit commit history of a branch outside "
+ "the \"refs/heads/\" reference namespace");
+ goto done;
+ }
+
error = got_ref_resolve(&head_commit_id, repo, branch);
got_ref_close(branch);
branch = NULL;
diff --git a/regress/cmdline/histedit.sh b/regress/cmdline/histedit.sh
index 4c72997..a859ac4 100755
--- a/regress/cmdline/histedit.sh
+++ b/regress/cmdline/histedit.sh
@@ -1039,6 +1039,62 @@ function test_histedit_path_prefix_edit {
test_done "$testroot" "$ret"
}
+function test_histedit_outside_refs_heads {
+ local testroot=`test_init histedit_outside_refs_heads`
+ local commit1=`git_show_head $testroot/repo`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got checkout failed unexpectedly"
+ 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 "got commit failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+ local commit2=`git_show_head $testroot/repo`
+
+ got ref -r $testroot/repo refs/remotes/origin/master master
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got ref failed unexpectedly" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ (cd $testroot/wt && got update -b origin/master -c $commit1 >/dev/null)
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got update failed unexpectedly"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "edit $commit2" > $testroot/histedit-script
+ (cd $testroot/wt && got histedit -F $testroot/histedit-script \
+ 2> $testroot/stderr)
+
+ echo -n "got: will not edit commit history of 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_histedit_no_op
run_test test_histedit_swap
run_test test_histedit_drop
@@ -1049,3 +1105,4 @@ run_test test_histedit_missing_commit
run_test test_histedit_abort
run_test test_histedit_path_prefix_drop
run_test test_histedit_path_prefix_edit
+run_test test_histedit_outside_refs_heads