{"thread":{"id":"44958","subject":"[PATCH] [draft]blame: add --aggregate option","startedAt":"2017-01-24T02:11:04Z","lastAt":"2017-01-24T02:18:49Z","messageCount":2,"participants":["Edmundo Carmona Antoranz"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"310069","messageId":"20170124021046.30735-1-eantoranz@gmail.com","threadId":"44958","inReplyTo":null,"subject":"[PATCH] [draft]blame: add --aggregate option","fromName":"Edmundo Carmona Antoranz","fromEmail":"eantoranz@gmail.com","sentAt":"2017-01-24T02:10:46Z","receivedAt":"2017-01-24T02:11:04Z","isPatch":true,"sender":{"key":"eantoranz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1491018?v=4"},"body":"---\n builtin/blame.c | 78 +++++++++++++++++++++++++++++++++++++--------------------\n 1 file changed, 51 insertions(+), 27 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 126b8c9e5..9e8403303 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1884,6 +1884,7 @@ static const char *format_time(unsigned long time, const char *tz_str,\n #define OUTPUT_NO_AUTHOR       0200\n #define OUTPUT_SHOW_EMAIL\t0400\n #define OUTPUT_LINE_PORCELAIN 01000\n+#define OUTPUT_AGGREGATE      02000\n \n static void emit_porcelain_details(struct origin *suspect, int repeat)\n {\n@@ -1931,43 +1932,36 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent,\n \t\tputchar('\\n');\n }\n \n-static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)\n+/**\n+ * Print information about the revision.\n+ * This information can be used in either aggregated output\n+ * or prepending each line of the content of the file being blamed\n+ */\n+static void print_revision_info(char* revision_hex, int revision_length, struct blame_entry* ent,\n+\t\tstruct commit* commit, struct commit_info ci, int opt, int show_raw_time)\n {\n-\tint cnt;\n-\tconst char *cp;\n-\tstruct origin *suspect = ent->suspect;\n-\tstruct commit_info ci;\n-\tchar hex[GIT_SHA1_HEXSZ + 1];\n-\tint show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);\n-\n-\tget_commit_info(suspect->commit, &ci, 1);\n-\tsha1_to_hex_r(hex, suspect->commit->object.oid.hash);\n-\n-\tcp = nth_line(sb, ent->lno);\n-\tfor (cnt = 0; cnt < ent->num_lines; cnt++) {\n-\t\tchar ch;\n-\t\tint length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev;\n-\n-\t\tif (suspect->commit->object.flags & UNINTERESTING) {\n+\tif (opt & OUTPUT_AGGREGATE)\n+\t\tprintf(\"\\t\");\n+\tint length = revision_length;\n+\t\t\tif (commit->object.flags & UNINTERESTING) {\n \t\t\tif (blank_boundary)\n-\t\t\t\tmemset(hex, ' ', length);\n+\t\t\t\tmemset(revision_hex, ' ', length);\n \t\t\telse if (!(opt & OUTPUT_ANNOTATE_COMPAT)) {\n \t\t\t\tlength--;\n \t\t\t\tputchar('^');\n \t\t\t}\n \t\t}\n \n-\t\tprintf(\"%.*s\", length, hex);\n+\t\tprintf(\"%.*s\", length, revision_hex);\n \t\tif (opt & OUTPUT_ANNOTATE_COMPAT) {\n \t\t\tconst char *name;\n \t\t\tif (opt & OUTPUT_SHOW_EMAIL)\n \t\t\t\tname = ci.author_mail.buf;\n \t\t\telse\n \t\t\t\tname = ci.author.buf;\n-\t\t\tprintf(\"\\t(%10s\\t%10s\\t%d)\", name,\n+\t\t\tprintf(\"\\t(%10s\\t%10s\\t\", name,\n \t\t\t       format_time(ci.author_time, ci.author_tz.buf,\n-\t\t\t\t\t   show_raw_time),\n-\t\t\t       ent->lno + 1 + cnt);\n+\t\t\t\t\t   show_raw_time));\n \t\t} else {\n \t\t\tif (opt & OUTPUT_SHOW_SCORE)\n \t\t\t\tprintf(\" %*d %02d\",\n@@ -1975,11 +1969,7 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)\n \t\t\t\t       ent->suspect->refcnt);\n \t\t\tif (opt & OUTPUT_SHOW_NAME)\n \t\t\t\tprintf(\" %-*.*s\", longest_file, longest_file,\n-\t\t\t\t       suspect->path);\n-\t\t\tif (opt & OUTPUT_SHOW_NUMBER)\n-\t\t\t\tprintf(\" %*d\", max_orig_digits,\n-\t\t\t\t       ent->s_lno + 1 + cnt);\n-\n+\t\t\t\t       ent->suspect->path);\n \t\t\tif (!(opt & OUTPUT_NO_AUTHOR)) {\n \t\t\t\tconst char *name;\n \t\t\t\tint pad;\n@@ -1994,9 +1984,42 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)\n \t\t\t\t\t\t   ci.author_tz.buf,\n \t\t\t\t\t\t   show_raw_time));\n \t\t\t}\n+\t\t}\n+\t\tif (opt & OUTPUT_AGGREGATE)\n+\t\t\tprintf(\")\\n\");\n+}\n+\n+static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)\n+{\n+\tint cnt;\n+\tconst char *cp;\n+\tstruct origin *suspect = ent->suspect;\n+\tstruct commit_info ci;\n+\tchar hex[GIT_SHA1_HEXSZ + 1];\n+\tint show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);\n+\tint revision_length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev;\n+\n+\tget_commit_info(suspect->commit, &ci, 1);\n+\tsha1_to_hex_r(hex, suspect->commit->object.oid.hash);\n+\n+\tif (opt & OUTPUT_AGGREGATE)\n+\t\tprint_revision_info(hex, revision_length, ent, suspect->commit, ci, opt, show_raw_time);\n+\n+\tcp = nth_line(sb, ent->lno);\n+\tfor (cnt = 0; cnt < ent->num_lines; cnt++) {\n+\t\tif (!(opt & OUTPUT_AGGREGATE))\n+\t\t\tprint_revision_info(hex, revision_length, ent, suspect->commit, ci, opt, show_raw_time);\n+\t\tif (opt & OUTPUT_ANNOTATE_COMPAT) {\n+\t\t\tprintf(\"%*d) \",\n+\t\t\t       max_digits, ent->lno + 1 + cnt);\n+\t\t} else {\n+\t\t\tif (opt & OUTPUT_SHOW_NUMBER)\n+\t\t\t\tprintf(\" %*d \", max_orig_digits,\n+\t\t\t\t       ent->s_lno + 1 + cnt);\n \t\t\tprintf(\" %*d) \",\n \t\t\t       max_digits, ent->lno + 1 + cnt);\n \t\t}\n+\t\tchar ch;\n \t\tdo {\n \t\t\tch = *cp++;\n \t\t\tputchar(ch);\n@@ -2609,6 +2632,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)\n \t\t{ OPTION_CALLBACK, 'C', NULL, &opt, N_(\"score\"), N_(\"Find line copies within and across files\"), PARSE_OPT_OPTARG, blame_copy_callback },\n \t\t{ OPTION_CALLBACK, 'M', NULL, &opt, N_(\"score\"), N_(\"Find line movements within and across files\"), PARSE_OPT_OPTARG, blame_move_callback },\n \t\tOPT_STRING_LIST('L', NULL, &range_list, N_(\"n,m\"), N_(\"Process only line range n,m, counting from 1\")),\n+\t\tOPT_BIT(0, \"aggregate\", &output_option, N_(\"Aggregate output\"), OUTPUT_AGGREGATE),\n \t\tOPT__ABBREV(&abbrev),\n \t\tOPT_END()\n \t};\n-- \n2.11.0.rc1\n\n"},{"id":"310071","messageId":"CAOc6etYWiY=7-uvz_SRDmun=fX1rO03+-k=TFf_11kt5Vtsxzg@mail.gmail.com","threadId":"44958","inReplyTo":"20170124021046.30735-1-eantoranz@gmail.com","subject":"Re: [PATCH] [draft]blame: add --aggregate option","fromName":"Edmundo Carmona Antoranz","fromEmail":"eantoranz@gmail.com","sentAt":"2017-01-24T02:18:43Z","receivedAt":"2017-01-24T02:18:49Z","isPatch":true,"sender":{"key":"eantoranz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1491018?v=4"},"body":"Developers of the world, rejoice! :-)\n\nJunio, Pranit (and whoever is paying attention to the conversation\nthat was being held about --tips), here's a draft of what I meant when\nI was talking about the option of \"aggregating\" blame output. I'm not\nconsidering _all_ cases yet, just would like for people to give it a\nquick test and tell me if they think it's worth \"polishing\" it for\ninclusion into mainline git.\n\nThe output would look like this:\n\n$ ./git blame -L 1,19 -t --aggregate builtin/blame.c\nBlaming lines:   0% (19/2974), done.\n       cee7f245dc builtin-pickaxe.c (Junio C Hamano   1161298804 -0700)\n 1) /*\n       31653c1abc builtin-blame.c   (Eugene Letuchy   1235170271 -0800)\n 2)  * Blame\n       cee7f245dc builtin-pickaxe.c (Junio C Hamano   1161298804 -0700)\n 3)  *\n       7e6ac6e439 builtin/blame.c   (David Kastrup    1398470209 +0200)\n 4)  * Copyright (c) 2006, 2014 by its authors\n 5)  * See COPYING for licensing conditions\n       cee7f245dc builtin-pickaxe.c (Junio C Hamano   1161298804 -0700)\n 6)  */\n 7)\n 8) #include \"cache.h\"\n       fb58c8d507 builtin/blame.c   (Michael Haggerty 1434981785 +0200)\n 9) #include \"refs.h\"\n       cee7f245dc builtin-pickaxe.c (Junio C Hamano   1161298804 -0700)\n10) #include \"builtin.h\"\n11) #include \"blob.h\"\n12) #include \"commit.h\"\n13) #include \"tag.h\"\n14) #include \"tree-walk.h\"\n15) #include \"diff.h\"\n16) #include \"diffcore.h\"\n17) #include \"revision.h\"\n       717d1462ba builtin-blame.c   (Linus Torvalds   1169976846 -0800)\n18) #include \"quote.h\"\n       cee7f245dc builtin-pickaxe.c (Junio C Hamano   1161298804 -0700)\n19) #include \"xdiff-interface.h\"\n\n\n\nIt can be seen that options like -t still work in aggregation.\n\nIn relation to the previous conversation about \"tips\", I think a\nbetter name could be \"hints\" and it could be added on top of the\naggregation.\n\nOn Mon, Jan 23, 2017 at 8:10 PM, Edmundo Carmona Antoranz\n<eantoranz@gmail.com> wrote:\n> ---\n>  builtin/blame.c | 78 +++++++++++++++++++++++++++++++++++++--------------------\n>  1 file changed, 51 insertions(+), 27 deletions(-)\n>\n> diff --git a/builtin/blame.c b/builtin/blame.c\n> index 126b8c9e5..9e8403303 100644\n> --- a/builtin/blame.c\n> +++ b/builtin/blame.c\n> @@ -1884,6 +1884,7 @@ static const char *format_time(unsigned long time, const char *tz_str,\n>  #define OUTPUT_NO_AUTHOR       0200\n>  #define OUTPUT_SHOW_EMAIL      0400\n>  #define OUTPUT_LINE_PORCELAIN 01000\n> +#define OUTPUT_AGGREGATE      02000\n>\n>  static void emit_porcelain_details(struct origin *suspect, int repeat)\n>  {\n> @@ -1931,43 +1932,36 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent,\n>                 putchar('\\n');\n>  }\n>\n> -static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)\n> +/**\n> + * Print information about the revision.\n> + * This information can be used in either aggregated output\n> + * or prepending each line of the content of the file being blamed\n> + */\n> +static void print_revision_info(char* revision_hex, int revision_length, struct blame_entry* ent,\n> +               struct commit* commit, struct commit_info ci, int opt, int show_raw_time)\n>  {\n> -       int cnt;\n> -       const char *cp;\n> -       struct origin *suspect = ent->suspect;\n> -       struct commit_info ci;\n> -       char hex[GIT_SHA1_HEXSZ + 1];\n> -       int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);\n> -\n> -       get_commit_info(suspect->commit, &ci, 1);\n> -       sha1_to_hex_r(hex, suspect->commit->object.oid.hash);\n> -\n> -       cp = nth_line(sb, ent->lno);\n> -       for (cnt = 0; cnt < ent->num_lines; cnt++) {\n> -               char ch;\n> -               int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev;\n> -\n> -               if (suspect->commit->object.flags & UNINTERESTING) {\n> +       if (opt & OUTPUT_AGGREGATE)\n> +               printf(\"\\t\");\n> +       int length = revision_length;\n> +                       if (commit->object.flags & UNINTERESTING) {\n>                         if (blank_boundary)\n> -                               memset(hex, ' ', length);\n> +                               memset(revision_hex, ' ', length);\n>                         else if (!(opt & OUTPUT_ANNOTATE_COMPAT)) {\n>                                 length--;\n>                                 putchar('^');\n>                         }\n>                 }\n>\n> -               printf(\"%.*s\", length, hex);\n> +               printf(\"%.*s\", length, revision_hex);\n>                 if (opt & OUTPUT_ANNOTATE_COMPAT) {\n>                         const char *name;\n>                         if (opt & OUTPUT_SHOW_EMAIL)\n>                                 name = ci.author_mail.buf;\n>                         else\n>                                 name = ci.author.buf;\n> -                       printf(\"\\t(%10s\\t%10s\\t%d)\", name,\n> +                       printf(\"\\t(%10s\\t%10s\\t\", name,\n>                                format_time(ci.author_time, ci.author_tz.buf,\n> -                                          show_raw_time),\n> -                              ent->lno + 1 + cnt);\n> +                                          show_raw_time));\n>                 } else {\n>                         if (opt & OUTPUT_SHOW_SCORE)\n>                                 printf(\" %*d %02d\",\n> @@ -1975,11 +1969,7 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)\n>                                        ent->suspect->refcnt);\n>                         if (opt & OUTPUT_SHOW_NAME)\n>                                 printf(\" %-*.*s\", longest_file, longest_file,\n> -                                      suspect->path);\n> -                       if (opt & OUTPUT_SHOW_NUMBER)\n> -                               printf(\" %*d\", max_orig_digits,\n> -                                      ent->s_lno + 1 + cnt);\n> -\n> +                                      ent->suspect->path);\n>                         if (!(opt & OUTPUT_NO_AUTHOR)) {\n>                                 const char *name;\n>                                 int pad;\n> @@ -1994,9 +1984,42 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)\n>                                                    ci.author_tz.buf,\n>                                                    show_raw_time));\n>                         }\n> +               }\n> +               if (opt & OUTPUT_AGGREGATE)\n> +                       printf(\")\\n\");\n> +}\n> +\n> +static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)\n> +{\n> +       int cnt;\n> +       const char *cp;\n> +       struct origin *suspect = ent->suspect;\n> +       struct commit_info ci;\n> +       char hex[GIT_SHA1_HEXSZ + 1];\n> +       int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);\n> +       int revision_length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev;\n> +\n> +       get_commit_info(suspect->commit, &ci, 1);\n> +       sha1_to_hex_r(hex, suspect->commit->object.oid.hash);\n> +\n> +       if (opt & OUTPUT_AGGREGATE)\n> +               print_revision_info(hex, revision_length, ent, suspect->commit, ci, opt, show_raw_time);\n> +\n> +       cp = nth_line(sb, ent->lno);\n> +       for (cnt = 0; cnt < ent->num_lines; cnt++) {\n> +               if (!(opt & OUTPUT_AGGREGATE))\n> +                       print_revision_info(hex, revision_length, ent, suspect->commit, ci, opt, show_raw_time);\n> +               if (opt & OUTPUT_ANNOTATE_COMPAT) {\n> +                       printf(\"%*d) \",\n> +                              max_digits, ent->lno + 1 + cnt);\n> +               } else {\n> +                       if (opt & OUTPUT_SHOW_NUMBER)\n> +                               printf(\" %*d \", max_orig_digits,\n> +                                      ent->s_lno + 1 + cnt);\n>                         printf(\" %*d) \",\n>                                max_digits, ent->lno + 1 + cnt);\n>                 }\n> +               char ch;\n>                 do {\n>                         ch = *cp++;\n>                         putchar(ch);\n> @@ -2609,6 +2632,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)\n>                 { OPTION_CALLBACK, 'C', NULL, &opt, N_(\"score\"), N_(\"Find line copies within and across files\"), PARSE_OPT_OPTARG, blame_copy_callback },\n>                 { OPTION_CALLBACK, 'M', NULL, &opt, N_(\"score\"), N_(\"Find line movements within and across files\"), PARSE_OPT_OPTARG, blame_move_callback },\n>                 OPT_STRING_LIST('L', NULL, &range_list, N_(\"n,m\"), N_(\"Process only line range n,m, counting from 1\")),\n> +               OPT_BIT(0, \"aggregate\", &output_option, N_(\"Aggregate output\"), OUTPUT_AGGREGATE),\n>                 OPT__ABBREV(&abbrev),\n>                 OPT_END()\n>         };\n> --\n> 2.11.0.rc1\n>\n"}]}