diff options
Diffstat (limited to 'diff-lib.c')
-rw-r--r-- | diff-lib.c | 45 |
1 files changed, 35 insertions, 10 deletions
diff --git a/diff-lib.c b/diff-lib.c index 069e4507a..fe2ccec7e 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -264,6 +264,9 @@ int setup_diff_no_index(struct rev_info *revs, DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS); break; } + if (nongit && argc != i + 2) + die("git diff [--no-index] takes two paths"); + if (argc != i + 2 || (!is_outside_repo(argv[i + 1], nongit, prefix) && !is_outside_repo(argv[i], nongit, prefix))) return -1; @@ -334,22 +337,41 @@ int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv) } return run_diff_files(revs, options); } + /* - * See if work tree has an entity that can be staged. Return 0 if so, - * return 1 if not and return -1 if error. + * Has the work tree entity been removed? + * + * Return 1 if it was removed from the work tree, 0 if an entity to be + * compared with the cache entry ce still exists (the latter includes + * the case where a directory that is not a submodule repository + * exists for ce that is a submodule -- it is a submodule that is not + * checked out). Return negative for an error. */ -static int check_work_tree_entity(const struct cache_entry *ce, struct stat *st, char *symcache) +static int check_removed(const struct cache_entry *ce, struct stat *st) { if (lstat(ce->name, st) < 0) { if (errno != ENOENT && errno != ENOTDIR) return -1; return 1; } - if (has_symlink_leading_path(ce->name, symcache)) + if (has_symlink_leading_path(ce_namelen(ce), ce->name)) return 1; if (S_ISDIR(st->st_mode)) { unsigned char sub[20]; - if (resolve_gitlink_ref(ce->name, "HEAD", sub)) + + /* + * If ce is already a gitlink, we can have a plain + * directory (i.e. the submodule is not checked out), + * or a checked out submodule. Either case this is not + * a case where something was removed from the work tree, + * so we will return 0. + * + * Otherwise, if the directory is not a submodule + * repository, that means ce which was a blob turned into + * a directory --- the blob was removed! + */ + if (!S_ISGITLINK(ce->ce_mode) && + resolve_gitlink_ref(ce->name, "HEAD", sub)) return 1; } return 0; @@ -399,7 +421,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) memset(&(dpath->parent[0]), 0, sizeof(struct combine_diff_parent)*5); - changed = check_work_tree_entity(ce, &st, symcache); + changed = check_removed(ce, &st); if (!changed) dpath->mode = ce_mode_from_stat(ce, st.st_mode); else { @@ -463,7 +485,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) if (ce_uptodate(ce)) continue; - changed = check_work_tree_entity(ce, &st, symcache); + changed = check_removed(ce, &st); if (changed) { if (changed < 0) { perror(ce->name); @@ -476,8 +498,11 @@ int run_diff_files(struct rev_info *revs, unsigned int option) continue; } changed = ce_match_stat(ce, &st, ce_option); - if (!changed && !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER)) - continue; + if (!changed) { + ce_mark_uptodate(ce); + if (!DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER)) + continue; + } oldmode = ce->ce_mode; newmode = ce_mode_from_stat(ce, st.st_mode); diff_change(&revs->diffopt, oldmode, newmode, @@ -521,7 +546,7 @@ static int get_stat_data(struct cache_entry *ce, if (!cached) { int changed; struct stat st; - changed = check_work_tree_entity(ce, &st, cbdata->symcache); + changed = check_removed(ce, &st); if (changed < 0) return -1; else if (changed) { |