Merge branch 'bc/hash-algo'
authorJunio C Hamano <gitster@pobox.com>
Wed, 13 Dec 2017 21:28:54 +0000 (13:28 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 13 Dec 2017 21:28:54 +0000 (13:28 -0800)
An infrastructure to define what hash function is used in Git is
introduced, and an effort to plumb that throughout various
codepaths has been started.

* bc/hash-algo:
repository: fix a sparse 'using integer as NULL pointer' warning
Switch empty tree and blob lookups to use hash abstraction
Integrate hash algorithm support with repo setup
Add structure representing hash algorithm
setup: expose enumerated repo info

1  2 
builtin/am.c
builtin/checkout.c
builtin/pull.c
cache.h
diff-lib.c
merge-recursive.c
sequencer.c
sha1_file.c
submodule.c
diff --combined builtin/am.c
index 02853b3e05bfef638963dbfe91a7eccf3d40b9e6,99dbde3e856a9533f2c2b316947fd8c631698efd..3d98e52085711abc6fa5ff9fd16d2828156df375
@@@ -1433,7 -1433,7 +1433,7 @@@ static void write_index_patch(const str
        if (!get_oid_tree("HEAD", &head))
                tree = lookup_tree(&head);
        else
-               tree = lookup_tree(&empty_tree_oid);
+               tree = lookup_tree(the_hash_algo->empty_tree);
  
        fp = xfopen(am_path(state, "patch"), "w");
        init_revisions(&rev_info, NULL);
@@@ -2148,7 -2148,7 +2148,7 @@@ static void am_abort(struct am_state *s
                           has_curr_head ? &curr_head : NULL, 0,
                           UPDATE_REFS_DIE_ON_ERR);
        else if (curr_branch)
 -              delete_ref(NULL, curr_branch, NULL, REF_NODEREF);
 +              delete_ref(NULL, curr_branch, NULL, REF_NO_DEREF);
  
        free(curr_branch);
        am_destroy(state);
diff --combined builtin/checkout.c
index 3faae382de4fa345f6d54c9120d33ed86c02e2cc,2b64805f353044539abc92c6b9320433bfdab2e9..e1e157d205a06ffad39a9685cab55b16c69d339c
@@@ -514,7 -514,7 +514,7 @@@ static int merge_working_tree(const str
                }
                tree = parse_tree_indirect(old->commit ?
                                           &old->commit->object.oid :
-                                          &empty_tree_oid);
+                                          the_hash_algo->empty_tree);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
                tree = parse_tree_indirect(&new->commit->object.oid);
                init_tree_desc(&trees[1], tree->buffer, tree->size);
@@@ -663,7 -663,7 +663,7 @@@ static void update_refs_for_switch(cons
                /* Nothing to do. */
        } else if (opts->force_detach || !new->path) {  /* No longer on any branch. */
                update_ref(msg.buf, "HEAD", &new->commit->object.oid, NULL,
 -                         REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
 +                         REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
                if (!opts->quiet) {
                        if (old->path &&
                            advice_detached_head && !opts->force_detach)
@@@ -1287,11 -1287,11 +1287,11 @@@ int cmd_checkout(int argc, const char *
        if (opts.new_branch) {
                struct strbuf buf = STRBUF_INIT;
  
 -              opts.branch_exists =
 -                      validate_new_branchname(opts.new_branch, &buf,
 -                                              !!opts.new_branch_force,
 -                                              !!opts.new_branch_force);
 -
 +              if (opts.new_branch_force)
 +                      opts.branch_exists = validate_branchname(opts.new_branch, &buf);
 +              else
 +                      opts.branch_exists =
 +                              validate_new_branchname(opts.new_branch, &buf, 0);
                strbuf_release(&buf);
        }
  
diff --combined builtin/pull.c
index 166b777ed69073f44f82e8052a0bdb6f287d22a9,3d26f8ff32723f1e60450ecae493204dda9cbb6b..511dbbe0f6e25d8f0e8c6ce511cc0ff734adc9bc
@@@ -113,8 -113,6 +113,8 @@@ static char *opt_depth
  static char *opt_unshallow;
  static char *opt_update_shallow;
  static char *opt_refmap;
 +static char *opt_ipv4;
 +static char *opt_ipv6;
  
  static struct option pull_options[] = {
        /* Shared options */
        OPT_PASSTHRU(0, "refmap", &opt_refmap, N_("refmap"),
                N_("specify fetch refmap"),
                PARSE_OPT_NONEG),
 +      OPT_PASSTHRU('4',  "ipv4", &opt_ipv4, NULL,
 +              N_("use IPv4 addresses only"),
 +              PARSE_OPT_NOARG),
 +      OPT_PASSTHRU('6',  "ipv6", &opt_ipv6, NULL,
 +              N_("use IPv6 addresses only"),
 +              PARSE_OPT_NOARG),
  
        OPT_END()
  };
@@@ -530,10 -522,6 +530,10 @@@ static int run_fetch(const char *repo, 
                argv_array_push(&args, opt_update_shallow);
        if (opt_refmap)
                argv_array_push(&args, opt_refmap);
 +      if (opt_ipv4)
 +              argv_array_push(&args, opt_ipv4);
 +      if (opt_ipv6)
 +              argv_array_push(&args, opt_ipv6);
  
        if (repo) {
                argv_array_push(&args, repo);
@@@ -557,7 -545,7 +557,7 @@@ static int pull_into_void(const struct 
         * index/worktree changes that the user already made on the unborn
         * branch.
         */
-       if (checkout_fast_forward(&empty_tree_oid, merge_head, 0))
+       if (checkout_fast_forward(the_hash_algo->empty_tree, merge_head, 0))
                return 1;
  
        if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
@@@ -763,15 -751,12 +763,15 @@@ static int get_octopus_merge_base(struc
        if (!is_null_oid(fork_point))
                commit_list_insert(lookup_commit_reference(fork_point), &revs);
  
 -      result = reduce_heads(get_octopus_merge_bases(revs));
 +      result = get_octopus_merge_bases(revs);
        free_commit_list(revs);
 +      reduce_heads_replace(&result);
 +
        if (!result)
                return 1;
  
        oidcpy(merge_base, &result->item->object.oid);
 +      free_commit_list(result);
        return 0;
  }
  
diff --combined cache.h
index cb5db7bf83053f675acebe4f8255f52881425773,d68895b45fbeb95df893bf7c95efe639097ee0fc..d3e240228c9c488f78ee9be06c9d151f1d2325b2
+++ b/cache.h
@@@ -14,6 -14,7 +14,7 @@@
  #include "hash.h"
  #include "path.h"
  #include "sha1-array.h"
+ #include "repository.h"
  
  #ifndef platform_SHA_CTX
  /*
@@@ -77,6 -78,8 +78,8 @@@ struct object_id 
        unsigned char hash[GIT_MAX_RAWSZ];
  };
  
+ #define the_hash_algo the_repository->hash_algo
  #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
  #define DTYPE(de)     ((de)->d_type)
  #else
@@@ -204,7 -207,6 +207,7 @@@ struct cache_entry 
  #define CE_ADDED             (1 << 19)
  
  #define CE_HASHED            (1 << 20)
 +#define CE_FSMONITOR_VALID   (1 << 21)
  #define CE_WT_REMOVE         (1 << 22) /* remove in work directory */
  #define CE_CONFLICTED        (1 << 23)
  
@@@ -328,7 -330,6 +331,7 @@@ static inline unsigned int canon_mode(u
  #define CACHE_TREE_CHANGED    (1 << 5)
  #define SPLIT_INDEX_ORDERED   (1 << 6)
  #define UNTRACKED_CHANGED     (1 << 7)
 +#define FSMONITOR_CHANGED     (1 << 8)
  
  struct split_index;
  struct untracked_cache;
@@@ -347,8 -348,6 +350,8 @@@ struct index_state 
        struct hashmap dir_hash;
        unsigned char sha1[20];
        struct untracked_cache *untracked;
 +      uint64_t fsmonitor_last_update;
 +      struct ewah_bitmap *fsmonitor_dirty;
  };
  
  extern struct index_state the_index;
@@@ -450,16 -449,6 +453,16 @@@ static inline enum object_type object_t
  #define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
  #define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
  
 +/*
 + * Environment variable used in handshaking the wire protocol.
 + * Contains a colon ':' separated list of keys with optional values
 + * 'key[=value]'.  Presence of unknown keys and values must be
 + * ignored.
 + */
 +#define GIT_PROTOCOL_ENVIRONMENT "GIT_PROTOCOL"
 +/* HTTP header used to handshake the wire protocol */
 +#define GIT_PROTOCOL_HEADER "Git-Protocol"
 +
  /*
   * This environment variable is expected to contain a boolean indicating
   * whether we should or should not treat:
@@@ -714,14 -703,11 +717,14 @@@ extern void *read_blob_data_from_index(
  #define CE_MATCH_IGNORE_MISSING               0x08
  /* enable stat refresh */
  #define CE_MATCH_REFRESH              0x10
 -extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
 -extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
 +/* don't refresh_fsmonitor state or do stat comparison even if CE_FSMONITOR_VALID is true */
 +#define CE_MATCH_IGNORE_FSMONITOR 0X20
 +extern int ie_match_stat(struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
 +extern int ie_modified(struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
  
  #define HASH_WRITE_OBJECT 1
  #define HASH_FORMAT_CHECK 2
 +#define HASH_RENORMALIZE  4
  extern int index_fd(struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
  extern int index_path(struct object_id *oid, const char *path, struct stat *st, unsigned flags);
  
@@@ -762,7 -748,6 +765,7 @@@ extern int hold_locked_index(struct loc
  extern void set_alternate_index_output(const char *);
  
  extern int verify_index_checksum;
 +extern int verify_ce_order;
  
  /* Environment bits from configuration mechanism */
  extern int trust_executable_bit;
@@@ -816,7 -801,6 +819,7 @@@ extern int core_apply_sparse_checkout
  extern int precomposed_unicode;
  extern int protect_hfs;
  extern int protect_ntfs;
 +extern const char *core_fsmonitor;
  
  /*
   * Include broken refs in all ref iterations, which will
@@@ -907,6 -891,7 +910,7 @@@ struct repository_format 
        int version;
        int precious_objects;
        int is_bare;
+       int hash_algo;
        char *work_tree;
        struct string_list unknown_extensions;
  };
@@@ -1039,22 -1024,22 +1043,22 @@@ extern const struct object_id empty_blo
  
  static inline int is_empty_blob_sha1(const unsigned char *sha1)
  {
-       return !hashcmp(sha1, EMPTY_BLOB_SHA1_BIN);
+       return !hashcmp(sha1, the_hash_algo->empty_blob->hash);
  }
  
  static inline int is_empty_blob_oid(const struct object_id *oid)
  {
-       return !hashcmp(oid->hash, EMPTY_BLOB_SHA1_BIN);
+       return !oidcmp(oid, the_hash_algo->empty_blob);
  }
  
  static inline int is_empty_tree_sha1(const unsigned char *sha1)
  {
-       return !hashcmp(sha1, EMPTY_TREE_SHA1_BIN);
+       return !hashcmp(sha1, the_hash_algo->empty_tree->hash);
  }
  
  static inline int is_empty_tree_oid(const struct object_id *oid)
  {
-       return !hashcmp(oid->hash, EMPTY_TREE_SHA1_BIN);
+       return !oidcmp(oid, the_hash_algo->empty_tree);
  }
  
  /* set default permissions by passing mode arguments to open(2) */
diff --combined diff-lib.c
index 5173023cd3c3e4390e9ddc08e898d813f6a32093,893fee432cccef4ec82cb9ea3303709a48a8bb76..8104603a3b36f2fd73761db34efde44d5938f68f
@@@ -12,7 -12,6 +12,7 @@@
  #include "refs.h"
  #include "submodule.h"
  #include "dir.h"
 +#include "fsmonitor.h"
  
  /*
   * diff-files
@@@ -218,7 -217,7 +218,7 @@@ int run_diff_files(struct rev_info *rev
                        } else if (revs->diffopt.ita_invisible_in_index &&
                                   ce_intent_to_add(ce)) {
                                diff_addremove(&revs->diffopt, '+', ce->ce_mode,
-                                              &empty_tree_oid, 0,
+                                              the_hash_algo->empty_tree, 0,
                                               ce->name, 0);
                                continue;
                        }
  
                if (!changed && !dirty_submodule) {
                        ce_mark_uptodate(ce);
 +                      mark_fsmonitor_valid(ce);
                        if (!revs->diffopt.flags.find_copies_harder)
                                continue;
                }
diff --combined merge-recursive.c
index d00b274381e7fff7efd2b38f4328764105d9d7af,f89cc751e1fefd6e363fc4a52cd7d0957d985d47..a4c280dfc78e943ec541f83ccb0b39921ccdf2b2
@@@ -1901,9 -1901,8 +1901,9 @@@ static int process_entry(struct merge_o
                        oid = b_oid;
                        conf = _("directory/file");
                }
 -              if (dir_in_way(path, !o->call_depth,
 -                             S_ISGITLINK(a_mode))) {
 +              if (dir_in_way(path,
 +                             !o->call_depth && !S_ISGITLINK(a_mode),
 +                             0)) {
                        char *new_path = unique_path(o, path, add_branch);
                        clean_merge = 0;
                        output(o, 1, _("CONFLICT (%s): There is a directory with name %s in %s. "
@@@ -2082,7 -2081,7 +2082,7 @@@ int merge_recursive(struct merge_option
                /* if there is no common ancestor, use an empty tree */
                struct tree *tree;
  
-               tree = lookup_tree(&empty_tree_oid);
+               tree = lookup_tree(the_hash_algo->empty_tree);
                merged_common_ancestors = make_virtual_commit(tree, "ancestor");
        }
  
@@@ -2202,7 -2201,6 +2202,7 @@@ static void merge_recursive_config(stru
  
  void init_merge_options(struct merge_options *o)
  {
 +      const char *merge_verbosity;
        memset(o, 0, sizeof(struct merge_options));
        o->verbosity = 2;
        o->buffer_output = 1;
        o->renormalize = 0;
        o->detect_rename = 1;
        merge_recursive_config(o);
 -      if (getenv("GIT_MERGE_VERBOSITY"))
 -              o->verbosity =
 -                      strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10);
 +      merge_verbosity = getenv("GIT_MERGE_VERBOSITY");
 +      if (merge_verbosity)
 +              o->verbosity = strtol(merge_verbosity, NULL, 10);
        if (o->verbosity >= 5)
                o->buffer_output = 0;
        strbuf_init(&o->obuf, 0);
@@@ -2253,8 -2251,6 +2253,8 @@@ int parse_merge_opt(struct merge_option
                DIFF_XDL_SET(o, IGNORE_WHITESPACE);
        else if (!strcmp(s, "ignore-space-at-eol"))
                DIFF_XDL_SET(o, IGNORE_WHITESPACE_AT_EOL);
 +      else if (!strcmp(s, "ignore-cr-at-eol"))
 +              DIFF_XDL_SET(o, IGNORE_CR_AT_EOL);
        else if (!strcmp(s, "renormalize"))
                o->renormalize = 1;
        else if (!strcmp(s, "no-renormalize"))
diff --combined sequencer.c
index fa94ed652d2ce87fddf824aa516456b5f42735e7,2c191aeb36bb8222cd39b4749dcc5d062176a99b..e90bc316bb7a232a40c332c6d1add255d3893869
@@@ -347,7 -347,7 +347,7 @@@ static int read_oneliner(struct strbuf 
  
  static struct tree *empty_tree(void)
  {
-       return lookup_tree(&empty_tree_oid);
+       return lookup_tree(the_hash_algo->empty_tree);
  }
  
  static int error_dirty_index(struct replay_opts *opts)
@@@ -438,8 -438,7 +438,8 @@@ static int do_recursive_merge(struct co
        char **xopt;
        static struct lock_file index_lock;
  
 -      hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
 +      if (hold_locked_index(&index_lock, LOCK_REPORT_ON_ERROR) < 0)
 +              return -1;
  
        read_cache();
  
@@@ -706,7 -705,7 +706,7 @@@ static int is_original_commit_empty(str
                                oid_to_hex(&parent->object.oid));
                ptree_oid = &parent->tree->object.oid;
        } else {
-               ptree_oid = &empty_tree_oid; /* commit is root */
+               ptree_oid = the_hash_algo->empty_tree; /* commit is root */
        }
  
        return !oidcmp(ptree_oid, &commit->tree->object.oid);
@@@ -959,7 -958,7 +959,7 @@@ static int do_pick_commit(enum todo_com
        } else {
                unborn = get_oid("HEAD", &head);
                if (unborn)
-                       oidcpy(&head, &empty_tree_oid);
+                       oidcpy(&head, the_hash_algo->empty_tree);
                if (index_differs_from(unborn ? EMPTY_TREE_SHA1_HEX : "HEAD",
                                       NULL, 0))
                        return error_dirty_index(opts);
         */
        if (command == TODO_PICK && !opts->no_commit && (res == 0 || res == 1) &&
            update_ref(NULL, "CHERRY_PICK_HEAD", &commit->object.oid, NULL,
 -                     REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))
 +                     REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
                res = -1;
        if (command == TODO_REVERT && ((opts->no_commit && res == 0) || res == 1) &&
            update_ref(NULL, "REVERT_HEAD", &commit->object.oid, NULL,
 -                     REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))
 +                     REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR))
                res = -1;
  
        if (res) {
@@@ -2131,7 -2130,7 +2131,7 @@@ cleanup_head_ref
                        msg = reflog_message(opts, "finish", "%s onto %s",
                                head_ref.buf, buf.buf);
                        if (update_ref(msg, head_ref.buf, &head, &orig,
 -                                     REF_NODEREF, UPDATE_REFS_MSG_ON_ERR)) {
 +                                     REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
                                res = error(_("could not update %s"),
                                        head_ref.buf);
                                goto cleanup_head_ref;
@@@ -2671,19 -2670,6 +2671,19 @@@ leave_check
        return res;
  }
  
 +static int rewrite_file(const char *path, const char *buf, size_t len)
 +{
 +      int rc = 0;
 +      int fd = open(path, O_WRONLY | O_TRUNC);
 +      if (fd < 0)
 +              return error_errno(_("could not open '%s' for writing"), path);
 +      if (write_in_full(fd, buf, len) < 0)
 +              rc = error_errno(_("could not write to '%s'"), path);
 +      if (close(fd) && !rc)
 +              rc = error_errno(_("could not close '%s'"), path);
 +      return rc;
 +}
 +
  /* skip picking commits whose parents are unchanged */
  int skip_unnecessary_picks(void)
  {
                }
                close(fd);
  
 -              fd = open(rebase_path_todo(), O_WRONLY, 0666);
 -              if (fd < 0) {
 -                      error_errno(_("could not open '%s' for writing"),
 -                                  rebase_path_todo());
 +              if (rewrite_file(rebase_path_todo(), todo_list.buf.buf + offset,
 +                               todo_list.buf.len - offset) < 0) {
                        todo_list_release(&todo_list);
                        return -1;
                }
 -              if (write_in_full(fd, todo_list.buf.buf + offset,
 -                              todo_list.buf.len - offset) < 0) {
 -                      error_errno(_("could not write to '%s'"),
 -                                  rebase_path_todo());
 -                      close(fd);
 -                      todo_list_release(&todo_list);
 -                      return -1;
 -              }
 -              if (ftruncate(fd, todo_list.buf.len - offset) < 0) {
 -                      error_errno(_("could not truncate '%s'"),
 -                                  rebase_path_todo());
 -                      todo_list_release(&todo_list);
 -                      close(fd);
 -                      return -1;
 -              }
 -              close(fd);
  
                todo_list.current = i;
                if (is_fixup(peek_command(&todo_list, 0)))
@@@ -2945,7 -2949,15 +2945,7 @@@ int rearrange_squash(void
                        }
                }
  
 -              fd = open(todo_file, O_WRONLY);
 -              if (fd < 0)
 -                      res = error_errno(_("could not open '%s'"), todo_file);
 -              else if (write(fd, buf.buf, buf.len) < 0)
 -                      res = error_errno(_("could not write to '%s'"), todo_file);
 -              else if (ftruncate(fd, buf.len) < 0)
 -                      res = error_errno(_("could not truncate '%s'"),
 -                                         todo_file);
 -              close(fd);
 +              res = rewrite_file(todo_file, buf.buf, buf.len);
                strbuf_release(&buf);
        }
  
diff --combined sha1_file.c
index afe4b90f6ee0e6c00af3e57c7c92ac5245bd1792,a04389be71dc27f18106226d3c24624e4b62434b..b44f5247caa9389f8d1c7643b7d9d99418d21f72
@@@ -39,6 -39,64 +39,64 @@@ const struct object_id empty_blob_oid 
        EMPTY_BLOB_SHA1_BIN_LITERAL
  };
  
+ static void git_hash_sha1_init(void *ctx)
+ {
+       git_SHA1_Init((git_SHA_CTX *)ctx);
+ }
+ static void git_hash_sha1_update(void *ctx, const void *data, size_t len)
+ {
+       git_SHA1_Update((git_SHA_CTX *)ctx, data, len);
+ }
+ static void git_hash_sha1_final(unsigned char *hash, void *ctx)
+ {
+       git_SHA1_Final(hash, (git_SHA_CTX *)ctx);
+ }
+ static void git_hash_unknown_init(void *ctx)
+ {
+       die("trying to init unknown hash");
+ }
+ static void git_hash_unknown_update(void *ctx, const void *data, size_t len)
+ {
+       die("trying to update unknown hash");
+ }
+ static void git_hash_unknown_final(unsigned char *hash, void *ctx)
+ {
+       die("trying to finalize unknown hash");
+ }
+ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
+       {
+               NULL,
+               0x00000000,
+               0,
+               0,
+               0,
+               git_hash_unknown_init,
+               git_hash_unknown_update,
+               git_hash_unknown_final,
+               NULL,
+               NULL,
+       },
+       {
+               "sha-1",
+               /* "sha1", big-endian */
+               0x73686131,
+               sizeof(git_SHA_CTX),
+               GIT_SHA1_RAWSZ,
+               GIT_SHA1_HEXSZ,
+               git_hash_sha1_init,
+               git_hash_sha1_update,
+               git_hash_sha1_final,
+               &empty_tree_oid,
+               &empty_blob_oid,
+       },
+ };
  /*
   * This is meant to hold a *small* number of objects that you would
   * want read_sha1_file() to be able to return, but yet you do not want
@@@ -74,18 -132,6 +132,18 @@@ static struct cached_object *find_cache
        return NULL;
  }
  
 +
 +static enum safe_crlf get_safe_crlf(unsigned flags)
 +{
 +      if (flags & HASH_RENORMALIZE)
 +              return SAFE_CRLF_RENORMALIZE;
 +      else if (flags & HASH_WRITE_OBJECT)
 +              return safe_crlf;
 +      else
 +              return SAFE_CRLF_FALSE;
 +}
 +
 +
  int mkdir_in_gitdir(const char *path)
  {
        if (mkdir(path, 0777)) {
@@@ -416,9 -462,6 +474,9 @@@ static void link_alt_odb_entries(const 
        struct strbuf objdirbuf = STRBUF_INIT;
        struct strbuf entry = STRBUF_INIT;
  
 +      if (!alt || !*alt)
 +              return;
 +
        if (depth > 5) {
                error("%s: ignoring alternate object stores, nesting too deep.",
                                relative_base);
@@@ -619,6 -662,7 +677,6 @@@ void prepare_alt_odb(void
                return;
  
        alt = getenv(ALTERNATE_DB_ENVIRONMENT);
 -      if (!alt) alt = "";
  
        alt_odb_tail = &alt_odb_list;
        link_alt_odb_entries(alt, PATH_SEP, NULL, 0);
@@@ -1164,9 -1208,6 +1222,9 @@@ int sha1_object_info_extended(const uns
                                    lookup_replace_object(sha1) :
                                    sha1;
  
 +      if (is_null_sha1(real))
 +              return -1;
 +
        if (!oi)
                oi = &blank_oi;
  
@@@ -1694,7 -1735,7 +1752,7 @@@ static int index_mem(struct object_id *
        if ((type == OBJ_BLOB) && path) {
                struct strbuf nbuf = STRBUF_INIT;
                if (convert_to_git(&the_index, path, buf, size, &nbuf,
 -                                 write_object ? safe_crlf : SAFE_CRLF_FALSE)) {
 +                                 get_safe_crlf(flags))) {
                        buf = strbuf_detach(&nbuf, &size);
                        re_allocated = 1;
                }
@@@ -1728,7 -1769,7 +1786,7 @@@ static int index_stream_convert_blob(st
        assert(would_convert_to_git_filter_fd(path));
  
        convert_to_git_filter_fd(&the_index, path, fd, &sbuf,
 -                               write_object ? safe_crlf : SAFE_CRLF_FALSE);
 +                               get_safe_crlf(flags));
  
        if (write_object)
                ret = write_sha1_file(sbuf.buf, sbuf.len, typename(OBJ_BLOB),
diff --combined submodule.c
index 95e6aff2bb74e1374d22997d1918ed190c6edafc,ec269a6fc0dbe2621ddf56037a50fee323b0da14..fa25888783aa9ba7ce5b290ba64ec3c1b7a87cec
@@@ -62,7 -62,7 +62,7 @@@ int is_staging_gitmodules_ok(const stru
        if ((pos >= 0) && (pos < istate->cache_nr)) {
                struct stat st;
                if (lstat(GITMODULES_FILE, &st) == 0 &&
 -                  ce_match_stat(istate->cache[pos], &st, 0) & DATA_CHANGED)
 +                  ce_match_stat(istate->cache[pos], &st, CE_MATCH_IGNORE_FSMONITOR) & DATA_CHANGED)
                        return 0;
        }
  
@@@ -587,7 -587,7 +587,7 @@@ void show_submodule_inline_diff(struct 
                struct object_id *one, struct object_id *two,
                unsigned dirty_submodule)
  {
-       const struct object_id *old = &empty_tree_oid, *new = &empty_tree_oid;
+       const struct object_id *old = the_hash_algo->empty_tree, *new = the_hash_algo->empty_tree;
        struct commit *left = NULL, *right = NULL;
        struct commit_list *merge_bases = NULL;
        struct child_process cp = CHILD_PROCESS_INIT;
@@@ -1670,8 -1670,7 +1670,8 @@@ int submodule_move_head(const char *pat
                        cp.dir = path;
  
                        prepare_submodule_repo_env(&cp.env_array);
 -                      argv_array_pushl(&cp.args, "update-ref", "HEAD", new, NULL);
 +                      argv_array_pushl(&cp.args, "update-ref", "HEAD",
 +                                       "--no-deref", new, NULL);
  
                        if (run_command(&cp)) {
                                ret = -1;