{"thread":{"id":"9894","subject":"[PATCH 0/3] the return of the strbuf","startedAt":"2007-09-17T09:19:04Z","lastAt":"2007-09-20T21:52:33Z","messageCount":11,"participants":["Pierre Habouzit","Shawn O. Pearce","Junio C Hamano","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"53304","messageId":"20070917125257.1BF16344A4A@madism.org","threadId":"9894","inReplyTo":"20070917125211.GA18176@artemis.corp","subject":"[PATCH 1/3] Drop strbuf's 'eof' marker, and make read_line a first class citizen.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-17T09:19:04Z","receivedAt":"2007-09-17T09:19:04Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"read_line is now strbuf_getline, and is a first class citizen, it returns 0\nwhen reading a line worked, EOF else.\n\nThe ->eof marker was used non-locally by fast-import.c, mimic the same\nbehaviour using a static int in \"read_next_command\", that now returns -1 on\nEOF, and avoids to call strbuf_getline when it's in EOF state.\n\nAlso no longer automagically strbuf_release the buffer, it's counter\nintuitive and breaks fast-import in a very subtle way.\n\nNote: being at EOF implies that command_buf.len == 0.\n\nSigned-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n builtin-checkout-index.c |    5 ++---\n builtin-update-index.c   |    8 ++++----\n fast-import.c            |   34 +++++++++++++++++++---------------\n fetch.c                  |    4 ++--\n mktree.c                 |    4 ++--\n strbuf.c                 |   20 ++++++++------------\n strbuf.h                 |    5 ++---\n 7 files changed, 39 insertions(+), 41 deletions(-)\n\ndiff --git a/builtin-checkout-index.c b/builtin-checkout-index.c\nindex 85e8efe..a18ecc4 100644\n--- a/builtin-checkout-index.c\n+++ b/builtin-checkout-index.c\n@@ -277,9 +277,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)\n \t\twhile (1) {\n \t\t\tchar *path_name;\n \t\t\tconst char *p;\n-\n-\t\t\tread_line(&buf, stdin, line_termination);\n-\t\t\tif (buf.eof)\n+\t\t\tif (strbuf_getline(&buf, stdin, line_termination) == EOF)\n \t\t\t\tbreak;\n \t\t\tif (line_termination && buf.buf[0] == '\"')\n \t\t\t\tpath_name = unquote_c_style(buf.buf, NULL);\n@@ -292,6 +290,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)\n \t\t\tif (path_name != buf.buf)\n \t\t\t\tfree(path_name);\n \t\t}\n+\t\tstrbuf_release(&buf);\n \t}\n \n \tif (all)\ndiff --git a/builtin-update-index.c b/builtin-update-index.c\nindex 0b60513..acd5ab5 100644\n--- a/builtin-update-index.c\n+++ b/builtin-update-index.c\n@@ -320,8 +320,7 @@ static void read_index_info(int line_termination)\n \t\t * This format is to put higher order stages into the\n \t\t * index file and matches git-ls-files --stage output.\n \t\t */\n-\t\tread_line(&buf, stdin, line_termination);\n-\t\tif (buf.eof)\n+\t\tif (strbuf_getline(&buf, stdin, line_termination) == EOF)\n \t\t\tbreak;\n \n \t\terrno = 0;\n@@ -383,6 +382,7 @@ static void read_index_info(int line_termination)\n \tbad_line:\n \t\tdie(\"malformed index info %s\", buf.buf);\n \t}\n+\tstrbuf_release(&buf);\n }\n \n static const char update_index_usage[] =\n@@ -710,8 +710,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t\twhile (1) {\n \t\t\tchar *path_name;\n \t\t\tconst char *p;\n-\t\t\tread_line(&buf, stdin, line_termination);\n-\t\t\tif (buf.eof)\n+\t\t\tif (strbuf_getline(&buf, stdin, line_termination) == EOF)\n \t\t\t\tbreak;\n \t\t\tif (line_termination && buf.buf[0] == '\"')\n \t\t\t\tpath_name = unquote_c_style(buf.buf, NULL);\n@@ -726,6 +725,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t\t\tif (path_name != buf.buf)\n \t\t\t\tfree(path_name);\n \t\t}\n+\t\tstrbuf_release(&buf);\n \t}\n \n  finish:\ndiff --git a/fast-import.c b/fast-import.c\nindex 1866d34..da04566 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1584,20 +1584,25 @@ static void dump_marks(void)\n \t\t\tmark_file, strerror(errno));\n }\n \n-static void read_next_command(void)\n+static int read_next_command(void)\n {\n+\tstatic int stdin_eof = 0;\n+\n+\tif (stdin_eof) {\n+\t\tunread_command_buf = 0;\n+\t\treturn EOF;\n+\t}\n+\n \tdo {\n \t\tif (unread_command_buf) {\n \t\t\tunread_command_buf = 0;\n-\t\t\tif (command_buf.eof)\n-\t\t\t\treturn;\n \t\t} else {\n \t\t\tstruct recent_command *rc;\n \n \t\t\tstrbuf_detach(&command_buf);\n-\t\t\tread_line(&command_buf, stdin, '\\n');\n-\t\t\tif (command_buf.eof)\n-\t\t\t\treturn;\n+\t\t\tstdin_eof = strbuf_getline(&command_buf, stdin, '\\n');\n+\t\t\tif (stdin_eof)\n+\t\t\t\treturn EOF;\n \n \t\t\trc = rc_free;\n \t\t\tif (rc)\n@@ -1616,6 +1621,8 @@ static void read_next_command(void)\n \t\t\tcmd_tail = rc;\n \t\t}\n \t} while (command_buf.buf[0] == '#');\n+\n+\treturn 0;\n }\n \n static void skip_optional_lf(void)\n@@ -1648,8 +1655,7 @@ static void *cmd_data (size_t *size)\n \t\tsize_t term_len = command_buf.len - 5 - 2;\n \n \t\tfor (;;) {\n-\t\t\tread_line(&command_buf, stdin, '\\n');\n-\t\t\tif (command_buf.eof)\n+\t\t\tif (strbuf_getline(&command_buf, stdin, '\\n') == EOF)\n \t\t\t\tdie(\"EOF in data (terminator '%s' not found)\", term);\n \t\t\tif (term_len == command_buf.len\n \t\t\t\t&& !strcmp(term, command_buf.buf))\n@@ -2095,7 +2101,7 @@ static void cmd_new_commit(void)\n \t}\n \n \t/* file_change* */\n-\twhile (!command_buf.eof && command_buf.len > 0) {\n+\twhile (command_buf.len > 0) {\n \t\tif (!prefixcmp(command_buf.buf, \"M \"))\n \t\t\tfile_change_m(b);\n \t\telse if (!prefixcmp(command_buf.buf, \"D \"))\n@@ -2110,7 +2116,8 @@ static void cmd_new_commit(void)\n \t\t\tunread_command_buf = 1;\n \t\t\tbreak;\n \t\t}\n-\t\tread_next_command();\n+\t\tif (read_next_command() == EOF)\n+\t\t\tbreak;\n \t}\n \n \t/* build the tree and the commit */\n@@ -2375,11 +2382,8 @@ int main(int argc, const char **argv)\n \tprepare_packed_git();\n \tstart_packfile();\n \tset_die_routine(die_nicely);\n-\tfor (;;) {\n-\t\tread_next_command();\n-\t\tif (command_buf.eof)\n-\t\t\tbreak;\n-\t\telse if (!strcmp(\"blob\", command_buf.buf))\n+\twhile (read_next_command() != EOF) {\n+\t\tif (!strcmp(\"blob\", command_buf.buf))\n \t\t\tcmd_new_blob();\n \t\telse if (!prefixcmp(command_buf.buf, \"commit \"))\n \t\t\tcmd_new_commit();\ndiff --git a/fetch.c b/fetch.c\nindex c256e6f..b1c1f07 100644\n--- a/fetch.c\n+++ b/fetch.c\n@@ -222,8 +222,7 @@ int pull_targets_stdin(char ***target, const char ***write_ref)\n \t\tchar *rf_one = NULL;\n \t\tchar *tg_one;\n \n-\t\tread_line(&buf, stdin, '\\n');\n-\t\tif (buf.eof)\n+\t\tif (strbuf_getline(&buf, stdin, '\\n') == EOF)\n \t\t\tbreak;\n \t\ttg_one = buf.buf;\n \t\trf_one = strchr(tg_one, '\\t');\n@@ -239,6 +238,7 @@ int pull_targets_stdin(char ***target, const char ***write_ref)\n \t\t(*write_ref)[targets] = rf_one ? xstrdup(rf_one) : NULL;\n \t\ttargets++;\n \t}\n+\tstrbuf_release(&buf);\n \treturn targets;\n }\n \ndiff --git a/mktree.c b/mktree.c\nindex 5dab4bd..9c137de 100644\n--- a/mktree.c\n+++ b/mktree.c\n@@ -88,8 +88,7 @@ int main(int ac, char **av)\n \t\tenum object_type type;\n \t\tchar *path;\n \n-\t\tread_line(&sb, stdin, line_termination);\n-\t\tif (sb.eof)\n+\t\tif (strbuf_getline(&sb, stdin, line_termination) == EOF)\n \t\t\tbreak;\n \t\tptr = sb.buf;\n \t\t/* Input is non-recursive ls-tree output format\n@@ -121,6 +120,7 @@ int main(int ac, char **av)\n \t\tif (path != ntr)\n \t\t\tfree(path);\n \t}\n+\tstrbuf_release(&sb);\n \twrite_tree(sha1);\n \tputs(sha1_to_hex(sha1));\n \texit(0);\ndiff --git a/strbuf.c b/strbuf.c\nindex c5f9e2a..59383ac 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -17,7 +17,6 @@ void strbuf_reset(struct strbuf *sb)\n {\n \tif (sb->len)\n \t\tstrbuf_setlen(sb, 0);\n-\tsb->eof = 0;\n }\n \n char *strbuf_detach(struct strbuf *sb)\n@@ -145,14 +144,13 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)\n \treturn sb->len - oldlen;\n }\n \n-void read_line(struct strbuf *sb, FILE *fp, int term)\n+int strbuf_getline(struct strbuf *sb, FILE *fp, int term)\n {\n \tint ch;\n-\tif (feof(fp)) {\n-\t\tstrbuf_release(sb);\n-\t\tsb->eof = 1;\n-\t\treturn;\n-\t}\n+\n+\tstrbuf_grow(sb, 0);\n+\tif (feof(fp))\n+\t\treturn EOF;\n \n \tstrbuf_reset(sb);\n \twhile ((ch = fgetc(fp)) != EOF) {\n@@ -161,11 +159,9 @@ void read_line(struct strbuf *sb, FILE *fp, int term)\n \t\tstrbuf_grow(sb, 1);\n \t\tsb->buf[sb->len++] = ch;\n \t}\n-\tif (ch == EOF && sb->len == 0) {\n-\t\tstrbuf_release(sb);\n-\t\tsb->eof = 1;\n-\t}\n+\tif (ch == EOF && sb->len == 0)\n+\t\treturn EOF;\n \n-\tstrbuf_grow(sb, 1);\n \tsb->buf[sb->len] = '\\0';\n+\treturn 0;\n }\ndiff --git a/strbuf.h b/strbuf.h\nindex f163c63..b2cbd97 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -44,11 +44,10 @@\n struct strbuf {\n \tsize_t alloc;\n \tsize_t len;\n-\tint eof;\n \tchar *buf;\n };\n \n-#define STRBUF_INIT  { 0, 0, 0, NULL }\n+#define STRBUF_INIT  { 0, 0, NULL }\n \n /*----- strbuf life cycle -----*/\n extern void strbuf_init(struct strbuf *, size_t);\n@@ -101,6 +100,6 @@ extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);\n /* XXX: if read fails, any partial read is undone */\n extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint);\n \n-extern void read_line(struct strbuf *, FILE *, int);\n+extern int strbuf_getline(struct strbuf *, FILE *, int);\n \n #endif /* STRBUF_H */\n-- \n1.5.3.1\n"},{"id":"53305","messageId":"20070917125258.2521C344A4A@madism.org","threadId":"9894","inReplyTo":"20070917125211.GA18176@artemis.corp","subject":"[PATCH 2/3] fast-import was using dbuf's, replace them with strbuf's.","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-17T11:48:17Z","receivedAt":"2007-09-17T11:48:17Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"Signed-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n fast-import.c |  177 ++++++++++++++++++++++-----------------------------------\n 1 files changed, 68 insertions(+), 109 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex da04566..e456eab 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -250,12 +250,6 @@ struct tag\n \tunsigned char sha1[20];\n };\n \n-struct dbuf\n-{\n-\tvoid *buffer;\n-\tsize_t capacity;\n-};\n-\n struct hash_list\n {\n \tstruct hash_list *next;\n@@ -323,8 +317,8 @@ static unsigned int tree_entry_alloc = 1000;\n static void *avail_tree_entry;\n static unsigned int avail_tree_table_sz = 100;\n static struct avail_tree_content **avail_tree_table;\n-static struct dbuf old_tree;\n-static struct dbuf new_tree;\n+static struct strbuf old_tree = STRBUF_INIT;\n+static struct strbuf new_tree = STRBUF_INIT;\n \n /* Branch data */\n static unsigned long max_active_branches = 5;\n@@ -346,7 +340,7 @@ static struct recent_command *cmd_tail = &cmd_hist;\n static struct recent_command *rc_free;\n static unsigned int cmd_save = 100;\n static uintmax_t next_mark;\n-static struct dbuf new_data;\n+static struct strbuf new_data = STRBUF_INIT;\n \n static void write_branch_report(FILE *rpt, struct branch *b)\n {\n@@ -566,17 +560,6 @@ static char *pool_strdup(const char *s)\n \treturn r;\n }\n \n-static void size_dbuf(struct dbuf *b, size_t maxlen)\n-{\n-\tif (b->buffer) {\n-\t\tif (b->capacity >= maxlen)\n-\t\t\treturn;\n-\t\tfree(b->buffer);\n-\t}\n-\tb->capacity = ((maxlen / 1024) + 1) * 1024;\n-\tb->buffer = xmalloc(b->capacity);\n-}\n-\n static void insert_mark(uintmax_t idnum, struct object_entry *oe)\n {\n \tstruct mark_set *s = marks;\n@@ -1005,8 +988,7 @@ static size_t encode_header(\n \n static int store_object(\n \tenum object_type type,\n-\tvoid *dat,\n-\tsize_t datlen,\n+\tstruct strbuf *dat,\n \tstruct last_object *last,\n \tunsigned char *sha1out,\n \tuintmax_t mark)\n@@ -1020,10 +1002,10 @@ static int store_object(\n \tz_stream s;\n \n \thdrlen = sprintf((char*)hdr,\"%s %lu\", typename(type),\n-\t\t(unsigned long)datlen) + 1;\n+\t\t(unsigned long)dat->len) + 1;\n \tSHA1_Init(&c);\n \tSHA1_Update(&c, hdr, hdrlen);\n-\tSHA1_Update(&c, dat, datlen);\n+\tSHA1_Update(&c, dat->buf, dat->len);\n \tSHA1_Final(sha1, &c);\n \tif (sha1out)\n \t\thashcpy(sha1out, sha1);\n@@ -1044,9 +1026,9 @@ static int store_object(\n \n \tif (last && last->data && last->depth < max_depth) {\n \t\tdelta = diff_delta(last->data, last->len,\n-\t\t\tdat, datlen,\n+\t\t\tdat->buf, dat->len,\n \t\t\t&deltalen, 0);\n-\t\tif (delta && deltalen >= datlen) {\n+\t\tif (delta && deltalen >= dat->len) {\n \t\t\tfree(delta);\n \t\t\tdelta = NULL;\n \t\t}\n@@ -1059,8 +1041,8 @@ static int store_object(\n \t\ts.next_in = delta;\n \t\ts.avail_in = deltalen;\n \t} else {\n-\t\ts.next_in = dat;\n-\t\ts.avail_in = datlen;\n+\t\ts.next_in = (void *)dat->buf;\n+\t\ts.avail_in = dat->len;\n \t}\n \ts.avail_out = deflateBound(&s, s.avail_in);\n \ts.next_out = out = xmalloc(s.avail_out);\n@@ -1083,8 +1065,8 @@ static int store_object(\n \n \t\t\tmemset(&s, 0, sizeof(s));\n \t\t\tdeflateInit(&s, zlib_compression_level);\n-\t\t\ts.next_in = dat;\n-\t\t\ts.avail_in = datlen;\n+\t\t\ts.next_in = (void *)dat->buf;\n+\t\t\ts.avail_in = dat->len;\n \t\t\ts.avail_out = deflateBound(&s, s.avail_in);\n \t\t\ts.next_out = out = xrealloc(out, s.avail_out);\n \t\t\twhile (deflate(&s, Z_FINISH) == Z_OK)\n@@ -1118,7 +1100,7 @@ static int store_object(\n \t} else {\n \t\tif (last)\n \t\t\tlast->depth = 0;\n-\t\thdrlen = encode_header(type, datlen, hdr);\n+\t\thdrlen = encode_header(type, dat->len, hdr);\n \t\twrite_or_die(pack_data->pack_fd, hdr, hdrlen);\n \t\tpack_size += hdrlen;\n \t}\n@@ -1131,9 +1113,9 @@ static int store_object(\n \tif (last) {\n \t\tif (!last->no_free)\n \t\t\tfree(last->data);\n-\t\tlast->data = dat;\n \t\tlast->offset = e->offset;\n-\t\tlast->len = datlen;\n+\t\tlast->data = dat->buf;\n+\t\tlast->len = dat->len;\n \t}\n \treturn 0;\n }\n@@ -1229,14 +1211,10 @@ static int tecmp1 (const void *_a, const void *_b)\n \t\tb->name->str_dat, b->name->str_len, b->versions[1].mode);\n }\n \n-static void mktree(struct tree_content *t,\n-\tint v,\n-\tunsigned long *szp,\n-\tstruct dbuf *b)\n+static void mktree(struct tree_content *t, int v, struct strbuf *b)\n {\n \tsize_t maxlen = 0;\n \tunsigned int i;\n-\tchar *c;\n \n \tif (!v)\n \t\tqsort(t->entries,t->entry_count,sizeof(t->entries[0]),tecmp0);\n@@ -1248,27 +1226,22 @@ static void mktree(struct tree_content *t,\n \t\t\tmaxlen += t->entries[i]->name->str_len + 34;\n \t}\n \n-\tsize_dbuf(b, maxlen);\n-\tc = b->buffer;\n+\tstrbuf_reset(b);\n+\tstrbuf_grow(b, maxlen);\n \tfor (i = 0; i < t->entry_count; i++) {\n \t\tstruct tree_entry *e = t->entries[i];\n \t\tif (!e->versions[v].mode)\n \t\t\tcontinue;\n-\t\tc += sprintf(c, \"%o\", (unsigned int)e->versions[v].mode);\n-\t\t*c++ = ' ';\n-\t\tstrcpy(c, e->name->str_dat);\n-\t\tc += e->name->str_len + 1;\n-\t\thashcpy((unsigned char*)c, e->versions[v].sha1);\n-\t\tc += 20;\n+\t\tstrbuf_addf(b, \"%o %s%c\", (unsigned int)e->versions[v].mode,\n+\t\t\t\t\te->name->str_dat, '\\0');\n+\t\tstrbuf_add(b, e->versions[v].sha1, 20);\n \t}\n-\t*szp = c - (char*)b->buffer;\n }\n \n static void store_tree(struct tree_entry *root)\n {\n \tstruct tree_content *t = root->tree;\n \tunsigned int i, j, del;\n-\tunsigned long new_len;\n \tstruct last_object lo;\n \tstruct object_entry *le;\n \n@@ -1288,16 +1261,16 @@ static void store_tree(struct tree_entry *root)\n \t\tlo.depth = 0;\n \t\tlo.no_free = 0;\n \t} else {\n-\t\tmktree(t, 0, &lo.len, &old_tree);\n-\t\tlo.data = old_tree.buffer;\n+\t\tmktree(t, 0, &old_tree);\n+\t\tlo.len  = old_tree.len;\n+\t\tlo.data = old_tree.buf;\n \t\tlo.offset = le->offset;\n \t\tlo.depth = t->delta_depth;\n \t\tlo.no_free = 1;\n \t}\n \n-\tmktree(t, 1, &new_len, &new_tree);\n-\tstore_object(OBJ_TREE, new_tree.buffer, new_len,\n-\t\t&lo, root->versions[1].sha1, 0);\n+\tmktree(t, 1, &new_tree);\n+\tstore_object(OBJ_TREE, &new_tree, &lo, root->versions[1].sha1, 0);\n \n \tt->delta_depth = lo.depth;\n \tfor (i = 0, j = 0, del = 0; i < t->entry_count; i++) {\n@@ -1642,11 +1615,10 @@ static void cmd_mark(void)\n \t\tnext_mark = 0;\n }\n \n-static void *cmd_data (size_t *size)\n+static void cmd_data(struct strbuf *sb)\n {\n-\tstruct strbuf buffer;\n+\tstrbuf_reset(sb);\n \n-\tstrbuf_init(&buffer, 0);\n \tif (prefixcmp(command_buf.buf, \"data \"))\n \t\tdie(\"Expected 'data n' command, found: %s\", command_buf.buf);\n \n@@ -1660,8 +1632,8 @@ static void *cmd_data (size_t *size)\n \t\t\tif (term_len == command_buf.len\n \t\t\t\t&& !strcmp(term, command_buf.buf))\n \t\t\t\tbreak;\n-\t\t\tstrbuf_addbuf(&buffer, &command_buf);\n-\t\t\tstrbuf_addch(&buffer, '\\n');\n+\t\t\tstrbuf_addbuf(sb, &command_buf);\n+\t\t\tstrbuf_addch(sb, '\\n');\n \t\t}\n \t\tfree(term);\n \t}\n@@ -1671,7 +1643,7 @@ static void *cmd_data (size_t *size)\n \t\tlength = strtoul(command_buf.buf + 5, NULL, 10);\n \n \t\twhile (n < length) {\n-\t\t\tsize_t s = strbuf_fread(&buffer, length - n, stdin);\n+\t\t\tsize_t s = strbuf_fread(sb, length - n, stdin);\n \t\t\tif (!s && feof(stdin))\n \t\t\t\tdie(\"EOF in data (%lu bytes remaining)\",\n \t\t\t\t\t(unsigned long)(length - n));\n@@ -1680,8 +1652,6 @@ static void *cmd_data (size_t *size)\n \t}\n \n \tskip_optional_lf();\n-\t*size = buffer.len;\n-\treturn strbuf_detach(&buffer);\n }\n \n static int validate_raw_date(const char *src, char *result, int maxlen)\n@@ -1744,15 +1714,14 @@ static char *parse_ident(const char *buf)\n \n static void cmd_new_blob(void)\n {\n-\tsize_t l;\n-\tvoid *d;\n+\tstruct strbuf buf;\n \n \tread_next_command();\n \tcmd_mark();\n-\td = cmd_data(&l);\n-\n-\tif (store_object(OBJ_BLOB, d, l, &last_blob, NULL, next_mark))\n-\t\tfree(d);\n+\tstrbuf_init(&buf, 0);\n+\tcmd_data(&buf);\n+\tif (store_object(OBJ_BLOB, &buf, &last_blob, NULL, next_mark))\n+\t\tstrbuf_release(&buf);\n }\n \n static void unload_one_branch(void)\n@@ -1848,14 +1817,15 @@ static void file_change_m(struct branch *b)\n \t}\n \n \tif (inline_data) {\n-\t\tsize_t l;\n-\t\tvoid *d;\n+\t\tstruct strbuf buf;\n+\n \t\tif (!p_uq)\n \t\t\tp = p_uq = xstrdup(p);\n \t\tread_next_command();\n-\t\td = cmd_data(&l);\n-\t\tif (store_object(OBJ_BLOB, d, l, &last_blob, sha1, 0))\n-\t\t\tfree(d);\n+\t\tstrbuf_init(&buf, 0);\n+\t\tcmd_data(&buf);\n+\t\tif (store_object(OBJ_BLOB, &buf, &last_blob, sha1, 0))\n+\t\t\tstrbuf_release(&buf);\n \t} else if (oe) {\n \t\tif (oe->type != OBJ_BLOB)\n \t\t\tdie(\"Not a blob (actually a %s): %s\",\n@@ -2062,9 +2032,8 @@ static struct hash_list *cmd_merge(unsigned int *count)\n \n static void cmd_new_commit(void)\n {\n+\tstatic struct strbuf msg = STRBUF_INIT;\n \tstruct branch *b;\n-\tvoid *msg;\n-\tsize_t msglen;\n \tchar *sp;\n \tchar *author = NULL;\n \tchar *committer = NULL;\n@@ -2089,7 +2058,7 @@ static void cmd_new_commit(void)\n \t}\n \tif (!committer)\n \t\tdie(\"Expected committer but didn't get one\");\n-\tmsg = cmd_data(&msglen);\n+\tcmd_data(&msg);\n \tread_next_command();\n \tcmd_from(b);\n \tmerge_list = cmd_merge(&merge_count);\n@@ -2124,46 +2093,39 @@ static void cmd_new_commit(void)\n \tstore_tree(&b->branch_tree);\n \thashcpy(b->branch_tree.versions[0].sha1,\n \t\tb->branch_tree.versions[1].sha1);\n-\tsize_dbuf(&new_data, 114 + msglen\n-\t\t+ merge_count * 49\n-\t\t+ (author\n-\t\t\t? strlen(author) + strlen(committer)\n-\t\t\t: 2 * strlen(committer)));\n-\tsp = new_data.buffer;\n-\tsp += sprintf(sp, \"tree %s\\n\",\n+\n+\tstrbuf_reset(&new_data);\n+\tstrbuf_addf(&new_data, \"tree %s\\n\",\n \t\tsha1_to_hex(b->branch_tree.versions[1].sha1));\n \tif (!is_null_sha1(b->sha1))\n-\t\tsp += sprintf(sp, \"parent %s\\n\", sha1_to_hex(b->sha1));\n+\t\tstrbuf_addf(&new_data, \"parent %s\\n\", sha1_to_hex(b->sha1));\n \twhile (merge_list) {\n \t\tstruct hash_list *next = merge_list->next;\n-\t\tsp += sprintf(sp, \"parent %s\\n\", sha1_to_hex(merge_list->sha1));\n+\t\tstrbuf_addf(&new_data, \"parent %s\\n\", sha1_to_hex(merge_list->sha1));\n \t\tfree(merge_list);\n \t\tmerge_list = next;\n \t}\n-\tsp += sprintf(sp, \"author %s\\n\", author ? author : committer);\n-\tsp += sprintf(sp, \"committer %s\\n\", committer);\n-\t*sp++ = '\\n';\n-\tmemcpy(sp, msg, msglen);\n-\tsp += msglen;\n+\tstrbuf_addf(&new_data,\n+\t\t\"author %s\\n\"\n+\t\t\"committer %s\\n\"\n+\t\t\"\\n\",\n+\t\tauthor ? author : committer, committer);\n+\tstrbuf_addbuf(&new_data, &msg);\n \tfree(author);\n \tfree(committer);\n-\tfree(msg);\n \n-\tif (!store_object(OBJ_COMMIT,\n-\t\tnew_data.buffer, sp - (char*)new_data.buffer,\n-\t\tNULL, b->sha1, next_mark))\n+\tif (!store_object(OBJ_COMMIT, &new_data, NULL, b->sha1, next_mark))\n \t\tb->pack_id = pack_id;\n \tb->last_commit = object_count_by_type[OBJ_COMMIT];\n }\n \n static void cmd_new_tag(void)\n {\n+\tstatic struct strbuf msg = STRBUF_INIT;\n \tchar *sp;\n \tconst char *from;\n \tchar *tagger;\n \tstruct branch *s;\n-\tvoid *msg;\n-\tsize_t msglen;\n \tstruct tag *t;\n \tuintmax_t from_mark = 0;\n \tunsigned char sha1[20];\n@@ -2214,24 +2176,21 @@ static void cmd_new_tag(void)\n \n \t/* tag payload/message */\n \tread_next_command();\n-\tmsg = cmd_data(&msglen);\n+\tcmd_data(&msg);\n \n \t/* build the tag object */\n-\tsize_dbuf(&new_data, 67+strlen(t->name)+strlen(tagger)+msglen);\n-\tsp = new_data.buffer;\n-\tsp += sprintf(sp, \"object %s\\n\", sha1_to_hex(sha1));\n-\tsp += sprintf(sp, \"type %s\\n\", commit_type);\n-\tsp += sprintf(sp, \"tag %s\\n\", t->name);\n-\tsp += sprintf(sp, \"tagger %s\\n\", tagger);\n-\t*sp++ = '\\n';\n-\tmemcpy(sp, msg, msglen);\n-\tsp += msglen;\n+\tstrbuf_reset(&new_data);\n+\tstrbuf_addf(&new_data,\n+\t\t\"object %s\\n\"\n+\t\t\"type %s\\n\"\n+\t\t\"tag %s\\n\"\n+\t\t\"tagger %s\\n\"\n+\t\t\"\\n\",\n+\t\tsha1_to_hex(sha1), commit_type, t->name, tagger);\n+\tstrbuf_addbuf(&new_data, &msg);\n \tfree(tagger);\n-\tfree(msg);\n \n-\tif (store_object(OBJ_TAG, new_data.buffer,\n-\t\tsp - (char*)new_data.buffer,\n-\t\tNULL, t->sha1, 0))\n+\tif (store_object(OBJ_TAG, &new_data, NULL, t->sha1, 0))\n \t\tt->pack_id = MAX_PACK_ID;\n \telse\n \t\tt->pack_id = pack_id;\n-- \n1.5.3.1\n"},{"id":"53306","messageId":"20070917125259.2DE83344A4A@madism.org","threadId":"9894","inReplyTo":"20070917125211.GA18176@artemis.corp","subject":"[PATCH 3/3] fast-import optimization:","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-17T12:00:38Z","receivedAt":"2007-09-17T12:00:38Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"Now that cmd_data acts on a strbuf, make last_object stashed buffer be a\nstrbuf as well. On new stash, don't free the last stashed buffer, rather\nswap it with the one you will stash, this way, callers of store_object can\nact on static strbufs, and at some point, fast-import won't allocate new\nmemory for objects buffers.\n---\n fast-import.c |   52 ++++++++++++++++++++--------------------------------\n 1 files changed, 20 insertions(+), 32 deletions(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex e456eab..e2a4834 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -182,11 +182,10 @@ struct mark_set\n \n struct last_object\n {\n-\tvoid *data;\n-\tunsigned long len;\n+\tstruct strbuf data;\n \tuint32_t offset;\n \tunsigned int depth;\n-\tunsigned no_free:1;\n+\tunsigned no_swap : 1;\n };\n \n struct mem_pool\n@@ -310,7 +309,7 @@ static struct mark_set *marks;\n static const char* mark_file;\n \n /* Our last blob */\n-static struct last_object last_blob;\n+static struct last_object last_blob = { STRBUF_INIT, 0, 0, 0 };\n \n /* Tree management */\n static unsigned int tree_entry_alloc = 1000;\n@@ -950,9 +949,7 @@ static void end_packfile(void)\n \tfree(old_p);\n \n \t/* We can't carry a delta across packfiles. */\n-\tfree(last_blob.data);\n-\tlast_blob.data = NULL;\n-\tlast_blob.len = 0;\n+\tstrbuf_release(&last_blob.data);\n \tlast_blob.offset = 0;\n \tlast_blob.depth = 0;\n }\n@@ -1024,8 +1021,8 @@ static int store_object(\n \t\treturn 1;\n \t}\n \n-\tif (last && last->data && last->depth < max_depth) {\n-\t\tdelta = diff_delta(last->data, last->len,\n+\tif (last && last->data.buf && last->depth < max_depth) {\n+\t\tdelta = diff_delta(last->data.buf, last->data.len,\n \t\t\tdat->buf, dat->len,\n \t\t\t&deltalen, 0);\n \t\tif (delta && deltalen >= dat->len) {\n@@ -1111,11 +1108,14 @@ static int store_object(\n \tfree(out);\n \tfree(delta);\n \tif (last) {\n-\t\tif (!last->no_free)\n-\t\t\tfree(last->data);\n+\t\tif (last->no_swap) {\n+\t\t\tlast->data = *dat;\n+\t\t} else {\n+\t\t\tstruct strbuf tmp = *dat;\n+\t\t\t*dat = last->data;\n+\t\t\tlast->data = tmp;\n+\t\t}\n \t\tlast->offset = e->offset;\n-\t\tlast->data = dat->buf;\n-\t\tlast->len = dat->len;\n \t}\n \treturn 0;\n }\n@@ -1242,7 +1242,7 @@ static void store_tree(struct tree_entry *root)\n {\n \tstruct tree_content *t = root->tree;\n \tunsigned int i, j, del;\n-\tstruct last_object lo;\n+\tstruct last_object lo = { STRBUF_INIT, 0, 0, /* no_swap */ 1 };\n \tstruct object_entry *le;\n \n \tif (!is_null_sha1(root->versions[1].sha1))\n@@ -1254,19 +1254,11 @@ static void store_tree(struct tree_entry *root)\n \t}\n \n \tle = find_object(root->versions[0].sha1);\n-\tif (!S_ISDIR(root->versions[0].mode)\n-\t\t|| !le\n-\t\t|| le->pack_id != pack_id) {\n-\t\tlo.data = NULL;\n-\t\tlo.depth = 0;\n-\t\tlo.no_free = 0;\n-\t} else {\n+\tif (S_ISDIR(root->versions[0].mode) && le && le->pack_id == pack_id) {\n \t\tmktree(t, 0, &old_tree);\n-\t\tlo.len  = old_tree.len;\n-\t\tlo.data = old_tree.buf;\n+\t\tlo.data = old_tree;\n \t\tlo.offset = le->offset;\n \t\tlo.depth = t->delta_depth;\n-\t\tlo.no_free = 1;\n \t}\n \n \tmktree(t, 1, &new_tree);\n@@ -1714,14 +1706,12 @@ static char *parse_ident(const char *buf)\n \n static void cmd_new_blob(void)\n {\n-\tstruct strbuf buf;\n+\tstatic struct strbuf buf = STRBUF_INIT;\n \n \tread_next_command();\n \tcmd_mark();\n-\tstrbuf_init(&buf, 0);\n \tcmd_data(&buf);\n-\tif (store_object(OBJ_BLOB, &buf, &last_blob, NULL, next_mark))\n-\t\tstrbuf_release(&buf);\n+\tstore_object(OBJ_BLOB, &buf, &last_blob, NULL, next_mark);\n }\n \n static void unload_one_branch(void)\n@@ -1817,15 +1807,13 @@ static void file_change_m(struct branch *b)\n \t}\n \n \tif (inline_data) {\n-\t\tstruct strbuf buf;\n+\t\tstatic struct strbuf buf = STRBUF_INIT;\n \n \t\tif (!p_uq)\n \t\t\tp = p_uq = xstrdup(p);\n \t\tread_next_command();\n-\t\tstrbuf_init(&buf, 0);\n \t\tcmd_data(&buf);\n-\t\tif (store_object(OBJ_BLOB, &buf, &last_blob, sha1, 0))\n-\t\t\tstrbuf_release(&buf);\n+\t\tstore_object(OBJ_BLOB, &buf, &last_blob, sha1, 0);\n \t} else if (oe) {\n \t\tif (oe->type != OBJ_BLOB)\n \t\t\tdie(\"Not a blob (actually a %s): %s\",\n-- \n1.5.3.1\n"},{"id":"53303","messageId":"20070917125211.GA18176@artemis.corp","threadId":"9894","inReplyTo":null,"subject":"[PATCH 0/3] the return of the strbuf","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-17T12:52:11Z","receivedAt":"2007-09-17T12:52:11Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"  While getting rid of ->eof in strbuf (as it was somehow tasteless). It\nmade me aware of the fact that fast-import.c was using a custom buffer\nimplementation (I think that was the fourth if not the fifth). So here\nis the series that eradicates it.\n\n  Trying to understand fast-import.c code, I happened to remark that it\nwas possible to avoid many reallocations, just by reusing old buffers\nrather than dropping them (this was not possible in a readable way\nbefore, but it is now, and uses the same mechanisms that was garbage\ncollecting buffers, to swap them instead).\n\n  I've not enough stuff to do real-life tests of the old fast-import and\nthe new one, but I wouldn't be surprised that it gives a quite nice\nspeed improvements for tools that use long fast-import batches. If not,\nwell, the code is shorter and more readable, hence it's still a gain.\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"53310","messageId":"20070917133522.GD18176@artemis.corp","threadId":"9894","inReplyTo":"20070917125211.GA18176@artemis.corp","subject":"Re: [PATCH 0/3] the return of the strbuf","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2007-09-17T13:35:22Z","receivedAt":"2007-09-17T13:35:22Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On lun, sep 17, 2007 at 12:52:11 +0000, Pierre Habouzit wrote:\n>   While getting rid of ->eof in strbuf (as it was somehow tasteless). It\n> made me aware of the fact that fast-import.c was using a custom buffer\n> implementation (I think that was the fourth if not the fifth). So here\n> is the series that eradicates it.\n> \n>   Trying to understand fast-import.c code, I happened to remark that it\n> was possible to avoid many reallocations, just by reusing old buffers\n> rather than dropping them (this was not possible in a readable way\n> before, but it is now, and uses the same mechanisms that was garbage\n> collecting buffers, to swap them instead).\n> \n>   I've not enough stuff to do real-life tests of the old fast-import and\n> the new one, but I wouldn't be surprised that it gives a quite nice\n> speed improvements for tools that use long fast-import batches. If not,\n> well, the code is shorter and more readable, hence it's still a gain.\n\nShawn: Johannes makes me remark that you are git-fast-import author,\nhence may want to be Cc-ed of that series, so here is a mail so that you\ndon't miss the thread.\n\n\nThe list: it's often hard to know who you should Cc on a given change,\nI use format.headers to force Junio and git@, but sometimes you want a\ndifferent set of persons. I wonder if this could not be wired in the\nrepository, as a .gitattribute extension ?\n\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"53396","messageId":"20070918035721.GL3099@spearce.org","threadId":"9894","inReplyTo":"20070917133522.GD18176@artemis.corp","subject":"Re: [PATCH 0/3] the return of the strbuf","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-09-18T03:57:21Z","receivedAt":"2007-09-18T03:57:21Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Pierre Habouzit <madcoder@debian.org> wrote:\n> On lun, sep 17, 2007 at 12:52:11 +0000, Pierre Habouzit wrote:\n> >   While getting rid of ->eof in strbuf (as it was somehow tasteless). It\n> > made me aware of the fact that fast-import.c was using a custom buffer\n> > implementation (I think that was the fourth if not the fifth). So here\n> > is the series that eradicates it.\n> \n> Shawn: Johannes makes me remark that you are git-fast-import author,\n> hence may want to be Cc-ed of that series, so here is a mail so that you\n> don't miss the thread.\n\nThanks.  The subject caught my attention.  The patches look good and\nfast-import is usually maintained by me applying them and Junio pulling\nfrom my fast-import tree.  I'm doing that now.\n\nBTW, I haven't thanked you for doing this cleanup work.  It really\nis appreciated.  The code is definately more readable in the end.\nThanks.\n \n> The list: it's often hard to know who you should Cc on a given change,\n> I use format.headers to force Junio and git@, but sometimes you want a\n> different set of persons. I wonder if this could not be wired in the\n> repository, as a .gitattribute extension ?\n\nThe Linux kernel folks were talking about this not too long ago\nand the discussion spilled onto the git list when someone CC'd it\nin the middle of the thread.  If I recall correctly it ended off with\nthis is probably something that a build script should be doing, not\nsomething Git should do natively, as the data is readily available\nfrom tools like git-log.\n\nIndeed in this case if you do:\n\n $ git log --pretty=format:%an --since=6.months.ago -- fast-import.c \\\n      | sort | uniq -c | sort -nr\n  14 Shawn O. Pearce\n   3 Pierre Habouzit\n   3 Junio C Hamano\n   2 Simon Hausmann\n   2 Alex Riesen\n   1 Theodore Ts'o\n   1 Sven Verdoolaege\n   1 Sami Farin\n   1 Nicolas Pitre\n   1 Luiz Fernando N. Capitulino\n   1 Dana L. How\n \nSo you'd probably want to CC me on stuff in that file.  On the other hand\nlooking at something else that's much more important to Git:\n\n  $ git log --pretty=format:%an --since=6.months.ago -- builtin-pack-objects.c \\\n       | sort | uniq -c | sort -nr\n  38 Nicolas Pitre\n  12 Junio C Hamano\n   4 Dana L. How\n   3 Martin Koegler\n   3 Linus Torvalds\n   3 Brian Downing\n   2 Theodore Ts'o\n   2 Dana How\n   1 Luiz Fernando N. Capitulino\n   1 Geert Bosch\n   1 Alex Riesen\n\nI don't think anyone would argue that CC'ing Nico and Junio on all\nsizeable pack-objects changes would be prudent.  Dana too actually\nas he has been active in here recently.  Meanwhile I don't make\nthe 6 month cut.  ;-)\n\nThe other alternative that men with real computing horsepower at\ntheir disposal can ask is through git-blame:\n\n  $ git blame -C -C -w --porcelain builtin-pack-objects.c | grep 'author ' \\\n       | sort | uniq -c | sort -nr\n  52 author Nicolas Pitre\n  39 author Junio C Hamano\n  22 author Linus Torvalds\n   6 author Shawn O. Pearce\n   6 author Dana L. How\n   3 author Martin Koegler\n  ...\n\nAgain Nico scores very high (52 commits surviving in current `next`)\nbut so does Junio and Linus.  The output of git-blame may actually\nbe a better indicator of who Junio likes to CC when changes are\nmade in this module.\n\nDoing something like this automatically based on the filepaths shown\nby `git diff --name-only $cmit^ $cmt` could be expensive in terms\nof CPU time, and might offer little gain for an old hand who knows\nwhere the maintainer boundaries tend to be, but it does really help\nsomeone who is newer to the project and might not know who is the\nbest person to talk to.\n\n-- \nShawn.\n"},{"id":"53410","messageId":"7vzlzkwgnh.fsf@gitster.siamese.dyndns.org","threadId":"9894","inReplyTo":"20070917125211.GA18176@artemis.corp","subject":"Re: [PATCH 0/3] the return of the strbuf","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-09-18T07:56:34Z","receivedAt":"2007-09-18T07:56:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thanks, will queue in 'pu' and hopefully soon move to 'next'.\n"},{"id":"53639","messageId":"Pine.LNX.4.64.0709201248400.28395@racer.site","threadId":"9894","inReplyTo":"20070918035721.GL3099@spearce.org","subject":"Re: [PATCH 0/3] the return of the strbuf","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-09-20T11:49:30Z","receivedAt":"2007-09-20T11:49:30Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 17 Sep 2007, Shawn O. Pearce wrote:\n\n\n>  $ git log --pretty=format:%an --since=6.months.ago -- fast-import.c \\\n>       | sort | uniq -c | sort -nr\n>   14 Shawn O. Pearce\n>    3 Pierre Habouzit\n>    3 Junio C Hamano\n>    2 Simon Hausmann\n>    2 Alex Riesen\n>    1 Theodore Ts'o\n>    1 Sven Verdoolaege\n>    1 Sami Farin\n>    1 Nicolas Pitre\n>    1 Luiz Fernando N. Capitulino\n>    1 Dana L. How\n\nFWIW I'd do\n\ngit shortlog -n --since=6.months.ago HEAD -- fast-import.c|grep \"^[A-Z]\"\n\ninstead...\n\nCiao,\nDscho\n"},{"id":"53652","messageId":"20070920141906.GR3099@spearce.org","threadId":"9894","inReplyTo":"Pine.LNX.4.64.0709201248400.28395@racer.site","subject":"Re: [PATCH 0/3] the return of the strbuf","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-09-20T14:19:06Z","receivedAt":"2007-09-20T14:19:06Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> On Mon, 17 Sep 2007, Shawn O. Pearce wrote:\n> \n> >  $ git log --pretty=format:%an --since=6.months.ago -- fast-import.c \\\n> >       | sort | uniq -c | sort -nr\n...\n> FWIW I'd do\n> \n> git shortlog -n --since=6.months.ago HEAD -- fast-import.c|grep \"^[A-Z]\"\n> \n> instead...\n\nYea, Junio pointed out how stupid I was being on #git.  I don't\nknow why I didn't think of using shortlog here as this is one\nof the things it was built for.  Whatever.  I forgot my git-fu\non Monday.  :)\n\n-- \nShawn.\n"},{"id":"53677","messageId":"7v1wctkoao.fsf@gitster.siamese.dyndns.org","threadId":"9894","inReplyTo":"Pine.LNX.4.64.0709201248400.28395@racer.site","subject":"Re: [PATCH 0/3] the return of the strbuf","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-09-20T21:41:19Z","receivedAt":"2007-09-20T21:41:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> On Mon, 17 Sep 2007, Shawn O. Pearce wrote:\n>\n>>  $ git log --pretty=format:%an --since=6.months.ago -- fast-import.c \\\n>>       | sort | uniq -c | sort -nr\n>>   14 Shawn O. Pearce\n>>    3 Pierre Habouzit\n>>    3 Junio C Hamano\n>>    2 Simon Hausmann\n>>    2 Alex Riesen\n>>    1 Theodore Ts'o\n>>    1 Sven Verdoolaege\n>>    1 Sami Farin\n>>    1 Nicolas Pitre\n>>    1 Luiz Fernando N. Capitulino\n>>    1 Dana L. How\n>\n> FWIW I'd do\n>\n> git shortlog -n --since=6.months.ago HEAD -- fast-import.c|grep \"^[A-Z]\"\n>\n> instead...\n\nI am sure you certainly meant a single command without grep, like:\n\n\t$ git shortlog -n -s --since=6.months.ago HEAD -- fast-import.c\n"},{"id":"53681","messageId":"Pine.LNX.4.64.0709202252070.28395@racer.site","threadId":"9894","inReplyTo":"7v1wctkoao.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 0/3] the return of the strbuf","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-09-20T21:52:33Z","receivedAt":"2007-09-20T21:52:33Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 20 Sep 2007, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > On Mon, 17 Sep 2007, Shawn O. Pearce wrote:\n> >\n> >>  $ git log --pretty=format:%an --since=6.months.ago -- fast-import.c \\\n> >>       | sort | uniq -c | sort -nr\n> >>   14 Shawn O. Pearce\n> >>    3 Pierre Habouzit\n> >>    3 Junio C Hamano\n> >>    2 Simon Hausmann\n> >>    2 Alex Riesen\n> >>    1 Theodore Ts'o\n> >>    1 Sven Verdoolaege\n> >>    1 Sami Farin\n> >>    1 Nicolas Pitre\n> >>    1 Luiz Fernando N. Capitulino\n> >>    1 Dana L. How\n> >\n> > FWIW I'd do\n> >\n> > git shortlog -n --since=6.months.ago HEAD -- fast-import.c|grep \"^[A-Z]\"\n> >\n> > instead...\n> \n> I am sure you certainly meant a single command without grep, like:\n> \n> \t$ git shortlog -n -s --since=6.months.ago HEAD -- fast-import.c\n\nHehe.  I said \"I'd do\" ;-)\n\nThanks,\nDscho\n"}]}