{"thread":{"id":"49331","subject":"[PATCH 0/1] contrib: Add script to show uncovered \"new\" lines","startedAt":"2018-09-12T16:45:53Z","lastAt":"2018-10-12T12:09:48Z","messageCount":22,"participants":["Derrick Stolee via GitGitGadget","Derrick Stolee","Ben Peart","Junio C Hamano","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":1},"messages":[{"id":"357983","messageId":"pull.40.git.gitgitgadget@gmail.com","threadId":"49331","inReplyTo":null,"subject":"[PATCH 0/1] contrib: Add script to show uncovered \"new\" lines","fromName":"Derrick Stolee via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-12T16:45:48Z","receivedAt":"2018-09-12T16:45:53Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"We have coverage targets in our Makefile for using gcov to display line\ncoverage based on our test suite. The way I like to do it is to run:\n\nmake coverage-test\nmake coverage-report\n\nThis leaves the repo in a state where every X.c file that was covered has an\nX.c.gcov file containing the coverage counts for every line, and \"#####\" at\nevery uncovered line.\n\nThere have been a few bugs in recent patches what would have been caught if\nthe test suite covered those blocks (including a few of mine). I want to\nwork towards a \"sensible\" amount of coverage on new topics. In my opinion,\nthis means that any logic should be covered, but the 'die()' blocks in error\ncases do not need to be covered.\n\nIt is important to not measure the coverage of the codebase by what old code\nis not covered. To help, I created the 'contrib/coverage-diff.sh' script.\nAfter creating the coverage statistics at a version (say, 'topic') you can\nthen run\n\ncontrib/coverage-diff.sh base topic\n\nto see the lines added between 'base' and 'topic' that are not covered by\nthe test suite. For example, I ran this against the 'jch' branch (d3c0046)\nversus 'next' (dd90340) and got the following output:\n\nbuiltin/commit.c\n859fdc0c3cf     (Derrick Stolee 2018-08-29 05:49:04 -0700       1657)           write_commit_graph_reachable(get_object_directory(), 0);\nbuiltin/rev-list.c\n250edfa8c87     (Harald Nordgren        2018-04-18 23:05:35 +0200       431)                    bisect_flags |= BISECT_FIND_ALL;\nbuiltin/worktree.c\ne5353bef550     (Eric Sunshine  2018-08-28 17:20:19 -0400       60)             error_errno(_(\"failed to delete '%s'\"), sb.buf);\ne19831c94f9     (Eric Sunshine  2018-08-28 17:20:23 -0400       251)                die(_(\"unable to re-add worktree '%s'\"), path);\n68a6b3a1bd4     (Eric Sunshine  2018-08-28 17:20:24 -0400       793)                    die(_(\"cannot move a locked working tree, lock reason: %s\\nuse 'move -f -f' to override or unlock first\"),\nf4143101cbb     (Eric Sunshine  2018-08-28 17:20:25 -0400       906)                    die(_(\"cannot remove a locked working tree, lock reason: %s\\nuse 'remove -f -f' to override or unlock first\"),\nread-cache.c\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1754)           const unsigned char *cp = (const unsigned char *)name;\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1757)           previous_len = previous_ce ? previous_ce->ce_namelen : 0;\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1758)           strip_len = decode_varint(&cp);\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1759)           if (previous_len < strip_len) {\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1760)                   if (previous_ce)\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1761)                           die(_(\"malformed name field in the index, near path '%s'\"),\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1762)                               previous_ce->name);\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1764)                           die(_(\"malformed name field in the index in the first path\"));\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1766)           copy_len = previous_len - strip_len;\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1767)           name = (const char *)cp;\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1773)                   len += copy_len;\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1794)           if (copy_len)\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1795)                   memcpy(ce->name, previous_ce->name, copy_len);\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1796)           memcpy(ce->name + copy_len, name, len + 1 - copy_len);\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1797)           *ent_size = (name - ((char *)ondisk)) + len + 1 - copy_len;\nremote-curl.c\nc3b9bc94b9b     (Elijah Newren  2018-09-05 10:03:07 -0700       181)            options.filter = xstrdup(value);\n\nUsing this 'git blame' output, we can quickly inspect whether the uncovered\nlines are appropriate. For instance:\n\n 1. The line in builtin/commit.c is due to writing the commit-graph file\n    when GIT_TEST_COMMIT_GRAPH is enabled, which is not on by default in the\n    test suite. Being uncovered is expected here.\n    \n    \n 2. The lines in builtin/worktree.c are all related to error conditions.\n    This is acceptable.\n    \n    \n 3. The line in builtin/rev-list.c is a flag replacement in a block that is\n    otherwise unchanged. It must not be covered by the test suite normally.\n    This could be worth adding a test to ensure the new logic maintains old\n    behavior.\n    \n    \n 4. The lines in read-cache.c are part of a new block for the condition \"if\n    (expand_name_field)\" as part of an optimization. These lines should\n    probably be covered before that series is merged to 'next'. I understand\n    that Ben and Duy are continuing work in this direction [1].\n    \n    \n\nI used this approach for 'next' over 'master' and got a larger list, some of\nwhich I have already submitted tests to increase coverage [2] or will be\ncovered by topics not in 'next' [3].\n\nThanks, -Stolee\n\n[1] \nhttps://public-inbox.org/git/20180912161832.55324-1-benpeart@microsoft.com/T/#u\n\n[2] https://public-inbox.org/git/pull.37.git.gitgitgadget@gmail.com/\n\n[3] https://public-inbox.org/git/pull.34.git.gitgitgadget@gmail.com/\n\nDerrick Stolee (1):\n  contrib: add coverage-diff script\n\n contrib/coverage-diff.sh | 70 ++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 70 insertions(+)\n create mode 100755 contrib/coverage-diff.sh\n\n\nbase-commit: 1d4361b0f344188ab5eec6dcea01f61a3a3a1670\nPublished-As: https://github.com/gitgitgadget/git/releases/tags/pr-40%2Fderrickstolee%2Fcoverage-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-40/derrickstolee/coverage-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/40\n-- \ngitgitgadget\n"},{"id":"357984","messageId":"e4124471e5494b737d99eceed25fb03e787d0b96.1536770746.git.gitgitgadget@gmail.com","threadId":"49331","inReplyTo":"pull.40.git.gitgitgadget@gmail.com","subject":"[PATCH 1/1] contrib: add coverage-diff script","fromName":"Derrick Stolee via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-12T16:45:49Z","receivedAt":"2018-09-12T16:45:54Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"From: Derrick Stolee <dstolee@microsoft.com>\n\nWe have coverage targets in our Makefile for using gcov to display line\ncoverage based on our test suite. The way I like to do it is to run:\n\n    make coverage-test\n    make coverage-report\n\nThis leaves the repo in a state where every X.c file that was covered has\nan X.c.gcov file containing the coverage counts for every line, and \"#####\"\nat every uncovered line.\n\nThere have been a few bugs in recent patches what would have been caught\nif the test suite covered those blocks (including a few of mine). I want\nto work towards a \"sensible\" amount of coverage on new topics. In my opinion,\nthis means that any logic should be covered, but the 'die()' blocks in error\ncases do not need to be covered.\n\nIt is important to not measure the coverage of the codebase by what old code\nis not covered. To help, I created the 'contrib/coverage-diff.sh' script.\nAfter creating the coverage statistics at a version (say, 'topic') you can\nthen run\n\n    contrib/coverage-diff.sh base topic\n\nto see the lines added between 'base' and 'topic' that are not covered by the\ntest suite. The output uses 'git blame -c' format so you can find the commits\nresponsible and view the line numbers for quick access to the context.\n\nSigned-off-by: Derrick Stolee <dstolee@microsoft.com>\n---\n contrib/coverage-diff.sh | 70 ++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 70 insertions(+)\n create mode 100755 contrib/coverage-diff.sh\n\ndiff --git a/contrib/coverage-diff.sh b/contrib/coverage-diff.sh\nnew file mode 100755\nindex 0000000000..22acb13d38\n--- /dev/null\n+++ b/contrib/coverage-diff.sh\n@@ -0,0 +1,70 @@\n+#!/bin/bash\n+\n+# Usage: 'contrib/coverage-diff.sh <version1> <version2>\n+# Outputs a list of new lines in version2 compared to version1 that are\n+# not covered by the test suite. Assumes you ran\n+# 'make coverage-test coverage-report' from root first, so .gcov files exist.\n+\n+V1=$1\n+V2=$2\n+\n+diff-lines() {\n+    local path=\n+    local line=\n+    while read; do\n+\tesc=$'\\033'\n+\tif [[ $REPLY =~ ---\\ (a/)?.* ]]; then\n+\t    continue\n+\telif [[ $REPLY =~ \\+\\+\\+\\ (b/)?([^[:blank:]$esc]+).* ]]; then\n+\t    path=${BASH_REMATCH[2]}\n+\telif [[ $REPLY =~ @@\\ -[0-9]+(,[0-9]+)?\\ \\+([0-9]+)(,[0-9]+)?\\ @@.* ]]; then\n+\t    line=${BASH_REMATCH[2]}\n+\telif [[ $REPLY =~ ^($esc\\[[0-9;]+m)*([\\ +-]) ]]; then\n+\t    echo \"$path:$line:$REPLY\"\n+\t    if [[ ${BASH_REMATCH[2]} != - ]]; then\n+\t\t((line++))\n+\t    fi\n+\tfi\n+    done\n+}\n+\n+git diff --raw $V1 $V2 | grep \\.c$ | awk 'NF>1{print $NF}' >files.txt\n+\n+for file in $(cat files.txt)\n+do\n+\thash_file=${file//\\//\\#}\n+\n+\tgit diff $V1 $V2 -- $file \\\n+\t\t| diff-lines \\\n+\t\t| grep \":+\" \\\n+\t\t>\"diff_file.txt\"\n+\n+\tcat diff_file.txt \\\n+\t\t| sed -E 's/:/ /g' \\\n+\t\t| awk '{print $2}' \\\n+\t\t| sort \\\n+\t\t>new_lines.txt\n+\n+\tcat \"$hash_file.gcov\" \\\n+\t\t| grep \\#\\#\\#\\#\\# \\\n+\t\t| sed 's/    #####: //g' \\\n+\t\t| sed 's/\\:/ /g' \\\n+\t\t| awk '{print $1}' \\\n+\t\t| sort \\\n+\t\t>uncovered_lines.txt\n+\n+\tcomm -12 uncovered_lines.txt new_lines.txt \\\n+\t\t| sed -e 's/$/\\)/' \\\n+\t\t| sed -e 's/^/\\t/' \\\n+\t\t>uncovered_new_lines.txt\n+\n+\tgrep -q '[^[:space:]]' < uncovered_new_lines.txt && \\\n+\t\techo $file && \\\n+\t\tgit blame -c $file \\\n+\t\t\t| grep -f uncovered_new_lines.txt\n+\n+\trm -f diff_file.txt new_lines.txt \\\n+\t\tuncovered_lines.txt uncovered_new_lines.txt\n+done\n+\n+rm -rf files.txt\n-- \ngitgitgadget\n"},{"id":"357997","messageId":"7edb321e-c2df-d3b6-b4f3-9e8b1fc60698@gmail.com","threadId":"49331","inReplyTo":"pull.40.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 0/1] contrib: Add script to show uncovered \"new\" lines","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-09-12T19:14:31Z","receivedAt":"2018-09-12T19:14:39Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 9/12/2018 12:45 PM, Derrick Stolee via GitGitGadget wrote:\n> For example, I ran this against the 'jch' branch (d3c0046)\n> versus 'next' (dd90340)\n\nAs another example, I ran this against the 'pu' branch (4c416a53) versus \n'jch' (d3c0046) and got the following output, submitted here without \ncommentary:\n\nbuiltin/bisect--helper.c\n0b1f0fd910c     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n43)             free((void *) terms->term_good);\n3d3237b0e6b     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n162)            if (get_oid_commit(commit, &oid))\n3d3237b0e6b     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n163)                    return error(_(\"'%s' is not a valid commit\"), \ncommit);\n3d3237b0e6b     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n164)            strbuf_addstr(&branch, commit);\n3d3237b0e6b     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n172)                    error(_(\"Could not check out original HEAD '%s'. \nTry \"\n3d3237b0e6b     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n174)                    strbuf_release(&branch);\n3d3237b0e6b     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n175)                    argv_array_clear(&argv);\n3d3237b0e6b     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n176)                    return -1;\n0b1f0fd910c     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n215)            error(_(\"Bad bisect_write argument: %s\"), state);\n0b1f0fd910c     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n216)            goto fail;\n0b1f0fd910c     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n220)            error(_(\"couldn't get the oid of the rev '%s'\"), rev);\n0b1f0fd910c     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n221)            goto fail;\n0b1f0fd910c     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n226)            goto fail;\n0b1f0fd910c     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n230)            error_errno(_(\"couldn't open the file '%s'\"), \ngit_path_bisect_log());\n0b1f0fd910c     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n231)            goto fail;\n0b1f0fd910c     (Pranit Bauva   2017-10-27 15:06:37 +0000 242)fail:\n0b1f0fd910c     (Pranit Bauva   2017-10-27 15:06:37 +0000 243)    retval \n= -1;\na919f328ba3     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n323)            yesno = git_prompt(_(\"Are you sure [Y/n]? \"), PROMPT_ECHO);\na919f328ba3     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n324)            if (starts_with(yesno, \"N\") || starts_with(yesno, \"n\"))\na919f328ba3     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n327)            goto finish;\na919f328ba3     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n336)            error(_(\"You need to start by \\\"git bisect start\\\". You \"\na919f328ba3     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n341)            goto fail;\na919f328ba3     (Pranit Bauva   2017-10-27 15:06:37 +0000 345)fail:\n35f7ca528ae     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n387)            return error(_(\"--bisect-term requires exactly one \nargument\"));\n35f7ca528ae     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n400)                    error(_(\"BUG: invalid argument %s for 'git \nbisect terms'.\\n\"\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n416)            return -1;\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n419)            goto fail;\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n423)            goto fail;\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 427)fail:\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 428)    retval \n= -1;\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n466)                    no_checkout = 1;\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n488)                     !one_of(arg, \"--term-good\", \"--term-bad\", NULL)) {\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n489)                    return error(_(\"unrecognised option: '%s'\"), arg);\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n523)            if (get_oid(\"HEAD\", &head_oid))\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n524)                    return error(_(\"Bad HEAD - I need a HEAD\"));\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n539)                            error(_(\"checking out '%s' failed. Try \n'git \"\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n559)                            return error(_(\"won't bisect on \ncg-seek'ed tree\"));\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n562)                    return error(_(\"Bad HEAD - strange symbolic ref\"));\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n570)            return -1;\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n588)                    goto fail;\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n598)                    goto fail;\n5dfeec316b8     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n606)            goto fail;\n3d3237b0e6b     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n686)                    return error(_(\"--bisect-reset requires either \nno argument or a commit\"));\n0b1f0fd910c     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n690)                    return error(_(\"--bisect-write requires either 4 \nor 5 arguments\"));\n20edf353b72     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n697)                    return error(_(\"--check-and-set-terms requires 3 \narguments\"));\na919f328ba3     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n703)                    return error(_(\"--bisect-next-check requires 2 \nor 3 arguments\"));\nbuiltin/blame.c\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 922)    case \nDATE_HUMAN:\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n924)            blame_date_width = sizeof(\"Thu Oct 19 16:00\");\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n925)            break;\nbuiltin/gc.c\n3029970275b     (Jonathan Nieder        2018-07-16 23:57:40 -0700       \n461)            ret = error_errno(_(\"cannot stat '%s'\"), gc_log_path);\n3029970275b     (Jonathan Nieder        2018-07-16 23:57:40 -0700       \n470)            ret = error_errno(_(\"cannot read '%s'\"), gc_log_path);\nfec2ed21871     (Jonathan Nieder        2018-07-16 23:54:16 -0700       \n495)            die(FAILED_RUN, pack_refs_cmd.argv[0]);\nfec2ed21871     (Jonathan Nieder        2018-07-16 23:54:16 -0700       \n498)            die(FAILED_RUN, reflog.argv[0]);\n3029970275b     (Jonathan Nieder        2018-07-16 23:57:40 -0700       \n585)                            exit(128);\nfec2ed21871     (Jonathan Nieder        2018-07-16 23:54:16 -0700       \n637)                    die(FAILED_RUN, repack.argv[0]);\nfec2ed21871     (Jonathan Nieder        2018-07-16 23:54:16 -0700       \n647)                            die(FAILED_RUN, prune.argv[0]);\nfec2ed21871     (Jonathan Nieder        2018-07-16 23:54:16 -0700       \n654)                    die(FAILED_RUN, prune_worktrees.argv[0]);\nfec2ed21871     (Jonathan Nieder        2018-07-16 23:54:16 -0700       \n658)            die(FAILED_RUN, rerere.argv[0]);\nbuiltin/rebase--interactive.c\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 \n24)             return error(_(\"no HEAD?\"));\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 \n51)             return error_errno(_(\"could not create temporary %s\"), \npath_state_dir());\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 \n57)             return error_errno(_(\"could not mark as interactive\"));\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 \n77)             return -1;\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 \n81)             return -1;\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 \n87)             free(revisions);\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 \n88)             free(shortrevisions);\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 \n90)             return -1;\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 \n98)             free(revisions);\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 \n99)             free(shortrevisions);\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 \n101)            return error_errno(_(\"could not open %s\"), \nrebase_path_todo());\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 \n106)            argv_array_push(&make_script_args, restrict_revision);\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 \n114)            error(_(\"could not generate todo list\"));\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 205) \nusage_with_options(builtin_rebase_interactive_usage, options);\n93420467efe     (Alban Gruin    2018-08-28 14:10:42 +0200 \n219)            warning(_(\"--[no-]rebase-cousins has no effect without \"\nadb4f8f6b72     (Alban Gruin    2018-08-28 14:10:43 +0200 \n225)                    die(_(\"a base commit must be provided with \n--upstream or --onto\"));\nb3fe2e1f8cb     (Alban Gruin    2018-08-28 14:10:45 +0200 259)    case \nREARRANGE_SQUASH:\nb3fe2e1f8cb     (Alban Gruin    2018-08-28 14:10:45 +0200 \n260)            ret = rearrange_squash();\nb3fe2e1f8cb     (Alban Gruin    2018-08-28 14:10:45 +0200 \n261)            break;\nb3fe2e1f8cb     (Alban Gruin    2018-08-28 14:10:45 +0200 262)    case \nADD_EXEC:\nb3fe2e1f8cb     (Alban Gruin    2018-08-28 14:10:45 +0200 \n263)            ret = sequencer_add_exec_commands(cmd);\nb3fe2e1f8cb     (Alban Gruin    2018-08-28 14:10:45 +0200 \n264)            break;\nadb4f8f6b72     (Alban Gruin    2018-08-28 14:10:43 +0200 265)    default:\nadb4f8f6b72     (Alban Gruin    2018-08-28 14:10:43 +0200 \n266)            BUG(\"invalid command '%d'\", command);\nbuiltin/rebase.c\n55071ea248e     (Pratik Karki   2018-08-07 01:16:09 +0545 61)     \nstrbuf_trim(&out);\n55071ea248e     (Pratik Karki   2018-08-07 01:16:09 +0545 62)     ret = \n!strcmp(\"true\", out.buf);\n55071ea248e     (Pratik Karki   2018-08-07 01:16:09 +0545 63)     \nstrbuf_release(&out);\n002ee2fe682     (Pratik Karki   2018-09-04 14:59:57 -0700 114)    case \nREBASE_AM:\n002ee2fe682     (Pratik Karki   2018-09-04 14:59:57 -0700 \n115)            die(_(\"%s requires an interactive rebase\"), option);\nf95736288a3     (Pratik Karki   2018-08-08 20:51:16 +0545 \n148)            return error_errno(_(\"could not read '%s'\"), path);\nf95736288a3     (Pratik Karki   2018-08-08 20:51:16 +0545 \n162)            return -1;\nf95736288a3     (Pratik Karki   2018-08-08 20:51:16 +0545 \n167)            return error(_(\"could not get 'onto': '%s'\"), buf.buf);\nf95736288a3     (Pratik Karki   2018-08-08 20:51:16 +0545 \n178)                    return -1;\nf95736288a3     (Pratik Karki   2018-08-08 20:51:16 +0545 179)    } else \nif (read_one(state_dir_path(\"head\", opts), &buf))\nf95736288a3     (Pratik Karki   2018-08-08 20:51:16 +0545 \n180)            return -1;\nf95736288a3     (Pratik Karki   2018-08-08 20:51:16 +0545 \n182)            return error(_(\"invalid orig-head: '%s'\"), buf.buf);\nf95736288a3     (Pratik Karki   2018-08-08 20:51:16 +0545 \n186)            return -1;\nf95736288a3     (Pratik Karki   2018-08-08 20:51:16 +0545 \n188)            opts->flags &= ~REBASE_NO_QUIET;\n73d51ed0a59     (Pratik Karki   2018-09-04 14:59:50 -0700 \n196)            opts->signoff = 1;\n73d51ed0a59     (Pratik Karki   2018-09-04 14:59:50 -0700 \n197)            opts->flags |= REBASE_FORCE;\nead98c111b8     (Pratik Karki   2018-09-04 14:59:52 -0700 \n204)                    return -1;\n28a02c5a790     (Pratik Karki   2018-09-04 15:00:00 -0700 \n219)                    return -1;\n399a505296a     (Pratik Karki   2018-09-04 15:00:11 -0700 \n227)                    return -1;\n399a505296a     (Pratik Karki   2018-09-04 15:00:11 -0700 \n235)                    return -1;\n7debdaa4ad1     (Pratik Karki   2018-09-04 15:00:02 -0700 \n255)            return error(_(\"Could not read '%s'\"), path);\n7debdaa4ad1     (Pratik Karki   2018-09-04 15:00:02 -0700 \n271)                    res = error(_(\"Cannot store %s\"), autostash.buf);\n7debdaa4ad1     (Pratik Karki   2018-09-04 15:00:02 -0700 \n275)                    return res;\nb2263c13613     (Johannes Schindelin    2018-08-29 07:31:17 -0700       \n373) argv_array_pushf(&child.args,\nb2263c13613     (Johannes Schindelin    2018-08-29 07:31:17 -0700       \n375) oid_to_hex(&opts->restrict_revision->object.oid));\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 479)    case \nREBASE_INTERACTIVE:\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n480)            backend = \"git-rebase--interactive\";\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n481)            backend_func = \"git_rebase__interactive\";\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n482)            break;\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 491)    default:\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n492)            BUG(\"Unhandled rebase type %d\", opts->type);\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n509)            struct strbuf dir = STRBUF_INIT;\n7debdaa4ad1     (Pratik Karki   2018-09-04 15:00:02 -0700 \n511)            apply_autostash(opts);\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n512)            strbuf_addstr(&dir, opts->state_dir);\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n513)            remove_dir_recursively(&dir, 0);\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n514)            strbuf_release(&dir);\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n515)            die(\"Nothing to do\");\nd4c569f8f4c     (Pratik Karki   2018-09-04 14:27:20 -0700 \n542)            BUG(\"Not a fully qualified branch: '%s'\", switch_to_branch);\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n545)            return -1;\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n549)                    rollback_lock_file(&lock);\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n550)                    return error(_(\"could not determine HEAD \nrevision\"));\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n567)            rollback_lock_file(&lock);\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n568)            return error(_(\"could not read index\"));\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n572)            error(_(\"failed to find tree of %s\"), oid_to_hex(oid));\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n573)            rollback_lock_file(&lock);\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n574)            free((void *)desc.buffer);\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n575)            return -1;\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n588)            ret = error(_(\"could not write index\"));\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n592)            return ret;\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 608)    } else \nif (old_orig)\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n609)            delete_ref(NULL, \"ORIG_HEAD\", old_orig, 0);\nbff014dac7d     (Pratik Karki   2018-09-04 14:27:13 -0700 \n637)                    opts->flags &= !REBASE_DIFFSTAT;\n9a48a615b47     (Pratik Karki   2018-09-04 14:27:16 -0700 \n671)                    return 1;\n9a48a615b47     (Pratik Karki   2018-09-04 14:27:16 -0700 \n687)            return 0;\n55071ea248e     (Pratik Karki   2018-08-07 01:16:09 +0545 \n894)            const char *path = mkpath(\"%s/git-legacy-rebase\",\n55071ea248e     (Pratik Karki   2018-08-07 01:16:09 +0545 \n897)            if (sane_execvp(path, (char **)argv) < 0)\n55071ea248e     (Pratik Karki   2018-08-07 01:16:09 +0545 \n898)                    die_errno(_(\"could not exec %s\"), path);\n55071ea248e     (Pratik Karki   2018-08-07 01:16:09 +0545 \n900)                    BUG(\"sane_execvp() returned???\");\n0eabf4b95ca     (Pratik Karki   2018-08-08 20:51:22 +0545 \n916)            die(_(\"It looks like 'git am' is in progress. Cannot \nrebase.\"));\nf28d40d3a99     (Pratik Karki   2018-09-04 14:27:07 -0700 \n953)            usage_with_options(builtin_rebase_usage,\nf95736288a3     (Pratik Karki   2018-08-08 20:51:16 +0545 \n973)                    die(_(\"Cannot read HEAD\"));\nf95736288a3     (Pratik Karki   2018-08-08 20:51:16 +0545 \n977)                    die(_(\"could not read index\"));\nf95736288a3     (Pratik Karki   2018-08-08 20:51:16 +0545 \n991)                    exit(1);\n122420c2953     (Pratik Karki   2018-08-08 20:51:17 +0545 \n1003)                   die(_(\"could not discard worktree changes\"));\n122420c2953     (Pratik Karki   2018-08-08 20:51:17 +0545 \n1005)                   exit(1);\n5e5d96197ca     (Pratik Karki   2018-08-08 20:51:18 +0545 \n1016)                   exit(1);\n5e5d96197ca     (Pratik Karki   2018-08-08 20:51:18 +0545 \n1019)                   die(_(\"could not move back to %s\"),\n5a61494539b     (Pratik Karki   2018-08-08 20:51:19 +0545 \n1029)                   die(_(\"could not remove '%s'\"), options.state_dir);\nf95736288a3     (Pratik Karki   2018-08-08 20:51:16 +0545 1042)   default:\n51e9ea6da76     (Pratik Karki   2018-08-08 20:51:20 +0545 \n1043)           BUG(\"action: %d\", action);\nc54dacb50ea     (Pratik Karki   2018-09-04 14:27:18 -0700 \n1048)           const char *last_slash = strrchr(options.state_dir, '/');\nc54dacb50ea     (Pratik Karki   2018-09-04 14:27:18 -0700 \n1049)           const char *state_dir_base =\nc54dacb50ea     (Pratik Karki   2018-09-04 14:27:18 -0700 \n1050)                   last_slash ? last_slash + 1 : options.state_dir;\nc54dacb50ea     (Pratik Karki   2018-09-04 14:27:18 -0700 \n1051)           const char *cmd_live_rebase =\nc54dacb50ea     (Pratik Karki   2018-09-04 14:27:18 -0700 \n1053)           strbuf_reset(&buf);\nc54dacb50ea     (Pratik Karki   2018-09-04 14:27:18 -0700 \n1054)           strbuf_addf(&buf, \"rm -fr \\\"%s\\\"\", options.state_dir);\nc54dacb50ea     (Pratik Karki   2018-09-04 14:27:18 -0700 \n1055)           die(_(\"It seems that there is already a %s directory, and\\n\"\n53f9e5be94e     (Pratik Karki   2018-09-04 14:59:56 -0700 \n1079)           strbuf_addstr(&options.git_am_opt, \" --ignore-date\");\n53f9e5be94e     (Pratik Karki   2018-09-04 14:59:56 -0700 \n1080)           options.flags |= REBASE_FORCE;\nc7ee2134d42     (Pratik Karki   2018-09-04 15:00:01 -0700 \n1092)           strbuf_addf(&options.git_am_opt, \" -C%d\", opt_c);\n0073df2bd31     (Pratik Karki   2018-09-04 15:00:07 -0700 \n1124)           else if (strcmp(\"no-rebase-cousins\", rebase_merges))\n0073df2bd31     (Pratik Karki   2018-09-04 15:00:07 -0700 \n1125)                   die(_(\"Unknown mode: %s\"), rebase_merges);\n399a505296a     (Pratik Karki   2018-09-04 15:00:11 -0700 \n1146)           case REBASE_AM:\n399a505296a     (Pratik Karki   2018-09-04 15:00:11 -0700 \n1147)                   die(_(\"--strategy requires --merge or \n--interactive\"));\n399a505296a     (Pratik Karki   2018-09-04 15:00:11 -0700 \n1156)           default:\n399a505296a     (Pratik Karki   2018-09-04 15:00:11 -0700 \n1157)                   BUG(\"unhandled rebase type (%d)\", options.type);\n6dc73173f6c     (Pratik Karki   2018-08-08 21:21:33 +0545 \n1165)           strbuf_addstr(&options.git_format_patch_opt, \" --progress\");\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 1173)   case \nREBASE_AM:\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n1174)           options.state_dir = apply_dir();\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n1175)           break;\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n1252)                   die(_(\"invalid upstream '%s'\"), \noptions.upstream_name);\nbfa5147095f     (Pratik Karki   2018-09-04 15:00:12 -0700 \n1258)                           die(_(\"Could not create new root commit\"));\ne65123a71d0     (Pratik Karki   2018-09-04 14:27:21 -0700 \n1308)                   die(_(\"fatal: no such branch/commit '%s'\"),\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n1316)                   die(_(\"No such ref: %s\"), \"HEAD\");\nac7f467fef8     (Pratik Karki   2018-08-07 01:16:11 +0545 \n1328)                   die(_(\"Could not resolve HEAD to a revision\"));\ne65123a71d0     (Pratik Karki   2018-09-04 14:27:21 -0700 \n1330)           BUG(\"unexpected number of arguments left to parse\");\ne0333e5c63f     (Pratik Karki   2018-09-04 14:27:14 -0700 \n1341)           die(_(\"could not read index\"));\n7debdaa4ad1     (Pratik Karki   2018-09-04 15:00:02 -0700 \n1368)                           die(_(\"Cannot autostash\"));\n7debdaa4ad1     (Pratik Karki   2018-09-04 15:00:02 -0700 \n1371)                           die(_(\"Unexpected stash response: '%s'\"),\n7debdaa4ad1     (Pratik Karki   2018-09-04 15:00:02 -0700 \n1377)                           die(_(\"Could not create directory for \n'%s'\"),\n7debdaa4ad1     (Pratik Karki   2018-09-04 15:00:02 -0700 \n1383)                           die(_(\"could not reset --hard\"));\ne65123a71d0     (Pratik Karki   2018-09-04 14:27:21 -0700 \n1427)                                   ret = !!error(_(\"could not parse \n'%s'\"),\ne65123a71d0     (Pratik Karki   2018-09-04 14:27:21 -0700 \n1429)                                   goto cleanup;\ne65123a71d0     (Pratik Karki   2018-09-04 14:27:21 -0700 \n1438)                                   ret = !!error(_(\"could not \nswitch to \"\n1ed9c14ff25     (Pratik Karki   2018-09-04 14:27:17 -0700 \n1448)                            resolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n1ed9c14ff25     (Pratik Karki   2018-09-04 14:27:17 -0700 \n1449)                           puts(_(\"HEAD is up to date.\"));\n9a48a615b47     (Pratik Karki   2018-09-04 14:27:16 -0700 \n1458)                    resolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n9a48a615b47     (Pratik Karki   2018-09-04 14:27:16 -0700 \n1459)                   puts(_(\"HEAD is up to date, rebase forced.\"));\nbuiltin/rev-list.c\n0eee403f2f7     (Matthew DeVore 2018-09-04 11:05:47 -0700 \n227)            die(\"unexpected missing %s object '%s'\",\n0eee403f2f7     (Matthew DeVore 2018-09-04 11:05:47 -0700 \n228)                type_name(obj->type), oid_to_hex(&obj->oid));\nbuiltin/stash.c\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n130)            free_stash_info(info);\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n131)            error(_(\"'%s' is not a stash-like commit\"), revision);\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n132)            exit(128);\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n165)                    free_stash_info(info);\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n166)                    fprintf_ln(stderr, _(\"No stash entries found.\"));\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n167)                    return -1;\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 201)    \ndefault: /* Invalid or ambiguous */\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n202)            free_stash_info(info);\n31f109a3618     (Joel Teichroeb 2018-08-31 00:40:37 +0300 \n229)            return error(_(\"git stash clear with parameters is \nunimplemented\"));\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n244)            return -1;\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n252)            return -1;\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n265)            return -1;\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n268)            return error(_(\"unable to write new index file\"));\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n374)            remove_path(stash_index_path.buf);\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n375)            return -1;\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n402)            return -1;\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n405)            return error(_(\"Cannot apply a stash in the middle of a \nmerge\"));\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n415)                            strbuf_release(&out);\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n416)                            return -1;\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n422)                            return -1;\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n427)                            return -1;\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n434)            return error(_(\"Could not restore untracked files from \nstash\"));\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n465)                    return -1;\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n470)                    strbuf_release(&out);\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n475)                    strbuf_release(&out);\n93871263d18     (Joel Teichroeb 2018-08-31 00:40:36 +0300 \n476)                    return -1;\n31f109a3618     (Joel Teichroeb 2018-08-31 00:40:37 +0300 \n551)            return error(_(\"%s: Could not drop stash entry\"),\nb3513da4bd9     (Joel Teichroeb 2018-08-31 00:40:39 +0300 \n623)            printf_ln(_(\"The stash entry is kept in case you need it \nagain.\"));\n8ceb24b2c38     (Paul-Sebastian Ungureanu       2018-08-31 00:40:41 \n+0300       754)            free_stash_info(&info);\n129f0b0a009     (Paul-Sebastian Ungureanu       2018-08-31 00:40:48 \n+0300       755) usage_with_options(git_stash_show_usage, options);\n0ac06fb81f2     (Paul-Sebastian Ungureanu       2018-08-31 00:40:43 \n+0300       808)            fprintf_ln(stderr, _(\"\\\"git stash store\\\" \nrequires one <commit> argument\"));\n0ac06fb81f2     (Paul-Sebastian Ungureanu       2018-08-31 00:40:43 \n+0300       809)            return -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       884)            return 1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       925)            ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       926)            goto done;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       931)            ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       932)            goto done;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       937)            ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       938)            goto done;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       966)            ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       967)            goto done;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       978)            ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       979)            goto done;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       984)            ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       985)            goto done;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       992)            ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       993)            goto done;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1018)           ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1019)           goto done;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1031)           ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1032)           goto done;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1037)           ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1038)           goto done;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1049)           ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1050)           goto done;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1055)           ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1056)           goto done;\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1089)                   fprintf_ln(stderr, _(\"You do not \nhave the initial commit yet\"));\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1110)           if (!quiet)\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1111)                   fprintf_ln(stderr, _(\"Cannot save \nthe current index state\"));\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1112)           ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1113)           *stash_msg = NULL;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1114)           goto done;\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1119)                   if (!quiet)\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1120) fprintf_ln(stderr, _(\"Cannot save the untracked files\"));\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1121)                   ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1122)                   *stash_msg = NULL;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1123)                   goto done;\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1131)                   if (!quiet)\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1132) fprintf_ln(stderr, _(\"Cannot save the current worktree \nstate\"));\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1133)                   goto done;\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1139)                   if (!quiet)\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1140) fprintf_ln(stderr, _(\"Cannot save the current worktree \nstate\"));\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1141)                   ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1142)                   *stash_msg = NULL;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1143)                   goto done;\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1166)           if (!quiet)\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1167)                   fprintf_ln(stderr, _(\"Cannot record \nworking tree state\"));\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1168)           ret = -1;\nf6f191b3f25     (Paul-Sebastian Ungureanu       2018-08-31 00:40:44 \n+0300       1169)           goto done;\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1251)           return -1;\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1260)           if (!quiet)\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1261)                   fprintf_ln(stderr, _(\"Cannot \ninitialize stash\"));\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1262)           return -1;\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1272)           if (!quiet)\n8002b9e6264     (Paul-Sebastian Ungureanu       2018-08-31 00:40:46 \n+0300       1273)                   fprintf_ln(stderr, _(\"Cannot save \nthe current status\"));\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1274)           ret = -1;\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1275)           goto done;\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1292)                           ret = -1;\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1311)                           ret = -1;\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1312)                           goto done;\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1321)                           ret = -1;\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1322)                           goto done;\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1330)                           ret = -1;\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1339)                           ret = -1;\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1350)                           ret = -1;\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1359)                           ret = -1;\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1360)                           goto done;\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1368)                           ret = -1;\n48c061fa443     (Paul-Sebastian Ungureanu       2018-08-31 00:40:45 \n+0300       1394)                           ret = -1;\n129f0b0a009     (Paul-Sebastian Ungureanu       2018-08-31 00:40:48 \n+0300       1524) usage_msg_opt(xstrfmt(_(\"unknown subcommand: %s\"), \nargv[0]),\n129f0b0a009     (Paul-Sebastian Ungureanu       2018-08-31 00:40:48 \n+0300       1554)                           continue;\nbuiltin/submodule--helper.c\n9d34daefb74     (Antonio Ospite 2018-08-14 13:05:22 +0200 2174)   \ndie(\"submodule--helper config takes 1 or 2 arguments: name [value]\");\ncommit-graph.c\n5cef295f283     (Derrick Stolee 2018-08-20 18:24:32 +0000 \n66)             return 0;\n20fd6d57996     (Derrick Stolee 2018-08-20 18:24:30 +0000 \n78)             return 0;\ndate.c\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n113)            die(\"Timestamp too large for this system: %\"PRItime, time);\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n216)            if (tm->tm_mon == human_tm->tm_mon) {\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n217)                    if (tm->tm_mday > human_tm->tm_mday) {\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n219)                    } else if (tm->tm_mday == human_tm->tm_mday) {\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n220)                            hide.date = hide.wday = 1;\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n221)                    } else if (tm->tm_mday + 5 > human_tm->tm_mday) {\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n223)                            hide.date = 1;\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n231)            gettimeofday(&now, NULL);\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n232)            show_date_relative(time, tz, &now, buf);\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n233)            return;\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n246)            hide.seconds = 1;\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n247)            hide.tz |= !hide.date;\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n248)            hide.wday = hide.time = !hide.year;\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n262)            strbuf_rtrim(buf);\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n287)            gettimeofday(&now, NULL);\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n290)            human_tz = local_time_tzoffset(now.tv_sec, &human_tm);\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 886)static int \nauto_date_style(void)\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 888)    return \n(isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n909)            return DATE_HUMAN;\n74e8221b523     (Linus Torvalds 2018-07-07 15:02:35 -0700 \n911)            return auto_date_style();\ndiff-lib.c\nfa49029577c     (Alex Vandiver  2018-01-02 19:04:56 -0800 \n205)                    continue;\nlist-objects-filter.c\ndbebce653b5     (Matthew DeVore 2018-09-04 11:05:49 -0700 \n47)             BUG(\"unknown filter_situation: %d\", filter_situation);\n7329b7c6cdc     (Matthew DeVore 2018-09-04 11:05:50 -0700 100)    default:\n7329b7c6cdc     (Matthew DeVore 2018-09-04 11:05:50 -0700 \n101)            BUG(\"unknown filter_situation: %d\", filter_situation);\ndbebce653b5     (Matthew DeVore 2018-09-04 11:05:49 -0700 \n152)            BUG(\"unknown filter_situation: %d\", filter_situation);\ndbebce653b5     (Matthew DeVore 2018-09-04 11:05:49 -0700 \n257)            BUG(\"unknown filter_situation: %d\", filter_situation);\ndbebce653b5     (Matthew DeVore 2018-09-04 11:05:49 -0700 \n438)            BUG(\"invalid list-objects filter choice: %d\",\nlist-objects.c\nf447a499dbb     (Matthew DeVore 2018-08-13 11:14:28 -0700 \n197)                    ctx->show_object(obj, base->buf, ctx->show_data);\nrebase-interactive.c\n64a43cbd5da     (Alban Gruin    2018-08-10 18:51:31 +0200 \n61)             return error_errno(_(\"could not read '%s'.\"), todo_file);\n64a43cbd5da     (Alban Gruin    2018-08-10 18:51:31 +0200 \n65)             strbuf_release(&buf);\n64a43cbd5da     (Alban Gruin    2018-08-10 18:51:31 +0200 \n66)             return -1;\na9f5476fbca     (Alban Gruin    2018-08-10 18:51:35 +0200 \n74)             return error_errno(_(\"could not read '%s'.\"), todo_file);\na9f5476fbca     (Alban Gruin    2018-08-10 18:51:35 +0200 \n78)             strbuf_release(&buf);\na9f5476fbca     (Alban Gruin    2018-08-10 18:51:35 +0200 \n79)             return -1;\n64a43cbd5da     (Alban Gruin    2018-08-10 18:51:31 +0200 \n85)             return -1;\nrefs.c\n4a6067cda51     (Stefan Beller  2018-08-20 18:24:16 +0000 \n1405)           return 0;\nsequencer.c\n65850686cf0     (Alban Gruin    2018-08-28 14:10:40 +0200 \n2276)           return;\n65850686cf0     (Alban Gruin    2018-08-28 14:10:40 +0200 \n2373)           write_file(rebase_path_quiet(), \"%s\\n\", quiet);\n2c58483a598     (Alban Gruin    2018-08-10 18:51:33 +0200 \n3371)                   return error(_(\"could not checkout %s\"), commit);\n4df66c40b08     (Alban Gruin    2018-08-10 18:51:34 +0200 \n3385)           return error(_(\"%s: not a valid OID\"), orig_head);\nb97e1873649     (Alban Gruin    2018-08-28 14:10:36 +0200 \n4750)           return -1;\nb97e1873649     (Alban Gruin    2018-08-28 14:10:36 +0200 \n4753)           return -1;\nb97e1873649     (Alban Gruin    2018-08-28 14:10:36 +0200 \n4759)           return error_errno(_(\"could not read '%s'.\"), todo_file);\nb97e1873649     (Alban Gruin    2018-08-28 14:10:36 +0200 \n4762)           todo_list_release(&todo_list);\nb97e1873649     (Alban Gruin    2018-08-28 14:10:36 +0200 \n4763)           return error(_(\"unusable todo list: '%s'\"), todo_file);\nb97e1873649     (Alban Gruin    2018-08-28 14:10:36 +0200 \n4782)           todo_list_release(&todo_list);\nb97e1873649     (Alban Gruin    2018-08-28 14:10:36 +0200 \n4783)           return -1;\nb97e1873649     (Alban Gruin    2018-08-28 14:10:36 +0200 \n4787)           return error(_(\"could not copy '%s' to '%s'.\"), todo_file,\nb97e1873649     (Alban Gruin    2018-08-28 14:10:36 +0200 \n4791)           return error(_(\"could not transform the todo list\"));\nb97e1873649     (Alban Gruin    2018-08-28 14:10:36 +0200 \n4820)           return error(_(\"could not transform the todo list\"));\nb97e1873649     (Alban Gruin    2018-08-28 14:10:36 +0200 \n4823)           return error(_(\"could not skip unnecessary pick commands\"));\nb97e1873649     (Alban Gruin    2018-08-28 14:10:36 +0200 \n4829)           return -1;\nstrbuf.c\nf95736288a3     (Pratik Karki   2018-08-08 20:51:16 +0545 \n127)                    --sb->len;\nsubmodule-config.c\n83a66534e63     (Antonio Ospite 2018-08-14 13:05:19 +0200 \n714)            return CONFIG_INVALID_KEY;\n150984f5339     (Antonio Ospite 2018-08-14 13:05:20 +0200 \n729)            warning(_(\"Could not update .gitmodules entry %s\"), key);\nt/helper/test-dump-fsmonitor.c\n6e1123ec573     (Alex Vandiver  2018-01-02 19:04:54 -0800 \n25)                     valid++;\nt/helper/test-repository.c\nb7758963424     (Derrick Stolee 2018-08-20 18:24:24 +0000 \n21)             die(\"Couldn't init repo\");\nb7758963424     (Derrick Stolee 2018-08-20 18:24:24 +0000 \n47)             die(\"Couldn't init repo\");\nwrapper.c\n7e621449185     (Pranit Bauva   2017-10-27 15:06:37 +0000 \n701)            die_errno(_(\"could not stat %s\"), filename);\nwt-status.c\nf3bd35fa0dd     (Stephen P. Smith       2018-09-05 17:53:29 -0700       \n671)                    s->committable = 1;\n1c623c066c2     (Junio C Hamano 2018-09-07 15:32:24 -0700 \n1949)                   if (s->state.rebase_in_progress ||\n1c623c066c2     (Junio C Hamano 2018-09-07 15:32:24 -0700 1950) \ns->state.rebase_interactive_in_progress)\n1c623c066c2     (Junio C Hamano 2018-09-07 15:32:24 -0700 \n1951)                           branch_name = s->state.onto;\n1c623c066c2     (Junio C Hamano 2018-09-07 15:32:24 -0700 \n1952)                   else if (s->state.detached_from)\n1c623c066c2     (Junio C Hamano 2018-09-07 15:32:24 -0700 \n1953)                           branch_name = s->state.detached_from;\n\n"},{"id":"358001","messageId":"a99b2a7a-6674-033f-16b9-34e2fce857b6@gmail.com","threadId":"49331","inReplyTo":"pull.40.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 0/1] contrib: Add script to show uncovered \"new\" lines","fromName":"Ben Peart","fromEmail":"peartben@gmail.com","sentAt":"2018-09-12T19:33:32Z","receivedAt":"2018-09-12T19:33:39Z","isPatch":true,"sender":{"key":"benpeart@microsoft.com","avatar":"https://avatars.githubusercontent.com/u/15252029?v=4"},"body":"\n\nOn 9/12/2018 12:45 PM, Derrick Stolee via GitGitGadget wrote:\n> We have coverage targets in our Makefile for using gcov to display line\n> coverage based on our test suite. The way I like to do it is to run:\n> \n> make coverage-test\n> make coverage-report\n> \n\nVery nice, I was unaware of the coverage test make targets.  I like the \nnew report; it makes it easier to verify any new changes are actually \ntested.\n\n>      \n>   4. The lines in read-cache.c are part of a new block for the condition \"if\n>      (expand_name_field)\" as part of an optimization. These lines should\n>      probably be covered before that series is merged to 'next'. I understand\n>      that Ben and Duy are continuing work in this direction [1].\n>      \n\nThis code is only exercised when the index format is V4 but the default \nis version 2/3 [1].  To enable the test suite to use version 4 and test \nthose code paths will require the addition of a new \nGIT_TEST_INDEX_VERSION environment variable.  I'll add that to my TODO list.\n\n[1] https://git-scm.com/docs/git/2.1.0\n\n"},{"id":"358004","messageId":"xmqq36uelcgz.fsf@gitster-ct.c.googlers.com","threadId":"49331","inReplyTo":"pull.40.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 0/1] contrib: Add script to show uncovered \"new\" lines","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-09-12T19:53:00Z","receivedAt":"2018-09-12T19:53:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Derrick Stolee via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> There have been a few bugs in recent patches what would have been caught if\n> the test suite covered those blocks (including a few of mine). I want to\n> work towards a \"sensible\" amount of coverage on new topics. In my opinion,\n> this means that any logic should be covered, but the 'die()' blocks in error\n> cases do not need to be covered.\n\nNice.\n\n> It is important to not measure the coverage of the codebase by what old code\n> is not covered. To help, I created the 'contrib/coverage-diff.sh' script.\n> After creating the coverage statistics at a version (say, 'topic') you can\n> then run\n>\n> contrib/coverage-diff.sh base topic\n> ...\n> Using this 'git blame' output, we can quickly inspect whether the uncovered\n> lines are appropriate. For instance:\n> ...\n> I used this approach for 'next' over 'master' and got a larger list, some of\n> which I have already submitted tests to increase coverage [2] or will be\n> covered by topics not in 'next' [3].\n>\n> Thanks, -Stolee\n\nThanks for working on this.\n"},{"id":"358015","messageId":"xmqqa7omjred.fsf@gitster-ct.c.googlers.com","threadId":"49331","inReplyTo":"e4124471e5494b737d99eceed25fb03e787d0b96.1536770746.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 1/1] contrib: add coverage-diff script","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-09-12T22:13:30Z","receivedAt":"2018-09-12T22:13:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Derrick Stolee via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n>  contrib/coverage-diff.sh | 70 ++++++++++++++++++++++++++++++++++++++++\n>  1 file changed, 70 insertions(+)\n>  create mode 100755 contrib/coverage-diff.sh\n\nI fully appreciate the motivation.  But it is a bit sad that this\nbegins with \"#!/bin/bash\" but it seems that the script is full of\nbash-isms.  I haven't gone through the script to see if these are\ninevitable or gratuitous yet, but I'd assume it made it easier for\nyou to write it to step outside the pure POSIX shell?\n\n> +V1=$1\n> +V2=$2\n> +\n> +diff-lines() {\n\nBeing able to use '-' in identifier is probably a bash-ism that you\ndid not have to use.\n\n> +    local path=\n> +    local line=\n> +    while read; do\n\nBeing able to omit variable to be read into and can use the implicit\nvariable $REPLY also is.\n\n> +\tesc=$'\\033'\n> +\tif [[ $REPLY =~ ---\\ (a/)?.* ]]; then\n> +\t    continue\n> +\telif [[ $REPLY =~ \\+\\+\\+\\ (b/)?([^[:blank:]$esc]+).* ]]; then\n> +\t    path=${BASH_REMATCH[2]}\n\nOK, it probably is easier to write in bash than using expr if you\nwant to do regexp.  Where do these escape code come from in \"git\ndiff\" output, by the way?\n\n> +\telif [[ $REPLY =~ @@\\ -[0-9]+(,[0-9]+)?\\ \\+([0-9]+)(,[0-9]+)?\\ @@.* ]]; then\n> +\t    line=${BASH_REMATCH[2]}\n> +\telif [[ $REPLY =~ ^($esc\\[[0-9;]+m)*([\\ +-]) ]]; then\n> +\t    echo \"$path:$line:$REPLY\"\n> +\t    if [[ ${BASH_REMATCH[2]} != - ]]; then\n> +\t\t((line++))\n> +\t    fi\n> +\tfi\n> +    done\n> +}\n> +\n> +git diff --raw $V1 $V2 | grep \\.c$ | awk 'NF>1{print $NF}' >files.txt\n\nHmph, not \n\n\tgit diff --name-only \"$V1\" \"$V2\" -- \"*.c\"\n\nDo we (or do we not) want \"--no-renames\"?\n\n> +for file in $(cat files.txt)\n> +do\n> +\thash_file=${file//\\//\\#}\n> +\n> +\tgit diff $V1 $V2 -- $file \\\n> +\t\t| diff-lines \\\n> +\t\t| grep \":+\" \\\n> +\t\t>\"diff_file.txt\"\n\nStyle:\n\n\tcmd1 |\n\tcmd2 |\n\tcmd3 >output\n\nis easier to read without backslashes.\n\n> +\tcat diff_file.txt \\\n> +\t\t| sed -E 's/:/ /g' \\\n> +\t\t| awk '{print $2}' \\\n> +\t\t| sort \\\n> +\t\t>new_lines.txt\n> +\n> +\tcat \"$hash_file.gcov\" \\\n> +\t\t| grep \\#\\#\\#\\#\\# \\\n> +\t\t| sed 's/    #####: //g' \\\n> +\t\t| sed 's/\\:/ /g' \\\n> +\t\t| awk '{print $1}' \\\n> +\t\t| sort \\\n> +\t\t>uncovered_lines.txt\n\nOK, so we assume that we have run coverage in $V2 checkout so that\nwe can pick up the postimage line numbers in \"diff $V1 $V2\" and find\ncorresponding record in .gcov file in the filesystem.  I did not\nrealize the significance of 'topic' being the later argument to the\nscript in this part\n\n    After creating the coverage statistics at a version (say,\n    'topic') you can then run\n\n        contrib/coverage-diff.sh base topic\n\nof your description before I see this implementation.  Also the\ncomment at the beginning\n\n    # Usage: 'contrib/coverage-diff.sh <version1> <version2>\n    # Outputs a list of new lines in version2 compared to version1 that are\n    # not covered by the test suite. Assumes you ran\n    # 'make coverage-test coverage-report' from root first, so .gcov files exist.\n\nwould want to make it clear that we want coverage run from root\nfor version2 before using this script.\n\n> +\tcomm -12 uncovered_lines.txt new_lines.txt \\\n> +\t\t| sed -e 's/$/\\)/' \\\n> +\t\t| sed -e 's/^/\\t/' \\\n> +\t\t>uncovered_new_lines.txt\n> +\n> +\tgrep -q '[^[:space:]]' < uncovered_new_lines.txt && \\\n\nStyle: when you end a line with && (or || or | for that matter), the\nshell knows that you have not finished speaking, and will wait to\nlisten to you to finish the sentence.  No need for backslash there.\n\n> +\t\techo $file && \\\n> +\t\tgit blame -c $file \\\n> +\t\t\t| grep -f uncovered_new_lines.txt\n> +\n> +\trm -f diff_file.txt new_lines.txt \\\n> +\t\tuncovered_lines.txt uncovered_new_lines.txt\n> +done\n> +\n> +rm -rf files.txt\n"},{"id":"358021","messageId":"xmqq5zzajpi1.fsf@gitster-ct.c.googlers.com","threadId":"49331","inReplyTo":"xmqqa7omjred.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 1/1] contrib: add coverage-diff script","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-09-12T22:54:30Z","receivedAt":"2018-09-12T22:54:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> \"Derrick Stolee via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n>\n>>  contrib/coverage-diff.sh | 70 ++++++++++++++++++++++++++++++++++++++++\n>>  1 file changed, 70 insertions(+)\n>>  create mode 100755 contrib/coverage-diff.sh\n>\n> I fully appreciate the motivation.  But it is a bit sad that this\n> begins with \"#!/bin/bash\" but it seems that the script is full of\n> bash-isms.  I haven't gone through the script to see if these are\n> inevitable or gratuitous yet, but I'd assume it made it easier for\n> you to write it to step outside the pure POSIX shell?\n> ...\n>> +\telif [[ $REPLY =~ \\+\\+\\+\\ (b/)?([^[:blank:]$esc]+).* ]]; then\n>> +\t    path=${BASH_REMATCH[2]}\n>\n> OK, it probably is easier to write in bash than using expr if you\n> want to do regexp.\n\nJust to clarify. I am saying that it is OK to give up writing in\npure POSIX and relying on bash-isms after seeing these lines.\n"},{"id":"358045","messageId":"1e712541-3101-049a-acd2-b6d7c98bd1e2@gmail.com","threadId":"49331","inReplyTo":"xmqq5zzajpi1.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 1/1] contrib: add coverage-diff script","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-09-13T12:21:14Z","receivedAt":"2018-09-13T12:21:19Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 9/12/2018 6:54 PM, Junio C Hamano wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> \"Derrick Stolee via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n>>\n>>>   contrib/coverage-diff.sh | 70 ++++++++++++++++++++++++++++++++++++++++\n>>>   1 file changed, 70 insertions(+)\n>>>   create mode 100755 contrib/coverage-diff.sh\n>> I fully appreciate the motivation.  But it is a bit sad that this\n>> begins with \"#!/bin/bash\" but it seems that the script is full of\n>> bash-isms.  I haven't gone through the script to see if these are\n>> inevitable or gratuitous yet, but I'd assume it made it easier for\n>> you to write it to step outside the pure POSIX shell?\n\nI completely forgot to avoid bash, as I wrote this first as an experiment.\n\n>> ...\n>>> +\telif [[ $REPLY =~ \\+\\+\\+\\ (b/)?([^[:blank:]$esc]+).* ]]; then\n>>> +\t    path=${BASH_REMATCH[2]}\n>> OK, it probably is easier to write in bash than using expr if you\n>> want to do regexp.\n> Just to clarify. I am saying that it is OK to give up writing in\n> pure POSIX and relying on bash-isms after seeing these lines.\n\nI'll try rewriting it using POSIX shell and see how hard it is.\n\nThanks,\n\n-Stolee\n\n"},{"id":"358048","messageId":"pull.40.v2.git.gitgitgadget@gmail.com","threadId":"49331","inReplyTo":"pull.40.git.gitgitgadget@gmail.com","subject":"[PATCH v2 0/1] contrib: Add script to show uncovered \"new\" lines","fromName":"Derrick Stolee via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-13T14:56:42Z","receivedAt":"2018-09-13T14:56:47Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"We have coverage targets in our Makefile for using gcov to display line\ncoverage based on our test suite. The way I like to do it is to run:\n\nmake coverage-test\nmake coverage-report\n\nThis leaves the repo in a state where every X.c file that was covered has an\nX.c.gcov file containing the coverage counts for every line, and \"#####\" at\nevery uncovered line.\n\nThere have been a few bugs in recent patches what would have been caught if\nthe test suite covered those blocks (including a few of mine). I want to\nwork towards a \"sensible\" amount of coverage on new topics. In my opinion,\nthis means that any logic should be covered, but the 'die()' blocks in error\ncases do not need to be covered.\n\nIt is important to not measure the coverage of the codebase by what old code\nis not covered. To help, I created the 'contrib/coverage-diff.sh' script.\nAfter creating the coverage statistics at a version (say, 'topic') you can\nthen run\n\ncontrib/coverage-diff.sh base topic\n\nto see the lines added between 'base' and 'topic' that are not covered by\nthe test suite. For example, I ran this against the 'jch' branch (d3c0046)\nversus 'next' (dd90340) and got the following output:\n\nbuiltin/commit.c\n859fdc0c3cf     (Derrick Stolee 2018-08-29 05:49:04 -0700       1657)           write_commit_graph_reachable(get_object_directory(), 0);\nbuiltin/rev-list.c\n250edfa8c87     (Harald Nordgren        2018-04-18 23:05:35 +0200       431)                    bisect_flags |= BISECT_FIND_ALL;\nbuiltin/worktree.c\ne5353bef550     (Eric Sunshine  2018-08-28 17:20:19 -0400       60)             error_errno(_(\"failed to delete '%s'\"), sb.buf);\ne19831c94f9     (Eric Sunshine  2018-08-28 17:20:23 -0400       251)                die(_(\"unable to re-add worktree '%s'\"), path);\n68a6b3a1bd4     (Eric Sunshine  2018-08-28 17:20:24 -0400       793)                    die(_(\"cannot move a locked working tree, lock reason: %s\\nuse 'move -f -f' to override or unlock first\"),\nf4143101cbb     (Eric Sunshine  2018-08-28 17:20:25 -0400       906)                    die(_(\"cannot remove a locked working tree, lock reason: %s\\nuse 'remove -f -f' to override or unlock first\"),\nread-cache.c\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1754)           const unsigned char *cp = (const unsigned char *)name;\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1757)           previous_len = previous_ce ? previous_ce->ce_namelen : 0;\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1758)           strip_len = decode_varint(&cp);\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1759)           if (previous_len < strip_len) {\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1760)                   if (previous_ce)\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1761)                           die(_(\"malformed name field in the index, near path '%s'\"),\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1762)                               previous_ce->name);\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1764)                           die(_(\"malformed name field in the index in the first path\"));\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1766)           copy_len = previous_len - strip_len;\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1767)           name = (const char *)cp;\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1773)                   len += copy_len;\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1794)           if (copy_len)\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1795)                   memcpy(ce->name, previous_ce->name, copy_len);\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1796)           memcpy(ce->name + copy_len, name, len + 1 - copy_len);\n67922abbbb3     (Nguyễn Thái Ngọc Duy   2018-09-02 15:19:33 +0200       1797)           *ent_size = (name - ((char *)ondisk)) + len + 1 - copy_len;\nremote-curl.c\nc3b9bc94b9b     (Elijah Newren  2018-09-05 10:03:07 -0700       181)            options.filter = xstrdup(value);\n\nUsing this 'git blame' output, we can quickly inspect whether the uncovered\nlines are appropriate. For instance:\n\n 1. The line in builtin/commit.c is due to writing the commit-graph file\n    when GIT_TEST_COMMIT_GRAPH is enabled, which is not on by default in the\n    test suite. Being uncovered is expected here.\n    \n    \n 2. The lines in builtin/worktree.c are all related to error conditions.\n    This is acceptable.\n    \n    \n 3. The line in builtin/rev-list.c is a flag replacement in a block that is\n    otherwise unchanged. It must not be covered by the test suite normally.\n    This could be worth adding a test to ensure the new logic maintains old\n    behavior.\n    \n    \n 4. The lines in read-cache.c are part of a new block for the condition \"if\n    (expand_name_field)\" as part of an optimization. These lines should\n    probably be covered before that series is merged to 'next'. I understand\n    that Ben and Duy are continuing work in this direction [1].\n    \n    \n\nI used this approach for 'next' over 'master' and got a larger list, some of\nwhich I have already submitted tests to increase coverage [2] or will be\ncovered by topics not in 'next' [3].\n\nThanks, -Stolee\n\nCHANGES IN V2: I converted the script from bash to sh (there may still be\nPOSIX-compliance issues with the new script, I don't know a lot when it\ncomes to that area). I also streamlined the machinery to add line numbers to\nthe diff. One downside is that the script runs a little slower with all of\nthe grep process invocations.\n\n[1] \nhttps://public-inbox.org/git/20180912161832.55324-1-benpeart@microsoft.com/T/#u\n\n[2] https://public-inbox.org/git/pull.37.git.gitgitgadget@gmail.com/\n\n[3] https://public-inbox.org/git/pull.34.git.gitgitgadget@gmail.com/\n\nDerrick Stolee (1):\n  contrib: add coverage-diff script\n\n contrib/coverage-diff.sh | 63 ++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 63 insertions(+)\n create mode 100755 contrib/coverage-diff.sh\n\n\nbase-commit: 1d4361b0f344188ab5eec6dcea01f61a3a3a1670\nPublished-As: https://github.com/gitgitgadget/git/releases/tags/pr-40%2Fderrickstolee%2Fcoverage-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-40/derrickstolee/coverage-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/40\n\nRange-diff vs v1:\n\n 1:  e4124471e5 < -:  ---------- contrib: add coverage-diff script\n -:  ---------- > 1:  7714b0659e contrib: add coverage-diff script\n\n-- \ngitgitgadget\n"},{"id":"358049","messageId":"7714b0659e3210e34d0904b3347473427546d15c.1536850601.git.gitgitgadget@gmail.com","threadId":"49331","inReplyTo":"pull.40.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 1/1] contrib: add coverage-diff script","fromName":"Derrick Stolee via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-13T14:56:44Z","receivedAt":"2018-09-13T14:56:48Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"From: Derrick Stolee <dstolee@microsoft.com>\n\nWe have coverage targets in our Makefile for using gcov to display line\ncoverage based on our test suite. The way I like to do it is to run:\n\n    make coverage-test\n    make coverage-report\n\nThis leaves the repo in a state where every X.c file that was covered has\nan X.c.gcov file containing the coverage counts for every line, and \"#####\"\nat every uncovered line.\n\nThere have been a few bugs in recent patches what would have been caught\nif the test suite covered those blocks (including a few of mine). I want\nto work towards a \"sensible\" amount of coverage on new topics. In my opinion,\nthis means that any logic should be covered, but the 'die()' blocks in error\ncases do not need to be covered.\n\nIt is important to not measure the coverage of the codebase by what old code\nis not covered. To help, I created the 'contrib/coverage-diff.sh' script.\nAfter creating the coverage statistics at a version (say, 'topic') you can\nthen run\n\n    contrib/coverage-diff.sh base topic\n\nto see the lines added between 'base' and 'topic' that are not covered by the\ntest suite. The output uses 'git blame -c' format so you can find the commits\nresponsible and view the line numbers for quick access to the context.\n\nSigned-off-by: Derrick Stolee <dstolee@microsoft.com>\n---\n contrib/coverage-diff.sh | 63 ++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 63 insertions(+)\n create mode 100755 contrib/coverage-diff.sh\n\ndiff --git a/contrib/coverage-diff.sh b/contrib/coverage-diff.sh\nnew file mode 100755\nindex 0000000000..0f226f038c\n--- /dev/null\n+++ b/contrib/coverage-diff.sh\n@@ -0,0 +1,63 @@\n+#!/bin/sh\n+\n+# Usage: 'contrib/coverage-diff.sh <version1> <version2>\n+# Outputs a list of new lines in version2 compared to version1 that are\n+# not covered by the test suite. Assumes you ran\n+# 'make coverage-test coverage-report' from root first, so .gcov files exist.\n+\n+V1=$1\n+V2=$2\n+\n+diff_lines () {\n+\twhile read line\n+\tdo\n+\t\tif echo $line | grep -q -e \"^@@ -([0-9]+)(,[0-9]+)? \\\\+([0-9]+)(,[0-9]+)? @@.*\"\n+\t\tthen\n+\t\t\tline_num=$(echo $line \\\n+\t\t\t\t| awk 'match($0, \"@@ -([0-9]+)(,[0-9]+)? \\\\+([0-9]+)(,[0-9]+)? @@.*\", m) { print m[3] }')\n+\t\telse\n+\t\t\techo \"$line_num:$line\"\n+\t\t\tif ! echo $line | grep -q -e \"^-\"\n+\t\t\tthen\n+\t\t\t\tline_num=$(($line_num + 1))\n+\t\t\tfi\n+\t\tfi\n+\tdone\n+}\n+\n+files=$(git diff --raw $V1 $V2 \\\n+\t| grep \\.c$ \\\n+\t| awk 'NF>1{print $NF}')\n+\n+for file in $files\n+do\n+\tgit diff $V1 $V2 -- $file \\\n+\t\t| diff_lines \\\n+\t\t| grep \":+\" \\\n+\t\t| sed 's/:/ /g' \\\n+\t\t| awk '{print $1}' \\\n+\t\t| sort \\\n+\t\t>new_lines.txt\n+\n+\thash_file=$(echo $file | sed \"s/\\//\\#/\")\n+\tcat \"$hash_file.gcov\" \\\n+\t\t| grep \\#\\#\\#\\#\\# \\\n+\t\t| sed 's/    #####: //g' \\\n+\t\t| sed 's/\\:/ /g' \\\n+\t\t| awk '{print $1}' \\\n+\t\t| sort \\\n+\t\t>uncovered_lines.txt\n+\n+\tcomm -12 uncovered_lines.txt new_lines.txt \\\n+\t\t| sed -e 's/$/\\)/' \\\n+\t\t| sed -e 's/^/\\t/' \\\n+\t\t>uncovered_new_lines.txt\n+\n+\tgrep -q '[^[:space:]]' < uncovered_new_lines.txt && \\\n+\t\techo $file && \\\n+\t\tgit blame -c $file \\\n+\t\t\t| grep -f uncovered_new_lines.txt\n+\n+\trm -f new_lines.txt uncovered_lines.txt uncovered_new_lines.txt\n+done\n+\n-- \ngitgitgadget\n"},{"id":"358051","messageId":"xmqqin39igt2.fsf@gitster-ct.c.googlers.com","threadId":"49331","inReplyTo":"1e712541-3101-049a-acd2-b6d7c98bd1e2@gmail.com","subject":"Re: [PATCH 1/1] contrib: add coverage-diff script","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-09-13T14:59:53Z","receivedAt":"2018-09-13T14:59:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Derrick Stolee <stolee@gmail.com> writes:\n\n> On 9/12/2018 6:54 PM, Junio C Hamano wrote:\n>> Junio C Hamano <gitster@pobox.com> writes:\n>>\n>>> \"Derrick Stolee via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n>>>\n>>>>   contrib/coverage-diff.sh | 70 ++++++++++++++++++++++++++++++++++++++++\n>>>>   1 file changed, 70 insertions(+)\n>>>>   create mode 100755 contrib/coverage-diff.sh\n>>> I fully appreciate the motivation.  But it is a bit sad that this\n>>> begins with \"#!/bin/bash\" but it seems that the script is full of\n>>> bash-isms.  I haven't gone through the script to see if these are\n>>> inevitable or gratuitous yet, but I'd assume it made it easier for\n>>> you to write it to step outside the pure POSIX shell?\n>\n> I completely forgot to avoid bash, as I wrote this first as an experiment.\n>\n>>> ...\n>>>> +\telif [[ $REPLY =~ \\+\\+\\+\\ (b/)?([^[:blank:]$esc]+).* ]]; then\n>>>> +\t    path=${BASH_REMATCH[2]}\n>>> OK, it probably is easier to write in bash than using expr if you\n>>> want to do regexp.\n>> Just to clarify. I am saying that it is OK to give up writing in\n>> pure POSIX and relying on bash-isms after seeing these lines.\n>\n> I'll try rewriting it using POSIX shell and see how hard it is.\n\nThanks.  Don't waste too much time on it and try to bend backwards\ntoo far, though.\n"},{"id":"358061","messageId":"xmqqzhwlfg7o.fsf@gitster-ct.c.googlers.com","threadId":"49331","inReplyTo":"7714b0659e3210e34d0904b3347473427546d15c.1536850601.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 1/1] contrib: add coverage-diff script","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-09-13T17:40:59Z","receivedAt":"2018-09-13T17:41:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Derrick Stolee via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> From: Derrick Stolee <dstolee@microsoft.com>\n>\n> We have coverage targets in our Makefile for using gcov to display line\n> coverage based on our test suite. The way I like to do it is to run:\n>\n>     make coverage-test\n>     make coverage-report\n>\n> This leaves the repo in a state where every X.c file that was covered has\n> an X.c.gcov file containing the coverage counts for every line, and \"#####\"\n> at every uncovered line.\n>\n> There have been a few bugs in recent patches what would have been caught\n> if the test suite covered those blocks (including a few of mine). I want\n> to work towards a \"sensible\" amount of coverage on new topics. In my opinion,\n> this means that any logic should be covered, but the 'die()' blocks in error\n> cases do not need to be covered.\n>\n> It is important to not measure the coverage of the codebase by what old code\n> is not covered. To help, I created the 'contrib/coverage-diff.sh' script.\n> After creating the coverage statistics at a version (say, 'topic') you can\n> then run\n>\n>     contrib/coverage-diff.sh base topic\n>\n> to see the lines added between 'base' and 'topic' that are not covered by the\n> test suite. The output uses 'git blame -c' format so you can find the commits\n> responsible and view the line numbers for quick access to the context.\n>\n> Signed-off-by: Derrick Stolee <dstolee@microsoft.com>\n> ---\n>  contrib/coverage-diff.sh | 63 ++++++++++++++++++++++++++++++++++++++++\n>  1 file changed, 63 insertions(+)\n>  create mode 100755 contrib/coverage-diff.sh\n>\n> diff --git a/contrib/coverage-diff.sh b/contrib/coverage-diff.sh\n> new file mode 100755\n> index 0000000000..0f226f038c\n> --- /dev/null\n> +++ b/contrib/coverage-diff.sh\n> @@ -0,0 +1,63 @@\n> +#!/bin/sh\n> +\n> +# Usage: 'contrib/coverage-diff.sh <version1> <version2>\n> +# Outputs a list of new lines in version2 compared to version1 that are\n> +# not covered by the test suite. Assumes you ran\n> +# 'make coverage-test coverage-report' from root first, so .gcov files exist.\n\nI presume that it is \"from root first while you have a checkout of\nversion2, so .gcov files for version2 exist in the working tree\"?\n\n> +V1=$1\n> +V2=$2\n> +\n> +diff_lines () {\n> +\twhile read line\n> +\tdo\n> +\t\tif echo $line | grep -q -e \"^@@ -([0-9]+)(,[0-9]+)? \\\\+([0-9]+)(,[0-9]+)? @@.*\"\n\nAs you know you are reading from diff output, you do not have to be\nso strict in this if condition.  It's not like you try to carefully\nreject a line that began with \"@@\" but did not match this pattern in\nthe corresponding else block.\n\n\"read line\" does funny things to backslashes and whitespaces in the\npayload (\"read -r line\" sometimes helps), and echoing $line without\nquoting will destroy its contents here and in the line below (but\nyou do not care because all you care about is if it begins with a\ndash).\n\n> +\t\tthen\n> +\t\t\tline_num=$(echo $line \\\n> +\t\t\t\t| awk 'match($0, \"@@ -([0-9]+)(,[0-9]+)? \\\\+([0-9]+)(,[0-9]+)? @@.*\", m) { print m[3] }')\n> +\t\telse\n> +\t\t\techo \"$line_num:$line\"\n> +\t\t\tif ! echo $line | grep -q -e \"^-\"\n\nIf a patch removes a line with a solitary 'n' on it, possibly\nfollowed by a SP and something else, such a line would say \"-n\nsomething else\", and some implementation of \"echo -n something else\"\nwould do what this line does not expect.  A safer way to do this,\nas you only care if it is a deletion line, is to do\n\n\tcase \"$line\" in -*) ;; *) line_num=$(( $line_num + 1 ));; esac\n\nAlso you can make the echoing of \"$line_num:$line\" above\nconditional, which will allow you to lose \"grep ':+'\" in the\npipeline that consumes output from this thing, e.g.\n\n\tcase \"$line\" in +*) echo \"$line_num:$line\";; esac\n\niff you must write this in shell (but see below).\n\n> +\t\t\tthen\n> +\t\t\t\tline_num=$(($line_num + 1))\n> +\t\t\tfi\n> +\t\tfi\n> +\tdone\n\nI have a feeling that a single Perl script instead of a shell loop\nthat runs many grep and awk as subprocesses performs better even on\nWindows, and it would be more readable and maintainable.\n\nperl -e '\n\tmy $line_num;\n\twhile (<>) {\n\t\t# Hunk header?  Grab the beginning in postimage.\n\t\tif (/^@@ -\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/) {\n\t\t\t$line_num = $1;\n\t\t\tnext;\n\t\t}\n\n\t\t# Have we seen a hunk?  Ignore \"diff --git\" etc.\n\t\tnext unless defined $line_num;\n\n\t\t# Deleted line? Ignore.\n\t\tif (/^-/) {\n\t\t\tnext;\n\t\t}\n\n\t\t# Show only the line number of added lines.\n\t\tif (/^\\+/) {\n\t\t\tprint \"$line_num\\n\";\n\t\t}\n\t\t# Either common context or added line appear in\n\t\t# the postimage.  Count it.\n\t\t$line_num++;\n\t}\n'\n\nor something like that, given that you seem to only need line\nnumbers in new_lines.txt anyway?\n\n> +}\n> +\n> +files=$(git diff --raw $V1 $V2 \\\n> +\t| grep \\.c$ \\\n> +\t| awk 'NF>1{print $NF}')\n\nDo we need these other commands in the pipe?  How is this different\nfrom, say,\n\n\tgit diff --name-only \"$V1\" \"$V2\" -- \\*.c\n\n?\n\n> +for file in $files\n> +do\n> +\tgit diff $V1 $V2 -- $file \\\n> +\t\t| diff_lines \\\n> +\t\t| grep \":+\" \\\n\nI think you meant to match \"^<linenum>:+<added contents>\" you are\nechoing out in the above helper function, but this will find a\nremoved line that happens to have colon followed by a plus (which is\nnot all that uncommon in a patch to a shell script).\n\n> +\t\t| sed 's/:/ /g' \\\n\nTurning \"<linenum>:+<added contents>\" to \"<linenum> +<added contents>\"\nwith this, so that the next \"awk\" can show <linenum> only?  Then you\ndo not need 'g' at the end.  I see you use 'g' in many sed scripts\nfor uncovered_lines.txt, and I suspect most of 'g's you do not mean.\n\n> +\t\t| awk '{print $1}' \\\n\nThen we get a list of $line_num here?\n\n> +\t\t| sort \\\n\nThis is sorted textually, which goes against intuition because these\nlines are all line numbers, but it is done so that you can run\n\"comm\" on it later and \"comm\" requires us to feed lines sorted\ntextually.\n\n> +\t\t>new_lines.txt\n\nIf I were writing this part, I'd probably write a small Perl script\nthat takes output from 'git diff \"$V1\" \"$V2\" -- \"$file\"' and then\nreduces it to a list of line numbers for newly introduced lines.\nThen pipe it to \"sort >new_lines.txt\" to match what we see below.\n\n> +\thash_file=$(echo $file | sed \"s/\\//\\#/\")\n> +\tcat \"$hash_file.gcov\" \\\n> +\t\t| grep \\#\\#\\#\\#\\# \\\n> +\t\t| sed 's/    #####: //g' \\\n> +\t\t| sed 's/\\:/ /g' \\\n> +\t\t| awk '{print $1}' \\\n> +\t\t| sort \\\n> +\t\t>uncovered_lines.txt\n\nDo not cat a single regular file into a pipe.  Write pipe at the end\nof the line, not the beginning of next line.  Do not grep into sed.\nDo not feed sed into sed unless needed.\n\nWithout knowing what the above is trying to do, but just\nmechanically translating, I'd get something like this:\n\n\tsed -ne '/#####/{\n\t\ts/    #####: //g\n\t\ts/:.*//\n                p\n\t}' \"$hash_file.gcov\" |\n\tsort >uncovered_lines.txt\n\n> +\tcomm -12 uncovered_lines.txt new_lines.txt \\\n> +\t\t| sed -e 's/$/\\)/' \\\n> +\t\t| sed -e 's/^/\\t/' \\\n> +\t\t>uncovered_new_lines.txt\n\n;-)  This creates something like\n\n\t1)\n\t2)\n\t3)\n\nout of a list of numbers.  Cute.\n\n> +\tgrep -q '[^[:space:]]' < uncovered_new_lines.txt && \\\n> +\t\techo $file && \\\n> +\t\tgit blame -c $file \\\n> +\t\t\t| grep -f uncovered_new_lines.txt\n> +\n> +\trm -f new_lines.txt uncovered_lines.txt uncovered_new_lines.txt\n> +done\n> +\n"},{"id":"358064","messageId":"CAPig+cQeA9UhVEAz-4TgMD4K6FsFk5tL0AH_uSjXApt888q25g@mail.gmail.com","threadId":"49331","inReplyTo":"7714b0659e3210e34d0904b3347473427546d15c.1536850601.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 1/1] contrib: add coverage-diff script","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-09-13T17:54:37Z","receivedAt":"2018-09-13T17:54:50Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Sep 13, 2018 at 10:56 AM Derrick Stolee via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n> There have been a few bugs in recent patches what would have been caught\n> if the test suite covered those blocks (including a few of mine). I want\n> to work towards a \"sensible\" amount of coverage on new topics. In my opinion,\n> this means that any logic should be covered, but the 'die()' blocks in error\n> cases do not need to be covered.\n\nThe bit about die() blocks is perhaps a bit too general. While it's\ntrue that some die()'s signal very unlikely (or near-impossible)\nconditions, others are merely reporting invalid user or other input to\nthe program. The latter category is often very much worth testing, as\nthe number of test_must_fail() invocations in the test suite shows.\n68a6b3a1bd (worktree: teach 'move' to override lock when --force given\ntwice, 2018-08-28), which was highlighted in your cover letter,\nprovides a good example of legitimately testing that a die() is\ncovered. So, perhaps the above can be toned-down a bit by saying\nsomething like:\n\n    ...but die() blocks covering very unlikely (or near-impossible)\n    situations may not warrant coverage.\n\n> It is important to not measure the coverage of the codebase by what old code\n> is not covered.\n"},{"id":"358081","messageId":"3ba684df-f6eb-1ebb-2421-160b89b2f246@gmail.com","threadId":"49331","inReplyTo":"xmqqzhwlfg7o.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 1/1] contrib: add coverage-diff script","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-09-13T18:15:10Z","receivedAt":"2018-09-13T18:15:15Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 9/13/2018 1:40 PM, Junio C Hamano wrote:\n> \"Derrick Stolee via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n>> +\t\t\tthen\n>> +\t\t\t\tline_num=$(($line_num + 1))\n>> +\t\t\tfi\n>> +\t\tfi\n>> +\tdone\n> I have a feeling that a single Perl script instead of a shell loop\n> that runs many grep and awk as subprocesses performs better even on\n> Windows, and it would be more readable and maintainable.\n>\n> perl -e '\n> \tmy $line_num;\n> \twhile (<>) {\n> \t\t# Hunk header?  Grab the beginning in postimage.\n> \t\tif (/^@@ -\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/) {\n> \t\t\t$line_num = $1;\n> \t\t\tnext;\n> \t\t}\n>\n> \t\t# Have we seen a hunk?  Ignore \"diff --git\" etc.\n> \t\tnext unless defined $line_num;\n>\n> \t\t# Deleted line? Ignore.\n> \t\tif (/^-/) {\n> \t\t\tnext;\n> \t\t}\n>\n> \t\t# Show only the line number of added lines.\n> \t\tif (/^\\+/) {\n> \t\t\tprint \"$line_num\\n\";\n> \t\t}\n> \t\t# Either common context or added line appear in\n> \t\t# the postimage.  Count it.\n> \t\t$line_num++;\n> \t}\n> '\n>\n> or something like that, given that you seem to only need line\n> numbers in new_lines.txt anyway?\n\nThanks for the deep dive here, especially with the perl assistance. I've \nnever written any perl, but it seems like the right tool here. I'll have \ntime to revisit this next week.\n\nThanks,\n\n-Stolee\n\n"},{"id":"358574","messageId":"pull.40.v3.git.gitgitgadget@gmail.com","threadId":"49331","inReplyTo":"pull.40.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v3 0/1] contrib: Add script to show uncovered \"new\" lines","fromName":"Derrick Stolee via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-21T15:15:54Z","receivedAt":"2018-09-21T15:15:58Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"We have coverage targets in our Makefile for using gcov to display line\ncoverage based on our test suite. The way I like to do it is to run:\n\nmake coverage-test\nmake coverage-report\n\nThis leaves the repo in a state where every X.c file that was covered has an\nX.c.gcov file containing the coverage counts for every line, and \"#####\" at\nevery uncovered line.\n\nThere have been a few bugs in recent patches what would have been caught if\nthe test suite covered those blocks (including a few of mine). I want to\nwork towards a \"sensible\" amount of coverage on new topics. In my opinion,\nthis means that any logic should be covered, but the 'die()' blocks in error\ncases do not need to be covered.\n\nIt is important to not measure the coverage of the codebase by what old code\nis not covered. To help, I created the 'contrib/coverage-diff.sh' script.\nAfter creating the coverage statistics at a version (say, 'topic') you can\nthen run\n\ncontrib/coverage-diff.sh base topic\n\nto see the lines added between 'base' and 'topic' that are not covered by\nthe test suite. For example, I ran this against the 'next' branch (22e244b)\nversus 'master' (150f307) and got the following output:\n\nfsck.c\nfb8952077df     (René Scharfe   2018-09-03 14:49:26 +0000       212)            die_errno(\"Could not read '%s'\", path);\nlist-objects-filter-options.c\nf12b8fc6d3b     (Matthew DeVore 2018-09-13 17:55:27 -0700       56)                     if (errbuf) {\nf12b8fc6d3b     (Matthew DeVore 2018-09-13 17:55:27 -0700       57)                             strbuf_init(errbuf, 0);\nf12b8fc6d3b     (Matthew DeVore 2018-09-13 17:55:27 -0700       58)                             strbuf_addstr(\nf12b8fc6d3b     (Matthew DeVore 2018-09-13 17:55:27 -0700       62)                     return 1;\nlist-objects-filter.c\n77d7a65d502     (Matthew DeVore 2018-09-13 17:55:26 -0700       47)             BUG(\"unknown filter_situation: %d\", filter_situation);\nf12b8fc6d3b     (Matthew DeVore 2018-09-13 17:55:27 -0700       100)    default:\nf12b8fc6d3b     (Matthew DeVore 2018-09-13 17:55:27 -0700       101)            BUG(\"unknown filter_situation: %d\", filter_situation);\n77d7a65d502     (Matthew DeVore 2018-09-13 17:55:26 -0700       152)            BUG(\"unknown filter_situation: %d\", filter_situation);\n77d7a65d502     (Matthew DeVore 2018-09-13 17:55:26 -0700       257)            BUG(\"unknown filter_situation: %d\", filter_situation);\n77d7a65d502     (Matthew DeVore 2018-09-13 17:55:26 -0700       438)            BUG(\"invalid list-objects filter choice: %d\",\nlist-objects.c\nf447a499dbb     (Matthew DeVore 2018-08-13 11:14:28 -0700       197)                    ctx->show_object(obj, base->buf, ctx->show_data);\nll-merge.c\nd64324cb60e     (Torsten Bögershausen   2018-09-12 21:32:02 +0200       379)                    marker_size = DEFAULT_CONFLICT_MARKER_SIZE;\nmidx.c\n56ee7ff1565     (Derrick Stolee 2018-09-13 11:02:13 -0700       949)            return 0;\ncc6af73c029     (Derrick Stolee 2018-09-13 11:02:25 -0700       990)                    midx_report(_(\"failed to load pack-index for packfile %s\"),\ncc6af73c029     (Derrick Stolee 2018-09-13 11:02:25 -0700       991)                                e.p->pack_name);\ncc6af73c029     (Derrick Stolee 2018-09-13 11:02:25 -0700       992)                    break;\nremote-curl.c\nc3b9bc94b9b     (Elijah Newren  2018-09-05 10:03:07 -0700       181)            options.filter = xstrdup(value);\nsubmodule.c\ndf255b8cac7     (Brandon Williams       2018-08-08 15:33:22 -0700       1738)           die(_(\"could not create directory '%s'\"), new_gitdir.buf);\n\nUsing this 'git blame' output, we can quickly inspect whether the uncovered\nlines are appropriate. For instance:\n\n 1. The line in builtin/commit.c is due to writing the commit-graph file\n    when GIT_TEST_COMMIT_GRAPH is enabled, which is not on by default in the\n    test suite. Being uncovered is expected here.\n    \n    \n 2. The lines in builtin/worktree.c are all related to error conditions.\n    This is acceptable.\n    \n    \n 3. The line in builtin/rev-list.c is a flag replacement in a block that is\n    otherwise unchanged. It must not be covered by the test suite normally.\n    This could be worth adding a test to ensure the new logic maintains old\n    behavior.\n    \n    \n 4. The lines in read-cache.c are part of a new block for the condition \"if\n    (expand_name_field)\" as part of an optimization. These lines should\n    probably be covered before that series is merged to 'next'. I understand\n    that Ben and Duy are continuing work in this direction [1].\n    \n    \n\nI used this approach for 'next' over 'master' and got a larger list, some of\nwhich I have already submitted tests to increase coverage [2] or will be\ncovered by topics not in 'next' [3].\n\nThanks, -Stolee\n\nCHANGES IN V3: I took Junio's perl script verbatim, which speeds up the\nperformance greatly. Some of the other sed commands needed some massaging,\nbut also added extra cleanup. Thanks for the help!\n\n[1] \nhttps://public-inbox.org/git/20180912161832.55324-1-benpeart@microsoft.com/T/#u\n\n[2] https://public-inbox.org/git/pull.37.git.gitgitgadget@gmail.com/\n\n[3] https://public-inbox.org/git/pull.34.git.gitgitgadget@gmail.com/\n\nDerrick Stolee (1):\n  contrib: add coverage-diff script\n\n contrib/coverage-diff.sh | 79 ++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 79 insertions(+)\n create mode 100755 contrib/coverage-diff.sh\n\n\nbase-commit: 1d4361b0f344188ab5eec6dcea01f61a3a3a1670\nPublished-As: https://github.com/gitgitgadget/git/releases/tags/pr-40%2Fderrickstolee%2Fcoverage-v3\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-40/derrickstolee/coverage-v3\nPull-Request: https://github.com/gitgitgadget/git/pull/40\n\nRange-diff vs v2:\n\n 1:  7714b0659e < -:  ---------- contrib: add coverage-diff script\n -:  ---------- > 1:  21214cc321 contrib: add coverage-diff script\n\n-- \ngitgitgadget\n"},{"id":"358575","messageId":"21214cc321f80cf2e9eb0cdb1ec3ebb869ea496d.1537542952.git.gitgitgadget@gmail.com","threadId":"49331","inReplyTo":"pull.40.v3.git.gitgitgadget@gmail.com","subject":"[PATCH v3 1/1] contrib: add coverage-diff script","fromName":"Derrick Stolee via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-21T15:15:55Z","receivedAt":"2018-09-21T15:15:59Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"From: Derrick Stolee <dstolee@microsoft.com>\n\nWe have coverage targets in our Makefile for using gcov to display line\ncoverage based on our test suite. The way I like to do it is to run:\n\n    make coverage-test\n    make coverage-report\n\nThis leaves the repo in a state where every X.c file that was covered has\nan X.c.gcov file containing the coverage counts for every line, and \"#####\"\nat every uncovered line.\n\nThere have been a few bugs in recent patches what would have been caught\nif the test suite covered those blocks (including a few of mine). I want\nto work towards a \"sensible\" amount of coverage on new topics. In my opinion,\nthis means that any logic should be covered, but the 'die()' blocks covering\nvery unlikely (or near-impossible) situations may not warrant coverage.\n\nIt is important to not measure the coverage of the codebase by what old code\nis not covered. To help, I created the 'contrib/coverage-diff.sh' script.\nAfter creating the coverage statistics at a version (say, 'topic') you can\nthen run\n\n    contrib/coverage-diff.sh base topic\n\nto see the lines added between 'base' and 'topic' that are not covered by the\ntest suite. The output uses 'git blame -c' format so you can find the commits\nresponsible and view the line numbers for quick access to the context.\n\nHelped-by: Junio C Hamano <gister@pobox.com>\nSigned-off-by: Derrick Stolee <dstolee@microsoft.com>\n---\n contrib/coverage-diff.sh | 79 ++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 79 insertions(+)\n create mode 100755 contrib/coverage-diff.sh\n\ndiff --git a/contrib/coverage-diff.sh b/contrib/coverage-diff.sh\nnew file mode 100755\nindex 0000000000..48b9a3ae96\n--- /dev/null\n+++ b/contrib/coverage-diff.sh\n@@ -0,0 +1,79 @@\n+#!/bin/sh\n+\n+# Usage: Run 'contrib/coverage-diff.sh <version1> <version2>' from source-root\n+# after running\n+#\n+#     make coverage-test\n+#     make coverage-report\n+#\n+# while checked out at <version2>. This script combines the *.gcov files\n+# generated by the 'make' commands above with 'git diff <version1> <version2>'\n+# to report new lines that are not covered by the test suite.\n+\n+V1=$1\n+V2=$2\n+\n+diff_lines () {\n+\tperl -e '\n+\t\tmy $line_num;\n+\t\twhile (<>) {\n+\t\t\t# Hunk header?  Grab the beginning in postimage.\n+\t\t\tif (/^@@ -\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/) {\n+\t\t\t\t$line_num = $1;\n+\t\t\t\tnext;\n+\t\t\t}\n+\n+\t\t\t# Have we seen a hunk?  Ignore \"diff --git\" etc.\n+\t\t\tnext unless defined $line_num;\n+\n+\t\t\t# Deleted line? Ignore.\n+\t\t\tif (/^-/) {\n+\t\t\t\tnext;\n+\t\t\t}\n+\n+\t\t\t# Show only the line number of added lines.\n+\t\t\tif (/^\\+/) {\n+\t\t\t\tprint \"$line_num\\n\";\n+\t\t\t}\n+\t\t\t# Either common context or added line appear in\n+\t\t\t# the postimage.  Count it.\n+\t\t\t$line_num++;\n+\t\t}\n+\t'\n+}\n+\n+files=$(git diff --name-only $V1 $V2 -- *.c)\n+\n+for file in $files\n+do\n+\tgit diff $V1 $V2 -- $file \\\n+\t\t| diff_lines \\\n+\t\t| sort >new_lines.txt\n+\n+\tif ! test -s new_lines.txt\n+\tthen\n+\t\tcontinue\n+\tfi\n+\n+\thash_file=$(echo $file | sed \"s/\\//\\#/\")\n+\tsed -ne '/#####:/{\n+\t\t\ts/    #####://\n+\t\t\ts/:.*//\n+\t\t\ts/ //g\n+\t\t\tp\n+\t\t}' \"$hash_file.gcov\" \\\n+\t\t| sort >uncovered_lines.txt\n+\n+\tcomm -12 uncovered_lines.txt new_lines.txt \\\n+\t\t| sed -e 's/$/\\)/' \\\n+\t\t| sed -e 's/^/\\t/' \\\n+\t\t>uncovered_new_lines.txt\n+\n+\tgrep -q '[^[:space:]]' < uncovered_new_lines.txt && \\\n+\t\techo $file && \\\n+\t\tgit blame -c $file \\\n+\t\t\t| grep -f uncovered_new_lines.txt\n+\n+\trm -f new_lines.txt uncovered_lines.txt uncovered_new_lines.txt\n+done\n+\n-- \ngitgitgadget\n"},{"id":"358576","messageId":"ee607ff3-b13e-b034-f0cc-03ee458e187e@gmail.com","threadId":"49331","inReplyTo":"pull.40.v3.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 0/1] contrib: Add script to show uncovered \"new\" lines","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-09-21T15:20:22Z","receivedAt":"2018-09-21T15:20:26Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 9/21/2018 11:15 AM, Derrick Stolee via GitGitGadget wrote:\n> For example, I ran this against the 'next' branch (22e244b)\n> versus 'master' (150f307) and got the following output:\n>\n> fsck.c\n> fb8952077df     (René Scharfe   2018-09-03 14:49:26 +0000       212)            die_errno(\"Could not read '%s'\", path);\n> list-objects-filter-options.c\n> f12b8fc6d3b     (Matthew DeVore 2018-09-13 17:55:27 -0700       56)                     if (errbuf) {\n> f12b8fc6d3b     (Matthew DeVore 2018-09-13 17:55:27 -0700       57)                             strbuf_init(errbuf, 0);\n> f12b8fc6d3b     (Matthew DeVore 2018-09-13 17:55:27 -0700       58)                             strbuf_addstr(\n> f12b8fc6d3b     (Matthew DeVore 2018-09-13 17:55:27 -0700       62)                     return 1;\n> list-objects-filter.c\n> 77d7a65d502     (Matthew DeVore 2018-09-13 17:55:26 -0700       47)             BUG(\"unknown filter_situation: %d\", filter_situation);\n> f12b8fc6d3b     (Matthew DeVore 2018-09-13 17:55:27 -0700       100)    default:\n> f12b8fc6d3b     (Matthew DeVore 2018-09-13 17:55:27 -0700       101)            BUG(\"unknown filter_situation: %d\", filter_situation);\n> 77d7a65d502     (Matthew DeVore 2018-09-13 17:55:26 -0700       152)            BUG(\"unknown filter_situation: %d\", filter_situation);\n> 77d7a65d502     (Matthew DeVore 2018-09-13 17:55:26 -0700       257)            BUG(\"unknown filter_situation: %d\", filter_situation);\n> 77d7a65d502     (Matthew DeVore 2018-09-13 17:55:26 -0700       438)            BUG(\"invalid list-objects filter choice: %d\",\n> list-objects.c\n> f447a499dbb     (Matthew DeVore 2018-08-13 11:14:28 -0700       197)                    ctx->show_object(obj, base->buf, ctx->show_data);\n> ll-merge.c\n> d64324cb60e     (Torsten Bögershausen   2018-09-12 21:32:02 +0200       379)                    marker_size = DEFAULT_CONFLICT_MARKER_SIZE;\n> midx.c\n> 56ee7ff1565     (Derrick Stolee 2018-09-13 11:02:13 -0700       949)            return 0;\n> cc6af73c029     (Derrick Stolee 2018-09-13 11:02:25 -0700       990)                    midx_report(_(\"failed to load pack-index for packfile %s\"),\n> cc6af73c029     (Derrick Stolee 2018-09-13 11:02:25 -0700       991)                                e.p->pack_name);\n> cc6af73c029     (Derrick Stolee 2018-09-13 11:02:25 -0700       992)                    break;\n> remote-curl.c\n> c3b9bc94b9b     (Elijah Newren  2018-09-05 10:03:07 -0700       181)            options.filter = xstrdup(value);\n> submodule.c\n> df255b8cac7     (Brandon Williams       2018-08-08 15:33:22 -0700       1738)           die(_(\"could not create directory '%s'\"), new_gitdir.buf);\n\nI updated this output, but then forgot that I had a \"commentary\" of the \nold diff below it. Please ignore that portion of the cover letter.\n\n-Stolee\n\n"},{"id":"358852","messageId":"xmqqo9clpgox.fsf@gitster-ct.c.googlers.com","threadId":"49331","inReplyTo":"21214cc321f80cf2e9eb0cdb1ec3ebb869ea496d.1537542952.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 1/1] contrib: add coverage-diff script","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-09-25T18:36:46Z","receivedAt":"2018-09-25T18:36:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Derrick Stolee via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> +files=$(git diff --name-only $V1 $V2 -- *.c)\n\nYou'd want to quote that *.c from the shell, i.e. either one of\nthese\n\n\tfiles=$(git diff --name-only $V1 $V2 -- \\*.c)\n\tfiles=$(git diff --name-only $V1 $V2 -- '*.c')\n\notherwise you'd lose things like \"builtin/am.c\", I'd think.\n\n> +\n> +for file in $files\n> +do\n\nI know this is only for running in _our_ source tree, and we do not\nhave a source with $IFS in it, so I'd declare that this is OK.  It\nwould be good to document that assumption in red capital letters at\nthe beginning of this loop, though ;-)\n\n\t# Note: this script is only for our codebase and we rely on\n\t# the fact that the pathnames of our source files do not\n\t# have any funny characters---letting the shell split $files\n\t# list at $IFS boundary is very much intentional, and not\n\t# quoting \"$file\" in the code below also is.  Don't imitate\n\t# this in scripts that are meant to handle random end-user\n\t# repositories!\n\tfor file in $files\n\tdo\n\t\t...\n\n> +\tgit diff $V1 $V2 -- $file \\\n> +\t\t| diff_lines \\\n> +\t\t| sort >new_lines.txt\n\nI do not see a strong reason why we would want to limit $V1 and $V2\nto branch names and raw commit object names, and quoting them in dq\npair is a cheap fix to allow things like\n\n\t$ contrib/coverage-diff.sh master 'pu^{/^### match next}'\n\nso let's do so.\n\nCould you cut lines _after_ typing a pipe and omit backslashes, i.e.\n\n\tgit diff \"$V1\" \"$V2\" -- $file |\n\tdiff_lines |\n\tsort >new_lines.txt\n\nIt seems to be personal taste whether to indent the second and\nsubsequent lines; I do not care if you indent or if you align too\nmuch either way (but I have moderate perference to align).  \n\nBut I do not want to see people type unnecessary backslashes.  This\nis not limited to just this pipeline but elsewhere in the script.\n\n> +\tif ! test -s new_lines.txt\n> +\tthen\n> +\t\tcontinue\n> +\tfi\n> +\n> +\thash_file=$(echo $file | sed \"s/\\//\\#/\")\n> +\tsed -ne '/#####:/{\n> +\t\t\ts/    #####://\n> +\t\t\ts/:.*//\n> +\t\t\ts/ //g\n> +\t\t\tp\n> +\t\t}' \"$hash_file.gcov\" \\\n> +\t\t| sort >uncovered_lines.txt\n> +\n> +\tcomm -12 uncovered_lines.txt new_lines.txt \\\n> +\t\t| sed -e 's/$/\\)/' \\\n> +\t\t| sed -e 's/^/\\t/' \\\n\nDo you need two sed invocations for this, or would\n\n\tsed -e 's/$/\\)/' -e '/^/\t/'\n\nwork as well?  By the way \"\"\"The meaning of an unescaped <backslash>\nimmediately followed by any character other than '&', <backslash>, a\ndigit, <newline>, or the delimiter character used for this command,\nis unspecified.\"\"\"[*1*] so '\\t' on the replacement side is a no-no\nin the portability department.\n\n\tReference. *1*\n\thttp://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html\n\n\n> +\t\t>uncovered_new_lines.txt\n> +\n> +\tgrep -q '[^[:space:]]' < uncovered_new_lines.txt && \\\n\nLose the backslash at the end.  The shell knows that you haven't\nfinished your sentence when it sees a line that ends with &&, || or\na pipe |, so there is no need to tell it redundantly that you have\nmore things to say with the backslash.\n\n> +\t\techo $file && \\\n> +\t\tgit blame -c $file \\\n> +\t\t\t| grep -f uncovered_new_lines.txt\n> +\n> +\trm -f new_lines.txt uncovered_lines.txt uncovered_new_lines.txt\n> +done\n\nNear the begininng (like just before the \"for file in $files\" loop),\nyou can probably have a trap to make sure these are removed upon\nexit, e.g.\n\n    trap 'rm -f new_lines.txt uncovered_lines.txt uncovered_new_lines.txt' 0\n\n"},{"id":"359826","messageId":"pull.40.v4.git.gitgitgadget@gmail.com","threadId":"49331","inReplyTo":"pull.40.v3.git.gitgitgadget@gmail.com","subject":"[PATCH v4 0/1] contrib: Add script to show uncovered \"new\" lines","fromName":"Derrick Stolee via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-10-08T14:52:08Z","receivedAt":"2018-10-08T14:52:11Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"We have coverage targets in our Makefile for using gcov to display line\ncoverage based on our test suite. The way I like to do it is to run:\n\nmake coverage-test\nmake coverage-report\n\nThis leaves the repo in a state where every X.c file that was covered has an\nX.c.gcov file containing the coverage counts for every line, and \"#####\" at\nevery uncovered line.\n\nThere have been a few bugs in recent patches what would have been caught if\nthe test suite covered those blocks (including a few of mine). I want to\nwork towards a \"sensible\" amount of coverage on new topics. In my opinion,\nthis means that any logic should be covered, but the 'die()' blocks in error\ncases do not need to be covered.\n\nIt is important to not measure the coverage of the codebase by what old code\nis not covered. To help, I created the 'contrib/coverage-diff.sh' script.\nAfter creating the coverage statistics at a version (say, 'topic') you can\nthen run\n\ncontrib/coverage-diff.sh base topic\n\nto see the lines added between 'base' and 'topic' that are not covered by\nthe test suite. For example, I ran this against the 'next' branch (e82ca0)\nversus 'master' (f84b9b) and got the following output:\n\nbuiltin/commit.c\n76f2f5c1e3 builtin/commit.c 1657) write_commit_graph_reachable(get_object_directory(), 0, 0);\n\nbuiltin/fsck.c\n66ec0390e7 builtin/fsck.c 862) midx_argv[2] = \"--object-dir\";\n66ec0390e7 builtin/fsck.c 863) midx_argv[3] = alt->path;\n66ec0390e7 builtin/fsck.c 864) if (run_command(&midx_verify))\n66ec0390e7 builtin/fsck.c 865) errors_found |= ERROR_COMMIT_GRAPH;\n\nfsck.c\nfb8952077d  214) die_errno(\"Could not read '%s'\", path);\n\nmidx.c\n56ee7ff156  949) return 0;\ncc6af73c02  990) midx_report(_(\"failed to load pack-index for packfile %s\"),\ncc6af73c02  991)     e.p->pack_name);\ncc6af73c02  992) break;\n\nCommits introducing uncovered code:\nDerrick Stolee      56ee7ff15: multi-pack-index: add 'verify' verb\nDerrick Stolee      66ec0390e: fsck: verify multi-pack-index\nDerrick Stolee      cc6af73c0: multi-pack-index: verify object offsets\nJunio C Hamano      76f2f5c1e: Merge branch 'ab/commit-graph-progress' into next\nRené Scharfe      fb8952077: fsck: use strbuf_getline() to read skiplist file\n\nThanks, -Stolee\n\nCHANGES IN V3: I took Junio's perl script verbatim, which speeds up the\nperformance greatly. Some of the other sed commands needed some massaging,\nbut also added extra cleanup. Thanks for the help!\n\nCHANGES IN V4: I reduced the blame output using -s which decreases the\nwidth. I include a summary of the commit authors at the end to help people\nsee the lines they wrote. This version is also copied into a build\ndefinition in the public Git project on Azure Pipelines [1]. I'll use this\nbuild definition to generate the coverage report after each \"What's Cooking\"\nemail.\n\n[1] https://git.visualstudio.com/git/_build?definitionId=5\n\nDerrick Stolee (1):\n  contrib: add coverage-diff script\n\n contrib/coverage-diff.sh | 108 +++++++++++++++++++++++++++++++++++++++\n 1 file changed, 108 insertions(+)\n create mode 100755 contrib/coverage-diff.sh\n\n\nbase-commit: 1d4361b0f344188ab5eec6dcea01f61a3a3a1670\nPublished-As: https://github.com/gitgitgadget/git/releases/tags/pr-40%2Fderrickstolee%2Fcoverage-v4\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-40/derrickstolee/coverage-v4\nPull-Request: https://github.com/gitgitgadget/git/pull/40\n\nRange-diff vs v3:\n\n 1:  21214cc321 ! 1:  6daf310a43 contrib: add coverage-diff script\n     @@ -26,10 +26,10 @@\n              contrib/coverage-diff.sh base topic\n      \n          to see the lines added between 'base' and 'topic' that are not covered by the\n     -    test suite. The output uses 'git blame -c' format so you can find the commits\n     -    responsible and view the line numbers for quick access to the context.\n     +    test suite. The output uses 'git blame -s' format so you can find the commits\n     +    responsible and view the line numbers for quick access to the context, but\n     +    trims leading tabs in the file contents to reduce output width.\n      \n     -    Helped-by: Junio C Hamano <gister@pobox.com>\n          Signed-off-by: Derrick Stolee <dstolee@microsoft.com>\n      \n      diff --git a/contrib/coverage-diff.sh b/contrib/coverage-diff.sh\n     @@ -81,13 +81,16 @@\n      +\t'\n      +}\n      +\n     -+files=$(git diff --name-only $V1 $V2 -- *.c)\n     ++files=$(git diff --name-only \"$V1\" \"$V2\" -- \\*.c)\n     ++\n     ++# create empty file\n     ++>coverage-data.txt\n      +\n      +for file in $files\n      +do\n     -+\tgit diff $V1 $V2 -- $file \\\n     -+\t\t| diff_lines \\\n     -+\t\t| sort >new_lines.txt\n     ++\tgit diff \"$V1\" \"$V2\" -- \"$file\" |\n     ++\tdiff_lines |\n     ++\tsort >new_lines.txt\n      +\n      +\tif ! test -s new_lines.txt\n      +\tthen\n     @@ -95,24 +98,50 @@\n      +\tfi\n      +\n      +\thash_file=$(echo $file | sed \"s/\\//\\#/\")\n     ++\n     ++\tif ! test -s \"$hash_file.gcov\"\n     ++\tthen\n     ++\t\tcontinue\n     ++\tfi\n     ++\n      +\tsed -ne '/#####:/{\n      +\t\t\ts/    #####://\n      +\t\t\ts/:.*//\n      +\t\t\ts/ //g\n      +\t\t\tp\n     -+\t\t}' \"$hash_file.gcov\" \\\n     -+\t\t| sort >uncovered_lines.txt\n     ++\t\t}' \"$hash_file.gcov\" |\n     ++\tsort >uncovered_lines.txt\n      +\n     -+\tcomm -12 uncovered_lines.txt new_lines.txt \\\n     -+\t\t| sed -e 's/$/\\)/' \\\n     -+\t\t| sed -e 's/^/\\t/' \\\n     -+\t\t>uncovered_new_lines.txt\n     ++\tcomm -12 uncovered_lines.txt new_lines.txt |\n     ++\tsed -e 's/$/\\)/' |\n     ++\tsed -e 's/^/ /' >uncovered_new_lines.txt\n      +\n     -+\tgrep -q '[^[:space:]]' < uncovered_new_lines.txt && \\\n     -+\t\techo $file && \\\n     -+\t\tgit blame -c $file \\\n     -+\t\t\t| grep -f uncovered_new_lines.txt\n     ++\tgrep -q '[^[:space:]]' <uncovered_new_lines.txt &&\n     ++\techo $file >>coverage-data.txt &&\n     ++\tgit blame -s \"$V2\" -- \"$file\" |\n     ++\tsed 's/\\t//g' |\n     ++\tgrep -f uncovered_new_lines.txt >>coverage-data.txt &&\n     ++\techo >>coverage-data.txt\n      +\n      +\trm -f new_lines.txt uncovered_lines.txt uncovered_new_lines.txt\n      +done\n      +\n     ++cat coverage-data.txt\n     ++\n     ++echo \"Commits introducing uncovered code:\"\n     ++\n     ++commit_list=$(cat coverage-data.txt |\n     ++\tgrep -E '^[0-9a-f]{7,} ' |\n     ++\tawk '{print $1;}' |\n     ++\tsort |\n     ++\tuniq)\n     ++\n     ++(\n     ++\tfor commit in $commit_list\n     ++\tdo\n     ++\t\tgit log --no-decorate --pretty=format:'%an      %h: %s' -1 $commit\n     ++\t\techo\n     ++\tdone\n     ++) | sort\n     ++\n     ++rm coverage-data.txt\n\n-- \ngitgitgadget\n"},{"id":"359827","messageId":"6daf310a43b2b35467393a8c5e34e76f4b9391d7.1539010326.git.gitgitgadget@gmail.com","threadId":"49331","inReplyTo":"pull.40.v4.git.gitgitgadget@gmail.com","subject":"[PATCH v4 1/1] contrib: add coverage-diff script","fromName":"Derrick Stolee via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-10-08T14:52:09Z","receivedAt":"2018-10-08T14:52:13Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"From: Derrick Stolee <dstolee@microsoft.com>\n\nWe have coverage targets in our Makefile for using gcov to display line\ncoverage based on our test suite. The way I like to do it is to run:\n\n    make coverage-test\n    make coverage-report\n\nThis leaves the repo in a state where every X.c file that was covered has\nan X.c.gcov file containing the coverage counts for every line, and \"#####\"\nat every uncovered line.\n\nThere have been a few bugs in recent patches what would have been caught\nif the test suite covered those blocks (including a few of mine). I want\nto work towards a \"sensible\" amount of coverage on new topics. In my opinion,\nthis means that any logic should be covered, but the 'die()' blocks covering\nvery unlikely (or near-impossible) situations may not warrant coverage.\n\nIt is important to not measure the coverage of the codebase by what old code\nis not covered. To help, I created the 'contrib/coverage-diff.sh' script.\nAfter creating the coverage statistics at a version (say, 'topic') you can\nthen run\n\n    contrib/coverage-diff.sh base topic\n\nto see the lines added between 'base' and 'topic' that are not covered by the\ntest suite. The output uses 'git blame -s' format so you can find the commits\nresponsible and view the line numbers for quick access to the context, but\ntrims leading tabs in the file contents to reduce output width.\n\nSigned-off-by: Derrick Stolee <dstolee@microsoft.com>\n---\n contrib/coverage-diff.sh | 108 +++++++++++++++++++++++++++++++++++++++\n 1 file changed, 108 insertions(+)\n create mode 100755 contrib/coverage-diff.sh\n\ndiff --git a/contrib/coverage-diff.sh b/contrib/coverage-diff.sh\nnew file mode 100755\nindex 0000000000..4ec419f900\n--- /dev/null\n+++ b/contrib/coverage-diff.sh\n@@ -0,0 +1,108 @@\n+#!/bin/sh\n+\n+# Usage: Run 'contrib/coverage-diff.sh <version1> <version2>' from source-root\n+# after running\n+#\n+#     make coverage-test\n+#     make coverage-report\n+#\n+# while checked out at <version2>. This script combines the *.gcov files\n+# generated by the 'make' commands above with 'git diff <version1> <version2>'\n+# to report new lines that are not covered by the test suite.\n+\n+V1=$1\n+V2=$2\n+\n+diff_lines () {\n+\tperl -e '\n+\t\tmy $line_num;\n+\t\twhile (<>) {\n+\t\t\t# Hunk header?  Grab the beginning in postimage.\n+\t\t\tif (/^@@ -\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/) {\n+\t\t\t\t$line_num = $1;\n+\t\t\t\tnext;\n+\t\t\t}\n+\n+\t\t\t# Have we seen a hunk?  Ignore \"diff --git\" etc.\n+\t\t\tnext unless defined $line_num;\n+\n+\t\t\t# Deleted line? Ignore.\n+\t\t\tif (/^-/) {\n+\t\t\t\tnext;\n+\t\t\t}\n+\n+\t\t\t# Show only the line number of added lines.\n+\t\t\tif (/^\\+/) {\n+\t\t\t\tprint \"$line_num\\n\";\n+\t\t\t}\n+\t\t\t# Either common context or added line appear in\n+\t\t\t# the postimage.  Count it.\n+\t\t\t$line_num++;\n+\t\t}\n+\t'\n+}\n+\n+files=$(git diff --name-only \"$V1\" \"$V2\" -- \\*.c)\n+\n+# create empty file\n+>coverage-data.txt\n+\n+for file in $files\n+do\n+\tgit diff \"$V1\" \"$V2\" -- \"$file\" |\n+\tdiff_lines |\n+\tsort >new_lines.txt\n+\n+\tif ! test -s new_lines.txt\n+\tthen\n+\t\tcontinue\n+\tfi\n+\n+\thash_file=$(echo $file | sed \"s/\\//\\#/\")\n+\n+\tif ! test -s \"$hash_file.gcov\"\n+\tthen\n+\t\tcontinue\n+\tfi\n+\n+\tsed -ne '/#####:/{\n+\t\t\ts/    #####://\n+\t\t\ts/:.*//\n+\t\t\ts/ //g\n+\t\t\tp\n+\t\t}' \"$hash_file.gcov\" |\n+\tsort >uncovered_lines.txt\n+\n+\tcomm -12 uncovered_lines.txt new_lines.txt |\n+\tsed -e 's/$/\\)/' |\n+\tsed -e 's/^/ /' >uncovered_new_lines.txt\n+\n+\tgrep -q '[^[:space:]]' <uncovered_new_lines.txt &&\n+\techo $file >>coverage-data.txt &&\n+\tgit blame -s \"$V2\" -- \"$file\" |\n+\tsed 's/\\t//g' |\n+\tgrep -f uncovered_new_lines.txt >>coverage-data.txt &&\n+\techo >>coverage-data.txt\n+\n+\trm -f new_lines.txt uncovered_lines.txt uncovered_new_lines.txt\n+done\n+\n+cat coverage-data.txt\n+\n+echo \"Commits introducing uncovered code:\"\n+\n+commit_list=$(cat coverage-data.txt |\n+\tgrep -E '^[0-9a-f]{7,} ' |\n+\tawk '{print $1;}' |\n+\tsort |\n+\tuniq)\n+\n+(\n+\tfor commit in $commit_list\n+\tdo\n+\t\tgit log --no-decorate --pretty=format:'%an      %h: %s' -1 $commit\n+\t\techo\n+\tdone\n+) | sort\n+\n+rm coverage-data.txt\n-- \ngitgitgadget\n"},{"id":"360265","messageId":"xmqq5zy7eulx.fsf@gitster-ct.c.googlers.com","threadId":"49331","inReplyTo":"pull.40.v4.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v4 0/1] contrib: Add script to show uncovered \"new\" lines","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-10-12T03:01:30Z","receivedAt":"2018-10-12T03:01:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Derrick Stolee via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> CHANGES IN V4: I reduced the blame output using -s which decreases the\n> width. I include a summary of the commit authors at the end to help people\n> see the lines they wrote. This version is also copied into a build\n> definition in the public Git project on Azure Pipelines [1]. I'll use this\n> build definition to generate the coverage report after each \"What's Cooking\"\n> email.\n>\n> [1] https://git.visualstudio.com/git/_build?definitionId=5\n\nThanks.  Let's move this forward by merging it down to 'next'.\n"},{"id":"360298","messageId":"1aedfa31-33a5-ac7c-bcd5-7455a83d3f0a@gmail.com","threadId":"49331","inReplyTo":"xmqq5zy7eulx.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 0/1] contrib: Add script to show uncovered \"new\" lines","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-10-12T12:09:42Z","receivedAt":"2018-10-12T12:09:48Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 10/11/2018 11:01 PM, Junio C Hamano wrote:\n> \"Derrick Stolee via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n>\n>> CHANGES IN V4: I reduced the blame output using -s which decreases the\n>> width. I include a summary of the commit authors at the end to help people\n>> see the lines they wrote. This version is also copied into a build\n>> definition in the public Git project on Azure Pipelines [1]. I'll use this\n>> build definition to generate the coverage report after each \"What's Cooking\"\n>> email.\n>>\n>> [1] https://git.visualstudio.com/git/_build?definitionId=5\n> Thanks.  Let's move this forward by merging it down to 'next'.\nSounds good. When it moves into 'master' I can update my build to call \nthe script from source.\n\nThanks,\n-Stolee\n"}]}