#!/bin/sh test_description='git log' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME . ./test-lib.sh . "$TEST_DIRECTORY/lib-gpg.sh" . "$TEST_DIRECTORY/lib-terminal.sh" . "$TEST_DIRECTORY/lib-log-graph.sh" test_cmp_graph () { lib_test_cmp_graph --format=%s "$@" } test_expect_success setup ' echo one >one && git add one && test_tick && git commit -m initial && echo ichi >one && git add one && test_tick && git commit -m second && git mv one ichi && test_tick && git commit -m third && cp ichi ein && git add ein && test_tick && git commit -m fourth && mkdir a && echo ni >a/two && git add a/two && test_tick && git commit -m fifth && git rm a/two && test_tick && git commit -m sixth ' printf "sixth\nfifth\nfourth\nthird\nsecond\ninitial" > expect test_expect_success 'pretty' ' git log --pretty="format:%s" > actual && test_cmp expect actual ' printf "sixth\nfifth\nfourth\nthird\nsecond\ninitial\n" > expect test_expect_success 'pretty (tformat)' ' git log --pretty="tformat:%s" > actual && test_cmp expect actual ' test_expect_success 'pretty (shortcut)' ' git log --pretty="%s" > actual && test_cmp expect actual ' test_expect_success 'format' ' git log --format="%s" > actual && test_cmp expect actual ' cat > expect << EOF This is the sixth commit. This is the fifth commit. EOF test_expect_success 'format %w(11,1,2)' ' git log -2 --format="%w(11,1,2)This is the %s commit." > actual && test_cmp expect actual ' test_expect_success 'format %w(,1,2)' ' git log -2 --format="%w(,1,2)This is%nthe %s%ncommit." > actual && test_cmp expect actual ' cat > expect << EOF $(git rev-parse --short :/sixth ) sixth $(git rev-parse --short :/fifth ) fifth $(git rev-parse --short :/fourth ) fourth $(git rev-parse --short :/third ) third $(git rev-parse --short :/second ) second $(git rev-parse --short :/initial) initial EOF test_expect_success 'oneline' ' git log --oneline > actual && test_cmp expect actual ' test_expect_success 'diff-filter=A' ' git log --no-renames --pretty="format:%s" --diff-filter=A HEAD > actual && git log --no-renames --pretty="format:%s" --diff-filter A HEAD > actual-separate && printf "fifth\nfourth\nthird\ninitial" > expect && test_cmp expect actual && test_cmp expect actual-separate ' test_expect_success 'diff-filter=M' ' git log --pretty="format:%s" --diff-filter=M HEAD >actual && printf "second" >expect && test_cmp expect actual ' test_expect_success 'diff-filter=D' ' git log --no-renames --pretty="format:%s" --diff-filter=D HEAD >actual && printf "sixth\nthird" >expect && test_cmp expect actual ' test_expect_success 'diff-filter=R' ' git log -M --pretty="format:%s" --diff-filter=R HEAD >actual && printf "third" >expect && test_cmp expect actual ' test_expect_success 'multiple --diff-filter bits' ' git log -M --pretty="format:%s" --diff-filter=R HEAD >expect && git log -M --pretty="format:%s" --diff-filter=Ra HEAD >actual && test_cmp expect actual && git log -M --pretty="format:%s" --diff-filter=aR HEAD >actual && test_cmp expect actual && git log -M --pretty="format:%s" \ --diff-filter=a --diff-filter=R HEAD >actual && test_cmp expect actual ' test_expect_success 'diff-filter=C' ' git log -C -C --pretty="format:%s" --diff-filter=C HEAD >actual && printf "fourth" >expect && test_cmp expect actual ' test_expect_success 'git log --follow' ' git log --follow --pretty="format:%s" ichi >actual && printf "third\nsecond\ninitial" >expect && test_cmp expect actual ' test_expect_success 'git config log.follow works like --follow' ' test_config log.follow true && git log --pretty="format:%s" ichi >actual && printf "third\nsecond\ninitial" >expect && test_cmp expect actual ' test_expect_success 'git config log.follow does not die with multiple paths' ' test_config log.follow true && git log --pretty="format:%s" ichi ein ' test_expect_success 'git config log.follow does not die with no paths' ' test_config log.follow true && git log -- ' test_expect_success 'git config log.follow is overridden by --no-follow' ' test_config log.follow true && git log --no-follow --pretty="format:%s" ichi >actual && printf "third" >expect && test_cmp expect actual ' # Note that these commits are intentionally listed out of order. last_three="$(git rev-parse :/fourth :/sixth :/fifth)" cat > expect << EOF $(git rev-parse --short :/sixth ) sixth $(git rev-parse --short :/fifth ) fifth $(git rev-parse --short :/fourth) fourth EOF test_expect_success 'git log --no-walk sorts by commit time' ' git log --no-walk --oneline $last_three > actual && test_cmp expect actual ' test_expect_success 'git log --no-walk=sorted sorts by commit time' ' git log --no-walk=sorted --oneline $last_three > actual && test_cmp expect actual ' cat > expect << EOF === $(git rev-parse --short :/sixth ) sixth === $(git rev-parse --short :/fifth ) fifth === $(git rev-parse --short :/fourth) fourth EOF test_expect_success 'git log --line-prefix="=== " --no-walk sorts by commit time' ' git log --line-prefix="=== " --no-walk --oneline $last_three > actual && test_cmp expect actual ' cat > expect << EOF $(git rev-parse --short :/fourth) fourth $(git rev-parse --short :/sixth ) sixth $(git rev-parse --short :/fifth ) fifth EOF test_expect_success 'git log --no-walk=unsorted leaves list of commits as given' ' git log --no-walk=unsorted --oneline $last_three > actual && test_cmp expect actual ' test_expect_success 'git show leaves list of commits as given' ' git show --oneline -s $last_three > actual && test_cmp expect actual ' test_expect_success 'setup case sensitivity tests' ' echo case >one && test_tick && git add one && git commit -a -m Second ' test_expect_success 'log --grep' ' echo second >expect && git log -1 --pretty="tformat:%s" --grep=sec >actual && test_cmp expect actual ' cat > expect << EOF second initial EOF test_expect_success 'log --invert-grep --grep' ' # Fixed git -c grep.patternType=fixed log --pretty="tformat:%s" --invert-grep --grep=th --grep=Sec >actual && test_cmp expect actual && # POSIX basic git -c grep.patternType=basic log --pretty="tformat:%s" --invert-grep --grep=t[h] --grep=S[e]c >actual && test_cmp expect actual && # POSIX extended git -c grep.patternType=extended log --pretty="tformat:%s" --invert-grep --grep=t[h] --grep=S[e]c >actual && test_cmp expect actual && # PCRE if test_have_prereq PCRE then git -c grep.patternType=perl log --pretty="tformat:%s" --invert-grep --grep=t[h] --grep=S[e]c >actual && test_cmp expect actual fi ' test_expect_success 'log --invert-grep --grep -i' ' echo initial >expect && # Fixed git -c grep.patternType=fixed log --pretty="tformat:%s" --invert-grep -i --grep=th --grep=Sec >actual && test_cmp expect actual && # POSIX basic git -c grep.patternType=basic log --pretty="tformat:%s" --invert-grep -i --grep=t[h] --grep=S[e]c >actual && test_cmp expect actual && # POSIX extended git -c grep.patternType=extended log --pretty="tformat:%s" --invert-grep -i --grep=t[h] --grep=S[e]c >actual && test_cmp expect actual && # PCRE if test_have_prereq PCRE then git -c grep.patternType=perl log --pretty="tformat:%s" --invert-grep -i --grep=t[h] --grep=S[e]c >actual && test_cmp expect actual fi ' test_expect_success 'log --grep option parsing' ' echo second >expect && git log -1 --pretty="tformat:%s" --grep sec >actual && test_cmp expect actual && test_must_fail git log -1 --pretty="tformat:%s" --grep ' test_expect_success 'log -i --grep' ' echo Second >expect && git log -1 --pretty="tformat:%s" -i --grep=sec >actual && test_cmp expect actual ' test_expect_success 'log --grep -i' ' echo Second >expect && # Fixed git log -1 --pretty="tformat:%s" --grep=sec -i >actual && test_cmp expect actual && # POSIX basic git -c grep.patternType=basic log -1 --pretty="tformat:%s" --grep=s[e]c -i >actual && test_cmp expect actual && # POSIX extended git -c grep.patternType=extended log -1 --pretty="tformat:%s" --grep=s[e]c -i >actual && test_cmp expect actual && # PCRE if test_have_prereq PCRE then git -c grep.patternType=perl log -1 --pretty="tformat:%s" --grep=s[e]c -i >actual && test_cmp expect actual fi ' test_expect_success 'log -F -E --grep= uses ere' ' echo second >expect && # basic would need \(s\) to do the same git log -1 --pretty="tformat:%s" -F -E --grep="(s).c.nd" >actual && test_cmp expect actual ' test_expect_success PCRE 'log -F -E --perl-regexp --grep= uses PCRE' ' test_when_finished "rm -rf num_commits" && git init num_commits && ( cd num_commits && test_commit 1d && test_commit 2e ) && # In PCRE \d in [\d] is like saying "0-9", and matches the 2 # in 2e... echo 2e >expect && git -C num_commits log -1 --pretty="tformat:%s" -F -E --perl-regexp --grep="[\d]" >actual && test_cmp expect actual && # ...in POSIX basic and extended it is the same as [d], # i.e. "d", which matches 1d, but does not match 2e. echo 1d >expect && git -C num_commits log -1 --pretty="tformat:%s" -F -E --grep="[\d]" >actual && test_cmp expect actual ' test_expect_success 'log with grep.patternType configuration' ' git -c grep.patterntype=fixed \ log -1 --pretty=tformat:%s --grep=s.c.nd >actual && test_must_be_empty actual ' test_expect_success 'log with grep.patternType configuration and command line' ' echo second >expect && git -c grep.patterntype=fixed \ log -1 --pretty=tformat:%s --basic-regexp --grep=s.c.nd >actual && test_cmp expect actual ' test_expect_success !FAIL_PREREQS 'log with various grep.patternType configurations & command-lines' ' git init pattern-type && ( cd pattern-type && test_commit 1 file A && # The tagname is overridden here because creating a # tag called "(1|2)" as test_commit would otherwise # implicitly do would fail on e.g. MINGW. test_commit "(1|2)" file B 2 && echo "(1|2)" >expect.fixed && cp expect.fixed expect.basic && cp expect.fixed expect.extended && cp expect.fixed expect.perl && # A strcmp-like match with fixed. git -c grep.patternType=fixed log --pretty=tformat:%s \ --grep="(1|2)" >actual.fixed && # POSIX basic matches (, | and ) literally. git -c grep.patternType=basic log --pretty=tformat:%s \ --grep="(.|.)" >actual.basic && # POSIX extended needs to have | escaped to match it # literally, whereas under basic this is the same as # (|2), i.e. it would also match "1". This test checks # for extended by asserting that it is not matching # what basic would match. git -c grep.patternType=extended log --pretty=tformat:%s \ --grep="\|2" >actual.extended && if test_have_prereq PCRE then # Only PCRE would match [\d]\| with only # "(1|2)" due to [\d]. POSIX basic would match # both it and "1" since similarly to the # extended match above it is the same as # \([\d]\|\). POSIX extended would # match neither. git -c grep.patternType=perl log --pretty=tformat:%s \ --grep="[\d]\|" >actual.perl && test_cmp expect.perl actual.perl fi && test_cmp expect.fixed actual.fixed && test_cmp expect.basic actual.basic && test_cmp expect.extended actual.extended && git log --pretty=tformat:%s -F \ --grep="(1|2)" >actual.fixed.short-arg && git log --pretty=tformat:%s -E \ --grep="\|2" >actual.extended.short-arg && if test_have_prereq PCRE then git log --pretty=tformat:%s -P \ --grep="[\d]\|" >actual.perl.short-arg else test_must_fail git log -P \ --grep="[\d]\|" fi && test_cmp expect.fixed actual.fixed.short-arg && test_cmp expect.extended actual.extended.short-arg && if test_have_prereq PCRE then test_cmp expect.perl actual.perl.short-arg fi && git log --pretty=tformat:%s --fixed-strings \ --grep="(1|2)" >actual.fixed.long-arg && git log --pretty=tformat:%s --basic-regexp \ --grep="(.|.)" >actual.basic.long-arg && git log --pretty=tformat:%s --extended-regexp \ --grep="\|2" >actual.extended.long-arg && if test_have_prereq PCRE then git log --pretty=tformat:%s --perl-regexp \ --grep="[\d]\|" >actual.perl.long-arg && test_cmp expect.perl actual.perl.long-arg else test_must_fail git log --perl-regexp \ --grep="[\d]\|" fi && test_cmp expect.fixed actual.fixed.long-arg && test_cmp expect.basic actual.basic.long-arg && test_cmp expect.extended actual.extended.long-arg ) ' for cmd in show whatchanged reflog format-patch do case "$cmd" in format-patch) myarg="HEAD~.." ;; *) myarg= ;; esac test_expect_success "$cmd: understands grep.patternType, like 'log'" ' git init "pattern-type-$cmd" && ( cd "pattern-type-$cmd" && test_commit 1 file A && test_commit "(1|2)" file B 2 && git -c grep.patternType=fixed $cmd --grep="..." $myarg >actual && test_must_be_empty actual && git -c grep.patternType=basic $cmd --grep="..." $myarg >actual && test_file_not_empty actual ) ' done test_expect_success 'log --author' ' cat >expect <<-\EOF && Author: A U Thor EOF git log -1 --color=always --author="A U" >log && grep Author log >actual.raw && test_decode_color actual && test_cmp expect actual ' test_expect_success 'log --committer' ' cat >expect <<-\EOF && Commit: C O Mitter example.com> EOF git log -1 --color=always --pretty=fuller --committer="example" >log && grep "Commit:" log >actual.raw && test_decode_color actual && test_cmp expect actual ' test_expect_success 'log -i --grep with color' ' cat >expect <<-\EOF && Second second EOF git log --color=always -i --grep=^sec >log && grep -i sec log >actual.raw && test_decode_color actual && test_cmp expect actual ' test_expect_success '-c color.grep.selected log --grep' ' cat >expect <<-\EOF && third EOF git -c color.grep.selected="green" log --color=always --grep=ir >log && grep ir log >actual.raw && test_decode_color actual && test_cmp expect actual ' test_expect_success '-c color.grep.matchSelected log --grep' ' cat >expect <<-\EOF && initial EOF git -c color.grep.matchSelected="blue" log --color=always --grep=i >log && grep al log >actual.raw && test_decode_color actual && test_cmp expect actual ' cat > expect < expect < expect <<\EOF * Merge branch 'side' |\ | * side-2 | * side-1 * | Second * | sixth * | fifth * | fourth |/ * third * second * initial EOF test_expect_success 'log --graph with merge' ' test_cmp_graph --date-order ' cat > expect <<\EOF | | | * Merge branch 'side' | | | |\ | | | | * side-2 | | | | * side-1 | | | * | Second | | | * | sixth | | | * | fifth | | | * | fourth | | | |/ | | | * third | | | * second | | | * initial EOF test_expect_success 'log --graph --line-prefix="| | | " with merge' ' test_cmp_graph --line-prefix="| | | " --date-order ' cat > expect.colors <<\EOF * Merge branch 'side' |\ | * side-2 | * side-1 * | Second * | sixth * | fifth * | fourth |/ * third * second * initial EOF test_expect_success 'log --graph with merge with log.graphColors' ' test_config log.graphColors " blue,invalid-color, cyan, red , " && lib_test_cmp_colored_graph --date-order --format=%s ' test_expect_success 'log --raw --graph -m with merge' ' git log --raw --graph --oneline -m main | head -n 500 >actual && grep "initial" actual ' test_expect_success 'diff-tree --graph' ' git diff-tree --graph main^ | head -n 500 >actual && grep "one" actual ' cat > expect <<\EOF * commit main |\ Merge: A B | | Author: A U Thor | | | | Merge branch 'side' | | | * commit tags/side-2 | | Author: A U Thor | | | | side-2 | | | * commit tags/side-1 | | Author: A U Thor | | | | side-1 | | * | commit main~1 | | Author: A U Thor | | | | Second | | * | commit main~2 | | Author: A U Thor | | | | sixth | | * | commit main~3 | | Author: A U Thor | | | | fifth | | * | commit main~4 |/ Author: A U Thor | | fourth | * commit tags/side-1~1 | Author: A U Thor | | third | * commit tags/side-1~2 | Author: A U Thor | | second | * commit tags/side-1~3 Author: A U Thor initial EOF test_expect_success 'log --graph with full output' ' git log --graph --date-order --pretty=short | git name-rev --name-only --annotate-stdin | sed "s/Merge:.*/Merge: A B/;s/ *\$//" >actual && test_cmp expect actual ' test_expect_success 'set up more tangled history' ' git checkout -b tangle HEAD~6 && test_commit tangle-a tangle-a a && git merge main~3 && git merge side~1 && git checkout main && git merge tangle && git checkout -b reach && test_commit reach && git checkout main && git checkout -b octopus-a && test_commit octopus-a && git checkout main && git checkout -b octopus-b && test_commit octopus-b && git checkout main && test_commit seventh && git merge octopus-a octopus-b && git merge reach ' cat > expect <<\EOF * Merge tag 'reach' |\ | \ | \ *-. \ Merge tags 'octopus-a' and 'octopus-b' |\ \ \ * | | | seventh | | * | octopus-b | |/ / |/| | | * | octopus-a |/ / | * reach |/ * Merge branch 'tangle' |\ | * Merge branch 'side' (early part) into tangle | |\ | * \ Merge branch 'main' (early part) into tangle | |\ \ | * | | tangle-a * | | | Merge branch 'side' |\ \ \ \ | * | | | side-2 | | |_|/ | |/| | | * | | side-1 * | | | Second * | | | sixth | |_|/ |/| | * | | fifth * | | fourth |/ / * / third |/ * second * initial EOF test_expect_success 'log --graph with merge' ' test_cmp_graph --date-order ' test_expect_success 'log.decorate configuration' ' git log --oneline --no-decorate >expect.none && git log --oneline --decorate >expect.short && git log --oneline --decorate=full >expect.full && echo "[log] decorate" >>.git/config && git log --oneline >actual && test_cmp expect.short actual && test_config log.decorate true && git log --oneline >actual && test_cmp expect.short actual && git log --oneline --decorate=full >actual && test_cmp expect.full actual && git log --oneline --decorate=no >actual && test_cmp expect.none actual && test_config log.decorate no && git log --oneline >actual && test_cmp expect.none actual && git log --oneline --decorate >actual && test_cmp expect.short actual && git log --oneline --decorate=full >actual && test_cmp expect.full actual && test_config log.decorate 1 && git log --oneline >actual && test_cmp expect.short actual && git log --oneline --decorate=full >actual && test_cmp expect.full actual && git log --oneline --decorate=no >actual && test_cmp expect.none actual && test_config log.decorate short && git log --oneline >actual && test_cmp expect.short actual && git log --oneline --no-decorate >actual && test_cmp expect.none actual && git log --oneline --decorate=full >actual && test_cmp expect.full actual && test_config log.decorate full && git log --oneline >actual && test_cmp expect.full actual && git log --oneline --no-decorate >actual && test_cmp expect.none actual && git log --oneline --decorate >actual && test_cmp expect.short actual && test_unconfig log.decorate && git log --pretty=raw >expect.raw && test_config log.decorate full && git log --pretty=raw >actual && test_cmp expect.raw actual ' test_expect_success 'decorate-refs with glob' ' cat >expect.decorate <<-\EOF && Merge-tag-reach Merge-tags-octopus-a-and-octopus-b seventh octopus-b (octopus-b) octopus-a (octopus-a) reach EOF cat >expect.no-decorate <<-\EOF && Merge-tag-reach Merge-tags-octopus-a-and-octopus-b seventh octopus-b octopus-a reach EOF git log -n6 --decorate=short --pretty="tformat:%f%d" \ --decorate-refs="heads/octopus*" >actual && test_cmp expect.decorate actual && git log -n6 --decorate=short --pretty="tformat:%f%d" \ --decorate-refs-exclude="heads/octopus*" \ --decorate-refs="heads/octopus*" >actual && test_cmp expect.no-decorate actual && git -c log.excludeDecoration="heads/octopus*" log \ -n6 --decorate=short --pretty="tformat:%f%d" \ --decorate-refs="heads/octopus*" >actual && test_cmp expect.decorate actual ' test_expect_success 'decorate-refs without globs' ' cat >expect.decorate <<-\EOF && Merge-tag-reach Merge-tags-octopus-a-and-octopus-b seventh octopus-b octopus-a reach (tag: reach) EOF git log -n6 --decorate=short --pretty="tformat:%f%d" \ --decorate-refs="tags/reach" >actual && test_cmp expect.decorate actual ' test_expect_success 'multiple decorate-refs' ' cat >expect.decorate <<-\EOF && Merge-tag-reach Merge-tags-octopus-a-and-octopus-b seventh octopus-b (octopus-b) octopus-a (octopus-a) reach (tag: reach) EOF git log -n6 --decorate=short --pretty="tformat:%f%d" \ --decorate-refs="heads/octopus*" \ --decorate-refs="tags/reach" >actual && test_cmp expect.decorate actual ' test_expect_success 'decorate-refs-exclude with glob' ' cat >expect.decorate <<-\EOF && Merge-tag-reach (HEAD -> main) Merge-tags-octopus-a-and-octopus-b seventh (tag: seventh) octopus-b (tag: octopus-b) octopus-a (tag: octopus-a) reach (tag: reach, reach) EOF git log -n6 --decorate=short --pretty="tformat:%f%d" \ --decorate-refs-exclude="heads/octopus*" >actual && test_cmp expect.decorate actual && git -c log.excludeDecoration="heads/octopus*" log \ -n6 --decorate=short --pretty="tformat:%f%d" >actual && test_cmp expect.decorate actual ' test_expect_success 'decorate-refs-exclude without globs' ' cat >expect.decorate <<-\EOF && Merge-tag-reach (HEAD -> main) Merge-tags-octopus-a-and-octopus-b seventh (tag: seventh) octopus-b (tag: octopus-b, octopus-b) octopus-a (tag: octopus-a, octopus-a) reach (reach) EOF git log -n6 --decorate=short --pretty="tformat:%f%d" \ --decorate-refs-exclude="tags/reach" >actual && test_cmp expect.decorate actual && git -c log.excludeDecoration="tags/reach" log \ -n6 --decorate=short --pretty="tformat:%f%d" >actual && test_cmp expect.decorate actual ' test_expect_success 'multiple decorate-refs-exclude' ' cat >expect.decorate <<-\EOF && Merge-tag-reach (HEAD -> main) Merge-tags-octopus-a-and-octopus-b seventh (tag: seventh) octopus-b (tag: octopus-b) octopus-a (tag: octopus-a) reach (reach) EOF git log -n6 --decorate=short --pretty="tformat:%f%d" \ --decorate-refs-exclude="heads/octopus*" \ --decorate-refs-exclude="tags/reach" >actual && test_cmp expect.decorate actual && git -c log.excludeDecoration="heads/octopus*" \ -c log.excludeDecoration="tags/reach" log \ -n6 --decorate=short --pretty="tformat:%f%d" >actual && test_cmp expect.decorate actual && git -c log.excludeDecoration="heads/octopus*" log \ --decorate-refs-exclude="tags/reach" \ -n6 --decorate=short --pretty="tformat:%f%d" >actual && test_cmp expect.decorate actual ' test_expect_success 'decorate-refs and decorate-refs-exclude' ' cat >expect.no-decorate <<-\EOF && Merge-tag-reach (main) Merge-tags-octopus-a-and-octopus-b seventh octopus-b octopus-a reach (reach) EOF git log -n6 --decorate=short --pretty="tformat:%f%d" \ --decorate-refs="heads/*" \ --decorate-refs-exclude="heads/oc*" >actual && test_cmp expect.no-decorate actual ' test_expect_success 'deocrate-refs and log.excludeDecoration' ' cat >expect.decorate <<-\EOF && Merge-tag-reach (main) Merge-tags-octopus-a-and-octopus-b seventh octopus-b (octopus-b) octopus-a (octopus-a) reach (reach) EOF git -c log.excludeDecoration="heads/oc*" log \ --decorate-refs="heads/*" \ -n6 --decorate=short --pretty="tformat:%f%d" >actual && test_cmp expect.decorate actual ' test_expect_success 'decorate-refs-exclude and simplify-by-decoration' ' cat >expect.decorate <<-\EOF && Merge-tag-reach (HEAD -> main) reach (tag: reach, reach) seventh (tag: seventh) Merge-branch-tangle Merge-branch-side-early-part-into-tangle (tangle) tangle-a (tag: tangle-a) EOF git log -n6 --decorate=short --pretty="tformat:%f%d" \ --decorate-refs-exclude="*octopus*" \ --simplify-by-decoration >actual && test_cmp expect.decorate actual && git -c log.excludeDecoration="*octopus*" log \ -n6 --decorate=short --pretty="tformat:%f%d" \ --simplify-by-decoration >actual && test_cmp expect.decorate actual ' test_expect_success 'decorate-refs with implied decorate from format' ' cat >expect <<-\EOF && side-2 (tag: side-2) side-1 EOF git log --no-walk --format="%s%d" \ --decorate-refs="*side-2" side-1 side-2 \ >actual && test_cmp expect actual ' test_expect_success 'implied decorate does not override option' ' cat >expect <<-\EOF && side-2 (tag: refs/tags/side-2, refs/heads/side) side-1 (tag: refs/tags/side-1) EOF git log --no-walk --format="%s%d" \ --decorate=full side-1 side-2 \ >actual && test_cmp expect actual ' test_expect_success 'decorate-refs and simplify-by-decoration without output' ' cat >expect <<-\EOF && side-2 initial EOF # Do not just use a --format without %d here; we want to # make sure that we did not accidentally turn on displaying # the decorations, too. And that requires one of the regular # formats. git log --decorate-refs="*side-2" --oneline \ --simplify-by-decoration >actual.raw && sed "s/^[0-9a-f]* //" actual && test_cmp expect actual ' test_expect_success 'log.decorate config parsing' ' git log --oneline --decorate=full >expect.full && git log --oneline --decorate=short >expect.short && test_config log.decorate full && test_config log.mailmap true && git log --oneline >actual && test_cmp expect.full actual && git log --oneline --decorate=short >actual && test_cmp expect.short actual ' test_expect_success TTY 'log output on a TTY' ' git log --color --oneline --decorate >expect.short && test_terminal git log --oneline >actual && test_cmp expect.short actual ' test_expect_success 'reflog is expected format' ' git log -g --abbrev-commit --pretty=oneline >expect && git reflog >actual && test_cmp expect actual ' test_expect_success 'whatchanged is expected format' ' git log --no-merges --raw >expect && git whatchanged >actual && test_cmp expect actual ' test_expect_success 'log.abbrevCommit configuration' ' git log --abbrev-commit >expect.log.abbrev && git log --no-abbrev-commit >expect.log.full && git log --pretty=raw >expect.log.raw && git reflog --abbrev-commit >expect.reflog.abbrev && git reflog --no-abbrev-commit >expect.reflog.full && git whatchanged --abbrev-commit >expect.whatchanged.abbrev && git whatchanged --no-abbrev-commit >expect.whatchanged.full && test_config log.abbrevCommit true && git log >actual && test_cmp expect.log.abbrev actual && git log --no-abbrev-commit >actual && test_cmp expect.log.full actual && git log --pretty=raw >actual && test_cmp expect.log.raw actual && git reflog >actual && test_cmp expect.reflog.abbrev actual && git reflog --no-abbrev-commit >actual && test_cmp expect.reflog.full actual && git whatchanged >actual && test_cmp expect.whatchanged.abbrev actual && git whatchanged --no-abbrev-commit >actual && test_cmp expect.whatchanged.full actual ' test_expect_success 'show added path under "--follow -M"' ' # This tests for a regression introduced in v1.7.2-rc0~103^2~2 test_create_repo regression && ( cd regression && test_commit needs-another-commit && test_commit foo.bar && git log -M --follow -p foo.bar.t && git log -M --follow --stat foo.bar.t && git log -M --follow --name-only foo.bar.t ) ' test_expect_success 'git log -c --follow' ' test_create_repo follow-c && ( cd follow-c && test_commit initial file original && git rm file && test_commit rename file2 original && git reset --hard initial && test_commit modify file foo && git merge -m merge rename && git log -c --follow file2 ) ' cat >expect <<\EOF * commit COMMIT_OBJECT_NAME |\ Merge: MERGE_PARENTS | | Author: A U Thor | | | | Merge HEADS DESCRIPTION | | | * commit COMMIT_OBJECT_NAME | | Author: A U Thor | | | | reach | | --- | | reach.t | 1 + | | 1 file changed, 1 insertion(+) | | | | diff --git a/reach.t b/reach.t | | new file mode 100644 | | index BEFORE..AFTER | | --- /dev/null | | +++ b/reach.t | | @@ -0,0 +1 @@ | | +reach | | | \ *-. \ commit COMMIT_OBJECT_NAME |\ \ \ Merge: MERGE_PARENTS | | | | Author: A U Thor | | | | | | | | Merge HEADS DESCRIPTION | | | | | | * | commit COMMIT_OBJECT_NAME | | |/ Author: A U Thor | | | | | | octopus-b | | | --- | | | octopus-b.t | 1 + | | | 1 file changed, 1 insertion(+) | | | | | | diff --git a/octopus-b.t b/octopus-b.t | | | new file mode 100644 | | | index BEFORE..AFTER | | | --- /dev/null | | | +++ b/octopus-b.t | | | @@ -0,0 +1 @@ | | | +octopus-b | | | | * | commit COMMIT_OBJECT_NAME | |/ Author: A U Thor | | | | octopus-a | | --- | | octopus-a.t | 1 + | | 1 file changed, 1 insertion(+) | | | | diff --git a/octopus-a.t b/octopus-a.t | | new file mode 100644 | | index BEFORE..AFTER | | --- /dev/null | | +++ b/octopus-a.t | | @@ -0,0 +1 @@ | | +octopus-a | | * | commit COMMIT_OBJECT_NAME |/ Author: A U Thor | | seventh | --- | seventh.t | 1 + | 1 file changed, 1 insertion(+) | | diff --git a/seventh.t b/seventh.t | new file mode 100644 | index BEFORE..AFTER | --- /dev/null | +++ b/seventh.t | @@ -0,0 +1 @@ | +seventh | * commit COMMIT_OBJECT_NAME |\ Merge: MERGE_PARENTS | | Author: A U Thor | | | | Merge branch 'tangle' | | | * commit COMMIT_OBJECT_NAME | |\ Merge: MERGE_PARENTS | | | Author: A U Thor | | | | | | Merge branch 'side' (early part) into tangle | | | | * | commit COMMIT_OBJECT_NAME | |\ \ Merge: MERGE_PARENTS | | | | Author: A U Thor | | | | | | | | Merge branch 'main' (early part) into tangle | | | | | * | | commit COMMIT_OBJECT_NAME | | | | Author: A U Thor | | | | | | | | tangle-a | | | | --- | | | | tangle-a | 1 + | | | | 1 file changed, 1 insertion(+) | | | | | | | | diff --git a/tangle-a b/tangle-a | | | | new file mode 100644 | | | | index BEFORE..AFTER | | | | --- /dev/null | | | | +++ b/tangle-a | | | | @@ -0,0 +1 @@ | | | | +a | | | | * | | | commit COMMIT_OBJECT_NAME |\ \ \ \ Merge: MERGE_PARENTS | | | | | Author: A U Thor | | | | | | | | | | Merge branch 'side' | | | | | | * | | | commit COMMIT_OBJECT_NAME | | |_|/ Author: A U Thor | |/| | | | | | side-2 | | | | --- | | | | 2 | 1 + | | | | 1 file changed, 1 insertion(+) | | | | | | | | diff --git a/2 b/2 | | | | new file mode 100644 | | | | index BEFORE..AFTER | | | | --- /dev/null | | | | +++ b/2 | | | | @@ -0,0 +1 @@ | | | | +2 | | | | | * | | commit COMMIT_OBJECT_NAME | | | | Author: A U Thor | | | | | | | | side-1 | | | | --- | | | | 1 | 1 + | | | | 1 file changed, 1 insertion(+) | | | | | | | | diff --git a/1 b/1 | | | | new file mode 100644 | | | | index BEFORE..AFTER | | | | --- /dev/null | | | | +++ b/1 | | | | @@ -0,0 +1 @@ | | | | +1 | | | | * | | | commit COMMIT_OBJECT_NAME | | | | Author: A U Thor | | | | | | | | Second | | | | --- | | | | one | 1 + | | | | 1 file changed, 1 insertion(+) | | | | | | | | diff --git a/one b/one | | | | new file mode 100644 | | | | index BEFORE..AFTER | | | | --- /dev/null | | | | +++ b/one | | | | @@ -0,0 +1 @@ | | | | +case | | | | * | | | commit COMMIT_OBJECT_NAME | |_|/ Author: A U Thor |/| | | | | sixth | | | --- | | | a/two | 1 - | | | 1 file changed, 1 deletion(-) | | | | | | diff --git a/a/two b/a/two | | | deleted file mode 100644 | | | index BEFORE..AFTER | | | --- a/a/two | | | +++ /dev/null | | | @@ -1 +0,0 @@ | | | -ni | | | * | | commit COMMIT_OBJECT_NAME | | | Author: A U Thor | | | | | | fifth | | | --- | | | a/two | 1 + | | | 1 file changed, 1 insertion(+) | | | | | | diff --git a/a/two b/a/two | | | new file mode 100644 | | | index BEFORE..AFTER | | | --- /dev/null | | | +++ b/a/two | | | @@ -0,0 +1 @@ | | | +ni | | | * | | commit COMMIT_OBJECT_NAME |/ / Author: A U Thor | | | | fourth | | --- | | ein | 1 + | | 1 file changed, 1 insertion(+) | | | | diff --git a/ein b/ein | | new file mode 100644 | | index BEFORE..AFTER | | --- /dev/null | | +++ b/ein | | @@ -0,0 +1 @@ | | +ichi | | * | commit COMMIT_OBJECT_NAME |/ Author: A U Thor | | third | --- | ichi | 1 + | one | 1 - | 2 files changed, 1 insertion(+), 1 deletion(-) | | diff --git a/ichi b/ichi | new file mode 100644 | index BEFORE..AFTER | --- /dev/null | +++ b/ichi | @@ -0,0 +1 @@ | +ichi | diff --git a/one b/one | deleted file mode 100644 | index BEFORE..AFTER | --- a/one | +++ /dev/null | @@ -1 +0,0 @@ | -ichi | * commit COMMIT_OBJECT_NAME | Author: A U Thor | | second | --- | one | 2 +- | 1 file changed, 1 insertion(+), 1 deletion(-) | | diff --git a/one b/one | index BEFORE..AFTER 100644 | --- a/one | +++ b/one | @@ -1 +1 @@ | -one | +ichi | * commit COMMIT_OBJECT_NAME Author: A U Thor initial --- one | 1 + 1 file changed, 1 insertion(+) diff --git a/one b/one new file mode 100644 index BEFORE..AFTER --- /dev/null +++ b/one @@ -0,0 +1 @@ +one EOF test_expect_success 'log --graph with diff and stats' ' lib_test_cmp_short_graph --no-renames --stat -p ' cat >expect <<\EOF *** * commit COMMIT_OBJECT_NAME *** |\ Merge: MERGE_PARENTS *** | | Author: A U Thor *** | | *** | | Merge HEADS DESCRIPTION *** | | *** | * commit COMMIT_OBJECT_NAME *** | | Author: A U Thor *** | | *** | | reach *** | | --- *** | | reach.t | 1 + *** | | 1 file changed, 1 insertion(+) *** | | *** | | diff --git a/reach.t b/reach.t *** | | new file mode 100644 *** | | index BEFORE..AFTER *** | | --- /dev/null *** | | +++ b/reach.t *** | | @@ -0,0 +1 @@ *** | | +reach *** | | *** | \ *** *-. \ commit COMMIT_OBJECT_NAME *** |\ \ \ Merge: MERGE_PARENTS *** | | | | Author: A U Thor *** | | | | *** | | | | Merge HEADS DESCRIPTION *** | | | | *** | | * | commit COMMIT_OBJECT_NAME *** | | |/ Author: A U Thor *** | | | *** | | | octopus-b *** | | | --- *** | | | octopus-b.t | 1 + *** | | | 1 file changed, 1 insertion(+) *** | | | *** | | | diff --git a/octopus-b.t b/octopus-b.t *** | | | new file mode 100644 *** | | | index BEFORE..AFTER *** | | | --- /dev/null *** | | | +++ b/octopus-b.t *** | | | @@ -0,0 +1 @@ *** | | | +octopus-b *** | | | *** | * | commit COMMIT_OBJECT_NAME *** | |/ Author: A U Thor *** | | *** | | octopus-a *** | | --- *** | | octopus-a.t | 1 + *** | | 1 file changed, 1 insertion(+) *** | | *** | | diff --git a/octopus-a.t b/octopus-a.t *** | | new file mode 100644 *** | | index BEFORE..AFTER *** | | --- /dev/null *** | | +++ b/octopus-a.t *** | | @@ -0,0 +1 @@ *** | | +octopus-a *** | | *** * | commit COMMIT_OBJECT_NAME *** |/ Author: A U Thor *** | *** | seventh *** | --- *** | seventh.t | 1 + *** | 1 file changed, 1 insertion(+) *** | *** | diff --git a/seventh.t b/seventh.t *** | new file mode 100644 *** | index BEFORE..AFTER *** | --- /dev/null *** | +++ b/seventh.t *** | @@ -0,0 +1 @@ *** | +seventh *** | *** * commit COMMIT_OBJECT_NAME *** |\ Merge: MERGE_PARENTS *** | | Author: A U Thor *** | | *** | | Merge branch 'tangle' *** | | *** | * commit COMMIT_OBJECT_NAME *** | |\ Merge: MERGE_PARENTS *** | | | Author: A U Thor *** | | | *** | | | Merge branch 'side' (early part) into tangle *** | | | *** | * | commit COMMIT_OBJECT_NAME *** | |\ \ Merge: MERGE_PARENTS *** | | | | Author: A U Thor *** | | | | *** | | | | Merge branch 'main' (early part) into tangle *** | | | | *** | * | | commit COMMIT_OBJECT_NAME *** | | | | Author: A U Thor *** | | | | *** | | | | tangle-a *** | | | | --- *** | | | | tangle-a | 1 + *** | | | | 1 file changed, 1 insertion(+) *** | | | | *** | | | | diff --git a/tangle-a b/tangle-a *** | | | | new file mode 100644 *** | | | | index BEFORE..AFTER *** | | | | --- /dev/null *** | | | | +++ b/tangle-a *** | | | | @@ -0,0 +1 @@ *** | | | | +a *** | | | | *** * | | | commit COMMIT_OBJECT_NAME *** |\ \ \ \ Merge: MERGE_PARENTS *** | | | | | Author: A U Thor *** | | | | | *** | | | | | Merge branch 'side' *** | | | | | *** | * | | | commit COMMIT_OBJECT_NAME *** | | |_|/ Author: A U Thor *** | |/| | *** | | | | side-2 *** | | | | --- *** | | | | 2 | 1 + *** | | | | 1 file changed, 1 insertion(+) *** | | | | *** | | | | diff --git a/2 b/2 *** | | | | new file mode 100644 *** | | | | index BEFORE..AFTER *** | | | | --- /dev/null *** | | | | +++ b/2 *** | | | | @@ -0,0 +1 @@ *** | | | | +2 *** | | | | *** | * | | commit COMMIT_OBJECT_NAME *** | | | | Author: A U Thor *** | | | | *** | | | | side-1 *** | | | | --- *** | | | | 1 | 1 + *** | | | | 1 file changed, 1 insertion(+) *** | | | | *** | | | | diff --git a/1 b/1 *** | | | | new file mode 100644 *** | | | | index BEFORE..AFTER *** | | | | --- /dev/null *** | | | | +++ b/1 *** | | | | @@ -0,0 +1 @@ *** | | | | +1 *** | | | | *** * | | | commit COMMIT_OBJECT_NAME *** | | | | Author: A U Thor *** | | | | *** | | | | Second *** | | | | --- *** | | | | one | 1 + *** | | | | 1 file changed, 1 insertion(+) *** | | | | *** | | | | diff --git a/one b/one *** | | | | new file mode 100644 *** | | | | index BEFORE..AFTER *** | | | | --- /dev/null *** | | | | +++ b/one *** | | | | @@ -0,0 +1 @@ *** | | | | +case *** | | | | *** * | | | commit COMMIT_OBJECT_NAME *** | |_|/ Author: A U Thor *** |/| | *** | | | sixth *** | | | --- *** | | | a/two | 1 - *** | | | 1 file changed, 1 deletion(-) *** | | | *** | | | diff --git a/a/two b/a/two *** | | | deleted file mode 100644 *** | | | index BEFORE..AFTER *** | | | --- a/a/two *** | | | +++ /dev/null *** | | | @@ -1 +0,0 @@ *** | | | -ni *** | | | *** * | | commit COMMIT_OBJECT_NAME *** | | | Author: A U Thor *** | | | *** | | | fifth *** | | | --- *** | | | a/two | 1 + *** | | | 1 file changed, 1 insertion(+) *** | | | *** | | | diff --git a/a/two b/a/two *** | | | new file mode 100644 *** | | | index BEFORE..AFTER *** | | | --- /dev/null *** | | | +++ b/a/two *** | | | @@ -0,0 +1 @@ *** | | | +ni *** | | | *** * | | commit COMMIT_OBJECT_NAME *** |/ / Author: A U Thor *** | | *** | | fourth *** | | --- *** | | ein | 1 + *** | | 1 file changed, 1 insertion(+) *** | | *** | | diff --git a/ein b/ein *** | | new file mode 100644 *** | | index BEFORE..AFTER *** | | --- /dev/null *** | | +++ b/ein *** | | @@ -0,0 +1 @@ *** | | +ichi *** | | *** * | commit COMMIT_OBJECT_NAME *** |/ Author: A U Thor *** | *** | third *** | --- *** | ichi | 1 + *** | one | 1 - *** | 2 files changed, 1 insertion(+), 1 deletion(-) *** | *** | diff --git a/ichi b/ichi *** | new file mode 100644 *** | index BEFORE..AFTER *** | --- /dev/null *** | +++ b/ichi *** | @@ -0,0 +1 @@ *** | +ichi *** | diff --git a/one b/one *** | deleted file mode 100644 *** | index BEFORE..AFTER *** | --- a/one *** | +++ /dev/null *** | @@ -1 +0,0 @@ *** | -ichi *** | *** * commit COMMIT_OBJECT_NAME *** | Author: A U Thor *** | *** | second *** | --- *** | one | 2 +- *** | 1 file changed, 1 insertion(+), 1 deletion(-) *** | *** | diff --git a/one b/one *** | index BEFORE..AFTER 100644 *** | --- a/one *** | +++ b/one *** | @@ -1 +1 @@ *** | -one *** | +ichi *** | *** * commit COMMIT_OBJECT_NAME *** Author: A U Thor *** *** initial *** --- *** one | 1 + *** 1 file changed, 1 insertion(+) *** *** diff --git a/one b/one *** new file mode 100644 *** index BEFORE..AFTER *** --- /dev/null *** +++ b/one *** @@ -0,0 +1 @@ *** +one EOF test_expect_success 'log --line-prefix="*** " --graph with diff and stats' ' lib_test_cmp_short_graph --line-prefix="*** " --no-renames --stat -p ' cat >expect <<-\EOF * reach | | A reach.t * Merge branch 'tangle' * Merge branch 'side' |\ | * side-2 | | A 2 * Second | | A one * sixth D a/two EOF test_expect_success 'log --graph with --name-status' ' test_cmp_graph --name-status tangle..reach ' cat >expect <<-\EOF * reach | | reach.t * Merge branch 'tangle' * Merge branch 'side' |\ | * side-2 | | 2 * Second | | one * sixth a/two EOF test_expect_success 'log --graph with --name-only' ' test_cmp_graph --name-only tangle..reach ' test_expect_success '--no-graph countermands --graph' ' git log >expect && git log --graph --no-graph >actual && test_cmp expect actual ' test_expect_success '--graph countermands --no-graph' ' git log --graph >expect && git log --no-graph --graph >actual && test_cmp expect actual ' test_expect_success '--no-graph does not unset --topo-order' ' git log --topo-order >expect && git log --topo-order --no-graph >actual && test_cmp expect actual ' test_expect_success '--no-graph does not unset --parents' ' git log --parents >expect && git log --parents --no-graph >actual && test_cmp expect actual ' test_expect_success '--reverse and --graph conflict' ' test_must_fail git log --reverse --graph 2>stderr && test_i18ngrep "cannot be used together" stderr ' test_expect_success '--reverse --graph --no-graph works' ' git log --reverse >expect && git log --reverse --graph --no-graph >actual && test_cmp expect actual ' test_expect_success '--show-linear-break and --graph conflict' ' test_must_fail git log --show-linear-break --graph 2>stderr && test_i18ngrep "cannot be used together" stderr ' test_expect_success '--show-linear-break --graph --no-graph works' ' git log --show-linear-break >expect && git log --show-linear-break --graph --no-graph >actual && test_cmp expect actual ' test_expect_success '--no-walk and --graph conflict' ' test_must_fail git log --no-walk --graph 2>stderr && test_i18ngrep "cannot be used together" stderr ' test_expect_success '--no-walk --graph --no-graph works' ' git log --no-walk >expect && git log --no-walk --graph --no-graph >actual && test_cmp expect actual ' test_expect_success '--walk-reflogs and --graph conflict' ' test_must_fail git log --walk-reflogs --graph 2>stderr && (test_i18ngrep "cannot combine" stderr || test_i18ngrep "cannot be used together" stderr) ' test_expect_success '--walk-reflogs --graph --no-graph works' ' git log --walk-reflogs >expect && git log --walk-reflogs --graph --no-graph >actual && test_cmp expect actual ' test_expect_success 'dotdot is a parent directory' ' mkdir -p a/b && ( echo sixth && echo fifth ) >expect && ( cd a/b && git log --format=%s .. ) >actual && test_cmp expect actual ' test_expect_success GPG 'setup signed branch' ' test_when_finished "git reset --hard && git checkout main" && git checkout -b signed main && echo foo >foo && git add foo && git commit -S -m signed_commit ' test_expect_success GPG 'setup signed branch with subkey' ' test_when_finished "git reset --hard && git checkout main" && git checkout -b signed-subkey main && echo foo >foo && git add foo && git commit -SB7227189 -m signed_commit ' test_expect_success GPGSM 'setup signed branch x509' ' test_when_finished "git reset --hard && git checkout main" && git checkout -b signed-x509 main && echo foo >foo && git add foo && test_config gpg.format x509 && test_config user.signingkey $GIT_COMMITTER_EMAIL && git commit -S -m signed_commit ' test_expect_success GPGSSH 'setup sshkey signed branch' ' test_config gpg.format ssh && test_config user.signingkey "${GPGSSH_KEY_PRIMARY}" && test_when_finished "git reset --hard && git checkout main" && git checkout -b signed-ssh main && echo foo >foo && git add foo && git commit -S -m signed_commit ' test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'create signed commits with keys having defined lifetimes' ' test_config gpg.format ssh && touch file && git add file && echo expired >file && test_tick && git commit -a -m expired -S"${GPGSSH_KEY_EXPIRED}" && git tag expired-signed && echo notyetvalid >file && test_tick && git commit -a -m notyetvalid -S"${GPGSSH_KEY_NOTYETVALID}" && git tag notyetvalid-signed && echo timeboxedvalid >file && test_tick && git commit -a -m timeboxedvalid -S"${GPGSSH_KEY_TIMEBOXEDVALID}" && git tag timeboxedvalid-signed && echo timeboxedinvalid >file && test_tick && git commit -a -m timeboxedinvalid -S"${GPGSSH_KEY_TIMEBOXEDINVALID}" && git tag timeboxedinvalid-signed ' test_expect_success GPGSM 'log x509 fingerprint' ' echo "F8BF62E0693D0694816377099909C779FA23FD65 | " >expect && git log -n1 --format="%GF | %GP" signed-x509 >actual && test_cmp expect actual ' test_expect_success GPGSM 'log OpenPGP fingerprint' ' echo "D4BE22311AD3131E5EDA29A461092E85B7227189" > expect && git log -n1 --format="%GP" signed-subkey >actual && test_cmp expect actual ' test_expect_success GPGSSH 'log ssh key fingerprint' ' test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && ssh-keygen -lf "${GPGSSH_KEY_PRIMARY}" | awk "{print \$2\" | \"}" >expect && git log -n1 --format="%GF | %GP" signed-ssh >actual && test_cmp expect actual ' test_expect_success GPG 'log --graph --show-signature' ' git log --graph --show-signature -n1 signed >actual && grep "^| gpg: Signature made" actual && grep "^| gpg: Good signature" actual ' test_expect_success GPGSM 'log --graph --show-signature x509' ' git log --graph --show-signature -n1 signed-x509 >actual && grep "^| gpgsm: Signature made" actual && grep "^| gpgsm: Good signature" actual ' test_expect_success GPGSSH 'log --graph --show-signature ssh' ' test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && git log --graph --show-signature -n1 signed-ssh >actual && grep "${GOOD_SIGNATURE_TRUSTED}" actual ' test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'log shows failure on expired signature key' ' test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && git log --graph --show-signature -n1 expired-signed >actual && ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual ' test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'log shows failure on not yet valid signature key' ' test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && git log --graph --show-signature -n1 notyetvalid-signed >actual && ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual ' test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'log show success with commit date and key validity matching' ' test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && git log --graph --show-signature -n1 timeboxedvalid-signed >actual && grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual && ! grep "${GPGSSH_BAD_SIGNATURE}" actual ' test_expect_success GPGSSH,GPGSSH_VERIFYTIME 'log shows failure with commit date outside of key validity' ' test_config gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" && git log --graph --show-signature -n1 timeboxedinvalid-signed >actual && ! grep "${GPGSSH_GOOD_SIGNATURE_TRUSTED}" actual ' test_expect_success GPG 'log --graph --show-signature for merged tag' ' test_when_finished "git reset --hard && git checkout main" && git checkout -b plain main && echo aaa >bar && git add bar && git commit -m bar_commit && git checkout -b tagged main && echo bbb >baz && git add baz && git commit -m baz_commit && git tag -s -m signed_tag_msg signed_tag && git checkout plain && git merge --no-ff -m msg signed_tag && git log --graph --show-signature -n1 plain >actual && grep "^|\\\ merged tag" actual && grep "^| | gpg: Signature made" actual && grep "^| | gpg: Good signature" actual ' test_expect_success GPG 'log --graph --show-signature for merged tag in shallow clone' ' test_when_finished "git reset --hard && git checkout main" && git checkout -b plain-shallow main && echo aaa >bar && git add bar && git commit -m bar_commit && git checkout --detach main && echo bbb >baz && git add baz && git commit -m baz_commit && git tag -s -m signed_tag_msg signed_tag_shallow && hash=$(git rev-parse HEAD) && git checkout plain-shallow && git merge --no-ff -m msg signed_tag_shallow && git clone --depth 1 --no-local . shallow && test_when_finished "rm -rf shallow" && git -C shallow log --graph --show-signature -n1 plain-shallow >actual && grep "tag signed_tag_shallow names a non-parent $hash" actual ' test_expect_success GPG 'log --graph --show-signature for merged tag with missing key' ' test_when_finished "git reset --hard && git checkout main" && git checkout -b plain-nokey main && echo aaa >bar && git add bar && git commit -m bar_commit && git checkout -b tagged-nokey main && echo bbb >baz && git add baz && git commit -m baz_commit && git tag -s -m signed_tag_msg signed_tag_nokey && git checkout plain-nokey && git merge --no-ff -m msg signed_tag_nokey && GNUPGHOME=. git log --graph --show-signature -n1 plain-nokey >actual && grep "^|\\\ merged tag" actual && grep "^| | gpg: Signature made" actual && grep -E "^| | gpg: Can'"'"'t check signature: (public key not found|No public key)" actual ' test_expect_success GPG 'log --graph --show-signature for merged tag with bad signature' ' test_when_finished "git reset --hard && git checkout main" && git checkout -b plain-bad main && echo aaa >bar && git add bar && git commit -m bar_commit && git checkout -b tagged-bad main && echo bbb >baz && git add baz && git commit -m baz_commit && git tag -s -m signed_tag_msg signed_tag_bad && git cat-file tag signed_tag_bad >raw && sed -e "s/signed_tag_msg/forged/" raw >forged && git hash-object -w -t tag forged >forged.tag && git checkout plain-bad && git merge --no-ff -m msg "$(cat forged.tag)" && git log --graph --show-signature -n1 plain-bad >actual && grep "^|\\\ merged tag" actual && grep "^| | gpg: Signature made" actual && grep "^| | gpg: BAD signature from" actual ' test_expect_success GPG 'log --show-signature for merged tag with GPG failure' ' test_when_finished "git reset --hard && git checkout main" && git checkout -b plain-fail main && echo aaa >bar && git add bar && git commit -m bar_commit && git checkout -b tagged-fail main && echo bbb >baz && git add baz && git commit -m baz_commit && git tag -s -m signed_tag_msg signed_tag_fail && git checkout plain-fail && git merge --no-ff -m msg signed_tag_fail && if ! test_have_prereq VALGRIND then TMPDIR="$(pwd)/bogus" git log --show-signature -n1 plain-fail >actual && grep "^merged tag" actual && grep "^No signature" actual && ! grep "^gpg: Signature made" actual fi ' test_expect_success GPGSM 'log --graph --show-signature for merged tag x509' ' test_when_finished "git reset --hard && git checkout main" && test_config gpg.format x509 && test_config user.signingkey $GIT_COMMITTER_EMAIL && git checkout -b plain-x509 main && echo aaa >bar && git add bar && git commit -m bar_commit && git checkout -b tagged-x509 main && echo bbb >baz && git add baz && git commit -m baz_commit && git tag -s -m signed_tag_msg signed_tag_x509 && git checkout plain-x509 && git merge --no-ff -m msg signed_tag_x509 && git log --graph --show-signature -n1 plain-x509 >actual && grep "^|\\\ merged tag" actual && grep "^| | gpgsm: Signature made" actual && grep "^| | gpgsm: Good signature" actual ' test_expect_success GPGSM 'log --graph --show-signature for merged tag x509 missing key' ' test_when_finished "git reset --hard && git checkout main" && test_config gpg.format x509 && test_config user.signingkey $GIT_COMMITTER_EMAIL && git checkout -b plain-x509-nokey main && echo aaa >bar && git add bar && git commit -m bar_commit && git checkout -b tagged-x509-nokey main && echo bbb >baz && git add baz && git commit -m baz_commit && git tag -s -m signed_tag_msg signed_tag_x509_nokey && git checkout plain-x509-nokey && git merge --no-ff -m msg signed_tag_x509_nokey && GNUPGHOME=. git log --graph --show-signature -n1 plain-x509-nokey >actual && grep "^|\\\ merged tag" actual && grep -e "^| | gpgsm: certificate not found" \ -e "^| | gpgsm: failed to find the certificate: Not found" actual ' test_expect_success GPGSM 'log --graph --show-signature for merged tag x509 bad signature' ' test_when_finished "git reset --hard && git checkout main" && test_config gpg.format x509 && test_config user.signingkey $GIT_COMMITTER_EMAIL && git checkout -b plain-x509-bad main && echo aaa >bar && git add bar && git commit -m bar_commit && git checkout -b tagged-x509-bad main && echo bbb >baz && git add baz && git commit -m baz_commit && git tag -s -m signed_tag_msg signed_tag_x509_bad && git cat-file tag signed_tag_x509_bad >raw && sed -e "s/signed_tag_msg/forged/" raw >forged && git hash-object -w -t tag forged >forged.tag && git checkout plain-x509-bad && git merge --no-ff -m msg "$(cat forged.tag)" && git log --graph --show-signature -n1 plain-x509-bad >actual && grep "^|\\\ merged tag" actual && grep "^| | gpgsm: Signature made" actual && grep "^| | gpgsm: invalid signature" actual ' test_expect_success GPG '--no-show-signature overrides --show-signature' ' git log -1 --show-signature --no-show-signature signed >actual && ! grep "^gpg:" actual ' test_expect_success GPG 'log.showsignature=true behaves like --show-signature' ' test_config log.showsignature true && git log -1 signed >actual && grep "gpg: Signature made" actual && grep "gpg: Good signature" actual ' test_expect_success GPG '--no-show-signature overrides log.showsignature=true' ' test_config log.showsignature true && git log -1 --no-show-signature signed >actual && ! grep "^gpg:" actual ' test_expect_success GPG '--show-signature overrides log.showsignature=false' ' test_config log.showsignature false && git log -1 --show-signature signed >actual && grep "gpg: Signature made" actual && grep "gpg: Good signature" actual ' test_expect_success 'log --graph --no-walk is forbidden' ' test_must_fail git log --graph --no-walk ' test_expect_success 'log on empty repo fails' ' git init empty && test_when_finished "rm -rf empty" && test_must_fail git -C empty log 2>stderr && test_i18ngrep does.not.have.any.commits stderr ' test_expect_success REFFILES 'log diagnoses bogus HEAD hash' ' git init empty && test_when_finished "rm -rf empty" && echo 1234abcd >empty/.git/refs/heads/main && test_must_fail git -C empty log 2>stderr && test_i18ngrep broken stderr ' test_expect_success REFFILES 'log diagnoses bogus HEAD symref' ' git init empty && echo "ref: refs/heads/invalid.lock" > empty/.git/HEAD && test_must_fail git -C empty log 2>stderr && test_i18ngrep broken stderr && test_must_fail git -C empty log --default totally-bogus 2>stderr && test_i18ngrep broken stderr ' test_expect_success 'log does not default to HEAD when rev input is given' ' git log --branches=does-not-exist >actual && test_must_be_empty actual ' test_expect_success 'do not default to HEAD with ignored object on cmdline' ' git log --ignore-missing $ZERO_OID >actual && test_must_be_empty actual ' test_expect_success 'do not default to HEAD with ignored object on stdin' ' echo $ZERO_OID | git log --ignore-missing --stdin >actual && test_must_be_empty actual ' test_expect_success 'set up --source tests' ' git checkout --orphan source-a && test_commit one && test_commit two && git checkout -b source-b HEAD^ && test_commit three ' test_expect_success 'log --source paints branch names' ' cat >expect <<-EOF && $(git rev-parse --short :/three) source-b three $(git rev-parse --short :/two ) source-a two $(git rev-parse --short :/one ) source-b one EOF git log --oneline --source source-a source-b >actual && test_cmp expect actual ' test_expect_success 'log --source paints tag names' ' git tag -m tagged source-tag && cat >expect <<-EOF && $(git rev-parse --short :/three) source-tag three $(git rev-parse --short :/two ) source-a two $(git rev-parse --short :/one ) source-tag one EOF git log --oneline --source source-tag source-a >actual && test_cmp expect actual ' test_expect_success 'log --source paints symmetric ranges' ' cat >expect <<-EOF && $(git rev-parse --short :/three) source-b three $(git rev-parse --short :/two ) source-a two EOF git log --oneline --source source-a...source-b >actual && test_cmp expect actual ' test_expect_success '--exclude-promisor-objects does not BUG-crash' ' test_must_fail git log --exclude-promisor-objects source-a ' test_expect_success 'log --decorate includes all levels of tag annotated tags' ' git checkout -b branch && git commit --allow-empty -m "new commit" && git tag lightweight HEAD && git tag -m annotated annotated HEAD && git tag -m double-0 double-0 HEAD && git tag -m double-1 double-1 double-0 && cat >expect <<-\EOF && HEAD -> branch, tag: lightweight, tag: double-1, tag: double-0, tag: annotated EOF git log -1 --format="%D" >actual && test_cmp expect actual ' test_expect_success 'log --end-of-options' ' git update-ref refs/heads/--source HEAD && git log --end-of-options --source >actual && git log >expect && test_cmp expect actual ' test_expect_success 'set up commits with different authors' ' git checkout --orphan authors && test_commit --author "Jim " jim_1 && test_commit --author "Val " val_1 && test_commit --author "Val " val_2 && test_commit --author "Jim " jim_2 && test_commit --author "Val " val_3 && test_commit --author "Jim " jim_3 ' test_expect_success 'log --invert-grep --grep --author' ' cat >expect <<-\EOF && val_3 val_1 EOF git log --format=%s --author=Val --grep 2 --invert-grep >actual && test_cmp expect actual ' test_done