diff options
author | Russell Belfer <rb@github.com> | 2012-05-15 14:17:39 -0700 |
---|---|---|
committer | Russell Belfer <rb@github.com> | 2012-05-15 14:34:15 -0700 |
commit | 41a82592ef56a216f96558942d717af15589071d (patch) | |
tree | 8f9c2969000d388f1091b2cd134776bee59e29c6 /src/diff.c | |
parent | 54695f4098c75801f477f5bc229a52653484e08a (diff) | |
download | libgit2-41a82592ef56a216f96558942d717af15589071d.tar.gz |
Ranged iterators and rewritten git_status_file
The goal of this work is to rewrite git_status_file to use the
same underlying code as git_status_foreach.
This is done in 3 phases:
1. Extend iterators to allow ranged iteration with start and
end prefixes for the range of file names to be covered.
2. Improve diff so that when there is a pathspec and there is
a common non-wildcard prefix of the pathspec, it will use
ranged iterators to minimize excess iteration.
3. Rewrite git_status_file to call git_status_foreach_ext
with a pathspec that covers just the one file being checked.
Since ranged iterators underlie the status & diff implementation,
this is actually fairly efficient. The workdir iterator does
end up loading the contents of all the directories down to the
single file, which should ideally be avoided, but it is pretty
good.
Diffstat (limited to 'src/diff.c')
-rw-r--r-- | src/diff.c | 47 |
1 files changed, 39 insertions, 8 deletions
diff --git a/src/diff.c b/src/diff.c index fed22f403..c8670b53e 100644 --- a/src/diff.c +++ b/src/diff.c @@ -11,6 +11,25 @@ #include "config.h" #include "attr_file.h" +static char *diff_prefix_from_pathspec(const git_strarray *pathspec) +{ + git_buf prefix = GIT_BUF_INIT; + const char *scan; + + if (git_buf_common_prefix(&prefix, pathspec) < 0) + return NULL; + + /* diff prefix will only be leading non-wildcards */ + for (scan = prefix.ptr; *scan && !git__iswildcard(*scan); ++scan); + git_buf_truncate(&prefix, scan - prefix.ptr); + + if (prefix.size > 0) + return git_buf_detach(&prefix); + + git_buf_free(&prefix); + return NULL; +} + static bool diff_pathspec_is_interesting(const git_strarray *pathspec) { const char *str; @@ -613,13 +632,16 @@ int git_diff_tree_to_tree( git_diff_list **diff) { git_iterator *a = NULL, *b = NULL; + char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL; assert(repo && old_tree && new_tree && diff); - if (git_iterator_for_tree(repo, old_tree, &a) < 0 || - git_iterator_for_tree(repo, new_tree, &b) < 0) + if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 || + git_iterator_for_tree_range(&b, repo, new_tree, prefix, prefix) < 0) return -1; + git__free(prefix); + return diff_from_iterators(repo, opts, a, b, diff); } @@ -630,13 +652,16 @@ int git_diff_index_to_tree( git_diff_list **diff) { git_iterator *a = NULL, *b = NULL; + char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL; assert(repo && diff); - if (git_iterator_for_tree(repo, old_tree, &a) < 0 || - git_iterator_for_index(repo, &b) < 0) + if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 || + git_iterator_for_index_range(&b, repo, prefix, prefix) < 0) return -1; + git__free(prefix); + return diff_from_iterators(repo, opts, a, b, diff); } @@ -646,13 +671,16 @@ int git_diff_workdir_to_index( git_diff_list **diff) { git_iterator *a = NULL, *b = NULL; + char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL; assert(repo && diff); - if (git_iterator_for_index(repo, &a) < 0 || - git_iterator_for_workdir(repo, &b) < 0) + if (git_iterator_for_index_range(&a, repo, prefix, prefix) < 0 || + git_iterator_for_workdir_range(&b, repo, prefix, prefix) < 0) return -1; + git__free(prefix); + return diff_from_iterators(repo, opts, a, b, diff); } @@ -664,13 +692,16 @@ int git_diff_workdir_to_tree( git_diff_list **diff) { git_iterator *a = NULL, *b = NULL; + char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL; assert(repo && old_tree && diff); - if (git_iterator_for_tree(repo, old_tree, &a) < 0 || - git_iterator_for_workdir(repo, &b) < 0) + if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 || + git_iterator_for_workdir_range(&b, repo, prefix, prefix) < 0) return -1; + git__free(prefix); + return diff_from_iterators(repo, opts, a, b, diff); } |