Merge branch 'tb/push-simple-uses-branch-merge-config'
[git] / t / t3420-rebase-autostash.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2013 Ramkumar Ramachandra
4 #
5
6 test_description='git rebase --autostash tests'
7 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
8 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
9
10 . ./test-lib.sh
11
12 test_expect_success setup '
13         echo hello-world >file0 &&
14         git add . &&
15         test_tick &&
16         git commit -m "initial commit" &&
17         git checkout -b feature-branch &&
18         echo another-hello >file1 &&
19         echo goodbye >file2 &&
20         git add . &&
21         test_tick &&
22         git commit -m "second commit" &&
23         echo final-goodbye >file3 &&
24         git add . &&
25         test_tick &&
26         git commit -m "third commit" &&
27         git checkout -b unrelated-onto-branch main &&
28         echo unrelated >file4 &&
29         git add . &&
30         test_tick &&
31         git commit -m "unrelated commit" &&
32         git checkout -b related-onto-branch main &&
33         echo conflicting-change >file2 &&
34         git add . &&
35         test_tick &&
36         git commit -m "related commit" &&
37         remove_progress_re="$(printf "s/.*\\r//")"
38 '
39
40 create_expected_success_apply () {
41         cat >expected <<-EOF
42         $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
43         First, rewinding head to replay your work on top of it...
44         Applying: second commit
45         Applying: third commit
46         Applied autostash.
47         EOF
48 }
49
50 create_expected_success_merge () {
51         q_to_cr >expected <<-EOF
52         $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
53         Applied autostash.
54         Successfully rebased and updated refs/heads/rebased-feature-branch.
55         EOF
56 }
57
58 create_expected_failure_apply () {
59         cat >expected <<-EOF
60         $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
61         First, rewinding head to replay your work on top of it...
62         Applying: second commit
63         Applying: third commit
64         Applying autostash resulted in conflicts.
65         Your changes are safe in the stash.
66         You can run "git stash pop" or "git stash drop" at any time.
67         EOF
68 }
69
70 create_expected_failure_merge () {
71         cat >expected <<-EOF
72         $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
73         Applying autostash resulted in conflicts.
74         Your changes are safe in the stash.
75         You can run "git stash pop" or "git stash drop" at any time.
76         Successfully rebased and updated refs/heads/rebased-feature-branch.
77         EOF
78 }
79
80 testrebase () {
81         type=$1
82         dotest=$2
83
84         test_expect_success "rebase$type: dirty worktree, --no-autostash" '
85                 test_config rebase.autostash true &&
86                 git reset --hard &&
87                 git checkout -b rebased-feature-branch feature-branch &&
88                 test_when_finished git branch -D rebased-feature-branch &&
89                 test_when_finished git checkout feature-branch &&
90                 echo dirty >>file3 &&
91                 test_must_fail git rebase$type --no-autostash unrelated-onto-branch
92         '
93
94         test_expect_success "rebase$type: dirty worktree, non-conflicting rebase" '
95                 test_config rebase.autostash true &&
96                 git reset --hard &&
97                 git checkout -b rebased-feature-branch feature-branch &&
98                 echo dirty >>file3 &&
99                 git rebase$type unrelated-onto-branch >actual 2>&1 &&
100                 grep unrelated file4 &&
101                 grep dirty file3 &&
102                 git checkout feature-branch
103         '
104
105         test_expect_success "rebase$type --autostash: check output" '
106                 test_when_finished git branch -D rebased-feature-branch &&
107                 suffix=${type#\ --} && suffix=${suffix:-apply} &&
108                 if test ${suffix} = "interactive"; then
109                         suffix=merge
110                 fi &&
111                 create_expected_success_$suffix &&
112                 sed "$remove_progress_re" <actual >actual2 &&
113                 test_cmp expected actual2
114         '
115
116         test_expect_success "rebase$type: dirty index, non-conflicting rebase" '
117                 test_config rebase.autostash true &&
118                 git reset --hard &&
119                 git checkout -b rebased-feature-branch feature-branch &&
120                 test_when_finished git branch -D rebased-feature-branch &&
121                 echo dirty >>file3 &&
122                 git add file3 &&
123                 git rebase$type unrelated-onto-branch &&
124                 grep unrelated file4 &&
125                 grep dirty file3 &&
126                 git checkout feature-branch
127         '
128
129         test_expect_success "rebase$type: conflicting rebase" '
130                 test_config rebase.autostash true &&
131                 git reset --hard &&
132                 git checkout -b rebased-feature-branch feature-branch &&
133                 test_when_finished git branch -D rebased-feature-branch &&
134                 echo dirty >>file3 &&
135                 test_must_fail git rebase$type related-onto-branch &&
136                 test_path_is_file $dotest/autostash &&
137                 test_path_is_missing file3 &&
138                 rm -rf $dotest &&
139                 git reset --hard &&
140                 git checkout feature-branch
141         '
142
143         test_expect_success "rebase$type: --continue" '
144                 test_config rebase.autostash true &&
145                 git reset --hard &&
146                 git checkout -b rebased-feature-branch feature-branch &&
147                 test_when_finished git branch -D rebased-feature-branch &&
148                 echo dirty >>file3 &&
149                 test_must_fail git rebase$type related-onto-branch &&
150                 test_path_is_file $dotest/autostash &&
151                 test_path_is_missing file3 &&
152                 echo "conflicting-plus-goodbye" >file2 &&
153                 git add file2 &&
154                 git rebase --continue &&
155                 test_path_is_missing $dotest/autostash &&
156                 grep dirty file3 &&
157                 git checkout feature-branch
158         '
159
160         test_expect_success "rebase$type: --skip" '
161                 test_config rebase.autostash true &&
162                 git reset --hard &&
163                 git checkout -b rebased-feature-branch feature-branch &&
164                 test_when_finished git branch -D rebased-feature-branch &&
165                 echo dirty >>file3 &&
166                 test_must_fail git rebase$type related-onto-branch &&
167                 test_path_is_file $dotest/autostash &&
168                 test_path_is_missing file3 &&
169                 git rebase --skip &&
170                 test_path_is_missing $dotest/autostash &&
171                 grep dirty file3 &&
172                 git checkout feature-branch
173         '
174
175         test_expect_success "rebase$type: --abort" '
176                 test_config rebase.autostash true &&
177                 git reset --hard &&
178                 git checkout -b rebased-feature-branch feature-branch &&
179                 test_when_finished git branch -D rebased-feature-branch &&
180                 echo dirty >>file3 &&
181                 test_must_fail git rebase$type related-onto-branch &&
182                 test_path_is_file $dotest/autostash &&
183                 test_path_is_missing file3 &&
184                 git rebase --abort &&
185                 test_path_is_missing $dotest/autostash &&
186                 grep dirty file3 &&
187                 git checkout feature-branch
188         '
189
190         test_expect_success "rebase$type: --quit" '
191                 test_config rebase.autostash true &&
192                 git reset --hard &&
193                 git checkout -b rebased-feature-branch feature-branch &&
194                 test_when_finished git branch -D rebased-feature-branch &&
195                 echo dirty >>file3 &&
196                 git diff >expect &&
197                 test_must_fail git rebase$type related-onto-branch &&
198                 test_path_is_file $dotest/autostash &&
199                 test_path_is_missing file3 &&
200                 git rebase --quit &&
201                 test_when_finished git stash drop &&
202                 test_path_is_missing $dotest/autostash &&
203                 ! grep dirty file3 &&
204                 git stash show -p >actual &&
205                 test_cmp expect actual &&
206                 git reset --hard &&
207                 git checkout feature-branch
208         '
209
210         test_expect_success "rebase$type: non-conflicting rebase, conflicting stash" '
211                 test_config rebase.autostash true &&
212                 git reset --hard &&
213                 git checkout -b rebased-feature-branch feature-branch &&
214                 echo dirty >file4 &&
215                 git add file4 &&
216                 git rebase$type unrelated-onto-branch >actual 2>&1 &&
217                 test_path_is_missing $dotest &&
218                 git reset --hard &&
219                 grep unrelated file4 &&
220                 ! grep dirty file4 &&
221                 git checkout feature-branch &&
222                 git stash pop &&
223                 grep dirty file4
224         '
225
226         test_expect_success "rebase$type: check output with conflicting stash" '
227                 test_when_finished git branch -D rebased-feature-branch &&
228                 suffix=${type#\ --} && suffix=${suffix:-apply} &&
229                 if test ${suffix} = "interactive"; then
230                         suffix=merge
231                 fi &&
232                 create_expected_failure_$suffix &&
233                 sed "$remove_progress_re" <actual >actual2 &&
234                 test_cmp expected actual2
235         '
236 }
237
238 test_expect_success "rebase: fast-forward rebase" '
239         test_config rebase.autostash true &&
240         git reset --hard &&
241         git checkout -b behind-feature-branch feature-branch~1 &&
242         test_when_finished git branch -D behind-feature-branch &&
243         echo dirty >>file1 &&
244         git rebase feature-branch &&
245         grep dirty file1 &&
246         git checkout feature-branch
247 '
248
249 test_expect_success "rebase: noop rebase" '
250         test_config rebase.autostash true &&
251         git reset --hard &&
252         git checkout -b same-feature-branch feature-branch &&
253         test_when_finished git branch -D same-feature-branch &&
254         echo dirty >>file1 &&
255         git rebase feature-branch &&
256         grep dirty file1 &&
257         git checkout feature-branch
258 '
259
260 testrebase " --apply" .git/rebase-apply
261 testrebase " --merge" .git/rebase-merge
262 testrebase " --interactive" .git/rebase-merge
263
264 test_expect_success 'abort rebase -i with --autostash' '
265         test_when_finished "git reset --hard" &&
266         echo uncommitted-content >file0 &&
267         (
268                 write_script abort-editor.sh <<-\EOF &&
269                         echo >"$1"
270                 EOF
271                 test_set_editor "$(pwd)/abort-editor.sh" &&
272                 test_must_fail git rebase -i --autostash HEAD^ &&
273                 rm -f abort-editor.sh
274         ) &&
275         echo uncommitted-content >expected &&
276         test_cmp expected file0
277 '
278
279 test_expect_success 'restore autostash on editor failure' '
280         test_when_finished "git reset --hard" &&
281         echo uncommitted-content >file0 &&
282         (
283                 test_set_editor "false" &&
284                 test_must_fail git rebase -i --autostash HEAD^
285         ) &&
286         echo uncommitted-content >expected &&
287         test_cmp expected file0
288 '
289
290 test_expect_success 'autostash is saved on editor failure with conflict' '
291         test_when_finished "git reset --hard" &&
292         echo uncommitted-content >file0 &&
293         (
294                 write_script abort-editor.sh <<-\EOF &&
295                         echo conflicting-content >file0
296                         exit 1
297                 EOF
298                 test_set_editor "$(pwd)/abort-editor.sh" &&
299                 test_must_fail git rebase -i --autostash HEAD^ &&
300                 rm -f abort-editor.sh
301         ) &&
302         echo conflicting-content >expected &&
303         test_cmp expected file0 &&
304         git checkout file0 &&
305         git stash pop &&
306         echo uncommitted-content >expected &&
307         test_cmp expected file0
308 '
309
310 test_expect_success 'autostash with dirty submodules' '
311         test_when_finished "git reset --hard && git checkout main" &&
312         git checkout -b with-submodule &&
313         git submodule add ./ sub &&
314         test_tick &&
315         git commit -m add-submodule &&
316         echo changed >sub/file0 &&
317         git rebase -i --autostash HEAD
318 '
319
320 test_expect_success 'branch is left alone when possible' '
321         git checkout -b unchanged-branch &&
322         echo changed >file0 &&
323         git rebase --autostash unchanged-branch &&
324         test changed = "$(cat file0)" &&
325         test unchanged-branch = "$(git rev-parse --abbrev-ref HEAD)"
326 '
327
328 test_expect_success 'never change active branch' '
329         git checkout -b not-the-feature-branch unrelated-onto-branch &&
330         test_when_finished "git reset --hard && git checkout main" &&
331         echo changed >file0 &&
332         git rebase --autostash not-the-feature-branch feature-branch &&
333         test_cmp_rev not-the-feature-branch unrelated-onto-branch
334 '
335
336 test_done