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