{"thread":{"id":"3565","subject":"[PATCH] git-blame: Make the output human readable","startedAt":"2006-03-05T11:03:51Z","lastAt":"2006-03-07T16:34:27Z","messageCount":10,"participants":["Fredrik Kuivinen","Junio C Hamano","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"17182","messageId":"20060305110351.GA23448@c165.ib.student.liu.se","threadId":"3565","inReplyTo":null,"subject":"[PATCH] git-blame: Make the output human readable","fromName":"Fredrik Kuivinen","fromEmail":"freku045@student.liu.se","sentAt":"2006-03-05T11:03:51Z","receivedAt":"2006-03-05T11:03:51Z","isPatch":true,"sender":{"key":"frekui@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13770967?v=4"},"body":"The default output mode is slightly different from git-annotate's.\nHowever, git-annotate's output mode can be obtained by using the\n'-c' flag.\n\nSigned-off-by: Fredrik Kuivinen <freku045@student.liu.se>\n\n\n---\n\n Makefile |    4 ++\n blame.c  |  164 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------\n 2 files changed, 149 insertions(+), 19 deletions(-)\n\n3459b7c5032d1462d5857cf6afc2d3e3ef61b93b\ndiff --git a/Makefile b/Makefile\nindex b6d8804..eb1887d 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -534,6 +534,10 @@ git-rev-list$X: rev-list.o $(LIB_FILE)\n \t$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n \t\t$(LIBS) $(OPENSSL_LIBSSL)\n \n+git-blame$X: blame.o $(LIB_FILE)\n+\t$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n+\t\t$(LIBS) -lm\n+\n init-db.o: init-db.c\n \t$(CC) -c $(ALL_CFLAGS) \\\n \t\t-DDEFAULT_GIT_TEMPLATE_DIR='\"$(template_dir_SQ)\"' $*.c\ndiff --git a/blame.c b/blame.c\nindex 7308c36..6dccae5 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -5,6 +5,7 @@\n #include <assert.h>\n #include <time.h>\n #include <sys/time.h>\n+#include <math.h>\n \n #include \"cache.h\"\n #include \"refs.h\"\n@@ -17,8 +18,15 @@\n \n #define DEBUG 0\n \n-struct commit **blame_lines;\n-int num_blame_lines;\n+static const char blame_usage[] = \"[-c] [-l] [--] file [commit]\\n\"\n+\t\"  -c, --compability Use the same output mode as git-annotate (Default: off)\\n\"\n+\t\"  -l, --long        Show long commit SHA1 (Default: off)\\n\"\n+\t\"  -h, --help        This message\";\n+\n+static struct commit **blame_lines;\n+static int num_blame_lines;\n+static char* blame_contents;\n+static int blame_len;\n \n struct util_info {\n \tint *line_map;\n@@ -388,9 +396,8 @@ static void init_first_commit(struct com\n \talloc_line_map(commit);\n \n \tutil = commit->object.util;\n-\tnum_blame_lines = util->num_lines;\n \n-\tfor (i = 0; i < num_blame_lines; i++)\n+\tfor (i = 0; i < util->num_lines; i++)\n \t\tutil->line_map[i] = i;\n }\n \n@@ -412,6 +419,9 @@ static void process_commits(struct rev_i\n \tutil = commit->object.util;\n \tnum_blame_lines = util->num_lines;\n \tblame_lines = xmalloc(sizeof(struct commit *) * num_blame_lines);\n+\tblame_contents = util->buf;\n+\tblame_len = util->size;\n+\n \tfor (i = 0; i < num_blame_lines; i++)\n \t\tblame_lines[i] = NULL;\n \n@@ -499,32 +509,128 @@ static void process_commits(struct rev_i\n \t} while ((commit = get_revision(rev)) != NULL);\n }\n \n+struct commit_info\n+{\n+\tchar* author;\n+\tchar* author_mail;\n+\tunsigned long author_time;\n+\tchar* author_tz;\n+};\n+\n+static void get_commit_info(struct commit* commit, struct commit_info* ret)\n+{\n+\tint len;\n+\tchar* tmp;\n+\tstatic char author_buf[1024];\n+\n+\ttmp = strstr(commit->buffer, \"\\nauthor \") + 8;\n+\tlen = index(tmp, '\\n') - tmp;\n+\tret->author = author_buf;\n+\tmemcpy(ret->author, tmp, len);\n+\n+\ttmp = ret->author;\n+\ttmp += len;\n+\t*tmp = 0;\n+\twhile(*tmp != ' ')\n+\t\ttmp--;\n+\tret->author_tz = tmp+1;\n+\n+\t*tmp = 0;\n+\twhile(*tmp != ' ')\n+\t\ttmp--;\n+\tret->author_time = strtoul(tmp, NULL, 10);\n+\n+\t*tmp = 0;\n+\twhile(*tmp != ' ')\n+\t\ttmp--;\n+\tret->author_mail = tmp + 1;\n+\n+\t*tmp = 0;\n+}\n+\n+char* format_time(unsigned long time, const char* tz)\n+{\n+\tstatic char time_buf[128];\n+\ttime_t t = time;\n+\n+\tstrftime(time_buf, sizeof(time_buf), \"%Y-%m-%d %H:%M:%S \", gmtime(&t));\n+\tstrcat(time_buf, tz);\n+\treturn time_buf;\n+}\n+\n int main(int argc, const char **argv)\n {\n \tint i;\n \tstruct commit *initial = NULL;\n \tunsigned char sha1[20];\n-\tconst char* filename;\n+\n+\tconst char *filename = NULL, *commit = NULL;\n+\tchar filename_buf[256];\n+\tint sha1_len = 8;\n+\tint compability = 0;\n+\tint options = 1;\n+\n \tint num_args;\n \tconst char* args[10];\n \tstruct rev_info rev;\n \n-\tsetup_git_directory();\n-\n-\tif (argc != 3)\n-\t\tdie(\"Usage: blame commit-ish file\");\n+\tstruct commit_info ci;\n+\tconst char *buf;\n+\tint max_digits;\n+\n+\tconst char* prefix = setup_git_directory();\n+\n+\tfor(i = 1; i < argc; i++) {\n+\t\tif(options) {\n+\t\t\tif(!strcmp(argv[i], \"-h\") ||\n+\t\t\t   !strcmp(argv[i], \"--help\"))\n+\t\t\t\tusage(blame_usage);\n+\t\t\telse if(!strcmp(argv[i], \"-l\") ||\n+\t\t\t\t!strcmp(argv[i], \"--long\")) {\n+\t\t\t\tsha1_len = 20;\n+\t\t\t\tcontinue;\n+\t\t\t} else if(!strcmp(argv[i], \"-c\") ||\n+\t\t\t\t  !strcmp(argv[i], \"--compability\")) {\n+\t\t\t\tcompability = 1;\n+\t\t\t\tcontinue;\n+\t\t\t} else if(!strcmp(argv[i], \"--\")) {\n+\t\t\t\toptions = 0;\n+\t\t\t\tcontinue;\n+\t\t\t} else if(argv[i][0] == '-')\n+\t\t\t\tusage(blame_usage);\n+\t\t\telse\n+\t\t\t\toptions = 0;\n+\t\t}\n \n+\t\tif(!options) {\n+\t\t\tif(!filename)\n+\t\t\t\tfilename = argv[i];\n+\t\t\telse if(!commit)\n+\t\t\t\tcommit = argv[i];\n+\t\t\telse\n+\t\t\t\tusage(blame_usage);\n+\t\t}\n+\t}\n \n-\tfilename = argv[2];\n+\tif(!filename)\n+\t\tusage(blame_usage);\n+\tif(!commit)\n+\t\tcommit = \"HEAD\";\n+\n+\tif(prefix)\n+\t\tsprintf(filename_buf, \"%s%s\", prefix, filename);\n+\telse\n+\t\tstrcpy(filename_buf, filename);\n+\tfilename = filename_buf;\n \n \t{\n-\t\tstruct commit* commit;\n-\t\tif (get_sha1(argv[1], sha1))\n-\t\t\tdie(\"get_sha1 failed\");\n-\t\tcommit = lookup_commit_reference(sha1);\n+\t\tstruct commit* c;\n+\t\tif (get_sha1(commit, sha1))\n+\t\t\tdie(\"get_sha1 failed, commit '%s' not found\", commit);\n+\t\tc = lookup_commit_reference(sha1);\n \n-\t\tif (fill_util_info(commit, filename)) {\n-\t\t\tprintf(\"%s not found in %s\\n\", filename, argv[1]);\n+\t\tif (fill_util_info(c, filename)) {\n+\t\t\tprintf(\"%s not found in %s\\n\", filename, commit);\n \t\t\treturn 1;\n \t\t}\n \t}\n@@ -533,7 +639,7 @@ int main(int argc, const char **argv)\n \targs[num_args++] = NULL;\n \targs[num_args++] = \"--topo-order\";\n \targs[num_args++] = \"--remove-empty\";\n-\targs[num_args++] = argv[1];\n+\targs[num_args++] = commit;\n \targs[num_args++] = \"--\";\n \targs[num_args++] = filename;\n \targs[num_args] = NULL;\n@@ -542,13 +648,33 @@ int main(int argc, const char **argv)\n \tprepare_revision_walk(&rev);\n \tprocess_commits(&rev, filename, &initial);\n \n+\tbuf = blame_contents;\n+\tmax_digits = 1 + log(num_blame_lines+1)/log(10);\n \tfor (i = 0; i < num_blame_lines; i++) {\n \t\tstruct commit *c = blame_lines[i];\n \t\tif (!c)\n \t\t\tc = initial;\n \n-\t\tprintf(\"%d %.8s\\n\", i, sha1_to_hex(c->object.sha1));\n-// printf(\"%d %s\\n\", i, find_unique_abbrev(blame_lines[i]->object.sha1, 6));\n+\t\tget_commit_info(c, &ci);\n+\t\tfwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout);\n+\t\tif(compability)\n+\t\t\tprintf(\"\\t(%10s\\t%10s\\t%d)\", ci.author,\n+\t\t\t       format_time(ci.author_time, ci.author_tz), i+1);\n+\t\telse\n+\t\t\tprintf(\" (%-15.15s %10s %*d) \", ci.author,\n+\t\t\t       format_time(ci.author_time, ci.author_tz),\n+\t\t\t       max_digits, i+1);\n+\n+\t\tif(i == num_blame_lines - 1) {\n+\t\t\tfwrite(buf, blame_len - (buf - blame_contents),\n+\t\t\t       1, stdout);\n+\t\t\tif(blame_contents[blame_len-1] != '\\n')\n+\t\t\t\tputc('\\n', stdout);\n+\t\t} else {\n+\t\t\tchar* next_buf = index(buf, '\\n') + 1;\n+\t\t\tfwrite(buf, next_buf - buf, 1, stdout);\n+\t\t\tbuf = next_buf;\n+\t\t}\n \t}\n \n \tif (DEBUG) {\n-- \n1.2.4.g4644-dirty\n"},{"id":"17187","messageId":"7vbqwlgkhk.fsf@assigned-by-dhcp.cox.net","threadId":"3565","inReplyTo":"20060305110351.GA23448@c165.ib.student.liu.se","subject":"Re: [PATCH] git-blame: Make the output human readable","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-05T12:10:47Z","receivedAt":"2006-03-05T12:10:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fredrik Kuivinen <freku045@student.liu.se> writes:\n\n> The default output mode is slightly different from git-annotate's.\n> However, git-annotate's output mode can be obtained by using the\n> '-c' flag.\n\nIt might be better to default to human readable and make the\nscript consumption format an option, if only to reduce typing.\n\n> diff --git a/Makefile b/Makefile\n> index b6d8804..eb1887d 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -534,6 +534,10 @@ git-rev-list$X: rev-list.o $(LIB_FILE)\n>  \t$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n>  \t\t$(LIBS) $(OPENSSL_LIBSSL)\n>  \n> +git-blame$X: blame.o $(LIB_FILE)\n> +\t$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n> +\t\t$(LIBS) -lm\n> +\n\nI wonder what it is about to link this binary different from others...\n\n> +char* format_time(unsigned long time, const char* tz)\n> +{\n> +\tstatic char time_buf[128];\n> +\ttime_t t = time;\n> +\n> +\tstrftime(time_buf, sizeof(time_buf), \"%Y-%m-%d %H:%M:%S \", gmtime(&t));\n> +\tstrcat(time_buf, tz);\n> +\treturn time_buf;\n> +}\n\nI think this shows GMT with time offset, which is compatible\nwith the human readable time Johannes did to git-annotate.  I do\nnot know what timezone CVS annotate shows its dates offhand (it\nseems to only show dates).  Johannes, is this an attempt to\nmatch what CVS does?\n\nI am wondering if we want to be in line with the date formatting\nconvention used for our commits and tags, that is, to show local\ntimestamp with timezone.  The code to use would be show_date()\nfrom date.c if we go that route.\n"},{"id":"17190","messageId":"20060305123800.GD23448@c165.ib.student.liu.se","threadId":"3565","inReplyTo":"7vbqwlgkhk.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] git-blame: Make the output human readable","fromName":"Fredrik Kuivinen","fromEmail":"freku045@student.liu.se","sentAt":"2006-03-05T12:38:01Z","receivedAt":"2006-03-05T12:38:01Z","isPatch":true,"sender":{"key":"frekui@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13770967?v=4"},"body":"On Sun, Mar 05, 2006 at 04:10:47AM -0800, Junio C Hamano wrote:\n> Fredrik Kuivinen <freku045@student.liu.se> writes:\n> \n> > The default output mode is slightly different from git-annotate's.\n> > However, git-annotate's output mode can be obtained by using the\n> > '-c' flag.\n> \n> It might be better to default to human readable and make the\n> script consumption format an option, if only to reduce typing.\n> \n\nThe default output format is human readable, but it is different from\nthe output format used by git-annotate. By default, (when the patch is\napplied) git-blame outputs lines with on the following form:\n\n   <eight first digits of commit SHA1> (<first 15 letters of committer's name> YYYY-MM-DD HH:MM:SS TZ <line number, right justified>) file contents\n\nwhere as git-annotate uses\n\n   <eight first digits of commit SHA1>\\t(<committer's name, right justified, padded to 10 characters> YYYY-MM-DD HH:MM:SS TZ\\t<line number>)file contents\n\nI find the first format easier to read since everything is aligned (we\nalways output 15 characters for the committer's name padded with\nspaces if necessary and the line numbers are padded appropriately). It\nalso takes up less space on screen since it doesn't use tabs.\n\nHowever, I wanted to use the tests for git-annotate to test git-blame\ntoo and the tests do, of course, expect the output to be in\ngit-annotate's format. Hence, the '-c' switch.\n\nWe may want to add an output format suitable for scripts too, which\njust lists the SHA1. But I don't think it is much more difficult to\nparse the format above, at least not if you just want the SHA1s.\n\n> > diff --git a/Makefile b/Makefile\n> > index b6d8804..eb1887d 100644\n> > --- a/Makefile\n> > +++ b/Makefile\n> > @@ -534,6 +534,10 @@ git-rev-list$X: rev-list.o $(LIB_FILE)\n> >  \t$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n> >  \t\t$(LIBS) $(OPENSSL_LIBSSL)\n> >  \n> > +git-blame$X: blame.o $(LIB_FILE)\n> > +\t$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n> > +\t\t$(LIBS) -lm\n> > +\n> \n> I wonder what it is about to link this binary different from others...\n> \n\nIt uses log(3) to compute the number of digits needed to represent the\nlast line number. It is probably better to this some other way\nthough...\n\n> > +char* format_time(unsigned long time, const char* tz)\n> > +{\n> > +\tstatic char time_buf[128];\n> > +\ttime_t t = time;\n> > +\n> > +\tstrftime(time_buf, sizeof(time_buf), \"%Y-%m-%d %H:%M:%S \", gmtime(&t));\n> > +\tstrcat(time_buf, tz);\n> > +\treturn time_buf;\n> > +}\n> \n> I think this shows GMT with time offset, which is compatible\n> with the human readable time Johannes did to git-annotate.  I do\n> not know what timezone CVS annotate shows its dates offhand (it\n> seems to only show dates).  Johannes, is this an attempt to\n> match what CVS does?\n> \n> I am wondering if we want to be in line with the date formatting\n> convention used for our commits and tags, that is, to show local\n> timestamp with timezone.  The code to use would be show_date()\n> from date.c if we go that route.\n> \n\nI think it is a good idea. Consistency is good.\n\n- Fredrik\n"},{"id":"17191","messageId":"Pine.LNX.4.63.0603051509480.12799@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"3565","inReplyTo":"7vbqwlgkhk.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] git-blame: Make the output human readable","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-03-05T14:11:29Z","receivedAt":"2006-03-05T14:11:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 5 Mar 2006, Junio C Hamano wrote:\n\n> Fredrik Kuivinen <freku045@student.liu.se> writes:\n> \n> > +char* format_time(unsigned long time, const char* tz)\n> > +{\n> > +\tstatic char time_buf[128];\n> > +\ttime_t t = time;\n> > +\n> > +\tstrftime(time_buf, sizeof(time_buf), \"%Y-%m-%d %H:%M:%S \", gmtime(&t));\n> > +\tstrcat(time_buf, tz);\n> > +\treturn time_buf;\n> > +}\n> \n> I think this shows GMT with time offset, which is compatible\n> with the human readable time Johannes did to git-annotate.  I do\n> not know what timezone CVS annotate shows its dates offhand (it\n> seems to only show dates).  Johannes, is this an attempt to\n> match what CVS does?\n\nCVS only shows the date, something like\n\n\tstrftime(\"%Y-%b-%d\", gmtime($timestamp));\n\n> I am wondering if we want to be in line with the date formatting\n> convention used for our commits and tags, that is, to show local\n> timestamp with timezone.  The code to use would be show_date()\n> from date.c if we go that route.\n\nI like that approach. Sometimes imitating CVS can be overdone.\n\nCiao,\nDscho\n"},{"id":"17192","messageId":"Pine.LNX.4.63.0603051516020.12866@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"3565","inReplyTo":"20060305123800.GD23448@c165.ib.student.liu.se","subject":"Re: [PATCH] git-blame: Make the output human readable","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-03-05T14:23:04Z","receivedAt":"2006-03-05T14:23:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 5 Mar 2006, Fredrik Kuivinen wrote:\n\n> On Sun, Mar 05, 2006 at 04:10:47AM -0800, Junio C Hamano wrote:\n> > Fredrik Kuivinen <freku045@student.liu.se> writes:\n> > \n> > > +git-blame$X: blame.o $(LIB_FILE)\n> > > +\t$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n> > > +\t\t$(LIBS) -lm\n> > > +\n> > \n> > I wonder what it is about to link this binary different from others...\n> > \n> \n> It uses log(3) to compute the number of digits needed to represent the\n> last line number. It is probably better to this some other way\n> though...\n\nHow about this:\n\n-\tmax_digits = 1 + log(num_blame_lines+1)/log(10);\n+\tfor (i = 10, max_digits = 1; i <= num_blame_lines + 1;\n+\t\ti *= 10, max_digits++);\n\n(Totally untested)\n\nHth,\nDscho\n"},{"id":"17204","messageId":"7vveuseg2u.fsf@assigned-by-dhcp.cox.net","threadId":"3565","inReplyTo":"20060305123800.GD23448@c165.ib.student.liu.se","subject":"Re: [PATCH] git-blame: Make the output human readable","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-05T21:28:57Z","receivedAt":"2006-03-05T21:28:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fredrik Kuivinen <freku045@student.liu.se> writes:\n\n> I find the first format easier to read since everything is aligned (we\n> always output 15 characters for the committer's name padded with\n> spaces if necessary and the line numbers are padded appropriately). It\n> also takes up less space on screen since it doesn't use tabs.\n\nCareful.  The convention for names is to encode them in UTF-8,\nso if you mean 15 \"characters\" that might be OK but if it can\ntruncate in the middle of a multibyte sequence of UTF-8 encoded\nsingle character it is a no-no.\n\nWe are talking about \"casual\" aligning, so I would not bring up\n\"proportional fonts\", but even on a monospace terminal and\nline-printer output, there still is the issue of byte count not\nmatching columns.  In an i18nized environment, aligning columns\nby counting bytes is a lost battle.\n\nIn any case, please make sure you do not chop a character in the\nmiddle at least [*1*].\n\n> We may want to add an output format suitable for scripts too, which\n> just lists the SHA1. But I don't think it is much more difficult to\n> parse the format above, at least not if you just want the SHA1s.\n\nFair enough.\n\n> It uses log(3) to compute the number of digits needed to represent the\n> last line number. It is probably better to this some other way\n> though...\n\nYup.\n\n\n[Footnote]\n\n*1* I was kind of impressed that Linus was careful about this\nissue when I saw the commit log chopping is only done at line\nboundaries.  A very careful coder would have chopped the last\nline in the middle at character boundary, but if you do not want\nto bother that much, chopping at line boundary is better than\nchopping the last line in the middle of a character ;-).\n"},{"id":"17207","messageId":"7vhd6cechf.fsf_-_@assigned-by-dhcp.cox.net","threadId":"3565","inReplyTo":"20060305123800.GD23448@c165.ib.student.liu.se","subject":"[PATCH] blame: avoid -lm by not using log().","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-05T22:46:36Z","receivedAt":"2006-03-05T22:46:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\n... as suggested on the list.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n Makefile |    4 ----\n blame.c  |    6 ++++--\n 2 files changed, 4 insertions(+), 6 deletions(-)\n\ne0539773df17e5f8410850b8ffcfe8d2fa14ab7a\ndiff --git a/Makefile b/Makefile\nindex eb1887d..b6d8804 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -534,10 +534,6 @@ git-rev-list$X: rev-list.o $(LIB_FILE)\n \t$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n \t\t$(LIBS) $(OPENSSL_LIBSSL)\n \n-git-blame$X: blame.o $(LIB_FILE)\n-\t$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n-\t\t$(LIBS) -lm\n-\n init-db.o: init-db.c\n \t$(CC) -c $(ALL_CFLAGS) \\\n \t\t-DDEFAULT_GIT_TEMPLATE_DIR='\"$(template_dir_SQ)\"' $*.c\ndiff --git a/blame.c b/blame.c\nindex 168b1f5..59146fa 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -589,7 +589,7 @@ int main(int argc, const char **argv)\n \t\t\t\tusage(blame_usage);\n \t\t\telse if(!strcmp(argv[i], \"-l\") ||\n \t\t\t\t!strcmp(argv[i], \"--long\")) {\n-\t\t\t\tsha1_len = 20;\n+\t\t\t\tsha1_len = 40;\n \t\t\t\tcontinue;\n \t\t\t} else if(!strcmp(argv[i], \"-c\") ||\n \t\t\t\t  !strcmp(argv[i], \"--compability\")) {\n@@ -651,7 +651,9 @@ int main(int argc, const char **argv)\n \tprocess_commits(&rev, filename, &initial);\n \n \tbuf = blame_contents;\n-\tmax_digits = 1 + log(num_blame_lines+1)/log(10);\n+\tfor (max_digits = 1, i = 10; i <= num_blame_lines; max_digits++)\n+\t\ti *= 10;\n+\n \tfor (i = 0; i < num_blame_lines; i++) {\n \t\tstruct commit *c = blame_lines[i];\n \t\tif (!c)\n-- \n1.2.4.gee5c7\n"},{"id":"17208","messageId":"7vbqwkecf2.fsf_-_@assigned-by-dhcp.cox.net","threadId":"3565","inReplyTo":"20060305123800.GD23448@c165.ib.student.liu.se","subject":"[PATCH] blame and annotate: show localtime with timezone.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-05T22:48:01Z","receivedAt":"2006-03-05T22:48:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Earlier they showed gmtime and timezone, which was inconsistent\nwith the way our commits and tags are pretty-printed.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n blame.c           |   15 ++++++++++++---\n git-annotate.perl |    8 +++++++-\n 2 files changed, 19 insertions(+), 4 deletions(-)\n\ne29f298a17ee898fd0d191d448ba4fc202175896\ndiff --git a/blame.c b/blame.c\nindex 59146fa..a3a8ddc 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -550,13 +550,22 @@ static void get_commit_info(struct commi\n \t*tmp = 0;\n }\n \n-char* format_time(unsigned long time, const char* tz)\n+static const char* format_time(unsigned long time, const char* tz_str)\n {\n \tstatic char time_buf[128];\n \ttime_t t = time;\n+\tint minutes, tz;\n+\tstruct tm *tm;\n \n-\tstrftime(time_buf, sizeof(time_buf), \"%Y-%m-%d %H:%M:%S \", gmtime(&t));\n-\tstrcat(time_buf, tz);\n+\ttz = atoi(tz_str);\n+\tminutes = tz < 0 ? -tz : tz;\n+\tminutes = (minutes / 100)*60 + (minutes % 100);\n+\tminutes = tz < 0 ? -minutes : minutes;\n+\tt = time + minutes * 60;\n+\ttm = gmtime(&t);\n+\n+\tstrftime(time_buf, sizeof(time_buf), \"%Y-%m-%d %H:%M:%S \", tm);\n+\tstrcat(time_buf, tz_str);\n \treturn time_buf;\n }\n \ndiff --git a/git-annotate.perl b/git-annotate.perl\nindex d93ee19..b113def 100755\n--- a/git-annotate.perl\n+++ b/git-annotate.perl\n@@ -418,7 +418,13 @@ sub format_date {\n \t\treturn $_[0];\n \t}\n \tmy ($timestamp, $timezone) = split(' ', $_[0]);\n-\treturn strftime(\"%Y-%m-%d %H:%M:%S \" . $timezone, gmtime($timestamp));\n+\tmy $minutes = abs($timezone);\n+\t$minutes = int($minutes / 100) * 60 + ($minutes % 100);\n+\tif ($timezone < 0) {\n+\t    $minutes = -$minutes;\n+\t}\n+\tmy $t = $timestamp + $minutes * 60;\n+\treturn strftime(\"%Y-%m-%d %H:%M:%S \" . $timezone, gmtime($t));\n }\n \n # Copied from git-send-email.perl - We need a Git.pm module..\n-- \n1.2.4.gee5c7\n"},{"id":"17212","messageId":"Pine.LNX.4.63.0603060032410.32270@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"3565","inReplyTo":"7vhd6cechf.fsf_-_@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] blame: avoid -lm by not using log().","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-03-05T23:36:03Z","receivedAt":"2006-03-05T23:36:03Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 5 Mar 2006, Junio C Hamano wrote:\n\n> -\tmax_digits = 1 + log(num_blame_lines+1)/log(10);\n> +\tfor (max_digits = 1, i = 10; i <= num_blame_lines; max_digits++)\n> +\t\ti *= 10;\n\nAccording to my late-night maths skills, these two methods do not do the \nsame thing: if num_blame_lines == 9, the log method assigns 2 to \nmax_digits, but the for loop stops at max_digits == 1. A trivial fix would \nbe to test for i <= num_blame_lines + 1.\n\nCiao,\nDscho\n"},{"id":"17302","messageId":"20060307163427.GB4457@c165.ib.student.liu.se","threadId":"3565","inReplyTo":"7vveuseg2u.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] git-blame: Make the output human readable","fromName":"Fredrik Kuivinen","fromEmail":"freku045@student.liu.se","sentAt":"2006-03-07T16:34:27Z","receivedAt":"2006-03-07T16:34:27Z","isPatch":true,"sender":{"key":"frekui@gmail.com","avatar":"https://avatars.githubusercontent.com/u/13770967?v=4"},"body":"On Sun, Mar 05, 2006 at 01:28:57PM -0800, Junio C Hamano wrote:\n> Fredrik Kuivinen <freku045@student.liu.se> writes:\n> \n> > I find the first format easier to read since everything is aligned (we\n> > always output 15 characters for the committer's name padded with\n> > spaces if necessary and the line numbers are padded appropriately). It\n> > also takes up less space on screen since it doesn't use tabs.\n> \n> Careful.  The convention for names is to encode them in UTF-8,\n> so if you mean 15 \"characters\" that might be OK but if it can\n> truncate in the middle of a multibyte sequence of UTF-8 encoded\n> single character it is a no-no.\n> \n> We are talking about \"casual\" aligning, so I would not bring up\n> \"proportional fonts\", but even on a monospace terminal and\n> line-printer output, there still is the issue of byte count not\n> matching columns.  In an i18nized environment, aligning columns\n> by counting bytes is a lost battle.\n> \n> In any case, please make sure you do not chop a character in the\n> middle at least [*1*].\n> \n\nI hadn't thought of that. The code as it is now will occasionally do\nthe wrong thing when encountered with multibyte per code point\nencodings. If we can assume that the name is in UTF-8 then the code\nposted by \"linux@horizon.com\" to the list should do the trick.\n\nHowever, can we assume that the name is in UTF-8? Do\ni18n.commitencoding only apply to the commit message, or is it\nintended to apply to the author/committer information too?\n\nI am beginning to think that it might be best to, by default, store\nthe author, committer and commit messages in UTF-8. And then\nautomatically convert from/to the users locale on input/output. (I\njust read the old \"Rss produced by git is not valid xml?\" thread where\nthis issue was discussed quite a bit. However, I didn't see the 'store\nin UTF-8 by default and convert from/to users locale' method anywhere\nin that thread.)\n\n- Fredrik\n"}]}