From 5400677903bdb852e0ca89e41e009afb8a1b6239 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 11 Dec 2018 08:11:34 -0800 Subject: t5407: add a test demonstrating how interactive handles --skip differently The post-rewrite hook is documented as being invoked by commands that rewrite commits such as commit --amend and rebase, and that it will be called for each rewritten commit. Apparently, the three backends handled --skip'ed commits differently: am: treat the skipped commit as though it weren't rewritten merge: same as 'am' backend interactive: treat skipped commits as having been rewritten to empty (view them as an empty fixup to their parent) For now, just add a testcase documenting the different behavior (use --keep to force usage of the interactive machinery even though we have no empty commits). A subsequent commit will remove the inconsistency in --skip handling. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- t/t5407-post-rewrite-hook.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 't') diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh index 9b2a274c71..6426ec8991 100755 --- a/t/t5407-post-rewrite-hook.sh +++ b/t/t5407-post-rewrite-hook.sh @@ -125,6 +125,37 @@ test_expect_success 'git rebase -m --skip' ' verify_hook_input ' +test_expect_success 'git rebase with implicit use of interactive backend' ' + git reset --hard D && + clear_hook_input && + test_must_fail git rebase --keep --onto A B && + echo C > foo && + git add foo && + git rebase --continue && + echo rebase >expected.args && + cat >expected.data <<-EOF && + $(git rev-parse C) $(git rev-parse HEAD^) + $(git rev-parse D) $(git rev-parse HEAD) + EOF + verify_hook_input +' + +test_expect_success 'git rebase --skip with implicit use of interactive backend' ' + git reset --hard D && + clear_hook_input && + test_must_fail git rebase --keep --onto A B && + test_must_fail git rebase --skip && + echo D > foo && + git add foo && + git rebase --continue && + echo rebase >expected.args && + cat >expected.data <<-EOF && + $(git rev-parse C) $(git rev-parse HEAD^) + $(git rev-parse D) $(git rev-parse HEAD) + EOF + verify_hook_input +' + . "$TEST_DIRECTORY"/lib-rebase.sh set_fake_editor -- cgit v1.2.3 From 45339f74ef87123ab79831310bf8047cebe5177b Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 11 Dec 2018 08:11:35 -0800 Subject: am, rebase--merge: do not overlook --skip'ed commits with post-rewrite The post-rewrite hook is supposed to be invoked for each rewritten commit. The fact that a commit was selected and processed by the rebase operation (even though when we hit an error a user said it had no more useful changes), suggests we should write an entry for it. In particular, let's treat it as an empty commit trivially squashed into its parent. This brings the rebase--am and rebase--merge backends in sync with the behavior of the interactive rebase backend. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- t/t5407-post-rewrite-hook.sh | 3 +++ 1 file changed, 3 insertions(+) (limited to 't') diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh index 6426ec8991..a4a5903cba 100755 --- a/t/t5407-post-rewrite-hook.sh +++ b/t/t5407-post-rewrite-hook.sh @@ -78,6 +78,7 @@ test_expect_success 'git rebase --skip' ' git rebase --continue && echo rebase >expected.args && cat >expected.data <<-EOF && + $(git rev-parse C) $(git rev-parse HEAD^) $(git rev-parse D) $(git rev-parse HEAD) EOF verify_hook_input @@ -91,6 +92,7 @@ test_expect_success 'git rebase --skip the last one' ' echo rebase >expected.args && cat >expected.data <<-EOF && $(git rev-parse E) $(git rev-parse HEAD) + $(git rev-parse F) $(git rev-parse HEAD) EOF verify_hook_input ' @@ -120,6 +122,7 @@ test_expect_success 'git rebase -m --skip' ' git rebase --continue && echo rebase >expected.args && cat >expected.data <<-EOF && + $(git rev-parse C) $(git rev-parse HEAD^) $(git rev-parse D) $(git rev-parse HEAD) EOF verify_hook_input -- cgit v1.2.3 From c91c944a068e12eca5d4b6040ad05c7068437111 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 11 Dec 2018 08:11:38 -0800 Subject: rebase: define linearization ordering and enforce it Ever since commit 3f213981e44a ("add tests for rebasing merged history", 2013-06-06), t3425 has had tests which included the rebasing of merged history and whose order of applied commits was checked. Unfortunately, the tests expected different behavior depending on which backend was in use. Implementing these checks was the following four lines (including the TODO message) which were repeated verbatim three times in t3425: #TODO: make order consistent across all flavors of rebase test_run_rebase success 'e n o' '' test_run_rebase success 'e n o' -m test_run_rebase success 'n o e' -i As part of the effort to reduce differences between the rebase backends so that users get more uniform behavior, let's define the correct behavior and modify the different backends so they all get the right answer. It turns out that the difference in behavior here is entirely due to topological sorting; since some backends require topological sorting (particularly when --rebase-merges is specified), require it for all modes. Modify the am and merge backends to implement this. Performance Considerations: I was unable to measure any appreciable performance difference with this change. Trying to control the run-to-run variation was difficult; I eventually found a headless beefy box that I could ssh into, which seemed to help. Using git.git, I ran the following testcase: $ git reset --hard v2.20.0-rc1~2 $ time git rebase --quiet v2.20.0-rc0~16 I first ran once to warm any disk caches, then ran five subsequent runs and recorded the times of those five. I observed the following results for the average time: Before this change: "real" timing: 1.340s (standard deviation: 0.040s) "user" timing: 1.050s (standard deviation: 0.041s) "sys" timing: 0.270s (standard deviation: 0.011s) After this change: "real" timing: 1.327s (standard deviation: 0.065s) "user" timing: 1.031s (standard deviation: 0.061s) "sys" timing: 0.280s (standard deviation: 0.014s) Measurements aside, I would expect the timing for walking revisions to be dwarfed by the work involved in creating and applying patches, so this isn't too surprising. Further, while somewhat counter-intuitive, it is possible that turning on topological sorting is actually a performance improvement: by way of comparison, turning on --topo-order made fast-export faster (see https://public-inbox.org/git/20090211135640.GA19600@coredump.intra.peff.net/). Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- t/t3425-rebase-topology-merges.sh | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 't') diff --git a/t/t3425-rebase-topology-merges.sh b/t/t3425-rebase-topology-merges.sh index 5f892e33d7..fd8efe84fe 100755 --- a/t/t3425-rebase-topology-merges.sh +++ b/t/t3425-rebase-topology-merges.sh @@ -70,9 +70,8 @@ test_run_rebase () { test_linear_range "\'"$expected"\'" d.. " } -#TODO: make order consistent across all flavors of rebase -test_run_rebase success 'e n o' '' -test_run_rebase success 'e n o' -m +test_run_rebase success 'n o e' '' +test_run_rebase success 'n o e' -m test_run_rebase success 'n o e' -i test_run_rebase () { @@ -87,9 +86,8 @@ test_run_rebase () { test_linear_range "\'"$expected"\'" c.. " } -#TODO: make order consistent across all flavors of rebase -test_run_rebase success 'd e n o' '' -test_run_rebase success 'd e n o' -m +test_run_rebase success 'd n o e' '' +test_run_rebase success 'd n o e' -m test_run_rebase success 'd n o e' -i test_run_rebase () { @@ -104,9 +102,8 @@ test_run_rebase () { test_linear_range "\'"$expected"\'" c.. " } -#TODO: make order consistent across all flavors of rebase -test_run_rebase success 'd e n o' '' -test_run_rebase success 'd e n o' -m +test_run_rebase success 'd n o e' '' +test_run_rebase success 'd n o e' -m test_run_rebase success 'd n o e' -i if ! test_have_prereq REBASE_P; then -- cgit v1.2.3 From 68aa495b590d417e88562ab1e5da7d84d0531f21 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Tue, 11 Dec 2018 08:11:39 -0800 Subject: rebase: implement --merge via the interactive machinery As part of an ongoing effort to make rebase have more uniform behavior, modify the merge backend to behave like the interactive one, by re-implementing it on top of the latter. Interactive rebases are implemented in terms of cherry-pick rather than the merge-recursive builtin, but cherry-pick also calls into the recursive merge machinery by default and can accept special merge strategies and/or special strategy options. As such, there really is not any need for having both git-rebase--merge and git-rebase--interactive anymore. Delete git-rebase--merge.sh and instead implement it in builtin/rebase.c. This results in a few deliberate but small user-visible changes: * The progress output is modified (see t3406 and t3420 for examples) * A few known test failures are now fixed (see t3421) * bash-prompt during a rebase --merge is now REBASE-i instead of REBASE-m. Reason: The prompt is a reflection of the backend in use; this allows users to report an issue to the git mailing list with the appropriate backend information, and allows advanced users to know where to search for relevant control files. (see t9903) testcase modification notes: t3406: --interactive and --merge had slightly different progress output while running; adjust a test to match the new expectation t3420: these test precise output while running, but rebase--am, rebase--merge, and rebase--interactive all were built on very different commands (am, merge-recursive, cherry-pick), so the tests expected different output for each type. Now we expect --merge and --interactive to have the same output. t3421: --interactive fixes some bugs in --merge! Wahoo! t9903: --merge uses the interactive backend so the prompt expected is now REBASE-i. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- t/t3406-rebase-message.sh | 7 +--- t/t3420-rebase-autostash.sh | 78 +++------------------------------------ t/t3421-rebase-topology-linear.sh | 10 ++--- t/t9903-bash-prompt.sh | 2 +- 4 files changed, 13 insertions(+), 84 deletions(-) (limited to 't') diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index f64b130cb8..b393e1e9fe 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -17,14 +17,9 @@ test_expect_success 'setup' ' git tag start ' -cat >expect <<\EOF -Already applied: 0001 A -Already applied: 0002 B -Committed: 0003 Z -EOF - test_expect_success 'rebase -m' ' git rebase -m master >report && + >expect && sed -n -e "/^Already applied: /p" \ -e "/^Committed: /p" report >actual && test_cmp expect actual diff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh index 4c7494cc8f..2d1094e483 100755 --- a/t/t3420-rebase-autostash.sh +++ b/t/t3420-rebase-autostash.sh @@ -53,41 +53,6 @@ create_expected_success_interactive () { EOF } -create_expected_success_merge () { - cat >expected <<-EOF - $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual) - HEAD is now at $(git rev-parse --short feature-branch) third commit - First, rewinding head to replay your work on top of it... - Merging unrelated-onto-branch with HEAD~1 - Merging: - $(git rev-parse --short unrelated-onto-branch) unrelated commit - $(git rev-parse --short feature-branch^) second commit - found 1 common ancestor: - $(git rev-parse --short feature-branch~2) initial commit - [detached HEAD $(git rev-parse --short rebased-feature-branch~1)] second commit - Author: A U Thor - Date: Thu Apr 7 15:14:13 2005 -0700 - 2 files changed, 2 insertions(+) - create mode 100644 file1 - create mode 100644 file2 - Committed: 0001 second commit - Merging unrelated-onto-branch with HEAD~0 - Merging: - $(git rev-parse --short rebased-feature-branch~1) second commit - $(git rev-parse --short feature-branch) third commit - found 1 common ancestor: - $(git rev-parse --short feature-branch~1) second commit - [detached HEAD $(git rev-parse --short rebased-feature-branch)] third commit - Author: A U Thor - Date: Thu Apr 7 15:15:13 2005 -0700 - 1 file changed, 1 insertion(+) - create mode 100644 file3 - Committed: 0002 third commit - All done. - Applied autostash. - EOF -} - create_expected_failure_am () { cat >expected <<-EOF $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual) @@ -112,43 +77,6 @@ create_expected_failure_interactive () { EOF } -create_expected_failure_merge () { - cat >expected <<-EOF - $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual) - HEAD is now at $(git rev-parse --short feature-branch) third commit - First, rewinding head to replay your work on top of it... - Merging unrelated-onto-branch with HEAD~1 - Merging: - $(git rev-parse --short unrelated-onto-branch) unrelated commit - $(git rev-parse --short feature-branch^) second commit - found 1 common ancestor: - $(git rev-parse --short feature-branch~2) initial commit - [detached HEAD $(git rev-parse --short rebased-feature-branch~1)] second commit - Author: A U Thor - Date: Thu Apr 7 15:14:13 2005 -0700 - 2 files changed, 2 insertions(+) - create mode 100644 file1 - create mode 100644 file2 - Committed: 0001 second commit - Merging unrelated-onto-branch with HEAD~0 - Merging: - $(git rev-parse --short rebased-feature-branch~1) second commit - $(git rev-parse --short feature-branch) third commit - found 1 common ancestor: - $(git rev-parse --short feature-branch~1) second commit - [detached HEAD $(git rev-parse --short rebased-feature-branch)] third commit - Author: A U Thor - Date: Thu Apr 7 15:15:13 2005 -0700 - 1 file changed, 1 insertion(+) - create mode 100644 file3 - Committed: 0002 third commit - All done. - Applying autostash resulted in conflicts. - Your changes are safe in the stash. - You can run "git stash pop" or "git stash drop" at any time. - EOF -} - testrebase () { type=$1 dotest=$2 @@ -177,6 +105,9 @@ testrebase () { test_expect_success "rebase$type --autostash: check output" ' test_when_finished git branch -D rebased-feature-branch && suffix=${type#\ --} && suffix=${suffix:-am} && + if test ${suffix} = "merge"; then + suffix=interactive + fi && create_expected_success_$suffix && test_i18ncmp expected actual ' @@ -274,6 +205,9 @@ testrebase () { test_expect_success "rebase$type: check output with conflicting stash" ' test_when_finished git branch -D rebased-feature-branch && suffix=${type#\ --} && suffix=${suffix:-am} && + if test ${suffix} = "merge"; then + suffix=interactive + fi && create_expected_failure_$suffix && test_i18ncmp expected actual ' diff --git a/t/t3421-rebase-topology-linear.sh b/t/t3421-rebase-topology-linear.sh index 23ad4cff35..7274dca40b 100755 --- a/t/t3421-rebase-topology-linear.sh +++ b/t/t3421-rebase-topology-linear.sh @@ -111,7 +111,7 @@ test_run_rebase () { " } test_run_rebase success '' -test_run_rebase failure -m +test_run_rebase success -m test_run_rebase success -i test_have_prereq !REBASE_P || test_run_rebase success -p @@ -126,7 +126,7 @@ test_run_rebase () { " } test_run_rebase success '' -test_run_rebase failure -m +test_run_rebase success -m test_run_rebase success -i test_have_prereq !REBASE_P || test_run_rebase success -p @@ -141,7 +141,7 @@ test_run_rebase () { " } test_run_rebase success '' -test_run_rebase failure -m +test_run_rebase success -m test_run_rebase success -i test_have_prereq !REBASE_P || test_run_rebase success -p @@ -284,7 +284,7 @@ test_run_rebase () { " } test_run_rebase success '' -test_run_rebase failure -m +test_run_rebase success -m test_run_rebase success -i test_have_prereq !REBASE_P || test_run_rebase success -p @@ -315,7 +315,7 @@ test_run_rebase () { " } test_run_rebase success '' -test_run_rebase failure -m +test_run_rebase success -m test_run_rebase success -i test_have_prereq !REBASE_P || test_run_rebase failure -p diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh index 81a5179e28..5cadedb2a9 100755 --- a/t/t9903-bash-prompt.sh +++ b/t/t9903-bash-prompt.sh @@ -180,7 +180,7 @@ test_expect_success 'prompt - interactive rebase' ' ' test_expect_success 'prompt - rebase merge' ' - printf " (b2|REBASE-m 1/3)" >expected && + printf " (b2|REBASE-i 1/3)" >expected && git checkout b2 && test_when_finished "git checkout master" && test_must_fail git rebase --merge b1 b2 && -- cgit v1.2.3