diff options
author | Junio C Hamano <gitster@pobox.com> | 2013-07-22 11:23:53 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2013-07-22 11:23:53 -0700 |
commit | e9682cc028e4d360dcf1364691095accc75f4b74 (patch) | |
tree | e63f065122dc868da2a7c0dc1f5e90e1980c831a | |
parent | Merge branch 'tr/protect-low-3-fds' (diff) | |
parent | blame-options.txt: explain that -L <start> and <end> are optional (diff) | |
download | tgif-e9682cc028e4d360dcf1364691095accc75f4b74.tar.xz |
Merge branch 'es/blame-L-breakage'
The refactoring made for parsing "-L" option recently to support
"git log -L" seems to have broken "git blame -L X,-5" to show 5
lines leading to X.
* es/blame-L-breakage:
blame-options.txt: explain that -L <start> and <end> are optional
blame-options.txt: place each -L option variation on its own line
t8001/t8002 (blame): add blame -L :funcname tests
t8001/t8002 (blame): add blame -L tests
t8001/t8002 (blame): modernize style
line-range: fix "blame -L X,-N" regression
-rw-r--r-- | Documentation/blame-options.txt | 10 | ||||
-rw-r--r-- | line-range.c | 7 | ||||
-rw-r--r-- | t/annotate-tests.sh | 363 | ||||
-rwxr-xr-x | t/t8001-annotate.sh | 6 | ||||
-rwxr-xr-x | t/t8002-blame.sh | 12 |
5 files changed, 283 insertions, 115 deletions
diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt index e9f984ba01..4e55b1564e 100644 --- a/Documentation/blame-options.txt +++ b/Documentation/blame-options.txt @@ -9,9 +9,13 @@ --show-stats:: Include additional statistics at the end of blame output. --L <start>,<end>, -L :<regex>:: - Annotate only the given line range. <start> and <end> can take - one of these forms: +-L <start>,<end>:: +-L :<regex>:: + Annotate only the given line range. <start> and <end> are optional. + ``-L <start>'' or ``-L <start>,'' spans from <start> to end of file. + ``-L ,<end>'' spans from start of file to <end>. ++ +<start> and <end> can take one of these forms: include::line-range-format.txt[] diff --git a/line-range.c b/line-range.c index 8faf943745..3942475c2f 100644 --- a/line-range.c +++ b/line-range.c @@ -211,6 +211,8 @@ int parse_range_arg(const char *arg, nth_line_fn_t nth_line_cb, void *cb_data, long lines, long *begin, long *end, const char *path) { + *begin = *end = 0; + if (*arg == ':') { arg = parse_range_funcname(arg, nth_line_cb, cb_data, lines, begin, end, path); if (!arg || *arg) @@ -226,6 +228,11 @@ int parse_range_arg(const char *arg, nth_line_fn_t nth_line_cb, if (*arg) return -1; + if (*begin && *end && *end < *begin) { + long tmp; + tmp = *end; *end = *begin; *begin = tmp; + } + return 0; } diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index c56a77d237..0bfee001b4 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -2,11 +2,21 @@ # sourced from t8001-annotate.sh and t8002-blame.sh. check_count () { - head= - case "$1" in -h) head="$2"; shift; shift ;; esac - echo "$PROG file $head" >&4 - $PROG file $head >.result || return 1 - cat .result | perl -e ' + head= && + file='file' && + options= && + while : + do + case "$1" in + -h) head="$2"; shift; shift ;; + -f) file="$2"; shift; shift ;; + -*) options="$options $1"; shift ;; + *) break ;; + esac + done && + echo "$PROG $options $file $head" >&4 && + $PROG $options $file $head >actual && + perl -e ' my %expect = (@ARGV); my %count = map { $_ => 0 } keys %expect; while (<STDIN>) { @@ -31,107 +41,246 @@ check_count () { print STDERR "Author $author (expected $value, attributed $count) $ok\n"; } exit($bad); - ' "$@" + ' "$@" <actual } -test_expect_success \ - 'prepare reference tree' \ - 'echo "1A quick brown fox jumps over the" >file && - echo "lazy dog" >>file && - git add file && - GIT_AUTHOR_NAME="A" GIT_AUTHOR_EMAIL="A@test.git" git commit -a -m "Initial."' - -test_expect_success \ - 'check all lines blamed on A' \ - 'check_count A 2' - -test_expect_success \ - 'Setup new lines blamed on B' \ - 'echo "2A quick brown fox jumps over the" >>file && - echo "lazy dog" >> file && - GIT_AUTHOR_NAME="B" GIT_AUTHOR_EMAIL="B@test.git" git commit -a -m "Second."' - -test_expect_success \ - 'Two lines blamed on A, two on B' \ - 'check_count A 2 B 2' - -test_expect_success \ - 'merge-setup part 1' \ - 'git checkout -b branch1 master && - echo "3A slow green fox jumps into the" >> file && - echo "well." >> file && - GIT_AUTHOR_NAME="B1" GIT_AUTHOR_EMAIL="B1@test.git" git commit -a -m "Branch1-1"' - -test_expect_success \ - 'Two lines blamed on A, two on B, two on B1' \ - 'check_count A 2 B 2 B1 2' - -test_expect_success \ - 'merge-setup part 2' \ - 'git checkout -b branch2 master && - sed -e "s/2A quick brown/4A quick brown lazy dog/" < file > file.new && - mv file.new file && - GIT_AUTHOR_NAME="B2" GIT_AUTHOR_EMAIL="B2@test.git" git commit -a -m "Branch2-1"' - -test_expect_success \ - 'Two lines blamed on A, one on B, one on B2' \ - 'check_count A 2 B 1 B2 1' - -test_expect_success \ - 'merge-setup part 3' \ - 'git pull . branch1' - -test_expect_success \ - 'Two lines blamed on A, one on B, two on B1, one on B2' \ - 'check_count A 2 B 1 B1 2 B2 1' - -test_expect_success \ - 'Annotating an old revision works' \ - 'check_count -h master A 2 B 2' - -test_expect_success \ - 'Annotating an old revision works' \ - 'check_count -h master^ A 2' - -test_expect_success \ - 'merge-setup part 4' \ - 'echo "evil merge." >>file && - git commit -a --amend' - -test_expect_success \ - 'Two lines blamed on A, one on B, two on B1, one on B2, one on A U Thor' \ - 'check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1' - -test_expect_success \ - 'an incomplete line added' \ - 'echo "incomplete" | tr -d "\\012" >>file && - GIT_AUTHOR_NAME="C" GIT_AUTHOR_EMAIL="C@test.git" git commit -a -m "Incomplete"' - -test_expect_success \ - 'With incomplete lines.' \ - 'check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1 C 1' - -test_expect_success \ - 'some edit' \ - 'mv file file.orig && - { - cat file.orig && - echo - } | sed -e "s/^3A/99/" -e "/^1A/d" -e "/^incomplete/d" > file && - echo "incomplete" | tr -d "\\012" >>file && - GIT_AUTHOR_NAME="D" GIT_AUTHOR_EMAIL="D@test.git" git commit -a -m "edit"' - -test_expect_success \ - 'some edit' \ - 'check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1' - -test_expect_success \ - 'an obfuscated email added' \ - 'echo "No robots allowed" > file.new && - cat file >> file.new && - mv file.new file && - GIT_AUTHOR_NAME="E" GIT_AUTHOR_EMAIL="E at test dot git" git commit -a -m "norobots"' - -test_expect_success \ - 'obfuscated email parsed' \ - 'check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1' +test_expect_success 'setup A lines' ' + echo "1A quick brown fox jumps over the" >file && + echo "lazy dog" >>file && + git add file && + GIT_AUTHOR_NAME="A" GIT_AUTHOR_EMAIL="A@test.git" \ + git commit -a -m "Initial." +' + +test_expect_success 'blame 1 author' ' + check_count A 2 +' + +test_expect_success 'setup B lines' ' + echo "2A quick brown fox jumps over the" >>file && + echo "lazy dog" >>file && + GIT_AUTHOR_NAME="B" GIT_AUTHOR_EMAIL="B@test.git" \ + git commit -a -m "Second." +' + +test_expect_success 'blame 2 authors' ' + check_count A 2 B 2 +' + +test_expect_success 'setup B1 lines (branch1)' ' + git checkout -b branch1 master && + echo "3A slow green fox jumps into the" >>file && + echo "well." >>file && + GIT_AUTHOR_NAME="B1" GIT_AUTHOR_EMAIL="B1@test.git" \ + git commit -a -m "Branch1-1" +' + +test_expect_success 'blame 2 authors + 1 branch1 author' ' + check_count A 2 B 2 B1 2 +' + +test_expect_success 'setup B2 lines (branch2)' ' + git checkout -b branch2 master && + sed -e "s/2A quick brown/4A quick brown lazy dog/" <file >file.new && + mv file.new file && + GIT_AUTHOR_NAME="B2" GIT_AUTHOR_EMAIL="B2@test.git" \ + git commit -a -m "Branch2-1" +' + +test_expect_success 'blame 2 authors + 1 branch2 author' ' + check_count A 2 B 1 B2 1 +' + +test_expect_success 'merge branch1 & branch2' ' + git pull . branch1 +' + +test_expect_success 'blame 2 authors + 2 merged-in authors' ' + check_count A 2 B 1 B1 2 B2 1 +' + +test_expect_success 'blame ancestor' ' + check_count -h master A 2 B 2 +' + +test_expect_success 'blame great-ancestor' ' + check_count -h master^ A 2 +' + +test_expect_success 'setup evil merge' ' + echo "evil merge." >>file && + git commit -a --amend +' + +test_expect_success 'blame evil merge' ' + check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1 +' + +test_expect_success 'setup incomplete line' ' + echo "incomplete" | tr -d "\\012" >>file && + GIT_AUTHOR_NAME="C" GIT_AUTHOR_EMAIL="C@test.git" \ + git commit -a -m "Incomplete" +' + +test_expect_success 'blame incomplete line' ' + check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1 C 1 +' + +test_expect_success 'setup edits' ' + mv file file.orig && + { + cat file.orig && + echo + } | sed -e "s/^3A/99/" -e "/^1A/d" -e "/^incomplete/d" >file && + echo "incomplete" | tr -d "\\012" >>file && + GIT_AUTHOR_NAME="D" GIT_AUTHOR_EMAIL="D@test.git" \ + git commit -a -m "edit" +' + +test_expect_success 'blame edits' ' + check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 +' + +test_expect_success 'setup obfuscated email' ' + echo "No robots allowed" >file.new && + cat file >>file.new && + mv file.new file && + GIT_AUTHOR_NAME="E" GIT_AUTHOR_EMAIL="E at test dot git" \ + git commit -a -m "norobots" +' + +test_expect_success 'blame obfuscated email' ' + check_count A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1 +' + +test_expect_success 'blame -L 1 (all)' ' + check_count -L1 A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1 +' + +test_expect_success 'blame -L , (all)' ' + check_count -L, A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1 +' + +test_expect_success 'blame -L X (X to end)' ' + check_count -L5 B1 1 C 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L X, (X to end)' ' + check_count -L5, B1 1 C 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L ,Y (up to Y)' ' + check_count -L,3 A 1 B2 1 E 1 +' + +test_expect_success 'blame -L X,X' ' + check_count -L3,3 B2 1 +' + +test_expect_success 'blame -L X,Y' ' + check_count -L3,6 B 1 B1 1 B2 1 D 1 +' + +test_expect_success 'blame -L Y,X (undocumented)' ' + check_count -L6,3 B 1 B1 1 B2 1 D 1 +' + +test_expect_success 'blame -L X,+1' ' + check_count -L3,+1 B2 1 +' + +test_expect_success 'blame -L X,+N' ' + check_count -L3,+4 B 1 B1 1 B2 1 D 1 +' + +test_expect_success 'blame -L X,-1' ' + check_count -L3,-1 B2 1 +' + +test_expect_success 'blame -L X,-N' ' + check_count -L6,-4 B 1 B1 1 B2 1 D 1 +' + +test_expect_success 'blame -L /RE/ (RE to end)' ' + check_count -L/evil/ C 1 "A U Thor" 1 +' + +test_expect_success 'blame -L /RE/,/RE2/' ' + check_count -L/robot/,/green/ A 1 B 1 B2 1 D 1 E 1 +' + +test_expect_success 'blame -L X,/RE/' ' + check_count -L5,/evil/ B1 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L /RE/,Y' ' + check_count -L/99/,7 B1 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L /RE/,+N' ' + check_count -L/99/,+3 B1 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L /RE/,-N' ' + check_count -L/99/,-3 B 1 B2 1 D 1 +' + +test_expect_success 'blame -L X (X > nlines)' ' + test_must_fail $PROG -L12345 file +' + +test_expect_success 'blame -L ,Y (Y > nlines)' ' + test_must_fail $PROG -L,12345 file +' + +test_expect_success 'setup -L :regex' ' + tr Q "\\t" >hello.c <<-\EOF && + int main(int argc, const char *argv[]) + { + Qputs("hello"); + } + EOF + git add hello.c && + GIT_AUTHOR_NAME="F" GIT_AUTHOR_EMAIL="F@test.git" \ + git commit -m "hello" && + + mv hello.c hello.orig && + sed -e "/}/i\\ + Qputs(\"goodbye\");" <hello.orig | tr Q "\\t" >hello.c && + GIT_AUTHOR_NAME="G" GIT_AUTHOR_EMAIL="G@test.git" \ + git commit -a -m "goodbye" && + + mv hello.c hello.orig && + echo "#include <stdio.h>" >hello.c && + cat hello.orig >>hello.c && + tr Q "\\t" >>hello.c <<-\EOF + void mail() + { + Qputs("mail"); + } + EOF + GIT_AUTHOR_NAME="H" GIT_AUTHOR_EMAIL="H@test.git" \ + git commit -a -m "mail" +' + +test_expect_success 'blame -L :literal' ' + check_count -f hello.c -L:main F 4 G 1 +' + +test_expect_success 'blame -L :regex' ' + check_count -f hello.c "-L:m[a-z][a-z]l" H 4 +' + +test_expect_success 'blame -L :nomatch' ' + test_must_fail $PROG -L:nomatch hello.c +' + +test_expect_success 'blame -L bogus' ' + test_must_fail $PROG -L file && + test_must_fail $PROG -L1,+ file && + test_must_fail $PROG -L1,- file && + test_must_fail $PROG -LX file && + test_must_fail $PROG -L1,X file && + test_must_fail $PROG -L1,+N file && + test_must_fail $PROG -L1,-N file +' diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh index 41962f04a7..72176e42c1 100755 --- a/t/t8001-annotate.sh +++ b/t/t8001-annotate.sh @@ -6,9 +6,9 @@ test_description='git annotate' PROG='git annotate' . "$TEST_DIRECTORY"/annotate-tests.sh -test_expect_success 'Annotating an old revision works' ' - git annotate file master >result && - awk "{ print \$3; }" <result >authors && +test_expect_success 'annotate old revision' ' + git annotate file master >actual && + awk "{ print \$3; }" <actual >authors && test 2 = $(grep A <authors | wc -l) && test 2 = $(grep B <authors | wc -l) ' diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh index e2896cffc1..5cdf3f178e 100755 --- a/t/t8002-blame.sh +++ b/t/t8002-blame.sh @@ -7,8 +7,16 @@ PROG='git blame -c' . "$TEST_DIRECTORY"/annotate-tests.sh PROG='git blame -c -e' -test_expect_success 'Blame --show-email works' ' - check_count "<A@test.git>" 1 "<B@test.git>" 1 "<B1@test.git>" 1 "<B2@test.git>" 1 "<author@example.com>" 1 "<C@test.git>" 1 "<D@test.git>" 1 "<E at test dot git>" 1 +test_expect_success 'blame --show-email' ' + check_count \ + "<A@test.git>" 1 \ + "<B@test.git>" 1 \ + "<B1@test.git>" 1 \ + "<B2@test.git>" 1 \ + "<author@example.com>" 1 \ + "<C@test.git>" 1 \ + "<D@test.git>" 1 \ + "<E at test dot git>" 1 ' test_done |