{"thread":{"id":"25030","subject":"[PATCH 0/5] en/object-list-with-pathspec (v3?)","startedAt":"2010-09-07T15:47:58Z","lastAt":"2010-09-08T09:58:00Z","messageCount":8,"participants":["Nguyễn Thái Ngọc Duy","Elijah Newren","Nguyen Thai Ngoc Duy"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"150262","messageId":"1283874483-32017-1-git-send-email-pclouds@gmail.com","threadId":"25030","inReplyTo":null,"subject":"[PATCH 0/5] en/object-list-with-pathspec (v3?)","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-07T15:47:58Z","receivedAt":"2010-09-07T15:47:58Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Changes from last time is tree_entry_interesting() now takes\nstruct exclude * as the pathspecs.\n\nI think there'll be a bit of performance loss because diff_options.el\nis not initialized from the beginning. But that requires more changes\noutside tree-diff.c (makes sure that diff_options.el is copied properly,\nmakes sure that diff_tree_setup_* is called ...) So one step at a time.\nI'm working on it.\n\nElijah Newren (2):\n  Add testcases showing how pathspecs are ignored with rev-list\n    --objects\n  Make rev-list --objects work together with pathspecs\n\nNguyễn Thái Ngọc Duy (3):\n  diff-no-index.c: rename read_directory() to read_dir()\n  tree-walk: move tree_entry_interesting() from tree-diff.c\n  tree_entry_interesting(): remove dependency on struct diff_options\n\n diff-no-index.c          |    6 +-\n diff.h                   |    3 +\n list-objects.c           |   25 ++++++++\n revision.c               |    8 ++-\n revision.h               |    3 +-\n t/t6000-rev-list-misc.sh |   51 ++++++++++++++++\n tree-diff.c              |  145 +++++++++-------------------------------------\n tree-walk.c              |  111 +++++++++++++++++++++++++++++++++++\n tree-walk.h              |    4 +\n 9 files changed, 233 insertions(+), 123 deletions(-)\n create mode 100755 t/t6000-rev-list-misc.sh\n"},{"id":"150263","messageId":"1283874483-32017-2-git-send-email-pclouds@gmail.com","threadId":"25030","inReplyTo":"1283874483-32017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 1/5] diff-no-index.c: rename read_directory() to read_dir()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-07T15:47:59Z","receivedAt":"2010-09-07T15:47:59Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This name clashes with one in dir.h, to be included later on.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n diff-no-index.c |    6 +++---\n 1 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/diff-no-index.c b/diff-no-index.c\nindex ce9e783..859a8ba 100644\n--- a/diff-no-index.c\n+++ b/diff-no-index.c\n@@ -16,7 +16,7 @@\n #include \"builtin.h\"\n #include \"string-list.h\"\n \n-static int read_directory(const char *path, struct string_list *list)\n+static int read_dir(const char *path, struct string_list *list)\n {\n \tDIR *dir;\n \tstruct dirent *e;\n@@ -68,9 +68,9 @@ static int queue_diff(struct diff_options *o,\n \t\tstruct string_list p2 = STRING_LIST_INIT_DUP;\n \t\tint len1 = 0, len2 = 0, i1, i2, ret = 0;\n \n-\t\tif (name1 && read_directory(name1, &p1))\n+\t\tif (name1 && read_dir(name1, &p1))\n \t\t\treturn -1;\n-\t\tif (name2 && read_directory(name2, &p2)) {\n+\t\tif (name2 && read_dir(name2, &p2)) {\n \t\t\tstring_list_clear(&p1, 0);\n \t\t\treturn -1;\n \t\t}\n-- \n1.7.1.rc1.69.g24c2f7\n"},{"id":"150264","messageId":"1283874483-32017-3-git-send-email-pclouds@gmail.com","threadId":"25030","inReplyTo":"1283874483-32017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 2/5] Add testcases showing how pathspecs are ignored with rev-list --objects","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-07T15:48:00Z","receivedAt":"2010-09-07T15:48:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n t/t6000-rev-list-misc.sh |   51 ++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 51 insertions(+), 0 deletions(-)\n create mode 100755 t/t6000-rev-list-misc.sh\n\ndiff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh\nnew file mode 100755\nindex 0000000..b3c1dd8\n--- /dev/null\n+++ b/t/t6000-rev-list-misc.sh\n@@ -0,0 +1,51 @@\n+#!/bin/sh\n+\n+test_description='miscellaneous rev-list tests'\n+\n+. ./test-lib.sh\n+\n+test_expect_success setup '\n+\techo content1 >wanted_file &&\n+\techo content2 >unwanted_file &&\n+\tgit add wanted_file unwanted_file &&\n+\tgit commit -m one\n+'\n+\n+test_expect_failure 'rev-list --objects heeds pathspecs' '\n+\tgit rev-list --objects HEAD -- wanted_file >output &&\n+\tgrep wanted_file output &&\n+\t! grep unwanted_file output\n+'\n+\n+test_expect_failure 'rev-list --objects with pathspecs and deeper paths' '\n+\tmkdir foo &&\n+\t>foo/file &&\n+\tgit add foo/file &&\n+\tgit commit -m two &&\n+\n+\tgit rev-list --objects HEAD -- foo >output &&\n+\tgrep foo/file output &&\n+\n+\tgit rev-list --objects HEAD -- foo/file >output &&\n+\tgrep foo/file output &&\n+\t! grep unwanted_file output\n+'\n+\n+test_expect_failure 'rev-list --objects with pathspecs and copied files' '\n+\tgit checkout --orphan junio-testcase &&\n+\tgit rm -rf . &&\n+\n+\tmkdir two &&\n+\techo frotz >one &&\n+\tcp one two/three &&\n+\tgit add one two/three &&\n+\ttest_tick &&\n+\tgit commit -m that &&\n+\n+\tONE=$(git rev-parse HEAD:one)\n+\tgit rev-list --objects HEAD two >output &&\n+\tgrep \"$ONE two/three\" output &&\n+\t! grep one output\n+'\n+\n+test_done\n-- \n1.7.1.rc1.69.g24c2f7\n"},{"id":"150265","messageId":"1283874483-32017-4-git-send-email-pclouds@gmail.com","threadId":"25030","inReplyTo":"1283874483-32017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 3/5] tree-walk: move tree_entry_interesting() from tree-diff.c","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-07T15:48:01Z","receivedAt":"2010-09-07T15:48:01Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n tree-diff.c |  114 ----------------------------------------------------------\n tree-walk.c |  115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n tree-walk.h |    3 ++\n 3 files changed, 118 insertions(+), 114 deletions(-)\n\ndiff --git a/tree-diff.c b/tree-diff.c\nindex cd659c6..c74d0b5 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -82,120 +82,6 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const\n \treturn 0;\n }\n \n-/*\n- * Is a tree entry interesting given the pathspec we have?\n- *\n- * Return:\n- *  - 2 for \"yes, and all subsequent entries will be\"\n- *  - 1 for yes\n- *  - zero for no\n- *  - negative for \"no, and no subsequent entries will be either\"\n- */\n-static int tree_entry_interesting(struct tree_desc *desc, const char *base, int baselen, struct diff_options *opt)\n-{\n-\tconst char *path;\n-\tconst unsigned char *sha1;\n-\tunsigned mode;\n-\tint i;\n-\tint pathlen;\n-\tint never_interesting = -1;\n-\n-\tif (!opt->nr_paths)\n-\t\treturn 1;\n-\n-\tsha1 = tree_entry_extract(desc, &path, &mode);\n-\n-\tpathlen = tree_entry_len(path, sha1);\n-\n-\tfor (i = 0; i < opt->nr_paths; i++) {\n-\t\tconst char *match = opt->paths[i];\n-\t\tint matchlen = opt->pathlens[i];\n-\t\tint m = -1; /* signals that we haven't called strncmp() */\n-\n-\t\tif (baselen >= matchlen) {\n-\t\t\t/* If it doesn't match, move along... */\n-\t\t\tif (strncmp(base, match, matchlen))\n-\t\t\t\tcontinue;\n-\n-\t\t\t/*\n-\t\t\t * If the base is a subdirectory of a path which\n-\t\t\t * was specified, all of them are interesting.\n-\t\t\t */\n-\t\t\tif (!matchlen ||\n-\t\t\t    base[matchlen] == '/' ||\n-\t\t\t    match[matchlen - 1] == '/')\n-\t\t\t\treturn 2;\n-\n-\t\t\t/* Just a random prefix match */\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\t/* Does the base match? */\n-\t\tif (strncmp(base, match, baselen))\n-\t\t\tcontinue;\n-\n-\t\tmatch += baselen;\n-\t\tmatchlen -= baselen;\n-\n-\t\tif (never_interesting) {\n-\t\t\t/*\n-\t\t\t * We have not seen any match that sorts later\n-\t\t\t * than the current path.\n-\t\t\t */\n-\n-\t\t\t/*\n-\t\t\t * Does match sort strictly earlier than path\n-\t\t\t * with their common parts?\n-\t\t\t */\n-\t\t\tm = strncmp(match, path,\n-\t\t\t\t    (matchlen < pathlen) ? matchlen : pathlen);\n-\t\t\tif (m < 0)\n-\t\t\t\tcontinue;\n-\n-\t\t\t/*\n-\t\t\t * If we come here even once, that means there is at\n-\t\t\t * least one pathspec that would sort equal to or\n-\t\t\t * later than the path we are currently looking at.\n-\t\t\t * In other words, if we have never reached this point\n-\t\t\t * after iterating all pathspecs, it means all\n-\t\t\t * pathspecs are either outside of base, or inside the\n-\t\t\t * base but sorts strictly earlier than the current\n-\t\t\t * one.  In either case, they will never match the\n-\t\t\t * subsequent entries.  In such a case, we initialized\n-\t\t\t * the variable to -1 and that is what will be\n-\t\t\t * returned, allowing the caller to terminate early.\n-\t\t\t */\n-\t\t\tnever_interesting = 0;\n-\t\t}\n-\n-\t\tif (pathlen > matchlen)\n-\t\t\tcontinue;\n-\n-\t\tif (matchlen > pathlen) {\n-\t\t\tif (match[pathlen] != '/')\n-\t\t\t\tcontinue;\n-\t\t\tif (!S_ISDIR(mode))\n-\t\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (m == -1)\n-\t\t\t/*\n-\t\t\t * we cheated and did not do strncmp(), so we do\n-\t\t\t * that here.\n-\t\t\t */\n-\t\t\tm = strncmp(match, path, pathlen);\n-\n-\t\t/*\n-\t\t * If common part matched earlier then it is a hit,\n-\t\t * because we rejected the case where path is not a\n-\t\t * leading directory and is shorter than match.\n-\t\t */\n-\t\tif (!m)\n-\t\t\treturn 1;\n-\t}\n-\treturn never_interesting; /* No matches */\n-}\n-\n /* A whole sub-tree went away or appeared */\n static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen)\n {\ndiff --git a/tree-walk.c b/tree-walk.c\nindex a9bbf4e..bc83fa3 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -2,6 +2,7 @@\n #include \"tree-walk.h\"\n #include \"unpack-trees.h\"\n #include \"tree.h\"\n+#include \"diff.h\"\n \n static const char *get_mode(const char *str, unsigned int *modep)\n {\n@@ -455,3 +456,117 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch\n \tfree(tree);\n \treturn retval;\n }\n+\n+/*\n+ * Is a tree entry interesting given the pathspec we have?\n+ *\n+ * Return:\n+ *  - 2 for \"yes, and all subsequent entries will be\"\n+ *  - 1 for yes\n+ *  - zero for no\n+ *  - negative for \"no, and no subsequent entries will be either\"\n+ */\n+static int tree_entry_interesting(struct tree_desc *desc, const char *base, int baselen, struct diff_options *opt)\n+{\n+\tconst char *path;\n+\tconst unsigned char *sha1;\n+\tunsigned mode;\n+\tint i;\n+\tint pathlen;\n+\tint never_interesting = -1;\n+\n+\tif (!opt->nr_paths)\n+\t\treturn 1;\n+\n+\tsha1 = tree_entry_extract(desc, &path, &mode);\n+\n+\tpathlen = tree_entry_len(path, sha1);\n+\n+\tfor (i = 0; i < opt->nr_paths; i++) {\n+\t\tconst char *match = opt->paths[i];\n+\t\tint matchlen = opt->pathlens[i];\n+\t\tint m = -1; /* signals that we haven't called strncmp() */\n+\n+\t\tif (baselen >= matchlen) {\n+\t\t\t/* If it doesn't match, move along... */\n+\t\t\tif (strncmp(base, match, matchlen))\n+\t\t\t\tcontinue;\n+\n+\t\t\t/*\n+\t\t\t * If the base is a subdirectory of a path which\n+\t\t\t * was specified, all of them are interesting.\n+\t\t\t */\n+\t\t\tif (!matchlen ||\n+\t\t\t    base[matchlen] == '/' ||\n+\t\t\t    match[matchlen - 1] == '/')\n+\t\t\t\treturn 2;\n+\n+\t\t\t/* Just a random prefix match */\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* Does the base match? */\n+\t\tif (strncmp(base, match, baselen))\n+\t\t\tcontinue;\n+\n+\t\tmatch += baselen;\n+\t\tmatchlen -= baselen;\n+\n+\t\tif (never_interesting) {\n+\t\t\t/*\n+\t\t\t * We have not seen any match that sorts later\n+\t\t\t * than the current path.\n+\t\t\t */\n+\n+\t\t\t/*\n+\t\t\t * Does match sort strictly earlier than path\n+\t\t\t * with their common parts?\n+\t\t\t */\n+\t\t\tm = strncmp(match, path,\n+\t\t\t\t    (matchlen < pathlen) ? matchlen : pathlen);\n+\t\t\tif (m < 0)\n+\t\t\t\tcontinue;\n+\n+\t\t\t/*\n+\t\t\t * If we come here even once, that means there is at\n+\t\t\t * least one pathspec that would sort equal to or\n+\t\t\t * later than the path we are currently looking at.\n+\t\t\t * In other words, if we have never reached this point\n+\t\t\t * after iterating all pathspecs, it means all\n+\t\t\t * pathspecs are either outside of base, or inside the\n+\t\t\t * base but sorts strictly earlier than the current\n+\t\t\t * one.  In either case, they will never match the\n+\t\t\t * subsequent entries.  In such a case, we initialized\n+\t\t\t * the variable to -1 and that is what will be\n+\t\t\t * returned, allowing the caller to terminate early.\n+\t\t\t */\n+\t\t\tnever_interesting = 0;\n+\t\t}\n+\n+\t\tif (pathlen > matchlen)\n+\t\t\tcontinue;\n+\n+\t\tif (matchlen > pathlen) {\n+\t\t\tif (match[pathlen] != '/')\n+\t\t\t\tcontinue;\n+\t\t\tif (!S_ISDIR(mode))\n+\t\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (m == -1)\n+\t\t\t/*\n+\t\t\t * we cheated and did not do strncmp(), so we do\n+\t\t\t * that here.\n+\t\t\t */\n+\t\t\tm = strncmp(match, path, pathlen);\n+\n+\t\t/*\n+\t\t * If common part matched earlier then it is a hit,\n+\t\t * because we rejected the case where path is not a\n+\t\t * leading directory and is shorter than match.\n+\t\t */\n+\t\tif (!m)\n+\t\t\treturn 1;\n+\t}\n+\treturn never_interesting; /* No matches */\n+}\ndiff --git a/tree-walk.h b/tree-walk.h\nindex 88ea7e9..0572721 100644\n--- a/tree-walk.h\n+++ b/tree-walk.h\n@@ -57,4 +57,7 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru\n \treturn info->pathlen + tree_entry_len(n->path, n->sha1);\n }\n \n+struct diff_options;\n+extern int tree_entry_interesting(struct tree_desc *desc, const char *base, int baselen, struct diff_options *opt);\n+\n #endif\n-- \n1.7.1.rc1.69.g24c2f7\n"},{"id":"150266","messageId":"1283874483-32017-5-git-send-email-pclouds@gmail.com","threadId":"25030","inReplyTo":"1283874483-32017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 4/5] tree_entry_interesting(): remove dependency on struct diff_options","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-07T15:48:02Z","receivedAt":"2010-09-07T15:48:02Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This function can be potentially used in more places than just\ntree-diff.c. \"struct diff_options\" does not make much sense outside\ndiff_tree_sha1().\n\nMoreover people seem to be agree that diff machinery should learn\nproper pathspecs too (i.e. glob support [1] and stuff), not just\ntreating pathspecs as tree prefix.\n\nSo instead of using pathspecs in\ndiff_options.{nr_paths,paths,pathlens}, tree_entry_interesting() now\nuses struct exclude_list.\n\nStruct exclude_list is also added to diff_options with the intention\nto replace {nr_paths,paths,pathlens} later on. But for now, it's just\na temporary field.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n diff.h      |    3 +++\n tree-diff.c |   31 ++++++++++++++++++++++++++++---\n tree-walk.c |   26 +++++++++++---------------\n tree-walk.h |    5 +++--\n 4 files changed, 45 insertions(+), 20 deletions(-)\n\ndiff --git a/diff.h b/diff.h\nindex bf2f44d..bd8fe9e 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -5,6 +5,7 @@\n #define DIFF_H\n \n #include \"tree-walk.h\"\n+#include \"dir.h\"\n \n struct rev_info;\n struct diff_options;\n@@ -136,6 +137,7 @@ struct diff_options {\n \tint nr_paths;\n \tconst char **paths;\n \tint *pathlens;\n+\tstruct exclude_list el;\n \tchange_fn_t change;\n \tadd_remove_fn_t add_remove;\n \tdiff_format_fn_t format_callback;\n@@ -163,6 +165,7 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix);\n extern const char mime_boundary_leader[];\n \n extern void diff_tree_setup_paths(const char **paths, struct diff_options *);\n+extern void diff_tree_setup_exclude_list(struct diff_options *);\n extern void diff_tree_release_paths(struct diff_options *);\n extern int diff_tree(struct tree_desc *t1, struct tree_desc *t2,\n \t\t     const char *base, struct diff_options *opt);\ndiff --git a/tree-diff.c b/tree-diff.c\nindex c74d0b5..c2951af 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -92,8 +92,7 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_\n \t\tif (all_interesting)\n \t\t\tshow = 1;\n \t\telse {\n-\t\t\tshow = tree_entry_interesting(desc, base, baselen,\n-\t\t\t\t\t\t      opt);\n+\t\t\tshow = tree_entry_interesting(&desc->entry, base, baselen, &opt->el);\n \t\t\tif (show == 2)\n \t\t\t\tall_interesting = 1;\n \t\t}\n@@ -152,7 +151,7 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele\n \t\tif (all_interesting)\n \t\t\tshow = 1;\n \t\telse {\n-\t\t\tshow = tree_entry_interesting(t, base, baselen, opt);\n+\t\t\tshow = tree_entry_interesting(&t->entry, base, baselen, &opt->el);\n \t\t\tif (show == 2)\n \t\t\t\tall_interesting = 1;\n \t\t}\n@@ -167,10 +166,34 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele\n \t}\n }\n \n+void diff_tree_setup_exclude_list(struct diff_options *opt)\n+{\n+\tint i, size1, size2;\n+\n+\tmemset(&opt->el, 0, sizeof(opt->el));\n+\topt->el.nr = opt->nr_paths;\n+\tif (!opt->el.nr)\n+\t\treturn;\n+\n+\tsize1 = opt->el.nr * sizeof(struct exclude *);\n+\tsize2 = opt->el.nr * sizeof(struct exclude);\n+\topt->el.excludes = xmalloc(size1+size2);\n+\tmemset(opt->el.excludes, 0, size1+size2);\n+\tfor (i=0; i < opt->el.nr; i++) {\n+\t\tstruct exclude *exc = ((struct exclude *)((char*)opt->el.excludes+size1))+i;\n+\t\texc->base = opt->paths[i];\n+\t\texc->baselen = opt->pathlens[i];\n+\t\topt->el.excludes[i] = exc;\n+\t}\n+}\n+\n int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)\n {\n \tint baselen = strlen(base);\n+\tstruct exclude_list el;\n \n+\tel = opt->el; /* diff_tree() can be nested, save and restore opt->el later */\n+\tdiff_tree_setup_exclude_list(opt);\n \tfor (;;) {\n \t\tif (DIFF_OPT_TST(opt, QUICK) &&\n \t\t    DIFF_OPT_TST(opt, HAS_CHANGES))\n@@ -204,6 +227,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru\n \t\t}\n \t\tdie(\"git diff-tree: internal error\");\n \t}\n+\tfree(opt->el.excludes);\n+\topt->el = el;\n \treturn 0;\n }\n \ndiff --git a/tree-walk.c b/tree-walk.c\nindex bc83fa3..c915218 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -2,7 +2,7 @@\n #include \"tree-walk.h\"\n #include \"unpack-trees.h\"\n #include \"tree.h\"\n-#include \"diff.h\"\n+#include \"dir.h\"\n \n static const char *get_mode(const char *str, unsigned int *modep)\n {\n@@ -466,25 +466,21 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch\n  *  - zero for no\n  *  - negative for \"no, and no subsequent entries will be either\"\n  */\n-static int tree_entry_interesting(struct tree_desc *desc, const char *base, int baselen, struct diff_options *opt)\n+int tree_entry_interesting(const struct name_entry *entry, const char *base, int baselen,\n+\t\t\t   const struct exclude_list *el)\n {\n-\tconst char *path;\n-\tconst unsigned char *sha1;\n-\tunsigned mode;\n \tint i;\n \tint pathlen;\n \tint never_interesting = -1;\n \n-\tif (!opt->nr_paths)\n+\tif (!el->nr)\n \t\treturn 1;\n \n-\tsha1 = tree_entry_extract(desc, &path, &mode);\n-\n-\tpathlen = tree_entry_len(path, sha1);\n+\tpathlen = tree_entry_len(entry->path, entry->sha1);\n \n-\tfor (i = 0; i < opt->nr_paths; i++) {\n-\t\tconst char *match = opt->paths[i];\n-\t\tint matchlen = opt->pathlens[i];\n+\tfor (i = 0; i < el->nr; i++) {\n+\t\tconst char *match = el->excludes[i]->base;\n+\t\tint matchlen = el->excludes[i]->baselen;\n \t\tint m = -1; /* signals that we haven't called strncmp() */\n \n \t\tif (baselen >= matchlen) {\n@@ -522,7 +518,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int\n \t\t\t * Does match sort strictly earlier than path\n \t\t\t * with their common parts?\n \t\t\t */\n-\t\t\tm = strncmp(match, path,\n+\t\t\tm = strncmp(match, entry->path,\n \t\t\t\t    (matchlen < pathlen) ? matchlen : pathlen);\n \t\t\tif (m < 0)\n \t\t\t\tcontinue;\n@@ -549,7 +545,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int\n \t\tif (matchlen > pathlen) {\n \t\t\tif (match[pathlen] != '/')\n \t\t\t\tcontinue;\n-\t\t\tif (!S_ISDIR(mode))\n+\t\t\tif (!S_ISDIR(entry->mode))\n \t\t\t\tcontinue;\n \t\t}\n \n@@ -558,7 +554,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int\n \t\t\t * we cheated and did not do strncmp(), so we do\n \t\t\t * that here.\n \t\t\t */\n-\t\t\tm = strncmp(match, path, pathlen);\n+\t\t\tm = strncmp(match, entry->path, pathlen);\n \n \t\t/*\n \t\t * If common part matched earlier then it is a hit,\ndiff --git a/tree-walk.h b/tree-walk.h\nindex 0572721..4b37671 100644\n--- a/tree-walk.h\n+++ b/tree-walk.h\n@@ -57,7 +57,8 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru\n \treturn info->pathlen + tree_entry_len(n->path, n->sha1);\n }\n \n-struct diff_options;\n-extern int tree_entry_interesting(struct tree_desc *desc, const char *base, int baselen, struct diff_options *opt);\n+struct exclude_list;\n+extern int tree_entry_interesting(const struct name_entry *entry, const char *base, int baselen,\n+\t\t\t\t  const struct exclude_list *el);\n \n #endif\n-- \n1.7.1.rc1.69.g24c2f7\n"},{"id":"150267","messageId":"1283874483-32017-6-git-send-email-pclouds@gmail.com","threadId":"25030","inReplyTo":"1283874483-32017-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 5/5] Make rev-list --objects work together with pathspecs","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-07T15:48:03Z","receivedAt":"2010-09-07T15:48:03Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"From: Elijah Newren <newren@gmail.com>\n\nWhen traversing commits, the selection of commits would heed the list of\npathspecs passed, but subsequent walking of the trees of those commits\nwould not.  This resulted in 'rev-list --objects HEAD -- <paths>'\ndisplaying objects at unwanted paths.\n\nHave process_tree() call tree_entry_interesting() to determine which paths\nare interesting and should be walked.\n\nNaturally, this change can provide a large speedup when paths are specified\ntogether with --objects, since many tree entries are now correctly ignored.\nInterestingly, though, this change also gives me a small (~1%) but\nrepeatable speedup even when no paths are specified with --objects.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n list-objects.c           |   25 +++++++++++++++++++++++++\n revision.c               |    8 ++++++--\n revision.h               |    3 ++-\n t/t6000-rev-list-misc.sh |    6 +++---\n 4 files changed, 36 insertions(+), 6 deletions(-)\n\ndiff --git a/list-objects.c b/list-objects.c\nindex 8953548..44efca3 100644\n--- a/list-objects.c\n+++ b/list-objects.c\n@@ -67,6 +67,9 @@ static void process_tree(struct rev_info *revs,\n \tstruct tree_desc desc;\n \tstruct name_entry entry;\n \tstruct name_path me;\n+\tint all_interesting = (revs->diffopt.nr_paths == 0);\n+\tchar *full_prefix = NULL;\n+\tint full_prefix_len = 0;\n \n \tif (!revs->tree_objects)\n \t\treturn;\n@@ -82,9 +85,28 @@ static void process_tree(struct rev_info *revs,\n \tme.elem = name;\n \tme.elem_len = strlen(name);\n \n+\tif (!all_interesting) {\n+\t\tfull_prefix = path_name_impl(path, name, 1);\n+\t\tfull_prefix_len = strlen(full_prefix);\n+\t}\n+\n \tinit_tree_desc(&desc, tree->buffer, tree->size);\n \n \twhile (tree_entry(&desc, &entry)) {\n+\t\tif (!all_interesting) {\n+\t\t\tint showit = tree_entry_interesting(&entry,\n+\t\t\t\t\t\t\t    full_prefix,\n+\t\t\t\t\t\t\t    full_prefix_len,\n+\t\t\t\t\t\t\t    &revs->diffopt.el);\n+\n+\t\t\tif (showit < 0)\n+\t\t\t\tbreak;\n+\t\t\telse if (!showit)\n+\t\t\t\tcontinue;\n+\t\t\telse if (showit == 2)\n+\t\t\t\tall_interesting = 1;\n+\t\t}\n+\n \t\tif (S_ISDIR(entry.mode))\n \t\t\tprocess_tree(revs,\n \t\t\t\t     lookup_tree(entry.sha1),\n@@ -97,6 +119,7 @@ static void process_tree(struct rev_info *revs,\n \t\t\t\t     lookup_blob(entry.sha1),\n \t\t\t\t     show, &me, entry.path);\n \t}\n+\tfree(full_prefix);\n \tfree(tree->buffer);\n \ttree->buffer = NULL;\n }\n@@ -147,6 +170,7 @@ void traverse_commit_list(struct rev_info *revs,\n \tint i;\n \tstruct commit *commit;\n \n+\tdiff_tree_setup_exclude_list(&revs->diffopt);\n \twhile ((commit = get_revision(revs)) != NULL) {\n \t\tadd_pending_tree(revs, commit->tree);\n \t\tshow_commit(commit, data);\n@@ -181,4 +205,5 @@ void traverse_commit_list(struct rev_info *revs,\n \t\trevs->pending.alloc = 0;\n \t\trevs->pending.objects = NULL;\n \t}\n+\tfree(revs->diffopt.el.excludes);\n }\ndiff --git a/revision.c b/revision.c\nindex b1c1890..55c4586 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -16,7 +16,7 @@\n \n volatile show_early_output_fn_t show_early_output;\n \n-char *path_name(const struct name_path *path, const char *name)\n+char *path_name_impl(const struct name_path *path, const char *name, int isdir)\n {\n \tconst struct name_path *p;\n \tchar *n, *m;\n@@ -27,7 +27,7 @@ char *path_name(const struct name_path *path, const char *name)\n \t\tif (p->elem_len)\n \t\t\tlen += p->elem_len + 1;\n \t}\n-\tn = xmalloc(len);\n+\tn = xmalloc(len + !!isdir);\n \tm = n + len - (nlen + 1);\n \tstrcpy(m, name);\n \tfor (p = path; p; p = p->up) {\n@@ -37,6 +37,10 @@ char *path_name(const struct name_path *path, const char *name)\n \t\t\tm[p->elem_len] = '/';\n \t\t}\n \t}\n+\tif (isdir && len > 1) {\n+\t\tn[len-1] = '/';\n+\t\tn[len] = '\\0';\n+\t}\n \treturn n;\n }\n \ndiff --git a/revision.h b/revision.h\nindex 05659c6..92f4feb 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -173,7 +173,8 @@ struct name_path {\n \tconst char *elem;\n };\n \n-char *path_name(const struct name_path *path, const char *name);\n+char *path_name_impl(const struct name_path *path, const char *name, int isdir);\n+#define path_name(path, name) path_name_impl(path, name, 0)\n \n extern void add_object(struct object *obj,\n \t\t       struct object_array *p,\ndiff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh\nindex b3c1dd8..b10685a 100755\n--- a/t/t6000-rev-list-misc.sh\n+++ b/t/t6000-rev-list-misc.sh\n@@ -11,13 +11,13 @@ test_expect_success setup '\n \tgit commit -m one\n '\n \n-test_expect_failure 'rev-list --objects heeds pathspecs' '\n+test_expect_success 'rev-list --objects heeds pathspecs' '\n \tgit rev-list --objects HEAD -- wanted_file >output &&\n \tgrep wanted_file output &&\n \t! grep unwanted_file output\n '\n \n-test_expect_failure 'rev-list --objects with pathspecs and deeper paths' '\n+test_expect_success 'rev-list --objects with pathspecs and deeper paths' '\n \tmkdir foo &&\n \t>foo/file &&\n \tgit add foo/file &&\n@@ -31,7 +31,7 @@ test_expect_failure 'rev-list --objects with pathspecs and deeper paths' '\n \t! grep unwanted_file output\n '\n \n-test_expect_failure 'rev-list --objects with pathspecs and copied files' '\n+test_expect_success 'rev-list --objects with pathspecs and copied files' '\n \tgit checkout --orphan junio-testcase &&\n \tgit rm -rf . &&\n \n-- \n1.7.1.rc1.69.g24c2f7\n"},{"id":"150284","messageId":"AANLkTimFRUfK2+yNGkgJX8K-0N5QYOp4ud2O7afH_iNz@mail.gmail.com","threadId":"25030","inReplyTo":"1283874483-32017-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 0/5] en/object-list-with-pathspec (v3?)","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2010-09-08T07:47:21Z","receivedAt":"2010-09-08T07:47:21Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"2010/9/7 Nguyễn Thái Ngọc Duy <pclouds@gmail.com>:\n> Changes from last time is tree_entry_interesting() now takes\n> struct exclude * as the pathspecs.\n>\n> I think there'll be a bit of performance loss because diff_options.el\n> is not initialized from the beginning. But that requires more changes\n> outside tree-diff.c (makes sure that diff_options.el is copied properly,\n> makes sure that diff_tree_setup_* is called ...) So one step at a time.\n> I'm working on it.\n\nLooks reasonable to me so far.  I believe your series already makes\nnr_paths, paths, and pathlens fields from diff_options unused (other\nthan via exclude_list) -- yes?  If so, that suggests that we could\njust modify diff_tree_setup_paths() to do the work that your new\ndiff_tree_setup_exclude_lists() is doing (and to take an exclude_list*\ninstead of a diff_options*).  Then you wouldn't need to worry about\ndoing the setup \"on-the-fly\" and the performance differences should go\naway.\n\nAm I understanding correctly, and is that the route you're going?\n"},{"id":"150288","messageId":"AANLkTi=xHCXZKjuGrjYmFS_yH4RaSPtgA1QFzVrGgVuZ@mail.gmail.com","threadId":"25030","inReplyTo":"AANLkTimFRUfK2+yNGkgJX8K-0N5QYOp4ud2O7afH_iNz@mail.gmail.com","subject":"Re: [PATCH 0/5] en/object-list-with-pathspec (v3?)","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-08T09:58:00Z","receivedAt":"2010-09-08T09:58:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"2010/9/8 Elijah Newren <newren@gmail.com>:\n> 2010/9/7 Nguyễn Thái Ngọc Duy <pclouds@gmail.com>:\n>> Changes from last time is tree_entry_interesting() now takes\n>> struct exclude * as the pathspecs.\n>>\n>> I think there'll be a bit of performance loss because diff_options.el\n>> is not initialized from the beginning. But that requires more changes\n>> outside tree-diff.c (makes sure that diff_options.el is copied properly,\n>> makes sure that diff_tree_setup_* is called ...) So one step at a time.\n>> I'm working on it.\n>\n> Looks reasonable to me so far.  I believe your series already makes\n> nr_paths, paths, and pathlens fields from diff_options unused (other\n> than via exclude_list) -- yes?  If so, that suggests that we could\n> just modify diff_tree_setup_paths() to do the work that your new\n> diff_tree_setup_exclude_lists() is doing (and to take an exclude_list*\n> instead of a diff_options*).  Then you wouldn't need to worry about\n> doing the setup \"on-the-fly\" and the performance differences should go\n> away.\n\nThey are used elsewhere, passed around as prune data, even fed to\nread_cache_preload().. so they won't go away soon.\n\n> Am I understanding correctly, and is that the route you're going?\n\nYes. Except that both nr_paths, paths and pathlens will stay along with\nexclude_list. Getting rid of \"paths\" takes time (the other two fields are\neasier to deal with).\n-- \nDuy\n"}]}