From 3bf65f9e62d25089ca50eb348844d21cdbb53019 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Wed, 17 Jul 2013 17:25:27 -0400 Subject: [PATCH 1/6] line-range: fix "blame -L X,-N" regression "blame -L X,-N" is documented as blaming "N lines ending at X". In practice, the behavior is achieved by swapping the two range endpoints if the second is less than the first. 25ed3412 (Refactor parse_loc; 2013-03-28) broke this interpretation by removing the swapping code from blame.c and failing to add it to line-range.c along with other code relocated from blame.c. Thus, such a range is effectively treated as empty. Fix this regression. Signed-off-by: Eric Sunshine Signed-off-by: Junio C Hamano --- line-range.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/line-range.c b/line-range.c index 8faf94374..3942475c2 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; } From e37f39c134c3621f26fdcdbc22a6b2e4e00de2e5 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Wed, 17 Jul 2013 17:25:28 -0400 Subject: [PATCH 2/6] t8001/t8002 (blame): modernize style In particular, - indent with tabs - cuddle test description and opening body quote with test_expect_foo - normalize test descriptions and case - remove whitepsace following redirection operator - use standardized filenames (such as "actual", "expected") Signed-off-by: Eric Sunshine Signed-off-by: Junio C Hamano --- t/annotate-tests.sh | 221 +++++++++++++++++++++++--------------------- t/t8001-annotate.sh | 6 +- t/t8002-blame.sh | 12 ++- 3 files changed, 127 insertions(+), 112 deletions(-) diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index c56a77d23..3aa696443 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -2,11 +2,11 @@ # 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= && + case "$1" in -h) head="$2"; shift; shift ;; esac && + echo "$PROG file $head" >&4 && + $PROG file $head >actual && + perl -e ' my %expect = (@ARGV); my %count = map { $_ => 0 } keys %expect; while () { @@ -31,107 +31,114 @@ check_count () { print STDERR "Author $author (expected $value, attributed $count) $ok\n"; } exit($bad); - ' "$@" + ' "$@" 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.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 +' diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh index 41962f04a..72176e42c 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; }" authors && +test_expect_success 'annotate old revision' ' + git annotate file master >actual && + awk "{ print \$3; }" authors && test 2 = $(grep A " 1 "" 1 "" 1 "" 1 "" 1 "" 1 "" 1 "" 1 +test_expect_success 'blame --show-email' ' + check_count \ + "" 1 \ + "" 1 \ + "" 1 \ + "" 1 \ + "" 1 \ + "" 1 \ + "" 1 \ + "" 1 ' test_done From 03e15fc0b61450d6d7388e7514a67e1a9e7b72bd Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Wed, 17 Jul 2013 17:25:29 -0400 Subject: [PATCH 3/6] t8001/t8002 (blame): add blame -L tests With the exception of a couple "corner case" checks in t8003 (and some indirect tests in t4211 of -L parsing code shared by log -L), there is no systematic checking of blame -L. Add tests to check blame -L directly. Signed-off-by: Eric Sunshine Signed-off-by: Junio C Hamano --- t/annotate-tests.sh | 104 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 3 deletions(-) diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index 3aa696443..b6a747829 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -3,9 +3,17 @@ check_count () { head= && - case "$1" in -h) head="$2"; shift; shift ;; esac && - echo "$PROG file $head" >&4 && - $PROG file $head >actual && + options= && + while : + do + case "$1" in + -h) head="$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; @@ -142,3 +150,93 @@ test_expect_success 'setup obfuscated email' ' 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 '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 +' From 5a9830cb718ce13fcbad39384dd365bb895a1b21 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Wed, 17 Jul 2013 17:25:30 -0400 Subject: [PATCH 4/6] t8001/t8002 (blame): add blame -L :funcname tests git-blame inherited "-L :funcname" support when "-L :funcname:file" was implemented for git-log. Add tests. Signed-off-by: Eric Sunshine Signed-off-by: Junio C Hamano --- t/annotate-tests.sh | 48 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index b6a747829..0bfee001b 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -3,17 +3,19 @@ check_count () { 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 && + echo "$PROG $options $file $head" >&4 && + $PROG $options $file $head >actual && perl -e ' my %expect = (@ARGV); my %count = map { $_ => 0 } keys %expect; @@ -231,6 +233,48 @@ 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.c && + GIT_AUTHOR_NAME="G" GIT_AUTHOR_EMAIL="G@test.git" \ + git commit -a -m "goodbye" && + + mv hello.c hello.orig && + echo "#include " >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 && From e6d2b9f6e7670e64e1d79b95205fe2fb32f990c2 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Wed, 17 Jul 2013 17:25:31 -0400 Subject: [PATCH 5/6] blame-options.txt: place each -L option variation on its own line Standard practice in Git documentation is for each variation of an option (such as: -p / --porcelain) to be placed on its own line in the OPTIONS table. The -L option does not follow suit. It cuddles "-L ," and "-L :", separated by a comma. This is inconsistent and potentially confusing since the comma separating them is typeset the same as the comma in ",". Fix this by placing each variation on its own line. Signed-off-by: Eric Sunshine Signed-off-by: Junio C Hamano --- Documentation/blame-options.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt index e9f984ba0..624b3532a 100644 --- a/Documentation/blame-options.txt +++ b/Documentation/blame-options.txt @@ -9,7 +9,8 @@ --show-stats:: Include additional statistics at the end of blame output. --L ,, -L ::: +-L ,:: +-L ::: Annotate only the given line range. and can take one of these forms: From df83d5cf6759541d6f3d94b29a91fd0d3e5dbcd5 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Wed, 17 Jul 2013 17:25:32 -0400 Subject: [PATCH 6/6] blame-options.txt: explain that -L and are optional The ability to omit either end of the -L range is a handy but undocumented shortcut, and is thus not easily discovered. Fix this shortcoming. Signed-off-by: Eric Sunshine Signed-off-by: Junio C Hamano --- Documentation/blame-options.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt index 624b3532a..4e55b1564 100644 --- a/Documentation/blame-options.txt +++ b/Documentation/blame-options.txt @@ -11,8 +11,11 @@ -L ,:: -L ::: - Annotate only the given line range. and can take - one of these forms: + Annotate only the given line range. and are optional. + ``-L '' or ``-L ,'' spans from to end of file. + ``-L ,'' spans from start of file to . ++ + and can take one of these forms: include::line-range-format.txt[]