Merge branch 'th/diff-no-index-fixes'
authorJunio C Hamano <gitster@pobox.com>
Thu, 5 Jul 2012 06:40:38 +0000 (23:40 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 5 Jul 2012 06:40:38 +0000 (23:40 -0700)
"git diff --no-index" did not correctly handle relative paths and
did not give correct exit codes when run under "--quiet" option.

* th/diff-no-index-fixes:
diff-no-index: exit(1) if 'diff --quiet <repo file> <external file>' finds changes
diff: handle relative paths in no-index

1  2 
cache.h
diff-no-index.c
setup.c
diff --combined cache.h
index 506d1574f2ddba4b19146d5275e620f5f6733402,8e691957e9e0cfce5a17a02c8bdd25d51773bcff..89581041ce82603ae82866f8f8a5c01b4f7f6d0d
+++ b/cache.h
@@@ -105,9 -105,6 +105,9 @@@ struct cache_header 
        unsigned int hdr_entries;
  };
  
 +#define INDEX_FORMAT_LB 2
 +#define INDEX_FORMAT_UB 4
 +
  /*
   * The "cache_time" is just the low 32 bits of the
   * time. It doesn't matter if it overflows - we only
@@@ -118,6 -115,48 +118,6 @@@ struct cache_time 
        unsigned int nsec;
  };
  
 -/*
 - * dev/ino/uid/gid/size are also just tracked to the low 32 bits
 - * Again - this is just a (very strong in practice) heuristic that
 - * the inode hasn't changed.
 - *
 - * We save the fields in big-endian order to allow using the
 - * index file over NFS transparently.
 - */
 -struct ondisk_cache_entry {
 -      struct cache_time ctime;
 -      struct cache_time mtime;
 -      unsigned int dev;
 -      unsigned int ino;
 -      unsigned int mode;
 -      unsigned int uid;
 -      unsigned int gid;
 -      unsigned int size;
 -      unsigned char sha1[20];
 -      unsigned short flags;
 -      char name[FLEX_ARRAY]; /* more */
 -};
 -
 -/*
 - * This struct is used when CE_EXTENDED bit is 1
 - * The struct must match ondisk_cache_entry exactly from
 - * ctime till flags
 - */
 -struct ondisk_cache_entry_extended {
 -      struct cache_time ctime;
 -      struct cache_time mtime;
 -      unsigned int dev;
 -      unsigned int ino;
 -      unsigned int mode;
 -      unsigned int uid;
 -      unsigned int gid;
 -      unsigned int size;
 -      unsigned char sha1[20];
 -      unsigned short flags;
 -      unsigned short flags2;
 -      char name[FLEX_ARRAY]; /* more */
 -};
 -
  struct cache_entry {
        struct cache_time ce_ctime;
        struct cache_time ce_mtime;
@@@ -214,6 -253,9 +214,6 @@@ static inline size_t ce_namelen(const s
  }
  
  #define ce_size(ce) cache_entry_size(ce_namelen(ce))
 -#define ondisk_ce_size(ce) (((ce)->ce_flags & CE_EXTENDED) ? \
 -                          ondisk_cache_entry_extended_size(ce_namelen(ce)) : \
 -                          ondisk_cache_entry_size(ce_namelen(ce)))
  #define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
  #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
  #define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
@@@ -264,11 -306,13 +264,11 @@@ static inline unsigned int canon_mode(u
        return S_IFGITLINK;
  }
  
 -#define flexible_size(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7)
  #define cache_entry_size(len) (offsetof(struct cache_entry,name) + (len) + 1)
 -#define ondisk_cache_entry_size(len) flexible_size(ondisk_cache_entry,len)
 -#define ondisk_cache_entry_extended_size(len) flexible_size(ondisk_cache_entry_extended,len)
  
  struct index_state {
        struct cache_entry **cache;
 +      unsigned int version;
        unsigned int cache_nr, cache_alloc, cache_changed;
        struct string_list *resolve_undo;
        struct cache_tree *cache_tree;
@@@ -409,10 -453,9 +409,11 @@@ extern const char *setup_git_directory(
  extern char *prefix_path(const char *prefix, int len, const char *path);
  extern const char *prefix_filename(const char *prefix, int len, const char *path);
  extern int check_filename(const char *prefix, const char *name);
 -extern void verify_filename(const char *prefix, const char *name);
 +extern void verify_filename(const char *prefix,
 +                          const char *name,
 +                          int diagnose_misspelt_rev);
  extern void verify_non_filename(const char *prefix, const char *name);
+ extern int path_inside_repo(const char *prefix, const char *path);
  
  #define INIT_DB_QUIET 0x0001
  
@@@ -582,7 -625,6 +583,7 @@@ enum rebase_setup_type 
  enum push_default_type {
        PUSH_DEFAULT_NOTHING = 0,
        PUSH_DEFAULT_MATCHING,
 +      PUSH_DEFAULT_SIMPLE,
        PUSH_DEFAULT_UPSTREAM,
        PUSH_DEFAULT_CURRENT,
        PUSH_DEFAULT_UNSPECIFIED
@@@ -879,8 -921,10 +880,8 @@@ enum date_mode 
  };
  
  const char *show_date(unsigned long time, int timezone, enum date_mode mode);
 -const char *show_date_relative(unsigned long time, int tz,
 -                             const struct timeval *now,
 -                             char *timebuf,
 -                             size_t timebuf_size);
 +void show_date_relative(unsigned long time, int tz, const struct timeval *now,
 +                      struct strbuf *timebuf);
  int parse_date(const char *date, char *buf, int bufsize);
  int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);
  void datestamp(char *buf, int bufsize);
@@@ -889,19 -933,15 +890,19 @@@ unsigned long approxidate_careful(cons
  unsigned long approxidate_relative(const char *date, const struct timeval *now);
  enum date_mode parse_date_format(const char *format);
  
 -#define IDENT_WARN_ON_NO_NAME  1
 -#define IDENT_ERROR_ON_NO_NAME 2
 -#define IDENT_NO_DATE        4
 +#define IDENT_STRICT         1
 +#define IDENT_NO_DATE        2
 +#define IDENT_NO_NAME        4
  extern const char *git_author_info(int);
  extern const char *git_committer_info(int);
  extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
  extern const char *fmt_name(const char *name, const char *email);
 +extern const char *ident_default_name(void);
 +extern const char *ident_default_email(void);
 +extern const char *ident_default_date(void);
  extern const char *git_editor(void);
  extern const char *git_pager(int stdout_is_tty);
 +extern int git_ident_config(const char *, const char *, void *);
  
  struct ident_split {
        const char *name_begin;
@@@ -1145,6 -1185,9 +1146,6 @@@ struct config_include_data 
  #define CONFIG_INCLUDE_INIT { 0 }
  extern int git_config_include(const char *name, const char *value, void *data);
  
 -#define MAX_GITNAME (1000)
 -extern char git_default_email[MAX_GITNAME];
 -extern char git_default_name[MAX_GITNAME];
  #define IDENT_NAME_GIVEN 01
  #define IDENT_MAIL_GIVEN 02
  #define IDENT_ALL_GIVEN (IDENT_NAME_GIVEN|IDENT_MAIL_GIVEN)
diff --combined diff-no-index.c
index 77667b810d383d18a3b912b739ba97d430b30133,63c31cc4de35aeba713c2ae4700fa98b66158d30..beec49b5ac98c6d3ea895adcf66265f3a2fc7875
@@@ -151,23 -151,6 +151,6 @@@ static int queue_diff(struct diff_optio
        }
  }
  
- static int path_outside_repo(const char *path)
- {
-       const char *work_tree;
-       size_t len;
-       if (!is_absolute_path(path))
-               return 0;
-       work_tree = get_git_work_tree();
-       if (!work_tree)
-               return 1;
-       len = strlen(work_tree);
-       if (strncmp(path, work_tree, len) ||
-           (path[len] != '\0' && path[len] != '/'))
-               return 1;
-       return 0;
- }
  void diff_no_index(struct rev_info *revs,
                   int argc, const char **argv,
                   int nongit, const char *prefix)
                 * a colourful "diff" replacement.
                 */
                if ((argc != i + 2) ||
-                   (!path_outside_repo(argv[i]) &&
-                    !path_outside_repo(argv[i+1])))
+                   (path_inside_repo(prefix, argv[i]) &&
+                    path_inside_repo(prefix, argv[i+1])))
                        return;
        }
        if (argc != i + 2)
                }
        }
  
 -      /*
 -       * If the user asked for our exit code then don't start a
 -       * pager or we would end up reporting its exit code instead.
 -       */
 -      if (!DIFF_OPT_TST(&revs->diffopt, EXIT_WITH_STATUS))
 -              setup_pager();
 -
        if (prefix) {
                int len = strlen(prefix);
                const char *paths[3];
        if (!revs->diffopt.output_format)
                revs->diffopt.output_format = DIFF_FORMAT_PATCH;
  
 -      DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
        DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
  
        revs->max_count = -2;
        if (diff_setup_done(&revs->diffopt) < 0)
                die("diff_setup_done failed");
  
 +      setup_diff_pager(&revs->diffopt);
 +      DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
 +
        if (queue_diff(&revs->diffopt, revs->diffopt.pathspec.raw[0],
                       revs->diffopt.pathspec.raw[1]))
                exit(1);
         * The return code for --no-index imitates diff(1):
         * 0 = no changes, 1 = changes, else error
         */
-       exit(revs->diffopt.found_changes);
+       exit(diff_result_code(&revs->diffopt, 0));
  }
diff --combined setup.c
index 994976946b4b451ee41508a2649987c9b4e9bdbc,2cfa0377729bb0c90345a17e6cef4432626b6675..e11497720e01dd14a66e152883e675669fc3b548
+++ b/setup.c
@@@ -4,7 -4,7 +4,7 @@@
  static int inside_git_dir = -1;
  static int inside_work_tree = -1;
  
char *prefix_path(const char *prefix, int len, const char *path)
static char *prefix_path_gently(const char *prefix, int len, const char *path)
  {
        const char *orig = path;
        char *sanitized;
@@@ -31,7 -31,8 +31,8 @@@
                if (strncmp(sanitized, work_tree, len) ||
                    (len > root_len && sanitized[len] != '\0' && sanitized[len] != '/')) {
                error_out:
-                       die("'%s' is outside repository", orig);
+                       free(sanitized);
+                       return NULL;
                }
                if (sanitized[len] == '/')
                        len++;
        return sanitized;
  }
  
+ char *prefix_path(const char *prefix, int len, const char *path)
+ {
+       char *r = prefix_path_gently(prefix, len, path);
+       if (!r)
+               die("'%s' is outside repository", path);
+       return r;
+ }
+ int path_inside_repo(const char *prefix, const char *path)
+ {
+       int len = prefix ? strlen(prefix) : 0;
+       char *r = prefix_path_gently(prefix, len, path);
+       if (r) {
+               free(r);
+               return 1;
+       }
+       return 0;
+ }
  int check_filename(const char *prefix, const char *arg)
  {
        const char *name;
        die_errno("failed to stat '%s'", arg);
  }
  
 -static void NORETURN die_verify_filename(const char *prefix, const char *arg)
 +static void NORETURN die_verify_filename(const char *prefix,
 +                                       const char *arg,
 +                                       int diagnose_misspelt_rev)
  {
        unsigned char sha1[20];
        unsigned mode;
  
 +      if (!diagnose_misspelt_rev)
 +              die("%s: no such path in the working tree.\n"
 +                  "Use '-- <path>...' to specify paths that do not exist locally.",
 +                  arg);
        /*
         * Saying "'(icase)foo' does not exist in the index" when the
         * user gave us ":(icase)foo" is just stupid.  A magic pathspec
   * as true, because even if such a filename were to exist, we want
   * it to be preceded by the "--" marker (or we want the user to
   * use a format like "./-filename")
 + *
 + * The "diagnose_misspelt_rev" is used to provide a user-friendly
 + * diagnosis when dying upon finding that "name" is not a pathname.
 + * If set to 1, the diagnosis will try to diagnose "name" as an
 + * invalid object name (e.g. HEAD:foo). If set to 0, the diagnosis
 + * will only complain about an inexisting file.
 + *
 + * This function is typically called to check that a "file or rev"
 + * argument is unambiguous. In this case, the caller will want
 + * diagnose_misspelt_rev == 1 when verifying the first non-rev
 + * argument (which could have been a revision), and
 + * diagnose_misspelt_rev == 0 for the next ones (because we already
 + * saw a filename, there's not ambiguity anymore).
   */
 -void verify_filename(const char *prefix, const char *arg)
 +void verify_filename(const char *prefix,
 +                   const char *arg,
 +                   int diagnose_misspelt_rev)
  {
        if (*arg == '-')
                die("bad flag '%s' used after filename", arg);
        if (check_filename(prefix, arg))
                return;
 -      die_verify_filename(prefix, arg);
 +      die_verify_filename(prefix, arg, diagnose_misspelt_rev);
  }
  
  /*