3 test_description
='Test automatic use of a pager.'
5 TEST_PASSES_SANITIZE_LEAK
=true
7 .
"$TEST_DIRECTORY"/lib-pager.sh
8 .
"$TEST_DIRECTORY"/lib-terminal.sh
10 test_expect_success
'setup' '
11 sane_unset GIT_PAGER GIT_PAGER_IN_USE &&
12 test_unconfig core.pager &&
14 PAGER="cat >paginated.out" &&
20 test_expect_success TTY
'some commands use a pager' '
21 rm -f paginated.out &&
22 test_terminal git log &&
23 test_path_is_file paginated.out
26 test_expect_failure TTY
'pager runs from subdir' '
27 echo subdir/paginated.out >expected &&
29 rm -f paginated.out subdir/paginated.out &&
35 ls paginated.out subdir/paginated.out ||
38 test_cmp expected actual
41 test_expect_success TTY
'LESS and LV envvars are set for pagination' '
44 PAGER="env >pager-env.out; wc" &&
49 grep ^LESS= pager-env.out &&
50 grep ^LV= pager-env.out
53 test_expect_success
!MINGW
,TTY
'LESS and LV envvars set by git-sh-setup' '
56 PAGER="env >pager-env.out; wc" &&
58 PATH="$(git --exec-path):$PATH" &&
60 test_terminal sh -c ". git-sh-setup && git_pager"
62 grep ^LESS= pager-env.out &&
63 grep ^LV= pager-env.out
66 test_expect_success TTY
'some commands do not use a pager' '
67 rm -f paginated.out &&
68 test_terminal git rev-list HEAD &&
69 test_path_is_missing paginated.out
72 test_expect_success
'no pager when stdout is a pipe' '
73 rm -f paginated.out &&
75 test_path_is_missing paginated.out
78 test_expect_success
'no pager when stdout is a regular file' '
79 rm -f paginated.out &&
81 test_path_is_missing paginated.out
84 test_expect_success TTY
'git --paginate rev-list uses a pager' '
85 rm -f paginated.out &&
86 test_terminal git --paginate rev-list HEAD &&
87 test_path_is_file paginated.out
90 test_expect_success
'no pager even with --paginate when stdout is a pipe' '
91 rm -f file paginated.out &&
92 git --paginate log | cat &&
93 test_path_is_missing paginated.out
96 test_expect_success TTY
'no pager with --no-pager' '
97 rm -f paginated.out &&
98 test_terminal git --no-pager log &&
99 test_path_is_missing paginated.out
102 test_expect_success TTY
'configuration can disable pager' '
103 rm -f paginated.out &&
104 test_unconfig pager.grep &&
105 test_terminal git grep initial &&
106 test_path_is_file paginated.out &&
108 rm -f paginated.out &&
109 test_config pager.grep false &&
110 test_terminal git grep initial &&
111 test_path_is_missing paginated.out
114 test_expect_success TTY
'configuration can enable pager (from subdir)' '
115 rm -f paginated.out &&
117 test_config pager.bundle true &&
119 git bundle create test.bundle --all &&
120 rm -f paginated.out subdir/paginated.out &&
123 test_terminal git bundle unbundle ../test.bundle
126 test_path_is_file paginated.out ||
127 test_path_is_file subdir/paginated.out
131 test_expect_success TTY
'git tag -l defaults to paging' '
132 rm -f paginated.out &&
133 test_terminal git tag -l &&
134 test_path_is_file paginated.out
137 test_expect_success TTY
'git tag -l respects pager.tag' '
138 rm -f paginated.out &&
139 test_terminal git -c pager.tag=false tag -l &&
140 test_path_is_missing paginated.out
143 test_expect_success TTY
'git tag -l respects --no-pager' '
144 rm -f paginated.out &&
145 test_terminal git -c pager.tag --no-pager tag -l &&
146 test_path_is_missing paginated.out
149 test_expect_success TTY
'git tag with no args defaults to paging' '
150 # no args implies -l so this should page like -l
151 rm -f paginated.out &&
152 test_terminal git tag &&
153 test_path_is_file paginated.out
156 test_expect_success TTY
'git tag with no args respects pager.tag' '
157 # no args implies -l so this should page like -l
158 rm -f paginated.out &&
159 test_terminal git -c pager.tag=false tag &&
160 test_path_is_missing paginated.out
163 test_expect_success TTY
'git tag --contains defaults to paging' '
164 # --contains implies -l so this should page like -l
165 rm -f paginated.out &&
166 test_terminal git tag --contains &&
167 test_path_is_file paginated.out
170 test_expect_success TTY
'git tag --contains respects pager.tag' '
171 # --contains implies -l so this should page like -l
172 rm -f paginated.out &&
173 test_terminal git -c pager.tag=false tag --contains &&
174 test_path_is_missing paginated.out
177 test_expect_success TTY
'git tag -a defaults to not paging' '
178 test_when_finished "git tag -d newtag" &&
179 rm -f paginated.out &&
180 test_terminal git tag -am message newtag &&
181 test_path_is_missing paginated.out
184 test_expect_success TTY
'git tag -a ignores pager.tag' '
185 test_when_finished "git tag -d newtag" &&
186 rm -f paginated.out &&
187 test_terminal git -c pager.tag tag -am message newtag &&
188 test_path_is_missing paginated.out
191 test_expect_success TTY
'git tag -a respects --paginate' '
192 test_when_finished "git tag -d newtag" &&
193 rm -f paginated.out &&
194 test_terminal git --paginate tag -am message newtag &&
195 test_path_is_file paginated.out
198 test_expect_success TTY
'git tag as alias ignores pager.tag with -a' '
199 test_when_finished "git tag -d newtag" &&
200 rm -f paginated.out &&
201 test_terminal git -c pager.tag -c alias.t=tag t -am message newtag &&
202 test_path_is_missing paginated.out
205 test_expect_success TTY
'git tag as alias respects pager.tag with -l' '
206 rm -f paginated.out &&
207 test_terminal git -c pager.tag=false -c alias.t=tag t -l &&
208 test_path_is_missing paginated.out
211 test_expect_success TTY
'git branch defaults to paging' '
212 rm -f paginated.out &&
213 test_terminal git branch &&
214 test_path_is_file paginated.out
217 test_expect_success TTY
'git branch respects pager.branch' '
218 rm -f paginated.out &&
219 test_terminal git -c pager.branch=false branch &&
220 test_path_is_missing paginated.out
223 test_expect_success TTY
'git branch respects --no-pager' '
224 rm -f paginated.out &&
225 test_terminal git --no-pager branch &&
226 test_path_is_missing paginated.out
229 test_expect_success TTY
'git branch --edit-description ignores pager.branch' '
230 rm -f paginated.out editor.used &&
231 write_script editor <<-\EOF &&
232 echo "New description" >"$1"
235 EDITOR=./editor test_terminal git -c pager.branch branch --edit-description &&
236 test_path_is_missing paginated.out &&
237 test_path_is_file editor.used
240 test_expect_success TTY
'git branch --set-upstream-to ignores pager.branch' '
241 rm -f paginated.out &&
243 test_when_finished "git branch -D other" &&
244 test_terminal git -c pager.branch branch --set-upstream-to=other &&
245 test_when_finished "git branch --unset-upstream" &&
246 test_path_is_missing paginated.out
249 test_expect_success TTY
'git config ignores pager.config when setting' '
250 rm -f paginated.out &&
251 test_terminal git -c pager.config config foo.bar bar &&
252 test_path_is_missing paginated.out
255 test_expect_success TTY
'git config --edit ignores pager.config' '
256 rm -f paginated.out editor.used &&
257 write_script editor <<-\EOF &&
260 EDITOR=./editor test_terminal git -c pager.config config --edit &&
261 test_path_is_missing paginated.out &&
262 test_path_is_file editor.used
265 test_expect_success TTY
'git config --get ignores pager.config' '
266 rm -f paginated.out &&
267 test_terminal git -c pager.config config --get foo.bar &&
268 test_path_is_missing paginated.out
271 test_expect_success TTY
'git config --get-urlmatch defaults to paging' '
272 rm -f paginated.out &&
273 test_terminal git -c http."https://foo.com/".bar=foo \
274 config --get-urlmatch http https://foo.com &&
275 test_path_is_file paginated.out
278 test_expect_success TTY
'git config --get-all respects pager.config' '
279 rm -f paginated.out &&
280 test_terminal git -c pager.config=false config --get-all foo.bar &&
281 test_path_is_missing paginated.out
284 test_expect_success TTY
'git config --list defaults to paging' '
285 rm -f paginated.out &&
286 test_terminal git config --list &&
287 test_path_is_file paginated.out
291 # A colored commit log will begin with an appropriate ANSI escape
292 # for the first color; the text "commit" comes later.
295 ! expr "$firstline" : "[a-zA-Z]" >/dev
/null
298 test_expect_success
'tests can detect color' '
299 rm -f colorful.log colorless.log &&
300 git log --no-color >colorless.log &&
301 git log --color >colorful.log &&
302 ! colorful colorless.log &&
303 colorful colorful.log
306 test_expect_success
'no color when stdout is a regular file' '
307 rm -f colorless.log &&
308 test_config color.ui auto &&
309 git log >colorless.log &&
310 ! colorful colorless.log
313 test_expect_success TTY
'color when writing to a pager' '
314 rm -f paginated.out &&
315 test_config color.ui auto &&
316 test_terminal git log &&
317 colorful paginated.out
320 test_expect_success TTY
'colors are suppressed by color.pager' '
321 rm -f paginated.out &&
322 test_config color.ui auto &&
323 test_config color.pager false &&
324 test_terminal git log &&
325 ! colorful paginated.out
328 test_expect_success
'color when writing to a file intended for a pager' '
329 rm -f colorful.log &&
330 test_config color.ui auto &&
333 GIT_PAGER_IN_USE=true &&
334 export TERM GIT_PAGER_IN_USE &&
335 git log >colorful.log
337 colorful colorful.log
340 test_expect_success TTY
'colors are sent to pager for external commands' '
341 test_config alias.externallog "!git log" &&
342 test_config color.ui auto &&
343 test_terminal git -p externallog &&
344 colorful paginated.out
347 # Use this helper to make it easy for the caller of your
348 # terminal-using function to specify whether it should fail.
354 # $test_expectation "$cmd - behaves well" "
361 # then your test can be used like this:
363 # your_test expect_(success|failure) [test_must_fail] 'git foo'
366 test_expectation
="test_$1"
368 if test "$1" = test_must_fail
370 full_command
="test_must_fail test_terminal "
373 full_command
="test_terminal "
376 full_command
="$full_command $1"
379 test_default_pager
() {
382 $test_expectation SIMPLEPAGER
,TTY
"$cmd - default pager is used by default" "
383 sane_unset PAGER GIT_PAGER &&
384 test_unconfig core.pager &&
385 rm -f default_pager_used &&
386 cat >\$less <<-\EOF &&
388 wc >default_pager_used
396 test_path_is_file default_pager_used
400 test_PAGER_overrides
() {
403 $test_expectation TTY
"$cmd - PAGER overrides default pager" "
404 sane_unset GIT_PAGER &&
405 test_unconfig core.pager &&
407 PAGER='wc >PAGER_used' &&
410 test_path_is_file PAGER_used
414 test_core_pager_overrides
() {
416 used_if_wanted
='overrides PAGER'
420 test_local_config_ignored
() {
422 used_if_wanted
='is not used'
429 $test_expectation TTY
"$cmd - repository-local core.pager setting $used_if_wanted" "
430 sane_unset GIT_PAGER &&
431 rm -f core.pager_used &&
434 test_config core.pager 'wc >core.pager_used' &&
436 ${if_local_config}test_path_is_file core.pager_used
440 test_core_pager_subdir
() {
442 used_if_wanted
='overrides PAGER'
443 test_pager_subdir_helper
"$@"
446 test_no_local_config_subdir
() {
448 used_if_wanted
='is not used'
449 test_pager_subdir_helper
"$@"
452 test_pager_subdir_helper
() {
455 $test_expectation TTY
"$cmd - core.pager $used_if_wanted from subdirectory" "
456 sane_unset GIT_PAGER &&
457 rm -f core.pager_used &&
460 stampname=\$(pwd)/core.pager_used &&
461 export PAGER stampname &&
462 test_config core.pager 'wc >\"\$stampname\"' &&
468 ${if_local_config}test_path_is_file core.pager_used
472 test_GIT_PAGER_overrides
() {
475 $test_expectation TTY
"$cmd - GIT_PAGER overrides core.pager" "
476 rm -f GIT_PAGER_used &&
477 test_config core.pager wc &&
478 GIT_PAGER='wc >GIT_PAGER_used' &&
481 test_path_is_file GIT_PAGER_used
485 test_doesnt_paginate
() {
488 $test_expectation TTY
"no pager for '$cmd'" "
489 rm -f GIT_PAGER_used &&
490 GIT_PAGER='wc >GIT_PAGER_used' &&
493 test_path_is_missing GIT_PAGER_used
497 test_pager_choices
() {
498 test_default_pager expect_success
"$@"
499 test_PAGER_overrides expect_success
"$@"
500 test_core_pager_overrides expect_success
"$@"
501 test_core_pager_subdir expect_success
"$@"
502 test_GIT_PAGER_overrides expect_success
"$@"
505 test_expect_success
'setup: some aliases' '
506 git config alias.aliasedlog log &&
507 git config alias.true "!true"
510 test_pager_choices
'git log'
511 test_pager_choices
'git -p log'
512 test_pager_choices
'git aliasedlog'
514 test_default_pager expect_success
'git -p aliasedlog'
515 test_PAGER_overrides expect_success
'git -p aliasedlog'
516 test_core_pager_overrides expect_success
'git -p aliasedlog'
517 test_core_pager_subdir expect_success
'git -p aliasedlog'
518 test_GIT_PAGER_overrides expect_success
'git -p aliasedlog'
520 test_default_pager expect_success
'git -p true'
521 test_PAGER_overrides expect_success
'git -p true'
522 test_core_pager_overrides expect_success
'git -p true'
523 test_core_pager_subdir expect_success
'git -p true'
524 test_GIT_PAGER_overrides expect_success
'git -p true'
526 test_default_pager expect_success test_must_fail
'git -p request-pull'
527 test_PAGER_overrides expect_success test_must_fail
'git -p request-pull'
528 test_core_pager_overrides expect_success test_must_fail
'git -p request-pull'
529 test_core_pager_subdir expect_success test_must_fail
'git -p request-pull'
530 test_GIT_PAGER_overrides expect_success test_must_fail
'git -p request-pull'
532 test_default_pager expect_success test_must_fail
'git -p'
533 test_PAGER_overrides expect_success test_must_fail
'git -p'
534 test_local_config_ignored expect_failure test_must_fail
'git -p'
535 test_GIT_PAGER_overrides expect_success test_must_fail
'git -p'
537 test_expect_success TTY
'core.pager in repo config works and retains cwd' '
538 sane_unset GIT_PAGER &&
539 test_config core.pager "cat >cwd-retained" &&
542 rm -f cwd-retained &&
543 test_terminal git -p rev-parse HEAD &&
544 test_path_is_file cwd-retained
548 test_expect_success TTY
'core.pager is found via alias in subdirectory' '
549 sane_unset GIT_PAGER &&
550 test_config core.pager "cat >via-alias" &&
554 test_terminal git -c alias.r="-p rev-parse" r HEAD &&
555 test_path_is_file via-alias
559 test_doesnt_paginate expect_failure test_must_fail
'git -p nonsense'
561 test_pager_choices
'git shortlog'
562 test_expect_success
'setup: configure shortlog not to paginate' '
563 git config pager.shortlog false
565 test_doesnt_paginate expect_success
'git shortlog'
566 test_no_local_config_subdir expect_success
'git shortlog'
567 test_default_pager expect_success
'git -p shortlog'
568 test_core_pager_subdir expect_success
'git -p shortlog'
570 test_core_pager_subdir expect_success test_must_fail \
571 'git -p apply </dev/null'
573 test_expect_success TTY
'command-specific pager' '
574 sane_unset PAGER GIT_PAGER &&
575 echo "foo:initial" >expect &&
577 test_unconfig core.pager &&
578 test_config pager.log "sed s/^/foo:/ >actual" &&
579 test_terminal git log --format=%s -1 &&
580 test_cmp expect actual
583 test_expect_success TTY
'command-specific pager overrides core.pager' '
584 sane_unset PAGER GIT_PAGER &&
585 echo "foo:initial" >expect &&
587 test_config core.pager "exit 1" &&
588 test_config pager.log "sed s/^/foo:/ >actual" &&
589 test_terminal git log --format=%s -1 &&
590 test_cmp expect actual
593 test_expect_success TTY
'command-specific pager overridden by environment' '
594 GIT_PAGER="sed s/^/foo:/ >actual" && export GIT_PAGER &&
596 echo "foo:initial" >expect &&
597 test_config pager.log "exit 1" &&
598 test_terminal git log --format=%s -1 &&
599 test_cmp expect actual
602 test_expect_success
'setup external command' '
603 cat >git-external <<-\EOF &&
607 chmod +x git-external
610 test_expect_success TTY
'command-specific pager works for external commands' '
611 sane_unset PAGER GIT_PAGER &&
612 echo "foo:initial" >expect &&
614 test_config pager.external "sed s/^/foo:/ >actual" &&
615 test_terminal git --exec-path="$(pwd)" external log --format=%s -1 &&
616 test_cmp expect actual
619 test_expect_success TTY
'sub-commands of externals use their own pager' '
620 sane_unset PAGER GIT_PAGER &&
621 echo "foo:initial" >expect &&
623 test_config pager.log "sed s/^/foo:/ >actual" &&
624 test_terminal git --exec-path=. external log --format=%s -1 &&
625 test_cmp expect actual
628 test_expect_success TTY
'external command pagers override sub-commands' '
629 sane_unset PAGER GIT_PAGER &&
631 test_config pager.external false &&
632 test_config pager.log "sed s/^/log:/ >actual" &&
633 test_terminal git --exec-path=. external log --format=%s -1 &&
634 test_must_be_empty actual
637 test_expect_success
'command with underscores does not complain' '
638 write_script git-under_score <<-\EOF &&
641 git --exec-path=. under_score >actual 2>&1 &&
643 test_cmp expect actual
646 test_expect_success TTY
'git tag with auto-columns ' '
652 cat >expect <<-\EOF &&
653 initial one two three four five
655 test_terminal env PAGER="cat >actual" COLUMNS=80 \
656 git -c column.ui=auto tag --sort=authordate &&
657 test_cmp expect actual
660 test_expect_success
'setup trace2' '
661 GIT_TRACE2_BRIEF=1 &&
662 export GIT_TRACE2_BRIEF
665 test_expect_success
'setup large log output' '
667 print \"this is a long commit message\" x 50000
669 git commit --allow-empty -F commit-msg
672 test_expect_success TTY
'git returns SIGPIPE on early pager exit' '
673 test_when_finished "rm pager-used trace.normal" &&
674 test_config core.pager ">pager-used; head -n 1; exit 0" &&
675 GIT_TRACE2="$(pwd)/trace.normal" &&
677 test_when_finished "unset GIT_TRACE2" &&
679 if test_have_prereq !MINGW
681 { test_terminal git log >/dev/null; OUT=$?; } &&
682 test_match_signal 13 "$OUT"
684 test_terminal git log
687 grep child_exit trace.normal >child-exits &&
688 test_line_count = 1 child-exits &&
689 grep " code:0 " child-exits &&
690 test_path_is_file pager-used
693 test_expect_success TTY
'git returns SIGPIPE on early pager non-zero exit' '
694 test_when_finished "rm pager-used trace.normal" &&
695 test_config core.pager ">pager-used; head -n 1; exit 1" &&
696 GIT_TRACE2="$(pwd)/trace.normal" &&
698 test_when_finished "unset GIT_TRACE2" &&
700 if test_have_prereq !MINGW
702 { test_terminal git log >/dev/null; OUT=$?; } &&
703 test_match_signal 13 "$OUT"
705 test_terminal git log
708 grep child_exit trace.normal >child-exits &&
709 test_line_count = 1 child-exits &&
710 grep " code:1 " child-exits &&
711 test_path_is_file pager-used
714 test_expect_success TTY
'git discards pager non-zero exit without SIGPIPE' '
715 test_when_finished "rm pager-used trace.normal" &&
716 test_config core.pager "wc >pager-used; exit 1" &&
717 GIT_TRACE2="$(pwd)/trace.normal" &&
719 test_when_finished "unset GIT_TRACE2" &&
721 test_terminal git log &&
723 grep child_exit trace.normal >child-exits &&
724 test_line_count = 1 child-exits &&
725 grep " code:1 " child-exits &&
726 test_path_is_file pager-used
729 test_expect_success TTY
'git errors when asked to execute nonexisting pager' '
730 test_when_finished "rm -f err" &&
731 test_config core.pager "does-not-exist" &&
732 test_must_fail test_terminal git log 2>err &&
733 test_grep "unable to execute pager" err
736 test_expect_success TTY
'git returns SIGPIPE on propagated signals from pager' '
737 test_when_finished "rm pager-used trace.normal" &&
738 test_config core.pager ">pager-used; exec test-tool sigchain" &&
739 GIT_TRACE2="$(pwd)/trace.normal" &&
741 test_when_finished "unset GIT_TRACE2" &&
743 if test_have_prereq !MINGW
745 { test_terminal git log >/dev/null; OUT=$?; } &&
746 test_match_signal 13 "$OUT"
748 test_terminal git log
751 grep child_exit trace.normal >child-exits &&
752 test_line_count = 1 child-exits &&
753 grep " code:143 " child-exits &&
754 test_path_is_file pager-used
757 test_expect_success TTY
'non-existent pager doesnt cause crash' '
758 test_config pager.show invalid-pager &&
759 test_must_fail test_terminal git show