{"thread":{"id":"36306","subject":"[PATCH 00/10] [RFC] pickaxe for function names","startedAt":"2014-03-27T18:50:46Z","lastAt":"2014-04-28T20:04:40Z","messageCount":23,"participants":["David A. Dalrymple (and Bhushan G. Lodha)","Jeff King","Eric Sunshine","Johannes Sixt","René Scharfe","Junio C Hamano","Jakub Narębski","Bhushan Lodha"],"isPatch":true,"patchVersion":1,"patchTotal":10},"messages":[{"id":"237928","messageId":"1395946256-67124-1-git-send-email-dad-bgl@mit.edu","threadId":"36306","inReplyTo":null,"subject":"[PATCH 00/10] [RFC] pickaxe for function names","fromName":"David A. Dalrymple (and Bhushan G. Lodha)","fromEmail":"dad-bgl@mit.edu","sentAt":"2014-03-27T18:50:46Z","receivedAt":"2014-03-27T18:50:46Z","isPatch":true,"sender":{"key":"dad-bgl@mit.edu","avatar":null},"body":"This series introduces a --function-name=<pattern> option for git-log, intended\nto search for commits which touch a function matching a certain pattern (a\nfeature we've seen requested and are interested in using ourselves).\n\nThis is our first attempt to patch git; we've tried to observe and follow the\ncommunity standards, but we would greatly appreciate feedback. We've been\nworking on this for a few weeks, and I just noticed that René Scharfe has done\nconflicing (and better) refactoring work in diffcore-pickaxe.c a few days ago.\nWe'd be happy to rebase our changes and resolve the conflicts once René's\npatches are committed to master, but we thought we may as well ask for comments\non the version we have working now.\n\nThanks for your time!\n\n  .gitattributes: specify the language used\n  diffcore-pickaxe.c: refactor regex compilation\n  diffcore-pickaxe.c: Refactor pickaxe_fn signature\n  diff.c/diff.h: expose userdiff_funcname\n  diffcore-pickaxe.c: set up funcname pattern\n  log: --function-name pickaxe\n  xdiff: add XDL_EMIT_MOREFUNCNAMES to try harder\n  xdiff: add XDL_EMIT_MOREHUNKHEADS to split hunks\n  t4213: test --function-name option\n  Documentation: Document --function-name usage\n\n .gitattributes                 |   2 +-\n Documentation/diff-options.txt |   9 +++\n Documentation/gitdiffcore.txt  |  17 ++++-\n builtin/log.c                  |   2 +-\n diff.c                         |  13 +++-\n diff.h                         |   3 +\n diffcore-pickaxe.c             | 162 +++++++++++++++++++++++++++++++++++-----------\n revision.c                     |   3 +-\n t/t4213-log-function-name.sh   |  73 +++++++++++++++++++++\n xdiff/xdiff.h                  |   2 +\n xdiff/xdiffi.c                 |   2 +-\n xdiff/xemit.c                  |  99 ++++++++++++++++++++++------\n xdiff/xemit.h                  |   4 +-\n 13 files changed, 323 insertions(+), 68 deletions(-)\n"},{"id":"237929","messageId":"a833f392bebae7a2441d0a6e81a1c6dc52fa682e.1395942768.git.davidad@alum.mit.edu","threadId":"36306","inReplyTo":"1395946256-67124-1-git-send-email-dad-bgl@mit.edu","subject":"[PATCH 01/10] .gitattributes: specify the language used","fromName":"David A. Dalrymple (and Bhushan G. Lodha)","fromEmail":"dad-bgl@mit.edu","sentAt":"2014-03-27T18:50:47Z","receivedAt":"2014-03-27T18:50:47Z","isPatch":true,"sender":{"key":"dad-bgl@mit.edu","avatar":null},"body":"From: \"Bhushan G. Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n\nSince git can intelligently emit diff hunk headers based on the\nprogramming language of each file, assuming that the language is\nspecified in .gitattributes, it makes sense to specify our own\nlanguage (cpp) in our own .gitattributes file.\n\nSigned-off-by: David Dalrymple (on zayin) <davidad@alum.mit.edu>\n---\n .gitattributes | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/.gitattributes b/.gitattributes\nindex 5e98806..320e33c 100644\n--- a/.gitattributes\n+++ b/.gitattributes\n@@ -1,3 +1,3 @@\n * whitespace=!indent,trail,space\n-*.[ch] whitespace=indent,trail,space\n+*.[ch] whitespace=indent,trail,space diff=cpp\n *.sh whitespace=indent,trail,space\n-- \n1.7.12.4 (Apple Git-37)\n"},{"id":"237930","messageId":"36cbd6934df8cf17a52a4478aa4e2da436feaf0b.1395942768.git.davidad@alum.mit.edu","threadId":"36306","inReplyTo":"1395946256-67124-1-git-send-email-dad-bgl@mit.edu","subject":"[PATCH 02/10] diffcore-pickaxe.c: refactor regex compilation","fromName":"David A. Dalrymple (and Bhushan G. Lodha)","fromEmail":"dad-bgl@mit.edu","sentAt":"2014-03-27T18:50:48Z","receivedAt":"2014-03-27T18:50:48Z","isPatch":true,"sender":{"key":"dad-bgl@mit.edu","avatar":null},"body":"From: \"Bhushan G. Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n\nIn this file, two functions use identical blocks of code to call the\nPOSIX regex compiling function and handle a possible error. Here we\nfactor that block into its own function, in anticipation of using the\nsame code a third time.\n\nSigned-off-by: David Dalrymple (on zayin) <davidad@alum.mit.edu>\n---\n diffcore-pickaxe.c | 33 ++++++++++++++++-----------------\n 1 file changed, 16 insertions(+), 17 deletions(-)\n\ndiff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c\nindex 401eb72..0d36a3c 100644\n--- a/diffcore-pickaxe.c\n+++ b/diffcore-pickaxe.c\n@@ -12,6 +12,8 @@ typedef int (*pickaxe_fn)(mmfile_t *one, mmfile_t *two,\n \t\t\t  struct diff_options *o,\n \t\t\t  regex_t *regexp, kwset_t kws);\n \n+static void compile_regex(regex_t *r, const char *s, int cflags);\n+\n static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,\n \t\t\t regex_t *regexp, kwset_t kws, pickaxe_fn fn);\n \n@@ -110,20 +112,13 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,\n \n static void diffcore_pickaxe_grep(struct diff_options *o)\n {\n-\tint err;\n \tregex_t regex;\n \tint cflags = REG_EXTENDED | REG_NEWLINE;\n \n \tif (DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE))\n \t\tcflags |= REG_ICASE;\n \n-\terr = regcomp(&regex, o->pickaxe, cflags);\n-\tif (err) {\n-\t\tchar errbuf[1024];\n-\t\tregerror(err, &regex, errbuf, 1024);\n-\t\tregfree(&regex);\n-\t\tdie(\"invalid regex: %s\", errbuf);\n-\t}\n+\tcompile_regex(&regex, o->pickaxe, cflags);\n \n \tpickaxe(&diff_queued_diff, o, &regex, NULL, diff_grep);\n \n@@ -180,6 +175,18 @@ static int has_changes(mmfile_t *one, mmfile_t *two,\n \treturn one_contains != two_contains;\n }\n \n+static void compile_regex(regex_t *r, const char *s, int cflags)\n+{\n+\tint err;\n+\terr = regcomp(r, s, cflags);\n+\tif (err) {\n+\t\tchar errbuf[1024];\n+\t\tregerror(err, r, errbuf, 1024);\n+\t\tregfree(r);\n+\t\tdie(\"invalid regex: %s\", errbuf);\n+\t}\n+}\n+\n static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,\n \t\t\t regex_t *regexp, kwset_t kws, pickaxe_fn fn)\n {\n@@ -236,15 +243,7 @@ static void diffcore_pickaxe_count(struct diff_options *o)\n \tkwset_t kws = NULL;\n \n \tif (opts & DIFF_PICKAXE_REGEX) {\n-\t\tint err;\n-\t\terr = regcomp(&regex, needle, REG_EXTENDED | REG_NEWLINE);\n-\t\tif (err) {\n-\t\t\t/* The POSIX.2 people are surely sick */\n-\t\t\tchar errbuf[1024];\n-\t\t\tregerror(err, &regex, errbuf, 1024);\n-\t\t\tregfree(&regex);\n-\t\t\tdie(\"invalid regex: %s\", errbuf);\n-\t\t}\n+\t\tcompile_regex(&regex, needle, REG_EXTENDED | REG_NEWLINE);\n \t\tregexp = &regex;\n \t} else {\n \t\tkws = kwsalloc(DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE)\n-- \n1.7.12.4 (Apple Git-37)\n"},{"id":"237938","messageId":"6822f9d947ffb589df25537e2c1e7c4ead7656b0.1395942768.git.davidad@alum.mit.edu","threadId":"36306","inReplyTo":"1395946256-67124-1-git-send-email-dad-bgl@mit.edu","subject":"[PATCH 03/10] diffcore-pickaxe.c: Refactor pickaxe_fn signature","fromName":"David A. Dalrymple (and Bhushan G. Lodha)","fromEmail":"dad-bgl@mit.edu","sentAt":"2014-03-27T18:50:49Z","receivedAt":"2014-03-27T18:50:49Z","isPatch":true,"sender":{"key":"dad-bgl@mit.edu","avatar":null},"body":"From: \"Bhushan G. Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n\nThis function type previously accepted separate regex_t and kwset_t\nparameters, which conceptually go together. Here we create a struct to\nencapsulate them, in anticipation of adding a third field that\npickaxe_fn's may require.\n\nThis parallels the existing diffgrep_cb structure for passing possibly\nrelevant values through to the callbacks invoked by xdi_diff_outf.\n\nSigned-off-by: David Dalrymple (on zayin) <davidad@alum.mit.edu>\n---\n diffcore-pickaxe.c | 50 ++++++++++++++++++++++++++++++--------------------\n 1 file changed, 30 insertions(+), 20 deletions(-)\n\ndiff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c\nindex 0d36a3c..7e65095 100644\n--- a/diffcore-pickaxe.c\n+++ b/diffcore-pickaxe.c\n@@ -8,17 +8,22 @@\n #include \"xdiff-interface.h\"\n #include \"kwset.h\"\n \n+struct fn_options {\n+\tregex_t *regex;\n+\tkwset_t kws;\n+};\n+\n typedef int (*pickaxe_fn)(mmfile_t *one, mmfile_t *two,\n \t\t\t  struct diff_options *o,\n-\t\t\t  regex_t *regexp, kwset_t kws);\n+\t\t\t  struct fn_options *fno);\n \n static void compile_regex(regex_t *r, const char *s, int cflags);\n \n static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,\n-\t\t\t regex_t *regexp, kwset_t kws, pickaxe_fn fn);\n+\t\t\t pickaxe_fn fn, struct fn_options *fno);\n \n static void pickaxe(struct diff_queue_struct *q, struct diff_options *o,\n-\t\t    regex_t *regexp, kwset_t kws, pickaxe_fn fn)\n+\t\t    pickaxe_fn fn, struct fn_options *fno)\n {\n \tint i;\n \tstruct diff_queue_struct outq;\n@@ -29,7 +34,7 @@ static void pickaxe(struct diff_queue_struct *q, struct diff_options *o,\n \t\t/* Showing the whole changeset if needle exists */\n \t\tfor (i = 0; i < q->nr; i++) {\n \t\t\tstruct diff_filepair *p = q->queue[i];\n-\t\t\tif (pickaxe_match(p, o, regexp, kws, fn))\n+\t\t\tif (pickaxe_match(p, o, fn, fno))\n \t\t\t\treturn; /* do not munge the queue */\n \t\t}\n \n@@ -44,7 +49,7 @@ static void pickaxe(struct diff_queue_struct *q, struct diff_options *o,\n \t\t/* Showing only the filepairs that has the needle */\n \t\tfor (i = 0; i < q->nr; i++) {\n \t\t\tstruct diff_filepair *p = q->queue[i];\n-\t\t\tif (pickaxe_match(p, o, regexp, kws, fn))\n+\t\t\tif (pickaxe_match(p, o, fn, fno))\n \t\t\t\tdiff_q(&outq, p);\n \t\t\telse\n \t\t\t\tdiff_free_filepair(p);\n@@ -83,7 +88,7 @@ static void diffgrep_consume(void *priv, char *line, unsigned long len)\n \n static int diff_grep(mmfile_t *one, mmfile_t *two,\n \t\t     struct diff_options *o,\n-\t\t     regex_t *regexp, kwset_t kws)\n+\t\t     struct fn_options *fno)\n {\n \tregmatch_t regmatch;\n \tstruct diffgrep_cb ecbdata;\n@@ -91,9 +96,9 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,\n \txdemitconf_t xecfg;\n \n \tif (!one)\n-\t\treturn !regexec(regexp, two->ptr, 1, &regmatch, 0);\n+\t\treturn !regexec(fno->regex, two->ptr, 1, &regmatch, 0);\n \tif (!two)\n-\t\treturn !regexec(regexp, one->ptr, 1, &regmatch, 0);\n+\t\treturn !regexec(fno->regex, one->ptr, 1, &regmatch, 0);\n \n \t/*\n \t * We have both sides; need to run textual diff and see if\n@@ -101,7 +106,7 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,\n \t */\n \tmemset(&xpp, 0, sizeof(xpp));\n \tmemset(&xecfg, 0, sizeof(xecfg));\n-\tecbdata.regexp = regexp;\n+\tecbdata.regexp = fno->regex;\n \tecbdata.hit = 0;\n \txecfg.ctxlen = o->context;\n \txecfg.interhunkctxlen = o->interhunkcontext;\n@@ -113,6 +118,7 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,\n static void diffcore_pickaxe_grep(struct diff_options *o)\n {\n \tregex_t regex;\n+\tstruct fn_options fno;\n \tint cflags = REG_EXTENDED | REG_NEWLINE;\n \n \tif (DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE))\n@@ -120,13 +126,14 @@ static void diffcore_pickaxe_grep(struct diff_options *o)\n \n \tcompile_regex(&regex, o->pickaxe, cflags);\n \n-\tpickaxe(&diff_queued_diff, o, &regex, NULL, diff_grep);\n+\tfno.regex = &regex;\n+\tpickaxe(&diff_queued_diff, o, diff_grep, &fno);\n \n \tregfree(&regex);\n \treturn;\n }\n \n-static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws)\n+static unsigned int contains(mmfile_t *mf, struct fn_options *fno)\n {\n \tunsigned int cnt;\n \tunsigned long sz;\n@@ -136,12 +143,12 @@ static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws)\n \tdata = mf->ptr;\n \tcnt = 0;\n \n-\tif (regexp) {\n+\tif (fno->regex) {\n \t\tregmatch_t regmatch;\n \t\tint flags = 0;\n \n \t\tassert(data[sz] == '\\0');\n-\t\twhile (*data && !regexec(regexp, data, 1, &regmatch, flags)) {\n+\t\twhile (*data && !regexec(fno->regex, data, 1, &regmatch, flags)) {\n \t\t\tflags |= REG_NOTBOL;\n \t\t\tdata += regmatch.rm_eo;\n \t\t\tif (*data && regmatch.rm_so == regmatch.rm_eo)\n@@ -152,7 +159,7 @@ static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws)\n \t} else { /* Classic exact string match */\n \t\twhile (sz) {\n \t\t\tstruct kwsmatch kwsm;\n-\t\t\tsize_t offset = kwsexec(kws, data, sz, &kwsm);\n+\t\t\tsize_t offset = kwsexec(fno->kws, data, sz, &kwsm);\n \t\t\tconst char *found;\n \t\t\tif (offset == -1)\n \t\t\t\tbreak;\n@@ -168,10 +175,10 @@ static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws)\n \n static int has_changes(mmfile_t *one, mmfile_t *two,\n \t\t       struct diff_options *o,\n-\t\t       regex_t *regexp, kwset_t kws)\n+\t\t       struct fn_options *fno)\n {\n-\tunsigned int one_contains = one ? contains(one, regexp, kws) : 0;\n-\tunsigned int two_contains = two ? contains(two, regexp, kws) : 0;\n+\tunsigned int one_contains = one ? contains(one, fno) : 0;\n+\tunsigned int two_contains = two ? contains(two, fno) : 0;\n \treturn one_contains != two_contains;\n }\n \n@@ -188,7 +195,7 @@ static void compile_regex(regex_t *r, const char *s, int cflags)\n }\n \n static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,\n-\t\t\t regex_t *regexp, kwset_t kws, pickaxe_fn fn)\n+\t\t\t pickaxe_fn fn, struct fn_options *fno)\n {\n \tstruct userdiff_driver *textconv_one = NULL;\n \tstruct userdiff_driver *textconv_two = NULL;\n@@ -222,7 +229,7 @@ static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,\n \n \tret = fn(DIFF_FILE_VALID(p->one) ? &mf1 : NULL,\n \t\t DIFF_FILE_VALID(p->two) ? &mf2 : NULL,\n-\t\t o, regexp, kws);\n+\t\t o, fno);\n \n \tif (textconv_one)\n \t\tfree(mf1.ptr);\n@@ -236,6 +243,7 @@ static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,\n \n static void diffcore_pickaxe_count(struct diff_options *o)\n {\n+\tstruct fn_options fno;\n \tconst char *needle = o->pickaxe;\n \tint opts = o->pickaxe_opts;\n \tunsigned long len = strlen(needle);\n@@ -252,7 +260,9 @@ static void diffcore_pickaxe_count(struct diff_options *o)\n \t\tkwsprep(kws);\n \t}\n \n-\tpickaxe(&diff_queued_diff, o, regexp, kws, has_changes);\n+\tfno.regex = regexp;\n+\tfno.kws = kws;\n+\tpickaxe(&diff_queued_diff, o, has_changes, &fno);\n \n \tif (opts & DIFF_PICKAXE_REGEX)\n \t\tregfree(&regex);\n-- \n1.7.12.4 (Apple Git-37)\n"},{"id":"237931","messageId":"72e13d200ede2908cb5d9780a6a2b478b568c2fb.1395942768.git.davidad@alum.mit.edu","threadId":"36306","inReplyTo":"1395946256-67124-1-git-send-email-dad-bgl@mit.edu","subject":"[PATCH 04/10] diff.c/diff.h: expose userdiff_funcname","fromName":"David A. Dalrymple (and Bhushan G. Lodha)","fromEmail":"dad-bgl@mit.edu","sentAt":"2014-03-27T18:50:50Z","receivedAt":"2014-03-27T18:50:50Z","isPatch":true,"sender":{"key":"dad-bgl@mit.edu","avatar":null},"body":"From: \"Bhushan G. Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n\nThe functionality of userdiff_funcname (determining the language in use\nfor a given file and setting up patterns to match \"function names\" in\nthat language) is useful outside of diff.c, so here we remove its static\nspecifier and declare it in diff.h.\n\nSigned-off-by: David Dalrymple (on zayin) <davidad@alum.mit.edu>\n---\n diff.c | 2 +-\n diff.h | 2 ++\n 2 files changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/diff.c b/diff.c\nindex e343191..f978ee7 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2203,7 +2203,7 @@ int diff_filespec_is_binary(struct diff_filespec *one)\n \treturn one->is_binary;\n }\n \n-static const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespec *one)\n+const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespec *one)\n {\n \tdiff_filespec_load_driver(one);\n \treturn one->driver->funcname.pattern ? &one->driver->funcname : NULL;\ndiff --git a/diff.h b/diff.h\nindex a24a767..9e96fc9 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -349,4 +349,6 @@ extern int print_stat_summary(FILE *fp, int files,\n \t\t\t      int insertions, int deletions);\n extern void setup_diff_pager(struct diff_options *);\n \n+const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespec *);\n+\n #endif /* DIFF_H */\n-- \n1.7.12.4 (Apple Git-37)\n"},{"id":"237933","messageId":"d284b297c4ac277f883b9468755d24adcd82830b.1395942768.git.davidad@alum.mit.edu","threadId":"36306","inReplyTo":"1395946256-67124-1-git-send-email-dad-bgl@mit.edu","subject":"[PATCH 05/10] diffcore-pickaxe.c: set up funcname pattern","fromName":"David A. Dalrymple (and Bhushan G. Lodha)","fromEmail":"dad-bgl@mit.edu","sentAt":"2014-03-27T18:50:51Z","receivedAt":"2014-03-27T18:50:51Z","isPatch":true,"sender":{"key":"dad-bgl@mit.edu","avatar":null},"body":"From: \"Bhushan G. Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n\nWe use userdiff_funcname to make the filetype-dependent function name\npattern available to pickaxe functions.\n\nSigned-off-by: David Dalrymple (on zayin) <davidad@alum.mit.edu>\n---\n diffcore-pickaxe.c | 9 +++++++++\n 1 file changed, 9 insertions(+)\n\ndiff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c\nindex 7e65095..103fe6c 100644\n--- a/diffcore-pickaxe.c\n+++ b/diffcore-pickaxe.c\n@@ -7,10 +7,12 @@\n #include \"diffcore.h\"\n #include \"xdiff-interface.h\"\n #include \"kwset.h\"\n+#include \"userdiff.h\"\n \n struct fn_options {\n \tregex_t *regex;\n \tkwset_t kws;\n+\tconst struct userdiff_funcname *funcname_pattern;\n };\n \n typedef int (*pickaxe_fn)(mmfile_t *one, mmfile_t *two,\n@@ -224,6 +226,13 @@ static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,\n \tif (textconv_one == textconv_two && diff_unmodified_pair(p))\n \t\treturn 0;\n \n+\tconst struct userdiff_funcname *funcname_pattern;\n+\tfuncname_pattern = diff_funcname_pattern(p->one);\n+\tif (!funcname_pattern)\n+\t\tfuncname_pattern = diff_funcname_pattern(p->two);\n+\n+\tfno->funcname_pattern = funcname_pattern;\n+\n \tmf1.size = fill_textconv(textconv_one, p->one, &mf1.ptr);\n \tmf2.size = fill_textconv(textconv_two, p->two, &mf2.ptr);\n \n-- \n1.7.12.4 (Apple Git-37)\n"},{"id":"237937","messageId":"62ab0f9c34eabe020ae99c7c1f69d580d9bb36d8.1395942768.git.davidad@alum.mit.edu","threadId":"36306","inReplyTo":"1395946256-67124-1-git-send-email-dad-bgl@mit.edu","subject":"[PATCH 06/10] log: --function-name pickaxe","fromName":"David A. Dalrymple (and Bhushan G. Lodha)","fromEmail":"dad-bgl@mit.edu","sentAt":"2014-03-27T18:50:52Z","receivedAt":"2014-03-27T18:50:52Z","isPatch":true,"sender":{"key":"dad-bgl@mit.edu","avatar":null},"body":"From: \"Bhushan G. Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n\nThis is similar to the pickaxe grep option (-G), but applies the\nprovided regex only to diff hunk headers, thereby showing only those\ncommits which affect a \"function\" with a definition line matching the\npattern. These are \"functions\" in the same sense as with\n--function-context, i.e., they may be classes, structs, etc. depending\non the programming-language-specific pattern specified by the \"diff\"\nattribute in .gitattributes.\n\nbuiltin/log.c:\n\tas with pickaxe, set always_show_header when using --function-name\ndiff.c:\n\tparse option; as with pickaxe, always set the RECURSIVE option\n\tfor --function-name\ndiff.h:\n\tinclude \"funcname\" field in struct diff_options\ndiffcore-pickaxe.c:\n\timplementation of --function-name filtering (diffcore_funcname), like\n\tthe existing diffcore_pickaxe_grep and diffcore_pickaxe_count\nrevision.c:\n\tas with pickaxe, set revs->diff to always generate diffs when\n\tusing --function-name\n\nSigned-off-by: David Dalrymple (on zayin) <davidad@alum.mit.edu>\n---\n builtin/log.c      |  2 +-\n diff.c             |  8 +++++--\n diff.h             |  1 +\n diffcore-pickaxe.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++--\n revision.c         |  3 ++-\n 5 files changed, 77 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex b97373d..78694de 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -158,7 +158,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,\n \tif (rev->show_notes)\n \t\tinit_display_notes(&rev->notes_opt);\n \n-\tif (rev->diffopt.pickaxe || rev->diffopt.filter)\n+\tif (rev->diffopt.pickaxe || rev->diffopt.filter || rev->diffopt.funcname)\n \t\trev->always_show_header = 0;\n \tif (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) {\n \t\trev->always_show_header = 0;\ndiff --git a/diff.c b/diff.c\nindex f978ee7..2f6dbc1 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -3298,7 +3298,7 @@ void diff_setup_done(struct diff_options *options)\n \t/*\n \t * Also pickaxe would not work very well if you do not say recursive\n \t */\n-\tif (options->pickaxe)\n+\tif (options->pickaxe || options->funcname)\n \t\tDIFF_OPT_SET(options, RECURSIVE);\n \t/*\n \t * When patches are generated, submodules diffed against the work tree\n@@ -3821,6 +3821,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)\n \t\toptions->orderfile = optarg;\n \t\treturn argcount;\n \t}\n+\telse if ((argcount = parse_long_opt(\"function-name\", av, &optarg))) {\n+\t\toptions->funcname = optarg;\n+\t\treturn argcount;\n+\t}\n \telse if ((argcount = parse_long_opt(\"diff-filter\", av, &optarg))) {\n \t\tint offending = parse_diff_filter_opt(optarg, options);\n \t\tif (offending)\n@@ -4768,7 +4772,7 @@ void diffcore_std(struct diff_options *options)\n \t\tif (options->break_opt != -1)\n \t\t\tdiffcore_merge_broken();\n \t}\n-\tif (options->pickaxe)\n+\tif (options->pickaxe || options->funcname)\n \t\tdiffcore_pickaxe(options);\n \tif (options->orderfile)\n \t\tdiffcore_order(options->orderfile);\ndiff --git a/diff.h b/diff.h\nindex 9e96fc9..0fd5f1d 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -107,6 +107,7 @@ enum diff_words_type {\n struct diff_options {\n \tconst char *orderfile;\n \tconst char *pickaxe;\n+\tconst char *funcname;\n \tconst char *single_follow;\n \tconst char *a_prefix, *b_prefix;\n \tunsigned flags;\ndiff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c\nindex 103fe6c..259a8fa 100644\n--- a/diffcore-pickaxe.c\n+++ b/diffcore-pickaxe.c\n@@ -67,6 +67,12 @@ struct diffgrep_cb {\n \tint hit;\n };\n \n+struct funcname_cb {\n+\tstruct userdiff_funcname *pattern;\n+\tregex_t *regex;\n+\tint hit;\n+};\n+\n static void diffgrep_consume(void *priv, char *line, unsigned long len)\n {\n \tstruct diffgrep_cb *data = priv;\n@@ -88,6 +94,20 @@ static void diffgrep_consume(void *priv, char *line, unsigned long len)\n \tline[len] = hold;\n }\n \n+static void match_funcname(void *priv, char *line, unsigned long len)\n+{\n+\tregmatch_t regmatch;\n+\tint hold;\n+\tstruct funcname_cb *data = priv;\n+\thold = line[len];\n+\tline[len] = '\\0';\n+\n+\tif (line[0] == '@' && line[1] == '@')\n+\t\tif (!regexec(data->regex, line, 1, &regmatch, 0))\n+\t\t\tdata->hit = 1;\n+\tline[len] = hold;\n+}\n+\n static int diff_grep(mmfile_t *one, mmfile_t *two,\n \t\t     struct diff_options *o,\n \t\t     struct fn_options *fno)\n@@ -117,6 +137,38 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,\n \treturn ecbdata.hit;\n }\n \n+static int diff_funcname_filter(mmfile_t *one, mmfile_t *two,\n+\t\t\t\tstruct diff_options *o,\n+\t\t\t\tstruct fn_options *fno)\n+{\n+\tstruct funcname_cb ecbdata;\n+\txpparam_t xpp;\n+\txdemitconf_t xecfg;\n+\n+\tmmfile_t empty;\n+\tempty.ptr = \"\";\n+\tempty.size = 0;\n+\tif (!one)\n+\t\tone = &empty;\n+\tif (!two)\n+\t\ttwo = &empty;\n+\tmemset(&xpp, 0, sizeof(xpp));\n+\tmemset(&xecfg, 0, sizeof(xecfg));\n+\tecbdata.regex = fno->regex;\n+\tecbdata.hit = 0;\n+\txecfg.ctxlen = o->context;\n+\n+\tif (fno->funcname_pattern)\n+\t\txdiff_set_find_func(&xecfg, fno->funcname_pattern->pattern,\n+\t\t\t\t\t    fno->funcname_pattern->cflags);\n+\txecfg.interhunkctxlen = o->interhunkcontext;\n+\tif (!(one && two))\n+\t\txecfg.flags = XDL_EMIT_FUNCCONTEXT;\n+\txecfg.flags |= XDL_EMIT_FUNCNAMES;\n+\txdi_diff_outf(one, two, match_funcname, &ecbdata, &xpp, &xecfg);\n+\treturn ecbdata.hit;\n+}\n+\n static void diffcore_pickaxe_grep(struct diff_options *o)\n {\n \tregex_t regex;\n@@ -204,7 +256,7 @@ static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,\n \tmmfile_t mf1, mf2;\n \tint ret;\n \n-\tif (!o->pickaxe[0])\n+\tif (o->pickaxe && !o->pickaxe[0])\n \t\treturn 0;\n \n \t/* ignore unmerged */\n@@ -280,11 +332,24 @@ static void diffcore_pickaxe_count(struct diff_options *o)\n \treturn;\n }\n \n+static void diffcore_funcname(struct diff_options *o)\n+{\n+\tstruct fn_options fno;\n+\tregex_t regex;\n+\n+\tfno.regex = &regex;\n+\tcompile_regex(&regex, o->funcname, REG_EXTENDED | REG_NEWLINE);\n+\tpickaxe(&diff_queued_diff, o, diff_funcname_filter, &fno);\n+\tregfree(&regex);\n+}\n+\n void diffcore_pickaxe(struct diff_options *o)\n {\n+\tif (o->funcname)\n+\t\tdiffcore_funcname(o);\n \t/* Might want to warn when both S and G are on; I don't care... */\n \tif (o->pickaxe_opts & DIFF_PICKAXE_KIND_G)\n \t\tdiffcore_pickaxe_grep(o);\n-\telse\n+\telse if (o-> pickaxe_opts & DIFF_PICKAXE_KIND_S)\n \t\tdiffcore_pickaxe_count(o);\n }\ndiff --git a/revision.c b/revision.c\nindex 8508550..d81d9b9 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2211,8 +2211,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \tif (revs->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT)\n \t\trevs->diff = 1;\n \n-\t/* Pickaxe, diff-filter and rename following need diffs */\n+\t/* Pickaxe, funcname, diff-filter and rename following need diffs */\n \tif (revs->diffopt.pickaxe ||\n+\t    revs->diffopt.funcname ||\n \t    revs->diffopt.filter ||\n \t    DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))\n \t\trevs->diff = 1;\n-- \n1.7.12.4 (Apple Git-37)\n"},{"id":"237936","messageId":"201aa05a9cea6d82b85b44233e7cb02df2c5623a.1395942768.git.davidad@alum.mit.edu","threadId":"36306","inReplyTo":"1395946256-67124-1-git-send-email-dad-bgl@mit.edu","subject":"[PATCH 07/10] xdiff: add XDL_EMIT_MOREFUNCNAMES","fromName":"David A. Dalrymple (and Bhushan G. Lodha)","fromEmail":"dad-bgl@mit.edu","sentAt":"2014-03-27T18:50:53Z","receivedAt":"2014-03-27T18:50:53Z","isPatch":true,"sender":{"key":"dad-bgl@mit.edu","avatar":null},"body":"From: \"Bhushan G. Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n\nFor filtering commits by function name, it's useful to identify the\nfunction name in cases such as adding a new function to a file (where\nthe default functionality will not emit a function name in the hunk\nheader, because it isn't part of the context).\n\nThis adds a flag asking xdiff to be more aggressive in finding function\nnames to emit, and turns the flag on when the --function-name option is\nin use.\n\nSigned-off-by: David Dalrymple (on zayin) <davidad@alum.mit.edu>\n---\n diff.c             |  2 ++\n diffcore-pickaxe.c |  2 +-\n xdiff/xdiff.h      |  1 +\n xdiff/xemit.c      | 39 +++++++++++++++++++++++----------------\n 4 files changed, 27 insertions(+), 17 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 2f6dbc1..914b4a2 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2380,6 +2380,8 @@ static void builtin_diff(const char *name_a,\n \t\txecfg.ctxlen = o->context;\n \t\txecfg.interhunkctxlen = o->interhunkcontext;\n \t\txecfg.flags = XDL_EMIT_FUNCNAMES;\n+\t\tif (o->funcname)\n+\t\t\txecfg.flags |= XDL_EMIT_MOREFUNCNAMES;\n \t\tif (DIFF_OPT_TST(o, FUNCCONTEXT))\n \t\t\txecfg.flags |= XDL_EMIT_FUNCCONTEXT;\n \t\tif (pe)\ndiff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c\nindex 259a8fa..ab31c18 100644\n--- a/diffcore-pickaxe.c\n+++ b/diffcore-pickaxe.c\n@@ -164,7 +164,7 @@ static int diff_funcname_filter(mmfile_t *one, mmfile_t *two,\n \txecfg.interhunkctxlen = o->interhunkcontext;\n \tif (!(one && two))\n \t\txecfg.flags = XDL_EMIT_FUNCCONTEXT;\n-\txecfg.flags |= XDL_EMIT_FUNCNAMES;\n+\txecfg.flags |= XDL_EMIT_FUNCNAMES | XDL_EMIT_MOREFUNCNAMES;\n \txdi_diff_outf(one, two, match_funcname, &ecbdata, &xpp, &xecfg);\n \treturn ecbdata.hit;\n }\ndiff --git a/xdiff/xdiff.h b/xdiff/xdiff.h\nindex c033991..469bded 100644\n--- a/xdiff/xdiff.h\n+++ b/xdiff/xdiff.h\n@@ -44,6 +44,7 @@\n #define XDL_EMIT_FUNCNAMES (1 << 0)\n #define XDL_EMIT_COMMON (1 << 1)\n #define XDL_EMIT_FUNCCONTEXT (1 << 2)\n+#define XDL_EMIT_MOREFUNCNAMES (1 << 3)\n \n #define XDL_MMB_READONLY (1 << 0)\n \ndiff --git a/xdiff/xemit.c b/xdiff/xemit.c\nindex 4266ada..0ddb094 100644\n--- a/xdiff/xemit.c\n+++ b/xdiff/xemit.c\n@@ -23,6 +23,10 @@\n #include \"xinclude.h\"\n \n \n+struct func_line {\n+\tlong len;\n+\tchar buf[80];\n+};\n \n \n static long xdl_get_rec(xdfile_t *xdf, long ri, char const **rec);\n@@ -135,12 +139,7 @@ static int xdl_emit_common(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,\n \treturn 0;\n }\n \n-struct func_line {\n-\tlong len;\n-\tchar buf[80];\n-};\n-\n-static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg,\n+static long get_func_line(xdfile_t *xdf, xdemitconf_t const *xecfg,\n \t\t\t  struct func_line *func_line, long start, long limit)\n {\n \tfind_func_t ff = xecfg->find_func ? xecfg->find_func : def_ff;\n@@ -150,9 +149,9 @@ static long get_func_line(xdfenv_t *xe, xdemitconf_t const *xecfg,\n \tbuf = func_line ? func_line->buf : dummy;\n \tsize = func_line ? sizeof(func_line->buf) : sizeof(dummy);\n \n-\tfor (l = start; l != limit && 0 <= l && l < xe->xdf1.nrec; l += step) {\n+\tfor (l = start; l != limit && 0 <= l && l < xdf->nrec; l += step) {\n \t\tconst char *rec;\n-\t\tlong reclen = xdl_get_rec(&xe->xdf1, l, &rec);\n+\t\tlong reclen = xdl_get_rec(xdf, l, &rec);\n \t\tlong len = ff(rec, reclen, buf, size, xecfg->find_func_priv);\n \t\tif (len >= 0) {\n \t\t\tif (func_line)\n@@ -167,7 +166,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,\n \t\t  xdemitconf_t const *xecfg) {\n \tlong s1, s2, e1, e2, lctx;\n \txdchange_t *xch, *xche;\n-\tlong funclineprev = -1;\n+\tlong funclineprev1 = -1, funclineprev2 = -1;\n \tstruct func_line func_line = { 0 };\n \n \tif (xecfg->flags & XDL_EMIT_COMMON)\n@@ -182,7 +181,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,\n \t\ts2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0);\n \n \t\tif (xecfg->flags & XDL_EMIT_FUNCCONTEXT) {\n-\t\t\tlong fs1 = get_func_line(xe, xecfg, NULL, xch->i1, -1);\n+\t\t\tlong fs1 = get_func_line(&xe->xdf1, xecfg, NULL, xch->i1, -1);\n \t\t\tif (fs1 < 0)\n \t\t\t\tfs1 = 0;\n \t\t\tif (fs1 < s1) {\n@@ -200,7 +199,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,\n \t\te2 = xche->i2 + xche->chg2 + lctx;\n \n \t\tif (xecfg->flags & XDL_EMIT_FUNCCONTEXT) {\n-\t\t\tlong fe1 = get_func_line(xe, xecfg, NULL,\n+\t\t\tlong fe1 = get_func_line(&xe->xdf1, xecfg, NULL,\n \t\t\t\t\t\t xche->i1 + xche->chg1,\n \t\t\t\t\t\t xe->xdf1.nrec);\n \t\t\tif (fe1 < 0)\n@@ -218,7 +217,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,\n \t\t\tif (xche->next) {\n \t\t\t\tlong l = xche->next->i1;\n \t\t\t\tif (l <= e1 ||\n-\t\t\t\t    get_func_line(xe, xecfg, NULL, l, e1) < 0) {\n+\t\t\t\t    get_func_line(&xe->xdf1, xecfg, NULL, l, e1) < 0) {\n \t\t\t\t\txche = xche->next;\n \t\t\t\t\tgoto again;\n \t\t\t\t}\n@@ -229,10 +228,18 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,\n \t\t * Emit current hunk header.\n \t\t */\n \n-\t\tif (xecfg->flags & XDL_EMIT_FUNCNAMES) {\n-\t\t\tget_func_line(xe, xecfg, &func_line,\n-\t\t\t\t      s1 - 1, funclineprev);\n-\t\t\tfunclineprev = s1 - 1;\n+\t\tif (xecfg->flags & XDL_EMIT_MOREFUNCNAMES) {\n+\t\t\tlong fl_in_xch1 = get_func_line(&xe->xdf1, xecfg,\n+\t\t\t\t\t&func_line, xch->i1, xch->i1+xch->chg1);\n+\t\t\tif (fl_in_xch1 < 0) {\n+\t\t\t\tget_func_line(&xe->xdf2, xecfg, &func_line,\n+\t\t\t\t\t      xch->i2, funclineprev2);\n+\t\t\t\tfunclineprev2 = xch->i2;\n+\t\t\t}\n+\t\t} else if (xecfg->flags & XDL_EMIT_FUNCNAMES) {\n+\t\t\tget_func_line(&xe->xdf1, xecfg, &func_line,\n+\t\t\t\t      s1 - 1, funclineprev1);\n+\t\t\tfunclineprev1 = s1 - 1;\n \t\t}\n \t\tif (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2,\n \t\t\t\t      func_line.buf, func_line.len, ecb) < 0)\n-- \n1.7.12.4 (Apple Git-37)\n"},{"id":"237932","messageId":"2c07e06fbb17bfb6d9d51733df0ce5755bbe97f5.1395942768.git.davidad@alum.mit.edu","threadId":"36306","inReplyTo":"1395946256-67124-1-git-send-email-dad-bgl@mit.edu","subject":"[PATCH 08/10] xdiff: add XDL_EMIT_MOREHUNKHEADS","fromName":"David A. Dalrymple (and Bhushan G. Lodha)","fromEmail":"dad-bgl@mit.edu","sentAt":"2014-03-27T18:50:54Z","receivedAt":"2014-03-27T18:50:54Z","isPatch":true,"sender":{"key":"dad-bgl@mit.edu","avatar":null},"body":"From: \"Bhushan G. Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n\nFor filtering by function names, it's useful to split hunks whenever a\nfunction line is encountered, so that each function name being deleted\nor inserted gets its own hunk header (which then can be easily detected\nby the filter).\n\nThis adds a flag, XDL_EMIT_MOREHUNKHEADS, which triggers this\nnonstandard behavior, and enables it only in case the --function-name\noption is being used.\n\nSigned-off-by: David Dalrymple (on zayin) <davidad@alum.mit.edu>\n---\n diff.c             |  3 ++-\n diffcore-pickaxe.c |  3 ++-\n xdiff/xdiff.h      |  1 +\n xdiff/xdiffi.c     |  2 +-\n xdiff/xemit.c      | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++--\n xdiff/xemit.h      |  4 +++-\n 6 files changed, 67 insertions(+), 6 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex 914b4a2..a86206c 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -2381,7 +2381,8 @@ static void builtin_diff(const char *name_a,\n \t\txecfg.interhunkctxlen = o->interhunkcontext;\n \t\txecfg.flags = XDL_EMIT_FUNCNAMES;\n \t\tif (o->funcname)\n-\t\t\txecfg.flags |= XDL_EMIT_MOREFUNCNAMES;\n+\t\t\txecfg.flags |= XDL_EMIT_MOREFUNCNAMES\n+\t\t\t\t    | XDL_EMIT_MOREHUNKHEADS;\n \t\tif (DIFF_OPT_TST(o, FUNCCONTEXT))\n \t\t\txecfg.flags |= XDL_EMIT_FUNCCONTEXT;\n \t\tif (pe)\ndiff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c\nindex ab31c18..d9f4c30 100644\n--- a/diffcore-pickaxe.c\n+++ b/diffcore-pickaxe.c\n@@ -164,7 +164,8 @@ static int diff_funcname_filter(mmfile_t *one, mmfile_t *two,\n \txecfg.interhunkctxlen = o->interhunkcontext;\n \tif (!(one && two))\n \t\txecfg.flags = XDL_EMIT_FUNCCONTEXT;\n-\txecfg.flags |= XDL_EMIT_FUNCNAMES | XDL_EMIT_MOREFUNCNAMES;\n+\txecfg.flags |= XDL_EMIT_FUNCNAMES | XDL_EMIT_MOREFUNCNAMES\n+\t\t    | XDL_EMIT_MOREHUNKHEADS;\n \txdi_diff_outf(one, two, match_funcname, &ecbdata, &xpp, &xecfg);\n \treturn ecbdata.hit;\n }\ndiff --git a/xdiff/xdiff.h b/xdiff/xdiff.h\nindex 469bded..787c376 100644\n--- a/xdiff/xdiff.h\n+++ b/xdiff/xdiff.h\n@@ -45,6 +45,7 @@\n #define XDL_EMIT_COMMON (1 << 1)\n #define XDL_EMIT_FUNCCONTEXT (1 << 2)\n #define XDL_EMIT_MOREFUNCNAMES (1 << 3)\n+#define XDL_EMIT_MOREHUNKHEADS (1 << 4)\n \n #define XDL_MMB_READONLY (1 << 0)\n \ndiff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c\nindex 2358a2d..c29804e 100644\n--- a/xdiff/xdiffi.c\n+++ b/xdiff/xdiffi.c\n@@ -545,7 +545,7 @@ static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,\n \txdchange_t *xch, *xche;\n \n \tfor (xch = xscr; xch; xch = xche->next) {\n-\t\txche = xdl_get_hunk(&xch, xecfg);\n+\t\txche = xdl_get_hunk(xe, &xch, xecfg);\n \t\tif (!xch)\n \t\t\tbreak;\n \t\tif (xecfg->hunk_func(xch->i1, xche->i1 + xche->chg1 - xch->i1,\ndiff --git a/xdiff/xemit.c b/xdiff/xemit.c\nindex 0ddb094..f49eaaf 100644\n--- a/xdiff/xemit.c\n+++ b/xdiff/xemit.c\n@@ -29,6 +29,9 @@ struct func_line {\n };\n \n \n+static long get_func_line(xdfile_t *xdf, xdemitconf_t const *xecfg,\n+\t\t\t  struct func_line *func_line, long start, long limit);\n+\n static long xdl_get_rec(xdfile_t *xdf, long ri, char const **rec);\n static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *ecb);\n \n@@ -62,7 +65,7 @@ static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *\n  * inside the differential hunk according to the specified configuration.\n  * Also advance xscr if the first changes must be discarded.\n  */\n-xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)\n+xdchange_t *xdl_get_hunk(xdfenv_t *xe, xdchange_t **xscr, xdemitconf_t const *xecfg)\n {\n \txdchange_t *xch, *xchp, *lxch;\n \tlong max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen;\n@@ -83,6 +86,59 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)\n \n \tlxch = *xscr;\n \n+\tif (xecfg->flags & XDL_EMIT_MOREHUNKHEADS)\n+\t\tfor (xch = *xscr; xch; xch=xch->next) {\n+\t\t\t/*\n+\t\t\t * If a current change contains a func_line, end this\n+\t\t\t * hunk immediately before and create a new hunk\n+\t\t\t * starting from that line.\n+\t\t\t */\n+\t\t\tlong fl_in_xch1 = get_func_line(&xe->xdf1, xecfg, NULL,\n+\t\t\t\t\t\txch->i1, xch->i1+xch->chg1);\n+\t\t\tlong fl_in_xch2 = get_func_line(&xe->xdf2, xecfg, NULL,\n+\t\t\t\t\t\txch->i2, xch->i2+xch->chg2);\n+\t\t\tif (fl_in_xch1 >= xch->i1 && fl_in_xch2 >= xch->i2) {\n+\t\t\t\txdchange_t *new_next =\n+\t\t\t\t\t(xdchange_t *)xdl_malloc(sizeof(xdchange_t));\n+\t\t\t\tnew_next->i1 = xch->i1+xch->chg1;\n+\t\t\t\tnew_next->chg1 = 0;\n+\t\t\t\tnew_next->i2 = xch->i2;\n+\t\t\t\tnew_next->chg2 = xch->chg2;\n+\t\t\t\tnew_next->ignore = xch->ignore;\n+\t\t\t\tnew_next->next = xch->next;\n+\t\t\t\txch->next = new_next;\n+\t\t\t\txch->chg2 = 0;\n+\t\t\t\treturn xch;\n+\t\t\t}\n+\t\t\tif (fl_in_xch1 > xch->i1) {\n+\t\t\t\txdchange_t *new_next =\n+\t\t\t\t\t(xdchange_t *)xdl_malloc(sizeof(xdchange_t));\n+\t\t\t\tnew_next->i1 = fl_in_xch1;\n+\t\t\t\tnew_next->chg1 = (xch->i1+xch->chg1)-fl_in_xch1;\n+\t\t\t\tnew_next->i2 = xch->i2;\n+\t\t\t\tnew_next->chg2 = xch->chg2;\n+\t\t\t\tnew_next->ignore = xch->ignore;\n+\t\t\t\tnew_next->next = xch->next;\n+\t\t\t\txch->next = new_next;\n+\t\t\t\txch->chg1 = fl_in_xch1 - xch->i1;\n+\t\t\t\txch->chg2 = 0;\n+\t\t\t\treturn xch;\n+\t\t\t}\n+\t\t\tif (fl_in_xch2 > xch->i2) {\n+\t\t\t\txdchange_t *new_next =\n+\t\t\t\t\t(xdchange_t *)xdl_malloc(sizeof(xdchange_t));\n+\t\t\t\tnew_next->i2 = fl_in_xch2;\n+\t\t\t\tnew_next->chg2 = (xch->i2+xch->chg2)-fl_in_xch2;\n+\t\t\t\tnew_next->i1 = xch->i1+xch->chg1;\n+\t\t\t\tnew_next->chg1 = 0;\n+\t\t\t\tnew_next->ignore = xch->ignore;\n+\t\t\t\tnew_next->next = xch->next;\n+\t\t\t\txch->next = new_next;\n+\t\t\t\txch->chg2 = fl_in_xch2 - xch->i2;\n+\t\t\t\treturn xch;\n+\t\t\t}\n+\t\t}\n+\n \tfor (xchp = *xscr, xch = xchp->next; xch; xchp = xch, xch = xch->next) {\n \t\tlong distance = xch->i1 - (xchp->i1 + xchp->chg1);\n \t\tif (distance > max_common)\n@@ -173,7 +229,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,\n \t\treturn xdl_emit_common(xe, xscr, ecb, xecfg);\n \n \tfor (xch = xscr; xch; xch = xche->next) {\n-\t\txche = xdl_get_hunk(&xch, xecfg);\n+\t\txche = xdl_get_hunk(xe, &xch, xecfg);\n \t\tif (!xch)\n \t\t\tbreak;\n \ndiff --git a/xdiff/xemit.h b/xdiff/xemit.h\nindex d297107..4d584f5 100644\n--- a/xdiff/xemit.h\n+++ b/xdiff/xemit.h\n@@ -27,7 +27,9 @@\n typedef int (*emit_func_t)(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,\n \t\t\t   xdemitconf_t const *xecfg);\n \n-xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg);\n+xdchange_t *xdl_get_hunk(xdfenv_t *xe, xdchange_t **xscr,\n+\t\t\t xdemitconf_t const *xecfg);\n+\n int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,\n \t\t  xdemitconf_t const *xecfg);\n \n-- \n1.7.12.4 (Apple Git-37)\n"},{"id":"237934","messageId":"4eb91822043e730bf8a47f12a9129d02f6fc135d.1395942768.git.davidad@alum.mit.edu","threadId":"36306","inReplyTo":"1395946256-67124-1-git-send-email-dad-bgl@mit.edu","subject":"[PATCH 09/10] t4213: test --function-name option","fromName":"David A. Dalrymple (and Bhushan G. Lodha)","fromEmail":"dad-bgl@mit.edu","sentAt":"2014-03-27T18:50:55Z","receivedAt":"2014-03-27T18:50:55Z","isPatch":true,"sender":{"key":"dad-bgl@mit.edu","avatar":null},"body":"From: \"Bhushan G. Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n\nThis test builds a sample C file, adding and removing functions, and\nchecks that the right commits are filtered by --function-name matching.\n\nSigned-off-by: David Dalrymple (on zayin) <davidad@alum.mit.edu>\n---\n t/t4213-log-function-name.sh | 73 ++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 73 insertions(+)\n create mode 100755 t/t4213-log-function-name.sh\n\ndiff --git a/t/t4213-log-function-name.sh b/t/t4213-log-function-name.sh\nnew file mode 100755\nindex 0000000..1243ce5\n--- /dev/null\n+++ b/t/t4213-log-function-name.sh\n@@ -0,0 +1,73 @@\n+#!/bin/sh\n+\n+test_description='log --function-name'\n+. ./test-lib.sh\n+\n+test_expect_success setup '\n+\techo \"* diff=cpp\" > .gitattributes\n+\n+\t>file &&\n+\tgit add file &&\n+\ttest_tick &&\n+\tgit commit -m initial &&\n+\n+\tprintf \"int main(){\\n\\treturn 0;\\n}\\n\" >> file &&\n+\ttest_tick &&\n+\tgit commit -am second\n+\n+\tprintf \"void newfunc(){\\n\\treturn;\\n}\\n\" >> file &&\n+\ttest_tick &&\n+\tgit commit -am third\n+\n+\tprintf \"void newfunc2(){\\n\\treturn;\\n}\\n\" | cat - file > temp &&\n+\tmv temp file &&\n+\ttest_tick &&\n+\tgit commit -am fourth\n+\n+\tprintf \"void newfunc3(){\\n\\treturn;\\n}\\n\" | cat - file > temp &&\n+\tmv temp file &&\n+\ttest_tick &&\n+\tgit commit -am fifth\n+\n+\tsed -i -e \"s/void newfunc2/void newfunc4/\" file &&\n+\ttest_tick &&\n+\tgit commit -am sixth\n+'\n+\n+test_expect_success 'log --function-name=main' '\n+\tgit log --function-name=main >actual &&\n+\tgit log --grep=second >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'log --function-name \"newfunc\\W\"' '\n+\tgit log --function-name \"newfunc\\W\" >actual &&\n+\tgit log --grep=third >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'log --function-name \"newfunc2\"' '\n+\tgit log --function-name newfunc2 >actual &&\n+\tgit log -E --grep \"sixth|fourth\" >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'log --function-name \"newfunc3\"' '\n+\tgit log --function-name newfunc3 >actual &&\n+\tgit log --grep=fifth >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'log --function-name \"newfunc4\"' '\n+\tgit log --function-name newfunc4 >actual &&\n+\tgit log --grep=sixth >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'log --function-name \"newfunc\"' '\n+\tgit log --function-name newfunc >actual &&\n+\tgit log -E --grep \"third|fourth|fifth|sixth\" >expect &&\n+\ttest_cmp expect actual\n+'\n+\n+test_done\n-- \n1.7.12.4 (Apple Git-37)\n"},{"id":"237935","messageId":"c5de064075e6a2192817aafde75d8075ae82c974.1395942768.git.davidad@alum.mit.edu","threadId":"36306","inReplyTo":"1395946256-67124-1-git-send-email-dad-bgl@mit.edu","subject":"[PATCH 10/10] Documentation: Document --function-name usage","fromName":"David A. Dalrymple (and Bhushan G. Lodha)","fromEmail":"dad-bgl@mit.edu","sentAt":"2014-03-27T18:50:56Z","receivedAt":"2014-03-27T18:50:56Z","isPatch":true,"sender":{"key":"dad-bgl@mit.edu","avatar":null},"body":"From: \"Bhushan Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n\nSigned-off-by: David Dalrymple (on zayin) <davidad@alum.mit.edu>\n---\n Documentation/diff-options.txt |  9 +++++++++\n Documentation/gitdiffcore.txt  | 17 ++++++++++++++---\n 2 files changed, 23 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\nindex 9b37b2a..a778dff 100644\n--- a/Documentation/diff-options.txt\n+++ b/Documentation/diff-options.txt\n@@ -427,6 +427,15 @@ information.\n --pickaxe-regex::\n \tTreat the <string> given to `-S` as an extended POSIX regular\n \texpression to match.\n+\n+--function-name<regex>::\n+\tLook for differences whose patch text contains hunk headers that match\n+\t<regex>. This can be useful to locate changes to a particular function\n+\tor other semantic element in a program, since hunk headers are intended\n+\tto indicate the \"function context\" (in the sense of\n+\t`--function-context`) in which the particular change occurs. The\n+\tfunction context is determined by the diff driver corresponding to the\n+\tfile in question; see linkgit:gitattributes[7] for details.\n endif::git-format-patch[]\n \n -O<orderfile>::\ndiff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.txt\nindex c8b3e51..b8477ce 100644\n--- a/Documentation/gitdiffcore.txt\n+++ b/Documentation/gitdiffcore.txt\n@@ -222,10 +222,11 @@ version prefixed with '+'.\n diffcore-pickaxe: For Detecting Addition/Deletion of Specified String\n ---------------------------------------------------------------------\n \n-This transformation limits the set of filepairs to those that change\n+This transformation limits the set of filepairs to those that involve\n specified strings between the preimage and the postimage in a certain\n-way.  -S<block of text> and -G<regular expression> options are used to\n-specify different ways these strings are sought.\n+way.  -S<block of text>, -G<regular expression>, and\n+--function-name<regular expression> options are used to specify\n+different ways these strings are sought.\n \n \"-S<block of text>\" detects filepairs whose preimage and postimage\n have different number of occurrences of the specified block of text.\n@@ -251,6 +252,16 @@ criterion in a changeset, the entire changeset is kept.  This behavior\n is designed to make reviewing changes in the context of the whole\n changeset easier.\n \n+\"--function-name<regular expression>\" detects filepairs whose textual\n+diff contains a hunk header that matches the given regular expression.\n+The hunk header is generated via the diff driver specified in\n+`.gitattributes`, and is intended to reflect the \"function context\"\n+(in the sense of `--function-context`) in which the change occurs,\n+with programming-language-dependent heuristics. As of now, the\n+programming language is not auto-detected in any way. Also note that\n+hunks whose headers do not match the regular expression are not\n+currently filtered out; this is only a filepair filter.\n+\n diffcore-order: For Sorting the Output Based on Filenames\n ---------------------------------------------------------\n \n-- \n1.7.12.4 (Apple Git-37)\n"},{"id":"237940","messageId":"20140327190314.GB28668@sigill.intra.peff.net","threadId":"36306","inReplyTo":"1395946256-67124-1-git-send-email-dad-bgl@mit.edu","subject":"Re: [PATCH 00/10] [RFC] pickaxe for function names","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-03-27T19:03:14Z","receivedAt":"2014-03-27T19:03:14Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Mar 27, 2014 at 02:50:46PM -0400, David A. Dalrymple (and Bhushan G. Lodha) wrote:\n\n> This series introduces a --function-name=<pattern> option for git-log, intended\n> to search for commits which touch a function matching a certain pattern (a\n> feature we've seen requested and are interested in using ourselves).\n\nHow does your feature compare with the line-level history viewer? E.g.:\n\n  git log -L:myfunc:foo.c\n\nI guess by being part of pickaxe, it can be used to generally select\ncommits (whereas \"-L\" is about drilling down a particular set of lines,\nso something like --full-diff would not work).\n\nBut \"-L\" can do many things that pickaxe can't. It is not just about\nfinding lines touched within a pattern, but uses the pattern to\ndetermine an initial set of lines, and then recursively \"blames\" those\nlines going back through history. So how you specify the pattern is more\nflexible (you can give any line range, for example), and it should be\nable to cross boundaries like function renames.\n\n-Peff\n"},{"id":"237962","messageId":"CAPig+cQ5pEyPUG+Rhg2=H9r9RNo2=wFXxfawKZpb+RJxhdUKFA@mail.gmail.com","threadId":"36306","inReplyTo":"c5de064075e6a2192817aafde75d8075ae82c974.1395942768.git.davidad@alum.mit.edu","subject":"Re: [PATCH 10/10] Documentation: Document --function-name usage","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2014-03-28T00:30:49Z","receivedAt":"2014-03-28T00:30:49Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Mar 27, 2014 at 2:50 PM, David A. Dalrymple (and Bhushan G.\nLodha) <dad-bgl@mit.edu> wrote:\n> From: \"Bhushan Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n>\n> Signed-off-by: David Dalrymple (on zayin) <davidad@alum.mit.edu>\n> ---\n>  Documentation/diff-options.txt |  9 +++++++++\n>  Documentation/gitdiffcore.txt  | 17 ++++++++++++++---\n>  2 files changed, 23 insertions(+), 3 deletions(-)\n>\n> diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\n> index 9b37b2a..a778dff 100644\n> --- a/Documentation/diff-options.txt\n> +++ b/Documentation/diff-options.txt\n> @@ -427,6 +427,15 @@ information.\n>  --pickaxe-regex::\n>         Treat the <string> given to `-S` as an extended POSIX regular\n>         expression to match.\n> +\n> +--function-name<regex>::\n\nMissing '=' before <regex>. Ditto for the several additional instances\nin this patch.\n\n> +       Look for differences whose patch text contains hunk headers that match\n> +       <regex>. This can be useful to locate changes to a particular function\n> +       or other semantic element in a program, since hunk headers are intended\n> +       to indicate the \"function context\" (in the sense of\n> +       `--function-context`) in which the particular change occurs. The\n> +       function context is determined by the diff driver corresponding to the\n> +       file in question; see linkgit:gitattributes[7] for details.\n>  endif::git-format-patch[]\n>\n>  -O<orderfile>::\n> diff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.txt\n> index c8b3e51..b8477ce 100644\n> --- a/Documentation/gitdiffcore.txt\n> +++ b/Documentation/gitdiffcore.txt\n> @@ -222,10 +222,11 @@ version prefixed with '+'.\n>  diffcore-pickaxe: For Detecting Addition/Deletion of Specified String\n>  ---------------------------------------------------------------------\n>\n> -This transformation limits the set of filepairs to those that change\n> +This transformation limits the set of filepairs to those that involve\n>  specified strings between the preimage and the postimage in a certain\n> -way.  -S<block of text> and -G<regular expression> options are used to\n> -specify different ways these strings are sought.\n> +way.  -S<block of text>, -G<regular expression>, and\n> +--function-name<regular expression> options are used to specify\n> +different ways these strings are sought.\n>\n>  \"-S<block of text>\" detects filepairs whose preimage and postimage\n>  have different number of occurrences of the specified block of text.\n> @@ -251,6 +252,16 @@ criterion in a changeset, the entire changeset is kept.  This behavior\n>  is designed to make reviewing changes in the context of the whole\n>  changeset easier.\n>\n> +\"--function-name<regular expression>\" detects filepairs whose textual\n> +diff contains a hunk header that matches the given regular expression.\n> +The hunk header is generated via the diff driver specified in\n> +`.gitattributes`, and is intended to reflect the \"function context\"\n> +(in the sense of `--function-context`) in which the change occurs,\n> +with programming-language-dependent heuristics. As of now, the\n> +programming language is not auto-detected in any way. Also note that\n> +hunks whose headers do not match the regular expression are not\n> +currently filtered out; this is only a filepair filter.\n> +\n>  diffcore-order: For Sorting the Output Based on Filenames\n>  ---------------------------------------------------------\n>\n> --\n> 1.7.12.4 (Apple Git-37)\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"237986","messageId":"533523F9.2000108@viscovery.net","threadId":"36306","inReplyTo":"4eb91822043e730bf8a47f12a9129d02f6fc135d.1395942768.git.davidad@alum.mit.edu","subject":"Re: [PATCH 09/10] t4213: test --function-name option","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2014-03-28T07:25:45Z","receivedAt":"2014-03-28T07:25:45Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 3/27/2014 19:50, schrieb David A. Dalrymple (and Bhushan G. Lodha):\n> From: \"Bhushan G. Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n> \n> This test builds a sample C file, adding and removing functions, and\n> checks that the right commits are filtered by --function-name matching.\n\nThis is probably the most important patch in your series as it documents\nthe expected behavior. Unfortunately, I find its clarity very lacking. :(\n\nThis new feature uses the userdiff driver, IIUC. Does it do so in all\nrespects? In particular, does it also evaluate the negative patterns? For\nexample, when there is a label in the code, is it not mistaken as the\nbeginning of a function? A test for this case would be very instructive.\n\nFurthermore, consider a patch for a change at the very beginning of a\nfunction. Then the function name would appear in the pre-context of the\nhunk, but the hunk header would show the function before the one with the\nchange. Would such a change confuse your implementation? I guess not.\nAgain, a test case would remove any doubts.\n\nIs it possible to search for a change that is before any functions? It\nwould be useful to enumerate commits that change #include lines.\n\n> \n> Signed-off-by: David Dalrymple (on zayin) <davidad@alum.mit.edu>\n> ---\n>  t/t4213-log-function-name.sh | 73 ++++++++++++++++++++++++++++++++++++++++++++\n>  1 file changed, 73 insertions(+)\n>  create mode 100755 t/t4213-log-function-name.sh\n> \n> diff --git a/t/t4213-log-function-name.sh b/t/t4213-log-function-name.sh\n> new file mode 100755\n> index 0000000..1243ce5\n> --- /dev/null\n> +++ b/t/t4213-log-function-name.sh\n> @@ -0,0 +1,73 @@\n> +#!/bin/sh\n> +\n> +test_description='log --function-name'\n> +. ./test-lib.sh\n> +\n> +test_expect_success setup '\n> +\techo \"* diff=cpp\" > .gitattributes\n> +\n> +\t>file &&\n> +\tgit add file &&\n> +\ttest_tick &&\n> +\tgit commit -m initial &&\n> +\n> +\tprintf \"int main(){\\n\\treturn 0;\\n}\\n\" >> file &&\n> +\ttest_tick &&\n> +\tgit commit -am second\n\nBroken && chain here and later as well. Please be careful.\n\n> +\n> +\tprintf \"void newfunc(){\\n\\treturn;\\n}\\n\" >> file &&\n> +\ttest_tick &&\n> +\tgit commit -am third\n\n\tgit commit -am \"append a function\" &&\n\n> +\n> +\tprintf \"void newfunc2(){\\n\\treturn;\\n}\\n\" | cat - file > temp &&\n> +\tmv temp file &&\n> +\ttest_tick &&\n> +\tgit commit -am fourth\n\n\tgit commit -am \"prepend a function\" &&\n\netc. You get the picture.\n\n> +\n> +\tprintf \"void newfunc3(){\\n\\treturn;\\n}\\n\" | cat - file > temp &&\n> +\tmv temp file &&\n> +\ttest_tick &&\n> +\tgit commit -am fifth\n> +\n> +\tsed -i -e \"s/void newfunc2/void newfunc4/\" file &&\n> +\ttest_tick &&\n> +\tgit commit -am sixth\n> +'\n> +\n> +test_expect_success 'log --function-name=main' '\n\ntest_expect_success 'log --function-name finds a function with a change' '\n\n> +\tgit log --function-name=main >actual &&\n> +\tgit log --grep=second >expect &&\n> +\ttest_cmp expect actual\n> +'\n> +\n> +test_expect_success 'log --function-name \"newfunc\\W\"' '\n\ntest_expect_success 'log --function-name with extended regexp' '\n\netc. You get the picture.\n\n> +\tgit log --function-name \"newfunc\\W\" >actual &&\n> +\tgit log --grep=third >expect &&\n> +\ttest_cmp expect actual\n> +'\n> +\n> +test_expect_success 'log --function-name \"newfunc2\"' '\n> +\tgit log --function-name newfunc2 >actual &&\n> +\tgit log -E --grep \"sixth|fourth\" >expect &&\n> +\ttest_cmp expect actual\n> +'\n> +\n> +test_expect_success 'log --function-name \"newfunc3\"' '\n> +\tgit log --function-name newfunc3 >actual &&\n> +\tgit log --grep=fifth >expect &&\n> +\ttest_cmp expect actual\n> +'\n> +\n> +test_expect_success 'log --function-name \"newfunc4\"' '\n> +\tgit log --function-name newfunc4 >actual &&\n> +\tgit log --grep=sixth >expect &&\n> +\ttest_cmp expect actual\n> +'\n> +\n> +test_expect_success 'log --function-name \"newfunc\"' '\n> +\tgit log --function-name newfunc >actual &&\n> +\tgit log -E --grep \"third|fourth|fifth|sixth\" >expect &&\n> +\ttest_cmp expect actual\n> +'\n> +\n> +test_done\n> \n"},{"id":"237988","messageId":"CAPig+cSp0iJZjUAUSKyjVvYe=xR5h4c7OHQdSK0Op8vUD_mnhQ@mail.gmail.com","threadId":"36306","inReplyTo":"533523F9.2000108@viscovery.net","subject":"Re: [PATCH 09/10] t4213: test --function-name option","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2014-03-28T08:21:02Z","receivedAt":"2014-03-28T08:21:02Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Mar 28, 2014 at 3:25 AM, Johannes Sixt <j.sixt@viscovery.net> wrote:\n> Am 3/27/2014 19:50, schrieb David A. Dalrymple (and Bhushan G. Lodha):\n>> From: \"Bhushan G. Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n>>\n>> This test builds a sample C file, adding and removing functions, and\n>> checks that the right commits are filtered by --function-name matching.\n>\n> This is probably the most important patch in your series as it documents\n> the expected behavior. Unfortunately, I find its clarity very lacking. :(\n>\n> This new feature uses the userdiff driver, IIUC. Does it do so in all\n> respects? In particular, does it also evaluate the negative patterns? For\n> example, when there is a label in the code, is it not mistaken as the\n> beginning of a function? A test for this case would be very instructive.\n>\n> Furthermore, consider a patch for a change at the very beginning of a\n> function. Then the function name would appear in the pre-context of the\n> hunk, but the hunk header would show the function before the one with the\n> change. Would such a change confuse your implementation? I guess not.\n> Again, a test case would remove any doubts.\n>\n> Is it possible to search for a change that is before any functions? It\n> would be useful to enumerate commits that change #include lines.\n>\n>>\n>> Signed-off-by: David Dalrymple (on zayin) <davidad@alum.mit.edu>\n>> ---\n>>  t/t4213-log-function-name.sh | 73 ++++++++++++++++++++++++++++++++++++++++++++\n>>  1 file changed, 73 insertions(+)\n>>  create mode 100755 t/t4213-log-function-name.sh\n>>\n>> diff --git a/t/t4213-log-function-name.sh b/t/t4213-log-function-name.sh\n>> new file mode 100755\n>> index 0000000..1243ce5\n>> --- /dev/null\n>> +++ b/t/t4213-log-function-name.sh\n>> @@ -0,0 +1,73 @@\n>> +#!/bin/sh\n>> +\n>> +test_description='log --function-name'\n>> +. ./test-lib.sh\n>> +\n>> +test_expect_success setup '\n>> +     echo \"* diff=cpp\" > .gitattributes\n\nBroken &&-chain here, as well.\n\n>> +\n>> +     >file &&\n>> +     git add file &&\n>> +     test_tick &&\n>> +     git commit -m initial &&\n>> +\n>> +     printf \"int main(){\\n\\treturn 0;\\n}\\n\" >> file &&\n>> +     test_tick &&\n>> +     git commit -am second\n>\n> Broken && chain here and later as well. Please be careful.\n>\n>> +\n>> +     printf \"void newfunc(){\\n\\treturn;\\n}\\n\" >> file &&\n>> +     test_tick &&\n>> +     git commit -am third\n>\n>         git commit -am \"append a function\" &&\n>\n>> +\n>> +     printf \"void newfunc2(){\\n\\treturn;\\n}\\n\" | cat - file > temp &&\n>> +     mv temp file &&\n>> +     test_tick &&\n>> +     git commit -am fourth\n>\n>         git commit -am \"prepend a function\" &&\n>\n> etc. You get the picture.\n>\n>> +\n>> +     printf \"void newfunc3(){\\n\\treturn;\\n}\\n\" | cat - file > temp &&\n>> +     mv temp file &&\n>> +     test_tick &&\n>> +     git commit -am fifth\n>> +\n>> +     sed -i -e \"s/void newfunc2/void newfunc4/\" file &&\n>> +     test_tick &&\n>> +     git commit -am sixth\n>> +'\n>> +\n>> +test_expect_success 'log --function-name=main' '\n>\n> test_expect_success 'log --function-name finds a function with a change' '\n>\n>> +     git log --function-name=main >actual &&\n>> +     git log --grep=second >expect &&\n>> +     test_cmp expect actual\n>> +'\n>> +\n>> +test_expect_success 'log --function-name \"newfunc\\W\"' '\n>\n> test_expect_success 'log --function-name with extended regexp' '\n>\n> etc. You get the picture.\n>\n>> +     git log --function-name \"newfunc\\W\" >actual &&\n>> +     git log --grep=third >expect &&\n>> +     test_cmp expect actual\n>> +'\n>> +\n>> +test_expect_success 'log --function-name \"newfunc2\"' '\n>> +     git log --function-name newfunc2 >actual &&\n>> +     git log -E --grep \"sixth|fourth\" >expect &&\n>> +     test_cmp expect actual\n>> +'\n>> +\n>> +test_expect_success 'log --function-name \"newfunc3\"' '\n>> +     git log --function-name newfunc3 >actual &&\n>> +     git log --grep=fifth >expect &&\n>> +     test_cmp expect actual\n>> +'\n>> +\n>> +test_expect_success 'log --function-name \"newfunc4\"' '\n>> +     git log --function-name newfunc4 >actual &&\n>> +     git log --grep=sixth >expect &&\n>> +     test_cmp expect actual\n>> +'\n>> +\n>> +test_expect_success 'log --function-name \"newfunc\"' '\n>> +     git log --function-name newfunc >actual &&\n>> +     git log -E --grep \"third|fourth|fifth|sixth\" >expect &&\n>> +     test_cmp expect actual\n>> +'\n>> +\n>> +test_done\n>>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"237999","messageId":"533560E0.3010106@viscovery.net","threadId":"36306","inReplyTo":"533523F9.2000108@viscovery.net","subject":"Re: [PATCH 09/10] t4213: test --function-name option","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2014-03-28T11:45:36Z","receivedAt":"2014-03-28T11:45:36Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":">> +\tsed -i -e \"s/void newfunc2/void newfunc4/\" file &&\n\nI forgot to mention that sed -i is not portable.\n\n-- Hannes\n"},{"id":"238365","messageId":"533DD1B1.3000107@web.de","threadId":"36306","inReplyTo":"62ab0f9c34eabe020ae99c7c1f69d580d9bb36d8.1395942768.git.davidad@alum.mit.edu","subject":"Re: [PATCH 06/10] log: --function-name pickaxe","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2014-04-03T21:25:05Z","receivedAt":"2014-04-03T21:25:05Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 27.03.2014 19:50, schrieb David A. Dalrymple (and Bhushan G. Lodha):\n> From: \"Bhushan G. Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n>\n> This is similar to the pickaxe grep option (-G), but applies the\n> provided regex only to diff hunk headers, thereby showing only those\n> commits which affect a \"function\" with a definition line matching the\n> pattern. These are \"functions\" in the same sense as with\n> --function-context, i.e., they may be classes, structs, etc. depending\n> on the programming-language-specific pattern specified by the \"diff\"\n> attribute in .gitattributes.\n\nWith that approach you depend on the hunk header and apparently need to \nadd XDL_EMIT_MOREFUNCNAMES and XDL_EMIT_MOREHUNKHEADS to improve the \nresults.  This approach feels fragile.\n\nWould it perhaps be more robust to not base the implementation on diff \nand instead to scan the raw file contents?  You'd search both files for \na matching function signature, then search for a non-matching one from \nthere.  The parts in between are function bodies and can be compared. \nIf they match, you'd search for matching function starts again etc.\n\nOr would it make sense to make use of the diff option FUNCCONTEXT (git \ndiff -W) and look for the function signature in the diff body instead of \nin the hunk header?  Such a diff contains whole functions, but a single \nhunk could contain multiple ones.\n\nRené\n"},{"id":"238366","messageId":"xmqqwqf6ozp3.fsf@gitster.dls.corp.google.com","threadId":"36306","inReplyTo":"533DD1B1.3000107@web.de","subject":"Re: [PATCH 06/10] log: --function-name pickaxe","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-04-03T21:44:40Z","receivedAt":"2014-04-03T21:44:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"René Scharfe <l.s.r@web.de> writes:\n\n> With that approach you depend on the hunk header and apparently need\n> to add XDL_EMIT_MOREFUNCNAMES and XDL_EMIT_MOREHUNKHEADS to improve\n> the results.  This approach feels fragile.\n>\n> Would it perhaps be more robust to not base the implementation on diff\n> and instead to scan the raw file contents?\n\nThat is an interesting idea.\n\nPerhaps this can be implemented as a new stage in the transformation\npipeline, I wonder?  There is currently no transformation that\nmodifies the blob contents being compared, but I do not think there\nis anything fundamental that prevents one from being written.  The\nnew \"limit to this function body\" transformation would perhaps sit\nbefore the diffcore-rename and would transform all the blobs to\nempty, except for the part that is the body of the function the user\nis interested in.\n"},{"id":"238369","messageId":"533E92D1.9020406@gmail.com","threadId":"36306","inReplyTo":"6822f9d947ffb589df25537e2c1e7c4ead7656b0.1395942768.git.davidad@alum.mit.edu","subject":"Re: [PATCH 03/10] diffcore-pickaxe.c: Refactor pickaxe_fn signature","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2014-04-04T11:09:05Z","receivedAt":"2014-04-04T11:09:05Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 2014-03-27 19:50, David A. Dalrymple (and Bhushan G. Lodha) pisze:\n> From: \"Bhushan G. Lodha & David A. Dalrymple\" <dad-bgl@mit.edu>\n>\n> This function type previously accepted separate regex_t and kwset_t\n> parameters, which conceptually go together. Here we create a struct to\n> encapsulate them, in anticipation of adding a third field that\n> pickaxe_fn's may require.\n>\n> This parallels the existing diffgrep_cb structure for passing possibly\n> relevant values through to the callbacks invoked by xdi_diff_outf.\n\nIf it parallels existing diffgrep_cb structure, why not name this\nequivalent in simular way, i.e. pickaxe_cb or pickaxe_options or\npickaxe_cb_opts instead of generic name fn_options?\n\n> Signed-off-by: David Dalrymple (on zayin) <davidad@alum.mit.edu>\n> ---\n>   diffcore-pickaxe.c | 50 ++++++++++++++++++++++++++++++--------------------\n>   1 file changed, 30 insertions(+), 20 deletions(-)\n>\n> diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c\n> index 0d36a3c..7e65095 100644\n> --- a/diffcore-pickaxe.c\n> +++ b/diffcore-pickaxe.c\n> @@ -8,17 +8,22 @@\n>   #include \"xdiff-interface.h\"\n>   #include \"kwset.h\"\n>\n> +struct fn_options {\n> +\tregex_t *regex;\n> +\tkwset_t kws;\n> +};\n"},{"id":"238370","messageId":"533E9465.8070609@gmail.com","threadId":"36306","inReplyTo":"xmqqwqf6ozp3.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 06/10] log: --function-name pickaxe","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2014-04-04T11:15:49Z","receivedAt":"2014-04-04T11:15:49Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 2014-04-03 23:44, Junio C Hamano pisze:\n> René Scharfe <l.s.r@web.de> writes:\n>\n>> With that approach you depend on the hunk header and apparently need\n>> to add XDL_EMIT_MOREFUNCNAMES and XDL_EMIT_MOREHUNKHEADS to improve\n>> the results.  This approach feels fragile.\n>>\n>> Would it perhaps be more robust to not base the implementation on diff\n>> and instead to scan the raw file contents?\n>\n> That is an interesting idea.\n>\n> Perhaps this can be implemented as a new stage in the transformation\n> pipeline, I wonder?  There is currently no transformation that\n> modifies the blob contents being compared, but I do not think there\n> is anything fundamental that prevents one from being written.  The\n> new \"limit to this function body\" transformation would perhaps sit\n> before the diffcore-rename and would transform all the blobs to\n> empty, except for the part that is the body of the function the user\n> is interested in.\n\nWell, there is 'texconv', e.g.\n\n   .gitattributes\n   *.jpg diff=jpg\n\n   .git/config\n   [diff \"jpg\"]\n          textconv = exif\n\nDoesn't it fit in said place in the transformation pipeline?\n\n-- \nJakub Narębski\n"},{"id":"238371","messageId":"533E95A4.2010207@gmail.com","threadId":"36306","inReplyTo":"4eb91822043e730bf8a47f12a9129d02f6fc135d.1395942768.git.davidad@alum.mit.edu","subject":"Re: [PATCH 09/10] t4213: test --function-name option","fromName":"Jakub Narębski","fromEmail":"jnareb@gmail.com","sentAt":"2014-04-04T11:21:08Z","receivedAt":"2014-04-04T11:21:08Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"W dniu 2014-03-27 19:50, David A. Dalrymple (and Bhushan G. Lodha) pisze:\n\n> +test_expect_success setup '\n> +\techo \"* diff=cpp\" > .gitattributes\n> +\n> +\t>file &&\n> +\tgit add file &&\n> +\ttest_tick &&\n> +\tgit commit -m initial &&\n> +\n> +\tprintf \"int main(){\\n\\treturn 0;\\n}\\n\" >> file &&\n> +\ttest_tick &&\n> +\tgit commit -am second\n\nWouldn't it be more readable to use \"cat \\-EOF\" or separate files\ninstead of printf-s with embedded newlines \"\\n\" and tabs \"\\t\"?\n\n-- \nJakub Narębski\n"},{"id":"238378","messageId":"xmqqlhvlorug.fsf@gitster.dls.corp.google.com","threadId":"36306","inReplyTo":"533E9465.8070609@gmail.com","subject":"Re: [PATCH 06/10] log: --function-name pickaxe","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-04-04T18:46:31Z","receivedAt":"2014-04-04T18:46:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narębski <jnareb@gmail.com> writes:\n\n> W dniu 2014-04-03 23:44, Junio C Hamano pisze:\n>> René Scharfe <l.s.r@web.de> writes:\n>>\n>>> With that approach you depend on the hunk header and apparently need\n>>> to add XDL_EMIT_MOREFUNCNAMES and XDL_EMIT_MOREHUNKHEADS to improve\n>>> the results.  This approach feels fragile.\n>>>\n>>> Would it perhaps be more robust to not base the implementation on diff\n>>> and instead to scan the raw file contents?\n>>\n>> That is an interesting idea.\n>>\n>> Perhaps this can be implemented as a new stage in the transformation\n>> pipeline, I wonder?  There is currently no transformation that\n>> modifies the blob contents being compared, but I do not think there\n>> is anything fundamental that prevents one from being written.  The\n>> new \"limit to this function body\" transformation would perhaps sit\n>> before the diffcore-rename and would transform all the blobs to\n>> empty, except for the part that is the body of the function the user\n>> is interested in.\n>\n> Well, there is 'texconv', e.g.\n>\n>   .gitattributes\n>   *.jpg diff=jpg\n>\n>   .git/config\n>   [diff \"jpg\"]\n>          textconv = exif\n\n;-)  So you could define this textconv\n\n    sed -n -e '/^int main(/,/^}/p'\n\nto limit the output only to the definition of the function main().\n\n> Doesn't it fit in said place in the transformation pipeline?\n\nNot at all, unfortunately.  The textconv conversion happens in the\nfinal output stage and comes way too late to influence the earlier\nstages like renames and pickaxe, which will still see the whole\ncontents outside the definition of the function main().\n"},{"id":"240029","messageId":"CAHqUa-3myd+ephcRBQ97gV02BJqzKLqowU4GFi-PsS6qzCMQUw@mail.gmail.com","threadId":"36306","inReplyTo":"xmqqlhvlorug.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 06/10] log: --function-name pickaxe","fromName":"Bhushan Lodha","fromEmail":"bhushanlodha@gmail.com","sentAt":"2014-04-28T20:04:40Z","receivedAt":"2014-04-28T20:04:40Z","isPatch":true,"sender":{"key":"bhushanlodha@gmail.com","avatar":null},"body":"I plan to work on this in few weeks. If anybody has more suggestion or\nwant to discuss the implementation let me know\n\nOn Fri, Apr 4, 2014 at 2:46 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Jakub Narębski <jnareb@gmail.com> writes:\n>\n>> W dniu 2014-04-03 23:44, Junio C Hamano pisze:\n>>> René Scharfe <l.s.r@web.de> writes:\n>>>\n>>>> With that approach you depend on the hunk header and apparently need\n>>>> to add XDL_EMIT_MOREFUNCNAMES and XDL_EMIT_MOREHUNKHEADS to improve\n>>>> the results.  This approach feels fragile.\n>>>>\n>>>> Would it perhaps be more robust to not base the implementation on diff\n>>>> and instead to scan the raw file contents?\n>>>\n>>> That is an interesting idea.\n>>>\n>>> Perhaps this can be implemented as a new stage in the transformation\n>>> pipeline, I wonder?  There is currently no transformation that\n>>> modifies the blob contents being compared, but I do not think there\n>>> is anything fundamental that prevents one from being written.  The\n>>> new \"limit to this function body\" transformation would perhaps sit\n>>> before the diffcore-rename and would transform all the blobs to\n>>> empty, except for the part that is the body of the function the user\n>>> is interested in.\n>>\n>> Well, there is 'texconv', e.g.\n>>\n>>   .gitattributes\n>>   *.jpg diff=jpg\n>>\n>>   .git/config\n>>   [diff \"jpg\"]\n>>          textconv = exif\n>\n> ;-)  So you could define this textconv\n>\n>     sed -n -e '/^int main(/,/^}/p'\n>\n> to limit the output only to the definition of the function main().\n>\n>> Doesn't it fit in said place in the transformation pipeline?\n>\n> Not at all, unfortunately.  The textconv conversion happens in the\n> final output stage and comes way too late to influence the earlier\n> stages like renames and pickaxe, which will still see the whole\n> contents outside the definition of the function main().\n>\n>\n>\n"}]}