aboutsummaryrefslogtreecommitdiff
path: root/t/t3451-history-reword.sh
diff options
context:
space:
mode:
Diffstat (limited to 't/t3451-history-reword.sh')
-rwxr-xr-xt/t3451-history-reword.sh399
1 files changed, 399 insertions, 0 deletions
diff --git a/t/t3451-history-reword.sh b/t/t3451-history-reword.sh
new file mode 100755
index 0000000000..de7b357685
--- /dev/null
+++ b/t/t3451-history-reword.sh
@@ -0,0 +1,399 @@
+#!/bin/sh
+
+test_description='tests for git-history reword subcommand'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY/lib-log-graph.sh"
+
+reword_with_message () {
+ cat >message &&
+ write_script fake-editor.sh <<-\EOF &&
+ cp message "$1"
+ EOF
+ test_set_editor "$(pwd)"/fake-editor.sh &&
+ git history reword "$@" &&
+ rm fake-editor.sh message
+}
+
+expect_graph () {
+ cat >expect &&
+ lib_test_cmp_graph --graph --format=%s "$@"
+}
+
+expect_log () {
+ git log --format="%s" "$@" >actual &&
+ cat >expect &&
+ test_cmp expect actual
+}
+
+test_expect_success 'can reword tip of a branch' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit first &&
+ test_commit second &&
+ test_commit third &&
+
+ git symbolic-ref HEAD >expect &&
+ reword_with_message HEAD <<-EOF &&
+ third reworded
+ EOF
+ git symbolic-ref HEAD >actual &&
+ test_cmp expect actual &&
+
+ expect_log <<-\EOF &&
+ third reworded
+ second
+ first
+ EOF
+
+ git reflog >reflog &&
+ test_grep "reword: updating HEAD" reflog
+ )
+'
+
+test_expect_success 'can reword commit in the middle' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit first &&
+ test_commit second &&
+ test_commit third &&
+
+ git symbolic-ref HEAD >expect &&
+ reword_with_message HEAD~ <<-EOF &&
+ second reworded
+ EOF
+ git symbolic-ref HEAD >actual &&
+ test_cmp expect actual &&
+
+ expect_log <<-\EOF
+ third
+ second reworded
+ first
+ EOF
+ )
+'
+
+test_expect_success 'can reword commit in the middle even on detached head' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit first &&
+ test_commit second &&
+ test_commit third_on_main &&
+ git checkout --detach HEAD^ &&
+ test_commit third_on_head &&
+
+ reword_with_message HEAD~ <<-EOF &&
+ second reworded
+ EOF
+
+ expect_graph HEAD --branches <<-\EOF
+ * third_on_head
+ | * third_on_main
+ |/
+ * second reworded
+ * first
+ EOF
+ )
+'
+
+test_expect_success 'can reword the detached head' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit first &&
+ test_commit second &&
+ git checkout --detach HEAD &&
+ test_commit third &&
+
+ reword_with_message HEAD <<-EOF &&
+ third reworded
+ EOF
+
+ expect_log <<-\EOF
+ third reworded
+ second
+ first
+ EOF
+ )
+'
+
+test_expect_success 'can reword root commit' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit first &&
+ test_commit second &&
+ test_commit third &&
+ reword_with_message HEAD~2 <<-EOF &&
+ first reworded
+ EOF
+
+ expect_log <<-\EOF
+ third
+ second
+ first reworded
+ EOF
+ )
+'
+
+test_expect_success 'can reword in a bare repo' '
+ test_when_finished "rm -rf repo repo.git" &&
+ git init repo &&
+ test_commit -C repo first &&
+ git clone --bare repo repo.git &&
+ (
+ cd repo.git &&
+ reword_with_message HEAD <<-EOF &&
+ reworded
+ EOF
+
+ expect_log <<-\EOF
+ reworded
+ EOF
+ )
+'
+
+test_expect_success 'can reword a commit on a different branch' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit base &&
+ git branch theirs &&
+ test_commit ours &&
+ git switch theirs &&
+ test_commit theirs &&
+
+ git rev-parse ours >ours-before &&
+ reword_with_message theirs <<-EOF &&
+ Reworded theirs
+ EOF
+ git rev-parse ours >ours-after &&
+ test_cmp ours-before ours-after &&
+
+ expect_graph --branches <<-\EOF
+ * Reworded theirs
+ | * ours
+ |/
+ * base
+ EOF
+ )
+'
+
+test_expect_success 'can reword a merge commit' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit base &&
+ git branch branch &&
+ test_commit ours &&
+ git switch branch &&
+ test_commit theirs &&
+ git switch - &&
+ git merge theirs &&
+
+ # It is not possible to replay merge commits embedded in the
+ # history (yet).
+ test_must_fail git -c core.editor=false history reword HEAD~ 2>err &&
+ test_grep "replaying merge commits is not supported yet" err &&
+
+ # But it is possible to reword a merge commit directly.
+ reword_with_message HEAD <<-EOF &&
+ Reworded merge commit
+ EOF
+ expect_graph <<-\EOF
+ * Reworded merge commit
+ |\
+ | * theirs
+ * | ours
+ |/
+ * base
+ EOF
+ )
+'
+
+test_expect_success '--dry-run prints ref updates without modifying repo' '
+ test_when_finished "rm -rf repo" &&
+ git init repo --initial-branch=main &&
+ (
+ cd repo &&
+ test_commit base &&
+ git branch branch &&
+ test_commit ours &&
+ git switch branch &&
+ test_commit theirs &&
+
+ git refs list >refs-expect &&
+ reword_with_message --dry-run --update-refs=head base >updates <<-\EOF &&
+ reworded commit
+ EOF
+ git refs list >refs-actual &&
+ test_cmp refs-expect refs-actual &&
+ test_grep "update refs/heads/branch" updates &&
+ test_grep ! "update refs/heads/main" updates &&
+
+ reword_with_message --dry-run base >updates <<-\EOF &&
+ reworded commit
+ EOF
+ git refs list >refs-actual &&
+ test_cmp refs-expect refs-actual &&
+
+ test_grep "update refs/heads/branch" updates &&
+ test_grep "update refs/heads/main" updates &&
+ git update-ref --stdin <updates &&
+ expect_log --branches <<-\EOF
+ theirs
+ ours
+ reworded commit
+ EOF
+ )
+'
+
+test_expect_success '--update-refs=head updates only HEAD' '
+ test_when_finished "rm -rf repo" &&
+ git init repo --initial-branch=main &&
+ (
+ cd repo &&
+ test_commit base &&
+ git branch branch &&
+ test_commit theirs &&
+ git switch branch &&
+ test_commit ours &&
+
+ # When told to update HEAD, only, the command will refuse to
+ # rewrite commits that are not an ancestor of HEAD.
+ test_must_fail git -c core.editor=false history reword --update-refs=head theirs 2>err &&
+ test_grep "rewritten commit must be an ancestor of HEAD" err &&
+
+ reword_with_message --update-refs=head base >updates <<-\EOF &&
+ reworded base
+ EOF
+ expect_log HEAD <<-\EOF &&
+ ours
+ reworded base
+ EOF
+ expect_log main <<-\EOF
+ theirs
+ base
+ EOF
+ )
+'
+
+test_expect_success 'editor shows proper status' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit first &&
+
+ write_script fake-editor.sh <<-\EOF &&
+ cp "$1" . &&
+ printf "\namend a comment\n" >>"$1"
+ EOF
+ test_set_editor "$(pwd)"/fake-editor.sh &&
+ git history reword HEAD &&
+
+ cat >expect <<-EOF &&
+ first
+
+ # Please enter the commit message for the reworded changes. Lines starting
+ # with ${SQ}#${SQ} will be ignored, and an empty message aborts the commit.
+ # Changes to be committed:
+ # new file: first.t
+ #
+ EOF
+ test_cmp expect COMMIT_EDITMSG &&
+
+ test_commit_message HEAD <<-\EOF
+ first
+
+ amend a comment
+ EOF
+ )
+'
+
+# For now, git-history(1) does not yet execute any hooks. This is subject to
+# change in the future, and if it does this test here is expected to start
+# failing. In other words, this test is not an endorsement of the current
+# status quo.
+test_expect_success 'hooks are not executed for rewritten commits' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit first &&
+ test_commit second &&
+ test_commit third &&
+
+ ORIG_PATH="$(pwd)" &&
+ export ORIG_PATH &&
+ for hook in prepare-commit-msg pre-commit post-commit post-rewrite commit-msg
+ do
+ write_script .git/hooks/$hook <<-\EOF || exit 1
+ touch "$ORIG_PATH/hooks.log
+ EOF
+ done &&
+
+ reword_with_message HEAD~ <<-EOF &&
+ second reworded
+ EOF
+
+ cat >expect <<-EOF &&
+ third
+ second reworded
+ first
+ EOF
+ git log --format=%s >actual &&
+ test_cmp expect actual &&
+
+ test_path_is_missing hooks.log
+ )
+'
+
+test_expect_success 'aborts with empty commit message' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ test_commit first &&
+
+ ! reword_with_message HEAD 2>err </dev/null &&
+ test_grep "Aborting commit due to empty commit message." err
+ )
+'
+
+test_expect_success 'retains changes in the worktree and index' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ (
+ cd repo &&
+ touch a b &&
+ git add . &&
+ git commit -m "initial commit" &&
+ echo foo >a &&
+ echo bar >b &&
+ git add b &&
+ reword_with_message HEAD <<-EOF &&
+ message
+ EOF
+ cat >expect <<-\EOF &&
+ M a
+ M b
+ ?? actual
+ ?? expect
+ EOF
+ git status --porcelain >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_done