From 0cdca133ec8aa10fe4c806f6695ccbf32394aa91 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Thu, 6 May 2010 21:52:29 -0700 Subject: Make git log --follow find copies among unmodified files. 'git log --follow ' don't track copies from unmodified files, and this patch fix it. Signed-off-by: Bo Yang Signed-off-by: Junio C Hamano --- tree-diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tree-diff.c') diff --git a/tree-diff.c b/tree-diff.c index fe9f52c479..1fb3e94614 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -346,7 +346,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co diff_setup(&diff_opts); DIFF_OPT_SET(&diff_opts, RECURSIVE); - diff_opts.detect_rename = DIFF_DETECT_RENAME; + DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER); diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; diff_opts.single_follow = opt->paths[0]; diff_opts.break_opt = opt->break_opt; -- cgit v1.3 From 39f75d26e235798681394e46625716c187a4ee3e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 13 Aug 2010 10:36:01 -0700 Subject: diff --follow: do not waste cycles while recursing The "--follow" logic is called from diff_tree_sha1() function, but the input trees to diff_tree_sha1() are not necessarily the top-level trees (compare_tree_entry() calls it while it recursively descends into subtrees). When a newly created path lives in somewhere deep in the source hierarchy, e.g. "platform/", but the rename source is in a totally different place in the destination hierarchy, e.g. "lang-api/src/com/...", running "try_to_find_renames()" while base is set to "platform/" is a wasted call. We only need to run the rename following at the very top level. Signed-off-by: Junio C Hamano Acked-by: Linus Torvalds --- tree-diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tree-diff.c') diff --git a/tree-diff.c b/tree-diff.c index 1fb3e94614..5b68c0864c 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -412,7 +412,7 @@ int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const cha init_tree_desc(&t1, tree1, size1); init_tree_desc(&t2, tree2, size2); retval = diff_tree(&t1, &t2, base, opt); - if (DIFF_OPT_TST(opt, FOLLOW_RENAMES) && diff_might_be_rename()) { + if (!*base && DIFF_OPT_TST(opt, FOLLOW_RENAMES) && diff_might_be_rename()) { init_tree_desc(&t1, tree1, size1); init_tree_desc(&t2, tree2, size2); try_to_follow_renames(&t1, &t2, base, opt); -- cgit v1.3 From 44c48a909ae3d49afcaedb2b2cd042d1e329ee93 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 13 Aug 2010 12:17:45 -0700 Subject: diff --follow: do call diffcore_std() as necessary Usually, diff frontends populate the output queue with filepairs without any rename information and call diffcore_std() to sort the renames out. When --follow is in effect, however, diff-tree family of frontend has a hack that looks like this: diff-tree frontend -> diff_tree_sha1() . populate diff_queued_diff . if --follow is in effect and there is only one change that creates the target path, then -> try_to_follow_renames() -> diff_tree_sha1() with no pathspec but with -C -> diffcore_std() to find renames . if rename is found, tweak diff_queued_diff and put a single filepair that records the found rename there -> diffcore_std() . tweak elements on diff_queued_diff by - rename detection - path ordering - pickaxe filtering We need to skip parts of the second call to diffcore_std() that is related to rename detection, and do so only when try_to_follow_renames() did find a rename. Earlier 1da6175 (Make diffcore_std only can run once before a diff_flush, 2010-05-06) tried to deal with this issue incorrectly; it unconditionally disabled any second call to diffcore_std(). This hopefully fixes the breakage. Signed-off-by: Junio C Hamano --- diff.c | 27 +++++++++++++-------------- diff.h | 3 +++ diffcore.h | 2 -- tree-diff.c | 11 +++++++++++ 4 files changed, 27 insertions(+), 16 deletions(-) (limited to 'tree-diff.c') diff --git a/diff.c b/diff.c index bf65892f78..93004922de 100644 --- a/diff.c +++ b/diff.c @@ -4064,25 +4064,24 @@ void diffcore_fix_diff_index(struct diff_options *options) void diffcore_std(struct diff_options *options) { - /* We never run this function more than one time, because the - * rename/copy detection logic can only run once. - */ - if (diff_queued_diff.run) - return; - if (options->skip_stat_unmatch) diffcore_skip_stat_unmatch(options); - if (options->break_opt != -1) - diffcore_break(options->break_opt); - if (options->detect_rename) - diffcore_rename(options); - if (options->break_opt != -1) - diffcore_merge_broken(); + if (!options->found_follow) { + /* See try_to_follow_renames() in tree-diff.c */ + if (options->break_opt != -1) + diffcore_break(options->break_opt); + if (options->detect_rename) + diffcore_rename(options); + if (options->break_opt != -1) + diffcore_merge_broken(); + } if (options->pickaxe) diffcore_pickaxe(options->pickaxe, options->pickaxe_opts); if (options->orderfile) diffcore_order(options->orderfile); - diff_resolve_rename_copy(); + if (!options->found_follow) + /* See try_to_follow_renames() in tree-diff.c */ + diff_resolve_rename_copy(); diffcore_apply_filter(options->filter); if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) @@ -4090,7 +4089,7 @@ void diffcore_std(struct diff_options *options) else DIFF_OPT_CLR(options, HAS_CHANGES); - diff_queued_diff.run = 1; + options->found_follow = 0; } int diff_result_code(struct diff_options *opt, int status) diff --git a/diff.h b/diff.h index 063d10ac22..6fff024e3a 100644 --- a/diff.h +++ b/diff.h @@ -126,6 +126,9 @@ struct diff_options { /* this is set by diffcore for DIFF_FORMAT_PATCH */ int found_changes; + /* to support internal diff recursion by --follow hack*/ + int found_follow; + FILE *file; int close_file; diff --git a/diffcore.h b/diffcore.h index 05ebc115a1..8b3241ad13 100644 --- a/diffcore.h +++ b/diffcore.h @@ -91,13 +91,11 @@ struct diff_queue_struct { struct diff_filepair **queue; int alloc; int nr; - int run; }; #define DIFF_QUEUE_CLEAR(q) \ do { \ (q)->queue = NULL; \ (q)->nr = (q)->alloc = 0; \ - (q)->run = 0; \ } while (0) extern struct diff_queue_struct diff_queued_diff; diff --git a/tree-diff.c b/tree-diff.c index 5b68c0864c..cd659c6fe4 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -359,6 +359,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co diff_tree_release_paths(&diff_opts); /* Go through the new set of filepairing, and see if we find a more interesting one */ + opt->found_follow = 0; for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; @@ -376,6 +377,16 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co diff_tree_release_paths(opt); opt->paths[0] = xstrdup(p->one->path); diff_tree_setup_paths(opt->paths, opt); + + /* + * The caller expects us to return a set of vanilla + * filepairs to let a later call to diffcore_std() + * it makes to sort the renames out (among other + * things), but we already have found renames + * ourselves; signal diffcore_std() not to muck with + * rename information. + */ + opt->found_follow = 1; break; } } -- cgit v1.3 From b6b987a09457e9c8d49aad9170df32b1f607c5b9 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Thu, 26 Aug 2010 00:21:46 -0600 Subject: Document pre-condition for tree_entry_interesting tree_entry_interesting will fail to find appropriate matches if the base directory path is not terminated with a slash. Knowing this earlier would have saved me some debugging time. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- tree-diff.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tree-diff.c') diff --git a/tree-diff.c b/tree-diff.c index fe9f52c479..4d85fef5d0 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -85,6 +85,8 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const /* * Is a tree entry interesting given the pathspec we have? * + * Pre-condition: baselen == 0 || base[baselen-1] == '/' + * * Return: * - 2 for "yes, and all subsequent entries will be" * - 1 for yes -- cgit v1.3 From 4a5e74feb1a75a479acbc2f839e930966fdc2f2f Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Thu, 26 Aug 2010 00:21:48 -0600 Subject: tree_entry_interesting(): Make return value more specific tree_entry_interesting() can signal to its callers not only if the given entry matches one of the specified paths, but whether all remaining paths will (or will not) match. When no paths are specified, all paths are considered interesting, so intead of returning 1 (this path is interesting) return 2 (all paths are interesting). This will allow the caller to avoid calling tree_entry_interesting() again, which theoretically should speed up tree walking. I am not able to measure any actual gains in practice, but it certainly can not hurt and seems to make the code more readable to me. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- tree-diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tree-diff.c') diff --git a/tree-diff.c b/tree-diff.c index 4d85fef5d0..1b41b7f450 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -103,7 +103,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int int never_interesting = -1; if (!opt->nr_paths) - return 1; + return 2; sha1 = tree_entry_extract(desc, &path, &mode); -- cgit v1.3 From 7e1ec0d415dbea96d4ec6995c00cb66cdff7ceff Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Thu, 26 Aug 2010 00:21:49 -0600 Subject: diff_tree(): Skip skip_uninteresting() when all remaining paths interesting In 1d848f6 (tree_entry_interesting(): allow it to say "everything is interesting" 2007-03-21), both show_tree() and skip_uninteresting() were modified to determine if all remaining tree entries were interesting. However, the latter returns as soon as it finds the first interesting path, without any way to signal to its caller (namely, diff_tree()) that all remaining paths are interesting, making these extra checks useless. Pass whether all remaining entries are interesting back to diff_tree(), and whenever they are, have diff_tree() skip subsequent calls to skip_uninteresting(). With this change, I measure speedups of 3-4% for the commands $ git rev-list --quiet HEAD -- Documentation/ $ git rev-list --quiet HEAD -- t/ in git.git. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano --- tree-diff.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'tree-diff.c') diff --git a/tree-diff.c b/tree-diff.c index 1b41b7f450..f6a6b2f71f 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -259,19 +259,12 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree } } -static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt) +static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt, int *all_interesting) { - int all_interesting = 0; while (t->size) { - int show; - - if (all_interesting) - show = 1; - else { - show = tree_entry_interesting(t, base, baselen, opt); - if (show == 2) - all_interesting = 1; - } + int show = tree_entry_interesting(t, base, baselen, opt); + if (show == 2) + *all_interesting = 1; if (!show) { update_tree_entry(t); continue; @@ -286,14 +279,20 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt) { int baselen = strlen(base); + int all_t1_interesting = 0; + int all_t2_interesting = 0; for (;;) { if (DIFF_OPT_TST(opt, QUICK) && DIFF_OPT_TST(opt, HAS_CHANGES)) break; if (opt->nr_paths) { - skip_uninteresting(t1, base, baselen, opt); - skip_uninteresting(t2, base, baselen, opt); + if (!all_t1_interesting) + skip_uninteresting(t1, base, baselen, opt, + &all_t1_interesting); + if (!all_t2_interesting) + skip_uninteresting(t2, base, baselen, opt, + &all_t2_interesting); } if (!t1->size) { if (!t2->size) -- cgit v1.3 From 66f136252fe1998e2c1381c913795b5f56b6dc8c Mon Sep 17 00:00:00 2001 From: Nguyễn Thái Ngọc Duy Date: Wed, 15 Dec 2010 22:02:38 +0700 Subject: Convert struct diff_options to use struct pathspec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/diff-files.c | 2 +- builtin/diff.c | 4 ++-- builtin/log.c | 2 +- diff-lib.c | 2 +- diff-no-index.c | 4 ++-- diff.h | 4 +--- revision.c | 6 +----- tree-diff.c | 48 +++++++++++++----------------------------------- 8 files changed, 22 insertions(+), 50 deletions(-) (limited to 'tree-diff.c') diff --git a/builtin/diff-files.c b/builtin/diff-files.c index 951c7c8994..46085f862f 100644 --- a/builtin/diff-files.c +++ b/builtin/diff-files.c @@ -61,7 +61,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) (rev.diffopt.output_format & DIFF_FORMAT_PATCH)) rev.combine_merges = rev.dense_combined_merges = 1; - if (read_cache_preload(rev.diffopt.paths) < 0) { + if (read_cache_preload(rev.diffopt.pathspec.raw) < 0) { perror("read_cache_preload"); return -1; } diff --git a/builtin/diff.c b/builtin/diff.c index 945e7583a8..a08c3240d5 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -135,7 +135,7 @@ static int builtin_diff_index(struct rev_info *revs, revs->max_count != -1 || revs->min_age != -1 || revs->max_age != -1) usage(builtin_diff_usage); - if (read_cache_preload(revs->diffopt.paths) < 0) { + if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) { perror("read_cache_preload"); return -1; } @@ -237,7 +237,7 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv revs->combine_merges = revs->dense_combined_merges = 1; setup_work_tree(); - if (read_cache_preload(revs->diffopt.paths) < 0) { + if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) { perror("read_cache_preload"); return -1; } diff --git a/builtin/log.c b/builtin/log.c index d8c6c28d2f..f5ed690c43 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -89,7 +89,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, rev->always_show_header = 0; if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) { rev->always_show_header = 0; - if (rev->diffopt.nr_paths != 1) + if (rev->diffopt.pathspec.nr != 1) usage("git logs can only follow renames on one pathname at a time"); } for (i = 1; i < argc; i++) { diff --git a/diff-lib.c b/diff-lib.c index 392ce2bef0..3b809f2e0d 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -501,7 +501,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt) active_nr = dst - active_cache; init_revisions(&revs, NULL); - revs.prune_data = opt->paths; + revs.prune_data = opt->pathspec.raw; tree = parse_tree_indirect(tree_sha1); if (!tree) die("bad tree object %s", sha1_to_hex(tree_sha1)); diff --git a/diff-no-index.c b/diff-no-index.c index e48ab92ba1..3a36144687 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -260,8 +260,8 @@ void diff_no_index(struct rev_info *revs, if (diff_setup_done(&revs->diffopt) < 0) die("diff_setup_done failed"); - if (queue_diff(&revs->diffopt, revs->diffopt.paths[0], - revs->diffopt.paths[1])) + if (queue_diff(&revs->diffopt, revs->diffopt.pathspec.raw[0], + revs->diffopt.pathspec.raw[1])) exit(1); diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/"); diffcore_std(&revs->diffopt); diff --git a/diff.h b/diff.h index 0083d92438..310bd6b283 100644 --- a/diff.h +++ b/diff.h @@ -133,9 +133,7 @@ struct diff_options { FILE *file; int close_file; - int nr_paths; - const char **paths; - int *pathlens; + struct pathspec pathspec; change_fn_t change; add_remove_fn_t add_remove; diff_format_fn_t format_callback; diff --git a/revision.c b/revision.c index 7b9eaefae4..0c511aa44b 100644 --- a/revision.c +++ b/revision.c @@ -553,11 +553,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) left_first = left_count < right_count; init_patch_ids(&ids); - if (revs->diffopt.nr_paths) { - ids.diffopts.nr_paths = revs->diffopt.nr_paths; - ids.diffopts.paths = revs->diffopt.paths; - ids.diffopts.pathlens = revs->diffopt.pathlens; - } + ids.diffopts.pathspec = revs->diffopt.pathspec; /* Compute patch-ids for one side */ for (p = list; p; p = p->next) { diff --git a/tree-diff.c b/tree-diff.c index 12c9a88884..f6b4aa4caa 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -102,16 +102,17 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int int pathlen; int never_interesting = -1; - if (!opt->nr_paths) + if (!opt->pathspec.nr) return 2; sha1 = tree_entry_extract(desc, &path, &mode); pathlen = tree_entry_len(path, sha1); - for (i = 0; i < opt->nr_paths; i++) { - const char *match = opt->paths[i]; - int matchlen = opt->pathlens[i]; + for (i = 0; i < opt->pathspec.nr; i++) { + const struct pathspec_item *item = opt->pathspec.items+i; + const char *match = item->match; + int matchlen = item->len; int m = -1; /* signals that we haven't called strncmp() */ if (baselen >= matchlen) { @@ -286,7 +287,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru if (DIFF_OPT_TST(opt, QUICK) && DIFF_OPT_TST(opt, HAS_CHANGES)) break; - if (opt->nr_paths) { + if (opt->pathspec.nr) { if (!all_t1_interesting) skip_uninteresting(t1, base, baselen, opt, &all_t1_interesting); @@ -349,7 +350,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co DIFF_OPT_SET(&diff_opts, RECURSIVE); DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER); diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT; - diff_opts.single_follow = opt->paths[0]; + diff_opts.single_follow = opt->pathspec.raw[0]; diff_opts.break_opt = opt->break_opt; paths[0] = NULL; diff_tree_setup_paths(paths, &diff_opts); @@ -369,15 +370,16 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co * diff_queued_diff, we will also use that as the path in * the future! */ - if ((p->status == 'R' || p->status == 'C') && !strcmp(p->two->path, opt->paths[0])) { + if ((p->status == 'R' || p->status == 'C') && + !strcmp(p->two->path, opt->pathspec.raw[0])) { /* Switch the file-pairs around */ q->queue[i] = choice; choice = p; /* Update the path we use from now on.. */ diff_tree_release_paths(opt); - opt->paths[0] = xstrdup(p->one->path); - diff_tree_setup_paths(opt->paths, opt); + opt->pathspec.raw[0] = xstrdup(p->one->path); + diff_tree_setup_paths(opt->pathspec.raw, opt); /* * The caller expects us to return a set of vanilla @@ -452,36 +454,12 @@ int diff_root_tree_sha1(const unsigned char *new, const char *base, struct diff_ return retval; } -static int count_paths(const char **paths) -{ - int i = 0; - while (*paths++) - i++; - return i; -} - void diff_tree_release_paths(struct diff_options *opt) { - free(opt->pathlens); + free_pathspec(&opt->pathspec); } void diff_tree_setup_paths(const char **p, struct diff_options *opt) { - opt->nr_paths = 0; - opt->pathlens = NULL; - opt->paths = NULL; - - if (p) { - int i; - - opt->paths = p; - opt->nr_paths = count_paths(p); - if (opt->nr_paths == 0) { - opt->pathlens = NULL; - return; - } - opt->pathlens = xmalloc(opt->nr_paths * sizeof(int)); - for (i=0; i < opt->nr_paths; i++) - opt->pathlens[i] = strlen(p[i]); - } + init_pathspec(&opt->pathspec, p); } -- cgit v1.3 From 475005a11768a3906c42fac55e8b3371794bdef3 Mon Sep 17 00:00:00 2001 From: Nguyễn Thái Ngọc Duy Date: Wed, 15 Dec 2010 22:02:39 +0700 Subject: tree_entry_interesting(): remove dependency on struct diff_options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function can be potentially used in more places than just tree-diff.c. "struct diff_options" does not make much sense outside diff_tree_sha1(). While removing the use of diff_options, it also removes tree_entry_extract() call, which means S_ISDIR() uses the entry->mode directly, without being filtered by canon_mode() (called internally inside tree_entry_extract). The only use of the mode information in this function is to check the type of the entry by giving it to S_ISDIR() macro, and the result does not change with or without canon_mode(), so it is ok to bypass tree_entry_extract(). Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- tree-diff.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'tree-diff.c') diff --git a/tree-diff.c b/tree-diff.c index f6b4aa4caa..281b48c7c0 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -93,24 +93,19 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const * - zero for no * - negative for "no, and no subsequent entries will be either" */ -static int tree_entry_interesting(struct tree_desc *desc, const char *base, int baselen, struct diff_options *opt) +static int tree_entry_interesting(const struct name_entry *entry, const char *base, int baselen, const struct pathspec *ps) { - const char *path; - const unsigned char *sha1; - unsigned mode; int i; int pathlen; int never_interesting = -1; - if (!opt->pathspec.nr) + if (!ps || !ps->nr) return 2; - sha1 = tree_entry_extract(desc, &path, &mode); - - pathlen = tree_entry_len(path, sha1); + pathlen = tree_entry_len(entry->path, entry->sha1); - for (i = 0; i < opt->pathspec.nr; i++) { - const struct pathspec_item *item = opt->pathspec.items+i; + for (i = 0; i < ps->nr; i++) { + const struct pathspec_item *item = ps->items+i; const char *match = item->match; int matchlen = item->len; int m = -1; /* signals that we haven't called strncmp() */ @@ -150,7 +145,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int * Does match sort strictly earlier than path * with their common parts? */ - m = strncmp(match, path, + m = strncmp(match, entry->path, (matchlen < pathlen) ? matchlen : pathlen); if (m < 0) continue; @@ -177,7 +172,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int if (matchlen > pathlen) { if (match[pathlen] != '/') continue; - if (!S_ISDIR(mode)) + if (!S_ISDIR(entry->mode)) continue; } @@ -186,7 +181,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int * we cheated and did not do strncmp(), so we do * that here. */ - m = strncmp(match, path, pathlen); + m = strncmp(match, entry->path, pathlen); /* * If common part matched earlier then it is a hit, @@ -209,8 +204,7 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_ if (all_interesting) show = 1; else { - show = tree_entry_interesting(desc, base, baselen, - opt); + show = tree_entry_interesting(&desc->entry, base, baselen, &opt->pathspec); if (show == 2) all_interesting = 1; } @@ -263,7 +257,7 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt, int *all_interesting) { while (t->size) { - int show = tree_entry_interesting(t, base, baselen, opt); + int show = tree_entry_interesting(&t->entry, base, baselen, &opt->pathspec); if (show == 2) *all_interesting = 1; if (!show) { -- cgit v1.3 From 2c389fc8ec57722aa1e8f49d316401e2e21d1b05 Mon Sep 17 00:00:00 2001 From: Nguyễn Thái Ngọc Duy Date: Wed, 15 Dec 2010 22:02:40 +0700 Subject: Move tree_entry_interesting() to tree-walk.c and export it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- tree-diff.c | 112 ---------------------------------------------------------- tree-walk.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tree-walk.h | 2 ++ 3 files changed, 116 insertions(+), 112 deletions(-) (limited to 'tree-diff.c') diff --git a/tree-diff.c b/tree-diff.c index 281b48c7c0..23f4478cee 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -82,118 +82,6 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const return 0; } -/* - * Is a tree entry interesting given the pathspec we have? - * - * Pre-condition: baselen == 0 || base[baselen-1] == '/' - * - * Return: - * - 2 for "yes, and all subsequent entries will be" - * - 1 for yes - * - zero for no - * - negative for "no, and no subsequent entries will be either" - */ -static int tree_entry_interesting(const struct name_entry *entry, const char *base, int baselen, const struct pathspec *ps) -{ - int i; - int pathlen; - int never_interesting = -1; - - if (!ps || !ps->nr) - return 2; - - pathlen = tree_entry_len(entry->path, entry->sha1); - - for (i = 0; i < ps->nr; i++) { - const struct pathspec_item *item = ps->items+i; - const char *match = item->match; - int matchlen = item->len; - int m = -1; /* signals that we haven't called strncmp() */ - - if (baselen >= matchlen) { - /* If it doesn't match, move along... */ - if (strncmp(base, match, matchlen)) - continue; - - /* - * If the base is a subdirectory of a path which - * was specified, all of them are interesting. - */ - if (!matchlen || - base[matchlen] == '/' || - match[matchlen - 1] == '/') - return 2; - - /* Just a random prefix match */ - continue; - } - - /* Does the base match? */ - if (strncmp(base, match, baselen)) - continue; - - match += baselen; - matchlen -= baselen; - - if (never_interesting) { - /* - * We have not seen any match that sorts later - * than the current path. - */ - - /* - * Does match sort strictly earlier than path - * with their common parts? - */ - m = strncmp(match, entry->path, - (matchlen < pathlen) ? matchlen : pathlen); - if (m < 0) - continue; - - /* - * If we come here even once, that means there is at - * least one pathspec that would sort equal to or - * later than the path we are currently looking at. - * In other words, if we have never reached this point - * after iterating all pathspecs, it means all - * pathspecs are either outside of base, or inside the - * base but sorts strictly earlier than the current - * one. In either case, they will never match the - * subsequent entries. In such a case, we initialized - * the variable to -1 and that is what will be - * returned, allowing the caller to terminate early. - */ - never_interesting = 0; - } - - if (pathlen > matchlen) - continue; - - if (matchlen > pathlen) { - if (match[pathlen] != '/') - continue; - if (!S_ISDIR(entry->mode)) - continue; - } - - if (m == -1) - /* - * we cheated and did not do strncmp(), so we do - * that here. - */ - m = strncmp(match, entry->path, pathlen); - - /* - * If common part matched earlier then it is a hit, - * because we rejected the case where path is not a - * leading directory and is shorter than match. - */ - if (!m) - return 1; - } - return never_interesting; /* No matches */ -} - /* A whole sub-tree went away or appeared */ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen) { diff --git a/tree-walk.c b/tree-walk.c index a9bbf4e235..522bb6b8f6 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -455,3 +455,117 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch free(tree); return retval; } + +/* + * Is a tree entry interesting given the pathspec we have? + * + * Pre-condition: baselen == 0 || base[baselen-1] == '/' + * + * Return: + * - 2 for "yes, and all subsequent entries will be" + * - 1 for yes + * - zero for no + * - negative for "no, and no subsequent entries will be either" + */ +int tree_entry_interesting(const struct name_entry *entry, + const char *base, int baselen, + const struct pathspec *ps) +{ + int i; + int pathlen; + int never_interesting = -1; + + if (!ps || !ps->nr) + return 2; + + pathlen = tree_entry_len(entry->path, entry->sha1); + + for (i = 0; i < ps->nr; i++) { + const struct pathspec_item *item = ps->items+i; + const char *match = item->match; + int matchlen = item->len; + int m = -1; /* signals that we haven't called strncmp() */ + + if (baselen >= matchlen) { + /* If it doesn't match, move along... */ + if (strncmp(base, match, matchlen)) + continue; + + /* + * If the base is a subdirectory of a path which + * was specified, all of them are interesting. + */ + if (!matchlen || + base[matchlen] == '/' || + match[matchlen - 1] == '/') + return 2; + + /* Just a random prefix match */ + continue; + } + + /* Does the base match? */ + if (strncmp(base, match, baselen)) + continue; + + match += baselen; + matchlen -= baselen; + + if (never_interesting) { + /* + * We have not seen any match that sorts later + * than the current path. + */ + + /* + * Does match sort strictly earlier than path + * with their common parts? + */ + m = strncmp(match, entry->path, + (matchlen < pathlen) ? matchlen : pathlen); + if (m < 0) + continue; + + /* + * If we come here even once, that means there is at + * least one pathspec that would sort equal to or + * later than the path we are currently looking at. + * In other words, if we have never reached this point + * after iterating all pathspecs, it means all + * pathspecs are either outside of base, or inside the + * base but sorts strictly earlier than the current + * one. In either case, they will never match the + * subsequent entries. In such a case, we initialized + * the variable to -1 and that is what will be + * returned, allowing the caller to terminate early. + */ + never_interesting = 0; + } + + if (pathlen > matchlen) + continue; + + if (matchlen > pathlen) { + if (match[pathlen] != '/') + continue; + if (!S_ISDIR(entry->mode)) + continue; + } + + if (m == -1) + /* + * we cheated and did not do strncmp(), so we do + * that here. + */ + m = strncmp(match, entry->path, pathlen); + + /* + * If common part matched earlier then it is a hit, + * because we rejected the case where path is not a + * leading directory and is shorter than match. + */ + if (!m) + return 1; + } + return never_interesting; /* No matches */ +} diff --git a/tree-walk.h b/tree-walk.h index 7e3e0b5ad1..c12f0a2978 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -60,4 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru return info->pathlen + tree_entry_len(n->path, n->sha1); } +extern int tree_entry_interesting(const struct name_entry *, const char *, int, const struct pathspec *ps); + #endif -- cgit v1.3 From 48932677d62e426b3f26ac236384cb5195fb9dfd Mon Sep 17 00:00:00 2001 From: Nguyễn Thái Ngọc Duy Date: Wed, 15 Dec 2010 22:02:42 +0700 Subject: diff-tree: convert base+baselen to writable strbuf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In traversing trees, a full path is splitted into two parts: base directory and entry. They are however quite often concatenated whenever a full path is needed. Current code allocates a new buffer, do two memcpy(), use it, then release. Instead this patch turns "base" to a writable, extendable buffer. When a concatenation is needed, the callee only needs to append "entry" to base, use it, then truncate the entry out again. "base" must remain unchanged before and after entering a function. This avoids quite a bit of malloc() and memcpy(). Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- tree-diff.c | 120 ++++++++++++++++++++++++++---------------------------------- tree-walk.c | 5 ++- tree-walk.h | 2 +- 3 files changed, 56 insertions(+), 71 deletions(-) (limited to 'tree-diff.c') diff --git a/tree-diff.c b/tree-diff.c index 23f4478cee..45a3845c0a 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -6,34 +6,18 @@ #include "diffcore.h" #include "tree.h" -static char *malloc_base(const char *base, int baselen, const char *path, int pathlen) -{ - char *newbase = xmalloc(baselen + pathlen + 2); - memcpy(newbase, base, baselen); - memcpy(newbase + baselen, path, pathlen); - memcpy(newbase + baselen + pathlen, "/", 2); - return newbase; -} +static void show_entry(struct diff_options *opt, const char *prefix, + struct tree_desc *desc, struct strbuf *base); -static char *malloc_fullname(const char *base, int baselen, const char *path, int pathlen) -{ - char *fullname = xmalloc(baselen + pathlen + 1); - memcpy(fullname, base, baselen); - memcpy(fullname + baselen, path, pathlen); - fullname[baselen + pathlen] = 0; - return fullname; -} - -static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, - const char *base, int baselen); - -static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, int baselen, struct diff_options *opt) +static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, + struct strbuf *base, struct diff_options *opt) { unsigned mode1, mode2; const char *path1, *path2; const unsigned char *sha1, *sha2; int cmp, pathlen1, pathlen2; - char *fullname; + int old_baselen = base->len; + int retval = 0; sha1 = tree_entry_extract(t1, &path1, &mode1); sha2 = tree_entry_extract(t2, &path2, &mode2); @@ -42,11 +26,11 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const pathlen2 = tree_entry_len(path2, sha2); cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2); if (cmp < 0) { - show_entry(opt, "-", t1, base, baselen); + show_entry(opt, "-", t1, base); return -1; } if (cmp > 0) { - show_entry(opt, "+", t2, base, baselen); + show_entry(opt, "+", t2, base); return 1; } if (!DIFF_OPT_TST(opt, FIND_COPIES_HARDER) && !hashcmp(sha1, sha2) && mode1 == mode2) @@ -57,33 +41,29 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const * file, we need to consider it a remove and an add. */ if (S_ISDIR(mode1) != S_ISDIR(mode2)) { - show_entry(opt, "-", t1, base, baselen); - show_entry(opt, "+", t2, base, baselen); + show_entry(opt, "-", t1, base); + show_entry(opt, "+", t2, base); return 0; } + strbuf_add(base, path1, pathlen1); if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) { - int retval; - char *newbase = malloc_base(base, baselen, path1, pathlen1); if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { - newbase[baselen + pathlen1] = 0; opt->change(opt, mode1, mode2, - sha1, sha2, newbase, 0, 0); - newbase[baselen + pathlen1] = '/'; + sha1, sha2, base->buf, 0, 0); } - retval = diff_tree_sha1(sha1, sha2, newbase, opt); - free(newbase); - return retval; + strbuf_addch(base, '/'); + retval = diff_tree_sha1(sha1, sha2, base->buf, opt); + } else { + opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0); } - - fullname = malloc_fullname(base, baselen, path1, pathlen1); - opt->change(opt, mode1, mode2, sha1, sha2, fullname, 0, 0); - free(fullname); + strbuf_setlen(base, old_baselen); return 0; } /* A whole sub-tree went away or appeared */ -static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen) +static void show_tree(struct diff_options *opt, const char *prefix, + struct tree_desc *desc, struct strbuf *base) { int all_interesting = 0; while (desc->size) { @@ -92,30 +72,32 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_ if (all_interesting) show = 1; else { - show = tree_entry_interesting(&desc->entry, base, baselen, &opt->pathspec); + show = tree_entry_interesting(&desc->entry, base, + &opt->pathspec); if (show == 2) all_interesting = 1; } if (show < 0) break; if (show) - show_entry(opt, prefix, desc, base, baselen); + show_entry(opt, prefix, desc, base); update_tree_entry(desc); } } /* A file entry went away or appeared */ -static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, - const char *base, int baselen) +static void show_entry(struct diff_options *opt, const char *prefix, + struct tree_desc *desc, struct strbuf *base) { unsigned mode; const char *path; const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode); int pathlen = tree_entry_len(path, sha1); + int old_baselen = base->len; + strbuf_add(base, path, pathlen); if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode)) { enum object_type type; - char *newbase = malloc_base(base, baselen, path, pathlen); struct tree_desc inner; void *tree; unsigned long size; @@ -124,28 +106,25 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree if (!tree || type != OBJ_TREE) die("corrupt tree sha %s", sha1_to_hex(sha1)); - if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { - newbase[baselen + pathlen] = 0; - opt->add_remove(opt, *prefix, mode, sha1, newbase, 0); - newbase[baselen + pathlen] = '/'; - } + if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) + opt->add_remove(opt, *prefix, mode, sha1, base->buf, 0); - init_tree_desc(&inner, tree, size); - show_tree(opt, prefix, &inner, newbase, baselen + 1 + pathlen); + strbuf_addch(base, '/'); + init_tree_desc(&inner, tree, size); + show_tree(opt, prefix, &inner, base); free(tree); - free(newbase); - } else { - char *fullname = malloc_fullname(base, baselen, path, pathlen); - opt->add_remove(opt, prefix[0], mode, sha1, fullname, 0); - free(fullname); - } + } else + opt->add_remove(opt, prefix[0], mode, sha1, base->buf, 0); + + strbuf_setlen(base, old_baselen); } -static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt, int *all_interesting) +static void skip_uninteresting(struct tree_desc *t, struct strbuf *base, + struct diff_options *opt, int *all_interesting) { while (t->size) { - int show = tree_entry_interesting(&t->entry, base, baselen, &opt->pathspec); + int show = tree_entry_interesting(&t->entry, base, &opt->pathspec); if (show == 2) *all_interesting = 1; if (!show) { @@ -159,37 +138,40 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele } } -int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt) +int diff_tree(struct tree_desc *t1, struct tree_desc *t2, + const char *base_str, struct diff_options *opt) { - int baselen = strlen(base); + struct strbuf base; + int baselen = strlen(base_str); int all_t1_interesting = 0; int all_t2_interesting = 0; + strbuf_init(&base, PATH_MAX); + strbuf_add(&base, base_str, baselen); + for (;;) { if (DIFF_OPT_TST(opt, QUICK) && DIFF_OPT_TST(opt, HAS_CHANGES)) break; if (opt->pathspec.nr) { if (!all_t1_interesting) - skip_uninteresting(t1, base, baselen, opt, - &all_t1_interesting); + skip_uninteresting(t1, &base, opt, &all_t1_interesting); if (!all_t2_interesting) - skip_uninteresting(t2, base, baselen, opt, - &all_t2_interesting); + skip_uninteresting(t2, &base, opt, &all_t2_interesting); } if (!t1->size) { if (!t2->size) break; - show_entry(opt, "+", t2, base, baselen); + show_entry(opt, "+", t2, &base); update_tree_entry(t2); continue; } if (!t2->size) { - show_entry(opt, "-", t1, base, baselen); + show_entry(opt, "-", t1, &base); update_tree_entry(t1); continue; } - switch (compare_tree_entry(t1, t2, base, baselen, opt)) { + switch (compare_tree_entry(t1, t2, &base, opt)) { case -1: update_tree_entry(t1); continue; @@ -202,6 +184,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru } die("git diff-tree: internal error"); } + + strbuf_release(&base); return 0; } diff --git a/tree-walk.c b/tree-walk.c index 522bb6b8f6..21028d08dd 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -468,12 +468,13 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch * - negative for "no, and no subsequent entries will be either" */ int tree_entry_interesting(const struct name_entry *entry, - const char *base, int baselen, + const struct strbuf *base_buf, const struct pathspec *ps) { int i; - int pathlen; + int pathlen, baselen = base_buf->len; int never_interesting = -1; + const char *base = base_buf->buf; if (!ps || !ps->nr) return 2; diff --git a/tree-walk.h b/tree-walk.h index c12f0a2978..f81c232b5a 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -60,6 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru return info->pathlen + tree_entry_len(n->path, n->sha1); } -extern int tree_entry_interesting(const struct name_entry *, const char *, int, const struct pathspec *ps); +extern int tree_entry_interesting(const struct name_entry *, const struct strbuf *, const struct pathspec *ps); #endif -- cgit v1.3 From bc96cc87dbb229cbdabfd93391e24ef168713a74 Mon Sep 17 00:00:00 2001 From: Nguyễn Thái Ngọc Duy Date: Wed, 15 Dec 2010 22:02:44 +0700 Subject: tree_entry_interesting(): support depth limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is needed to replace pathspec_matches() in builtin/grep.c. max_depth == -1 means infinite depth. Depth limit is only effective when pathspec.recursive == 1. When pathspec.recursive == 0, the behavior depends on match functions: non-recursive for tree_entry_interesting() and recursive for match_pathspec{,_depth} Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- cache.h | 2 ++ dir.c | 15 +++++++++++++++ dir.h | 1 + tree-diff.c | 4 ++++ tree-walk.c | 19 ++++++++++++++++--- 5 files changed, 38 insertions(+), 3 deletions(-) (limited to 'tree-diff.c') diff --git a/cache.h b/cache.h index a6456143b2..0cf0bac893 100644 --- a/cache.h +++ b/cache.h @@ -503,6 +503,8 @@ extern int ie_modified(const struct index_state *, struct cache_entry *, struct struct pathspec { const char **raw; /* get_pathspec() result, not freed by free_pathspec() */ int nr; + int recursive:1; + int max_depth; struct pathspec_item { const char *match; int len; diff --git a/dir.c b/dir.c index 70d10bc3da..c3bddb60c8 100644 --- a/dir.c +++ b/dir.c @@ -87,6 +87,21 @@ int fill_directory(struct dir_struct *dir, const char **pathspec) return len; } +int within_depth(const char *name, int namelen, + int depth, int max_depth) +{ + const char *cp = name, *cpe = name + namelen; + + while (cp < cpe) { + if (*cp++ != '/') + continue; + depth++; + if (depth > max_depth) + return 0; + } + return 1; +} + /* * Does 'match' match the given name? * A match is found if diff --git a/dir.h b/dir.h index 72a764ed84..5fa3fbe4c5 100644 --- a/dir.h +++ b/dir.h @@ -65,6 +65,7 @@ struct dir_struct { #define MATCHED_FNMATCH 2 #define MATCHED_EXACTLY 3 extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen); +extern int within_depth(const char *name, int namelen, int depth, int max_depth); extern int fill_directory(struct dir_struct *dir, const char **pathspec); extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec); diff --git a/tree-diff.c b/tree-diff.c index 45a3845c0a..03dc5c8e70 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -146,6 +146,10 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, int all_t1_interesting = 0; int all_t2_interesting = 0; + /* Enable recursion indefinitely */ + opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE); + opt->pathspec.max_depth = -1; + strbuf_init(&base, PATH_MAX); strbuf_add(&base, base_str, baselen); diff --git a/tree-walk.c b/tree-walk.c index 83bede9527..33feafa964 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -1,6 +1,7 @@ #include "cache.h" #include "tree-walk.h" #include "unpack-trees.h" +#include "dir.h" #include "tree.h" static const char *get_mode(const char *str, unsigned int *modep) @@ -559,8 +560,13 @@ int tree_entry_interesting(const struct name_entry *entry, int pathlen, baselen = base->len; int never_interesting = -1; - if (!ps || !ps->nr) - return 2; + if (!ps->nr) { + if (!ps->recursive || ps->max_depth == -1) + return 2; + return !!within_depth(base->buf, baselen, + !!S_ISDIR(entry->mode), + ps->max_depth); + } pathlen = tree_entry_len(entry->path, entry->sha1); @@ -573,7 +579,14 @@ int tree_entry_interesting(const struct name_entry *entry, /* If it doesn't match, move along... */ if (!match_dir_prefix(base->buf, baselen, match, matchlen)) continue; - return 2; + + if (!ps->recursive || ps->max_depth == -1) + return 2; + + return !!within_depth(base->buf + matchlen + 1, + baselen - matchlen - 1, + !!S_ISDIR(entry->mode), + ps->max_depth); } /* Does the base match? */ -- cgit v1.3 From 1376e50723228fc21b7183fe86d71ee484a70dd7 Mon Sep 17 00:00:00 2001 From: Nguyễn Thái Ngọc Duy Date: Fri, 17 Dec 2010 19:45:33 +0700 Subject: grep: drop pathspec_matches() in favor of tree_entry_interesting() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/grep.c | 125 +++++++-------------------------------------------------- tree-diff.c | 4 +- tree-walk.c | 24 ++++++----- tree-walk.h | 2 +- 4 files changed, 30 insertions(+), 125 deletions(-) (limited to 'tree-diff.c') diff --git a/builtin/grep.c b/builtin/grep.c index c9622d6aa9..c3af8760cc 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -329,106 +329,6 @@ static int grep_config(const char *var, const char *value, void *cb) return 0; } -/* - * Return non-zero if max_depth is negative or path has no more then max_depth - * slashes. - */ -static int accept_subdir(const char *path, int max_depth) -{ - if (max_depth < 0) - return 1; - - while ((path = strchr(path, '/')) != NULL) { - max_depth--; - if (max_depth < 0) - return 0; - path++; - } - return 1; -} - -/* - * Return non-zero if name is a subdirectory of match and is not too deep. - */ -static int is_subdir(const char *name, int namelen, - const char *match, int matchlen, int max_depth) -{ - if (matchlen > namelen || strncmp(name, match, matchlen)) - return 0; - - if (name[matchlen] == '\0') /* exact match */ - return 1; - - if (!matchlen || match[matchlen-1] == '/' || name[matchlen] == '/') - return accept_subdir(name + matchlen + 1, max_depth); - - return 0; -} - -/* - * git grep pathspecs are somewhat different from diff-tree pathspecs; - * pathname wildcards are allowed. - */ -static int pathspec_matches(const char **paths, const char *name, int max_depth) -{ - int namelen, i; - if (!paths || !*paths) - return accept_subdir(name, max_depth); - namelen = strlen(name); - for (i = 0; paths[i]; i++) { - const char *match = paths[i]; - int matchlen = strlen(match); - const char *cp, *meta; - - if (is_subdir(name, namelen, match, matchlen, max_depth)) - return 1; - if (!fnmatch(match, name, 0)) - return 1; - if (name[namelen-1] != '/') - continue; - - /* We are being asked if the directory ("name") is worth - * descending into. - * - * Find the longest leading directory name that does - * not have metacharacter in the pathspec; the name - * we are looking at must overlap with that directory. - */ - for (cp = match, meta = NULL; cp - match < matchlen; cp++) { - char ch = *cp; - if (ch == '*' || ch == '[' || ch == '?') { - meta = cp; - break; - } - } - if (!meta) - meta = cp; /* fully literal */ - - if (namelen <= meta - match) { - /* Looking at "Documentation/" and - * the pattern says "Documentation/howto/", or - * "Documentation/diff*.txt". The name we - * have should match prefix. - */ - if (!memcmp(match, name, namelen)) - return 1; - continue; - } - - if (meta - match < namelen) { - /* Looking at "Documentation/howto/" and - * the pattern says "Documentation/h*"; - * match up to "Do.../h"; this avoids descending - * into "Documentation/technical/". - */ - if (!memcmp(match, name, meta - match)) - return 1; - continue; - } - } - return 0; -} - static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size) { void *data; @@ -621,25 +521,24 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, struct tree_desc *tree, struct strbuf *base, int tn_len) { - int hit = 0; + int hit = 0, matched = 0; struct name_entry entry; int old_baselen = base->len; while (tree_entry(tree, &entry)) { int te_len = tree_entry_len(entry.path, entry.sha1); - strbuf_add(base, entry.path, te_len); + if (matched != 2) { + matched = tree_entry_interesting(&entry, base, tn_len, pathspec); + if (matched == -1) + break; /* no more matches */ + if (!matched) + continue; + } - if (S_ISDIR(entry.mode)) - /* Match "abc/" against pathspec to - * decide if we want to descend into "abc" - * directory. - */ - strbuf_addch(base, '/'); + strbuf_add(base, entry.path, te_len); - if (!pathspec_matches(pathspec->raw, base->buf + tn_len, opt->max_depth)) - ; - else if (S_ISREG(entry.mode)) { + if (S_ISREG(entry.mode)) { hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len); } else if (S_ISDIR(entry.mode)) { @@ -652,6 +551,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, if (!data) die("unable to read tree (%s)", sha1_to_hex(entry.sha1)); + + strbuf_addch(base, '/'); init_tree_desc(&sub, data, size); hit |= grep_tree(opt, pathspec, &sub, base, tn_len); free(data); @@ -1058,6 +959,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) paths[1] = NULL; } init_pathspec(&pathspec, paths); + pathspec.max_depth = opt.max_depth; + pathspec.recursive = 1; if (show_in_pager && (cached || list.nr)) die("--open-files-in-pager only works on the worktree"); diff --git a/tree-diff.c b/tree-diff.c index 03dc5c8e70..3954281f50 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -72,7 +72,7 @@ static void show_tree(struct diff_options *opt, const char *prefix, if (all_interesting) show = 1; else { - show = tree_entry_interesting(&desc->entry, base, + show = tree_entry_interesting(&desc->entry, base, 0, &opt->pathspec); if (show == 2) all_interesting = 1; @@ -124,7 +124,7 @@ static void skip_uninteresting(struct tree_desc *t, struct strbuf *base, struct diff_options *opt, int *all_interesting) { while (t->size) { - int show = tree_entry_interesting(&t->entry, base, &opt->pathspec); + int show = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec); if (show == 2) *all_interesting = 1; if (!show) { diff --git a/tree-walk.c b/tree-walk.c index 7596716cf0..322becc3b4 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -544,7 +544,8 @@ static int match_dir_prefix(const char *base, int baselen, /* * Is a tree entry interesting given the pathspec we have? * - * Pre-condition: baselen == 0 || base[baselen-1] == '/' + * Pre-condition: either baselen == base_offset (i.e. empty path) + * or base[baselen-1] == '/' (i.e. with trailing slash). * * Return: * - 2 for "yes, and all subsequent entries will be" @@ -553,44 +554,45 @@ static int match_dir_prefix(const char *base, int baselen, * - negative for "no, and no subsequent entries will be either" */ int tree_entry_interesting(const struct name_entry *entry, - struct strbuf *base, + struct strbuf *base, int base_offset, const struct pathspec *ps) { int i; - int pathlen, baselen = base->len; + int pathlen, baselen = base->len - base_offset; int never_interesting = ps->has_wildcard ? 0 : -1; if (!ps->nr) { if (!ps->recursive || ps->max_depth == -1) return 2; - return !!within_depth(base->buf, baselen, + return !!within_depth(base->buf + base_offset, baselen, !!S_ISDIR(entry->mode), ps->max_depth); } pathlen = tree_entry_len(entry->path, entry->sha1); - for (i = ps->nr-1; i >= 0; i--) { + for (i = ps->nr - 1; i >= 0; i--) { const struct pathspec_item *item = ps->items+i; const char *match = item->match; + const char *base_str = base->buf + base_offset; int matchlen = item->len; if (baselen >= matchlen) { /* If it doesn't match, move along... */ - if (!match_dir_prefix(base->buf, baselen, match, matchlen)) + if (!match_dir_prefix(base_str, baselen, match, matchlen)) goto match_wildcards; if (!ps->recursive || ps->max_depth == -1) return 2; - return !!within_depth(base->buf + matchlen + 1, + return !!within_depth(base_str + matchlen + 1, baselen - matchlen - 1, !!S_ISDIR(entry->mode), ps->max_depth); } /* Does the base match? */ - if (!strncmp(base->buf, match, baselen)) { + if (!strncmp(base_str, match, baselen)) { if (match_entry(entry, pathlen, match + baselen, matchlen - baselen, &never_interesting)) @@ -622,11 +624,11 @@ match_wildcards: strbuf_add(base, entry->path, pathlen); - if (!fnmatch(match, base->buf, 0)) { - strbuf_setlen(base, baselen); + if (!fnmatch(match, base->buf + base_offset, 0)) { + strbuf_setlen(base, base_offset + baselen); return 1; } - strbuf_setlen(base, baselen); + strbuf_setlen(base, base_offset + baselen); /* * Match all directories. We'll try to match files diff --git a/tree-walk.h b/tree-walk.h index 6589ee27e4..39524b7dba 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -60,6 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru return info->pathlen + tree_entry_len(n->path, n->sha1); } -extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, const struct pathspec *ps); +extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, int, const struct pathspec *ps); #endif -- cgit v1.3 From c0aa335c95974caebcc972cd63a11e6ff73b1612 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 22 Mar 2011 13:50:08 +0100 Subject: Remove unused variables Noticed by gcc 4.6.0. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin/fsck.c | 3 +-- builtin/remote-ext.c | 4 ---- diff.c | 3 +-- reachable.c | 5 ----- test-subprocess.c | 3 +-- transport-helper.c | 3 +-- tree-diff.c | 3 +-- 7 files changed, 5 insertions(+), 19 deletions(-) (limited to 'tree-diff.c') diff --git a/builtin/fsck.c b/builtin/fsck.c index 795aba087f..5ae0366bc8 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -140,11 +140,10 @@ static int traverse_reachable(void) int result = 0; while (pending.nr) { struct object_array_entry *entry; - struct object *obj, *parent; + struct object *obj; entry = pending.objects + --pending.nr; obj = entry->item; - parent = (struct object *) entry->name; result |= traverse_one_object(obj); } return !!result; diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c index 155e609d68..692c834d9d 100644 --- a/builtin/remote-ext.c +++ b/builtin/remote-ext.c @@ -30,16 +30,12 @@ static char *strip_escapes(const char *str, const char *service, size_t rpos = 0; int escape = 0; char special = 0; - size_t pslen = 0; - size_t pSlen = 0; size_t psoff = 0; struct strbuf ret = STRBUF_INIT; /* Calculate prefix length for \s and lengths for \s and \S */ if (!strncmp(service, "git-", 4)) psoff = 4; - pSlen = strlen(service); - pslen = pSlen - psoff; /* Pass the service to command. */ setenv("GIT_EXT_SERVICE", service, 1); diff --git a/diff.c b/diff.c index 9b3eb9938f..9fa841010c 100644 --- a/diff.c +++ b/diff.c @@ -1242,7 +1242,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) uintmax_t max_change = 0, max_len = 0; int total_files = data->nr; int width, name_width; - const char *reset, *set, *add_c, *del_c; + const char *reset, *add_c, *del_c; const char *line_prefix = ""; struct strbuf *msg = NULL; @@ -1269,7 +1269,6 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) /* Find the longest filename and max number of changes */ reset = diff_get_color_opt(options, DIFF_RESET); - set = diff_get_color_opt(options, DIFF_PLAIN); add_c = diff_get_color_opt(options, DIFF_FILE_NEW); del_c = diff_get_color_opt(options, DIFF_FILE_OLD); diff --git a/reachable.c b/reachable.c index a03fabf060..3fc6b1d320 100644 --- a/reachable.c +++ b/reachable.c @@ -70,16 +70,11 @@ static void process_tree(struct tree *tree, static void process_tag(struct tag *tag, struct object_array *p, const char *name) { struct object *obj = &tag->object; - struct name_path me; if (obj->flags & SEEN) return; obj->flags |= SEEN; - me.up = NULL; - me.elem = "tag:/"; - me.elem_len = 5; - if (parse_tag(tag) < 0) die("bad tag object %s", sha1_to_hex(obj->sha1)); if (tag->tagged) diff --git a/test-subprocess.c b/test-subprocess.c index 667d3e5079..8926bc52a9 100644 --- a/test-subprocess.c +++ b/test-subprocess.c @@ -3,11 +3,10 @@ int main(int argc, char **argv) { - const char *prefix; struct child_process cp; int nogit = 0; - prefix = setup_git_directory_gently(&nogit); + setup_git_directory_gently(&nogit); if (nogit) die("No git repo found"); if (!strcmp(argv[1], "--setup-work-tree")) { diff --git a/transport-helper.c b/transport-helper.c index 5846b55875..660147f9e9 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -561,10 +561,9 @@ static int push_refs_with_push(struct transport *transport, int mirror = flags & TRANSPORT_PUSH_MIRROR; struct helper_data *data = transport->data; struct strbuf buf = STRBUF_INIT; - struct child_process *helper; struct ref *ref; - helper = get_helper(transport); + get_helper(transport); if (!data->push) return 1; diff --git a/tree-diff.c b/tree-diff.c index 3954281f50..76f83fcc27 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -17,7 +17,6 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const unsigned char *sha1, *sha2; int cmp, pathlen1, pathlen2; int old_baselen = base->len; - int retval = 0; sha1 = tree_entry_extract(t1, &path1, &mode1); sha2 = tree_entry_extract(t2, &path2, &mode2); @@ -53,7 +52,7 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, sha1, sha2, base->buf, 0, 0); } strbuf_addch(base, '/'); - retval = diff_tree_sha1(sha1, sha2, base->buf, opt); + diff_tree_sha1(sha1, sha2, base->buf, opt); } else { opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0); } -- cgit v1.3 From 97d0b74a49f0c81c3f9673c1a17721ac0624c3df Mon Sep 17 00:00:00 2001 From: Nguyễn Thái Ngọc Duy Date: Fri, 25 Mar 2011 16:34:20 +0700 Subject: Improve tree_entry_interesting() handling code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit t_e_i() can return -1 or 2 to early shortcut a search. Current code may use up to two variables to handle it. One for saving return value from t_e_i temporarily, one for saving return code 2. The second variable is not needed. If we make sure the first variable does not change until the next t_e_i() call, then we can do something like this: int ret = 0; while (...) { if (ret != 2) { ret = t_e_i(); if (ret < 0) /* no longer interesting */ break; if (ret == 0) /* skip this round */ continue; } /* ret > 0, interesting */ } Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin/grep.c | 12 ++++++------ list-objects.c | 18 +++++++----------- tree-diff.c | 53 ++++++++++++++++++++--------------------------------- 3 files changed, 33 insertions(+), 50 deletions(-) (limited to 'tree-diff.c') diff --git a/builtin/grep.c b/builtin/grep.c index c3af8760cc..73b962f832 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -521,18 +521,18 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, struct tree_desc *tree, struct strbuf *base, int tn_len) { - int hit = 0, matched = 0; + int hit = 0, match = 0; struct name_entry entry; int old_baselen = base->len; while (tree_entry(tree, &entry)) { int te_len = tree_entry_len(entry.path, entry.sha1); - if (matched != 2) { - matched = tree_entry_interesting(&entry, base, tn_len, pathspec); - if (matched == -1) - break; /* no more matches */ - if (!matched) + if (match != 2) { + match = tree_entry_interesting(&entry, base, tn_len, pathspec); + if (match < 0) + break; + if (match == 0) continue; } diff --git a/list-objects.c b/list-objects.c index 61f6cc98d9..cf9dbe23e4 100644 --- a/list-objects.c +++ b/list-objects.c @@ -68,7 +68,7 @@ static void process_tree(struct rev_info *revs, struct tree_desc desc; struct name_entry entry; struct name_path me; - int all_interesting = (revs->diffopt.pathspec.nr == 0); + int match = revs->diffopt.pathspec.nr == 0 ? 2 : 0; int baselen = base->len; if (!revs->tree_objects) @@ -85,7 +85,7 @@ static void process_tree(struct rev_info *revs, me.elem = name; me.elem_len = strlen(name); - if (!all_interesting) { + if (!match) { strbuf_addstr(base, name); if (base->len) strbuf_addch(base, '/'); @@ -94,17 +94,13 @@ static void process_tree(struct rev_info *revs, init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { - if (!all_interesting) { - int showit = tree_entry_interesting(&entry, - base, 0, - &revs->diffopt.pathspec); - - if (showit < 0) + if (match != 2) { + match = tree_entry_interesting(&entry, base, 0, + &revs->diffopt.pathspec); + if (match < 0) break; - else if (!showit) + if (match == 0) continue; - else if (showit == 2) - all_interesting = 1; } if (S_ISDIR(entry.mode)) diff --git a/tree-diff.c b/tree-diff.c index 3954281f50..f291069bc3 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -65,23 +65,17 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, struct strbuf *base) { - int all_interesting = 0; - while (desc->size) { - int show; - - if (all_interesting) - show = 1; - else { - show = tree_entry_interesting(&desc->entry, base, 0, - &opt->pathspec); - if (show == 2) - all_interesting = 1; + int match = 0; + for (; desc->size; update_tree_entry(desc)) { + if (match != 2) { + match = tree_entry_interesting(&desc->entry, base, 0, + &opt->pathspec); + if (match < 0) + break; + if (match == 0) + continue; } - if (show < 0) - break; - if (show) - show_entry(opt, prefix, desc, base); - update_tree_entry(desc); + show_entry(opt, prefix, desc, base); } } @@ -121,20 +115,16 @@ static void show_entry(struct diff_options *opt, const char *prefix, } static void skip_uninteresting(struct tree_desc *t, struct strbuf *base, - struct diff_options *opt, int *all_interesting) + struct diff_options *opt, int *match) { while (t->size) { - int show = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec); - if (show == 2) - *all_interesting = 1; - if (!show) { - update_tree_entry(t); - continue; + *match = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec); + if (*match) { + if (*match < 0) + t->size = 0; + break; } - /* Skip it all? */ - if (show < 0) - t->size = 0; - return; + update_tree_entry(t); } } @@ -143,8 +133,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, { struct strbuf base; int baselen = strlen(base_str); - int all_t1_interesting = 0; - int all_t2_interesting = 0; + int t1_match = 0, t2_match = 0; /* Enable recursion indefinitely */ opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE); @@ -158,10 +147,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, DIFF_OPT_TST(opt, HAS_CHANGES)) break; if (opt->pathspec.nr) { - if (!all_t1_interesting) - skip_uninteresting(t1, &base, opt, &all_t1_interesting); - if (!all_t2_interesting) - skip_uninteresting(t2, &base, opt, &all_t2_interesting); + skip_uninteresting(t1, &base, opt, &t1_match); + skip_uninteresting(t2, &base, opt, &t2_match); } if (!t1->size) { if (!t2->size) -- cgit v1.3 From af7b41c923677ff9291bab56ec7069922e37453b Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 31 May 2011 11:33:56 -0400 Subject: diff_tree: disable QUICK optimization with diff filter We stop looking for changes early with QUICK, so our diff queue contains only a subset of the changes. However, we don't apply diff filters until later; it will appear at that point as though there are no changes matching our filter, when in reality we simply didn't keep looking for changes long enough. Commit 2cfe8a6 (diff --quiet: disable optimization when --diff-filter=X is used, 2011-03-16) fixes this in some cases by disabling the optimization when a filter is present. However, it only tweaked run_diff_files, missing the similar case in diff_tree. Thus the fix worked only for diffing the working tree and index, but not between trees. Noticed by Yasushi SHOJI. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t4037-whitespace-status.sh | 5 +++++ tree-diff.c | 1 + 2 files changed, 6 insertions(+) (limited to 'tree-diff.c') diff --git a/t/t4037-whitespace-status.sh b/t/t4037-whitespace-status.sh index abc49348b1..3c728a3ebf 100755 --- a/t/t4037-whitespace-status.sh +++ b/t/t4037-whitespace-status.sh @@ -67,4 +67,9 @@ test_expect_success 'diff-files --diff-filter --quiet' ' test_must_fail git diff-files --diff-filter=M --quiet ' +test_expect_success 'diff-tree --diff-filter --quiet' ' + git commit -a -m "worktree state" && + test_must_fail git diff-tree --diff-filter=M --quiet HEAD^ HEAD +' + test_done diff --git a/tree-diff.c b/tree-diff.c index 7d745b4406..70bdb89656 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -287,6 +287,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru for (;;) { if (DIFF_OPT_TST(opt, QUICK) && + !opt->filter && DIFF_OPT_TST(opt, HAS_CHANGES)) break; if (opt->nr_paths) { -- cgit v1.3 From 28b9264dd6cbadcef8b3e48c24ffcb2893b668b3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 31 May 2011 09:14:17 -0700 Subject: diff: futureproof "stop feeding the backend early" logic Refactor the "do not stop feeding the backend early" logic into a small helper function and use it in both run_diff_files() and diff_tree() that has the stop-early optimization. We may later add other types of diffcore transformation that require to look at the whole result like diff-filter does, and having the logic in a single place is essential for longer term maintainability. Signed-off-by: Junio C Hamano --- diff-lib.c | 4 +--- diff.c | 7 +++++++ diff.h | 2 ++ tree-diff.c | 4 +--- 4 files changed, 11 insertions(+), 6 deletions(-) (limited to 'tree-diff.c') diff --git a/diff-lib.c b/diff-lib.c index bfa6503373..869d8f0e77 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -73,9 +73,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) struct cache_entry *ce = active_cache[i]; int changed; - if (DIFF_OPT_TST(&revs->diffopt, QUICK) && - !revs->diffopt.filter && - DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES)) + if (diff_can_quit_early(&revs->diffopt)) break; if (!ce_path_match(ce, revs->prune_data)) diff --git a/diff.c b/diff.c index 91d6ea21a9..ae6853fcf1 100644 --- a/diff.c +++ b/diff.c @@ -3513,6 +3513,13 @@ int diff_result_code(struct diff_options *opt, int status) return result; } +int diff_can_quit_early(struct diff_options *opt) +{ + return (DIFF_OPT_TST(opt, QUICK) && + !opt->filter && + DIFF_OPT_TST(opt, HAS_CHANGES)); +} + void diff_addremove(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, diff --git a/diff.h b/diff.h index a7e7ccbd42..b412ffb970 100644 --- a/diff.h +++ b/diff.h @@ -170,6 +170,8 @@ extern void diff_tree_combined_merge(const unsigned char *sha1, int, struct rev_ void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b); +extern int diff_can_quit_early(struct diff_options *); + extern void diff_addremove(struct diff_options *, int addremove, unsigned mode, diff --git a/tree-diff.c b/tree-diff.c index 70bdb89656..33881d1ad0 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -286,9 +286,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru int baselen = strlen(base); for (;;) { - if (DIFF_OPT_TST(opt, QUICK) && - !opt->filter && - DIFF_OPT_TST(opt, HAS_CHANGES)) + if (diff_can_quit_early(opt)) break; if (opt->nr_paths) { skip_uninteresting(t1, base, baselen, opt); -- cgit v1.3