Merge branch 'jt/unify-object-info'
authorJunio C Hamano <gitster@pobox.com>
Wed, 5 Jul 2017 20:32:57 +0000 (13:32 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 5 Jul 2017 20:32:57 +0000 (13:32 -0700)
Code clean-ups.

* jt/unify-object-info:
sha1_file: refactor has_sha1_file_with_flags
sha1_file: do not access pack if unneeded
sha1_file: teach sha1_object_info_extended more flags
sha1_file: refactor read_object
sha1_file: move delta base cache code up
sha1_file: rename LOOKUP_REPLACE_OBJECT
sha1_file: rename LOOKUP_UNKNOWN_OBJECT
sha1_file: teach packed_object_info about typename

1  2 
builtin/cat-file.c
builtin/fetch.c
builtin/index-pack.c
cache.h
sha1_file.c
diff --combined builtin/cat-file.c
index 7efbc4019ac59a16ae4f147889e6f489dac1e661,a58b8c8200acd14a0583ccf5af6ae19b92dfb60e..96b786e4892aec0ed7e5d07ac8d3261c7b765f33
@@@ -4,7 -4,6 +4,7 @@@
   * Copyright (C) Linus Torvalds, 2005
   */
  #include "cache.h"
 +#include "config.h"
  #include "builtin.h"
  #include "diff.h"
  #include "parse-options.h"
@@@ -57,11 -56,11 +57,11 @@@ static int cat_one_file(int opt, const 
        struct object_context obj_context;
        struct object_info oi = OBJECT_INFO_INIT;
        struct strbuf sb = STRBUF_INIT;
-       unsigned flags = LOOKUP_REPLACE_OBJECT;
+       unsigned flags = OBJECT_INFO_LOOKUP_REPLACE;
        const char *path = force_path;
  
        if (unknown_type)
-               flags |= LOOKUP_UNKNOWN_OBJECT;
+               flags |= OBJECT_INFO_ALLOW_UNKNOWN_TYPE;
  
        if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH,
                                  oid.hash, &obj_context))
@@@ -338,7 -337,8 +338,8 @@@ static void batch_object_write(const ch
        struct strbuf buf = STRBUF_INIT;
  
        if (!data->skip_object_info &&
-           sha1_object_info_extended(data->oid.hash, &data->info, LOOKUP_REPLACE_OBJECT) < 0) {
+           sha1_object_info_extended(data->oid.hash, &data->info,
+                                     OBJECT_INFO_LOOKUP_REPLACE) < 0) {
                printf("%s missing\n",
                       obj_name ? obj_name : oid_to_hex(&data->oid));
                fflush(stdout);
diff --combined builtin/fetch.c
index 16cf8421ce4cc2221e6ed59110928328693481fb,4c8d055d6e3099339b503d7fd862f5f5de1a5c9e..1838a9abfba61b76a52e96520b9dc559cf4747a2
@@@ -2,7 -2,6 +2,7 @@@
   * "git fetch"
   */
  #include "cache.h"
 +#include "config.h"
  #include "refs.h"
  #include "commit.h"
  #include "builtin.h"
@@@ -250,9 -249,11 +250,11 @@@ static void find_non_local_tags(struct 
                 */
                if (ends_with(ref->name, "^{}")) {
                        if (item &&
-                           !has_object_file_with_flags(&ref->old_oid, HAS_SHA1_QUICK) &&
+                           !has_object_file_with_flags(&ref->old_oid,
+                                                       OBJECT_INFO_QUICK) &&
                            !will_fetch(head, ref->old_oid.hash) &&
-                           !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) &&
+                           !has_sha1_file_with_flags(item->util,
+                                                     OBJECT_INFO_QUICK) &&
                            !will_fetch(head, item->util))
                                item->util = NULL;
                        item = NULL;
                 * fetch.
                 */
                if (item &&
-                   !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) &&
+                   !has_sha1_file_with_flags(item->util, OBJECT_INFO_QUICK) &&
                    !will_fetch(head, item->util))
                        item->util = NULL;
  
         * checked to see if it needs fetching.
         */
        if (item &&
-           !has_sha1_file_with_flags(item->util, HAS_SHA1_QUICK) &&
+           !has_sha1_file_with_flags(item->util, OBJECT_INFO_QUICK) &&
            !will_fetch(head, item->util))
                item->util = NULL;
  
diff --combined builtin/index-pack.c
index ad4de3517853892e979d43511e2e7260746c3ba9,587bc80c964f6d303822f7c42043d14638d30dfb..26828c1d82bc9a997041cb464d4a3fde38e2d19d
@@@ -1,5 -1,4 +1,5 @@@
  #include "builtin.h"
 +#include "config.h"
  #include "delta.h"
  #include "pack.h"
  #include "csum-file.h"
@@@ -389,7 -388,8 +389,7 @@@ static struct base_data *alloc_base_dat
  static void free_base_data(struct base_data *c)
  {
        if (c->data) {
 -              free(c->data);
 -              c->data = NULL;
 +              FREE_AND_NULL(c->data);
                get_thread_data()->base_cache_used -= c->size;
        }
  }
@@@ -605,7 -605,8 +605,7 @@@ static void *unpack_data(struct object_
        git_inflate_end(&stream);
        free(inbuf);
        if (consume) {
 -              free(data);
 -              data = NULL;
 +              FREE_AND_NULL(data);
        }
        return data;
  }
@@@ -793,7 -794,8 +793,8 @@@ static void sha1_object(const void *dat
  
        if (startup_info->have_repository) {
                read_lock();
-               collision_test_needed = has_sha1_file_with_flags(oid->hash, HAS_SHA1_QUICK);
+               collision_test_needed =
+                       has_sha1_file_with_flags(oid->hash, OBJECT_INFO_QUICK);
                read_unlock();
        }
  
diff --combined cache.h
index c12f45289044dd846a1ddbfecf24ea84d71ef29f,3ae9769aaf8430d883546a74e678f08f4f6b6fdd..71fe092644c2c4032ed29c2801fefdf976736db0
+++ b/cache.h
@@@ -11,8 -11,6 +11,8 @@@
  #include "string-list.h"
  #include "pack-revindex.h"
  #include "hash.h"
 +#include "path.h"
 +#include "sha1-array.h"
  
  #ifndef platform_SHA_CTX
  /*
@@@ -464,8 -462,6 +464,8 @@@ static inline enum object_type object_t
   */
  extern const char * const local_repo_env[];
  
 +extern void setup_git_env(void);
 +
  /*
   * Returns true iff we have a configured git repository (either via
   * setup_git_directory, or in the environment via $GIT_DIR).
@@@ -529,15 -525,12 +529,15 @@@ extern void set_git_work_tree(const cha
  
  extern void setup_work_tree(void);
  /*
 - * Find GIT_DIR of the repository that contains the current working directory,
 - * without changing the working directory or other global state. The result is
 - * appended to gitdir. The return value is either NULL if no repository was
 - * found, or pointing to the path inside gitdir's buffer.
 + * Find the commondir and gitdir of the repository that contains the current
 + * working directory, without changing the working directory or other global
 + * state. The result is appended to commondir and gitdir.  If the discovered
 + * gitdir does not correspond to a worktree, then 'commondir' and 'gitdir' will
 + * both have the same result appended to the buffer.  The return value is
 + * either 0 upon success and non-zero if no repository was found.
   */
 -extern const char *discover_git_directory(struct strbuf *gitdir);
 +extern int discover_git_directory(struct strbuf *commondir,
 +                                struct strbuf *gitdir);
  extern const char *setup_git_directory_gently(int *);
  extern const char *setup_git_directory(void);
  extern char *prefix_path(const char *prefix, int len, const char *path);
@@@ -773,6 -766,7 +773,6 @@@ extern int core_apply_sparse_checkout
  extern int precomposed_unicode;
  extern int protect_hfs;
  extern int protect_ntfs;
 -extern int git_db_env, git_index_env, git_graft_env, git_common_dir_env;
  
  /*
   * Include broken refs in all ref iterations, which will
@@@ -894,6 -888,64 +894,6 @@@ extern void check_repository_format(voi
  #define DATA_CHANGED    0x0020
  #define TYPE_CHANGED    0x0040
  
 -/*
 - * Return a statically allocated filename, either generically (mkpath), in
 - * the repository directory (git_path), or in a submodule's repository
 - * directory (git_path_submodule). In all cases, note that the result
 - * may be overwritten by another call to _any_ of the functions. Consider
 - * using the safer "dup" or "strbuf" formats below (in some cases, the
 - * unsafe versions have already been removed).
 - */
 -extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -extern const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -
 -extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
 -      __attribute__((format (printf, 3, 4)));
 -extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path,
 -                                   const char *fmt, ...)
 -      __attribute__((format (printf, 3, 4)));
 -extern char *git_pathdup(const char *fmt, ...)
 -      __attribute__((format (printf, 1, 2)));
 -extern char *mkpathdup(const char *fmt, ...)
 -      __attribute__((format (printf, 1, 2)));
 -extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -
 -extern void report_linked_checkout_garbage(void);
 -
 -/*
 - * You can define a static memoized git path like:
 - *
 - *    static GIT_PATH_FUNC(git_path_foo, "FOO");
 - *
 - * or use one of the global ones below.
 - */
 -#define GIT_PATH_FUNC(func, filename) \
 -      const char *func(void) \
 -      { \
 -              static char *ret; \
 -              if (!ret) \
 -                      ret = git_pathdup(filename); \
 -              return ret; \
 -      }
 -
 -const char *git_path_cherry_pick_head(void);
 -const char *git_path_revert_head(void);
 -const char *git_path_squash_msg(void);
 -const char *git_path_merge_msg(void);
 -const char *git_path_merge_rr(void);
 -const char *git_path_merge_mode(void);
 -const char *git_path_merge_head(void);
 -const char *git_path_fetch_head(void);
 -const char *git_path_shallow(void);
 -
  /*
   * Return the name of the file in the local object database that would
   * be used to store a loose object with the specified sha1.  The
@@@ -974,13 -1026,6 +974,13 @@@ static inline void oidcpy(struct object
        hashcpy(dst->hash, src->hash);
  }
  
 +static inline struct object_id *oiddup(const struct object_id *src)
 +{
 +      struct object_id *dst = xmalloc(sizeof(struct object_id));
 +      oidcpy(dst, src);
 +      return dst;
 +}
 +
  static inline void hashclr(unsigned char *hash)
  {
        memset(hash, 0, GIT_SHA1_RAWSZ);
@@@ -1160,13 -1205,12 +1160,12 @@@ extern char *xdg_config_home(const cha
   */
  extern char *xdg_cache_home(const char *filename);
  
- /* object replacement */
- #define LOOKUP_REPLACE_OBJECT 1
- #define LOOKUP_UNKNOWN_OBJECT 2
- extern void *read_sha1_file_extended(const unsigned char *sha1, enum object_type *type, unsigned long *size, unsigned flag);
+ extern void *read_sha1_file_extended(const unsigned char *sha1,
+                                    enum object_type *type,
+                                    unsigned long *size, int lookup_replace);
  static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
  {
-       return read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);
+       return read_sha1_file_extended(sha1, type, size, 1);
  }
  
  /*
@@@ -1188,13 -1232,6 +1187,6 @@@ static inline const unsigned char *look
        return do_lookup_replace_object(sha1);
  }
  
- static inline const unsigned char *lookup_replace_object_extended(const unsigned char *sha1, unsigned flag)
- {
-       if (!(flag & LOOKUP_REPLACE_OBJECT))
-               return sha1;
-       return lookup_replace_object(sha1);
- }
  /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
  extern int sha1_object_info(const unsigned char *, unsigned long *);
  extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
@@@ -1231,15 -1268,10 +1223,10 @@@ int read_loose_object(const char *path
                      void **contents);
  
  /*
-  * Return true iff we have an object named sha1, whether local or in
-  * an alternate object database, and whether packed or loose.  This
-  * function does not respect replace references.
-  *
-  * If the QUICK flag is set, do not re-check the pack directory
-  * when we cannot find the object (this means we may give a false
-  * negative answer if another process is simultaneously repacking).
+  * Convenience for sha1_object_info_extended() with a NULL struct
+  * object_info. OBJECT_INFO_SKIP_CACHED is automatically set; pass
+  * nonzero flags to also set other flags.
   */
- #define HAS_SHA1_QUICK 0x1
  extern int has_sha1_file_with_flags(const unsigned char *sha1, int flags);
  static inline int has_sha1_file(const unsigned char *sha1)
  {
@@@ -1541,16 -1573,6 +1528,16 @@@ extern struct alternate_object_databas
        struct strbuf scratch;
        size_t base_len;
  
 +      /*
 +       * Used to store the results of readdir(3) calls when searching
 +       * for unique abbreviated hashes.  This cache is never
 +       * invalidated, thus it's racy and not necessarily accurate.
 +       * That's fine for its purpose; don't use it for tasks requiring
 +       * greater accuracy!
 +       */
 +      char loose_objects_subdir_seen[256];
 +      struct oid_array loose_objects_cache;
 +
        char path[FLEX_ARRAY];
  } *alt_odb_list;
  extern void prepare_alt_odb(void);
@@@ -1766,15 -1788,9 +1753,15 @@@ typedef int each_loose_object_fn(const 
  typedef int each_loose_cruft_fn(const char *basename,
                                const char *path,
                                void *data);
 -typedef int each_loose_subdir_fn(int nr,
 +typedef int each_loose_subdir_fn(unsigned int nr,
                                 const char *path,
                                 void *data);
 +int for_each_file_in_obj_subdir(unsigned int subdir_nr,
 +                              struct strbuf *path,
 +                              each_loose_object_fn obj_cb,
 +                              each_loose_cruft_fn cruft_cb,
 +                              each_loose_subdir_fn subdir_cb,
 +                              void *data);
  int for_each_loose_file_in_objdir(const char *path,
                                  each_loose_object_fn obj_cb,
                                  each_loose_cruft_fn cruft_cb,
@@@ -1806,6 -1822,7 +1793,7 @@@ struct object_info 
        off_t *disk_sizep;
        unsigned char *delta_base_sha1;
        struct strbuf *typename;
+       void **contentp;
  
        /* Response */
        enum {
   */
  #define OBJECT_INFO_INIT {NULL}
  
+ /* Invoke lookup_replace_object() on the given hash */
+ #define OBJECT_INFO_LOOKUP_REPLACE 1
+ /* Allow reading from a loose object file of unknown/bogus type */
+ #define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2
+ /* Do not check cached storage */
+ #define OBJECT_INFO_SKIP_CACHED 4
+ /* Do not retry packed storage after checking packed and loose storage */
+ #define OBJECT_INFO_QUICK 8
  extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags);
  extern int packed_object_info(struct packed_git *pack, off_t offset, struct object_info *);
  
  /* Dumb servers support */
  extern int update_server_info(int);
  
 -/* git_config_parse_key() returns these negated: */
 -#define CONFIG_INVALID_KEY 1
 -#define CONFIG_NO_SECTION_OR_NAME 2
 -/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */
 -#define CONFIG_NO_LOCK -1
 -#define CONFIG_INVALID_FILE 3
 -#define CONFIG_NO_WRITE 4
 -#define CONFIG_NOTHING_SET 5
 -#define CONFIG_INVALID_PATTERN 6
 -#define CONFIG_GENERIC_ERROR 7
 -
 -#define CONFIG_REGEX_NONE ((void *)1)
 -
 -struct git_config_source {
 -      unsigned int use_stdin:1;
 -      const char *file;
 -      const char *blob;
 -};
 -
 -enum config_origin_type {
 -      CONFIG_ORIGIN_BLOB,
 -      CONFIG_ORIGIN_FILE,
 -      CONFIG_ORIGIN_STDIN,
 -      CONFIG_ORIGIN_SUBMODULE_BLOB,
 -      CONFIG_ORIGIN_CMDLINE
 -};
 -
 -struct config_options {
 -      unsigned int respect_includes : 1;
 -      const char *git_dir;
 -};
 -
 -typedef int (*config_fn_t)(const char *, const char *, void *);
 -extern int git_default_config(const char *, const char *, void *);
 -extern int git_config_from_file(config_fn_t fn, const char *, void *);
 -extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,
 -                                      const char *name, const char *buf, size_t len, void *data);
 -extern int git_config_from_blob_sha1(config_fn_t fn, const char *name,
 -                                   const unsigned char *sha1, void *data);
 -extern void git_config_push_parameter(const char *text);
 -extern int git_config_from_parameters(config_fn_t fn, void *data);
 -extern void read_early_config(config_fn_t cb, void *data);
 -extern void git_config(config_fn_t fn, void *);
 -extern int git_config_with_options(config_fn_t fn, void *,
 -                                 struct git_config_source *config_source,
 -                                 const struct config_options *opts);
 -extern int git_parse_ulong(const char *, unsigned long *);
 -extern int git_parse_maybe_bool(const char *);
 -extern int git_config_int(const char *, const char *);
 -extern int64_t git_config_int64(const char *, const char *);
 -extern unsigned long git_config_ulong(const char *, const char *);
 -extern ssize_t git_config_ssize_t(const char *, const char *);
 -extern int git_config_bool_or_int(const char *, const char *, int *);
 -extern int git_config_bool(const char *, const char *);
 -extern int git_config_maybe_bool(const char *, const char *);
 -extern int git_config_string(const char **, const char *, const char *);
 -extern int git_config_pathname(const char **, const char *, const char *);
 -extern int git_config_set_in_file_gently(const char *, const char *, const char *);
 -extern void git_config_set_in_file(const char *, const char *, const char *);
 -extern int git_config_set_gently(const char *, const char *);
 -extern void git_config_set(const char *, const char *);
 -extern int git_config_parse_key(const char *, char **, int *);
 -extern int git_config_key_is_valid(const char *key);
 -extern int git_config_set_multivar_gently(const char *, const char *, const char *, int);
 -extern void git_config_set_multivar(const char *, const char *, const char *, int);
 -extern int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int);
 -extern void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
 -extern int git_config_rename_section(const char *, const char *);
 -extern int git_config_rename_section_in_file(const char *, const char *, const char *);
 -extern const char *git_etc_gitconfig(void);
 -extern int git_env_bool(const char *, int);
 -extern unsigned long git_env_ulong(const char *, unsigned long);
 -extern int git_config_system(void);
 -extern int config_error_nonbool(const char *);
 -#if defined(__GNUC__)
 -#define config_error_nonbool(s) (config_error_nonbool(s), const_error())
 -#endif
  extern const char *get_log_output_encoding(void);
  extern const char *get_commit_output_encoding(void);
  
 -extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 -
 -enum config_scope {
 -      CONFIG_SCOPE_UNKNOWN = 0,
 -      CONFIG_SCOPE_SYSTEM,
 -      CONFIG_SCOPE_GLOBAL,
 -      CONFIG_SCOPE_REPO,
 -      CONFIG_SCOPE_CMDLINE,
 -};
 -
 -extern enum config_scope current_config_scope(void);
 -extern const char *current_config_origin_type(void);
 -extern const char *current_config_name(void);
 -
 -struct config_include_data {
 -      int depth;
 -      config_fn_t fn;
 -      void *data;
 -      const struct config_options *opts;
 -};
 -#define CONFIG_INCLUDE_INIT { 0 }
 -extern int git_config_include(const char *name, const char *value, void *data);
 -
 -/*
 - * Match and parse a config key of the form:
 - *
 - *   section.(subsection.)?key
 - *
 - * (i.e., what gets handed to a config_fn_t). The caller provides the section;
 - * we return -1 if it does not match, 0 otherwise. The subsection and key
 - * out-parameters are filled by the function (and *subsection is NULL if it is
 - * missing).
 - *
 - * If the subsection pointer-to-pointer passed in is NULL, returns 0 only if
 - * there is no subsection at all.
 - */
 -extern int parse_config_key(const char *var,
 -                          const char *section,
 -                          const char **subsection, int *subsection_len,
 -                          const char **key);
 -
 -struct config_set_element {
 -      struct hashmap_entry ent;
 -      char *key;
 -      struct string_list value_list;
 -};
 -
 -struct configset_list_item {
 -      struct config_set_element *e;
 -      int value_index;
 -};
 -
 -/*
 - * the contents of the list are ordered according to their
 - * position in the config files and order of parsing the files.
 - * (i.e. key-value pair at the last position of .git/config will
 - * be at the last item of the list)
 - */
 -struct configset_list {
 -      struct configset_list_item *items;
 -      unsigned int nr, alloc;
 -};
 -
 -struct config_set {
 -      struct hashmap config_hash;
 -      int hash_initialized;
 -      struct configset_list list;
 -};
 -
 -extern void git_configset_init(struct config_set *cs);
 -extern int git_configset_add_file(struct config_set *cs, const char *filename);
 -extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value);
 -extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);
 -extern void git_configset_clear(struct config_set *cs);
 -extern int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest);
 -extern int git_configset_get_string(struct config_set *cs, const char *key, char **dest);
 -extern int git_configset_get_int(struct config_set *cs, const char *key, int *dest);
 -extern int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest);
 -extern int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);
 -extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest);
 -extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);
 -extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);
 -
 -extern int git_config_get_value(const char *key, const char **value);
 -extern const struct string_list *git_config_get_value_multi(const char *key);
 -extern void git_config_clear(void);
 -extern void git_config_iter(config_fn_t fn, void *data);
 -extern int git_config_get_string_const(const char *key, const char **dest);
 -extern int git_config_get_string(const char *key, char **dest);
 -extern int git_config_get_int(const char *key, int *dest);
 -extern int git_config_get_ulong(const char *key, unsigned long *dest);
 -extern int git_config_get_bool(const char *key, int *dest);
 -extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);
 -extern int git_config_get_maybe_bool(const char *key, int *dest);
 -extern int git_config_get_pathname(const char *key, const char **dest);
 -extern int git_config_get_untracked_cache(void);
 -extern int git_config_get_split_index(void);
 -extern int git_config_get_max_percent_split_change(void);
 -
 -/* This dies if the configured or default date is in the future */
 -extern int git_config_get_expiry(const char *key, const char **output);
 -
  /*
   * This is a hack for test programs like test-dump-untracked-cache to
   * ensure that they do not modify the untracked cache when reading it.
   */
  extern int ignore_untracked_cache_config;
  
 -struct key_value_info {
 -      const char *filename;
 -      int linenr;
 -      enum config_origin_type origin_type;
 -      enum config_scope scope;
 -};
 -
 -extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
 -extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);
 -
  extern int committer_ident_sufficiently_given(void);
  extern int author_ident_sufficiently_given(void);
  
@@@ -1968,8 -2182,7 +1964,8 @@@ extern int ws_blank_line(const char *li
  #define ws_tab_width(rule)     ((rule) & WS_TAB_WIDTH_MASK)
  
  /* ls-files */
 -void overlay_tree_on_cache(const char *tree_name, const char *prefix);
 +void overlay_tree_on_index(struct index_state *istate,
 +                         const char *tree_name, const char *prefix);
  
  char *alias_lookup(const char *alias);
  int split_cmdline(char *cmdline, const char ***argv);
diff --combined sha1_file.c
index 9a9f7f7bcc8eaaa6c519af9955deaa6b39741d74,778f01d923873604aa39d66170ea7e393090158f..5862386cd0c2b2020890905bd06cd3a9d89c123b
@@@ -7,7 -7,6 +7,7 @@@
   * creation etc.
   */
  #include "cache.h"
 +#include "config.h"
  #include "string-list.h"
  #include "lockfile.h"
  #include "delta.h"
@@@ -611,7 -610,8 +611,7 @@@ char *compute_alternate_path(const cha
  
  out:
        if (seen_error) {
 -              free(ref_git);
 -              ref_git = NULL;
 +              FREE_AND_NULL(ref_git);
        }
  
        return ref_git;
@@@ -1964,7 -1964,7 +1964,7 @@@ static int parse_sha1_header_extended(c
         * we're obtaining the type using '--allow-unknown-type'
         * option.
         */
-       if ((flags & LOOKUP_UNKNOWN_OBJECT) && (type < 0))
+       if ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE) && (type < 0))
                type = 0;
        else if (type < 0)
                die("invalid object type");
@@@ -2002,20 -2002,7 +2002,7 @@@ int parse_sha1_header(const char *hdr, 
        struct object_info oi = OBJECT_INFO_INIT;
  
        oi.sizep = sizep;
-       return parse_sha1_header_extended(hdr, &oi, LOOKUP_REPLACE_OBJECT);
- }
- static void *unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size, const unsigned char *sha1)
- {
-       int ret;
-       git_zstream stream;
-       char hdr[8192];
-       ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
-       if (ret < Z_OK || (*type = parse_sha1_header(hdr, size)) < 0)
-               return NULL;
-       return unpack_sha1_rest(&stream, hdr, *size, sha1);
+       return parse_sha1_header_extended(hdr, &oi, 0);
  }
  
  unsigned long get_size_from_delta(struct packed_git *p,
@@@ -2239,107 -2226,6 +2226,6 @@@ unwind
        goto out;
  }
  
- int packed_object_info(struct packed_git *p, off_t obj_offset,
-                      struct object_info *oi)
- {
-       struct pack_window *w_curs = NULL;
-       unsigned long size;
-       off_t curpos = obj_offset;
-       enum object_type type;
-       /*
-        * We always get the representation type, but only convert it to
-        * a "real" type later if the caller is interested.
-        */
-       type = unpack_object_header(p, &w_curs, &curpos, &size);
-       if (oi->sizep) {
-               if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
-                       off_t tmp_pos = curpos;
-                       off_t base_offset = get_delta_base(p, &w_curs, &tmp_pos,
-                                                          type, obj_offset);
-                       if (!base_offset) {
-                               type = OBJ_BAD;
-                               goto out;
-                       }
-                       *oi->sizep = get_size_from_delta(p, &w_curs, tmp_pos);
-                       if (*oi->sizep == 0) {
-                               type = OBJ_BAD;
-                               goto out;
-                       }
-               } else {
-                       *oi->sizep = size;
-               }
-       }
-       if (oi->disk_sizep) {
-               struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
-               *oi->disk_sizep = revidx[1].offset - obj_offset;
-       }
-       if (oi->typep) {
-               *oi->typep = packed_to_object_type(p, obj_offset, type, &w_curs, curpos);
-               if (*oi->typep < 0) {
-                       type = OBJ_BAD;
-                       goto out;
-               }
-       }
-       if (oi->delta_base_sha1) {
-               if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
-                       const unsigned char *base;
-                       base = get_delta_base_sha1(p, &w_curs, curpos,
-                                                  type, obj_offset);
-                       if (!base) {
-                               type = OBJ_BAD;
-                               goto out;
-                       }
-                       hashcpy(oi->delta_base_sha1, base);
-               } else
-                       hashclr(oi->delta_base_sha1);
-       }
- out:
-       unuse_pack(&w_curs);
-       return type;
- }
- static void *unpack_compressed_entry(struct packed_git *p,
-                                   struct pack_window **w_curs,
-                                   off_t curpos,
-                                   unsigned long size)
- {
-       int st;
-       git_zstream stream;
-       unsigned char *buffer, *in;
-       buffer = xmallocz_gently(size);
-       if (!buffer)
-               return NULL;
-       memset(&stream, 0, sizeof(stream));
-       stream.next_out = buffer;
-       stream.avail_out = size + 1;
-       git_inflate_init(&stream);
-       do {
-               in = use_pack(p, w_curs, curpos, &stream.avail_in);
-               stream.next_in = in;
-               st = git_inflate(&stream, Z_FINISH);
-               if (!stream.avail_out)
-                       break; /* the payload is larger than it should be */
-               curpos += stream.next_in - in;
-       } while (st == Z_OK || st == Z_BUF_ERROR);
-       git_inflate_end(&stream);
-       if ((st != Z_STREAM_END) || stream.total_out != size) {
-               free(buffer);
-               return NULL;
-       }
-       return buffer;
- }
  static struct hashmap delta_base_cache;
  static size_t delta_base_cached;
  
@@@ -2427,8 -2313,10 +2313,10 @@@ static void *cache_or_unpack_entry(stru
        if (!ent)
                return unpack_entry(p, base_offset, type, base_size);
  
-       *type = ent->type;
-       *base_size = ent->size;
+       if (type)
+               *type = ent->type;
+       if (base_size)
+               *base_size = ent->size;
        return xmemdupz(ent->data, ent->size);
  }
  
@@@ -2477,6 -2365,123 +2365,123 @@@ static void add_delta_base_cache(struc
        hashmap_add(&delta_base_cache, ent);
  }
  
+ int packed_object_info(struct packed_git *p, off_t obj_offset,
+                      struct object_info *oi)
+ {
+       struct pack_window *w_curs = NULL;
+       unsigned long size;
+       off_t curpos = obj_offset;
+       enum object_type type;
+       /*
+        * We always get the representation type, but only convert it to
+        * a "real" type later if the caller is interested.
+        */
+       if (oi->contentp) {
+               *oi->contentp = cache_or_unpack_entry(p, obj_offset, oi->sizep,
+                                                     &type);
+               if (!*oi->contentp)
+                       type = OBJ_BAD;
+       } else {
+               type = unpack_object_header(p, &w_curs, &curpos, &size);
+       }
+       if (!oi->contentp && oi->sizep) {
+               if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
+                       off_t tmp_pos = curpos;
+                       off_t base_offset = get_delta_base(p, &w_curs, &tmp_pos,
+                                                          type, obj_offset);
+                       if (!base_offset) {
+                               type = OBJ_BAD;
+                               goto out;
+                       }
+                       *oi->sizep = get_size_from_delta(p, &w_curs, tmp_pos);
+                       if (*oi->sizep == 0) {
+                               type = OBJ_BAD;
+                               goto out;
+                       }
+               } else {
+                       *oi->sizep = size;
+               }
+       }
+       if (oi->disk_sizep) {
+               struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
+               *oi->disk_sizep = revidx[1].offset - obj_offset;
+       }
+       if (oi->typep || oi->typename) {
+               enum object_type ptot;
+               ptot = packed_to_object_type(p, obj_offset, type, &w_curs,
+                                            curpos);
+               if (oi->typep)
+                       *oi->typep = ptot;
+               if (oi->typename) {
+                       const char *tn = typename(ptot);
+                       if (tn)
+                               strbuf_addstr(oi->typename, tn);
+               }
+               if (ptot < 0) {
+                       type = OBJ_BAD;
+                       goto out;
+               }
+       }
+       if (oi->delta_base_sha1) {
+               if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
+                       const unsigned char *base;
+                       base = get_delta_base_sha1(p, &w_curs, curpos,
+                                                  type, obj_offset);
+                       if (!base) {
+                               type = OBJ_BAD;
+                               goto out;
+                       }
+                       hashcpy(oi->delta_base_sha1, base);
+               } else
+                       hashclr(oi->delta_base_sha1);
+       }
+ out:
+       unuse_pack(&w_curs);
+       return type;
+ }
+ static void *unpack_compressed_entry(struct packed_git *p,
+                                   struct pack_window **w_curs,
+                                   off_t curpos,
+                                   unsigned long size)
+ {
+       int st;
+       git_zstream stream;
+       unsigned char *buffer, *in;
+       buffer = xmallocz_gently(size);
+       if (!buffer)
+               return NULL;
+       memset(&stream, 0, sizeof(stream));
+       stream.next_out = buffer;
+       stream.avail_out = size + 1;
+       git_inflate_init(&stream);
+       do {
+               in = use_pack(p, w_curs, curpos, &stream.avail_in);
+               stream.next_in = in;
+               st = git_inflate(&stream, Z_FINISH);
+               if (!stream.avail_out)
+                       break; /* the payload is larger than it should be */
+               curpos += stream.next_in - in;
+       } while (st == Z_OK || st == Z_BUF_ERROR);
+       git_inflate_end(&stream);
+       if ((st != Z_STREAM_END) || stream.total_out != size) {
+               free(buffer);
+               return NULL;
+       }
+       return buffer;
+ }
  static void *read_object(const unsigned char *sha1, enum object_type *type,
                         unsigned long *size);
  
@@@ -2670,8 -2675,10 +2675,10 @@@ void *unpack_entry(struct packed_git *p
                free(external_base);
        }
  
-       *final_type = type;
-       *final_size = size;
+       if (final_type)
+               *final_type = type;
+       if (final_size)
+               *final_size = size;
  
        unuse_pack(&w_curs);
  
@@@ -2905,6 -2912,7 +2912,7 @@@ static int sha1_loose_object_info(cons
        git_zstream stream;
        char hdr[32];
        struct strbuf hdrbuf = STRBUF_INIT;
+       unsigned long size_scratch;
  
        if (oi->delta_base_sha1)
                hashclr(oi->delta_base_sha1);
         * return value implicitly indicates whether the
         * object even exists.
         */
-       if (!oi->typep && !oi->typename && !oi->sizep) {
+       if (!oi->typep && !oi->typename && !oi->sizep && !oi->contentp) {
                const char *path;
                struct stat st;
                if (stat_sha1_file(sha1, &st, &path) < 0)
        map = map_sha1_file(sha1, &mapsize);
        if (!map)
                return -1;
+       if (!oi->sizep)
+               oi->sizep = &size_scratch;
        if (oi->disk_sizep)
                *oi->disk_sizep = mapsize;
-       if ((flags & LOOKUP_UNKNOWN_OBJECT)) {
+       if ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE)) {
                if (unpack_sha1_header_to_strbuf(&stream, map, mapsize, hdr, sizeof(hdr), &hdrbuf) < 0)
                        status = error("unable to unpack %s header with --allow-unknown-type",
                                       sha1_to_hex(sha1));
                                       sha1_to_hex(sha1));
        } else if ((status = parse_sha1_header_extended(hdr, oi, flags)) < 0)
                status = error("unable to parse %s header", sha1_to_hex(sha1));
-       git_inflate_end(&stream);
+       if (status >= 0 && oi->contentp)
+               *oi->contentp = unpack_sha1_rest(&stream, hdr,
+                                                *oi->sizep, sha1);
+       else
+               git_inflate_end(&stream);
        munmap(map, mapsize);
        if (status && oi->typep)
                *oi->typep = status;
+       if (oi->sizep == &size_scratch)
+               oi->sizep = NULL;
        strbuf_release(&hdrbuf);
        return (status < 0) ? status : 0;
  }
  
  int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi, unsigned flags)
  {
-       struct cached_object *co;
+       static struct object_info blank_oi = OBJECT_INFO_INIT;
        struct pack_entry e;
        int rtype;
-       enum object_type real_type;
-       const unsigned char *real = lookup_replace_object_extended(sha1, flags);
-       co = find_cached_object(real);
-       if (co) {
-               if (oi->typep)
-                       *(oi->typep) = co->type;
-               if (oi->sizep)
-                       *(oi->sizep) = co->size;
-               if (oi->disk_sizep)
-                       *(oi->disk_sizep) = 0;
-               if (oi->delta_base_sha1)
-                       hashclr(oi->delta_base_sha1);
-               if (oi->typename)
-                       strbuf_addstr(oi->typename, typename(co->type));
-               oi->whence = OI_CACHED;
-               return 0;
+       const unsigned char *real = (flags & OBJECT_INFO_LOOKUP_REPLACE) ?
+                                   lookup_replace_object(sha1) :
+                                   sha1;
+       if (!oi)
+               oi = &blank_oi;
+       if (!(flags & OBJECT_INFO_SKIP_CACHED)) {
+               struct cached_object *co = find_cached_object(real);
+               if (co) {
+                       if (oi->typep)
+                               *(oi->typep) = co->type;
+                       if (oi->sizep)
+                               *(oi->sizep) = co->size;
+                       if (oi->disk_sizep)
+                               *(oi->disk_sizep) = 0;
+                       if (oi->delta_base_sha1)
+                               hashclr(oi->delta_base_sha1);
+                       if (oi->typename)
+                               strbuf_addstr(oi->typename, typename(co->type));
+                       if (oi->contentp)
+                               *oi->contentp = xmemdupz(co->buf, co->size);
+                       oi->whence = OI_CACHED;
+                       return 0;
+               }
        }
  
        if (!find_pack_entry(real, &e)) {
                }
  
                /* Not a loose object; someone else may have just packed it. */
-               reprepare_packed_git();
-               if (!find_pack_entry(real, &e))
+               if (flags & OBJECT_INFO_QUICK) {
                        return -1;
+               } else {
+                       reprepare_packed_git();
+                       if (!find_pack_entry(real, &e))
+                               return -1;
+               }
        }
  
-       /*
-        * packed_object_info() does not follow the delta chain to
-        * find out the real type, unless it is given oi->typep.
-        */
-       if (oi->typename && !oi->typep)
-               oi->typep = &real_type;
+       if (oi == &blank_oi)
+               /*
+                * We know that the caller doesn't actually need the
+                * information below, so return early.
+                */
+               return 0;
  
        rtype = packed_object_info(e.p, e.offset, oi);
        if (rtype < 0) {
                mark_bad_packed_object(e.p, real);
-               if (oi->typep == &real_type)
-                       oi->typep = NULL;
                return sha1_object_info_extended(real, oi, 0);
        } else if (in_delta_base_cache(e.p, e.offset)) {
                oi->whence = OI_DBCACHED;
                oi->u.packed.is_delta = (rtype == OBJ_REF_DELTA ||
                                         rtype == OBJ_OFS_DELTA);
        }
-       if (oi->typename)
-               strbuf_addstr(oi->typename, typename(*oi->typep));
-       if (oi->typep == &real_type)
-               oi->typep = NULL;
  
        return 0;
  }
@@@ -3030,7 -3056,8 +3056,8 @@@ int sha1_object_info(const unsigned cha
  
        oi.typep = &type;
        oi.sizep = sizep;
-       if (sha1_object_info_extended(sha1, &oi, LOOKUP_REPLACE_OBJECT) < 0)
+       if (sha1_object_info_extended(sha1, &oi,
+                                     OBJECT_INFO_LOOKUP_REPLACE) < 0)
                return -1;
        return type;
  }
@@@ -3080,28 -3107,15 +3107,15 @@@ int pretend_sha1_file(void *buf, unsign
  static void *read_object(const unsigned char *sha1, enum object_type *type,
                         unsigned long *size)
  {
-       unsigned long mapsize;
-       void *map, *buf;
-       struct cached_object *co;
-       co = find_cached_object(sha1);
-       if (co) {
-               *type = co->type;
-               *size = co->size;
-               return xmemdupz(co->buf, co->size);
-       }
+       struct object_info oi = OBJECT_INFO_INIT;
+       void *content;
+       oi.typep = type;
+       oi.sizep = size;
+       oi.contentp = &content;
  
-       buf = read_packed_sha1(sha1, type, size);
-       if (buf)
-               return buf;
-       map = map_sha1_file(sha1, &mapsize);
-       if (map) {
-               buf = unpack_sha1_file(map, mapsize, type, size, sha1);
-               munmap(map, mapsize);
-               return buf;
-       }
-       reprepare_packed_git();
-       return read_packed_sha1(sha1, type, size);
+       if (sha1_object_info_extended(sha1, &oi, 0) < 0)
+               return NULL;
+       return content;
  }
  
  /*
  void *read_sha1_file_extended(const unsigned char *sha1,
                              enum object_type *type,
                              unsigned long *size,
-                             unsigned flag)
+                             int lookup_replace)
  {
        void *data;
        const struct packed_git *p;
        const char *path;
        struct stat st;
-       const unsigned char *repl = lookup_replace_object_extended(sha1, flag);
+       const unsigned char *repl = lookup_replace ? lookup_replace_object(sha1)
+                                                  : sha1;
  
        errno = 0;
        data = read_object(repl, type, size);
@@@ -3479,18 -3494,10 +3494,10 @@@ int has_sha1_pack(const unsigned char *
  
  int has_sha1_file_with_flags(const unsigned char *sha1, int flags)
  {
-       struct pack_entry e;
        if (!startup_info->have_repository)
                return 0;
-       if (find_pack_entry(sha1, &e))
-               return 1;
-       if (has_loose_object(sha1))
-               return 1;
-       if (flags & HAS_SHA1_QUICK)
-               return 0;
-       reprepare_packed_git();
-       return find_pack_entry(sha1, &e);
+       return sha1_object_info_extended(sha1, NULL,
+                                        flags | OBJECT_INFO_SKIP_CACHED) >= 0;
  }
  
  int has_object_file(const struct object_id *oid)
@@@ -3546,7 -3553,7 +3553,7 @@@ static int index_mem(unsigned char *sha
         */
        if ((type == OBJ_BLOB) && path) {
                struct strbuf nbuf = STRBUF_INIT;
 -              if (convert_to_git(path, buf, size, &nbuf,
 +              if (convert_to_git(&the_index, path, buf, size, &nbuf,
                                   write_object ? safe_crlf : SAFE_CRLF_FALSE)) {
                        buf = strbuf_detach(&nbuf, &size);
                        re_allocated = 1;
@@@ -3580,7 -3587,7 +3587,7 @@@ static int index_stream_convert_blob(un
        assert(path);
        assert(would_convert_to_git_filter_fd(path));
  
 -      convert_to_git_filter_fd(path, fd, &sbuf,
 +      convert_to_git_filter_fd(&the_index, path, fd, &sbuf,
                                 write_object ? safe_crlf : SAFE_CRLF_FALSE);
  
        if (write_object)
@@@ -3668,7 -3675,7 +3675,7 @@@ int index_fd(unsigned char *sha1, int f
        else if (!S_ISREG(st->st_mode))
                ret = index_pipe(sha1, fd, type, path, flags);
        else if (st->st_size <= big_file_threshold || type != OBJ_BLOB ||
 -               (path && would_convert_to_git(path)))
 +               (path && would_convert_to_git(&the_index, path)))
                ret = index_core(sha1, fd, xsize_t(st->st_size), type, path,
                                 flags);
        else
@@@ -3735,32 -3742,22 +3742,32 @@@ void assert_sha1_type(const unsigned ch
                    typename(expect));
  }
  
 -static int for_each_file_in_obj_subdir(int subdir_nr,
 -                                     struct strbuf *path,
 -                                     each_loose_object_fn obj_cb,
 -                                     each_loose_cruft_fn cruft_cb,
 -                                     each_loose_subdir_fn subdir_cb,
 -                                     void *data)
 +int for_each_file_in_obj_subdir(unsigned int subdir_nr,
 +                              struct strbuf *path,
 +                              each_loose_object_fn obj_cb,
 +                              each_loose_cruft_fn cruft_cb,
 +                              each_loose_subdir_fn subdir_cb,
 +                              void *data)
  {
 -      size_t baselen = path->len;
 -      DIR *dir = opendir(path->buf);
 +      size_t origlen, baselen;
 +      DIR *dir;
        struct dirent *de;
        int r = 0;
  
 +      if (subdir_nr > 0xff)
 +              BUG("invalid loose object subdirectory: %x", subdir_nr);
 +
 +      origlen = path->len;
 +      strbuf_complete(path, '/');
 +      strbuf_addf(path, "%02x", subdir_nr);
 +      baselen = path->len;
 +
 +      dir = opendir(path->buf);
        if (!dir) {
 -              if (errno == ENOENT)
 -                      return 0;
 -              return error_errno("unable to open %s", path->buf);
 +              if (errno != ENOENT)
 +                      r = error_errno("unable to open %s", path->buf);
 +              strbuf_setlen(path, origlen);
 +              return r;
        }
  
        while ((de = readdir(dir))) {
        if (!r && subdir_cb)
                r = subdir_cb(subdir_nr, path->buf, data);
  
 +      strbuf_setlen(path, origlen);
 +
        return r;
  }
  
@@@ -3809,12 -3804,15 +3816,12 @@@ int for_each_loose_file_in_objdir_buf(s
                            each_loose_subdir_fn subdir_cb,
                            void *data)
  {
 -      size_t baselen = path->len;
        int r = 0;
        int i;
  
        for (i = 0; i < 256; i++) {
 -              strbuf_addf(path, "/%02x", i);
                r = for_each_file_in_obj_subdir(i, path, obj_cb, cruft_cb,
                                                subdir_cb, data);
 -              strbuf_setlen(path, baselen);
                if (r)
                        break;
        }