3 test_description
='Test cherry-pick continuation features
5 + conflicting: rewrites unrelated to conflicting
6 + yetanotherpick: rewrites foo to e
7 + anotherpick: rewrites foo to d
8 + picked: rewrites foo to c
9 + unrelatedpick: rewrites unrelated to reallyunrelated
10 + base: rewrites foo to b
11 + initial: writes foo as a, unrelated as unrelated
17 # Repeat first match 10 times
18 _r10
='\1\1\1\1\1\1\1\1\1\1'
21 git cherry-pick
--quit &&
22 git checkout
-f "$1^0" &&
23 git read-tree
-u --reset HEAD
&&
24 git clean
-d -f -f -q -x
27 test_expect_success setup
'
28 git config advice.detachedhead false &&
29 echo unrelated >unrelated &&
31 test_commit initial foo a &&
32 test_commit base foo b &&
33 test_commit unrelatedpick unrelated reallyunrelated &&
34 test_commit picked foo c &&
35 test_commit anotherpick foo d &&
36 test_commit yetanotherpick foo e &&
37 pristine_detach initial &&
38 test_commit conflicting unrelated
41 test_expect_success
'cherry-pick persists data on failure' '
42 pristine_detach initial &&
43 test_expect_code 1 git cherry-pick -s base..anotherpick &&
44 test_path_is_dir .git/sequencer &&
45 test_path_is_file .git/sequencer/head &&
46 test_path_is_file .git/sequencer/todo &&
47 test_path_is_file .git/sequencer/opts
50 test_expect_success
'cherry-pick mid-cherry-pick-sequence' '
51 pristine_detach initial &&
52 test_must_fail git cherry-pick base..anotherpick &&
53 test_cmp_rev picked CHERRY_PICK_HEAD &&
54 # "oops, I forgot that these patches rely on the change from base"
55 git checkout HEAD foo &&
56 git cherry-pick base &&
57 git cherry-pick picked &&
58 git cherry-pick --continue &&
59 git diff --exit-code anotherpick
62 test_expect_success
'cherry-pick persists opts correctly' '
63 pristine_detach initial &&
64 # to make sure that the session to cherry-pick a sequence
65 # gets interrupted, use a high-enough number that is larger
66 # than the number of parents of any commit we have created
68 test_expect_code 128 git cherry-pick -s -m $mainline --strategy=recursive -X patience -X ours --edit initial..anotherpick &&
69 test_path_is_dir .git/sequencer &&
70 test_path_is_file .git/sequencer/head &&
71 test_path_is_file .git/sequencer/todo &&
72 test_path_is_file .git/sequencer/opts &&
73 echo "true" >expect &&
74 git config --file=.git/sequencer/opts --get-all options.signoff >actual &&
75 test_cmp expect actual &&
76 echo "$mainline" >expect &&
77 git config --file=.git/sequencer/opts --get-all options.mainline >actual &&
78 test_cmp expect actual &&
79 echo "recursive" >expect &&
80 git config --file=.git/sequencer/opts --get-all options.strategy >actual &&
81 test_cmp expect actual &&
82 cat >expect <<-\EOF &&
86 git config --file=.git/sequencer/opts --get-all options.strategy-option >actual &&
87 test_cmp expect actual &&
88 echo "true" >expect &&
89 git config --file=.git/sequencer/opts --get-all options.edit >actual &&
90 test_cmp expect actual
93 test_expect_success
'cherry-pick persists --empty=stop correctly' '
94 pristine_detach yetanotherpick &&
95 # Picking `anotherpick` forces a conflict so that we stop. That
96 # commit is then skipped, after which we pick `yetanotherpick`
97 # while already on `yetanotherpick` to cause an empty commit
98 test_must_fail git cherry-pick --empty=stop anotherpick yetanotherpick &&
99 test_must_fail git cherry-pick --skip 2>msg &&
100 test_grep "The previous cherry-pick is now empty" msg &&
102 git cherry-pick --abort
105 test_expect_success
'cherry-pick persists --empty=drop correctly' '
106 pristine_detach yetanotherpick &&
107 # Picking `anotherpick` forces a conflict so that we stop. That
108 # commit is then skipped, after which we pick `yetanotherpick`
109 # while already on `yetanotherpick` to cause an empty commit
110 test_must_fail git cherry-pick --empty=drop anotherpick yetanotherpick &&
111 git cherry-pick --skip &&
112 test_cmp_rev yetanotherpick HEAD
115 test_expect_success
'cherry-pick persists --empty=keep correctly' '
116 pristine_detach yetanotherpick &&
117 # Picking `anotherpick` forces a conflict so that we stop. That
118 # commit is then skipped, after which we pick `yetanotherpick`
119 # while already on `yetanotherpick` to cause an empty commit
120 test_must_fail git cherry-pick --empty=keep anotherpick yetanotherpick &&
121 git cherry-pick --skip &&
122 test_cmp_rev yetanotherpick HEAD^
125 test_expect_success
'revert persists opts correctly' '
126 pristine_detach initial &&
127 # to make sure that the session to revert a sequence
128 # gets interrupted, revert commits that are not in the history
130 test_expect_code 1 git revert -s --strategy=recursive -X patience -X ours --no-edit picked yetanotherpick &&
131 test_path_is_dir .git/sequencer &&
132 test_path_is_file .git/sequencer/head &&
133 test_path_is_file .git/sequencer/todo &&
134 test_path_is_file .git/sequencer/opts &&
135 echo "true" >expect &&
136 git config --file=.git/sequencer/opts --get-all options.signoff >actual &&
137 test_cmp expect actual &&
138 echo "recursive" >expect &&
139 git config --file=.git/sequencer/opts --get-all options.strategy >actual &&
140 test_cmp expect actual &&
141 cat >expect <<-\EOF &&
145 git config --file=.git/sequencer/opts --get-all options.strategy-option >actual &&
146 test_cmp expect actual &&
147 echo "false" >expect &&
148 git config --file=.git/sequencer/opts --get-all options.edit >actual &&
149 test_cmp expect actual
152 test_expect_success
'cherry-pick cleans up sequencer state upon success' '
153 pristine_detach initial &&
154 git cherry-pick initial..picked &&
155 test_path_is_missing .git/sequencer
158 test_expect_success
'cherry-pick --skip requires cherry-pick in progress' '
159 pristine_detach initial &&
160 test_must_fail git cherry-pick --skip
163 test_expect_success
'revert --skip requires revert in progress' '
164 pristine_detach initial &&
165 test_must_fail git revert --skip
168 test_expect_success
'cherry-pick --skip to skip commit' '
169 pristine_detach initial &&
170 test_must_fail git cherry-pick anotherpick &&
171 test_must_fail git revert --skip &&
172 git cherry-pick --skip &&
173 test_cmp_rev initial HEAD &&
174 test_path_is_missing .git/CHERRY_PICK_HEAD
177 test_expect_success
'revert --skip to skip commit' '
178 pristine_detach anotherpick &&
179 test_must_fail git revert anotherpick~1 &&
180 test_must_fail git cherry-pick --skip &&
182 test_cmp_rev anotherpick HEAD
185 test_expect_success
'skip "empty" commit' '
186 pristine_detach picked &&
187 test_commit dummy foo d &&
188 test_must_fail git cherry-pick anotherpick 2>err &&
189 test_grep "git cherry-pick --skip" err &&
190 git cherry-pick --skip &&
191 test_cmp_rev dummy HEAD
194 test_expect_success
'skip a commit and check if rest of sequence is correct' '
195 pristine_detach initial &&
197 cat >expect.log <<-EOF &&
199 :100644 100644 OBJID OBJID M foo
201 :100644 100644 OBJID OBJID M foo
203 :100644 100644 OBJID OBJID M unrelated
205 :000000 100644 OBJID OBJID A foo
206 :000000 100644 OBJID OBJID A unrelated
208 test_must_fail git cherry-pick base..yetanotherpick &&
209 test_must_fail git cherry-pick --skip &&
212 git cherry-pick --continue &&
215 git diff-tree --root --stdin |
216 sed "s/$OID_REGEX/OBJID/g"
218 test_cmp expect foo &&
219 test_cmp expect.log actual.log
222 test_expect_success
'check advice when we move HEAD by committing' '
223 pristine_detach initial &&
224 cat >expect <<-EOF &&
225 error: there is nothing to skip
226 hint: have you committed already?
227 hint: try "git cherry-pick --continue"
228 fatal: cherry-pick failed
230 test_must_fail git cherry-pick base..yetanotherpick &&
233 test_path_is_missing .git/CHERRY_PICK_HEAD &&
234 test_must_fail git cherry-pick --skip 2>advice &&
235 test_cmp expect advice
238 test_expect_success
'selectively advise --skip while launching another sequence' '
239 pristine_detach initial &&
240 cat >expect <<-EOF &&
241 error: cherry-pick is already in progress
242 hint: try "git cherry-pick (--continue | --skip | --abort | --quit)"
243 fatal: cherry-pick failed
245 test_must_fail git cherry-pick picked..yetanotherpick &&
246 test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
247 test_cmp expect advice &&
248 cat >expect <<-EOF &&
249 error: cherry-pick is already in progress
250 hint: try "git cherry-pick (--continue | --abort | --quit)"
251 fatal: cherry-pick failed
254 test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
255 test_cmp expect advice
258 test_expect_success
'allow skipping commit but not abort for a new history' '
259 pristine_detach initial &&
260 cat >expect <<-EOF &&
261 error: cannot abort from a branch yet to be born
262 fatal: cherry-pick failed
264 git checkout --orphan new_disconnected &&
266 test_must_fail git cherry-pick anotherpick &&
267 test_must_fail git cherry-pick --abort 2>advice &&
268 git cherry-pick --skip &&
269 test_cmp expect advice
272 test_expect_success
'allow skipping stopped cherry-pick because of untracked file modifications' '
273 test_when_finished "rm unrelated" &&
274 pristine_detach initial &&
275 git rm --cached unrelated &&
276 git commit -m "untrack unrelated" &&
277 test_must_fail git cherry-pick initial base &&
278 test_path_is_missing .git/CHERRY_PICK_HEAD &&
279 git cherry-pick --skip
282 test_expect_success
'--quit does not complain when no cherry-pick is in progress' '
283 pristine_detach initial &&
284 git cherry-pick --quit
287 test_expect_success
'--abort requires cherry-pick in progress' '
288 pristine_detach initial &&
289 test_must_fail git cherry-pick --abort
292 test_expect_success
'--quit cleans up sequencer state' '
293 pristine_detach initial &&
294 test_expect_code 1 git cherry-pick base..picked &&
295 git cherry-pick --quit &&
296 test_path_is_missing .git/sequencer &&
297 test_path_is_missing .git/CHERRY_PICK_HEAD
300 test_expect_success
'--quit keeps HEAD and conflicted index intact' '
301 pristine_detach initial &&
302 cat >expect <<-\EOF &&
304 :100644 100644 OBJID OBJID M unrelated
306 :000000 100644 OBJID OBJID A foo
307 :000000 100644 OBJID OBJID A unrelated
309 test_expect_code 1 git cherry-pick base..picked &&
310 git cherry-pick --quit &&
311 test_path_is_missing .git/sequencer &&
312 test_must_fail git update-index --refresh &&
315 git diff-tree --root --stdin |
316 sed "s/$OID_REGEX/OBJID/g"
318 test_cmp expect actual
321 test_expect_success
'--abort to cancel multiple cherry-pick' '
322 pristine_detach initial &&
323 test_expect_code 1 git cherry-pick base..anotherpick &&
324 git cherry-pick --abort &&
325 test_path_is_missing .git/sequencer &&
326 test_path_is_missing .git/CHERRY_PICK_HEAD &&
327 test_cmp_rev initial HEAD &&
328 git update-index --refresh &&
329 git diff-index --exit-code HEAD
332 test_expect_success
'--abort to cancel single cherry-pick' '
333 pristine_detach initial &&
334 test_expect_code 1 git cherry-pick picked &&
335 git cherry-pick --abort &&
336 test_path_is_missing .git/sequencer &&
337 test_path_is_missing .git/CHERRY_PICK_HEAD &&
338 test_cmp_rev initial HEAD &&
339 git update-index --refresh &&
340 git diff-index --exit-code HEAD
343 test_expect_success
'--abort does not unsafely change HEAD' '
344 pristine_detach initial &&
345 test_must_fail git cherry-pick picked anotherpick &&
346 git reset --hard base &&
347 test_must_fail git cherry-pick picked anotherpick &&
348 git cherry-pick --abort 2>actual &&
349 test_grep "You seem to have moved HEAD" actual &&
350 test_cmp_rev base HEAD
353 test_expect_success
'cherry-pick --abort to cancel multiple revert' '
354 pristine_detach anotherpick &&
355 test_expect_code 1 git revert base..picked &&
356 git cherry-pick --abort &&
357 test_path_is_missing .git/sequencer &&
358 test_path_is_missing .git/CHERRY_PICK_HEAD &&
359 test_cmp_rev anotherpick HEAD &&
360 git update-index --refresh &&
361 git diff-index --exit-code HEAD
364 test_expect_success
'revert --abort works, too' '
365 pristine_detach anotherpick &&
366 test_expect_code 1 git revert base..picked &&
367 git revert --abort &&
368 test_path_is_missing .git/sequencer &&
369 test_cmp_rev anotherpick HEAD
372 test_expect_success
'--abort to cancel single revert' '
373 pristine_detach anotherpick &&
374 test_expect_code 1 git revert picked &&
375 git revert --abort &&
376 test_path_is_missing .git/sequencer &&
377 test_cmp_rev anotherpick HEAD &&
378 git update-index --refresh &&
379 git diff-index --exit-code HEAD
382 test_expect_success
'--abort keeps unrelated change, easy case' '
383 pristine_detach unrelatedpick &&
384 echo changed >expect &&
385 test_expect_code 1 git cherry-pick picked..yetanotherpick &&
386 echo changed >unrelated &&
387 git cherry-pick --abort &&
388 test_cmp expect unrelated
391 test_expect_success
'--abort refuses to clobber unrelated change, harder case' '
392 pristine_detach initial &&
393 echo changed >expect &&
394 test_expect_code 1 git cherry-pick base..anotherpick &&
395 echo changed >unrelated &&
396 test_must_fail git cherry-pick --abort &&
397 test_cmp expect unrelated &&
398 git rev-list HEAD >log &&
399 test_line_count = 2 log &&
400 test_must_fail git update-index --refresh &&
402 git checkout unrelated &&
403 git cherry-pick --abort &&
404 test_cmp_rev initial HEAD
407 test_expect_success
'cherry-pick still writes sequencer state when one commit is left' '
408 pristine_detach initial &&
409 test_expect_code 1 git cherry-pick base..picked &&
410 test_path_is_dir .git/sequencer &&
411 echo "resolved" >foo &&
416 git diff-tree --root --stdin |
417 sed "s/$OID_REGEX/OBJID/g"
419 cat >expect <<-\EOF &&
421 :100644 100644 OBJID OBJID M foo
423 :100644 100644 OBJID OBJID M unrelated
425 :000000 100644 OBJID OBJID A foo
426 :000000 100644 OBJID OBJID A unrelated
428 test_cmp expect actual
431 test_expect_success
'--abort after last commit in sequence' '
432 pristine_detach initial &&
433 test_expect_code 1 git cherry-pick base..picked &&
434 git cherry-pick --abort &&
435 test_path_is_missing .git/sequencer &&
436 test_path_is_missing .git/CHERRY_PICK_HEAD &&
437 test_cmp_rev initial HEAD &&
438 git update-index --refresh &&
439 git diff-index --exit-code HEAD
442 test_expect_success
'cherry-pick does not implicitly stomp an existing operation' '
443 pristine_detach initial &&
444 test_expect_code 1 git cherry-pick base..anotherpick &&
445 test-tool chmtime --get .git/sequencer >expect &&
446 test_expect_code 128 git cherry-pick unrelatedpick &&
447 test-tool chmtime --get .git/sequencer >actual &&
448 test_cmp expect actual
451 test_expect_success
'--continue complains when no cherry-pick is in progress' '
452 pristine_detach initial &&
453 test_expect_code 128 git cherry-pick --continue
456 test_expect_success
'--continue complains when there are unresolved conflicts' '
457 pristine_detach initial &&
458 test_expect_code 1 git cherry-pick base..anotherpick &&
459 test_expect_code 128 git cherry-pick --continue
462 test_expect_success
'--continue of single cherry-pick' '
463 pristine_detach initial &&
465 test_must_fail git cherry-pick picked &&
468 git cherry-pick --continue &&
470 test_cmp expect foo &&
471 test_cmp_rev initial HEAD^ &&
472 git diff --exit-code HEAD &&
473 test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
476 test_expect_success
'--continue of single revert' '
477 pristine_detach initial &&
478 echo resolved >expect &&
479 echo "Revert \"picked\"" >expect.msg &&
480 test_must_fail git revert picked &&
481 echo resolved >foo &&
483 git cherry-pick --continue &&
485 git diff --exit-code HEAD &&
486 test_cmp expect foo &&
487 test_cmp_rev initial HEAD^ &&
488 git diff-tree -s --pretty=tformat:%s HEAD >msg &&
489 test_cmp expect.msg msg &&
490 test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
491 test_must_fail git rev-parse --verify REVERT_HEAD
494 test_expect_success
'--continue after resolving conflicts' '
495 pristine_detach initial &&
497 cat >expect.log <<-\EOF &&
499 :100644 100644 OBJID OBJID M foo
501 :100644 100644 OBJID OBJID M foo
503 :100644 100644 OBJID OBJID M unrelated
505 :000000 100644 OBJID OBJID A foo
506 :000000 100644 OBJID OBJID A unrelated
508 test_must_fail git cherry-pick base..anotherpick &&
511 git cherry-pick --continue &&
514 git diff-tree --root --stdin |
515 sed "s/$OID_REGEX/OBJID/g"
517 test_cmp expect foo &&
518 test_cmp expect.log actual.log
521 test_expect_success
'--continue after resolving conflicts and committing' '
522 pristine_detach initial &&
523 test_expect_code 1 git cherry-pick base..anotherpick &&
527 git cherry-pick --continue &&
528 test_path_is_missing .git/sequencer &&
531 git diff-tree --root --stdin |
532 sed "s/$OID_REGEX/OBJID/g"
534 cat >expect <<-\EOF &&
536 :100644 100644 OBJID OBJID M foo
538 :100644 100644 OBJID OBJID M foo
540 :100644 100644 OBJID OBJID M unrelated
542 :000000 100644 OBJID OBJID A foo
543 :000000 100644 OBJID OBJID A unrelated
545 test_cmp expect actual
548 test_expect_success
'--continue asks for help after resolving patch to nil' '
549 pristine_detach conflicting &&
550 test_must_fail git cherry-pick initial..picked &&
552 test_cmp_rev unrelatedpick CHERRY_PICK_HEAD &&
553 git checkout HEAD -- unrelated &&
554 test_must_fail git cherry-pick --continue 2>msg &&
555 test_grep "The previous cherry-pick is now empty" msg
558 test_expect_success
'follow advice and skip nil patch' '
559 pristine_detach conflicting &&
560 test_must_fail git cherry-pick initial..picked &&
562 git checkout HEAD -- unrelated &&
563 test_must_fail git cherry-pick --continue &&
565 git cherry-pick --continue &&
567 git rev-list initial..HEAD >commits &&
568 test_line_count = 3 commits
571 test_expect_success
'--continue respects opts' '
572 pristine_detach initial &&
573 test_expect_code 1 git cherry-pick -x base..anotherpick &&
577 git cherry-pick --continue &&
578 test_path_is_missing .git/sequencer &&
579 git cat-file commit HEAD >anotherpick_msg &&
580 git cat-file commit HEAD~1 >picked_msg &&
581 git cat-file commit HEAD~2 >unrelatedpick_msg &&
582 git cat-file commit HEAD~3 >initial_msg &&
583 ! grep "cherry picked from" initial_msg &&
584 grep "cherry picked from" unrelatedpick_msg &&
585 grep "cherry picked from" picked_msg &&
586 grep "cherry picked from" anotherpick_msg
589 test_expect_success
'--continue of single-pick respects -x' '
590 pristine_detach initial &&
591 test_must_fail git cherry-pick -x picked &&
594 git cherry-pick --continue &&
595 test_path_is_missing .git/sequencer &&
596 git cat-file commit HEAD >msg &&
597 grep "cherry picked from" msg
600 test_expect_success
'--continue respects -x in first commit in multi-pick' '
601 pristine_detach initial &&
602 test_must_fail git cherry-pick -x picked anotherpick &&
605 git cherry-pick --continue &&
606 test_path_is_missing .git/sequencer &&
607 git cat-file commit HEAD^ >msg &&
608 picked=$(git rev-parse --verify picked) &&
609 grep "cherry picked from.*$picked" msg
612 test_expect_failure
'--signoff is automatically propagated to resolved conflict' '
613 pristine_detach initial &&
614 test_expect_code 1 git cherry-pick --signoff base..anotherpick &&
618 git cherry-pick --continue &&
619 test_path_is_missing .git/sequencer &&
620 git cat-file commit HEAD >anotherpick_msg &&
621 git cat-file commit HEAD~1 >picked_msg &&
622 git cat-file commit HEAD~2 >unrelatedpick_msg &&
623 git cat-file commit HEAD~3 >initial_msg &&
624 ! grep "Signed-off-by:" initial_msg &&
625 grep "Signed-off-by:" unrelatedpick_msg &&
626 ! grep "Signed-off-by:" picked_msg &&
627 grep "Signed-off-by:" anotherpick_msg
630 test_expect_failure
'--signoff dropped for implicit commit of resolution, multi-pick case' '
631 pristine_detach initial &&
632 test_must_fail git cherry-pick -s picked anotherpick &&
635 git cherry-pick --continue &&
637 git diff --exit-code HEAD &&
638 test_cmp_rev initial HEAD^^ &&
639 git cat-file commit HEAD^ >msg &&
640 ! grep Signed-off-by: msg
643 test_expect_failure
'sign-off needs to be reaffirmed after conflict resolution, single-pick case' '
644 pristine_detach initial &&
645 test_must_fail git cherry-pick -s picked &&
648 git cherry-pick --continue &&
650 git diff --exit-code HEAD &&
651 test_cmp_rev initial HEAD^ &&
652 git cat-file commit HEAD >msg &&
653 ! grep Signed-off-by: msg
656 test_expect_success
'malformed instruction sheet 1' '
657 pristine_detach initial &&
658 test_expect_code 1 git cherry-pick base..anotherpick &&
659 echo "resolved" >foo &&
662 sed "s/pick /pick/" .git/sequencer/todo >new_sheet &&
663 cp new_sheet .git/sequencer/todo &&
664 test_expect_code 128 git cherry-pick --continue
667 test_expect_success
'malformed instruction sheet 2' '
668 pristine_detach initial &&
669 test_expect_code 1 git cherry-pick base..anotherpick &&
670 echo "resolved" >foo &&
673 sed "s/pick/revert/" .git/sequencer/todo >new_sheet &&
674 cp new_sheet .git/sequencer/todo &&
675 test_expect_code 128 git cherry-pick --continue
678 test_expect_success
'empty commit set (no commits to walk)' '
679 pristine_detach initial &&
680 test_expect_code 128 git cherry-pick base..base
683 test_expect_success
'empty commit set (culled during walk)' '
684 pristine_detach initial &&
685 test_expect_code 128 git cherry-pick -2 --author=no.such.author base
688 test_expect_success
'malformed instruction sheet 3' '
689 pristine_detach initial &&
690 test_expect_code 1 git cherry-pick base..anotherpick &&
691 echo "resolved" >foo &&
694 sed "s/pick \([0-9a-f]*\)/pick $_r10/" .git/sequencer/todo >new_sheet &&
695 cp new_sheet .git/sequencer/todo &&
696 test_expect_code 128 git cherry-pick --continue
699 test_expect_success
'instruction sheet, fat-fingers version' '
700 pristine_detach initial &&
701 test_expect_code 1 git cherry-pick base..anotherpick &&
705 sed "s/pick \([0-9a-f]*\)/pick \1 /" .git/sequencer/todo >new_sheet &&
706 cp new_sheet .git/sequencer/todo &&
707 git cherry-pick --continue
710 test_expect_success
'commit descriptions in insn sheet are optional' '
711 pristine_detach initial &&
712 test_expect_code 1 git cherry-pick base..anotherpick &&
716 cut -d" " -f1,2 .git/sequencer/todo >new_sheet &&
717 cp new_sheet .git/sequencer/todo &&
718 git cherry-pick --continue &&
719 test_path_is_missing .git/sequencer &&
720 git rev-list HEAD >commits &&
721 test_line_count = 4 commits