Merge branch 'js/rebase-recreate-merge'
[git] / t / t3430-rebase-merges.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2018 Johannes E. Schindelin
4 #
5
6 test_description='git rebase -i --rebase-merges
7
8 This test runs git rebase "interactively", retaining the branch structure by
9 recreating merge commits.
10
11 Initial setup:
12
13     -- B --                   (first)
14    /       \
15  A - C - D - E - H            (master)
16        \       /
17          F - G                (second)
18 '
19 . ./test-lib.sh
20 . "$TEST_DIRECTORY"/lib-rebase.sh
21
22 test_cmp_graph () {
23         cat >expect &&
24         git log --graph --boundary --format=%s "$@" >output &&
25         sed "s/ *$//" <output >output.trimmed &&
26         test_cmp expect output.trimmed
27 }
28
29 test_expect_success 'setup' '
30         write_script replace-editor.sh <<-\EOF &&
31         mv "$1" "$(git rev-parse --git-path ORIGINAL-TODO)"
32         cp script-from-scratch "$1"
33         EOF
34
35         test_commit A &&
36         git checkout -b first &&
37         test_commit B &&
38         git checkout master &&
39         test_commit C &&
40         test_commit D &&
41         git merge --no-commit B &&
42         test_tick &&
43         git commit -m E &&
44         git tag -m E E &&
45         git checkout -b second C &&
46         test_commit F &&
47         test_commit G &&
48         git checkout master &&
49         git merge --no-commit G &&
50         test_tick &&
51         git commit -m H &&
52         git tag -m H H
53 '
54
55 test_expect_success 'create completely different structure' '
56         cat >script-from-scratch <<-\EOF &&
57         label onto
58
59         # onebranch
60         pick G
61         pick D
62         label onebranch
63
64         # second
65         reset onto
66         pick B
67         label second
68
69         reset onto
70         merge -C H second
71         merge onebranch # Merge the topic branch '\''onebranch'\''
72         EOF
73         test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
74         test_tick &&
75         git rebase -i -r A &&
76         test_cmp_graph <<-\EOF
77         *   Merge the topic branch '\''onebranch'\''
78         |\
79         | * D
80         | * G
81         * |   H
82         |\ \
83         | |/
84         |/|
85         | * B
86         |/
87         * A
88         EOF
89 '
90
91 test_expect_success 'generate correct todo list' '
92         cat >expect <<-\EOF &&
93         label onto
94
95         reset onto
96         pick d9df450 B
97         label E
98
99         reset onto
100         pick 5dee784 C
101         label branch-point
102         pick ca2c861 F
103         pick 088b00a G
104         label H
105
106         reset branch-point # C
107         pick 12bd07b D
108         merge -C 2051b56 E # E
109         merge -C 233d48a H # H
110
111         EOF
112
113         grep -v "^#" <.git/ORIGINAL-TODO >output &&
114         test_cmp expect output
115 '
116
117 test_expect_success '`reset` refuses to overwrite untracked files' '
118         git checkout -b refuse-to-reset &&
119         test_commit dont-overwrite-untracked &&
120         git checkout @{-1} &&
121         : >dont-overwrite-untracked.t &&
122         echo "reset refs/tags/dont-overwrite-untracked" >script-from-scratch &&
123         test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
124         test_must_fail git rebase -r HEAD &&
125         git rebase --abort
126 '
127
128 test_expect_success 'failed `merge` writes patch (may be rescheduled, too)' '
129         test_when_finished "test_might_fail git rebase --abort" &&
130         git checkout -b conflicting-merge A &&
131
132         : fail because of conflicting untracked file &&
133         >G.t &&
134         echo "merge -C H G" >script-from-scratch &&
135         test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
136         test_tick &&
137         test_must_fail git rebase -ir HEAD &&
138         grep "^merge -C .* G$" .git/rebase-merge/done &&
139         grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
140         test_path_is_file .git/rebase-merge/patch &&
141
142         : fail because of merge conflict &&
143         rm G.t .git/rebase-merge/patch &&
144         git reset --hard &&
145         test_commit conflicting-G G.t not-G conflicting-G &&
146         test_must_fail git rebase --continue &&
147         ! grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
148         test_path_is_file .git/rebase-merge/patch
149 '
150
151 test_expect_success 'with a branch tip that was cherry-picked already' '
152         git checkout -b already-upstream master &&
153         base="$(git rev-parse --verify HEAD)" &&
154
155         test_commit A1 &&
156         test_commit A2 &&
157         git reset --hard $base &&
158         test_commit B1 &&
159         test_tick &&
160         git merge -m "Merge branch A" A2 &&
161
162         git checkout -b upstream-with-a2 $base &&
163         test_tick &&
164         git cherry-pick A2 &&
165
166         git checkout already-upstream &&
167         test_tick &&
168         git rebase -i -r upstream-with-a2 &&
169         test_cmp_graph upstream-with-a2.. <<-\EOF
170         *   Merge branch A
171         |\
172         | * A1
173         * | B1
174         |/
175         o A2
176         EOF
177 '
178
179 test_expect_success 'do not rebase cousins unless asked for' '
180         git checkout -b cousins master &&
181         before="$(git rev-parse --verify HEAD)" &&
182         test_tick &&
183         git rebase -r HEAD^ &&
184         test_cmp_rev HEAD $before &&
185         test_tick &&
186         git rebase --rebase-merges=rebase-cousins HEAD^ &&
187         test_cmp_graph HEAD^.. <<-\EOF
188         *   Merge the topic branch '\''onebranch'\''
189         |\
190         | * D
191         | * G
192         |/
193         o H
194         EOF
195 '
196
197 test_expect_success 'refs/rewritten/* is worktree-local' '
198         git worktree add wt &&
199         cat >wt/script-from-scratch <<-\EOF &&
200         label xyz
201         exec GIT_DIR=../.git git rev-parse --verify refs/rewritten/xyz >a || :
202         exec git rev-parse --verify refs/rewritten/xyz >b
203         EOF
204
205         test_config -C wt sequence.editor \""$PWD"/replace-editor.sh\" &&
206         git -C wt rebase -i HEAD &&
207         test_must_be_empty wt/a &&
208         test_cmp_rev HEAD "$(cat wt/b)"
209 '
210
211 test_expect_success 'post-rewrite hook and fixups work for merges' '
212         git checkout -b post-rewrite &&
213         test_commit same1 &&
214         git reset --hard HEAD^ &&
215         test_commit same2 &&
216         git merge -m "to fix up" same1 &&
217         echo same old same old >same2.t &&
218         test_tick &&
219         git commit --fixup HEAD same2.t &&
220         fixup="$(git rev-parse HEAD)" &&
221
222         mkdir -p .git/hooks &&
223         test_when_finished "rm .git/hooks/post-rewrite" &&
224         echo "cat >actual" | write_script .git/hooks/post-rewrite &&
225
226         test_tick &&
227         git rebase -i --autosquash -r HEAD^^^ &&
228         printf "%s %s\n%s %s\n%s %s\n%s %s\n" >expect $(git rev-parse \
229                 $fixup^^2 HEAD^2 \
230                 $fixup^^ HEAD^ \
231                 $fixup^ HEAD \
232                 $fixup HEAD) &&
233         test_cmp expect actual
234 '
235
236 test_expect_success 'refuse to merge ancestors of HEAD' '
237         echo "merge HEAD^" >script-from-scratch &&
238         test_config -C wt sequence.editor \""$PWD"/replace-editor.sh\" &&
239         before="$(git rev-parse HEAD)" &&
240         git rebase -i HEAD &&
241         test_cmp_rev HEAD $before
242 '
243
244 test_done