Code

Merge git://git.kernel.org/pub/scm/gitk/gitk
[git.git] / diff-lib.c
index 069e4507ae7caa70f79d5369bc61dfefd0f174e2..fe2ccec7e6b3230715cbdf04591d1c0efb6a6389 100644 (file)
@@ -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) {