Merge branch 'ds/commit-graph-generation-config'
[git] / t / t3400-rebase.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2005 Amos Waterland
4 #
5
6 test_description='git rebase assorted tests
7
8 This test runs git rebase and checks that the author information is not lost
9 among other things.
10 '
11 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
12 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
13
14 . ./test-lib.sh
15
16 GIT_AUTHOR_NAME=author@name
17 GIT_AUTHOR_EMAIL=bogus@email@address
18 export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
19
20 test_expect_success 'prepare repository with topic branches' '
21         git config core.logAllRefUpdates true &&
22         echo First >A &&
23         git update-index --add A &&
24         git commit -m "Add A." &&
25         git checkout -b force-3way &&
26         echo Dummy >Y &&
27         git update-index --add Y &&
28         git commit -m "Add Y." &&
29         git checkout -b filemove &&
30         git reset --soft main &&
31         mkdir D &&
32         git mv A D/A &&
33         git commit -m "Move A." &&
34         git checkout -b my-topic-branch main &&
35         echo Second >B &&
36         git update-index --add B &&
37         git commit -m "Add B." &&
38         git checkout -f main &&
39         echo Third >>A &&
40         git update-index A &&
41         git commit -m "Modify A." &&
42         git checkout -b side my-topic-branch &&
43         echo Side >>C &&
44         git add C &&
45         git commit -m "Add C" &&
46         git checkout -f my-topic-branch &&
47         git tag topic
48 '
49
50 test_expect_success 'rebase on dirty worktree' '
51         echo dirty >>A &&
52         test_must_fail git rebase main
53 '
54
55 test_expect_success 'rebase on dirty cache' '
56         git add A &&
57         test_must_fail git rebase main
58 '
59
60 test_expect_success 'rebase against main' '
61         git reset --hard HEAD &&
62         git rebase main
63 '
64
65 test_expect_success 'rebase sets ORIG_HEAD to pre-rebase state' '
66         git checkout -b orig-head topic &&
67         pre="$(git rev-parse --verify HEAD)" &&
68         git rebase main &&
69         test_cmp_rev "$pre" ORIG_HEAD &&
70         test_cmp_rev ! "$pre" HEAD
71 '
72
73 test_expect_success 'rebase, with <onto> and <upstream> specified as :/quuxery' '
74         test_when_finished "git branch -D torebase" &&
75         git checkout -b torebase my-topic-branch^ &&
76         upstream=$(git rev-parse ":/Add B") &&
77         onto=$(git rev-parse ":/Add A") &&
78         git rebase --onto $onto $upstream &&
79         git reset --hard my-topic-branch^ &&
80         git rebase --onto ":/Add A" ":/Add B" &&
81         git checkout my-topic-branch
82 '
83
84 test_expect_success 'the rebase operation should not have destroyed author information' '
85         ! (git log | grep "Author:" | grep "<>")
86 '
87
88 test_expect_success 'the rebase operation should not have destroyed author information (2)' "
89         git log -1 |
90         grep 'Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>'
91 "
92
93 test_expect_success 'HEAD was detached during rebase' '
94         test $(git rev-parse HEAD@{1}) != $(git rev-parse my-topic-branch@{1})
95 '
96
97 test_expect_success 'rebase from ambiguous branch name' '
98         git checkout -b topic side &&
99         git rebase main
100 '
101
102 test_expect_success 'rebase off of the previous branch using "-"' '
103         git checkout main &&
104         git checkout HEAD^ &&
105         git rebase @{-1} >expect.messages &&
106         git merge-base main HEAD >expect.forkpoint &&
107
108         git checkout main &&
109         git checkout HEAD^ &&
110         git rebase - >actual.messages &&
111         git merge-base main HEAD >actual.forkpoint &&
112
113         test_cmp expect.forkpoint actual.forkpoint &&
114         # the next one is dubious---we may want to say "-",
115         # instead of @{-1}, in the message
116         test_cmp expect.messages actual.messages
117 '
118
119 test_expect_success 'rebase a single mode change' '
120         git checkout main &&
121         git branch -D topic &&
122         echo 1 >X &&
123         git add X &&
124         test_tick &&
125         git commit -m prepare &&
126         git checkout -b modechange HEAD^ &&
127         echo 1 >X &&
128         git add X &&
129         test_chmod +x A &&
130         test_tick &&
131         git commit -m modechange &&
132         GIT_TRACE=1 git rebase main
133 '
134
135 test_expect_success 'rebase is not broken by diff.renames' '
136         test_config diff.renames copies &&
137         git checkout filemove &&
138         GIT_TRACE=1 git rebase force-3way
139 '
140
141 test_expect_success 'setup: recover' '
142         test_might_fail git rebase --abort &&
143         git reset --hard &&
144         git checkout modechange
145 '
146
147 test_expect_success 'Show verbose error when HEAD could not be detached' '
148         >B &&
149         test_when_finished "rm -f B" &&
150         test_must_fail git rebase topic 2>output.err >output.out &&
151         test_i18ngrep "The following untracked working tree files would be overwritten by checkout:" output.err &&
152         test_i18ngrep B output.err
153 '
154
155 test_expect_success 'fail when upstream arg is missing and not on branch' '
156         git checkout topic &&
157         test_must_fail git rebase
158 '
159
160 test_expect_success 'fail when upstream arg is missing and not configured' '
161         git checkout -b no-config topic &&
162         test_must_fail git rebase
163 '
164
165 test_expect_success 'rebase works with format.useAutoBase' '
166         test_config format.useAutoBase true &&
167         git checkout topic &&
168         git rebase main
169 '
170
171 test_expect_success 'default to common base in @{upstream}s reflog if no upstream arg (--merge)' '
172         git checkout -b default-base main &&
173         git checkout -b default topic &&
174         git config branch.default.remote . &&
175         git config branch.default.merge refs/heads/default-base &&
176         git rebase --merge &&
177         git rev-parse --verify default-base >expect &&
178         git rev-parse default~1 >actual &&
179         test_cmp expect actual &&
180         git checkout default-base &&
181         git reset --hard HEAD^ &&
182         git checkout default &&
183         git rebase --merge &&
184         git rev-parse --verify default-base >expect &&
185         git rev-parse default~1 >actual &&
186         test_cmp expect actual
187 '
188
189 test_expect_success 'default to common base in @{upstream}s reflog if no upstream arg (--apply)' '
190         git checkout -B default-base main &&
191         git checkout -B default topic &&
192         git config branch.default.remote . &&
193         git config branch.default.merge refs/heads/default-base &&
194         git rebase --apply &&
195         git rev-parse --verify default-base >expect &&
196         git rev-parse default~1 >actual &&
197         test_cmp expect actual &&
198         git checkout default-base &&
199         git reset --hard HEAD^ &&
200         git checkout default &&
201         git rebase --apply &&
202         git rev-parse --verify default-base >expect &&
203         git rev-parse default~1 >actual &&
204         test_cmp expect actual
205 '
206
207 test_expect_success 'cherry-picked commits and fork-point work together' '
208         git checkout default-base &&
209         echo Amended >A &&
210         git commit -a --no-edit --amend &&
211         test_commit B B &&
212         test_commit new_B B "New B" &&
213         test_commit C C &&
214         git checkout default &&
215         git reset --hard default-base@{4} &&
216         test_commit D D &&
217         git cherry-pick -2 default-base^ &&
218         test_commit final_B B "Final B" &&
219         git rebase &&
220         echo Amended >expect &&
221         test_cmp expect A &&
222         echo "Final B" >expect &&
223         test_cmp expect B &&
224         echo C >expect &&
225         test_cmp expect C &&
226         echo D >expect &&
227         test_cmp expect D
228 '
229
230 test_expect_success 'rebase --apply -q is quiet' '
231         git checkout -b quiet topic &&
232         git rebase --apply -q main >output.out 2>&1 &&
233         test_must_be_empty output.out
234 '
235
236 test_expect_success 'rebase --merge -q is quiet' '
237         git checkout -B quiet topic &&
238         git rebase --merge -q main >output.out 2>&1 &&
239         test_must_be_empty output.out
240 '
241
242 test_expect_success 'Rebase a commit that sprinkles CRs in' '
243         (
244                 echo "One" &&
245                 echo "TwoQ" &&
246                 echo "Three" &&
247                 echo "FQur" &&
248                 echo "Five"
249         ) | q_to_cr >CR &&
250         git add CR &&
251         test_tick &&
252         git commit -a -m "A file with a line with CR" &&
253         git tag file-with-cr &&
254         git checkout HEAD^0 &&
255         git rebase --onto HEAD^^ HEAD^ &&
256         git diff --exit-code file-with-cr:CR HEAD:CR
257 '
258
259 test_expect_success 'rebase can copy notes' '
260         git config notes.rewrite.rebase true &&
261         git config notes.rewriteRef "refs/notes/*" &&
262         test_commit n1 &&
263         test_commit n2 &&
264         test_commit n3 &&
265         git notes add -m"a note" n3 &&
266         git rebase --onto n1 n2 &&
267         test "a note" = "$(git notes show HEAD)"
268 '
269
270 test_expect_success 'rebase -m can copy notes' '
271         git reset --hard n3 &&
272         git rebase -m --onto n1 n2 &&
273         test "a note" = "$(git notes show HEAD)"
274 '
275
276 test_expect_success 'rebase commit with an ancient timestamp' '
277         git reset --hard &&
278
279         >old.one && git add old.one && test_tick &&
280         git commit --date="@12345 +0400" -m "Old one" &&
281         >old.two && git add old.two && test_tick &&
282         git commit --date="@23456 +0500" -m "Old two" &&
283         >old.three && git add old.three && test_tick &&
284         git commit --date="@34567 +0600" -m "Old three" &&
285
286         git cat-file commit HEAD^^ >actual &&
287         grep "author .* 12345 +0400$" actual &&
288         git cat-file commit HEAD^ >actual &&
289         grep "author .* 23456 +0500$" actual &&
290         git cat-file commit HEAD >actual &&
291         grep "author .* 34567 +0600$" actual &&
292
293         git rebase --onto HEAD^^ HEAD^ &&
294
295         git cat-file commit HEAD >actual &&
296         grep "author .* 34567 +0600$" actual
297 '
298
299 test_expect_success 'rebase with "From " line in commit message' '
300         git checkout -b preserve-from main~1 &&
301         cat >From_.msg <<EOF &&
302 Somebody embedded an mbox in a commit message
303
304 This is from so-and-so:
305
306 From a@b Mon Sep 17 00:00:00 2001
307 From: John Doe <nobody@example.com>
308 Date: Sat, 11 Nov 2017 00:00:00 +0000
309 Subject: not this message
310
311 something
312 EOF
313         >From_ &&
314         git add From_ &&
315         git commit -F From_.msg &&
316         git rebase main &&
317         git log -1 --pretty=format:%B >out &&
318         test_cmp From_.msg out
319 '
320
321 test_expect_success 'rebase --apply and --show-current-patch' '
322         test_create_repo conflict-apply &&
323         (
324                 cd conflict-apply &&
325                 test_commit init &&
326                 echo one >>init.t &&
327                 git commit -a -m one &&
328                 echo two >>init.t &&
329                 git commit -a -m two &&
330                 git tag two &&
331                 test_must_fail git rebase --apply -f --onto init HEAD^ &&
332                 GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr &&
333                 grep "show.*$(git rev-parse two)" stderr
334         )
335 '
336
337 test_expect_success 'rebase --apply and .gitattributes' '
338         test_create_repo attributes &&
339         (
340                 cd attributes &&
341                 test_commit init &&
342                 git config filter.test.clean "sed -e '\''s/smudged/clean/g'\''" &&
343                 git config filter.test.smudge "sed -e '\''s/clean/smudged/g'\''" &&
344
345                 test_commit second &&
346                 git checkout -b test HEAD^ &&
347
348                 echo "*.txt filter=test" >.gitattributes &&
349                 git add .gitattributes &&
350                 test_commit third &&
351
352                 echo "This text is smudged." >a.txt &&
353                 git add a.txt &&
354                 test_commit fourth &&
355
356                 git checkout -b removal HEAD^ &&
357                 git rm .gitattributes &&
358                 git add -u &&
359                 test_commit fifth &&
360                 git cherry-pick test &&
361
362                 git checkout test &&
363                 git rebase main &&
364                 grep "smudged" a.txt &&
365
366                 git checkout removal &&
367                 git reset --hard &&
368                 git rebase main &&
369                 grep "clean" a.txt
370         )
371 '
372
373 test_expect_success 'rebase--merge.sh and --show-current-patch' '
374         test_create_repo conflict-merge &&
375         (
376                 cd conflict-merge &&
377                 test_commit init &&
378                 echo one >>init.t &&
379                 git commit -a -m one &&
380                 echo two >>init.t &&
381                 git commit -a -m two &&
382                 git tag two &&
383                 test_must_fail git rebase --merge --onto init HEAD^ &&
384                 git rebase --show-current-patch >actual.patch &&
385                 GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr &&
386                 grep "show.*REBASE_HEAD" stderr &&
387                 test "$(git rev-parse REBASE_HEAD)" = "$(git rev-parse two)"
388         )
389 '
390
391 test_expect_success 'rebase -c rebase.useBuiltin=false warning' '
392         expected="rebase.useBuiltin support has been removed" &&
393
394         # Only warn when the legacy rebase is requested...
395         test_must_fail git -c rebase.useBuiltin=false rebase 2>err &&
396         test_i18ngrep "$expected" err &&
397         test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=false git rebase 2>err &&
398         test_i18ngrep "$expected" err &&
399
400         # ...not when we would have used the built-in anyway
401         test_must_fail git -c rebase.useBuiltin=true rebase 2>err &&
402         test_must_be_empty err &&
403         test_must_fail env GIT_TEST_REBASE_USE_BUILTIN=true git rebase 2>err &&
404         test_must_be_empty err
405 '
406
407 test_expect_success 'switch to branch checked out here' '
408         git checkout main &&
409         git rebase main main
410 '
411
412 test_expect_success 'switch to branch not checked out' '
413         git checkout main &&
414         git branch other &&
415         git rebase main other
416 '
417
418 test_expect_success 'refuse to switch to branch checked out elsewhere' '
419         git checkout main &&
420         git worktree add wt &&
421         test_must_fail git -C wt rebase main main 2>err &&
422         test_i18ngrep "already checked out" err
423 '
424
425 test_done