From: Nguyễn Thái Ngọc Duy Date: Tue, 07 Sep 2010 15:48:03 GMT Subject: [PATCH 5/5] Make rev-list --objects work together with pathspecs Message-ID: <1283874483-32017-6-git-send-email-pclouds@gmail.com> In-Reply-To: <1283874483-32017-1-git-send-email-pclouds@gmail.com> From: Elijah Newren When traversing commits, the selection of commits would heed the list of pathspecs passed, but subsequent walking of the trees of those commits would not. This resulted in 'rev-list --objects HEAD -- ' displaying objects at unwanted paths. Have process_tree() call tree_entry_interesting() to determine which paths are interesting and should be walked. Naturally, this change can provide a large speedup when paths are specified together with --objects, since many tree entries are now correctly ignored. Interestingly, though, this change also gives me a small (~1%) but repeatable speedup even when no paths are specified with --objects. Signed-off-by: Elijah Newren Signed-off-by: Junio C Hamano Signed-off-by: Nguyễn Thái Ngọc Duy --- list-objects.c | 25 +++++++++++++++++++++++++ revision.c | 8 ++++++-- revision.h | 3 ++- t/t6000-rev-list-misc.sh | 6 +++--- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/list-objects.c b/list-objects.c index 8953548..44efca3 100644 --- a/list-objects.c +++ b/list-objects.c @@ -67,6 +67,9 @@ 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.nr_paths == 0); + char *full_prefix = NULL; + int full_prefix_len = 0; if (!revs->tree_objects) return; @@ -82,9 +85,28 @@ static void process_tree(struct rev_info *revs, me.elem = name; me.elem_len = strlen(name); + if (!all_interesting) { + full_prefix = path_name_impl(path, name, 1); + full_prefix_len = strlen(full_prefix); + } + init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { + if (!all_interesting) { + int showit = tree_entry_interesting(&entry, + full_prefix, + full_prefix_len, + &revs->diffopt.el); + + if (showit < 0) + break; + else if (!showit) + continue; + else if (showit == 2) + all_interesting = 1; + } + if (S_ISDIR(entry.mode)) process_tree(revs, lookup_tree(entry.sha1), @@ -97,6 +119,7 @@ static void process_tree(struct rev_info *revs, lookup_blob(entry.sha1), show, &me, entry.path); } + free(full_prefix); free(tree->buffer); tree->buffer = NULL; } @@ -147,6 +170,7 @@ void traverse_commit_list(struct rev_info *revs, int i; struct commit *commit; + diff_tree_setup_exclude_list(&revs->diffopt); while ((commit = get_revision(revs)) != NULL) { add_pending_tree(revs, commit->tree); show_commit(commit, data); @@ -181,4 +205,5 @@ void traverse_commit_list(struct rev_info *revs, revs->pending.alloc = 0; revs->pending.objects = NULL; } + free(revs->diffopt.el.excludes); } diff --git a/revision.c b/revision.c index b1c1890..55c4586 100644 --- a/revision.c +++ b/revision.c @@ -16,7 +16,7 @@ volatile show_early_output_fn_t show_early_output; -char *path_name(const struct name_path *path, const char *name) +char *path_name_impl(const struct name_path *path, const char *name, int isdir) { const struct name_path *p; char *n, *m; @@ -27,7 +27,7 @@ char *path_name(const struct name_path *path, const char *name) if (p->elem_len) len += p->elem_len + 1; } - n = xmalloc(len); + n = xmalloc(len + !!isdir); m = n + len - (nlen + 1); strcpy(m, name); for (p = path; p; p = p->up) { @@ -37,6 +37,10 @@ char *path_name(const struct name_path *path, const char *name) m[p->elem_len] = '/'; } } + if (isdir && len > 1) { + n[len-1] = '/'; + n[len] = '\0'; + } return n; } diff --git a/revision.h b/revision.h index 05659c6..92f4feb 100644 --- a/revision.h +++ b/revision.h @@ -173,7 +173,8 @@ struct name_path { const char *elem; }; -char *path_name(const struct name_path *path, const char *name); +char *path_name_impl(const struct name_path *path, const char *name, int isdir); +#define path_name(path, name) path_name_impl(path, name, 0) extern void add_object(struct object *obj, struct object_array *p, diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh index b3c1dd8..b10685a 100755 --- a/t/t6000-rev-list-misc.sh +++ b/t/t6000-rev-list-misc.sh @@ -11,13 +11,13 @@ test_expect_success setup ' git commit -m one ' -test_expect_failure 'rev-list --objects heeds pathspecs' ' +test_expect_success 'rev-list --objects heeds pathspecs' ' git rev-list --objects HEAD -- wanted_file >output && grep wanted_file output && ! grep unwanted_file output ' -test_expect_failure 'rev-list --objects with pathspecs and deeper paths' ' +test_expect_success 'rev-list --objects with pathspecs and deeper paths' ' mkdir foo && >foo/file && git add foo/file && @@ -31,7 +31,7 @@ test_expect_failure 'rev-list --objects with pathspecs and deeper paths' ' ! grep unwanted_file output ' -test_expect_failure 'rev-list --objects with pathspecs and copied files' ' +test_expect_success 'rev-list --objects with pathspecs and copied files' ' git checkout --orphan junio-testcase && git rm -rf . && -- 1.7.1.rc1.69.g24c2f7