Merge branch 'tg/diff-no-index-refactor'
authorJunio C Hamano <gitster@pobox.com>
Fri, 27 Dec 2013 22:58:17 +0000 (14:58 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 27 Dec 2013 22:58:17 +0000 (14:58 -0800)
"git diff ../else/where/A ../else/where/B" when ../else/where is
clearly outside the repository, and "git diff --no-index A B", do
not have to look at the index at all, but we used to read the index
unconditionally.

* tg/diff-no-index-refactor:
diff: avoid some nesting
diff: add test for --no-index executed outside repo
diff: don't read index when --no-index is given
diff: move no-index detection to builtin/diff.c

1  2 
builtin/diff.c
diff.h
diff --combined builtin/diff.c
index fe0cc7f1b5b1451f267b1d9e24a6e40cd6e55325,24d6271625d02b5aba877ac17b13daf36f5db0aa..0f247d24008a4dc7ba5958e716c13f7582a820f1
@@@ -16,6 -16,9 +16,9 @@@
  #include "submodule.h"
  #include "sha1-array.h"
  
+ #define DIFF_NO_INDEX_EXPLICIT 1
+ #define DIFF_NO_INDEX_IMPLICIT 2
  struct blobinfo {
        unsigned char sha1[20];
        const char *name;
@@@ -64,18 -67,15 +67,18 @@@ static void stuff_change(struct diff_op
  
  static int builtin_diff_b_f(struct rev_info *revs,
                            int argc, const char **argv,
 -                          struct blobinfo *blob,
 -                          const char *path)
 +                          struct blobinfo *blob)
  {
        /* Blob vs file in the working tree*/
        struct stat st;
 +      const char *path;
  
        if (argc > 1)
                usage(builtin_diff_usage);
  
 +      GUARD_PATHSPEC(&revs->prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
 +      path = revs->prune_data.items[0].match;
 +
        if (lstat(path, &st))
                die_errno(_("failed to stat '%s'"), path);
        if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
@@@ -258,8 -258,9 +261,8 @@@ int cmd_diff(int argc, const char **arg
        struct rev_info rev;
        struct object_array ent = OBJECT_ARRAY_INIT;
        int blobs = 0, paths = 0;
 -      const char *path = NULL;
        struct blobinfo blob[2];
-       int nongit;
+       int nongit = 0, no_index = 0;
        int result = 0;
  
        /*
         * Other cases are errors.
         */
  
-       prefix = setup_git_directory_gently(&nongit);
-       gitmodules_config();
+       /* Were we asked to do --no-index explicitly? */
+       for (i = 1; i < argc; i++) {
+               if (!strcmp(argv[i], "--")) {
+                       i++;
+                       break;
+               }
+               if (!strcmp(argv[i], "--no-index"))
+                       no_index = DIFF_NO_INDEX_EXPLICIT;
+               if (argv[i][0] != '-')
+                       break;
+       }
+       if (!no_index)
+               prefix = setup_git_directory_gently(&nongit);
+       /*
+        * Treat git diff with at least one path outside of the
+        * repo the same as if the command would have been executed
+        * outside of a git repository.  In this case it behaves
+        * the same way as "git diff --no-index <a> <b>", which acts
+        * as a colourful "diff" replacement.
+        */
+       if (nongit || ((argc == i + 2) &&
+                      (!path_inside_repo(prefix, argv[i]) ||
+                       !path_inside_repo(prefix, argv[i + 1]))))
+               no_index = DIFF_NO_INDEX_IMPLICIT;
+       if (!no_index)
+               gitmodules_config();
        git_config(git_diff_ui_config, NULL);
  
        init_revisions(&rev, prefix);
  
-       /* If this is a no-index diff, just run it and exit there. */
-       diff_no_index(&rev, argc, argv, nongit, prefix);
+       if (no_index && argc != i + 2) {
+               if (no_index == DIFF_NO_INDEX_IMPLICIT) {
+                       /*
+                        * There was no --no-index and there were not two
+                        * paths. It is possible that the user intended
+                        * to do an inside-repository operation.
+                        */
+                       fprintf(stderr, "Not a git repository\n");
+                       fprintf(stderr,
+                               "To compare two paths outside a working tree:\n");
+               }
+               /* Give the usage message for non-repository usage and exit. */
+               usagef("git diff %s <path> <path>",
+                      no_index == DIFF_NO_INDEX_EXPLICIT ?
+                      "--no-index" : "[--no-index]");
+       }
+       if (no_index)
+               /* If this is a no-index diff, just run it and exit there. */
+               diff_no_index(&rev, argc, argv, prefix);
  
        /* Otherwise, we are doing the usual "git" diff */
        rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
                        die(_("unhandled object '%s' given."), name);
                }
        }
 -      if (rev.prune_data.nr) {
 -              /* builtin_diff_b_f() */
 -              GUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
 -              if (!path)
 -                      path = rev.prune_data.items[0].match;
 +      if (rev.prune_data.nr)
                paths += rev.prune_data.nr;
 -      }
  
        /*
         * Now, do the arguments look reasonable?
                case 1:
                        if (paths != 1)
                                usage(builtin_diff_usage);
 -                      result = builtin_diff_b_f(&rev, argc, argv, blob, path);
 +                      result = builtin_diff_b_f(&rev, argc, argv, blob);
                        break;
                case 2:
                        if (paths)
diff --combined diff.h
index 760388fa174c7c8370463e2a9788ded6aab685c7,de105d392ae185fc6b94fb61b0967fbf11a61e47..ce123fa06fee6fb6e5e76d6a92ea8284a5bbbcf1
--- 1/diff.h
--- 2/diff.h
+++ b/diff.h
@@@ -164,8 -164,6 +164,8 @@@ struct diff_options 
        diff_prefix_fn_t output_prefix;
        int output_prefix_length;
        void *output_prefix_data;
 +
 +      int diff_path_counter;
  };
  
  enum color_diff {
@@@ -246,7 -244,7 +246,7 @@@ extern struct diff_filepair *diff_unmer
  #define DIFF_SETUP_USE_SIZE_CACHE     4
  
  /*
 - * Poor man's alternative to parse-option, to allow both sticked form
 + * Poor man's alternative to parse-option, to allow both stuck form
   * (--option=value) and separate form (--option value).
   */
  extern int parse_long_opt(const char *opt, const char **argv,
@@@ -332,7 -330,7 +332,7 @@@ extern int diff_flush_patch_id(struct d
  
  extern int diff_result_code(struct diff_options *, int);
  
- extern void diff_no_index(struct rev_info *, int, const char **, int, const char *);
+ extern void diff_no_index(struct rev_info *, int, const char **, const char *);
  
  extern int index_differs_from(const char *def, int diff_flags);