Merge branch 'rd/init-typo'
[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         cp script-from-scratch script-from-scratch-orig &&
74         test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
75         test_tick &&
76         git rebase -i -r A &&
77         test_cmp_graph <<-\EOF
78         *   Merge the topic branch '\''onebranch'\''
79         |\
80         | * D
81         | * G
82         * |   H
83         |\ \
84         | |/
85         |/|
86         | * B
87         |/
88         * A
89         EOF
90 '
91
92 test_expect_success 'generate correct todo list' '
93         cat >expect <<-\EOF &&
94         label onto
95
96         reset onto
97         pick d9df450 B
98         label E
99
100         reset onto
101         pick 5dee784 C
102         label branch-point
103         pick ca2c861 F
104         pick 088b00a G
105         label H
106
107         reset branch-point # C
108         pick 12bd07b D
109         merge -C 2051b56 E # E
110         merge -C 233d48a H # H
111
112         EOF
113
114         grep -v "^#" <.git/ORIGINAL-TODO >output &&
115         test_cmp expect output
116 '
117
118 test_expect_success '`reset` refuses to overwrite untracked files' '
119         git checkout -b refuse-to-reset &&
120         test_commit dont-overwrite-untracked &&
121         git checkout @{-1} &&
122         : >dont-overwrite-untracked.t &&
123         echo "reset refs/tags/dont-overwrite-untracked" >script-from-scratch &&
124         test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
125         test_must_fail git rebase -r HEAD &&
126         git rebase --abort
127 '
128
129 test_expect_success 'failed `merge` writes patch (may be rescheduled, too)' '
130         test_when_finished "test_might_fail git rebase --abort" &&
131         git checkout -b conflicting-merge A &&
132
133         : fail because of conflicting untracked file &&
134         >G.t &&
135         echo "merge -C H G" >script-from-scratch &&
136         test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
137         test_tick &&
138         test_must_fail git rebase -ir HEAD &&
139         grep "^merge -C .* G$" .git/rebase-merge/done &&
140         grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
141         test_path_is_file .git/rebase-merge/patch &&
142
143         : fail because of merge conflict &&
144         rm G.t .git/rebase-merge/patch &&
145         git reset --hard &&
146         test_commit conflicting-G G.t not-G conflicting-G &&
147         test_must_fail git rebase --continue &&
148         ! grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
149         test_path_is_file .git/rebase-merge/patch
150 '
151
152 test_expect_success 'with a branch tip that was cherry-picked already' '
153         git checkout -b already-upstream master &&
154         base="$(git rev-parse --verify HEAD)" &&
155
156         test_commit A1 &&
157         test_commit A2 &&
158         git reset --hard $base &&
159         test_commit B1 &&
160         test_tick &&
161         git merge -m "Merge branch A" A2 &&
162
163         git checkout -b upstream-with-a2 $base &&
164         test_tick &&
165         git cherry-pick A2 &&
166
167         git checkout already-upstream &&
168         test_tick &&
169         git rebase -i -r upstream-with-a2 &&
170         test_cmp_graph upstream-with-a2.. <<-\EOF
171         *   Merge branch A
172         |\
173         | * A1
174         * | B1
175         |/
176         o A2
177         EOF
178 '
179
180 test_expect_success 'do not rebase cousins unless asked for' '
181         git checkout -b cousins master &&
182         before="$(git rev-parse --verify HEAD)" &&
183         test_tick &&
184         git rebase -r HEAD^ &&
185         test_cmp_rev HEAD $before &&
186         test_tick &&
187         git rebase --rebase-merges=rebase-cousins HEAD^ &&
188         test_cmp_graph HEAD^.. <<-\EOF
189         *   Merge the topic branch '\''onebranch'\''
190         |\
191         | * D
192         | * G
193         |/
194         o H
195         EOF
196 '
197
198 test_expect_success 'refs/rewritten/* is worktree-local' '
199         git worktree add wt &&
200         cat >wt/script-from-scratch <<-\EOF &&
201         label xyz
202         exec GIT_DIR=../.git git rev-parse --verify refs/rewritten/xyz >a || :
203         exec git rev-parse --verify refs/rewritten/xyz >b
204         EOF
205
206         test_config -C wt sequence.editor \""$PWD"/replace-editor.sh\" &&
207         git -C wt rebase -i HEAD &&
208         test_must_be_empty wt/a &&
209         test_cmp_rev HEAD "$(cat wt/b)"
210 '
211
212 test_expect_success 'post-rewrite hook and fixups work for merges' '
213         git checkout -b post-rewrite &&
214         test_commit same1 &&
215         git reset --hard HEAD^ &&
216         test_commit same2 &&
217         git merge -m "to fix up" same1 &&
218         echo same old same old >same2.t &&
219         test_tick &&
220         git commit --fixup HEAD same2.t &&
221         fixup="$(git rev-parse HEAD)" &&
222
223         mkdir -p .git/hooks &&
224         test_when_finished "rm .git/hooks/post-rewrite" &&
225         echo "cat >actual" | write_script .git/hooks/post-rewrite &&
226
227         test_tick &&
228         git rebase -i --autosquash -r HEAD^^^ &&
229         printf "%s %s\n%s %s\n%s %s\n%s %s\n" >expect $(git rev-parse \
230                 $fixup^^2 HEAD^2 \
231                 $fixup^^ HEAD^ \
232                 $fixup^ HEAD \
233                 $fixup HEAD) &&
234         test_cmp expect actual
235 '
236
237 test_expect_success 'refuse to merge ancestors of HEAD' '
238         echo "merge HEAD^" >script-from-scratch &&
239         test_config -C wt sequence.editor \""$PWD"/replace-editor.sh\" &&
240         before="$(git rev-parse HEAD)" &&
241         git rebase -i HEAD &&
242         test_cmp_rev HEAD $before
243 '
244
245 test_expect_success 'root commits' '
246         git checkout --orphan unrelated &&
247         (GIT_AUTHOR_NAME="Parsnip" GIT_AUTHOR_EMAIL="root@example.com" \
248          test_commit second-root) &&
249         test_commit third-root &&
250         cat >script-from-scratch <<-\EOF &&
251         pick third-root
252         label first-branch
253         reset [new root]
254         pick second-root
255         merge first-branch # Merge the 3rd root
256         EOF
257         test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
258         test_tick &&
259         git rebase -i --force --root -r &&
260         test "Parsnip" = "$(git show -s --format=%an HEAD^)" &&
261         test $(git rev-parse second-root^0) != $(git rev-parse HEAD^) &&
262         test $(git rev-parse second-root:second-root.t) = \
263                 $(git rev-parse HEAD^:second-root.t) &&
264         test_cmp_graph HEAD <<-\EOF &&
265         *   Merge the 3rd root
266         |\
267         | * third-root
268         * second-root
269         EOF
270
271         : fast forward if possible &&
272         before="$(git rev-parse --verify HEAD)" &&
273         test_might_fail git config --unset sequence.editor &&
274         test_tick &&
275         git rebase -i --root -r &&
276         test_cmp_rev HEAD $before
277 '
278
279 test_expect_success 'a "merge" into a root commit is a fast-forward' '
280         head=$(git rev-parse HEAD) &&
281         cat >script-from-scratch <<-EOF &&
282         reset [new root]
283         merge $head
284         EOF
285         test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
286         test_tick &&
287         git rebase -i -r HEAD^ &&
288         test_cmp_rev HEAD $head
289 '
290
291 test_expect_success 'A root commit can be a cousin, treat it that way' '
292         git checkout --orphan khnum &&
293         test_commit yama &&
294         git checkout -b asherah master &&
295         test_commit shamkat &&
296         git merge --allow-unrelated-histories khnum &&
297         test_tick &&
298         git rebase -f -r HEAD^ &&
299         ! test_cmp_rev HEAD^2 khnum &&
300         test_cmp_graph HEAD^.. <<-\EOF &&
301         *   Merge branch '\''khnum'\'' into asherah
302         |\
303         | * yama
304         o shamkat
305         EOF
306         test_tick &&
307         git rebase --rebase-merges=rebase-cousins HEAD^ &&
308         test_cmp_graph HEAD^.. <<-\EOF
309         *   Merge branch '\''khnum'\'' into asherah
310         |\
311         | * yama
312         |/
313         o shamkat
314         EOF
315 '
316
317 test_expect_success 'labels that are object IDs are rewritten' '
318         git checkout -b third B &&
319         test_tick &&
320         test_commit I &&
321         third=$(git rev-parse HEAD) &&
322         git checkout -b labels master &&
323         git merge --no-commit third &&
324         test_tick &&
325         git commit -m "Merge commit '\''$third'\'' into labels" &&
326         cp script-from-scratch-orig script-from-scratch &&
327         test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
328         test_tick &&
329         git rebase -i -r A &&
330         ! grep "^label $third$" .git/ORIGINAL-TODO
331 '
332
333 test_done