#!/bin/sh test_description='tests for git-history split subcommand' . ./test-lib.sh set_fake_editor () { write_script fake-editor.sh <<-\EOF && echo "split-out commit" >"$1" EOF test_set_editor "$(pwd)"/fake-editor.sh } expect_log () { git log --format="%s" >actual && cat >expect && test_cmp expect actual } expect_tree_entries () { git ls-tree --name-only "$1" >actual && cat >expect && test_cmp expect actual } test_expect_success 'refuses to work with merge commits' ' 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 && test_must_fail git history split HEAD 2>err && test_grep "commit to be split must not be a merge commit" err && test_must_fail git history split HEAD~ 2>err && test_grep "cannot rearrange commit history with merges" err ) ' test_expect_success 'can split up tip commit' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && test_commit initial && touch bar foo && git add . && git commit -m split-me && git symbolic-ref HEAD >expect && set_fake_editor && git history split HEAD <<-EOF && y n EOF git symbolic-ref HEAD >actual && test_cmp expect actual && expect_log <<-EOF && split-me split-out commit initial EOF expect_tree_entries HEAD~ <<-EOF && bar initial.t EOF expect_tree_entries HEAD <<-EOF bar foo initial.t EOF ) ' test_expect_success 'can split up root commit' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && touch bar foo && git add . && git commit -m root && test_commit tip && set_fake_editor && git history split HEAD~ <<-EOF && y n EOF expect_log <<-EOF && tip root split-out commit EOF expect_tree_entries HEAD~2 <<-EOF && bar EOF expect_tree_entries HEAD~ <<-EOF && bar foo EOF expect_tree_entries HEAD <<-EOF bar foo tip.t EOF ) ' test_expect_success 'can split up in-between commit' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && test_commit initial && touch bar foo && git add . && git commit -m split-me && test_commit tip && set_fake_editor && git history split HEAD~ <<-EOF && y n EOF expect_log <<-EOF && tip split-me split-out commit initial EOF expect_tree_entries HEAD~2 <<-EOF && bar initial.t EOF expect_tree_entries HEAD~ <<-EOF && bar foo initial.t EOF expect_tree_entries HEAD <<-EOF bar foo initial.t tip.t EOF ) ' test_expect_success 'can pick multiple hunks' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && touch bar baz foo qux && git add . && git commit -m split-me && git history split HEAD -m "split-out commit" <<-EOF && y n y n EOF expect_tree_entries HEAD~ <<-EOF && bar foo EOF expect_tree_entries HEAD <<-EOF bar baz foo qux EOF ) ' test_expect_success 'can use only last hunk' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && touch bar foo && git add . && git commit -m split-me && git history split HEAD -m "split-out commit" <<-EOF && n y EOF expect_log <<-EOF && split-me split-out commit EOF expect_tree_entries HEAD~ <<-EOF && foo EOF expect_tree_entries HEAD <<-EOF bar foo EOF ) ' test_expect_success 'aborts with empty commit message' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && touch bar foo && git add . && git commit -m split-me && test_must_fail git history split HEAD -m "" <<-EOF 2>err && y n EOF test_grep "Aborting commit due to empty commit message." err ) ' test_expect_success 'can specify message via option' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && touch bar foo && git add . && git commit -m split-me && git history split HEAD -m "message option" <<-EOF && y n EOF expect_log <<-EOF split-me message option EOF ) ' test_expect_success 'commit message editor sees split-out changes' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && touch bar foo && git add . && git commit -m split-me && write_script fake-editor.sh <<-\EOF && cp "$1" . && echo "some commit message" >>"$1" EOF test_set_editor "$(pwd)"/fake-editor.sh && git history split HEAD <<-EOF && y n EOF cat >expect <<-EOF && # Please enter the commit message for the split-out changes. Lines starting # with ${SQ}#${SQ} will be kept; you may remove them yourself if you want to. # Changes to be committed: # new file: bar # EOF test_cmp expect COMMIT_EDITMSG && expect_log <<-EOF split-me some commit message EOF ) ' test_expect_success 'can use pathspec to limit what gets split' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && touch bar foo && git add . && git commit -m split-me && git history split HEAD -m "message option" -- foo <<-EOF && y EOF expect_tree_entries HEAD~ <<-EOF && foo EOF expect_tree_entries HEAD <<-EOF bar foo EOF ) ' test_expect_success 'refuses to create empty split-out commit' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && test_commit base && touch bar foo && git add . && git commit -m split-me && test_must_fail git history split HEAD 2>err <<-EOF && n n EOF test_grep "split commit is empty" err ) ' test_expect_success 'hooks are executed for rewritten commits' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && touch bar foo && git add . && git commit -m split-me && old_head=$(git rev-parse HEAD) && write_script .git/hooks/prepare-commit-msg <<-EOF && touch "$(pwd)/hooks.log" EOF write_script .git/hooks/post-commit <<-EOF && touch "$(pwd)/hooks.log" EOF write_script .git/hooks/post-rewrite <<-EOF && touch "$(pwd)/hooks.log" EOF set_fake_editor && git history split HEAD <<-EOF && y n EOF expect_log <<-EOF && split-me split-out commit EOF test_path_is_missing hooks.log ) ' test_expect_success 'refuses to create empty original commit' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && touch bar foo && git add . && git commit -m split-me && test_must_fail git history split HEAD 2>err <<-EOF && y y EOF test_grep "split commit tree matches original commit" err ) ' test_expect_success 'retains changes in the worktree and index' ' test_when_finished "rm -rf repo" && git init repo && ( cd repo && echo a >a && echo b >b && git add . && git commit -m "initial commit" && echo a-modified >a && echo b-modified >b && git add b && git history split HEAD -m a-only <<-EOF && y n EOF expect_tree_entries HEAD~ <<-EOF && a EOF expect_tree_entries HEAD <<-EOF && a b EOF cat >expect <<-\EOF && M a M b ?? actual ?? expect EOF git status --porcelain >actual && test_cmp expect actual ) ' test_done