We introduce a new set of API, diff_tree_*_with_exclude, that also exclude entries based on .gitignore patterns. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- diff.h | 11 +++++++++++ tree-diff.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/diff.h b/diff.h index 8c66b59..51c8a5f 100644 --- a/diff.h +++ b/diff.h @@ -12,6 +12,7 @@ struct diff_queue_struct; struct strbuf; struct diff_filespec; struct userdiff_driver; +struct exclude_list; typedef void (*change_fn_t)(struct diff_options *options, unsigned old_mode, unsigned new_mode, @@ -170,8 +171,18 @@ extern void diff_tree_setup_paths(const char **paths, struct diff_options *); extern void diff_tree_release_paths(struct diff_options *); extern int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt); +extern int diff_tree_with_exclude(struct tree_desc *t1, struct tree_desc *t2, + const char *base, struct diff_options *opt, + struct exclude_list *el, + int def_excl1, int def_excl2); extern int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base, struct diff_options *opt); +extern int diff_tree_sha1_with_exclude(const unsigned char *old, + const unsigned char *new, + const char *base, + struct diff_options *opt, + struct exclude_list *el, + int def_excl1, int def_excl2); extern int diff_root_tree_sha1(const unsigned char *new, const char *base, struct diff_options *opt); diff --git a/tree-diff.c b/tree-diff.c index b3cc2e4..9938ccf 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -5,12 +5,14 @@ #include "diff.h" #include "diffcore.h" #include "tree.h" +#include "dir.h" static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc, struct strbuf *base); static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, - struct strbuf *base, struct diff_options *opt) + struct strbuf *base, struct diff_options *opt, + struct exclude_list *el, int def_excl1, int def_excl2) { unsigned mode1, mode2; const char *path1, *path2; @@ -52,7 +54,8 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, sha1, sha2, base->buf, 0, 0); } strbuf_addch(base, '/'); - diff_tree_sha1(sha1, sha2, base->buf, opt); + diff_tree_sha1_with_exclude(sha1, sha2, base->buf, opt, + el, def_excl1, def_excl2); } else { opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0); } @@ -113,6 +116,31 @@ static void show_entry(struct diff_options *opt, const char *prefix, strbuf_setlen(base, old_baselen); } +static int skip_excludes(struct tree_desc *t, struct strbuf *base, + struct exclude_list *el, int defval) +{ + for (; t->size; update_tree_entry(t)) { + /* + * excluded_from_list only cares whether dtype is + * DT_DIR or something else (except DT_UNKNOWN). Any + * other value would do + */ + int dtype = S_ISDIR(t->entry.mode) ? DT_DIR : DT_REG; + int ret = excluded_from_list(base->buf, base->len, t->entry.path, + &dtype, el); + + /* If undecided, use matching result of parent dir in defval */ + if (ret < 0) + ret = defval; + + if (ret == 1 && dtype == DT_REG) + ; + else + return ret; + } + return defval; +} + static void skip_uninteresting(struct tree_desc *t, struct strbuf *base, struct diff_options *opt, int *match) { @@ -130,9 +158,17 @@ static void skip_uninteresting(struct tree_desc *t, struct strbuf *base, int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base_str, struct diff_options *opt) { + return diff_tree_with_exclude(t1, t2, base_str, opt, NULL, 0, 0); +} + +int diff_tree_with_exclude(struct tree_desc *t1, struct tree_desc *t2, + const char *base_str, struct diff_options *opt, + struct exclude_list *el, int def_excl1, int def_excl2) +{ struct strbuf base; int baselen = strlen(base_str); int t1_match = 0, t2_match = 0; + int excl1 = 0, excl2 = 0; /* Enable recursion indefinitely */ opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE); @@ -148,6 +184,10 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, skip_uninteresting(t1, &base, opt, &t1_match); skip_uninteresting(t2, &base, opt, &t2_match); } + if (el && el->nr) { + excl1 = skip_excludes(t1, &base, el, def_excl1); + excl2 = skip_excludes(t2, &base, el, def_excl2); + } if (!t1->size) { if (!t2->size) break; @@ -160,7 +200,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, update_tree_entry(t1); continue; } - switch (compare_tree_entry(t1, t2, &base, opt)) { + switch (compare_tree_entry(t1, t2, &base, opt, el, excl1, excl2)) { case -1: update_tree_entry(t1); continue; @@ -267,6 +307,16 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base, struct diff_options *opt) { + return diff_tree_sha1_with_exclude(old, new, base, opt, NULL, 0, 0); +} + +int diff_tree_sha1_with_exclude(const unsigned char *old, + const unsigned char *new, + const char *base, + struct diff_options *opt, + struct exclude_list *el, + int def_excl1, int def_excl2) +{ void *tree1, *tree2; struct tree_desc t1, t2; unsigned long size1, size2; @@ -280,7 +330,7 @@ int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const cha die("unable to read destination tree (%s)", sha1_to_hex(new)); init_tree_desc(&t1, tree1, size1); init_tree_desc(&t2, tree2, size2); - retval = diff_tree(&t1, &t2, base, opt); + retval = diff_tree_with_exclude(&t1, &t2, base, opt, el, def_excl1, def_excl2); if (!*base && DIFF_OPT_TST(opt, FOLLOW_RENAMES) && diff_might_be_rename()) { init_tree_desc(&t1, tree1, size1); init_tree_desc(&t2, tree2, size2); -- 1.7.3.1.256.g2539c.dirty -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html