Raw
1 #!/bin/sh
2
3 test_description='tests for git-history reword subcommand'
4
5 . ./test-lib.sh
6 . "$TEST_DIRECTORY/lib-log-graph.sh"
7
8 reword_with_message () {
9 cat >message &&
10 write_script fake-editor.sh <<-\EOF &&
11 cp message "$1"
12 EOF
13 test_set_editor "$(pwd)"/fake-editor.sh &&
14 git history reword "$@" &&
15 rm fake-editor.sh message
16 }
17
18 expect_graph () {
19 cat >expect &&
20 lib_test_cmp_graph --graph --format=%s "$@"
21 }
22
23 expect_log () {
24 git log --format="%s" "$@" >actual &&
25 cat >expect &&
26 test_cmp expect actual
27 }
28
29 test_expect_success 'can reword tip of a branch' '
30 test_when_finished "rm -rf repo" &&
31 git init repo &&
32 (
33 cd repo &&
34 test_commit first &&
35 test_commit second &&
36 test_commit third &&
37
38 git symbolic-ref HEAD >expect &&
39 reword_with_message HEAD <<-EOF &&
40 third reworded
41 EOF
42 git symbolic-ref HEAD >actual &&
43 test_cmp expect actual &&
44
45 expect_log <<-\EOF &&
46 third reworded
47 second
48 first
49 EOF
50
51 git reflog >reflog &&
52 test_grep "reword: updating HEAD" reflog
53 )
54 '
55
56 test_expect_success 'can reword commit in the middle' '
57 test_when_finished "rm -rf repo" &&
58 git init repo &&
59 (
60 cd repo &&
61 test_commit first &&
62 test_commit second &&
63 test_commit third &&
64
65 git symbolic-ref HEAD >expect &&
66 reword_with_message HEAD~ <<-EOF &&
67 second reworded
68 EOF
69 git symbolic-ref HEAD >actual &&
70 test_cmp expect actual &&
71
72 expect_log <<-\EOF
73 third
74 second reworded
75 first
76 EOF
77 )
78 '
79
80 test_expect_success 'can reword commit in the middle even on detached head' '
81 test_when_finished "rm -rf repo" &&
82 git init repo &&
83 (
84 cd repo &&
85 test_commit first &&
86 test_commit second &&
87 test_commit third_on_main &&
88 git checkout --detach HEAD^ &&
89 test_commit third_on_head &&
90
91 reword_with_message HEAD~ <<-EOF &&
92 second reworded
93 EOF
94
95 expect_graph HEAD --branches <<-\EOF
96 * third_on_head
97 | * third_on_main
98 |/
99 * second reworded
100 * first
101 EOF
102 )
103 '
104
105 test_expect_success 'can reword the detached head' '
106 test_when_finished "rm -rf repo" &&
107 git init repo &&
108 (
109 cd repo &&
110 test_commit first &&
111 test_commit second &&
112 git checkout --detach HEAD &&
113 test_commit third &&
114
115 reword_with_message HEAD <<-EOF &&
116 third reworded
117 EOF
118
119 expect_log <<-\EOF
120 third reworded
121 second
122 first
123 EOF
124 )
125 '
126
127 test_expect_success 'can reword root commit' '
128 test_when_finished "rm -rf repo" &&
129 git init repo &&
130 (
131 cd repo &&
132 test_commit first &&
133 test_commit second &&
134 test_commit third &&
135 reword_with_message HEAD~2 <<-EOF &&
136 first reworded
137 EOF
138
139 expect_log <<-\EOF
140 third
141 second
142 first reworded
143 EOF
144 )
145 '
146
147 test_expect_success 'can reword in a bare repo' '
148 test_when_finished "rm -rf repo repo.git" &&
149 git init repo &&
150 test_commit -C repo first &&
151 git clone --bare repo repo.git &&
152 (
153 cd repo.git &&
154 reword_with_message HEAD <<-EOF &&
155 reworded
156 EOF
157
158 expect_log <<-\EOF
159 reworded
160 EOF
161 )
162 '
163
164 test_expect_success 'can reword a commit on a different branch' '
165 test_when_finished "rm -rf repo" &&
166 git init repo &&
167 (
168 cd repo &&
169 test_commit base &&
170 git branch theirs &&
171 test_commit ours &&
172 git switch theirs &&
173 test_commit theirs &&
174
175 git rev-parse ours >ours-before &&
176 reword_with_message theirs <<-EOF &&
177 Reworded theirs
178 EOF
179 git rev-parse ours >ours-after &&
180 test_cmp ours-before ours-after &&
181
182 expect_graph --branches <<-\EOF
183 * Reworded theirs
184 | * ours
185 |/
186 * base
187 EOF
188 )
189 '
190
191 test_expect_success 'can reword a merge commit' '
192 test_when_finished "rm -rf repo" &&
193 git init repo &&
194 (
195 cd repo &&
196 test_commit base &&
197 git branch branch &&
198 test_commit ours &&
199 git switch branch &&
200 test_commit theirs &&
201 git switch - &&
202 git merge theirs &&
203
204 # It is not possible to replay merge commits embedded in the
205 # history (yet).
206 test_must_fail git -c core.editor=false history reword HEAD~ 2>err &&
207 test_grep "replaying merge commits is not supported yet" err &&
208
209 # But it is possible to reword a merge commit directly.
210 reword_with_message HEAD <<-EOF &&
211 Reworded merge commit
212 EOF
213 expect_graph <<-\EOF
214 * Reworded merge commit
215 |\
216 | * theirs
217 * | ours
218 |/
219 * base
220 EOF
221 )
222 '
223
224 test_expect_success '--dry-run prints ref updates without modifying repo' '
225 test_when_finished "rm -rf repo" &&
226 git init repo --initial-branch=main &&
227 (
228 cd repo &&
229 test_commit base &&
230 git branch branch &&
231 test_commit ours &&
232 git switch branch &&
233 test_commit theirs &&
234
235 git refs list >refs-expect &&
236 reword_with_message --dry-run --update-refs=head base >updates <<-\EOF &&
237 reworded commit
238 EOF
239 git refs list >refs-actual &&
240 test_cmp refs-expect refs-actual &&
241 test_grep "update refs/heads/branch" updates &&
242 test_grep ! "update refs/heads/main" updates &&
243
244 reword_with_message --dry-run base >updates <<-\EOF &&
245 reworded commit
246 EOF
247 git refs list >refs-actual &&
248 test_cmp refs-expect refs-actual &&
249
250 test_grep "update refs/heads/branch" updates &&
251 test_grep "update refs/heads/main" updates &&
252 git update-ref --stdin <updates &&
253 expect_log --branches <<-\EOF
254 theirs
255 ours
256 reworded commit
257 EOF
258 )
259 '
260
261 test_expect_success '--update-refs=head updates only HEAD' '
262 test_when_finished "rm -rf repo" &&
263 git init repo --initial-branch=main &&
264 (
265 cd repo &&
266 test_commit base &&
267 git branch branch &&
268 test_commit theirs &&
269 git switch branch &&
270 test_commit ours &&
271
272 # When told to update HEAD, only, the command will refuse to
273 # rewrite commits that are not an ancestor of HEAD.
274 test_must_fail git -c core.editor=false history reword --update-refs=head theirs 2>err &&
275 test_grep "rewritten commit must be an ancestor of HEAD" err &&
276
277 reword_with_message --update-refs=head base >updates <<-\EOF &&
278 reworded base
279 EOF
280 expect_log HEAD <<-\EOF &&
281 ours
282 reworded base
283 EOF
284 expect_log main <<-\EOF
285 theirs
286 base
287 EOF
288 )
289 '
290
291 test_expect_success 'editor shows proper status' '
292 test_when_finished "rm -rf repo" &&
293 git init repo &&
294 (
295 cd repo &&
296 test_commit first &&
297
298 write_script fake-editor.sh <<-\EOF &&
299 cp "$1" . &&
300 printf "\namend a comment\n" >>"$1"
301 EOF
302 test_set_editor "$(pwd)"/fake-editor.sh &&
303 git history reword HEAD &&
304
305 cat >expect <<-EOF &&
306 first
307
308 # Please enter the commit message for the reworded changes. Lines starting
309 # with ${SQ}#${SQ} will be ignored, and an empty message aborts the commit.
310 # Changes to be committed:
311 # new file: first.t
312 #
313 EOF
314 test_cmp expect COMMIT_EDITMSG &&
315
316 test_commit_message HEAD <<-\EOF
317 first
318
319 amend a comment
320 EOF
321 )
322 '
323
324 # For now, git-history(1) does not yet execute any hooks. This is subject to
325 # change in the future, and if it does this test here is expected to start
326 # failing. In other words, this test is not an endorsement of the current
327 # status quo.
328 test_expect_success 'hooks are not executed for rewritten commits' '
329 test_when_finished "rm -rf repo" &&
330 git init repo &&
331 (
332 cd repo &&
333 test_commit first &&
334 test_commit second &&
335 test_commit third &&
336
337 ORIG_PATH="$(pwd)" &&
338 export ORIG_PATH &&
339 for hook in prepare-commit-msg pre-commit post-commit post-rewrite commit-msg
340 do
341 write_script .git/hooks/$hook <<-\EOF || exit 1
342 touch "$ORIG_PATH/hooks.log
343 EOF
344 done &&
345
346 reword_with_message HEAD~ <<-EOF &&
347 second reworded
348 EOF
349
350 cat >expect <<-EOF &&
351 third
352 second reworded
353 first
354 EOF
355 git log --format=%s >actual &&
356 test_cmp expect actual &&
357
358 test_path_is_missing hooks.log
359 )
360 '
361
362 test_expect_success 'aborts with empty commit message' '
363 test_when_finished "rm -rf repo" &&
364 git init repo &&
365 (
366 cd repo &&
367 test_commit first &&
368
369 ! reword_with_message HEAD 2>err </dev/null &&
370 test_grep "Aborting commit due to empty commit message." err
371 )
372 '
373
374 test_expect_success 'retains changes in the worktree and index' '
375 test_when_finished "rm -rf repo" &&
376 git init repo &&
377 (
378 cd repo &&
379 touch a b &&
380 git add . &&
381 git commit -m "initial commit" &&
382 echo foo >a &&
383 echo bar >b &&
384 git add b &&
385 reword_with_message HEAD <<-EOF &&
386 message
387 EOF
388 cat >expect <<-\EOF &&
389 M a
390 M b
391 ?? actual
392 ?? expect
393 EOF
394 git status --porcelain >actual &&
395 test_cmp expect actual
396 )
397 '
398
399 test_done