Merge branch 'bw/config-h'
authorJunio C Hamano <gitster@pobox.com>
Sat, 24 Jun 2017 21:28:40 +0000 (14:28 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 24 Jun 2017 21:28:41 +0000 (14:28 -0700)
Fix configuration codepath to pay proper attention to commondir
that is used in multi-worktree situation, and isolate config API
into its own header file.

* bw/config-h:
config: don't implicitly use gitdir or commondir
config: respect commondir
setup: teach discover_git_directory to respect the commondir
config: don't include config.h by default
config: remove git_config_iter
config: create config.h

98 files changed:
1  2 
apply.c
archive-tar.c
archive-zip.c
archive.c
attr.c
bisect.c
branch.c
builtin/add.c
builtin/am.c
builtin/blame.c
builtin/branch.c
builtin/cat-file.c
builtin/check-ignore.c
builtin/checkout.c
builtin/clean.c
builtin/clone.c
builtin/commit-tree.c
builtin/commit.c
builtin/config.c
builtin/describe.c
builtin/diff-files.c
builtin/diff-index.c
builtin/diff-tree.c
builtin/diff.c
builtin/difftool.c
builtin/fast-export.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/fsck.c
builtin/gc.c
builtin/grep.c
builtin/index-pack.c
builtin/log.c
builtin/ls-files.c
builtin/ls-tree.c
builtin/merge-base.c
builtin/merge.c
builtin/name-rev.c
builtin/notes.c
builtin/pack-objects.c
builtin/pull.c
builtin/push.c
builtin/read-tree.c
builtin/receive-pack.c
builtin/reflog.c
builtin/remote.c
builtin/repack.c
builtin/replace.c
builtin/reset.c
builtin/rev-list.c
builtin/rev-parse.c
builtin/rm.c
builtin/show-branch.c
builtin/submodule--helper.c
builtin/tag.c
builtin/unpack-objects.c
builtin/update-index.c
builtin/verify-commit.c
builtin/worktree.c
cache.h
config.c
connect.c
convert.c
credential-cache--daemon.c
diff.c
dir.c
environment.c
fast-import.c
fetch-pack.c
git.c
grep.c
help.c
http-backend.c
ident.c
ll-merge.c
log-tree.c
mailinfo.c
merge-recursive.c
notes-utils.c
notes.c
parse-options.c
pathspec.c
pretty.c
read-cache.c
refs.c
refs/files-backend.c
remote.c
rerere.c
sequencer.c
setup.c
sha1_file.c
sha1_name.c
submodule.c
transport.c
unpack-trees.c
upload-pack.c
wrapper.c
xdiff-interface.c
diff --combined apply.c
index f24014a705edf5fc1f49e22502f563a469b850ed,5b442860df2f4fdb0137ac8036269308bc173624..f7251ccc8b42c789c1bed785d93cdeba4406480f
+++ b/apply.c
@@@ -8,6 -8,7 +8,7 @@@
   */
  
  #include "cache.h"
+ #include "config.h"
  #include "blob.h"
  #include "delta.h"
  #include "diff.h"
@@@ -762,6 -763,17 +763,6 @@@ static char *find_name_traditional(stru
        return find_name_common(state, line, def, p_value, line + len, 0);
  }
  
 -static int count_slashes(const char *cp)
 -{
 -      int cnt = 0;
 -      char ch;
 -
 -      while ((ch = *cp++))
 -              if (ch == '/')
 -                      cnt++;
 -      return cnt;
 -}
 -
  /*
   * Given the string after "--- " or "+++ ", guess the appropriate
   * p_value for the given patch.
@@@ -2256,7 -2268,7 +2257,7 @@@ static int read_old_data(struct stat *s
        case S_IFREG:
                if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
                        return error(_("unable to open or read %s"), path);
 -              convert_to_git(path, buf->buf, buf->len, buf, 0);
 +              convert_to_git(&the_index, path, buf->buf, buf->len, buf, 0);
                return 0;
        default:
                return -1;
@@@ -3730,7 -3742,7 +3731,7 @@@ static int check_to_create(struct apply
                        return 0;
  
                return EXISTS_IN_WORKTREE;
 -      } else if ((errno != ENOENT) && (errno != ENOTDIR)) {
 +      } else if (!is_missing_file_error(errno)) {
                return error_errno("%s", new_name);
        }
        return 0;
@@@ -4080,181 -4092,181 +4081,181 @@@ static int build_fake_ancestor(struct a
        res = write_locked_index(&result, &lock, COMMIT_LOCK);
        discard_index(&result);
  
 -       if (res)
 -               return error(_("could not write temporary index to %s"),
 -                            state->fake_ancestor);
 +      if (res)
 +              return error(_("could not write temporary index to %s"),
 +                           state->fake_ancestor);
  
 -       return 0;
 - }
 +      return 0;
 +}
 +
 +static void stat_patch_list(struct apply_state *state, struct patch *patch)
 +{
 +      int files, adds, dels;
  
 - static void stat_patch_list(struct apply_state *state, struct patch *patch)
 - {
 -       int files, adds, dels;
 +      for (files = adds = dels = 0 ; patch ; patch = patch->next) {
 +              files++;
 +              adds += patch->lines_added;
 +              dels += patch->lines_deleted;
 +              show_stats(state, patch);
 +      }
  
 -       for (files = adds = dels = 0 ; patch ; patch = patch->next) {
 -               files++;
 -               adds += patch->lines_added;
 -               dels += patch->lines_deleted;
 -               show_stats(state, patch);
 -       }
 +      print_stat_summary(stdout, files, adds, dels);
 +}
  
 -       print_stat_summary(stdout, files, adds, dels);
 - }
 +static void numstat_patch_list(struct apply_state *state,
 +                             struct patch *patch)
 +{
 +      for ( ; patch; patch = patch->next) {
 +              const char *name;
 +              name = patch->new_name ? patch->new_name : patch->old_name;
 +              if (patch->is_binary)
 +                      printf("-\t-\t");
 +              else
 +                      printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
 +              write_name_quoted(name, stdout, state->line_termination);
 +      }
 +}
  
 - static void numstat_patch_list(struct apply_state *state,
 -                              struct patch *patch)
 - {
 -       for ( ; patch; patch = patch->next) {
 -               const char *name;
 -               name = patch->new_name ? patch->new_name : patch->old_name;
 -               if (patch->is_binary)
 -                       printf("-\t-\t");
 -               else
 -                       printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
 -               write_name_quoted(name, stdout, state->line_termination);
 -       }
 - }
 -
 - static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name)
 - {
 -       if (mode)
 -               printf(" %s mode %06o %s\n", newdelete, mode, name);
 -       else
 -               printf(" %s %s\n", newdelete, name);
 - }
 -
 - static void show_mode_change(struct patch *p, int show_name)
 - {
 -       if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) {
 -               if (show_name)
 -                       printf(" mode change %06o => %06o %s\n",
 -                              p->old_mode, p->new_mode, p->new_name);
 -               else
 -                       printf(" mode change %06o => %06o\n",
 -                              p->old_mode, p->new_mode);
 -       }
 - }
 -
 - static void show_rename_copy(struct patch *p)
 - {
 -       const char *renamecopy = p->is_rename ? "rename" : "copy";
 -       const char *old, *new;
 -
 -       /* Find common prefix */
 -       old = p->old_name;
 -       new = p->new_name;
 -       while (1) {
 -               const char *slash_old, *slash_new;
 -               slash_old = strchr(old, '/');
 -               slash_new = strchr(new, '/');
 -               if (!slash_old ||
 -                   !slash_new ||
 -                   slash_old - old != slash_new - new ||
 -                   memcmp(old, new, slash_new - new))
 -                       break;
 -               old = slash_old + 1;
 -               new = slash_new + 1;
 -       }
 -       /* p->old_name thru old is the common prefix, and old and new
 -        * through the end of names are renames
 -        */
 -       if (old != p->old_name)
 -               printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
 -                      (int)(old - p->old_name), p->old_name,
 -                      old, new, p->score);
 -       else
 -               printf(" %s %s => %s (%d%%)\n", renamecopy,
 -                      p->old_name, p->new_name, p->score);
 -       show_mode_change(p, 0);
 - }
 -
 - static void summary_patch_list(struct patch *patch)
 - {
 -       struct patch *p;
 -
 -       for (p = patch; p; p = p->next) {
 -               if (p->is_new)
 -                       show_file_mode_name("create", p->new_mode, p->new_name);
 -               else if (p->is_delete)
 -                       show_file_mode_name("delete", p->old_mode, p->old_name);
 -               else {
 -                       if (p->is_rename || p->is_copy)
 -                               show_rename_copy(p);
 -                       else {
 -                               if (p->score) {
 -                                       printf(" rewrite %s (%d%%)\n",
 -                                              p->new_name, p->score);
 -                                       show_mode_change(p, 0);
 -                               }
 -                               else
 -                                       show_mode_change(p, 1);
 -                       }
 -               }
 -       }
 - }
 -
 - static void patch_stats(struct apply_state *state, struct patch *patch)
 - {
 -       int lines = patch->lines_added + patch->lines_deleted;
 -
 -       if (lines > state->max_change)
 -               state->max_change = lines;
 -       if (patch->old_name) {
 -               int len = quote_c_style(patch->old_name, NULL, NULL, 0);
 -               if (!len)
 -                       len = strlen(patch->old_name);
 -               if (len > state->max_len)
 -                       state->max_len = len;
 -       }
 -       if (patch->new_name) {
 -               int len = quote_c_style(patch->new_name, NULL, NULL, 0);
 -               if (!len)
 -                       len = strlen(patch->new_name);
 -               if (len > state->max_len)
 -                       state->max_len = len;
 -       }
 - }
 -
 - static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
 - {
 -       if (state->update_index) {
 -               if (remove_file_from_cache(patch->old_name) < 0)
 -                       return error(_("unable to remove %s from index"), patch->old_name);
 -       }
 -       if (!state->cached) {
 -               if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
 -                       remove_path(patch->old_name);
 -               }
 -       }
 -       return 0;
 - }
 -
 - static int add_index_file(struct apply_state *state,
 -                         const char *path,
 -                         unsigned mode,
 -                         void *buf,
 -                         unsigned long size)
 - {
 -       struct stat st;
 -       struct cache_entry *ce;
 -       int namelen = strlen(path);
 -       unsigned ce_size = cache_entry_size(namelen);
 -
 -       if (!state->update_index)
 -               return 0;
 -
 -       ce = xcalloc(1, ce_size);
 -       memcpy(ce->name, path, namelen);
 -       ce->ce_mode = create_ce_mode(mode);
 -       ce->ce_flags = create_ce_flags(0);
 -       ce->ce_namelen = namelen;
 -       if (S_ISGITLINK(mode)) {
 -               const char *s;
 -
 -               if (!skip_prefix(buf, "Subproject commit ", &s) ||
 -                   get_oid_hex(s, &ce->oid)) {
 +static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name)
 +{
 +      if (mode)
 +              printf(" %s mode %06o %s\n", newdelete, mode, name);
 +      else
 +              printf(" %s %s\n", newdelete, name);
 +}
 +
 +static void show_mode_change(struct patch *p, int show_name)
 +{
 +      if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) {
 +              if (show_name)
 +                      printf(" mode change %06o => %06o %s\n",
 +                             p->old_mode, p->new_mode, p->new_name);
 +              else
 +                      printf(" mode change %06o => %06o\n",
 +                             p->old_mode, p->new_mode);
 +      }
 +}
 +
 +static void show_rename_copy(struct patch *p)
 +{
 +      const char *renamecopy = p->is_rename ? "rename" : "copy";
 +      const char *old, *new;
 +
 +      /* Find common prefix */
 +      old = p->old_name;
 +      new = p->new_name;
 +      while (1) {
 +              const char *slash_old, *slash_new;
 +              slash_old = strchr(old, '/');
 +              slash_new = strchr(new, '/');
 +              if (!slash_old ||
 +                  !slash_new ||
 +                  slash_old - old != slash_new - new ||
 +                  memcmp(old, new, slash_new - new))
 +                      break;
 +              old = slash_old + 1;
 +              new = slash_new + 1;
 +      }
 +      /* p->old_name thru old is the common prefix, and old and new
 +       * through the end of names are renames
 +       */
 +      if (old != p->old_name)
 +              printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
 +                     (int)(old - p->old_name), p->old_name,
 +                     old, new, p->score);
 +      else
 +              printf(" %s %s => %s (%d%%)\n", renamecopy,
 +                     p->old_name, p->new_name, p->score);
 +      show_mode_change(p, 0);
 +}
 +
 +static void summary_patch_list(struct patch *patch)
 +{
 +      struct patch *p;
 +
 +      for (p = patch; p; p = p->next) {
 +              if (p->is_new)
 +                      show_file_mode_name("create", p->new_mode, p->new_name);
 +              else if (p->is_delete)
 +                      show_file_mode_name("delete", p->old_mode, p->old_name);
 +              else {
 +                      if (p->is_rename || p->is_copy)
 +                              show_rename_copy(p);
 +                      else {
 +                              if (p->score) {
 +                                      printf(" rewrite %s (%d%%)\n",
 +                                             p->new_name, p->score);
 +                                      show_mode_change(p, 0);
 +                              }
 +                              else
 +                                      show_mode_change(p, 1);
 +                      }
 +              }
 +      }
 +}
 +
 +static void patch_stats(struct apply_state *state, struct patch *patch)
 +{
 +      int lines = patch->lines_added + patch->lines_deleted;
 +
 +      if (lines > state->max_change)
 +              state->max_change = lines;
 +      if (patch->old_name) {
 +              int len = quote_c_style(patch->old_name, NULL, NULL, 0);
 +              if (!len)
 +                      len = strlen(patch->old_name);
 +              if (len > state->max_len)
 +                      state->max_len = len;
 +      }
 +      if (patch->new_name) {
 +              int len = quote_c_style(patch->new_name, NULL, NULL, 0);
 +              if (!len)
 +                      len = strlen(patch->new_name);
 +              if (len > state->max_len)
 +                      state->max_len = len;
 +      }
 +}
 +
 +static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
 +{
 +      if (state->update_index) {
 +              if (remove_file_from_cache(patch->old_name) < 0)
 +                      return error(_("unable to remove %s from index"), patch->old_name);
 +      }
 +      if (!state->cached) {
 +              if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
 +                      remove_path(patch->old_name);
 +              }
 +      }
 +      return 0;
 +}
 +
 +static int add_index_file(struct apply_state *state,
 +                        const char *path,
 +                        unsigned mode,
 +                        void *buf,
 +                        unsigned long size)
 +{
 +      struct stat st;
 +      struct cache_entry *ce;
 +      int namelen = strlen(path);
 +      unsigned ce_size = cache_entry_size(namelen);
 +
 +      if (!state->update_index)
 +              return 0;
 +
 +      ce = xcalloc(1, ce_size);
 +      memcpy(ce->name, path, namelen);
 +      ce->ce_mode = create_ce_mode(mode);
 +      ce->ce_flags = create_ce_flags(0);
 +      ce->ce_namelen = namelen;
 +      if (S_ISGITLINK(mode)) {
 +              const char *s;
 +
 +              if (!skip_prefix(buf, "Subproject commit ", &s) ||
 +                  get_oid_hex(s, &ce->oid)) {
                        free(ce);
 -                      return error(_("corrupt patch for submodule %s"), path);
 +                     return error(_("corrupt patch for submodule %s"), path);
                }
        } else {
                if (!state->cached) {
diff --combined archive-tar.c
index 073e60ebd3c366b42298ae443eee230407d4e3a7,d65ac016df09ccdb7bc7952291de12ec5912bc8d..c6ed96ee74ec10f5c9ffb6f520193326d4704b6b
@@@ -2,6 -2,7 +2,7 @@@
   * Copyright (c) 2005, 2006 Rene Scharfe
   */
  #include "cache.h"
+ #include "config.h"
  #include "tar.h"
  #include "archive.h"
  #include "streaming.h"
@@@ -27,13 -28,10 +28,13 @@@ static int write_tar_filter_archive(con
   */
  #if ULONG_MAX == 0xFFFFFFFF
  #define USTAR_MAX_SIZE ULONG_MAX
 -#define USTAR_MAX_MTIME ULONG_MAX
  #else
  #define USTAR_MAX_SIZE 077777777777UL
 -#define USTAR_MAX_MTIME 077777777777UL
 +#endif
 +#if TIME_MAX == 0xFFFFFFFF
 +#define USTAR_MAX_MTIME TIME_MAX
 +#else
 +#define USTAR_MAX_MTIME 077777777777ULL
  #endif
  
  /* writes out the whole block, but only if it is full */
diff --combined archive-zip.c
index 27563e9e2602108997033e6fa79c660bc08aa863,04fcd86872496837ddcc9bf354ce5ff5e878236d..e8913e5a26c6e97216c4b79ad96b5e3ddf906c45
@@@ -2,6 -2,7 +2,7 @@@
   * Copyright (c) 2006 Rene Scharfe
   */
  #include "cache.h"
+ #include "config.h"
  #include "archive.h"
  #include "streaming.h"
  #include "utf8.h"
  static int zip_date;
  static int zip_time;
  
 -static unsigned char *zip_dir;
 -static unsigned int zip_dir_size;
 +/* We only care about the "buf" part here. */
 +static struct strbuf zip_dir;
  
 -static unsigned int zip_offset;
 -static unsigned int zip_dir_offset;
 +static uintmax_t zip_offset;
  static uint64_t zip_dir_entries;
  
  static unsigned int max_creator_version;
  
 -#define ZIP_DIRECTORY_MIN_SIZE        (1024 * 1024)
  #define ZIP_STREAM    (1 <<  3)
  #define ZIP_UTF8      (1 << 11)
  
@@@ -45,11 -48,24 +46,11 @@@ struct zip_data_desc 
        unsigned char _end[1];
  };
  
 -struct zip_dir_header {
 +struct zip64_data_desc {
        unsigned char magic[4];
 -      unsigned char creator_version[2];
 -      unsigned char version[2];
 -      unsigned char flags[2];
 -      unsigned char compression_method[2];
 -      unsigned char mtime[2];
 -      unsigned char mdate[2];
        unsigned char crc32[4];
 -      unsigned char compressed_size[4];
 -      unsigned char size[4];
 -      unsigned char filename_length[2];
 -      unsigned char extra_length[2];
 -      unsigned char comment_length[2];
 -      unsigned char disk[2];
 -      unsigned char attr1[2];
 -      unsigned char attr2[4];
 -      unsigned char offset[4];
 +      unsigned char compressed_size[8];
 +      unsigned char size[8];
        unsigned char _end[1];
  };
  
@@@ -73,14 -89,6 +74,14 @@@ struct zip_extra_mtime 
        unsigned char _end[1];
  };
  
 +struct zip64_extra {
 +      unsigned char magic[2];
 +      unsigned char extra_size[2];
 +      unsigned char size[8];
 +      unsigned char compressed_size[8];
 +      unsigned char _end[1];
 +};
 +
  struct zip64_dir_trailer {
        unsigned char magic[4];
        unsigned char record_size[8];
@@@ -110,15 -118,11 +111,15 @@@ struct zip64_dir_trailer_locator 
   */
  #define ZIP_LOCAL_HEADER_SIZE offsetof(struct zip_local_header, _end)
  #define ZIP_DATA_DESC_SIZE    offsetof(struct zip_data_desc, _end)
 +#define ZIP64_DATA_DESC_SIZE  offsetof(struct zip64_data_desc, _end)
  #define ZIP_DIR_HEADER_SIZE   offsetof(struct zip_dir_header, _end)
  #define ZIP_DIR_TRAILER_SIZE  offsetof(struct zip_dir_trailer, _end)
  #define ZIP_EXTRA_MTIME_SIZE  offsetof(struct zip_extra_mtime, _end)
  #define ZIP_EXTRA_MTIME_PAYLOAD_SIZE \
        (ZIP_EXTRA_MTIME_SIZE - offsetof(struct zip_extra_mtime, flags))
 +#define ZIP64_EXTRA_SIZE      offsetof(struct zip64_extra, _end)
 +#define ZIP64_EXTRA_PAYLOAD_SIZE \
 +      (ZIP64_EXTRA_SIZE - offsetof(struct zip64_extra, size))
  #define ZIP64_DIR_TRAILER_SIZE        offsetof(struct zip64_dir_trailer, _end)
  #define ZIP64_DIR_TRAILER_RECORD_SIZE \
        (ZIP64_DIR_TRAILER_SIZE - \
@@@ -165,26 -169,6 +166,26 @@@ static void copy_le16_clamp(unsigned ch
        copy_le16(dest, clamp_max(n, 0xffff, clamped));
  }
  
 +static void copy_le32_clamp(unsigned char *dest, uint64_t n, int *clamped)
 +{
 +      copy_le32(dest, clamp_max(n, 0xffffffff, clamped));
 +}
 +
 +static int strbuf_add_le(struct strbuf *sb, size_t size, uintmax_t n)
 +{
 +      while (size-- > 0) {
 +              strbuf_addch(sb, n & 0xff);
 +              n >>= 8;
 +      }
 +      return -!!n;
 +}
 +
 +static uint32_t clamp32(uintmax_t n)
 +{
 +      const uintmax_t max = 0xffffffff;
 +      return (n < max) ? n : max;
 +}
 +
  static void *zlib_deflate_raw(void *data, unsigned long size,
                              int compression_level,
                              unsigned long *compressed_size)
@@@ -222,23 -206,23 +223,23 @@@ static void write_zip_data_desc(unsigne
                                unsigned long compressed_size,
                                unsigned long crc)
  {
 -      struct zip_data_desc trailer;
 -
 -      copy_le32(trailer.magic, 0x08074b50);
 -      copy_le32(trailer.crc32, crc);
 -      copy_le32(trailer.compressed_size, compressed_size);
 -      copy_le32(trailer.size, size);
 -      write_or_die(1, &trailer, ZIP_DATA_DESC_SIZE);
 -}
 -
 -static void set_zip_dir_data_desc(struct zip_dir_header *header,
 -                                unsigned long size,
 -                                unsigned long compressed_size,
 -                                unsigned long crc)
 -{
 -      copy_le32(header->crc32, crc);
 -      copy_le32(header->compressed_size, compressed_size);
 -      copy_le32(header->size, size);
 +      if (size >= 0xffffffff || compressed_size >= 0xffffffff) {
 +              struct zip64_data_desc trailer;
 +              copy_le32(trailer.magic, 0x08074b50);
 +              copy_le32(trailer.crc32, crc);
 +              copy_le64(trailer.compressed_size, compressed_size);
 +              copy_le64(trailer.size, size);
 +              write_or_die(1, &trailer, ZIP64_DATA_DESC_SIZE);
 +              zip_offset += ZIP64_DATA_DESC_SIZE;
 +      } else {
 +              struct zip_data_desc trailer;
 +              copy_le32(trailer.magic, 0x08074b50);
 +              copy_le32(trailer.crc32, crc);
 +              copy_le32(trailer.compressed_size, compressed_size);
 +              copy_le32(trailer.size, size);
 +              write_or_die(1, &trailer, ZIP_DATA_DESC_SIZE);
 +              zip_offset += ZIP_DATA_DESC_SIZE;
 +      }
  }
  
  static void set_zip_header_data_desc(struct zip_local_header *header,
@@@ -280,14 -264,12 +281,14 @@@ static int write_zip_entry(struct archi
                           unsigned int mode)
  {
        struct zip_local_header header;
 -      struct zip_dir_header dirent;
 +      uintmax_t offset = zip_offset;
        struct zip_extra_mtime extra;
 +      struct zip64_extra extra64;
 +      size_t header_extra_size = ZIP_EXTRA_MTIME_SIZE;
 +      int need_zip64_extra = 0;
        unsigned long attr2;
        unsigned long compressed_size;
        unsigned long crc;
 -      unsigned long direntsize;
        int method;
        unsigned char *out;
        void *deflated = NULL;
        int is_binary = -1;
        const char *path_without_prefix = path + args->baselen;
        unsigned int creator_version = 0;
 +      unsigned int version_needed = 10;
 +      size_t zip_dir_extra_size = ZIP_EXTRA_MTIME_SIZE;
 +      size_t zip64_dir_extra_payload_size = 0;
  
        crc = crc32(0, NULL, 0);
  
        extra.flags[0] = 1;     /* just mtime */
        copy_le32(extra.mtime, args->time);
  
 -      /* make sure we have enough free space in the dictionary */
 -      direntsize = ZIP_DIR_HEADER_SIZE + pathlen + ZIP_EXTRA_MTIME_SIZE;
 -      while (zip_dir_size < zip_dir_offset + direntsize) {
 -              zip_dir_size += ZIP_DIRECTORY_MIN_SIZE;
 -              zip_dir = xrealloc(zip_dir, zip_dir_size);
 -      }
 +      if (size > 0xffffffff || compressed_size > 0xffffffff)
 +              need_zip64_extra = 1;
 +      if (stream && size > 0x7fffffff)
 +              need_zip64_extra = 1;
  
 -      copy_le32(dirent.magic, 0x02014b50);
 -      copy_le16(dirent.creator_version, creator_version);
 -      copy_le16(dirent.version, 10);
 -      copy_le16(dirent.flags, flags);
 -      copy_le16(dirent.compression_method, method);
 -      copy_le16(dirent.mtime, zip_time);
 -      copy_le16(dirent.mdate, zip_date);
 -      set_zip_dir_data_desc(&dirent, size, compressed_size, crc);
 -      copy_le16(dirent.filename_length, pathlen);
 -      copy_le16(dirent.extra_length, ZIP_EXTRA_MTIME_SIZE);
 -      copy_le16(dirent.comment_length, 0);
 -      copy_le16(dirent.disk, 0);
 -      copy_le32(dirent.attr2, attr2);
 -      copy_le32(dirent.offset, zip_offset);
 +      if (need_zip64_extra)
 +              version_needed = 45;
  
        copy_le32(header.magic, 0x04034b50);
 -      copy_le16(header.version, 10);
 +      copy_le16(header.version, version_needed);
        copy_le16(header.flags, flags);
        copy_le16(header.compression_method, method);
        copy_le16(header.mtime, zip_time);
        copy_le16(header.mdate, zip_date);
 -      set_zip_header_data_desc(&header, size, compressed_size, crc);
 +      if (need_zip64_extra) {
 +              set_zip_header_data_desc(&header, 0xffffffff, 0xffffffff, crc);
 +              header_extra_size += ZIP64_EXTRA_SIZE;
 +      } else {
 +              set_zip_header_data_desc(&header, size, compressed_size, crc);
 +      }
        copy_le16(header.filename_length, pathlen);
 -      copy_le16(header.extra_length, ZIP_EXTRA_MTIME_SIZE);
 +      copy_le16(header.extra_length, header_extra_size);
        write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE);
        zip_offset += ZIP_LOCAL_HEADER_SIZE;
        write_or_die(1, path, pathlen);
        zip_offset += pathlen;
        write_or_die(1, &extra, ZIP_EXTRA_MTIME_SIZE);
        zip_offset += ZIP_EXTRA_MTIME_SIZE;
 +      if (need_zip64_extra) {
 +              copy_le16(extra64.magic, 0x0001);
 +              copy_le16(extra64.extra_size, ZIP64_EXTRA_PAYLOAD_SIZE);
 +              copy_le64(extra64.size, size);
 +              copy_le64(extra64.compressed_size, compressed_size);
 +              write_or_die(1, &extra64, ZIP64_EXTRA_SIZE);
 +              zip_offset += ZIP64_EXTRA_SIZE;
 +      }
 +
        if (stream && method == 0) {
                unsigned char buf[STREAM_BUFFER_SIZE];
                ssize_t readlen;
                zip_offset += compressed_size;
  
                write_zip_data_desc(size, compressed_size, crc);
 -              zip_offset += ZIP_DATA_DESC_SIZE;
 -
 -              set_zip_dir_data_desc(&dirent, size, compressed_size, crc);
        } else if (stream && method == 8) {
                unsigned char buf[STREAM_BUFFER_SIZE];
                ssize_t readlen;
                zip_offset += compressed_size;
  
                write_zip_data_desc(size, compressed_size, crc);
 -              zip_offset += ZIP_DATA_DESC_SIZE;
 -
 -              set_zip_dir_data_desc(&dirent, size, compressed_size, crc);
        } else if (compressed_size > 0) {
                write_or_die(1, out, compressed_size);
                zip_offset += compressed_size;
        free(deflated);
        free(buffer);
  
 -      copy_le16(dirent.attr1, !is_binary);
 +      if (compressed_size > 0xffffffff || size > 0xffffffff ||
 +          offset > 0xffffffff) {
 +              if (compressed_size >= 0xffffffff)
 +                      zip64_dir_extra_payload_size += 8;
 +              if (size >= 0xffffffff)
 +                      zip64_dir_extra_payload_size += 8;
 +              if (offset >= 0xffffffff)
 +                      zip64_dir_extra_payload_size += 8;
 +              zip_dir_extra_size += 2 + 2 + zip64_dir_extra_payload_size;
 +      }
  
 -      memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE);
 -      zip_dir_offset += ZIP_DIR_HEADER_SIZE;
 -      memcpy(zip_dir + zip_dir_offset, path, pathlen);
 -      zip_dir_offset += pathlen;
 -      memcpy(zip_dir + zip_dir_offset, &extra, ZIP_EXTRA_MTIME_SIZE);
 -      zip_dir_offset += ZIP_EXTRA_MTIME_SIZE;
 +      strbuf_add_le(&zip_dir, 4, 0x02014b50); /* magic */
 +      strbuf_add_le(&zip_dir, 2, creator_version);
 +      strbuf_add_le(&zip_dir, 2, version_needed);
 +      strbuf_add_le(&zip_dir, 2, flags);
 +      strbuf_add_le(&zip_dir, 2, method);
 +      strbuf_add_le(&zip_dir, 2, zip_time);
 +      strbuf_add_le(&zip_dir, 2, zip_date);
 +      strbuf_add_le(&zip_dir, 4, crc);
 +      strbuf_add_le(&zip_dir, 4, clamp32(compressed_size));
 +      strbuf_add_le(&zip_dir, 4, clamp32(size));
 +      strbuf_add_le(&zip_dir, 2, pathlen);
 +      strbuf_add_le(&zip_dir, 2, zip_dir_extra_size);
 +      strbuf_add_le(&zip_dir, 2, 0);          /* comment length */
 +      strbuf_add_le(&zip_dir, 2, 0);          /* disk */
 +      strbuf_add_le(&zip_dir, 2, !is_binary);
 +      strbuf_add_le(&zip_dir, 4, attr2);
 +      strbuf_add_le(&zip_dir, 4, clamp32(offset));
 +      strbuf_add(&zip_dir, path, pathlen);
 +      strbuf_add(&zip_dir, &extra, ZIP_EXTRA_MTIME_SIZE);
 +      if (zip64_dir_extra_payload_size) {
 +              strbuf_add_le(&zip_dir, 2, 0x0001);     /* magic */
 +              strbuf_add_le(&zip_dir, 2, zip64_dir_extra_payload_size);
 +              if (size >= 0xffffffff)
 +                      strbuf_add_le(&zip_dir, 8, size);
 +              if (compressed_size >= 0xffffffff)
 +                      strbuf_add_le(&zip_dir, 8, compressed_size);
 +              if (offset >= 0xffffffff)
 +                      strbuf_add_le(&zip_dir, 8, offset);
 +      }
        zip_dir_entries++;
  
        return 0;
@@@ -558,12 -511,12 +559,12 @@@ static void write_zip64_trailer(void
        copy_le32(trailer64.directory_start_disk, 0);
        copy_le64(trailer64.entries_on_this_disk, zip_dir_entries);
        copy_le64(trailer64.entries, zip_dir_entries);
 -      copy_le64(trailer64.size, zip_dir_offset);
 +      copy_le64(trailer64.size, zip_dir.len);
        copy_le64(trailer64.offset, zip_offset);
  
        copy_le32(locator64.magic, 0x07064b50);
        copy_le32(locator64.disk, 0);
 -      copy_le64(locator64.offset, zip_offset + zip_dir_offset);
 +      copy_le64(locator64.offset, zip_offset + zip_dir.len);
        copy_le32(locator64.number_of_disks, 1);
  
        write_or_die(1, &trailer64, ZIP64_DIR_TRAILER_SIZE);
@@@ -581,11 -534,11 +582,11 @@@ static void write_zip_trailer(const uns
        copy_le16_clamp(trailer.entries_on_this_disk, zip_dir_entries,
                        &clamped);
        copy_le16_clamp(trailer.entries, zip_dir_entries, &clamped);
 -      copy_le32(trailer.size, zip_dir_offset);
 -      copy_le32(trailer.offset, zip_offset);
 +      copy_le32(trailer.size, zip_dir.len);
 +      copy_le32_clamp(trailer.offset, zip_offset, &clamped);
        copy_le16(trailer.comment_length, sha1 ? GIT_SHA1_HEXSZ : 0);
  
 -      write_or_die(1, zip_dir, zip_dir_offset);
 +      write_or_die(1, zip_dir.buf, zip_dir.len);
        if (clamped)
                write_zip64_trailer();
        write_or_die(1, &trailer, ZIP_DIR_TRAILER_SIZE);
                write_or_die(1, sha1_to_hex(sha1), GIT_SHA1_HEXSZ);
  }
  
 -static void dos_time(time_t *time, int *dos_date, int *dos_time)
 +static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)
  {
 -      struct tm *t = localtime(time);
 +      time_t time;
 +      struct tm *t;
 +
 +      if (date_overflows(*timestamp))
 +              die("timestamp too large for this system: %"PRItime,
 +                  *timestamp);
 +      time = (time_t)*timestamp;
 +      t = localtime(&time);
 +      *timestamp = time;
  
        *dos_date = t->tm_mday + (t->tm_mon + 1) * 32 +
                    (t->tm_year + 1900 - 1980) * 512;
@@@ -624,13 -569,14 +625,13 @@@ static int write_zip_archive(const stru
  
        dos_time(&args->time, &zip_date, &zip_time);
  
 -      zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE);
 -      zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
 +      strbuf_init(&zip_dir, 0);
  
        err = write_archive_entries(args, write_zip_entry);
        if (!err)
                write_zip_trailer(args->commit_sha1);
  
 -      free(zip_dir);
 +      strbuf_release(&zip_dir);
  
        return err;
  }
diff --combined archive.c
index b15a922dab56a525ca3ce7f1143d215fe39f3132,0cba5b4096fe9ec7b1919bf099a667806f16f36c..60b3035a7a6a9e7c2e69b4ba7de00ebdf8bfdbb8
+++ b/archive.c
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "refs.h"
  #include "commit.h"
  #include "tree-walk.h"
@@@ -360,7 -361,7 +361,7 @@@ static void parse_treeish_arg(const cha
        if (get_sha1(name, oid.hash))
                die("Not a valid object name");
  
 -      commit = lookup_commit_reference_gently(oid.hash, 1);
 +      commit = lookup_commit_reference_gently(&oid, 1);
        if (commit) {
                commit_sha1 = commit->object.oid.hash;
                archive_time = commit->date;
                archive_time = time(NULL);
        }
  
 -      tree = parse_tree_indirect(oid.hash);
 +      tree = parse_tree_indirect(&oid);
        if (tree == NULL)
                die("not a tree object");
  
                if (err || !S_ISDIR(mode))
                        die("current working directory is untracked");
  
 -              tree = parse_tree_indirect(tree_oid.hash);
 +              tree = parse_tree_indirect(&tree_oid);
        }
        ar_args->tree = tree;
        ar_args->commit_sha1 = commit_sha1;
diff --combined attr.c
index 821203e2a980c329fc065a0dfabe37ef67a4bbbe,9f8b029363f3dca3ffd968c5649581b3654a622e..6e4b247acd91d30ac5a879183332725d54e756a0
--- 1/attr.c
--- 2/attr.c
+++ b/attr.c
@@@ -9,6 -9,7 +9,7 @@@
  
  #define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
+ #include "config.h"
  #include "exec_cmd.h"
  #include "attr.h"
  #include "dir.h"
@@@ -720,13 -721,16 +721,13 @@@ void git_attr_set_direction(enum git_at
  
  static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
  {
 -      FILE *fp = fopen(path, "r");
 +      FILE *fp = fopen_or_warn(path, "r");
        struct attr_stack *res;
        char buf[2048];
        int lineno = 0;
  
 -      if (!fp) {
 -              if (errno != ENOENT && errno != ENOTDIR)
 -                      warn_on_inaccessible(path);
 +      if (!fp)
                return NULL;
 -      }
        res = xcalloc(1, sizeof(*res));
        while (fgets(buf, sizeof(buf), fp)) {
                char *bufp = buf;
diff --combined bisect.c
index 2a2b9b7267acbb8752015d64ec477f64c6047875,e8f03a08c494f30e4fa6af7138b4f1ba7dadfd77..a9fd9fbc61a661ab19e18713b115f868daab2f98
+++ b/bisect.c
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "commit.h"
  #include "diff.h"
  #include "revision.h"
@@@ -438,7 -439,10 +439,7 @@@ static void read_bisect_paths(struct ar
  {
        struct strbuf str = STRBUF_INIT;
        const char *filename = git_path_bisect_names();
 -      FILE *fp = fopen(filename, "r");
 -
 -      if (!fp)
 -              die_errno(_("Could not open file '%s'"), filename);
 +      FILE *fp = xfopen(filename, "r");
  
        while (strbuf_getline_lf(&str, fp) != EOF) {
                strbuf_trim(&str);
@@@ -543,7 -547,7 +544,7 @@@ static unsigned get_prn(unsigned count
  
  /*
   * Custom integer square root from
 - * http://en.wikipedia.org/wiki/Integer_square_root
 + * https://en.wikipedia.org/wiki/Integer_square_root
   */
  static int sqrti(int val)
  {
@@@ -666,7 -670,7 +667,7 @@@ static int is_expected_rev(const struc
        if (stat(filename, &st) || !S_ISREG(st.st_mode))
                return 0;
  
 -      fp = fopen(filename, "r");
 +      fp = fopen_or_warn(filename, "r");
        if (!fp)
                return 0;
  
@@@ -702,7 -706,7 +703,7 @@@ static int bisect_checkout(const unsign
  
  static struct commit *get_commit_reference(const struct object_id *oid)
  {
 -      struct commit *r = lookup_commit_reference(oid->hash);
 +      struct commit *r = lookup_commit_reference(oid);
        if (!r)
                die(_("Not a valid commit name %s"), oid_to_hex(oid));
        return r;
@@@ -992,10 -996,8 +993,10 @@@ int bisect_next_all(const char *prefix
  
        steps_msg = xstrfmt(Q_("(roughly %d step)", "(roughly %d steps)",
                  steps), steps);
 -      /* TRANSLATORS: the last %s will be replaced with
 -         "(roughly %d steps)" translation */
 +      /*
 +       * TRANSLATORS: the last %s will be replaced with "(roughly %d
 +       * steps)" translation.
 +       */
        printf(Q_("Bisecting: %d revision left to test after this %s\n",
                  "Bisecting: %d revisions left to test after this %s\n",
                  nr), nr, steps_msg);
diff --combined branch.c
index 985316eb76505a60bca0aa303322bef35e7defaa,5532b4218f086372ee6601b08d4a2caaec5dc7bf..a8a548ccf2870c99bbdbcdc7036003aa648faa0c
+++ b/branch.c
@@@ -1,5 -1,6 +1,6 @@@
  #include "git-compat-util.h"
  #include "cache.h"
+ #include "config.h"
  #include "branch.h"
  #include "refs.h"
  #include "remote.h"
@@@ -191,9 -192,9 +192,9 @@@ int validate_new_branchname(const char 
  
        if (!attr_only) {
                const char *head;
 -              unsigned char sha1[20];
 +              struct object_id oid;
  
 -              head = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
 +              head = resolve_ref_unsafe("HEAD", 0, oid.hash, NULL);
                if (!is_bare_repository() && head && !strcmp(head, ref->buf))
                        die(_("Cannot force update the current branch."));
        }
@@@ -233,7 -234,7 +234,7 @@@ void create_branch(const char *name, co
                   int quiet, enum branch_track track)
  {
        struct commit *commit;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        char *real_ref;
        struct strbuf ref = STRBUF_INIT;
        int forcing = 0;
        }
  
        real_ref = NULL;
 -      if (get_sha1(start_name, sha1)) {
 +      if (get_oid(start_name, &oid)) {
                if (explicit_tracking) {
                        if (advice_set_upstream_failure) {
                                error(_(upstream_missing), start_name);
                die(_("Not a valid object name: '%s'."), start_name);
        }
  
 -      switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
 +      switch (dwim_ref(start_name, strlen(start_name), oid.hash, &real_ref)) {
        case 0:
                /* Not branching from any existing branch */
                if (explicit_tracking)
                break;
        }
  
 -      if ((commit = lookup_commit_reference(sha1)) == NULL)
 +      if ((commit = lookup_commit_reference(&oid)) == NULL)
                die(_("Not a valid branch point: '%s'."), start_name);
 -      hashcpy(sha1, commit->object.oid.hash);
 +      oidcpy(&oid, &commit->object.oid);
  
        if (reflog)
                log_all_ref_updates = LOG_REFS_NORMAL;
                transaction = ref_transaction_begin(&err);
                if (!transaction ||
                    ref_transaction_update(transaction, ref.buf,
 -                                         sha1, forcing ? NULL : null_sha1,
 +                                         oid.hash, forcing ? NULL : null_sha1,
                                           0, msg, &err) ||
                    ref_transaction_commit(transaction, &err))
                        die("%s", err.buf);
@@@ -353,18 -354,17 +354,18 @@@ int replace_each_worktree_head_symref(c
        int i;
  
        for (i = 0; worktrees[i]; i++) {
 +              struct ref_store *refs;
 +
                if (worktrees[i]->is_detached)
                        continue;
 -              if (strcmp(oldref, worktrees[i]->head_ref))
 +              if (worktrees[i]->head_ref &&
 +                  strcmp(oldref, worktrees[i]->head_ref))
                        continue;
  
 -              if (set_worktree_head_symref(get_worktree_git_dir(worktrees[i]),
 -                                           newref, logmsg)) {
 -                      ret = -1;
 -                      error(_("HEAD of working tree %s is not updated"),
 -                            worktrees[i]->path);
 -              }
 +              refs = get_worktree_ref_store(worktrees[i]);
 +              if (refs_create_symref(refs, "HEAD", newref, logmsg))
 +                      ret = error(_("HEAD of working tree %s is not updated"),
 +                                  worktrees[i]->path);
        }
  
        free_worktrees(worktrees);
diff --combined builtin/add.c
index d9a2491e48f16d9ef7de5c05008f8c7e6a5e64b2,55759a6a78ab540562370e7af30864e0366ac04c..f2415e99f37d48e562913c17d8917bda4f892c09
@@@ -4,6 -4,7 +4,7 @@@
   * Copyright (C) 2006 Linus Torvalds
   */
  #include "cache.h"
+ #include "config.h"
  #include "builtin.h"
  #include "lockfile.h"
  #include "dir.h"
@@@ -17,7 -18,6 +18,7 @@@
  #include "revision.h"
  #include "bulk-checkin.h"
  #include "argv-array.h"
 +#include "submodule.h"
  
  static const char * const builtin_add_usage[] = {
        N_("git add [<options>] [--] <pathspec>..."),
@@@ -136,7 -136,7 +137,7 @@@ static char *prune_directory(struct dir
                        *dst++ = entry;
        }
        dir->nr = dst - dir->entries;
 -      add_pathspec_matches_against_index(pathspec, seen);
 +      add_pathspec_matches_against_index(pathspec, &the_index, seen);
        return seen;
  }
  
@@@ -380,19 -380,16 +381,19 @@@ int cmd_add(int argc, const char **argv
        if (read_cache() < 0)
                die(_("index file corrupt"));
  
 +      die_in_unpopulated_submodule(&the_index, prefix);
 +
        /*
         * Check the "pathspec '%s' did not match any files" block
         * below before enabling new magic.
         */
        parse_pathspec(&pathspec, 0,
                       PATHSPEC_PREFER_FULL |
 -                     PATHSPEC_SYMLINK_LEADING_PATH |
 -                     PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE,
 +                     PATHSPEC_SYMLINK_LEADING_PATH,
                       prefix, argv);
  
 +      die_path_inside_submodule(&the_index, &pathspec);
 +
        if (add_new_files) {
                int baselen;
  
                }
  
                /* This picks up the paths that are not tracked */
 -              baselen = fill_directory(&dir, &pathspec);
 +              baselen = fill_directory(&dir, &the_index, &pathspec);
                if (pathspec.nr)
                        seen = prune_directory(&dir, &pathspec, baselen);
        }
                int i;
  
                if (!seen)
 -                      seen = find_pathspecs_matching_against_index(&pathspec);
 +                      seen = find_pathspecs_matching_against_index(&pathspec, &the_index);
  
                /*
                 * file_exists() assumes exact match
                             !file_exists(path))) {
                                if (ignore_missing) {
                                        int dtype = DT_UNKNOWN;
 -                                      if (is_excluded(&dir, path, &dtype))
 -                                              dir_add_ignored(&dir, path, pathspec.items[i].len);
 +                                      if (is_excluded(&dir, &the_index, path, &dtype))
 +                                              dir_add_ignored(&dir, &the_index,
 +                                                              path, pathspec.items[i].len);
                                } else
                                        die(_("pathspec '%s' did not match any files"),
                                            pathspec.items[i].original);
diff --combined builtin/am.c
index 3985f9a89f985baa139ea69f5fde8ce1384871f6,59f46a29eea99665a94dcde31b885f61b5f6305d..7c7b916d2328be8e6dc7abb7e08bb9416b21d2e6
@@@ -4,6 -4,7 +4,7 @@@
   * Based on git-am.sh by Junio C Hamano.
   */
  #include "cache.h"
+ #include "config.h"
  #include "builtin.h"
  #include "exec_cmd.h"
  #include "parse-options.h"
@@@ -563,7 -564,7 +564,7 @@@ static int copy_notes_for_rebase(const 
                        goto finish;
                }
  
 -              if (copy_note_for_rewrite(c, from_obj.hash, to_obj.hash))
 +              if (copy_note_for_rewrite(c, &from_obj, &to_obj))
                        ret = error(_("Failed to copy notes from '%s' to '%s'"),
                                        oid_to_hex(&from_obj), oid_to_hex(&to_obj));
        }
@@@ -879,12 -880,12 +880,12 @@@ static int hg_patch_to_mail(FILE *out, 
                if (skip_prefix(sb.buf, "# User ", &str))
                        fprintf(out, "From: %s\n", str);
                else if (skip_prefix(sb.buf, "# Date ", &str)) {
 -                      unsigned long timestamp;
 +                      timestamp_t timestamp;
                        long tz, tz2;
                        char *end;
  
                        errno = 0;
 -                      timestamp = strtoul(str, &end, 10);
 +                      timestamp = parse_timestamp(str, &end, 10);
                        if (errno)
                                return error(_("invalid timestamp"));
  
@@@ -1145,7 -1146,7 +1146,7 @@@ static int index_has_changes(struct str
                DIFF_OPT_SET(&opt, EXIT_WITH_STATUS);
                if (!sb)
                        DIFF_OPT_SET(&opt, QUICK);
 -              do_diff_cache(head.hash, &opt);
 +              do_diff_cache(&head, &opt);
                diffcore_std(&opt);
                for (i = 0; sb && i < diff_queued_diff.nr; i++) {
                        if (i)
@@@ -1275,8 -1276,12 +1276,8 @@@ static int parse_mail(struct am_state *
                die("BUG: invalid value for state->scissors");
        }
  
 -      mi.input = fopen(mail, "r");
 -      if (!mi.input)
 -              die("could not open input");
 -      mi.output = fopen(am_path(state, "info"), "w");
 -      if (!mi.output)
 -              die("could not open output 'info'");
 +      mi.input = xfopen(mail, "r");
 +      mi.output = xfopen(am_path(state, "info"), "w");
        if (mailinfo(&mi, am_path(state, "msg"), am_path(state, "patch")))
                die("could not parse patch");
  
        }
  
        if (is_empty_file(am_path(state, "patch"))) {
 -              printf_ln(_("Patch is empty. Was it split wrong?"));
 +              printf_ln(_("Patch is empty."));
                die_user_resolve(state);
        }
  
@@@ -1347,16 -1352,19 +1348,16 @@@ static int get_mail_commit_oid(struct o
        struct strbuf sb = STRBUF_INIT;
        FILE *fp = xfopen(mail, "r");
        const char *x;
 +      int ret = 0;
  
 -      if (strbuf_getline_lf(&sb, fp))
 -              return -1;
 -
 -      if (!skip_prefix(sb.buf, "From ", &x))
 -              return -1;
 -
 -      if (get_oid_hex(x, commit_id) < 0)
 -              return -1;
 +      if (strbuf_getline_lf(&sb, fp) ||
 +          !skip_prefix(sb.buf, "From ", &x) ||
 +          get_oid_hex(x, commit_id) < 0)
 +              ret = -1;
  
        strbuf_release(&sb);
        fclose(fp);
 -      return 0;
 +      return ret;
  }
  
  /**
   */
  static void get_commit_info(struct am_state *state, struct commit *commit)
  {
 -      const char *buffer, *ident_line, *author_date, *msg;
 +      const char *buffer, *ident_line, *msg;
        size_t ident_len;
 -      struct ident_split ident_split;
 -      struct strbuf sb = STRBUF_INIT;
 +      struct ident_split id;
  
        buffer = logmsg_reencode(commit, NULL, get_commit_output_encoding());
  
        ident_line = find_commit_header(buffer, "author", &ident_len);
  
 -      if (split_ident_line(&ident_split, ident_line, ident_len) < 0) {
 -              strbuf_add(&sb, ident_line, ident_len);
 -              die(_("invalid ident line: %s"), sb.buf);
 -      }
 +      if (split_ident_line(&id, ident_line, ident_len) < 0)
 +              die(_("invalid ident line: %.*s"), (int)ident_len, ident_line);
  
        assert(!state->author_name);
 -      if (ident_split.name_begin) {
 -              strbuf_add(&sb, ident_split.name_begin,
 -                      ident_split.name_end - ident_split.name_begin);
 -              state->author_name = strbuf_detach(&sb, NULL);
 -      } else
 +      if (id.name_begin)
 +              state->author_name =
 +                      xmemdupz(id.name_begin, id.name_end - id.name_begin);
 +      else
                state->author_name = xstrdup("");
  
        assert(!state->author_email);
 -      if (ident_split.mail_begin) {
 -              strbuf_add(&sb, ident_split.mail_begin,
 -                      ident_split.mail_end - ident_split.mail_begin);
 -              state->author_email = strbuf_detach(&sb, NULL);
 -      } else
 +      if (id.mail_begin)
 +              state->author_email =
 +                      xmemdupz(id.mail_begin, id.mail_end - id.mail_begin);
 +      else
                state->author_email = xstrdup("");
  
 -      author_date = show_ident_date(&ident_split, DATE_MODE(NORMAL));
 -      strbuf_addstr(&sb, author_date);
        assert(!state->author_date);
 -      state->author_date = strbuf_detach(&sb, NULL);
 +      state->author_date = xstrdup(show_ident_date(&id, DATE_MODE(NORMAL)));
  
        assert(!state->msg);
        msg = strstr(buffer, "\n\n");
                die(_("unable to parse commit %s"), oid_to_hex(&commit->object.oid));
        state->msg = xstrdup(msg + 2);
        state->msg_len = strlen(state->msg);
 +      unuse_commit_buffer(commit, buffer);
  }
  
  /**
@@@ -1440,9 -1454,9 +1441,9 @@@ static void write_index_patch(const str
        FILE *fp;
  
        if (!get_sha1_tree("HEAD", head.hash))
 -              tree = lookup_tree(head.hash);
 +              tree = lookup_tree(&head);
        else
 -              tree = lookup_tree(EMPTY_TREE_SHA1_BIN);
 +              tree = lookup_tree(&empty_tree_oid);
  
        fp = xfopen(am_path(state, "patch"), "w");
        init_revisions(&rev_info, NULL);
@@@ -1475,7 -1489,7 +1476,7 @@@ static int parse_mail_rebase(struct am_
        if (get_mail_commit_oid(&commit_oid, mail) < 0)
                die(_("could not parse %s"), mail);
  
 -      commit = lookup_commit_or_die(commit_oid.hash, mail);
 +      commit = lookup_commit_or_die(&commit_oid, mail);
  
        get_commit_info(state, commit);
  
@@@ -1605,7 -1619,7 +1606,7 @@@ static int fall_back_threeway(const str
                init_revisions(&rev_info, NULL);
                rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS;
                diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1, rev_info.prefix);
 -              add_pending_sha1(&rev_info, "HEAD", our_tree.hash, 0);
 +              add_pending_oid(&rev_info, "HEAD", &our_tree, 0);
                diff_setup_done(&rev_info.diffopt);
                run_diff_index(&rev_info, 1);
        }
@@@ -1670,7 -1684,7 +1671,7 @@@ static void do_commit(const struct am_s
  
        if (!get_sha1_commit("HEAD", parent.hash)) {
                old_oid = &parent;
 -              commit_list_insert(lookup_commit(parent.hash), &parents);
 +              commit_list_insert(lookup_commit(&parent), &parents);
        } else {
                old_oid = NULL;
                say(state, stderr, _("applying to an empty history"));
@@@ -1927,8 -1941,7 +1928,8 @@@ static void am_resolve(struct am_state 
  
        if (unmerged_cache()) {
                printf_ln(_("You still have unmerged paths in your index.\n"
 -                      "Did you forget to use 'git add'?"));
 +                      "You should 'git add' each file with resolved conflicts to mark them as such.\n"
 +                      "You might run `git rm` on a file to accept \"deleted by them\" for it."));
                die_user_resolve(state);
        }
  
@@@ -2033,11 -2046,11 +2034,11 @@@ static int clean_index(const struct obj
        struct tree *head_tree, *remote_tree, *index_tree;
        struct object_id index;
  
 -      head_tree = parse_tree_indirect(head->hash);
 +      head_tree = parse_tree_indirect(head);
        if (!head_tree)
                return error(_("Could not parse object '%s'."), oid_to_hex(head));
  
 -      remote_tree = parse_tree_indirect(remote->hash);
 +      remote_tree = parse_tree_indirect(remote);
        if (!remote_tree)
                return error(_("Could not parse object '%s'."), oid_to_hex(remote));
  
        if (write_cache_as_tree(index.hash, 0, NULL))
                return -1;
  
 -      index_tree = parse_tree_indirect(index.hash);
 +      index_tree = parse_tree_indirect(&index);
        if (!index_tree)
                return error(_("Could not parse object '%s'."), oid_to_hex(&index));
  
@@@ -2144,7 -2157,7 +2145,7 @@@ static void am_abort(struct am_state *s
        am_rerere_clear();
  
        curr_branch = resolve_refdup("HEAD", 0, curr_head.hash, NULL);
 -      has_curr_head = !is_null_oid(&curr_head);
 +      has_curr_head = curr_branch && !is_null_oid(&curr_head);
        if (!has_curr_head)
                hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN);
  
@@@ -2307,9 -2320,6 +2308,9 @@@ int cmd_am(int argc, const char **argv
                OPT_END()
        };
  
 +      if (argc == 2 && !strcmp(argv[1], "-h"))
 +              usage_with_options(usage, options);
 +
        git_config(git_am_config, NULL);
  
        am_state_init(&state);
diff --combined builtin/blame.c
index 749ad7f05b657ba34534a4ae6601dd5d85649b36,1a7371808ad4615052e92b792149ad7f84845776..bda1a787265e6d44d2ec0bec1e4dee5bf8de9c3b
@@@ -6,13 -6,22 +6,14 @@@
   */
  
  #include "cache.h"
 -#include "refs.h"
+ #include "config.h"
  #include "builtin.h"
 -#include "blob.h"
  #include "commit.h"
 -#include "tag.h"
 -#include "tree-walk.h"
  #include "diff.h"
 -#include "diffcore.h"
  #include "revision.h"
  #include "quote.h"
 -#include "xdiff-interface.h"
 -#include "cache-tree.h"
  #include "string-list.h"
  #include "mailmap.h"
 -#include "mergesort.h"
  #include "parse-options.h"
  #include "prio-queue.h"
  #include "utf8.h"
@@@ -21,7 -30,6 +22,7 @@@
  #include "line-log.h"
  #include "dir.h"
  #include "progress.h"
 +#include "blame.h"
  
  static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
  
@@@ -55,21 -63,1497 +56,21 @@@ static struct string_list mailmap = STR
  #define DEBUG 0
  #endif
  
 -/* stats */
 -static int num_read_blob;
 -static int num_get_patch;
 -static int num_commits;
 -
 -#define PICKAXE_BLAME_MOVE            01
 -#define PICKAXE_BLAME_COPY            02
 -#define PICKAXE_BLAME_COPY_HARDER     04
 -#define PICKAXE_BLAME_COPY_HARDEST    010
 -
 -/*
 - * blame for a blame_entry with score lower than these thresholds
 - * is not passed to the parent using move/copy logic.
 - */
 -static unsigned blame_move_score;
 -static unsigned blame_copy_score;
 -#define BLAME_DEFAULT_MOVE_SCORE      20
 -#define BLAME_DEFAULT_COPY_SCORE      40
 -
 -/* Remember to update object flag allocation in object.h */
 -#define METAINFO_SHOWN                (1u<<12)
 -#define MORE_THAN_ONE_PATH    (1u<<13)
 -
 -/*
 - * One blob in a commit that is being suspected
 - */
 -struct origin {
 -      int refcnt;
 -      /* Record preceding blame record for this blob */
 -      struct origin *previous;
 -      /* origins are put in a list linked via `next' hanging off the
 -       * corresponding commit's util field in order to make finding
 -       * them fast.  The presence in this chain does not count
 -       * towards the origin's reference count.  It is tempting to
 -       * let it count as long as the commit is pending examination,
 -       * but even under circumstances where the commit will be
 -       * present multiple times in the priority queue of unexamined
 -       * commits, processing the first instance will not leave any
 -       * work requiring the origin data for the second instance.  An
 -       * interspersed commit changing that would have to be
 -       * preexisting with a different ancestry and with the same
 -       * commit date in order to wedge itself between two instances
 -       * of the same commit in the priority queue _and_ produce
 -       * blame entries relevant for it.  While we don't want to let
 -       * us get tripped up by this case, it certainly does not seem
 -       * worth optimizing for.
 -       */
 -      struct origin *next;
 -      struct commit *commit;
 -      /* `suspects' contains blame entries that may be attributed to
 -       * this origin's commit or to parent commits.  When a commit
 -       * is being processed, all suspects will be moved, either by
 -       * assigning them to an origin in a different commit, or by
 -       * shipping them to the scoreboard's ent list because they
 -       * cannot be attributed to a different commit.
 -       */
 -      struct blame_entry *suspects;
 -      mmfile_t file;
 -      struct object_id blob_oid;
 -      unsigned mode;
 -      /* guilty gets set when shipping any suspects to the final
 -       * blame list instead of other commits
 -       */
 -      char guilty;
 -      char path[FLEX_ARRAY];
 -};
 -
 -struct progress_info {
 -      struct progress *progress;
 -      int blamed_lines;
 -};
 -
 -static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b,
 -                    xdl_emit_hunk_consume_func_t hunk_func, void *cb_data)
 -{
 -      xpparam_t xpp = {0};
 -      xdemitconf_t xecfg = {0};
 -      xdemitcb_t ecb = {NULL};
 -
 -      xpp.flags = xdl_opts;
 -      xecfg.hunk_func = hunk_func;
 -      ecb.priv = cb_data;
 -      return xdi_diff(file_a, file_b, &xpp, &xecfg, &ecb);
 -}
 -
 -/*
 - * Prepare diff_filespec and convert it using diff textconv API
 - * if the textconv driver exists.
 - * Return 1 if the conversion succeeds, 0 otherwise.
 - */
 -int textconv_object(const char *path,
 -                  unsigned mode,
 -                  const struct object_id *oid,
 -                  int oid_valid,
 -                  char **buf,
 -                  unsigned long *buf_size)
 -{
 -      struct diff_filespec *df;
 -      struct userdiff_driver *textconv;
 -
 -      df = alloc_filespec(path);
 -      fill_filespec(df, oid->hash, oid_valid, mode);
 -      textconv = get_textconv(df);
 -      if (!textconv) {
 -              free_filespec(df);
 -              return 0;
 -      }
 -
 -      *buf_size = fill_textconv(textconv, df, buf);
 -      free_filespec(df);
 -      return 1;
 -}
 -
 -/*
 - * Given an origin, prepare mmfile_t structure to be used by the
 - * diff machinery
 - */
 -static void fill_origin_blob(struct diff_options *opt,
 -                           struct origin *o, mmfile_t *file)
 -{
 -      if (!o->file.ptr) {
 -              enum object_type type;
 -              unsigned long file_size;
 -
 -              num_read_blob++;
 -              if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
 -                  textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size))
 -                      ;
 -              else
 -                      file->ptr = read_sha1_file(o->blob_oid.hash, &type,
 -                                                 &file_size);
 -              file->size = file_size;
 -
 -              if (!file->ptr)
 -                      die("Cannot read blob %s for path %s",
 -                          oid_to_hex(&o->blob_oid),
 -                          o->path);
 -              o->file = *file;
 -      }
 -      else
 -              *file = o->file;
 -}
 -
 -/*
 - * Origin is refcounted and usually we keep the blob contents to be
 - * reused.
 - */
 -static inline struct origin *origin_incref(struct origin *o)
 -{
 -      if (o)
 -              o->refcnt++;
 -      return o;
 -}
 -
 -static void origin_decref(struct origin *o)
 -{
 -      if (o && --o->refcnt <= 0) {
 -              struct origin *p, *l = NULL;
 -              if (o->previous)
 -                      origin_decref(o->previous);
 -              free(o->file.ptr);
 -              /* Should be present exactly once in commit chain */
 -              for (p = o->commit->util; p; l = p, p = p->next) {
 -                      if (p == o) {
 -                              if (l)
 -                                      l->next = p->next;
 -                              else
 -                                      o->commit->util = p->next;
 -                              free(o);
 -                              return;
 -                      }
 -              }
 -              die("internal error in blame::origin_decref");
 -      }
 -}
 -
 -static void drop_origin_blob(struct origin *o)
 -{
 -      if (o->file.ptr) {
 -              free(o->file.ptr);
 -              o->file.ptr = NULL;
 -      }
 -}
 -
 -/*
 - * Each group of lines is described by a blame_entry; it can be split
 - * as we pass blame to the parents.  They are arranged in linked lists
 - * kept as `suspects' of some unprocessed origin, or entered (when the
 - * blame origin has been finalized) into the scoreboard structure.
 - * While the scoreboard structure is only sorted at the end of
 - * processing (according to final image line number), the lists
 - * attached to an origin are sorted by the target line number.
 - */
 -struct blame_entry {
 -      struct blame_entry *next;
 -
 -      /* the first line of this group in the final image;
 -       * internally all line numbers are 0 based.
 -       */
 -      int lno;
 -
 -      /* how many lines this group has */
 -      int num_lines;
 -
 -      /* the commit that introduced this group into the final image */
 -      struct origin *suspect;
 -
 -      /* the line number of the first line of this group in the
 -       * suspect's file; internally all line numbers are 0 based.
 -       */
 -      int s_lno;
 -
 -      /* how significant this entry is -- cached to avoid
 -       * scanning the lines over and over.
 -       */
 -      unsigned score;
 -};
 -
 -/*
 - * Any merge of blames happens on lists of blames that arrived via
 - * different parents in a single suspect.  In this case, we want to
 - * sort according to the suspect line numbers as opposed to the final
 - * image line numbers.  The function body is somewhat longish because
 - * it avoids unnecessary writes.
 - */
 -
 -static struct blame_entry *blame_merge(struct blame_entry *list1,
 -                                     struct blame_entry *list2)
 -{
 -      struct blame_entry *p1 = list1, *p2 = list2,
 -              **tail = &list1;
 -
 -      if (!p1)
 -              return p2;
 -      if (!p2)
 -              return p1;
 -
 -      if (p1->s_lno <= p2->s_lno) {
 -              do {
 -                      tail = &p1->next;
 -                      if ((p1 = *tail) == NULL) {
 -                              *tail = p2;
 -                              return list1;
 -                      }
 -              } while (p1->s_lno <= p2->s_lno);
 -      }
 -      for (;;) {
 -              *tail = p2;
 -              do {
 -                      tail = &p2->next;
 -                      if ((p2 = *tail) == NULL)  {
 -                              *tail = p1;
 -                              return list1;
 -                      }
 -              } while (p1->s_lno > p2->s_lno);
 -              *tail = p1;
 -              do {
 -                      tail = &p1->next;
 -                      if ((p1 = *tail) == NULL) {
 -                              *tail = p2;
 -                              return list1;
 -                      }
 -              } while (p1->s_lno <= p2->s_lno);
 -      }
 -}
 -
 -static void *get_next_blame(const void *p)
 -{
 -      return ((struct blame_entry *)p)->next;
 -}
 -
 -static void set_next_blame(void *p1, void *p2)
 -{
 -      ((struct blame_entry *)p1)->next = p2;
 -}
 -
 -/*
 - * Final image line numbers are all different, so we don't need a
 - * three-way comparison here.
 - */
 -
 -static int compare_blame_final(const void *p1, const void *p2)
 -{
 -      return ((struct blame_entry *)p1)->lno > ((struct blame_entry *)p2)->lno
 -              ? 1 : -1;
 -}
 -
 -static int compare_blame_suspect(const void *p1, const void *p2)
 -{
 -      const struct blame_entry *s1 = p1, *s2 = p2;
 -      /*
 -       * to allow for collating suspects, we sort according to the
 -       * respective pointer value as the primary sorting criterion.
 -       * The actual relation is pretty unimportant as long as it
 -       * establishes a total order.  Comparing as integers gives us
 -       * that.
 -       */
 -      if (s1->suspect != s2->suspect)
 -              return (intptr_t)s1->suspect > (intptr_t)s2->suspect ? 1 : -1;
 -      if (s1->s_lno == s2->s_lno)
 -              return 0;
 -      return s1->s_lno > s2->s_lno ? 1 : -1;
 -}
 -
 -static struct blame_entry *blame_sort(struct blame_entry *head,
 -                                    int (*compare_fn)(const void *, const void *))
 -{
 -      return llist_mergesort (head, get_next_blame, set_next_blame, compare_fn);
 -}
 -
 -static int compare_commits_by_reverse_commit_date(const void *a,
 -                                                const void *b,
 -                                                void *c)
 -{
 -      return -compare_commits_by_commit_date(a, b, c);
 -}
 -
 -/*
 - * The current state of the blame assignment.
 - */
 -struct scoreboard {
 -      /* the final commit (i.e. where we started digging from) */
 -      struct commit *final;
 -      /* Priority queue for commits with unassigned blame records */
 -      struct prio_queue commits;
 -      struct rev_info *revs;
 -      const char *path;
 -
 -      /*
 -       * The contents in the final image.
 -       * Used by many functions to obtain contents of the nth line,
 -       * indexed with scoreboard.lineno[blame_entry.lno].
 -       */
 -      const char *final_buf;
 -      unsigned long final_buf_size;
 -
 -      /* linked list of blames */
 -      struct blame_entry *ent;
 -
 -      /* look-up a line in the final buffer */
 -      int num_lines;
 -      int *lineno;
 -};
 -
 -static void sanity_check_refcnt(struct scoreboard *);
 -
 -/*
 - * If two blame entries that are next to each other came from
 - * contiguous lines in the same origin (i.e. <commit, path> pair),
 - * merge them together.
 - */
 -static void coalesce(struct scoreboard *sb)
 -{
 -      struct blame_entry *ent, *next;
 -
 -      for (ent = sb->ent; ent && (next = ent->next); ent = next) {
 -              if (ent->suspect == next->suspect &&
 -                  ent->s_lno + ent->num_lines == next->s_lno) {
 -                      ent->num_lines += next->num_lines;
 -                      ent->next = next->next;
 -                      origin_decref(next->suspect);
 -                      free(next);
 -                      ent->score = 0;
 -                      next = ent; /* again */
 -              }
 -      }
 -
 -      if (DEBUG) /* sanity */
 -              sanity_check_refcnt(sb);
 -}
 -
 -/*
 - * Merge the given sorted list of blames into a preexisting origin.
 - * If there were no previous blames to that commit, it is entered into
 - * the commit priority queue of the score board.
 - */
 -
 -static void queue_blames(struct scoreboard *sb, struct origin *porigin,
 -                       struct blame_entry *sorted)
 -{
 -      if (porigin->suspects)
 -              porigin->suspects = blame_merge(porigin->suspects, sorted);
 -      else {
 -              struct origin *o;
 -              for (o = porigin->commit->util; o; o = o->next) {
 -                      if (o->suspects) {
 -                              porigin->suspects = sorted;
 -                              return;
 -                      }
 -              }
 -              porigin->suspects = sorted;
 -              prio_queue_put(&sb->commits, porigin->commit);
 -      }
 -}
 -
 -/*
 - * Given a commit and a path in it, create a new origin structure.
 - * The callers that add blame to the scoreboard should use
 - * get_origin() to obtain shared, refcounted copy instead of calling
 - * this function directly.
 - */
 -static struct origin *make_origin(struct commit *commit, const char *path)
 -{
 -      struct origin *o;
 -      FLEX_ALLOC_STR(o, path, path);
 -      o->commit = commit;
 -      o->refcnt = 1;
 -      o->next = commit->util;
 -      commit->util = o;
 -      return o;
 -}
 -
 -/*
 - * Locate an existing origin or create a new one.
 - * This moves the origin to front position in the commit util list.
 - */
 -static struct origin *get_origin(struct scoreboard *sb,
 -                               struct commit *commit,
 -                               const char *path)
 -{
 -      struct origin *o, *l;
 -
 -      for (o = commit->util, l = NULL; o; l = o, o = o->next) {
 -              if (!strcmp(o->path, path)) {
 -                      /* bump to front */
 -                      if (l) {
 -                              l->next = o->next;
 -                              o->next = commit->util;
 -                              commit->util = o;
 -                      }
 -                      return origin_incref(o);
 -              }
 -      }
 -      return make_origin(commit, path);
 -}
 -
 -/*
 - * Fill the blob_sha1 field of an origin if it hasn't, so that later
 - * call to fill_origin_blob() can use it to locate the data.  blob_sha1
 - * for an origin is also used to pass the blame for the entire file to
 - * the parent to detect the case where a child's blob is identical to
 - * that of its parent's.
 - *
 - * This also fills origin->mode for corresponding tree path.
 - */
 -static int fill_blob_sha1_and_mode(struct origin *origin)
 -{
 -      if (!is_null_oid(&origin->blob_oid))
 -              return 0;
 -      if (get_tree_entry(origin->commit->object.oid.hash,
 -                         origin->path,
 -                         origin->blob_oid.hash, &origin->mode))
 -              goto error_out;
 -      if (sha1_object_info(origin->blob_oid.hash, NULL) != OBJ_BLOB)
 -              goto error_out;
 -      return 0;
 - error_out:
 -      oidclr(&origin->blob_oid);
 -      origin->mode = S_IFINVALID;
 -      return -1;
 -}
 -
 -/*
 - * We have an origin -- check if the same path exists in the
 - * parent and return an origin structure to represent it.
 - */
 -static struct origin *find_origin(struct scoreboard *sb,
 -                                struct commit *parent,
 -                                struct origin *origin)
 -{
 -      struct origin *porigin;
 -      struct diff_options diff_opts;
 -      const char *paths[2];
 -
 -      /* First check any existing origins */
 -      for (porigin = parent->util; porigin; porigin = porigin->next)
 -              if (!strcmp(porigin->path, origin->path)) {
 -                      /*
 -                       * The same path between origin and its parent
 -                       * without renaming -- the most common case.
 -                       */
 -                      return origin_incref (porigin);
 -              }
 -
 -      /* See if the origin->path is different between parent
 -       * and origin first.  Most of the time they are the
 -       * same and diff-tree is fairly efficient about this.
 -       */
 -      diff_setup(&diff_opts);
 -      DIFF_OPT_SET(&diff_opts, RECURSIVE);
 -      diff_opts.detect_rename = 0;
 -      diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
 -      paths[0] = origin->path;
 -      paths[1] = NULL;
 -
 -      parse_pathspec(&diff_opts.pathspec,
 -                     PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
 -                     PATHSPEC_LITERAL_PATH, "", paths);
 -      diff_setup_done(&diff_opts);
 -
 -      if (is_null_oid(&origin->commit->object.oid))
 -              do_diff_cache(parent->tree->object.oid.hash, &diff_opts);
 -      else
 -              diff_tree_sha1(parent->tree->object.oid.hash,
 -                             origin->commit->tree->object.oid.hash,
 -                             "", &diff_opts);
 -      diffcore_std(&diff_opts);
 -
 -      if (!diff_queued_diff.nr) {
 -              /* The path is the same as parent */
 -              porigin = get_origin(sb, parent, origin->path);
 -              oidcpy(&porigin->blob_oid, &origin->blob_oid);
 -              porigin->mode = origin->mode;
 -      } else {
 -              /*
 -               * Since origin->path is a pathspec, if the parent
 -               * commit had it as a directory, we will see a whole
 -               * bunch of deletion of files in the directory that we
 -               * do not care about.
 -               */
 -              int i;
 -              struct diff_filepair *p = NULL;
 -              for (i = 0; i < diff_queued_diff.nr; i++) {
 -                      const char *name;
 -                      p = diff_queued_diff.queue[i];
 -                      name = p->one->path ? p->one->path : p->two->path;
 -                      if (!strcmp(name, origin->path))
 -                              break;
 -              }
 -              if (!p)
 -                      die("internal error in blame::find_origin");
 -              switch (p->status) {
 -              default:
 -                      die("internal error in blame::find_origin (%c)",
 -                          p->status);
 -              case 'M':
 -                      porigin = get_origin(sb, parent, origin->path);
 -                      oidcpy(&porigin->blob_oid, &p->one->oid);
 -                      porigin->mode = p->one->mode;
 -                      break;
 -              case 'A':
 -              case 'T':
 -                      /* Did not exist in parent, or type changed */
 -                      break;
 -              }
 -      }
 -      diff_flush(&diff_opts);
 -      clear_pathspec(&diff_opts.pathspec);
 -      return porigin;
 -}
 -
 -/*
 - * We have an origin -- find the path that corresponds to it in its
 - * parent and return an origin structure to represent it.
 - */
 -static struct origin *find_rename(struct scoreboard *sb,
 -                                struct commit *parent,
 -                                struct origin *origin)
 -{
 -      struct origin *porigin = NULL;
 -      struct diff_options diff_opts;
 -      int i;
 -
 -      diff_setup(&diff_opts);
 -      DIFF_OPT_SET(&diff_opts, RECURSIVE);
 -      diff_opts.detect_rename = DIFF_DETECT_RENAME;
 -      diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
 -      diff_opts.single_follow = origin->path;
 -      diff_setup_done(&diff_opts);
 -
 -      if (is_null_oid(&origin->commit->object.oid))
 -              do_diff_cache(parent->tree->object.oid.hash, &diff_opts);
 -      else
 -              diff_tree_sha1(parent->tree->object.oid.hash,
 -                             origin->commit->tree->object.oid.hash,
 -                             "", &diff_opts);
 -      diffcore_std(&diff_opts);
 -
 -      for (i = 0; i < diff_queued_diff.nr; i++) {
 -              struct diff_filepair *p = diff_queued_diff.queue[i];
 -              if ((p->status == 'R' || p->status == 'C') &&
 -                  !strcmp(p->two->path, origin->path)) {
 -                      porigin = get_origin(sb, parent, p->one->path);
 -                      oidcpy(&porigin->blob_oid, &p->one->oid);
 -                      porigin->mode = p->one->mode;
 -                      break;
 -              }
 -      }
 -      diff_flush(&diff_opts);
 -      clear_pathspec(&diff_opts.pathspec);
 -      return porigin;
 -}
 -
 -/*
 - * Append a new blame entry to a given output queue.
 - */
 -static void add_blame_entry(struct blame_entry ***queue,
 -                          const struct blame_entry *src)
 -{
 -      struct blame_entry *e = xmalloc(sizeof(*e));
 -      memcpy(e, src, sizeof(*e));
 -      origin_incref(e->suspect);
 -
 -      e->next = **queue;
 -      **queue = e;
 -      *queue = &e->next;
 -}
 -
 -/*
 - * src typically is on-stack; we want to copy the information in it to
 - * a malloced blame_entry that gets added to the given queue.  The
 - * origin of dst loses a refcnt.
 - */
 -static void dup_entry(struct blame_entry ***queue,
 -                    struct blame_entry *dst, struct blame_entry *src)
 -{
 -      origin_incref(src->suspect);
 -      origin_decref(dst->suspect);
 -      memcpy(dst, src, sizeof(*src));
 -      dst->next = **queue;
 -      **queue = dst;
 -      *queue = &dst->next;
 -}
 -
 -static const char *nth_line(struct scoreboard *sb, long lno)
 -{
 -      return sb->final_buf + sb->lineno[lno];
 -}
 -
 -static const char *nth_line_cb(void *data, long lno)
 -{
 -      return nth_line((struct scoreboard *)data, lno);
 -}
 -
 -/*
 - * It is known that lines between tlno to same came from parent, and e
 - * has an overlap with that range.  it also is known that parent's
 - * line plno corresponds to e's line tlno.
 - *
 - *                <---- e ----->
 - *                   <------>
 - *                   <------------>
 - *             <------------>
 - *             <------------------>
 - *
 - * Split e into potentially three parts; before this chunk, the chunk
 - * to be blamed for the parent, and after that portion.
 - */
 -static void split_overlap(struct blame_entry *split,
 -                        struct blame_entry *e,
 -                        int tlno, int plno, int same,
 -                        struct origin *parent)
 -{
 -      int chunk_end_lno;
 -      memset(split, 0, sizeof(struct blame_entry [3]));
 -
 -      if (e->s_lno < tlno) {
 -              /* there is a pre-chunk part not blamed on parent */
 -              split[0].suspect = origin_incref(e->suspect);
 -              split[0].lno = e->lno;
 -              split[0].s_lno = e->s_lno;
 -              split[0].num_lines = tlno - e->s_lno;
 -              split[1].lno = e->lno + tlno - e->s_lno;
 -              split[1].s_lno = plno;
 -      }
 -      else {
 -              split[1].lno = e->lno;
 -              split[1].s_lno = plno + (e->s_lno - tlno);
 -      }
 -
 -      if (same < e->s_lno + e->num_lines) {
 -              /* there is a post-chunk part not blamed on parent */
 -              split[2].suspect = origin_incref(e->suspect);
 -              split[2].lno = e->lno + (same - e->s_lno);
 -              split[2].s_lno = e->s_lno + (same - e->s_lno);
 -              split[2].num_lines = e->s_lno + e->num_lines - same;
 -              chunk_end_lno = split[2].lno;
 -      }
 -      else
 -              chunk_end_lno = e->lno + e->num_lines;
 -      split[1].num_lines = chunk_end_lno - split[1].lno;
 -
 -      /*
 -       * if it turns out there is nothing to blame the parent for,
 -       * forget about the splitting.  !split[1].suspect signals this.
 -       */
 -      if (split[1].num_lines < 1)
 -              return;
 -      split[1].suspect = origin_incref(parent);
 -}
 -
 -/*
 - * split_overlap() divided an existing blame e into up to three parts
 - * in split.  Any assigned blame is moved to queue to
 - * reflect the split.
 - */
 -static void split_blame(struct blame_entry ***blamed,
 -                      struct blame_entry ***unblamed,
 -                      struct blame_entry *split,
 -                      struct blame_entry *e)
 -{
 -      if (split[0].suspect && split[2].suspect) {
 -              /* The first part (reuse storage for the existing entry e) */
 -              dup_entry(unblamed, e, &split[0]);
 -
 -              /* The last part -- me */
 -              add_blame_entry(unblamed, &split[2]);
 -
 -              /* ... and the middle part -- parent */
 -              add_blame_entry(blamed, &split[1]);
 -      }
 -      else if (!split[0].suspect && !split[2].suspect)
 -              /*
 -               * The parent covers the entire area; reuse storage for
 -               * e and replace it with the parent.
 -               */
 -              dup_entry(blamed, e, &split[1]);
 -      else if (split[0].suspect) {
 -              /* me and then parent */
 -              dup_entry(unblamed, e, &split[0]);
 -              add_blame_entry(blamed, &split[1]);
 -      }
 -      else {
 -              /* parent and then me */
 -              dup_entry(blamed, e, &split[1]);
 -              add_blame_entry(unblamed, &split[2]);
 -      }
 -}
 -
 -/*
 - * After splitting the blame, the origins used by the
 - * on-stack blame_entry should lose one refcnt each.
 - */
 -static void decref_split(struct blame_entry *split)
 -{
 -      int i;
 -
 -      for (i = 0; i < 3; i++)
 -              origin_decref(split[i].suspect);
 -}
 -
 -/*
 - * reverse_blame reverses the list given in head, appending tail.
 - * That allows us to build lists in reverse order, then reverse them
 - * afterwards.  This can be faster than building the list in proper
 - * order right away.  The reason is that building in proper order
 - * requires writing a link in the _previous_ element, while building
 - * in reverse order just requires placing the list head into the
 - * _current_ element.
 - */
 -
 -static struct blame_entry *reverse_blame(struct blame_entry *head,
 -                                       struct blame_entry *tail)
 -{
 -      while (head) {
 -              struct blame_entry *next = head->next;
 -              head->next = tail;
 -              tail = head;
 -              head = next;
 -      }
 -      return tail;
 -}
 -
 -/*
 - * Process one hunk from the patch between the current suspect for
 - * blame_entry e and its parent.  This first blames any unfinished
 - * entries before the chunk (which is where target and parent start
 - * differing) on the parent, and then splits blame entries at the
 - * start and at the end of the difference region.  Since use of -M and
 - * -C options may lead to overlapping/duplicate source line number
 - * ranges, all we can rely on from sorting/merging is the order of the
 - * first suspect line number.
 - */
 -static void blame_chunk(struct blame_entry ***dstq, struct blame_entry ***srcq,
 -                      int tlno, int offset, int same,
 -                      struct origin *parent)
 -{
 -      struct blame_entry *e = **srcq;
 -      struct blame_entry *samep = NULL, *diffp = NULL;
 -
 -      while (e && e->s_lno < tlno) {
 -              struct blame_entry *next = e->next;
 -              /*
 -               * current record starts before differing portion.  If
 -               * it reaches into it, we need to split it up and
 -               * examine the second part separately.
 -               */
 -              if (e->s_lno + e->num_lines > tlno) {
 -                      /* Move second half to a new record */
 -                      int len = tlno - e->s_lno;
 -                      struct blame_entry *n = xcalloc(1, sizeof (struct blame_entry));
 -                      n->suspect = e->suspect;
 -                      n->lno = e->lno + len;
 -                      n->s_lno = e->s_lno + len;
 -                      n->num_lines = e->num_lines - len;
 -                      e->num_lines = len;
 -                      e->score = 0;
 -                      /* Push new record to diffp */
 -                      n->next = diffp;
 -                      diffp = n;
 -              } else
 -                      origin_decref(e->suspect);
 -              /* Pass blame for everything before the differing
 -               * chunk to the parent */
 -              e->suspect = origin_incref(parent);
 -              e->s_lno += offset;
 -              e->next = samep;
 -              samep = e;
 -              e = next;
 -      }
 -      /*
 -       * As we don't know how much of a common stretch after this
 -       * diff will occur, the currently blamed parts are all that we
 -       * can assign to the parent for now.
 -       */
 -
 -      if (samep) {
 -              **dstq = reverse_blame(samep, **dstq);
 -              *dstq = &samep->next;
 -      }
 -      /*
 -       * Prepend the split off portions: everything after e starts
 -       * after the blameable portion.
 -       */
 -      e = reverse_blame(diffp, e);
 -
 -      /*
 -       * Now retain records on the target while parts are different
 -       * from the parent.
 -       */
 -      samep = NULL;
 -      diffp = NULL;
 -      while (e && e->s_lno < same) {
 -              struct blame_entry *next = e->next;
 -
 -              /*
 -               * If current record extends into sameness, need to split.
 -               */
 -              if (e->s_lno + e->num_lines > same) {
 -                      /*
 -                       * Move second half to a new record to be
 -                       * processed by later chunks
 -                       */
 -                      int len = same - e->s_lno;
 -                      struct blame_entry *n = xcalloc(1, sizeof (struct blame_entry));
 -                      n->suspect = origin_incref(e->suspect);
 -                      n->lno = e->lno + len;
 -                      n->s_lno = e->s_lno + len;
 -                      n->num_lines = e->num_lines - len;
 -                      e->num_lines = len;
 -                      e->score = 0;
 -                      /* Push new record to samep */
 -                      n->next = samep;
 -                      samep = n;
 -              }
 -              e->next = diffp;
 -              diffp = e;
 -              e = next;
 -      }
 -      **srcq = reverse_blame(diffp, reverse_blame(samep, e));
 -      /* Move across elements that are in the unblamable portion */
 -      if (diffp)
 -              *srcq = &diffp->next;
 -}
 -
 -struct blame_chunk_cb_data {
 -      struct origin *parent;
 -      long offset;
 -      struct blame_entry **dstq;
 -      struct blame_entry **srcq;
 -};
 -
 -/* diff chunks are from parent to target */
 -static int blame_chunk_cb(long start_a, long count_a,
 -                        long start_b, long count_b, void *data)
 -{
 -      struct blame_chunk_cb_data *d = data;
 -      if (start_a - start_b != d->offset)
 -              die("internal error in blame::blame_chunk_cb");
 -      blame_chunk(&d->dstq, &d->srcq, start_b, start_a - start_b,
 -                  start_b + count_b, d->parent);
 -      d->offset = start_a + count_a - (start_b + count_b);
 -      return 0;
 -}
 -
 -/*
 - * We are looking at the origin 'target' and aiming to pass blame
 - * for the lines it is suspected to its parent.  Run diff to find
 - * which lines came from parent and pass blame for them.
 - */
 -static void pass_blame_to_parent(struct scoreboard *sb,
 -                               struct origin *target,
 -                               struct origin *parent)
 -{
 -      mmfile_t file_p, file_o;
 -      struct blame_chunk_cb_data d;
 -      struct blame_entry *newdest = NULL;
 -
 -      if (!target->suspects)
 -              return; /* nothing remains for this target */
 -
 -      d.parent = parent;
 -      d.offset = 0;
 -      d.dstq = &newdest; d.srcq = &target->suspects;
 -
 -      fill_origin_blob(&sb->revs->diffopt, parent, &file_p);
 -      fill_origin_blob(&sb->revs->diffopt, target, &file_o);
 -      num_get_patch++;
 -
 -      if (diff_hunks(&file_p, &file_o, blame_chunk_cb, &d))
 -              die("unable to generate diff (%s -> %s)",
 -                  oid_to_hex(&parent->commit->object.oid),
 -                  oid_to_hex(&target->commit->object.oid));
 -      /* The rest are the same as the parent */
 -      blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, parent);
 -      *d.dstq = NULL;
 -      queue_blames(sb, parent, newdest);
 -
 -      return;
 -}
 -
 -/*
 - * The lines in blame_entry after splitting blames many times can become
 - * very small and trivial, and at some point it becomes pointless to
 - * blame the parents.  E.g. "\t\t}\n\t}\n\n" appears everywhere in any
 - * ordinary C program, and it is not worth to say it was copied from
 - * totally unrelated file in the parent.
 - *
 - * Compute how trivial the lines in the blame_entry are.
 - */
 -static unsigned ent_score(struct scoreboard *sb, struct blame_entry *e)
 -{
 -      unsigned score;
 -      const char *cp, *ep;
 -
 -      if (e->score)
 -              return e->score;
 -
 -      score = 1;
 -      cp = nth_line(sb, e->lno);
 -      ep = nth_line(sb, e->lno + e->num_lines);
 -      while (cp < ep) {
 -              unsigned ch = *((unsigned char *)cp);
 -              if (isalnum(ch))
 -                      score++;
 -              cp++;
 -      }
 -      e->score = score;
 -      return score;
 -}
 -
 -/*
 - * best_so_far[] and this[] are both a split of an existing blame_entry
 - * that passes blame to the parent.  Maintain best_so_far the best split
 - * so far, by comparing this and best_so_far and copying this into
 - * bst_so_far as needed.
 - */
 -static void copy_split_if_better(struct scoreboard *sb,
 -                               struct blame_entry *best_so_far,
 -                               struct blame_entry *this)
 -{
 -      int i;
 -
 -      if (!this[1].suspect)
 -              return;
 -      if (best_so_far[1].suspect) {
 -              if (ent_score(sb, &this[1]) < ent_score(sb, &best_so_far[1]))
 -                      return;
 -      }
 -
 -      for (i = 0; i < 3; i++)
 -              origin_incref(this[i].suspect);
 -      decref_split(best_so_far);
 -      memcpy(best_so_far, this, sizeof(struct blame_entry [3]));
 -}
 -
 -/*
 - * We are looking at a part of the final image represented by
 - * ent (tlno and same are offset by ent->s_lno).
 - * tlno is where we are looking at in the final image.
 - * up to (but not including) same match preimage.
 - * plno is where we are looking at in the preimage.
 - *
 - * <-------------- final image ---------------------->
 - *       <------ent------>
 - *         ^tlno ^same
 - *    <---------preimage----->
 - *         ^plno
 - *
 - * All line numbers are 0-based.
 - */
 -static void handle_split(struct scoreboard *sb,
 -                       struct blame_entry *ent,
 -                       int tlno, int plno, int same,
 -                       struct origin *parent,
 -                       struct blame_entry *split)
 -{
 -      if (ent->num_lines <= tlno)
 -              return;
 -      if (tlno < same) {
 -              struct blame_entry this[3];
 -              tlno += ent->s_lno;
 -              same += ent->s_lno;
 -              split_overlap(this, ent, tlno, plno, same, parent);
 -              copy_split_if_better(sb, split, this);
 -              decref_split(this);
 -      }
 -}
 -
 -struct handle_split_cb_data {
 -      struct scoreboard *sb;
 -      struct blame_entry *ent;
 -      struct origin *parent;
 -      struct blame_entry *split;
 -      long plno;
 -      long tlno;
 -};
 -
 -static int handle_split_cb(long start_a, long count_a,
 -                         long start_b, long count_b, void *data)
 -{
 -      struct handle_split_cb_data *d = data;
 -      handle_split(d->sb, d->ent, d->tlno, d->plno, start_b, d->parent,
 -                   d->split);
 -      d->plno = start_a + count_a;
 -      d->tlno = start_b + count_b;
 -      return 0;
 -}
 -
 -/*
 - * Find the lines from parent that are the same as ent so that
 - * we can pass blames to it.  file_p has the blob contents for
 - * the parent.
 - */
 -static void find_copy_in_blob(struct scoreboard *sb,
 -                            struct blame_entry *ent,
 -                            struct origin *parent,
 -                            struct blame_entry *split,
 -                            mmfile_t *file_p)
 -{
 -      const char *cp;
 -      mmfile_t file_o;
 -      struct handle_split_cb_data d;
 -
 -      memset(&d, 0, sizeof(d));
 -      d.sb = sb; d.ent = ent; d.parent = parent; d.split = split;
 -      /*
 -       * Prepare mmfile that contains only the lines in ent.
 -       */
 -      cp = nth_line(sb, ent->lno);
 -      file_o.ptr = (char *) cp;
 -      file_o.size = nth_line(sb, ent->lno + ent->num_lines) - cp;
 -
 -      /*
 -       * file_o is a part of final image we are annotating.
 -       * file_p partially may match that image.
 -       */
 -      memset(split, 0, sizeof(struct blame_entry [3]));
 -      if (diff_hunks(file_p, &file_o, handle_split_cb, &d))
 -              die("unable to generate diff (%s)",
 -                  oid_to_hex(&parent->commit->object.oid));
 -      /* remainder, if any, all match the preimage */
 -      handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);
 -}
 -
 -/* Move all blame entries from list *source that have a score smaller
 - * than score_min to the front of list *small.
 - * Returns a pointer to the link pointing to the old head of the small list.
 - */
 -
 -static struct blame_entry **filter_small(struct scoreboard *sb,
 -                                       struct blame_entry **small,
 -                                       struct blame_entry **source,
 -                                       unsigned score_min)
 -{
 -      struct blame_entry *p = *source;
 -      struct blame_entry *oldsmall = *small;
 -      while (p) {
 -              if (ent_score(sb, p) <= score_min) {
 -                      *small = p;
 -                      small = &p->next;
 -                      p = *small;
 -              } else {
 -                      *source = p;
 -                      source = &p->next;
 -                      p = *source;
 -              }
 -      }
 -      *small = oldsmall;
 -      *source = NULL;
 -      return small;
 -}
 -
 -/*
 - * See if lines currently target is suspected for can be attributed to
 - * parent.
 - */
 -static void find_move_in_parent(struct scoreboard *sb,
 -                              struct blame_entry ***blamed,
 -                              struct blame_entry **toosmall,
 -                              struct origin *target,
 -                              struct origin *parent)
 -{
 -      struct blame_entry *e, split[3];
 -      struct blame_entry *unblamed = target->suspects;
 -      struct blame_entry *leftover = NULL;
 -      mmfile_t file_p;
 -
 -      if (!unblamed)
 -              return; /* nothing remains for this target */
 -
 -      fill_origin_blob(&sb->revs->diffopt, parent, &file_p);
 -      if (!file_p.ptr)
 -              return;
 +static unsigned blame_move_score;
 +static unsigned blame_copy_score;
  
 -      /* At each iteration, unblamed has a NULL-terminated list of
 -       * entries that have not yet been tested for blame.  leftover
 -       * contains the reversed list of entries that have been tested
 -       * without being assignable to the parent.
 -       */
 -      do {
 -              struct blame_entry **unblamedtail = &unblamed;
 -              struct blame_entry *next;
 -              for (e = unblamed; e; e = next) {
 -                      next = e->next;
 -                      find_copy_in_blob(sb, e, parent, split, &file_p);
 -                      if (split[1].suspect &&
 -                          blame_move_score < ent_score(sb, &split[1])) {
 -                              split_blame(blamed, &unblamedtail, split, e);
 -                      } else {
 -                              e->next = leftover;
 -                              leftover = e;
 -                      }
 -                      decref_split(split);
 -              }
 -              *unblamedtail = NULL;
 -              toosmall = filter_small(sb, toosmall, &unblamed, blame_move_score);
 -      } while (unblamed);
 -      target->suspects = reverse_blame(leftover, NULL);
 -}
 +/* Remember to update object flag allocation in object.h */
 +#define METAINFO_SHOWN                (1u<<12)
 +#define MORE_THAN_ONE_PATH    (1u<<13)
  
 -struct blame_list {
 -      struct blame_entry *ent;
 -      struct blame_entry split[3];
 +struct progress_info {
 +      struct progress *progress;
 +      int blamed_lines;
  };
  
 -/*
 - * Count the number of entries the target is suspected for,
 - * and prepare a list of entry and the best split.
 - */
 -static struct blame_list *setup_blame_list(struct blame_entry *unblamed,
 -                                         int *num_ents_p)
 -{
 -      struct blame_entry *e;
 -      int num_ents, i;
 -      struct blame_list *blame_list = NULL;
 -
 -      for (e = unblamed, num_ents = 0; e; e = e->next)
 -              num_ents++;
 -      if (num_ents) {
 -              blame_list = xcalloc(num_ents, sizeof(struct blame_list));
 -              for (e = unblamed, i = 0; e; e = e->next)
 -                      blame_list[i++].ent = e;
 -      }
 -      *num_ents_p = num_ents;
 -      return blame_list;
 -}
 -
 -/*
 - * For lines target is suspected for, see if we can find code movement
 - * across file boundary from the parent commit.  porigin is the path
 - * in the parent we already tried.
 - */
 -static void find_copy_in_parent(struct scoreboard *sb,
 -                              struct blame_entry ***blamed,
 -                              struct blame_entry **toosmall,
 -                              struct origin *target,
 -                              struct commit *parent,
 -                              struct origin *porigin,
 -                              int opt)
 -{
 -      struct diff_options diff_opts;
 -      int i, j;
 -      struct blame_list *blame_list;
 -      int num_ents;
 -      struct blame_entry *unblamed = target->suspects;
 -      struct blame_entry *leftover = NULL;
 -
 -      if (!unblamed)
 -              return; /* nothing remains for this target */
 -
 -      diff_setup(&diff_opts);
 -      DIFF_OPT_SET(&diff_opts, RECURSIVE);
 -      diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
 -
 -      diff_setup_done(&diff_opts);
 -
 -      /* Try "find copies harder" on new path if requested;
 -       * we do not want to use diffcore_rename() actually to
 -       * match things up; find_copies_harder is set only to
 -       * force diff_tree_sha1() to feed all filepairs to diff_queue,
 -       * and this code needs to be after diff_setup_done(), which
 -       * usually makes find-copies-harder imply copy detection.
 -       */
 -      if ((opt & PICKAXE_BLAME_COPY_HARDEST)
 -          || ((opt & PICKAXE_BLAME_COPY_HARDER)
 -              && (!porigin || strcmp(target->path, porigin->path))))
 -              DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
 -
 -      if (is_null_oid(&target->commit->object.oid))
 -              do_diff_cache(parent->tree->object.oid.hash, &diff_opts);
 -      else
 -              diff_tree_sha1(parent->tree->object.oid.hash,
 -                             target->commit->tree->object.oid.hash,
 -                             "", &diff_opts);
 -
 -      if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER))
 -              diffcore_std(&diff_opts);
 -
 -      do {
 -              struct blame_entry **unblamedtail = &unblamed;
 -              blame_list = setup_blame_list(unblamed, &num_ents);
 -
 -              for (i = 0; i < diff_queued_diff.nr; i++) {
 -                      struct diff_filepair *p = diff_queued_diff.queue[i];
 -                      struct origin *norigin;
 -                      mmfile_t file_p;
 -                      struct blame_entry this[3];
 -
 -                      if (!DIFF_FILE_VALID(p->one))
 -                              continue; /* does not exist in parent */
 -                      if (S_ISGITLINK(p->one->mode))
 -                              continue; /* ignore git links */
 -                      if (porigin && !strcmp(p->one->path, porigin->path))
 -                              /* find_move already dealt with this path */
 -                              continue;
 -
 -                      norigin = get_origin(sb, parent, p->one->path);
 -                      oidcpy(&norigin->blob_oid, &p->one->oid);
 -                      norigin->mode = p->one->mode;
 -                      fill_origin_blob(&sb->revs->diffopt, norigin, &file_p);
 -                      if (!file_p.ptr)
 -                              continue;
 -
 -                      for (j = 0; j < num_ents; j++) {
 -                              find_copy_in_blob(sb, blame_list[j].ent,
 -                                                norigin, this, &file_p);
 -                              copy_split_if_better(sb, blame_list[j].split,
 -                                                   this);
 -                              decref_split(this);
 -                      }
 -                      origin_decref(norigin);
 -              }
 -
 -              for (j = 0; j < num_ents; j++) {
 -                      struct blame_entry *split = blame_list[j].split;
 -                      if (split[1].suspect &&
 -                          blame_copy_score < ent_score(sb, &split[1])) {
 -                              split_blame(blamed, &unblamedtail, split,
 -                                          blame_list[j].ent);
 -                      } else {
 -                              blame_list[j].ent->next = leftover;
 -                              leftover = blame_list[j].ent;
 -                      }
 -                      decref_split(split);
 -              }
 -              free(blame_list);
 -              *unblamedtail = NULL;
 -              toosmall = filter_small(sb, toosmall, &unblamed, blame_copy_score);
 -      } while (unblamed);
 -      target->suspects = reverse_blame(leftover, NULL);
 -      diff_flush(&diff_opts);
 -      clear_pathspec(&diff_opts.pathspec);
 -}
 -
 -/*
 - * The blobs of origin and porigin exactly match, so everything
 - * origin is suspected for can be blamed on the parent.
 - */
 -static void pass_whole_blame(struct scoreboard *sb,
 -                           struct origin *origin, struct origin *porigin)
 -{
 -      struct blame_entry *e, *suspects;
 -
 -      if (!porigin->file.ptr && origin->file.ptr) {
 -              /* Steal its file */
 -              porigin->file = origin->file;
 -              origin->file.ptr = NULL;
 -      }
 -      suspects = origin->suspects;
 -      origin->suspects = NULL;
 -      for (e = suspects; e; e = e->next) {
 -              origin_incref(porigin);
 -              origin_decref(e->suspect);
 -              e->suspect = porigin;
 -      }
 -      queue_blames(sb, porigin, suspects);
 -}
 -
 -/*
 - * We pass blame from the current commit to its parents.  We keep saying
 - * "parent" (and "porigin"), but what we mean is to find scapegoat to
 - * exonerate ourselves.
 - */
 -static struct commit_list *first_scapegoat(struct rev_info *revs, struct commit *commit)
 -{
 -      if (!reverse) {
 -              if (revs->first_parent_only &&
 -                  commit->parents &&
 -                  commit->parents->next) {
 -                      free_commit_list(commit->parents->next);
 -                      commit->parents->next = NULL;
 -              }
 -              return commit->parents;
 -      }
 -      return lookup_decoration(&revs->children, &commit->object);
 -}
 -
 -static int num_scapegoats(struct rev_info *revs, struct commit *commit)
 -{
 -      struct commit_list *l = first_scapegoat(revs, commit);
 -      return commit_list_count(l);
 -}
 -
 -/* Distribute collected unsorted blames to the respected sorted lists
 - * in the various origins.
 - */
 -static void distribute_blame(struct scoreboard *sb, struct blame_entry *blamed)
 -{
 -      blamed = blame_sort(blamed, compare_blame_suspect);
 -      while (blamed)
 -      {
 -              struct origin *porigin = blamed->suspect;
 -              struct blame_entry *suspects = NULL;
 -              do {
 -                      struct blame_entry *next = blamed->next;
 -                      blamed->next = suspects;
 -                      suspects = blamed;
 -                      blamed = next;
 -              } while (blamed && blamed->suspect == porigin);
 -              suspects = reverse_blame(suspects, NULL);
 -              queue_blames(sb, porigin, suspects);
 -      }
 -}
 -
 -#define MAXSG 16
 -
 -static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
 +static const char *nth_line_cb(void *data, long lno)
  {
 -      struct rev_info *revs = sb->revs;
 -      int i, pass, num_sg;
 -      struct commit *commit = origin->commit;
 -      struct commit_list *sg;
 -      struct origin *sg_buf[MAXSG];
 -      struct origin *porigin, **sg_origin = sg_buf;
 -      struct blame_entry *toosmall = NULL;
 -      struct blame_entry *blames, **blametail = &blames;
 -
 -      num_sg = num_scapegoats(revs, commit);
 -      if (!num_sg)
 -              goto finish;
 -      else if (num_sg < ARRAY_SIZE(sg_buf))
 -              memset(sg_buf, 0, sizeof(sg_buf));
 -      else
 -              sg_origin = xcalloc(num_sg, sizeof(*sg_origin));
 -
 -      /*
 -       * The first pass looks for unrenamed path to optimize for
 -       * common cases, then we look for renames in the second pass.
 -       */
 -      for (pass = 0; pass < 2 - no_whole_file_rename; pass++) {
 -              struct origin *(*find)(struct scoreboard *,
 -                                     struct commit *, struct origin *);
 -              find = pass ? find_rename : find_origin;
 -
 -              for (i = 0, sg = first_scapegoat(revs, commit);
 -                   i < num_sg && sg;
 -                   sg = sg->next, i++) {
 -                      struct commit *p = sg->item;
 -                      int j, same;
 -
 -                      if (sg_origin[i])
 -                              continue;
 -                      if (parse_commit(p))
 -                              continue;
 -                      porigin = find(sb, p, origin);
 -                      if (!porigin)
 -                              continue;
 -                      if (!oidcmp(&porigin->blob_oid, &origin->blob_oid)) {
 -                              pass_whole_blame(sb, origin, porigin);
 -                              origin_decref(porigin);
 -                              goto finish;
 -                      }
 -                      for (j = same = 0; j < i; j++)
 -                              if (sg_origin[j] &&
 -                                  !oidcmp(&sg_origin[j]->blob_oid, &porigin->blob_oid)) {
 -                                      same = 1;
 -                                      break;
 -                              }
 -                      if (!same)
 -                              sg_origin[i] = porigin;
 -                      else
 -                              origin_decref(porigin);
 -              }
 -      }
 -
 -      num_commits++;
 -      for (i = 0, sg = first_scapegoat(revs, commit);
 -           i < num_sg && sg;
 -           sg = sg->next, i++) {
 -              struct origin *porigin = sg_origin[i];
 -              if (!porigin)
 -                      continue;
 -              if (!origin->previous) {
 -                      origin_incref(porigin);
 -                      origin->previous = porigin;
 -              }
 -              pass_blame_to_parent(sb, origin, porigin);
 -              if (!origin->suspects)
 -                      goto finish;
 -      }
 -
 -      /*
 -       * Optionally find moves in parents' files.
 -       */
 -      if (opt & PICKAXE_BLAME_MOVE) {
 -              filter_small(sb, &toosmall, &origin->suspects, blame_move_score);
 -              if (origin->suspects) {
 -                      for (i = 0, sg = first_scapegoat(revs, commit);
 -                           i < num_sg && sg;
 -                           sg = sg->next, i++) {
 -                              struct origin *porigin = sg_origin[i];
 -                              if (!porigin)
 -                                      continue;
 -                              find_move_in_parent(sb, &blametail, &toosmall, origin, porigin);
 -                              if (!origin->suspects)
 -                                      break;
 -                      }
 -              }
 -      }
 -
 -      /*
 -       * Optionally find copies from parents' files.
 -       */
 -      if (opt & PICKAXE_BLAME_COPY) {
 -              if (blame_copy_score > blame_move_score)
 -                      filter_small(sb, &toosmall, &origin->suspects, blame_copy_score);
 -              else if (blame_copy_score < blame_move_score) {
 -                      origin->suspects = blame_merge(origin->suspects, toosmall);
 -                      toosmall = NULL;
 -                      filter_small(sb, &toosmall, &origin->suspects, blame_copy_score);
 -              }
 -              if (!origin->suspects)
 -                      goto finish;
 -
 -              for (i = 0, sg = first_scapegoat(revs, commit);
 -                   i < num_sg && sg;
 -                   sg = sg->next, i++) {
 -                      struct origin *porigin = sg_origin[i];
 -                      find_copy_in_parent(sb, &blametail, &toosmall,
 -                                          origin, sg->item, porigin, opt);
 -                      if (!origin->suspects)
 -                              goto finish;
 -              }
 -      }
 -
 -finish:
 -      *blametail = NULL;
 -      distribute_blame(sb, blames);
 -      /*
 -       * prepend toosmall to origin->suspects
 -       *
 -       * There is no point in sorting: this ends up on a big
 -       * unsorted list in the caller anyway.
 -       */
 -      if (toosmall) {
 -              struct blame_entry **tail = &toosmall;
 -              while (*tail)
 -                      tail = &(*tail)->next;
 -              *tail = origin->suspects;
 -              origin->suspects = toosmall;
 -      }
 -      for (i = 0; i < num_sg; i++) {
 -              if (sg_origin[i]) {
 -                      drop_origin_blob(sg_origin[i]);
 -                      origin_decref(sg_origin[i]);
 -              }
 -      }
 -      drop_origin_blob(origin);
 -      if (sg_buf != sg_origin)
 -              free(sg_origin);
 +      return blame_nth_line((struct blame_scoreboard *)data, lno);
  }
  
  /*
  struct commit_info {
        struct strbuf author;
        struct strbuf author_mail;
 -      unsigned long author_time;
 +      timestamp_t author_time;
        struct strbuf author_tz;
  
        /* filled only when asked for details */
        struct strbuf committer;
        struct strbuf committer_mail;
 -      unsigned long committer_time;
 +      timestamp_t committer_time;
        struct strbuf committer_tz;
  
        struct strbuf summary;
   */
  static void get_ac_line(const char *inbuf, const char *what,
        struct strbuf *name, struct strbuf *mail,
 -      unsigned long *time, struct strbuf *tz)
 +      timestamp_t *time, struct strbuf *tz)
  {
        struct ident_split ident;
        size_t len, maillen, namelen;
@@@ -216,10 -1700,10 +217,10 @@@ static void get_commit_info(struct comm
   * To allow LF and other nonportable characters in pathnames,
   * they are c-style quoted as needed.
   */
 -static void write_filename_info(struct origin *suspect)
 +static void write_filename_info(struct blame_origin *suspect)
  {
        if (suspect->previous) {
 -              struct origin *prev = suspect->previous;
 +              struct blame_origin *prev = suspect->previous;
                printf("previous %s ", oid_to_hex(&prev->commit->object.oid));
                write_name_quoted(prev->path, stdout, '\n');
        }
   * the first time each commit appears in the output (unless the
   * user has specifically asked for us to repeat).
   */
 -static int emit_one_suspect_detail(struct origin *suspect, int repeat)
 +static int emit_one_suspect_detail(struct blame_origin *suspect, int repeat)
  {
        struct commit_info ci;
  
        get_commit_info(suspect->commit, &ci, 1);
        printf("author %s\n", ci.author.buf);
        printf("author-mail %s\n", ci.author_mail.buf);
 -      printf("author-time %lu\n", ci.author_time);
 +      printf("author-time %"PRItime"\n", ci.author_time);
        printf("author-tz %s\n", ci.author_tz.buf);
        printf("committer %s\n", ci.committer.buf);
        printf("committer-mail %s\n", ci.committer_mail.buf);
 -      printf("committer-time %lu\n", ci.committer_time);
 +      printf("committer-time %"PRItime"\n", ci.committer_time);
        printf("committer-tz %s\n", ci.committer_tz.buf);
        printf("summary %s\n", ci.summary.buf);
        if (suspect->commit->object.flags & UNINTERESTING)
   * The blame_entry is found to be guilty for the range.
   * Show it in incremental output.
   */
 -static void found_guilty_entry(struct blame_entry *ent,
 -                         struct progress_info *pi)
 +static void found_guilty_entry(struct blame_entry *ent, void *data)
  {
 +      struct progress_info *pi = (struct progress_info *)data;
 +
        if (incremental) {
 -              struct origin *suspect = ent->suspect;
 +              struct blame_origin *suspect = ent->suspect;
  
                printf("%s %d %d %d\n",
                       oid_to_hex(&suspect->commit->object.oid),
        display_progress(pi->progress, pi->blamed_lines);
  }
  
 -/*
 - * The main loop -- while we have blobs with lines whose true origin
 - * is still unknown, pick one blob, and allow its lines to pass blames
 - * to its parents. */
 -static void assign_blame(struct scoreboard *sb, int opt)
 -{
 -      struct rev_info *revs = sb->revs;
 -      struct commit *commit = prio_queue_get(&sb->commits);
 -      struct progress_info pi = { NULL, 0 };
 -
 -      if (show_progress)
 -              pi.progress = start_progress_delay(_("Blaming lines"),
 -                                                 sb->num_lines, 50, 1);
 -
 -      while (commit) {
 -              struct blame_entry *ent;
 -              struct origin *suspect = commit->util;
 -
 -              /* find one suspect to break down */
 -              while (suspect && !suspect->suspects)
 -                      suspect = suspect->next;
 -
 -              if (!suspect) {
 -                      commit = prio_queue_get(&sb->commits);
 -                      continue;
 -              }
 -
 -              assert(commit == suspect->commit);
 -
 -              /*
 -               * We will use this suspect later in the loop,
 -               * so hold onto it in the meantime.
 -               */
 -              origin_incref(suspect);
 -              parse_commit(commit);
 -              if (reverse ||
 -                  (!(commit->object.flags & UNINTERESTING) &&
 -                   !(revs->max_age != -1 && commit->date < revs->max_age)))
 -                      pass_blame(sb, suspect, opt);
 -              else {
 -                      commit->object.flags |= UNINTERESTING;
 -                      if (commit->object.parsed)
 -                              mark_parents_uninteresting(commit);
 -              }
 -              /* treat root commit as boundary */
 -              if (!commit->parents && !show_root)
 -                      commit->object.flags |= UNINTERESTING;
 -
 -              /* Take responsibility for the remaining entries */
 -              ent = suspect->suspects;
 -              if (ent) {
 -                      suspect->guilty = 1;
 -                      for (;;) {
 -                              struct blame_entry *next = ent->next;
 -                              found_guilty_entry(ent, &pi);
 -                              if (next) {
 -                                      ent = next;
 -                                      continue;
 -                              }
 -                              ent->next = sb->ent;
 -                              sb->ent = suspect->suspects;
 -                              suspect->suspects = NULL;
 -                              break;
 -                      }
 -              }
 -              origin_decref(suspect);
 -
 -              if (DEBUG) /* sanity */
 -                      sanity_check_refcnt(sb);
 -      }
 -
 -      stop_progress(&pi.progress);
 -}
 -
 -static const char *format_time(unsigned long time, const char *tz_str,
 +static const char *format_time(timestamp_t time, const char *tz_str,
                               int show_raw_time)
  {
        static struct strbuf time_buf = STRBUF_INIT;
  
        strbuf_reset(&time_buf);
        if (show_raw_time) {
 -              strbuf_addf(&time_buf, "%lu %s", time, tz_str);
 +              strbuf_addf(&time_buf, "%"PRItime" %s", time, tz_str);
        }
        else {
                const char *time_str;
  #define OUTPUT_SHOW_EMAIL     0400
  #define OUTPUT_LINE_PORCELAIN 01000
  
 -static void emit_porcelain_details(struct origin *suspect, int repeat)
 +static void emit_porcelain_details(struct blame_origin *suspect, int repeat)
  {
        if (emit_one_suspect_detail(suspect, repeat) ||
            (suspect->commit->object.flags & MORE_THAN_ONE_PATH))
                write_filename_info(suspect);
  }
  
 -static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent,
 +static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
                           int opt)
  {
        int repeat = opt & OUTPUT_LINE_PORCELAIN;
        int cnt;
        const char *cp;
 -      struct origin *suspect = ent->suspect;
 +      struct blame_origin *suspect = ent->suspect;
        char hex[GIT_MAX_HEXSZ + 1];
  
        oid_to_hex_r(hex, &suspect->commit->object.oid);
               ent->num_lines);
        emit_porcelain_details(suspect, repeat);
  
 -      cp = nth_line(sb, ent->lno);
 +      cp = blame_nth_line(sb, ent->lno);
        for (cnt = 0; cnt < ent->num_lines; cnt++) {
                char ch;
                if (cnt) {
                putchar('\n');
  }
  
 -static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
 +static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int opt)
  {
        int cnt;
        const char *cp;
 -      struct origin *suspect = ent->suspect;
 +      struct blame_origin *suspect = ent->suspect;
        struct commit_info ci;
        char hex[GIT_MAX_HEXSZ + 1];
        int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);
        get_commit_info(suspect->commit, &ci, 1);
        oid_to_hex_r(hex, &suspect->commit->object.oid);
  
 -      cp = nth_line(sb, ent->lno);
 +      cp = blame_nth_line(sb, ent->lno);
        for (cnt = 0; cnt < ent->num_lines; cnt++) {
                char ch;
                int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? GIT_SHA1_HEXSZ : abbrev;
        commit_info_destroy(&ci);
  }
  
 -static void output(struct scoreboard *sb, int option)
 +static void output(struct blame_scoreboard *sb, int option)
  {
        struct blame_entry *ent;
  
        if (option & OUTPUT_PORCELAIN) {
                for (ent = sb->ent; ent; ent = ent->next) {
                        int count = 0;
 -                      struct origin *suspect;
 +                      struct blame_origin *suspect;
                        struct commit *commit = ent->suspect->commit;
                        if (commit->object.flags & MORE_THAN_ONE_PATH)
                                continue;
        }
  }
  
 -static const char *get_next_line(const char *start, const char *end)
 -{
 -      const char *nl = memchr(start, '\n', end - start);
 -      return nl ? nl + 1 : end;
 -}
 -
 -/*
 - * To allow quick access to the contents of nth line in the
 - * final image, prepare an index in the scoreboard.
 - */
 -static int prepare_lines(struct scoreboard *sb)
 -{
 -      const char *buf = sb->final_buf;
 -      unsigned long len = sb->final_buf_size;
 -      const char *end = buf + len;
 -      const char *p;
 -      int *lineno;
 -      int num = 0;
 -
 -      for (p = buf; p < end; p = get_next_line(p, end))
 -              num++;
 -
 -      ALLOC_ARRAY(sb->lineno, num + 1);
 -      lineno = sb->lineno;
 -
 -      for (p = buf; p < end; p = get_next_line(p, end))
 -              *lineno++ = p - buf;
 -
 -      *lineno = len;
 -
 -      sb->num_lines = num;
 -      return sb->num_lines;
 -}
 -
  /*
   * Add phony grafts for use with -S; this is primarily to
   * support git's cvsserver that wants to give a linear history
   */
  static int read_ancestry(const char *graft_file)
  {
 -      FILE *fp = fopen(graft_file, "r");
 +      FILE *fp = fopen_or_warn(graft_file, "r");
        struct strbuf buf = STRBUF_INIT;
        if (!fp)
                return -1;
        return 0;
  }
  
 -static int update_auto_abbrev(int auto_abbrev, struct origin *suspect)
 +static int update_auto_abbrev(int auto_abbrev, struct blame_origin *suspect)
  {
        const char *uniq = find_unique_abbrev(suspect->commit->object.oid.hash,
                                              auto_abbrev);
   * How many columns do we need to show line numbers, authors,
   * and filenames?
   */
 -static void find_alignment(struct scoreboard *sb, int *option)
 +static void find_alignment(struct blame_scoreboard *sb, int *option)
  {
        int longest_src_lines = 0;
        int longest_dst_lines = 0;
        int auto_abbrev = DEFAULT_ABBREV;
  
        for (e = sb->ent; e; e = e->next) {
 -              struct origin *suspect = e->suspect;
 +              struct blame_origin *suspect = e->suspect;
                int num;
  
                if (compute_auto_abbrev)
                num = e->lno + e->num_lines;
                if (longest_dst_lines < num)
                        longest_dst_lines = num;
 -              if (largest_score < ent_score(sb, e))
 -                      largest_score = ent_score(sb, e);
 +              if (largest_score < blame_entry_score(sb, e))
 +                      largest_score = blame_entry_score(sb, e);
        }
        max_orig_digits = decimal_width(longest_src_lines);
        max_digits = decimal_width(longest_dst_lines);
                abbrev = auto_abbrev + 1;
  }
  
 -/*
 - * For debugging -- origin is refcounted, and this asserts that
 - * we do not underflow.
 - */
 -static void sanity_check_refcnt(struct scoreboard *sb)
 +static void sanity_check_on_fail(struct blame_scoreboard *sb, int baa)
  {
 -      int baa = 0;
 -      struct blame_entry *ent;
 -
 -      for (ent = sb->ent; ent; ent = ent->next) {
 -              /* Nobody should have zero or negative refcnt */
 -              if (ent->suspect->refcnt <= 0) {
 -                      fprintf(stderr, "%s in %s has negative refcnt %d\n",
 -                              ent->suspect->path,
 -                              oid_to_hex(&ent->suspect->commit->object.oid),
 -                              ent->suspect->refcnt);
 -                      baa = 1;
 -              }
 -      }
 -      if (baa) {
 -              int opt = 0160;
 -              find_alignment(sb, &opt);
 -              output(sb, opt);
 -              die("Baa %d!", baa);
 -      }
 +      int opt = OUTPUT_SHOW_SCORE | OUTPUT_SHOW_NUMBER | OUTPUT_SHOW_NAME;
 +      find_alignment(sb, &opt);
 +      output(sb, opt);
 +      die("Baa %d!", baa);
  }
  
  static unsigned parse_score(const char *arg)
@@@ -615,6 -2225,301 +616,6 @@@ static int git_blame_config(const char 
        return git_default_config(var, value, cb);
  }
  
 -static void verify_working_tree_path(struct commit *work_tree, const char *path)
 -{
 -      struct commit_list *parents;
 -      int pos;
 -
 -      for (parents = work_tree->parents; parents; parents = parents->next) {
 -              const struct object_id *commit_oid = &parents->item->object.oid;
 -              struct object_id blob_oid;
 -              unsigned mode;
 -
 -              if (!get_tree_entry(commit_oid->hash, path, blob_oid.hash, &mode) &&
 -                  sha1_object_info(blob_oid.hash, NULL) == OBJ_BLOB)
 -                      return;
 -      }
 -
 -      pos = cache_name_pos(path, strlen(path));
 -      if (pos >= 0)
 -              ; /* path is in the index */
 -      else if (-1 - pos < active_nr &&
 -               !strcmp(active_cache[-1 - pos]->name, path))
 -              ; /* path is in the index, unmerged */
 -      else
 -              die("no such path '%s' in HEAD", path);
 -}
 -
 -static struct commit_list **append_parent(struct commit_list **tail, const struct object_id *oid)
 -{
 -      struct commit *parent;
 -
 -      parent = lookup_commit_reference(oid->hash);
 -      if (!parent)
 -              die("no such commit %s", oid_to_hex(oid));
 -      return &commit_list_insert(parent, tail)->next;
 -}
 -
 -static void append_merge_parents(struct commit_list **tail)
 -{
 -      int merge_head;
 -      struct strbuf line = STRBUF_INIT;
 -
 -      merge_head = open(git_path_merge_head(), O_RDONLY);
 -      if (merge_head < 0) {
 -              if (errno == ENOENT)
 -                      return;
 -              die("cannot open '%s' for reading", git_path_merge_head());
 -      }
 -
 -      while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
 -              struct object_id oid;
 -              if (line.len < GIT_SHA1_HEXSZ || get_oid_hex(line.buf, &oid))
 -                      die("unknown line in '%s': %s", git_path_merge_head(), line.buf);
 -              tail = append_parent(tail, &oid);
 -      }
 -      close(merge_head);
 -      strbuf_release(&line);
 -}
 -
 -/*
 - * This isn't as simple as passing sb->buf and sb->len, because we
 - * want to transfer ownership of the buffer to the commit (so we
 - * must use detach).
 - */
 -static void set_commit_buffer_from_strbuf(struct commit *c, struct strbuf *sb)
 -{
 -      size_t len;
 -      void *buf = strbuf_detach(sb, &len);
 -      set_commit_buffer(c, buf, len);
 -}
 -
 -/*
 - * Prepare a dummy commit that represents the work tree (or staged) item.
 - * Note that annotating work tree item never works in the reverse.
 - */
 -static struct commit *fake_working_tree_commit(struct diff_options *opt,
 -                                             const char *path,
 -                                             const char *contents_from)
 -{
 -      struct commit *commit;
 -      struct origin *origin;
 -      struct commit_list **parent_tail, *parent;
 -      struct object_id head_oid;
 -      struct strbuf buf = STRBUF_INIT;
 -      const char *ident;
 -      time_t now;
 -      int size, len;
 -      struct cache_entry *ce;
 -      unsigned mode;
 -      struct strbuf msg = STRBUF_INIT;
 -
 -      read_cache();
 -      time(&now);
 -      commit = alloc_commit_node();
 -      commit->object.parsed = 1;
 -      commit->date = now;
 -      parent_tail = &commit->parents;
 -
 -      if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
 -              die("no such ref: HEAD");
 -
 -      parent_tail = append_parent(parent_tail, &head_oid);
 -      append_merge_parents(parent_tail);
 -      verify_working_tree_path(commit, path);
 -
 -      origin = make_origin(commit, path);
 -
 -      ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0);
 -      strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n");
 -      for (parent = commit->parents; parent; parent = parent->next)
 -              strbuf_addf(&msg, "parent %s\n",
 -                          oid_to_hex(&parent->item->object.oid));
 -      strbuf_addf(&msg,
 -                  "author %s\n"
 -                  "committer %s\n\n"
 -                  "Version of %s from %s\n",
 -                  ident, ident, path,
 -                  (!contents_from ? path :
 -                   (!strcmp(contents_from, "-") ? "standard input" : contents_from)));
 -      set_commit_buffer_from_strbuf(commit, &msg);
 -
 -      if (!contents_from || strcmp("-", contents_from)) {
 -              struct stat st;
 -              const char *read_from;
 -              char *buf_ptr;
 -              unsigned long buf_len;
 -
 -              if (contents_from) {
 -                      if (stat(contents_from, &st) < 0)
 -                              die_errno("Cannot stat '%s'", contents_from);
 -                      read_from = contents_from;
 -              }
 -              else {
 -                      if (lstat(path, &st) < 0)
 -                              die_errno("Cannot lstat '%s'", path);
 -                      read_from = path;
 -              }
 -              mode = canon_mode(st.st_mode);
 -
 -              switch (st.st_mode & S_IFMT) {
 -              case S_IFREG:
 -                      if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
 -                          textconv_object(read_from, mode, &null_oid, 0, &buf_ptr, &buf_len))
 -                              strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
 -                      else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
 -                              die_errno("cannot open or read '%s'", read_from);
 -                      break;
 -              case S_IFLNK:
 -                      if (strbuf_readlink(&buf, read_from, st.st_size) < 0)
 -                              die_errno("cannot readlink '%s'", read_from);
 -                      break;
 -              default:
 -                      die("unsupported file type %s", read_from);
 -              }
 -      }
 -      else {
 -              /* Reading from stdin */
 -              mode = 0;
 -              if (strbuf_read(&buf, 0, 0) < 0)
 -                      die_errno("failed to read from stdin");
 -      }
 -      convert_to_git(path, buf.buf, buf.len, &buf, 0);
 -      origin->file.ptr = buf.buf;
 -      origin->file.size = buf.len;
 -      pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_oid.hash);
 -
 -      /*
 -       * Read the current index, replace the path entry with
 -       * origin->blob_sha1 without mucking with its mode or type
 -       * bits; we are not going to write this index out -- we just
 -       * want to run "diff-index --cached".
 -       */
 -      discard_cache();
 -      read_cache();
 -
 -      len = strlen(path);
 -      if (!mode) {
 -              int pos = cache_name_pos(path, len);
 -              if (0 <= pos)
 -                      mode = active_cache[pos]->ce_mode;
 -              else
 -                      /* Let's not bother reading from HEAD tree */
 -                      mode = S_IFREG | 0644;
 -      }
 -      size = cache_entry_size(len);
 -      ce = xcalloc(1, size);
 -      oidcpy(&ce->oid, &origin->blob_oid);
 -      memcpy(ce->name, path, len);
 -      ce->ce_flags = create_ce_flags(0);
 -      ce->ce_namelen = len;
 -      ce->ce_mode = create_ce_mode(mode);
 -      add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
 -
 -      cache_tree_invalidate_path(&the_index, path);
 -
 -      return commit;
 -}
 -
 -static struct commit *find_single_final(struct rev_info *revs,
 -                                      const char **name_p)
 -{
 -      int i;
 -      struct commit *found = NULL;
 -      const char *name = NULL;
 -
 -      for (i = 0; i < revs->pending.nr; i++) {
 -              struct object *obj = revs->pending.objects[i].item;
 -              if (obj->flags & UNINTERESTING)
 -                      continue;
 -              obj = deref_tag(obj, NULL, 0);
 -              if (obj->type != OBJ_COMMIT)
 -                      die("Non commit %s?", revs->pending.objects[i].name);
 -              if (found)
 -                      die("More than one commit to dig from %s and %s?",
 -                          revs->pending.objects[i].name, name);
 -              found = (struct commit *)obj;
 -              name = revs->pending.objects[i].name;
 -      }
 -      if (name_p)
 -              *name_p = name;
 -      return found;
 -}
 -
 -static char *prepare_final(struct scoreboard *sb)
 -{
 -      const char *name;
 -      sb->final = find_single_final(sb->revs, &name);
 -      return xstrdup_or_null(name);
 -}
 -
 -static const char *dwim_reverse_initial(struct scoreboard *sb)
 -{
 -      /*
 -       * DWIM "git blame --reverse ONE -- PATH" as
 -       * "git blame --reverse ONE..HEAD -- PATH" but only do so
 -       * when it makes sense.
 -       */
 -      struct object *obj;
 -      struct commit *head_commit;
 -      unsigned char head_sha1[20];
 -
 -      if (sb->revs->pending.nr != 1)
 -              return NULL;
 -
 -      /* Is that sole rev a committish? */
 -      obj = sb->revs->pending.objects[0].item;
 -      obj = deref_tag(obj, NULL, 0);
 -      if (obj->type != OBJ_COMMIT)
 -              return NULL;
 -
 -      /* Do we have HEAD? */
 -      if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL))
 -              return NULL;
 -      head_commit = lookup_commit_reference_gently(head_sha1, 1);
 -      if (!head_commit)
 -              return NULL;
 -
 -      /* Turn "ONE" into "ONE..HEAD" then */
 -      obj->flags |= UNINTERESTING;
 -      add_pending_object(sb->revs, &head_commit->object, "HEAD");
 -
 -      sb->final = (struct commit *)obj;
 -      return sb->revs->pending.objects[0].name;
 -}
 -
 -static char *prepare_initial(struct scoreboard *sb)
 -{
 -      int i;
 -      const char *final_commit_name = NULL;
 -      struct rev_info *revs = sb->revs;
 -
 -      /*
 -       * There must be one and only one negative commit, and it must be
 -       * the boundary.
 -       */
 -      for (i = 0; i < revs->pending.nr; i++) {
 -              struct object *obj = revs->pending.objects[i].item;
 -              if (!(obj->flags & UNINTERESTING))
 -                      continue;
 -              obj = deref_tag(obj, NULL, 0);
 -              if (obj->type != OBJ_COMMIT)
 -                      die("Non commit %s?", revs->pending.objects[i].name);
 -              if (sb->final)
 -                      die("More than one commit to dig up from, %s and %s?",
 -                          revs->pending.objects[i].name,
 -                          final_commit_name);
 -              sb->final = (struct commit *) obj;
 -              final_commit_name = revs->pending.objects[i].name;
 -      }
 -
 -      if (!final_commit_name)
 -              final_commit_name = dwim_reverse_initial(sb);
 -      if (!final_commit_name)
 -              die("No commit to dig up from?");
 -      return xstrdup(final_commit_name);
 -}
 -
  static int blame_copy_callback(const struct option *option, const char *arg, int unset)
  {
        int *opt = option->value;
@@@ -652,11 -2557,13 +653,11 @@@ int cmd_blame(int argc, const char **ar
  {
        struct rev_info revs;
        const char *path;
 -      struct scoreboard sb;
 -      struct origin *o;
 +      struct blame_scoreboard sb;
 +      struct blame_origin *o;
        struct blame_entry *ent = NULL;
        long dashdash_pos, lno;
 -      char *final_commit_name = NULL;
 -      enum object_type type;
 -      struct commit *final_commit = NULL;
 +      struct progress_info pi = { NULL, 0 };
  
        struct string_list range_list = STRING_LIST_INIT_NODUP;
        int output_option = 0, opt = 0;
@@@ -782,15 -2689,12 +783,15 @@@ parse_done
                blame_date_width = sizeof("2006-10-19");
                break;
        case DATE_RELATIVE:
 -              /* TRANSLATORS: This string is used to tell us the maximum
 -                 display width for a relative timestamp in "git blame"
 -                 output.  For C locale, "4 years, 11 months ago", which
 -                 takes 22 places, is the longest among various forms of
 -                 relative timestamps, but your language may need more or
 -                 fewer display columns. */
 +              /*
 +               * TRANSLATORS: This string is used to tell us the
 +               * maximum display width for a relative timestamp in
 +               * "git blame" output.  For C locale, "4 years, 11
 +               * months ago", which takes 22 places, is the longest
 +               * among various forms of relative timestamps, but
 +               * your language may need more or fewer display
 +               * columns.
 +               */
                blame_date_width = utf8_strwidth(_("4 years, 11 months ago")) + 1; /* add the null */
                break;
        case DATE_NORMAL:
                opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE |
                        PICKAXE_BLAME_COPY_HARDER);
  
 -      if (!blame_move_score)
 -              blame_move_score = BLAME_DEFAULT_MOVE_SCORE;
 -      if (!blame_copy_score)
 -              blame_copy_score = BLAME_DEFAULT_COPY_SCORE;
 -
        /*
         * We have collected options unknown to us in argv[1..unk]
         * which are to be passed to revision machinery if we are
  
        revs.disable_stdin = 1;
        setup_revisions(argc, argv, &revs, NULL);
 -      memset(&sb, 0, sizeof(sb));
  
 +      init_scoreboard(&sb);
        sb.revs = &revs;
 -      if (!reverse) {
 -              final_commit_name = prepare_final(&sb);
 -              sb.commits.compare = compare_commits_by_commit_date;
 -      }
 -      else if (contents_from)
 -              die(_("--contents and --reverse do not blend well."));
 -      else {
 -              final_commit_name = prepare_initial(&sb);
 -              sb.commits.compare = compare_commits_by_reverse_commit_date;
 -              if (revs.first_parent_only)
 -                      revs.children.name = NULL;
 -      }
 -
 -      if (!sb.final) {
 -              /*
 -               * "--not A B -- path" without anything positive;
 -               * do not default to HEAD, but use the working tree
 -               * or "--contents".
 -               */
 -              setup_work_tree();
 -              sb.final = fake_working_tree_commit(&sb.revs->diffopt,
 -                                                  path, contents_from);
 -              add_pending_object(&revs, &(sb.final->object), ":");
 -      }
 -      else if (contents_from)
 -              die(_("cannot use --contents with final commit object name"));
 -
 -      if (reverse && revs.first_parent_only) {
 -              final_commit = find_single_final(sb.revs, NULL);
 -              if (!final_commit)
 -                      die(_("--reverse and --first-parent together require specified latest commit"));
 -      }
 -
 -      /*
 -       * If we have bottom, this will mark the ancestors of the
 -       * bottom commits we would reach while traversing as
 -       * uninteresting.
 -       */
 -      if (prepare_revision_walk(&revs))
 -              die(_("revision walk setup failed"));
 -
 -      if (reverse && revs.first_parent_only) {
 -              struct commit *c = final_commit;
 -
 -              sb.revs->children.name = "children";
 -              while (c->parents &&
 -                     oidcmp(&c->object.oid, &sb.final->object.oid)) {
 -                      struct commit_list *l = xcalloc(1, sizeof(*l));
 -
 -                      l->item = c;
 -                      if (add_decoration(&sb.revs->children,
 -                                         &c->parents->item->object, l))
 -                              die("BUG: not unique item in first-parent chain");
 -                      c = c->parents->item;
 -              }
 -
 -              if (oidcmp(&c->object.oid, &sb.final->object.oid))
 -                      die(_("--reverse --first-parent together require range along first-parent chain"));
 -      }
 -
 -      if (is_null_oid(&sb.final->object.oid)) {
 -              o = sb.final->util;
 -              sb.final_buf = xmemdupz(o->file.ptr, o->file.size);
 -              sb.final_buf_size = o->file.size;
 -      }
 -      else {
 -              o = get_origin(&sb, sb.final, path);
 -              if (fill_blob_sha1_and_mode(o))
 -                      die(_("no such path %s in %s"), path, final_commit_name);
 -
 -              if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) &&
 -                  textconv_object(path, o->mode, &o->blob_oid, 1, (char **) &sb.final_buf,
 -                                  &sb.final_buf_size))
 -                      ;
 -              else
 -                      sb.final_buf = read_sha1_file(o->blob_oid.hash, &type,
 -                                                    &sb.final_buf_size);
 -
 -              if (!sb.final_buf)
 -                      die(_("cannot read blob %s for path %s"),
 -                          oid_to_hex(&o->blob_oid),
 -                          path);
 -      }
 -      num_read_blob++;
 -      lno = prepare_lines(&sb);
 +      sb.contents_from = contents_from;
 +      sb.reverse = reverse;
 +      setup_scoreboard(&sb, path, &o);
 +      lno = sb.num_lines;
  
        if (lno && !range_list.nr)
                string_list_append(&range_list, "1");
  
        for (range_i = ranges.nr; range_i > 0; --range_i) {
                const struct range *r = &ranges.ranges[range_i - 1];
 -              long bottom = r->start;
 -              long top = r->end;
 -              struct blame_entry *next = ent;
 -              ent = xcalloc(1, sizeof(*ent));
 -              ent->lno = bottom;
 -              ent->num_lines = top - bottom;
 -              ent->suspect = o;
 -              ent->s_lno = bottom;
 -              ent->next = next;
 -              origin_incref(o);
 +              ent = blame_entry_prepend(ent, r->start, r->end, o);
        }
  
        o->suspects = ent;
        prio_queue_put(&sb.commits, o->commit);
  
 -      origin_decref(o);
 +      blame_origin_decref(o);
  
        range_set_release(&ranges);
        string_list_clear(&range_list, 0);
        sb.ent = NULL;
        sb.path = path;
  
 +      if (blame_move_score)
 +              sb.move_score = blame_move_score;
 +      if (blame_copy_score)
 +              sb.copy_score = blame_copy_score;
 +
 +      sb.debug = DEBUG;
 +      sb.on_sanity_fail = &sanity_check_on_fail;
 +
 +      sb.show_root = show_root;
 +      sb.xdl_opts = xdl_opts;
 +      sb.no_whole_file_rename = no_whole_file_rename;
 +
        read_mailmap(&mailmap, NULL);
  
 +      sb.found_guilty_entry = &found_guilty_entry;
 +      sb.found_guilty_entry_data = &pi;
 +      if (show_progress)
 +              pi.progress = start_progress_delay(_("Blaming lines"),
 +                                                 sb.num_lines, 50, 1);
 +
        assign_blame(&sb, opt);
  
 +      stop_progress(&pi.progress);
 +
        if (!incremental)
                setup_pager();
 -
 -      free(final_commit_name);
 -
 -      if (incremental)
 +      else
                return 0;
  
 -      sb.ent = blame_sort(sb.ent, compare_blame_final);
 +      blame_sort_final(&sb);
  
 -      coalesce(&sb);
 +      blame_coalesce(&sb);
  
        if (!(output_option & OUTPUT_PORCELAIN))
                find_alignment(&sb, &output_option);
        }
  
        if (show_stats) {
 -              printf("num read blob: %d\n", num_read_blob);
 -              printf("num get patch: %d\n", num_get_patch);
 -              printf("num commits: %d\n", num_commits);
 +              printf("num read blob: %d\n", sb.num_read_blob);
 +              printf("num get patch: %d\n", sb.num_get_patch);
 +              printf("num commits: %d\n", sb.num_commits);
        }
        return 0;
  }
diff --combined builtin/branch.c
index 83fcda43dceec0255c6164eb42a35d3d89011efb,50b59238d4d3683f955321c0f58c5947a82aca6b..c958e93257910816bd8d40673805e8553f921f3f
@@@ -6,6 -6,7 +6,7 @@@
   */
  
  #include "cache.h"
+ #include "config.h"
  #include "color.h"
  #include "refs.h"
  #include "commit.h"
@@@ -124,7 -125,7 +125,7 @@@ static int branch_merged(int kind, cons
                    (reference_name = reference_name_to_free =
                     resolve_refdup(upstream, RESOLVE_REF_READING,
                                    oid.hash, NULL)) != NULL)
 -                      reference_rev = lookup_commit_reference(oid.hash);
 +                      reference_rev = lookup_commit_reference(&oid);
        }
        if (!reference_rev)
                reference_rev = head_rev;
@@@ -157,7 -158,7 +158,7 @@@ static int check_branch_commit(const ch
                               const struct object_id *oid, struct commit *head_rev,
                               int kinds, int force)
  {
 -      struct commit *rev = lookup_commit_reference(oid->hash);
 +      struct commit *rev = lookup_commit_reference(oid);
        if (!rev) {
                error(_("Couldn't look up commit object for '%s'"), refname);
                return -1;
@@@ -211,7 -212,7 +212,7 @@@ static int delete_branches(int argc, co
        }
  
        if (!force) {
 -              head_rev = lookup_commit_reference(head_oid.hash);
 +              head_rev = lookup_commit_reference(&head_oid);
                if (!head_rev)
                        die(_("Couldn't look up commit object for HEAD"));
        }
diff --combined builtin/cat-file.c
index 4bffd7a2d8eee2ea251afef70f63f646f184a339,12451205cf8929c25c57f6a2d7f7a1a0a5f11fa4..7efbc4019ac59a16ae4f147889e6f489dac1e661
@@@ -4,8 -4,8 +4,9 @@@
   * Copyright (C) Linus Torvalds, 2005
   */
  #include "cache.h"
+ #include "config.h"
  #include "builtin.h"
 +#include "diff.h"
  #include "parse-options.h"
  #include "userdiff.h"
  #include "streaming.h"
@@@ -62,8 -62,7 +63,8 @@@ static int cat_one_file(int opt, const 
        if (unknown_type)
                flags |= LOOKUP_UNKNOWN_OBJECT;
  
 -      if (get_sha1_with_context(obj_name, 0, oid.hash, &obj_context))
 +      if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH,
 +                                oid.hash, &obj_context))
                die("Not a valid object name %s", obj_name);
  
        if (!path)
                die("git cat-file %s: bad file", obj_name);
  
        write_or_die(1, buf, size);
 +      free(buf);
 +      free(obj_context.path);
        return 0;
  }
  
diff --combined builtin/check-ignore.c
index c7b8c08897193e225d8da32f4d402def3f16fe50,a2da09f4aec3bd68e26587250763648c1efb181b..3e280b9c7aa9c93c8e7572a4fe3f7ef3ac92b3af
@@@ -1,10 -1,10 +1,11 @@@
  #include "builtin.h"
  #include "cache.h"
+ #include "config.h"
  #include "dir.h"
  #include "quote.h"
  #include "pathspec.h"
  #include "parse-options.h"
 +#include "submodule.h"
  
  static int quiet, verbose, stdin_paths, show_non_matching, no_index;
  static const char * const check_ignore_usage[] = {
@@@ -88,23 -88,21 +89,23 @@@ static int check_ignore(struct dir_stru
        parse_pathspec(&pathspec,
                       PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,
                       PATHSPEC_SYMLINK_LEADING_PATH |
 -                     PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE |
                       PATHSPEC_KEEP_ORDER,
                       prefix, argv);
  
 +      die_path_inside_submodule(&the_index, &pathspec);
 +
        /*
         * look for pathspecs matching entries in the index, since these
         * should not be ignored, in order to be consistent with
         * 'git status', 'git add' etc.
         */
 -      seen = find_pathspecs_matching_against_index(&pathspec);
 +      seen = find_pathspecs_matching_against_index(&pathspec, &the_index);
        for (i = 0; i < pathspec.nr; i++) {
                full_path = pathspec.items[i].match;
                exclude = NULL;
                if (!seen[i]) {
 -                      exclude = last_exclude_matching(dir, full_path, &dtype);
 +                      exclude = last_exclude_matching(dir, &the_index,
 +                                                      full_path, &dtype);
                }
                if (!quiet && (exclude || show_non_matching))
                        output_exclude(pathspec.items[i].original, exclude);
diff --combined builtin/checkout.c
index 1624eed7e7625c18da7ffb58f1b9ae456c3dbd77,e0b58ddc0b6c7dcfc05b7576eaf2eec77e31616f..9661e1bcba31ffa4f7b8a2fb1a9d2060cb8efda7
@@@ -1,4 -1,5 +1,5 @@@
  #include "builtin.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "parse-options.h"
  #include "refs.h"
  #include "submodule-config.h"
  #include "submodule.h"
  
 -static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 -
  static const char * const checkout_usage[] = {
        N_("git checkout [<options>] <branch>"),
        N_("git checkout [<options>] [<branch>] -- <file>..."),
        NULL,
  };
  
 -static int option_parse_recurse_submodules(const struct option *opt,
 -                                         const char *arg, int unset)
 -{
 -      if (unset) {
 -              recurse_submodules = RECURSE_SUBMODULES_OFF;
 -              return 0;
 -      }
 -      if (arg)
 -              recurse_submodules =
 -                      parse_update_recurse_submodules_arg(opt->long_name,
 -                                                          arg);
 -      else
 -              recurse_submodules = RECURSE_SUBMODULES_ON;
 -
 -      return 0;
 -}
 -
  struct checkout_opts {
        int patch_mode;
        int quiet;
@@@ -216,24 -236,22 +217,24 @@@ static int checkout_merged(int pos, con
        /*
         * NEEDSWORK:
         * There is absolutely no reason to write this as a blob object
 -       * and create a phony cache entry just to leak.  This hack is
 -       * primarily to get to the write_entry() machinery that massages
 -       * the contents to work-tree format and writes out which only
 -       * allows it for a cache entry.  The code in write_entry() needs
 -       * to be refactored to allow us to feed a <buffer, size, mode>
 -       * instead of a cache entry.  Such a refactoring would help
 -       * merge_recursive as well (it also writes the merge result to the
 -       * object database even when it may contain conflicts).
 +       * and create a phony cache entry.  This hack is primarily to get
 +       * to the write_entry() machinery that massages the contents to
 +       * work-tree format and writes out which only allows it for a
 +       * cache entry.  The code in write_entry() needs to be refactored
 +       * to allow us to feed a <buffer, size, mode> instead of a cache
 +       * entry.  Such a refactoring would help merge_recursive as well
 +       * (it also writes the merge result to the object database even
 +       * when it may contain conflicts).
         */
        if (write_sha1_file(result_buf.ptr, result_buf.size,
                            blob_type, oid.hash))
                die(_("Unable to add merge result for '%s'"), path);
 +      free(result_buf.ptr);
        ce = make_cache_entry(mode, oid.hash, path, 2, 0);
        if (!ce)
                die(_("make_cache_entry failed for path '%s'"), path);
        status = checkout_entry(ce, state, NULL);
 +      free(ce);
        return status;
  }
  
@@@ -376,7 -394,7 +377,7 @@@ static int checkout_paths(const struct 
                die(_("unable to write new index file"));
  
        read_ref_full("HEAD", 0, rev.hash, NULL);
 -      head = lookup_commit_reference_gently(rev.hash, 1);
 +      head = lookup_commit_reference_gently(&rev, 1);
  
        errs |= post_checkout_hook(head, head, 0);
        return errs;
@@@ -510,10 -528,10 +511,10 @@@ static int merge_working_tree(const str
                        setup_standard_excludes(topts.dir);
                }
                tree = parse_tree_indirect(old->commit ?
 -                                         old->commit->object.oid.hash :
 -                                         EMPTY_TREE_SHA1_BIN);
 +                                         &old->commit->object.oid :
 +                                         &empty_tree_oid);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
 -              tree = parse_tree_indirect(new->commit->object.oid.hash);
 +              tree = parse_tree_indirect(&new->commit->object.oid);
                init_tree_desc(&trees[1], tree->buffer, tree->size);
  
                ret = unpack_trees(2, trees, &topts);
@@@ -704,7 -722,7 +705,7 @@@ static int add_pending_uninteresting_re
                                         const struct object_id *oid,
                                         int flags, void *cb_data)
  {
 -      add_pending_sha1(cb_data, refname, oid->hash, UNINTERESTING);
 +      add_pending_oid(cb_data, refname, oid, UNINTERESTING);
        return 0;
  }
  
@@@ -790,7 -808,7 +791,7 @@@ static void orphaned_commit_warning(str
        add_pending_object(&revs, object, oid_to_hex(&object->oid));
  
        for_each_ref(add_pending_uninteresting_ref, &revs);
 -      add_pending_sha1(&revs, "HEAD", new->object.oid.hash, UNINTERESTING);
 +      add_pending_oid(&revs, "HEAD", &new->object.oid, UNINTERESTING);
  
        refs = revs.pending;
        revs.leak_pending = 1;
@@@ -816,8 -834,7 +817,8 @@@ static int switch_branches(const struc
        int flag, writeout_error = 0;
        memset(&old, 0, sizeof(old));
        old.path = path_to_free = resolve_refdup("HEAD", 0, rev.hash, &flag);
 -      old.commit = lookup_commit_reference_gently(rev.hash, 1);
 +      if (old.path)
 +              old.commit = lookup_commit_reference_gently(&rev, 1);
        if (!(flag & REF_ISSYMREF))
                old.path = NULL;
  
@@@ -857,7 -874,7 +858,7 @@@ static int git_checkout_config(const ch
        }
  
        if (starts_with(var, "submodule."))
 -              return parse_submodule_config_option(var, value);
 +              return submodule_config(var, value, NULL);
  
        return git_xmerge_config(var, value, NULL);
  }
@@@ -1031,10 -1048,10 +1032,10 @@@ static int parse_branchname_arg(int arg
        else
                new->path = NULL; /* not an existing branch */
  
 -      new->commit = lookup_commit_reference_gently(rev->hash, 1);
 +      new->commit = lookup_commit_reference_gently(rev, 1);
        if (!new->commit) {
                /* not a commit */
 -              *source_tree = parse_tree_indirect(rev->hash);
 +              *source_tree = parse_tree_indirect(rev);
        } else {
                parse_commit_or_die(new->commit);
                *source_tree = new->commit->tree;
@@@ -1165,9 -1182,9 +1166,9 @@@ int cmd_checkout(int argc, const char *
                                N_("second guess 'git checkout <no-such-branch>'")),
                OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
                         N_("do not check if another worktree is holding the given ref")),
 -              { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules,
 +              { OPTION_CALLBACK, 0, "recurse-submodules", NULL,
                            "checkout", "control recursive updating of submodules",
 -                          PARSE_OPT_OPTARG, option_parse_recurse_submodules },
 +                          PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },
                OPT_BOOL(0, "progress", &opts.show_progress, N_("force progress reporting")),
                OPT_END(),
        };
                git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
        }
  
 -      if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
 -              git_config(submodule_config, NULL);
 -              if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT)
 -                      set_config_update_recurse_submodules(recurse_submodules);
 -      }
 -
        if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)
                die(_("-b, -B and --orphan are mutually exclusive"));
  
                 * new_branch && argc > 1 will be caught later.
                 */
                if (opts.new_branch && argc == 1)
 -                      die(_("Cannot update paths and switch to branch '%s' at the same time.\n"
 -                            "Did you intend to checkout '%s' which can not be resolved as commit?"),
 -                          opts.new_branch, argv[0]);
 +                      die(_("'%s' is not a commit and a branch '%s' cannot be created from it"),
 +                              argv[0], opts.new_branch);
  
                if (opts.force_detach)
                        die(_("git checkout: --detach does not take a path argument '%s'"),
diff --combined builtin/clean.c
index 142bf668cffe814006fae791f1bdc6b20fe6f366,57093db8be9953c37bd480bdb237cd08871ac535..ed954134d2dd03242a06eef88bcaec71cc41ffe9
@@@ -8,6 -8,7 +8,7 @@@
  
  #include "builtin.h"
  #include "cache.h"
+ #include "config.h"
  #include "dir.h"
  #include "parse-options.h"
  #include "string-list.h"
@@@ -683,7 -684,7 +684,7 @@@ static int filter_by_patterns_cmd(void
                for_each_string_list_item(item, &del_list) {
                        int dtype = DT_UNKNOWN;
  
 -                      if (is_excluded(&dir, item->string, &dtype)) {
 +                      if (is_excluded(&dir, &the_index, item->string, &dtype)) {
                                *item->string = '\0';
                                changed++;
                        }
@@@ -857,38 -858,6 +858,38 @@@ static void interactive_main_loop(void
        }
  }
  
 +static void correct_untracked_entries(struct dir_struct *dir)
 +{
 +      int src, dst, ign;
 +
 +      for (src = dst = ign = 0; src < dir->nr; src++) {
 +              /* skip paths in ignored[] that cannot be inside entries[src] */
 +              while (ign < dir->ignored_nr &&
 +                     0 <= cmp_dir_entry(&dir->entries[src], &dir->ignored[ign]))
 +                      ign++;
 +
 +              if (ign < dir->ignored_nr &&
 +                  check_dir_entry_contains(dir->entries[src], dir->ignored[ign])) {
 +                      /* entries[src] contains an ignored path, so we drop it */
 +                      free(dir->entries[src]);
 +              } else {
 +                      struct dir_entry *ent = dir->entries[src++];
 +
 +                      /* entries[src] does not contain an ignored path, so we keep it */
 +                      dir->entries[dst++] = ent;
 +
 +                      /* then discard paths in entries[] contained inside entries[src] */
 +                      while (src < dir->nr &&
 +                             check_dir_entry_contains(ent, dir->entries[src]))
 +                              free(dir->entries[src++]);
 +
 +                      /* compensate for the outer loop's loop control */
 +                      src--;
 +              }
 +      }
 +      dir->nr = dst;
 +}
 +
  int cmd_clean(int argc, const char **argv, const char *prefix)
  {
        int i, res;
  
        dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
  
 +      if (remove_directories)
 +              dir.flags |= DIR_SHOW_IGNORED_TOO | DIR_KEEP_UNTRACKED_CONTENTS;
 +
        if (read_cache() < 0)
                die(_("index file corrupt"));
  
                       PATHSPEC_PREFER_CWD,
                       prefix, argv);
  
 -      fill_directory(&dir, &pathspec);
 +      fill_directory(&dir, &the_index, &pathspec);
 +      correct_untracked_entries(&dir);
  
        for (i = 0; i < dir.nr; i++) {
                struct dir_entry *ent = dir.entries[i];
                string_list_append(&del_list, rel);
        }
  
 +      for (i = 0; i < dir.nr; i++)
 +              free(dir.entries[i]);
 +
 +      for (i = 0; i < dir.ignored_nr; i++)
 +              free(dir.ignored[i]);
 +
        if (interactive && del_list.nr > 0)
                interactive_main_loop();
  
diff --combined builtin/clone.c
index a2ea019c590190a00d1a7cf51a917c7ebdc7886c,eaacac221b193b2243416a320e1125c63881b310..08b5cc433c6fcad5eea2dfc3321aea28a599d51f
@@@ -9,6 -9,7 +9,7 @@@
   */
  
  #include "builtin.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "parse-options.h"
  #include "fetch-pack.h"
@@@ -40,7 -41,6 +41,7 @@@ static const char * const builtin_clone
  
  static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
  static int option_local = -1, option_no_hardlinks, option_shared;
 +static int option_no_tags;
  static int option_shallow_submodules;
  static int deepen;
  static char *option_template, *option_depth, *option_since;
@@@ -121,8 -121,6 +122,8 @@@ static struct option builtin_clone_opti
                        N_("deepen history of shallow clone, excluding rev")),
        OPT_BOOL(0, "single-branch", &option_single_branch,
                    N_("clone only one branch, HEAD or --branch")),
 +      OPT_BOOL(0, "no-tags", &option_no_tags,
 +               N_("don't clone any tags, and make later fetches not to follow them")),
        OPT_BOOL(0, "shallow-submodules", &option_shallow_submodules,
                    N_("any cloned submodules will be shallow")),
        OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
@@@ -360,7 -358,7 +361,7 @@@ static void copy_alternates(struct strb
         * to turn entries with paths relative to the original
         * absolute, so that they can be used in the new repository.
         */
 -      FILE *in = fopen(src->buf, "r");
 +      FILE *in = xfopen(src->buf, "r");
        struct strbuf line = STRBUF_INIT;
  
        while (strbuf_getline(&line, in) != EOF) {
@@@ -566,7 -564,7 +567,7 @@@ static struct ref *wanted_peer_refs(con
        } else
                get_fetch_map(refs, refspec, &tail, 0);
  
 -      if (!option_mirror && !option_single_branch)
 +      if (!option_mirror && !option_single_branch && !option_no_tags)
                get_fetch_map(refs, tag_refspec, &tail, 0);
  
        return local_refs;
@@@ -655,7 -653,7 +656,7 @@@ static void update_remote_refs(const st
  
        if (refs) {
                write_remote_refs(mapped_refs);
 -              if (option_single_branch)
 +              if (option_single_branch && !option_no_tags)
                        write_followtags(refs, msg);
        }
  
@@@ -685,7 -683,7 +686,7 @@@ static void update_head(const struct re
                        install_branch_config(0, head, option_origin, our->name);
                }
        } else if (our) {
 -              struct commit *c = lookup_commit_reference(our->old_oid.hash);
 +              struct commit *c = lookup_commit_reference(&our->old_oid);
                /* --branch specifies a non-branch (i.e. tags), detach HEAD */
                update_ref(msg, "HEAD", c->object.oid.hash,
                           NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
@@@ -742,7 -740,7 +743,7 @@@ static int checkout(int submodule_progr
        opts.src_index = &the_index;
        opts.dst_index = &the_index;
  
 -      tree = parse_tree_indirect(oid.hash);
 +      tree = parse_tree_indirect(&oid);
        parse_tree(tree);
        init_tree_desc(&t, tree->buffer, tree->size);
        if (unpack_trees(1, &t, &opts) < 0)
  
  static int write_one_config(const char *key, const char *value, void *data)
  {
 -      return git_config_set_multivar_gently(key, value ? value : "true", "^$", 0);
 +      return git_config_set_multivar_gently(key,
 +                                            value ? value : "true",
 +                                            CONFIG_REGEX_NONE, 0);
  }
  
  static void write_config(struct string_list *config)
@@@ -1040,12 -1036,6 +1041,12 @@@ int cmd_clone(int argc, const char **ar
        git_config_set(key.buf, repo);
        strbuf_reset(&key);
  
 +      if (option_no_tags) {
 +              strbuf_addf(&key, "remote.%s.tagOpt", option_origin);
 +              git_config_set(key.buf, "--no-tags");
 +              strbuf_reset(&key);
 +      }
 +
        if (option_required_reference.nr || option_optional_reference.nr)
                setup_reference();
  
diff --combined builtin/commit-tree.c
index f39c2b27375fcd70f050e56174b0966053652eef,e1c17ba64b0346a35778dac48a66203418c119aa..a4a923d7c0b688e162c8e4d0411ff9b72748fb5c
@@@ -4,6 -4,7 +4,7 @@@
   * Copyright (C) Linus Torvalds, 2005
   */
  #include "cache.h"
+ #include "config.h"
  #include "commit.h"
  #include "tree.h"
  #include "builtin.h"
@@@ -58,7 -59,7 +59,7 @@@ int cmd_commit_tree(int argc, const cha
                        if (get_sha1_commit(argv[i], oid.hash))
                                die("Not a valid object name %s", argv[i]);
                        assert_sha1_type(oid.hash, OBJ_COMMIT);
 -                      new_parent(lookup_commit(oid.hash), &parents);
 +                      new_parent(lookup_commit(&oid), &parents);
                        continue;
                }
  
diff --combined builtin/commit.c
index 5968970b6519a8ed1a8b80ff6341a3ad1e6f542e,929a45abed7067c80ca05662124fe962cd0f61bf..021070e693e78fe49a168f842f64aeea73de4a8b
@@@ -6,6 -6,7 +6,7 @@@
   */
  
  #include "cache.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "cache-tree.h"
  #include "color.h"
@@@ -253,8 -254,7 +254,8 @@@ static int list_paths(struct string_lis
  
        if (with_tree) {
                char *max_prefix = common_prefix(pattern);
 -              overlay_tree_on_cache(with_tree, max_prefix ? max_prefix : prefix);
 +              overlay_tree_on_index(&the_index, with_tree,
 +                                    max_prefix ? max_prefix : prefix);
                free(max_prefix);
        }
  
@@@ -314,7 -314,7 +315,7 @@@ static void create_base_index(const str
        opts.dst_index = &the_index;
  
        opts.fn = oneway_merge;
 -      tree = parse_tree_indirect(current_head->object.oid.hash);
 +      tree = parse_tree_indirect(&current_head->object.oid);
        if (!tree)
                die(_("failed to unpack HEAD tree object"));
        parse_tree(tree);
@@@ -1264,10 -1264,6 +1265,10 @@@ static int parse_status_slot(const cha
                return WT_STATUS_NOBRANCH;
        if (!strcasecmp(slot, "unmerged"))
                return WT_STATUS_UNMERGED;
 +      if (!strcasecmp(slot, "localBranch"))
 +              return WT_STATUS_LOCAL_BRANCH;
 +      if (!strcasecmp(slot, "remoteBranch"))
 +              return WT_STATUS_REMOTE_BRANCH;
        return -1;
  }
  
@@@ -1435,7 -1431,7 +1436,7 @@@ static void print_summary(const char *p
        struct strbuf author_ident = STRBUF_INIT;
        struct strbuf committer_ident = STRBUF_INIT;
  
 -      commit = lookup_commit(oid->hash);
 +      commit = lookup_commit(oid);
        if (!commit)
                die(_("couldn't look up newly created commit"));
        if (parse_commit(commit))
@@@ -1659,7 -1655,7 +1660,7 @@@ int cmd_commit(int argc, const char **a
        if (get_sha1("HEAD", oid.hash))
                current_head = NULL;
        else {
 -              current_head = lookup_commit_or_die(oid.hash, "HEAD");
 +              current_head = lookup_commit_or_die(&oid, "HEAD");
                if (parse_commit(current_head))
                        die(_("could not parse HEAD commit"));
        }
                if (!reflog_msg)
                        reflog_msg = "commit (merge)";
                pptr = commit_list_append(current_head, pptr);
 -              fp = fopen(git_path_merge_head(), "r");
 -              if (fp == NULL)
 -                      die_errno(_("could not open '%s' for reading"),
 -                                git_path_merge_head());
 +              fp = xfopen(git_path_merge_head(), "r");
                while (strbuf_getline_lf(&m, fp) != EOF) {
                        struct commit *parent;
  
  
        if (verbose || /* Truncate the message just before the diff, if any. */
            cleanup_mode == CLEANUP_SCISSORS)
 -              wt_status_truncate_message_at_cut_line(&sb);
 +              strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
  
        if (cleanup_mode != CLEANUP_NONE)
                strbuf_stripspace(&sb, cleanup_mode == CLEANUP_ALL);
                append_merge_tag_headers(parents, &tail);
        }
  
 -      if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->sha1,
 +      if (commit_tree_extended(sb.buf, sb.len, active_cache_tree->oid.hash,
                         parents, oid.hash, author_ident.buf, sign_commit, extra)) {
                rollback_index_files();
                die(_("failed to write commit object"));
                cfg = init_copy_notes_for_rewrite("amend");
                if (cfg) {
                        /* we are amending, so current_head is not NULL */
 -                      copy_note_for_rewrite(cfg, current_head->object.oid.hash, oid.hash);
 +                      copy_note_for_rewrite(cfg, &current_head->object.oid, &oid);
                        finish_copy_notes_for_rewrite(cfg, "Notes added by 'git commit --amend'");
                }
                run_rewrite_hook(&current_head->object.oid, &oid);
diff --combined builtin/config.c
index 7f6c25d4d95b37f7785e0b6872d059095548c87f,1fc6471f37a061318ea16442a15c378c49648188..82db29fae71551a44150c64a4c1187ef4ebd572a
@@@ -1,5 -1,6 +1,6 @@@
  #include "builtin.h"
  #include "cache.h"
+ #include "config.h"
  #include "color.h"
  #include "parse-options.h"
  #include "urlmatch.h"
@@@ -242,8 -243,8 +243,8 @@@ static int get_value(const char *key_, 
                }
        }
  
-       git_config_with_options(collect_config, &values,
-                               &given_config_source, &config_options);
+       config_with_options(collect_config, &values,
+                           &given_config_source, &config_options);
  
        ret = !values.nr;
  
@@@ -320,8 -321,8 +321,8 @@@ static void get_color(const char *var, 
        get_color_slot = var;
        get_color_found = 0;
        parsed_color[0] = '\0';
-       git_config_with_options(git_get_color_config, NULL,
-                               &given_config_source, &config_options);
+       config_with_options(git_get_color_config, NULL,
+                           &given_config_source, &config_options);
  
        if (!get_color_found && def_color) {
                if (color_parse(def_color, parsed_color) < 0)
@@@ -352,8 -353,8 +353,8 @@@ static int get_colorbool(const char *va
        get_colorbool_found = -1;
        get_diff_color_found = -1;
        get_color_ui_found = -1;
-       git_config_with_options(git_get_colorbool_config, NULL,
-                               &given_config_source, &config_options);
+       config_with_options(git_get_colorbool_config, NULL,
+                           &given_config_source, &config_options);
  
        if (get_colorbool_found < 0) {
                if (!strcmp(get_colorbool_slot, "color.diff"))
@@@ -441,8 -442,8 +442,8 @@@ static int get_urlmatch(const char *var
                show_keys = 1;
        }
  
-       git_config_with_options(urlmatch_config_entry, &config,
-                               &given_config_source, &config_options);
+       config_with_options(urlmatch_config_entry, &config,
+                           &given_config_source, &config_options);
  
        ret = !values.nr;
  
@@@ -496,9 -497,6 +497,9 @@@ int cmd_config(int argc, const char **a
                usage_with_options(builtin_config_usage, builtin_config_options);
        }
  
 +      if (use_local_config && nongit)
 +              die(_("--local can only be used inside a git repository"));
 +
        if (given_config_source.file &&
                        !strcmp(given_config_source.file, "-")) {
                given_config_source.file = NULL;
                config_options.respect_includes = !given_config_source.file;
        else
                config_options.respect_includes = respect_includes_opt;
+       if (!nongit) {
+               config_options.commondir = get_git_common_dir();
+               config_options.git_dir = get_git_dir();
+       }
  
        if (end_null) {
                term = '\0';
  
        if (actions == ACTION_LIST) {
                check_argc(argc, 0, 0);
-               if (git_config_with_options(show_all_config, NULL,
-                                           &given_config_source,
-                                           &config_options) < 0) {
+               if (config_with_options(show_all_config, NULL,
+                                       &given_config_source,
+                                       &config_options) < 0) {
                        if (given_config_source.file)
                                die_errno("unable to read config file '%s'",
                                          given_config_source.file);
diff --combined builtin/describe.c
index 893c8789f4f563c58041040740384322e6ea205b,3eddfd37061ebe5a347cc65a829a2edf65883a80..70eb1446089583cd859ea1f05b260283cd78067f
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "commit.h"
  #include "tag.h"
@@@ -79,13 -80,13 +80,13 @@@ static int replace_name(struct commit_n
                struct tag *t;
  
                if (!e->tag) {
 -                      t = lookup_tag(e->oid.hash);
 +                      t = lookup_tag(&e->oid);
                        if (!t || parse_tag(t))
                                return 1;
                        e->tag = t;
                }
  
 -              t = lookup_tag(oid->hash);
 +              t = lookup_tag(oid);
                if (!t || parse_tag(t))
                        return 0;
                *tag = t;
@@@ -245,7 -246,7 +246,7 @@@ static unsigned long finish_depth_compu
  static void display_name(struct commit_name *n)
  {
        if (n->prio == 2 && !n->tag) {
 -              n->tag = lookup_tag(n->oid.hash);
 +              n->tag = lookup_tag(&n->oid);
                if (!n->tag || parse_tag(n->tag))
                        die(_("annotated tag %s not available"), n->path);
        }
@@@ -281,7 -282,7 +282,7 @@@ static void describe(const char *arg, i
  
        if (get_oid(arg, &oid))
                die(_("Not a valid object name %s"), arg);
 -      cmit = lookup_commit_reference(oid.hash);
 +      cmit = lookup_commit_reference(&oid);
        if (!cmit)
                die(_("%s is not a valid '%s' object"), arg, commit_type);
  
                struct commit *c;
                struct commit_name *n = hashmap_iter_first(&names, &iter);
                for (; n; n = hashmap_iter_next(&iter)) {
 -                      c = lookup_commit_reference_gently(n->peeled.hash, 1);
 +                      c = lookup_commit_reference_gently(&n->peeled, 1);
                        if (c)
                                c->util = n;
                }
diff --combined builtin/diff-files.c
index c97069a714e42a1737b5dfa223fe39c26ad9aa67,29d3e4f416746eda53c9d599d4adf92966ffff09..17bf84d18f802d3f223e7408fee644b94878b35f
@@@ -4,6 -4,7 +4,7 @@@
   * Copyright (C) Linus Torvalds, 2005
   */
  #include "cache.h"
+ #include "config.h"
  #include "diff.h"
  #include "commit.h"
  #include "revision.h"
@@@ -20,12 -21,9 +21,12 @@@ int cmd_diff_files(int argc, const cha
        int result;
        unsigned options = 0;
  
 +      if (argc == 2 && !strcmp(argv[1], "-h"))
 +              usage(diff_files_usage);
 +
 +      git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        init_revisions(&rev, prefix);
        gitmodules_config();
 -      git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        rev.abbrev = 0;
        precompose_argv(argc, argv);
  
diff --combined builtin/diff-index.c
index d59bf6cf5f8da394251532765f27a044c14a572d,e3d418361c7db8b4206019898d4373f31169652f..185e6f9b582fdcf15072038b570463a0cfb1bbf2
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "diff.h"
  #include "commit.h"
  #include "revision.h"
@@@ -17,12 -18,9 +18,12 @@@ int cmd_diff_index(int argc, const cha
        int i;
        int result;
  
 +      if (argc == 2 && !strcmp(argv[1], "-h"))
 +              usage(diff_cache_usage);
 +
 +      git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        init_revisions(&rev, prefix);
        gitmodules_config();
 -      git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        rev.abbrev = 0;
        precompose_argv(argc, argv);
  
diff --combined builtin/diff-tree.c
index 7e15d01f36396fdc6b630eb43a5f36d462fb78e6,c81063d534f87a0d6d6ee768fab2253144674279..31d2cb410738d335d9f6431d6901ea1c0f8b67ff
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "diff.h"
  #include "commit.h"
  #include "log-tree.h"
@@@ -7,9 -8,9 +8,9 @@@
  
  static struct rev_info log_tree_opt;
  
 -static int diff_tree_commit_sha1(const struct object_id *oid)
 +static int diff_tree_commit_oid(const struct object_id *oid)
  {
 -      struct commit *commit = lookup_commit_reference(oid->hash);
 +      struct commit *commit = lookup_commit_reference(oid);
        if (!commit)
                return -1;
        return log_tree_commit(&log_tree_opt, commit);
@@@ -23,7 -24,7 +24,7 @@@ static int stdin_diff_commit(struct com
  
        /* Graft the fake parents locally to the commit */
        while (isspace(*p++) && !parse_oid_hex(p, &oid, &p)) {
 -              struct commit *parent = lookup_commit(oid.hash);
 +              struct commit *parent = lookup_commit(&oid);
                if (!pptr) {
                        /* Free the real parent list */
                        free_commit_list(commit->parents);
@@@ -44,13 -45,13 +45,13 @@@ static int stdin_diff_trees(struct tre
        struct tree *tree2;
        if (!isspace(*p++) || parse_oid_hex(p, &oid, &p) || *p)
                return error("Need exactly two trees, separated by a space");
 -      tree2 = lookup_tree(oid.hash);
 +      tree2 = lookup_tree(&oid);
        if (!tree2 || parse_tree(tree2))
                return -1;
        printf("%s %s\n", oid_to_hex(&tree1->object.oid),
                          oid_to_hex(&tree2->object.oid));
 -      diff_tree_sha1(tree1->object.oid.hash, tree2->object.oid.hash,
 -                     "", &log_tree_opt.diffopt);
 +      diff_tree_oid(&tree1->object.oid, &tree2->object.oid,
 +                    "", &log_tree_opt.diffopt);
        log_tree_diff_flush(&log_tree_opt);
        return 0;
  }
@@@ -67,7 -68,7 +68,7 @@@ static int diff_tree_stdin(char *line
        line[len-1] = 0;
        if (parse_oid_hex(line, &oid, &p))
                return -1;
 -      obj = parse_object(oid.hash);
 +      obj = parse_object(&oid);
        if (!obj)
                return -1;
        if (obj->type == OBJ_COMMIT)
@@@ -98,18 -99,16 +99,18 @@@ static void diff_tree_tweak_rev(struct 
  
  int cmd_diff_tree(int argc, const char **argv, const char *prefix)
  {
 -      int nr_sha1;
        char line[1000];
        struct object *tree1, *tree2;
        static struct rev_info *opt = &log_tree_opt;
        struct setup_revision_opt s_r_opt;
        int read_stdin = 0;
  
 +      if (argc == 2 && !strcmp(argv[1], "-h"))
 +              usage(diff_tree_usage);
 +
 +      git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        init_revisions(opt, prefix);
        gitmodules_config();
 -      git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        opt->abbrev = 0;
        opt->diff = 1;
        opt->disable_stdin = 1;
        }
  
        /*
 -       * NOTE! We expect "a ^b" to be equal to "a..b", so we
 -       * reverse the order of the objects if the second one
 -       * is marked UNINTERESTING.
 +       * NOTE!  We expect "a..b" to expand to "^a b" but it is
 +       * perfectly valid for revision range parser to yield "b ^a",
 +       * which means the same thing. If we get the latter, i.e. the
 +       * second one is marked UNINTERESTING, we recover the original
 +       * order the user gave, i.e. "a..b", by swapping the trees.
         */
 -      nr_sha1 = opt->pending.nr;
 -      switch (nr_sha1) {
 +      switch (opt->pending.nr) {
        case 0:
                if (!read_stdin)
                        usage(diff_tree_usage);
                break;
        case 1:
                tree1 = opt->pending.objects[0].item;
 -              diff_tree_commit_sha1(&tree1->oid);
 +              diff_tree_commit_oid(&tree1->oid);
                break;
        case 2:
                tree1 = opt->pending.objects[0].item;
                if (tree2->flags & UNINTERESTING) {
                        SWAP(tree2, tree1);
                }
 -              diff_tree_sha1(tree1->oid.hash,
 -                             tree2->oid.hash,
 -                             "", &opt->diffopt);
 +              diff_tree_oid(&tree1->oid, &tree2->oid, "", &opt->diffopt);
                log_tree_diff_flush(opt);
                break;
        }
diff --combined builtin/diff.c
index d9152c21bf5a8aa41778f838b4d804ac698bdc2b,1ce40c63b23cdec6f0f9c22bbce351acdf3effed..7cde6abbcf7651af8313bd3d70eb1944e72c9cb3
@@@ -4,6 -4,7 +4,7 @@@
   * Copyright (c) 2006 Junio C Hamano
   */
  #include "cache.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "color.h"
  #include "commit.h"
  #define DIFF_NO_INDEX_EXPLICIT 1
  #define DIFF_NO_INDEX_IMPLICIT 2
  
 -struct blobinfo {
 -      struct object_id oid;
 -      const char *name;
 -      unsigned mode;
 -};
 -
  static const char builtin_diff_usage[] =
  "git diff [<options>] [<commit> [<commit>]] [--] [<path>...]";
  
 +static const char *blob_path(struct object_array_entry *entry)
 +{
 +      return entry->path ? entry->path : entry->name;
 +}
 +
  static void stuff_change(struct diff_options *opt,
                         unsigned old_mode, unsigned new_mode,
                         const struct object_id *old_oid,
                         const struct object_id *new_oid,
                         int old_oid_valid,
                         int new_oid_valid,
 -                       const char *old_name,
 -                       const char *new_name)
 +                       const char *old_path,
 +                       const char *new_path)
  {
        struct diff_filespec *one, *two;
  
        if (DIFF_OPT_TST(opt, REVERSE_DIFF)) {
                SWAP(old_mode, new_mode);
                SWAP(old_oid, new_oid);
 -              SWAP(old_name, new_name);
 +              SWAP(old_path, new_path);
        }
  
        if (opt->prefix &&
 -          (strncmp(old_name, opt->prefix, opt->prefix_length) ||
 -           strncmp(new_name, opt->prefix, opt->prefix_length)))
 +          (strncmp(old_path, opt->prefix, opt->prefix_length) ||
 +           strncmp(new_path, opt->prefix, opt->prefix_length)))
                return;
  
 -      one = alloc_filespec(old_name);
 -      two = alloc_filespec(new_name);
 -      fill_filespec(one, old_oid->hash, old_oid_valid, old_mode);
 -      fill_filespec(two, new_oid->hash, new_oid_valid, new_mode);
 +      one = alloc_filespec(old_path);
 +      two = alloc_filespec(new_path);
 +      fill_filespec(one, old_oid, old_oid_valid, old_mode);
 +      fill_filespec(two, new_oid, new_oid_valid, new_mode);
  
        diff_queue(&diff_queued_diff, one, two);
  }
  
  static int builtin_diff_b_f(struct rev_info *revs,
                            int argc, const char **argv,
 -                          struct blobinfo *blob)
 +                          struct object_array_entry **blob)
  {
        /* Blob vs file in the working tree*/
        struct stat st;
  
        diff_set_mnemonic_prefix(&revs->diffopt, "o/", "w/");
  
 -      if (blob[0].mode == S_IFINVALID)
 -              blob[0].mode = canon_mode(st.st_mode);
 +      if (blob[0]->mode == S_IFINVALID)
 +              blob[0]->mode = canon_mode(st.st_mode);
  
        stuff_change(&revs->diffopt,
 -                   blob[0].mode, canon_mode(st.st_mode),
 -                   &blob[0].oid, &null_oid,
 +                   blob[0]->mode, canon_mode(st.st_mode),
 +                   &blob[0]->item->oid, &null_oid,
                     1, 0,
 -                   path, path);
 +                   blob[0]->path ? blob[0]->path : path,
 +                   path);
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
        return 0;
  
  static int builtin_diff_blobs(struct rev_info *revs,
                              int argc, const char **argv,
 -                            struct blobinfo *blob)
 +                            struct object_array_entry **blob)
  {
        unsigned mode = canon_mode(S_IFREG | 0644);
  
        if (argc > 1)
                usage(builtin_diff_usage);
  
 -      if (blob[0].mode == S_IFINVALID)
 -              blob[0].mode = mode;
 +      if (blob[0]->mode == S_IFINVALID)
 +              blob[0]->mode = mode;
  
 -      if (blob[1].mode == S_IFINVALID)
 -              blob[1].mode = mode;
 +      if (blob[1]->mode == S_IFINVALID)
 +              blob[1]->mode = mode;
  
        stuff_change(&revs->diffopt,
 -                   blob[0].mode, blob[1].mode,
 -                   &blob[0].oid, &blob[1].oid,
 +                   blob[0]->mode, blob[1]->mode,
 +                   &blob[0]->item->oid, &blob[1]->item->oid,
                     1, 1,
 -                   blob[0].name, blob[1].name);
 +                   blob_path(blob[0]), blob_path(blob[1]));
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
        return 0;
@@@ -174,7 -175,7 +175,7 @@@ static int builtin_diff_tree(struct rev
                swap = 1;
        oid[swap] = &ent0->item->oid;
        oid[1 - swap] = &ent1->item->oid;
 -      diff_tree_sha1(oid[0]->hash, oid[1]->hash, "", &revs->diffopt);
 +      diff_tree_oid(oid[0], oid[1], "", &revs->diffopt);
        log_tree_diff_flush(revs);
        return 0;
  }
@@@ -194,7 -195,7 +195,7 @@@ static int builtin_diff_combined(struc
                revs->dense_combined_merges = revs->combine_merges = 1;
        for (i = 1; i < ents; i++)
                oid_array_append(&parents, &ent[i].item->oid);
 -      diff_tree_combined(ent[0].item->oid.hash, &parents,
 +      diff_tree_combined(&ent[0].item->oid, &parents,
                           revs->dense_combined_merges, revs);
        oid_array_clear(&parents);
        return 0;
@@@ -259,7 -260,7 +260,7 @@@ int cmd_diff(int argc, const char **arg
        struct rev_info rev;
        struct object_array ent = OBJECT_ARRAY_INIT;
        int blobs = 0, paths = 0;
 -      struct blobinfo blob[2];
 +      struct object_array_entry *blob[2];
        int nongit = 0, no_index = 0;
        int result = 0;
  
                                add_head_to_pending(&rev);
                                if (!rev.pending.nr) {
                                        struct tree *tree;
 -                                      tree = lookup_tree(EMPTY_TREE_SHA1_BIN);
 +                                      tree = lookup_tree(&empty_tree_oid);
                                        add_pending_object(&rev, &tree->object, "HEAD");
                                }
                                break;
                const char *name = entry->name;
                int flags = (obj->flags & UNINTERESTING);
                if (!obj->parsed)
 -                      obj = parse_object(obj->oid.hash);
 +                      obj = parse_object(&obj->oid);
                obj = deref_tag(obj, NULL, 0);
                if (!obj)
                        die(_("invalid object '%s' given."), name);
                } else if (obj->type == OBJ_BLOB) {
                        if (2 <= blobs)
                                die(_("more than two blobs given: '%s'"), name);
 -                      hashcpy(blob[blobs].oid.hash, obj->oid.hash);
 -                      blob[blobs].name = name;
 -                      blob[blobs].mode = entry->mode;
 +                      blob[blobs] = entry;
                        blobs++;
  
                } else {
diff --combined builtin/difftool.c
index b9a892f2693efe01a08c958f7064f13ba6ec43aa,538b0187faf8738b7056ba4999a2082232bf0ee1..9199227f6e9dc0b6d0c3e350f701aeaf9caaddd3
@@@ -12,6 -12,7 +12,7 @@@
   * Copyright (C) 2016 Johannes Schindelin
   */
  #include "cache.h"
+ #include "config.h"
  #include "builtin.h"
  #include "run-command.h"
  #include "exec_cmd.h"
@@@ -226,7 -227,6 +227,7 @@@ static void changed_files(struct hashma
                hashmap_entry_init(entry, strhash(buf.buf));
                hashmap_add(result, entry);
        }
 +      fclose(fp);
        if (finish_command(&diff_files))
                die("diff-files did not exit properly");
        strbuf_release(&index_env);
@@@ -440,10 -440,8 +441,10 @@@ static int run_dir_diff(const char *ext
                }
  
                if (lmode && status != 'C') {
 -                      if (checkout_path(lmode, &loid, src_path, &lstate))
 -                              return error("could not write '%s'", src_path);
 +                      if (checkout_path(lmode, &loid, src_path, &lstate)) {
 +                              ret = error("could not write '%s'", src_path);
 +                              goto finish;
 +                      }
                }
  
                if (rmode && !S_ISLNK(rmode)) {
                        hashmap_add(&working_tree_dups, entry);
  
                        if (!use_wt_file(workdir, dst_path, &roid)) {
 -                              if (checkout_path(rmode, &roid, dst_path, &rstate))
 -                                      return error("could not write '%s'",
 -                                                   dst_path);
 +                              if (checkout_path(rmode, &roid, dst_path,
 +                                                &rstate)) {
 +                                      ret = error("could not write '%s'",
 +                                                  dst_path);
 +                                      goto finish;
 +                              }
                        } else if (!is_null_oid(&roid)) {
                                /*
                                 * Changes in the working tree need special
                                                ADD_CACHE_JUST_APPEND);
  
                                add_path(&rdir, rdir_len, dst_path);
 -                              if (ensure_leading_directories(rdir.buf))
 -                                      return error("could not create "
 -                                                   "directory for '%s'",
 -                                                   dst_path);
 +                              if (ensure_leading_directories(rdir.buf)) {
 +                                      ret = error("could not create "
 +                                                  "directory for '%s'",
 +                                                  dst_path);
 +                                      goto finish;
 +                              }
                                add_path(&wtdir, wtdir_len, dst_path);
                                if (symlinks) {
                                        if (symlink(wtdir.buf, rdir.buf)) {
                }
        }
  
 +      fclose(fp);
 +      fp = NULL;
        if (finish_command(&child)) {
                ret = error("error occurred running diff --raw");
                goto finish;
        }
  
        if (!i)
 -              return 0;
 +              goto finish;
  
        /*
         * Changes to submodules require special treatment.This loop writes a
                exit_cleanup(tmpdir, rc);
  
  finish:
 +      if (fp)
 +              fclose(fp);
 +
        free(lbase_dir);
        free(rbase_dir);
        strbuf_release(&ldir);
diff --combined builtin/fast-export.c
index a932be04f4d5f733eebe1ebeba82c1bc64de3088,e4304e2dd6550d434138c9e2b9261f66645146c5..12d501bfde3aac09c411169f99ff28ad35593a3b
@@@ -5,6 -5,7 +5,7 @@@
   */
  #include "builtin.h"
  #include "cache.h"
+ #include "config.h"
  #include "refs.h"
  #include "commit.h"
  #include "object.h"
@@@ -232,7 -233,7 +233,7 @@@ static void export_blob(const struct ob
  
        if (anonymize) {
                buf = anonymize_blob(&size);
 -              object = (struct object *)lookup_blob(oid->hash);
 +              object = (struct object *)lookup_blob(oid);
                eaten = 0;
        } else {
                buf = read_sha1_file(oid->hash, &type, &size);
                        die ("Could not read blob %s", oid_to_hex(oid));
                if (check_sha1_signature(oid->hash, buf, size, typename(type)) < 0)
                        die("sha1 mismatch in blob %s", oid_to_hex(oid));
 -              object = parse_object_buffer(oid->hash, type, size, buf, &eaten);
 +              object = parse_object_buffer(oid, type, size, buf, &eaten);
        }
  
        if (!object)
@@@ -562,12 -563,12 +563,12 @@@ static void handle_commit(struct commi
            get_object_mark(&commit->parents->item->object) != 0 &&
            !full_tree) {
                parse_commit_or_die(commit->parents->item);
 -              diff_tree_sha1(commit->parents->item->tree->object.oid.hash,
 -                             commit->tree->object.oid.hash, "", &rev->diffopt);
 +              diff_tree_oid(&commit->parents->item->tree->object.oid,
 +                            &commit->tree->object.oid, "", &rev->diffopt);
        }
        else
 -              diff_root_tree_sha1(commit->tree->object.oid.hash,
 -                                  "", &rev->diffopt);
 +              diff_root_tree_oid(&commit->tree->object.oid,
 +                                 "", &rev->diffopt);
  
        /* Export the referenced blobs, and remember the marks. */
        for (i = 0; i < diff_queued_diff.nr; i++)
@@@ -734,7 -735,6 +735,7 @@@ static void handle_tag(const char *name
                             oid_to_hex(&tag->object.oid));
                case DROP:
                        /* Ignore this tag altogether */
 +                      free(buf);
                        return;
                case REWRITE:
                        if (tagged->type != OBJ_COMMIT) {
               (int)(tagger_end - tagger), tagger,
               tagger == tagger_end ? "" : "\n",
               (int)message_size, (int)message_size, message ? message : "");
 +      free(buf);
  }
  
  static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
  
                /* handle nested tags */
                while (tag && tag->object.type == OBJ_TAG) {
 -                      parse_object(tag->object.oid.hash);
 +                      parse_object(&tag->object.oid);
                        string_list_append(&extra_refs, full_name)->util = tag;
                        tag = (struct tag *)tag->tagged;
                }
@@@ -907,7 -906,9 +908,7 @@@ static void export_marks(char *file
  static void import_marks(char *input_file)
  {
        char line[512];
 -      FILE *f = fopen(input_file, "r");
 -      if (!f)
 -              die_errno("cannot read '%s'", input_file);
 +      FILE *f = xfopen(input_file, "r");
  
        while (fgets(line, sizeof(line), f)) {
                uint32_t mark;
                        /* only commits */
                        continue;
  
 -              commit = lookup_commit(oid.hash);
 +              commit = lookup_commit(&oid);
                if (!commit)
                        die("not a commit? can't happen: %s", oid_to_hex(&oid));
  
diff --combined builtin/fetch.c
index 100248c5afe3e1c16fa7fe79696200aeb5d1bde2,1fe8f6238557d932b02fb2f5dabf85eb863450b1..16cf8421ce4cc2221e6ed59110928328693481fb
@@@ -2,6 -2,7 +2,7 @@@
   * "git fetch"
   */
  #include "cache.h"
+ #include "config.h"
  #include "refs.h"
  #include "commit.h"
  #include "builtin.h"
@@@ -73,13 -74,6 +74,13 @@@ static int git_fetch_config(const char 
                fetch_prune_config = git_config_bool(k, v);
                return 0;
        }
 +
 +      if (!strcmp(k, "submodule.recurse")) {
 +              int r = git_config_bool(k, v) ?
 +                      RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
 +              recurse_submodules = r;
 +      }
 +
        return git_default_config(k, v, cb);
  }
  
@@@ -643,8 -637,8 +644,8 @@@ static int update_local_ref(struct ref 
                return r;
        }
  
 -      current = lookup_commit_reference_gently(ref->old_oid.hash, 1);
 -      updated = lookup_commit_reference_gently(ref->new_oid.hash, 1);
 +      current = lookup_commit_reference_gently(&ref->old_oid, 1);
 +      updated = lookup_commit_reference_gently(&ref->new_oid, 1);
        if (!current || !updated) {
                const char *msg;
                const char *what;
@@@ -777,8 -771,7 +778,8 @@@ static int store_updated_refs(const cha
                                continue;
                        }
  
 -                      commit = lookup_commit_reference_gently(rm->old_oid.hash, 1);
 +                      commit = lookup_commit_reference_gently(&rm->old_oid,
 +                                                              1);
                        if (!commit)
                                rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
  
@@@ -948,7 -941,7 +949,7 @@@ static int prune_refs(struct refspec *r
                for (ref = stale_refs; ref; ref = ref->next)
                        string_list_append(&refnames, ref->name);
  
 -              result = delete_refs(&refnames, 0);
 +              result = delete_refs("fetch: prune", &refnames, 0);
                string_list_clear(&refnames, 0);
        }
  
diff --combined builtin/fmt-merge-msg.c
index 70137b0b7e56e6319872fddc3527fe1094009dee,2e30b514f2d19c6a87ad6f0ebcde7a27a54f0be5..10cbb434163f2f6e60e0cc9cb55bab220004a549
@@@ -1,5 -1,6 +1,6 @@@
  #include "builtin.h"
  #include "cache.h"
+ #include "config.h"
  #include "refs.h"
  #include "commit.h"
  #include "diff.h"
@@@ -341,7 -342,7 +342,7 @@@ static void shortlog(const char *name
        const struct object_id *oid = &origin_data->oid;
        int limit = opts->shortlog_len;
  
 -      branch = deref_tag(parse_object(oid->hash), oid_to_hex(oid), GIT_SHA1_HEXSZ);
 +      branch = deref_tag(parse_object(oid), oid_to_hex(oid), GIT_SHA1_HEXSZ);
        if (!branch || branch->type != OBJ_COMMIT)
                return;
  
@@@ -559,14 -560,14 +560,14 @@@ static void find_merge_parents(struct m
                 * "name" here and we do not want to contaminate its
                 * util field yet.
                 */
 -              obj = parse_object(oid.hash);
 +              obj = parse_object(&oid);
                parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT);
                if (!parent)
                        continue;
                commit_list_insert(parent, &parents);
                add_merge_parent(result, &obj->oid, &parent->object.oid);
        }
 -      head_commit = lookup_commit(head->hash);
 +      head_commit = lookup_commit(head);
        if (head_commit)
                commit_list_insert(head_commit, &parents);
        parents = reduce_heads(parents);
@@@ -633,7 -634,7 +634,7 @@@ int fmt_merge_msg(struct strbuf *in, st
                struct commit *head;
                struct rev_info rev;
  
 -              head = lookup_commit_or_die(head_oid.hash, "HEAD");
 +              head = lookup_commit_or_die(&head_oid, "HEAD");
                init_revisions(&rev, NULL);
                rev.commit_format = CMIT_FMT_ONELINE;
                rev.ignore_merges = 1;
diff --combined builtin/fsck.c
index 3a2c27f2413e5e377926e0e7df339549c37a76b3,0c63f6259f4912cdaca446c1097164455cc5f70f..87c675689986413f4c2ace09701adccf6e836942
@@@ -1,5 -1,6 +1,6 @@@
  #include "builtin.h"
  #include "cache.h"
+ #include "config.h"
  #include "commit.h"
  #include "tree.h"
  #include "blob.h"
@@@ -280,7 -281,8 +281,7 @@@ static void check_unreachable_object(st
                                free(filename);
                                return;
                        }
 -                      if (!(f = fopen(filename, "w")))
 -                              die_errno("Could not open '%s'", filename);
 +                      f = xfopen(filename, "w");
                        if (obj->type == OBJ_BLOB) {
                                if (stream_blob_to_fd(fileno(f), &obj->oid, NULL, 1))
                                        die_errno("Could not write '%s'", filename);
@@@ -376,7 -378,7 +377,7 @@@ static int fsck_obj(struct object *obj
        return 0;
  }
  
 -static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,
 +static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
                           unsigned long size, void *buffer, int *eaten)
  {
        /*
         * verify_packfile(), data_valid variable for details.
         */
        struct object *obj;
 -      obj = parse_object_buffer(sha1, type, size, buffer, eaten);
 +      obj = parse_object_buffer(oid, type, size, buffer, eaten);
        if (!obj) {
                errors_found |= ERROR_OBJECT;
 -              return error("%s: object corrupt or missing", sha1_to_hex(sha1));
 +              return error("%s: object corrupt or missing", oid_to_hex(oid));
        }
        obj->flags = HAS_OBJ;
        return fsck_obj(obj);
  static int default_refs;
  
  static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
 -      unsigned long timestamp)
 +      timestamp_t timestamp)
  {
        struct object *obj;
  
                        if (timestamp && name_objects)
                                add_decoration(fsck_walk_options.object_names,
                                        obj,
 -                                      xstrfmt("%s@{%ld}", refname, timestamp));
 +                                      xstrfmt("%s@{%"PRItime"}", refname, timestamp));
                        obj->used = 1;
                        mark_object_reachable(obj);
                } else {
  }
  
  static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid,
 -              const char *email, unsigned long timestamp, int tz,
 +              const char *email, timestamp_t timestamp, int tz,
                const char *message, void *cb_data)
  {
        const char *refname = cb_data;
@@@ -443,7 -445,7 +444,7 @@@ static int fsck_handle_ref(const char *
  {
        struct object *obj;
  
 -      obj = parse_object(oid->hash);
 +      obj = parse_object(oid);
        if (!obj) {
                error("%s: invalid sha1 pointer %s", refname, oid_to_hex(oid));
                errors_found |= ERROR_REACHABLE;
@@@ -505,7 -507,7 +506,7 @@@ static struct object *parse_loose_objec
        if (!contents && type != OBJ_BLOB)
                die("BUG: read_loose_object streamed a non-blob");
  
 -      obj = parse_object_buffer(oid->hash, type, size, contents, &eaten);
 +      obj = parse_object_buffer(oid, type, size, contents, &eaten);
  
        if (!eaten)
                free(contents);
@@@ -598,10 -600,10 +599,10 @@@ static int fsck_cache_tree(struct cache
                fprintf(stderr, "Checking cache tree\n");
  
        if (0 <= it->entry_count) {
 -              struct object *obj = parse_object(it->sha1);
 +              struct object *obj = parse_object(&it->oid);
                if (!obj) {
                        error("%s: invalid sha1 pointer in cache-tree",
 -                            sha1_to_hex(it->sha1));
 +                            oid_to_hex(&it->oid));
                        errors_found |= ERROR_REFS;
                        return 1;
                }
@@@ -780,7 -782,7 +781,7 @@@ int cmd_fsck(int argc, const char **arg
                        mode = active_cache[i]->ce_mode;
                        if (S_ISGITLINK(mode))
                                continue;
 -                      blob = lookup_blob(active_cache[i]->oid.hash);
 +                      blob = lookup_blob(&active_cache[i]->oid);
                        if (!blob)
                                continue;
                        obj = &blob->object;
diff --combined builtin/gc.c
index f484eda43ca06046924931d2055b50c2f89ea8d7,0a6790d7144aae8258048b111effe9c1fc361cf0..bd91f136fed125ab06502c22b74b4f193f60773a
@@@ -11,6 -11,7 +11,7 @@@
   */
  
  #include "builtin.h"
+ #include "config.h"
  #include "tempfile.h"
  #include "lockfile.h"
  #include "parse-options.h"
@@@ -33,7 -34,7 +34,7 @@@ static int aggressive_window = 250
  static int gc_auto_threshold = 6700;
  static int gc_auto_pack_limit = 50;
  static int detach_auto = 1;
 -static unsigned long gc_log_expire_time;
 +static timestamp_t gc_log_expire_time;
  static const char *gc_log_expire = "1.day.ago";
  static const char *prune_expire = "2.weeks.ago";
  static const char *prune_worktrees_expire = "3.months.ago";
diff --combined builtin/grep.c
index 3e4b9600e86b661c99f4b936dfa574029ac4fbba,3df9e08f0368024dd067d5897bf46c83a7cbfdfc..f61a9d938b44424414812c57eecc309bd563f4b3
@@@ -4,6 -4,7 +4,7 @@@
   * Copyright (c) 2006 Junio C Hamano
   */
  #include "cache.h"
+ #include "config.h"
  #include "blob.h"
  #include "tree.h"
  #include "commit.h"
@@@ -73,14 -74,14 +74,14 @@@ static pthread_mutex_t grep_mutex
  
  static inline void grep_lock(void)
  {
 -      if (num_threads)
 -              pthread_mutex_lock(&grep_mutex);
 +      assert(num_threads);
 +      pthread_mutex_lock(&grep_mutex);
  }
  
  static inline void grep_unlock(void)
  {
 -      if (num_threads)
 -              pthread_mutex_unlock(&grep_mutex);
 +      assert(num_threads);
 +      pthread_mutex_unlock(&grep_mutex);
  }
  
  /* Signalled when a new work_item is added to todo. */
@@@ -224,8 -225,7 +225,8 @@@ static void start_threads(struct grep_o
                int err;
                struct grep_opt *o = grep_opt_dup(opt);
                o->output = strbuf_out;
 -              o->debug = 0;
 +              if (i)
 +                      o->debug = 0;
                compile_grep_patterns(o);
                err = pthread_create(&threads[i], NULL, run, o);
  
@@@ -290,22 -290,8 +291,22 @@@ static int grep_cmd_config(const char *
                if (num_threads < 0)
                        die(_("invalid number of threads specified (%d) for %s"),
                            num_threads, var);
 +#ifdef NO_PTHREADS
 +              else if (num_threads && num_threads != 1) {
 +                      /*
 +                       * TRANSLATORS: %s is the configuration
 +                       * variable for tweaking threads, currently
 +                       * grep.threads
 +                       */
 +                      warning(_("no threads support, ignoring %s"), var);
 +                      num_threads = 0;
 +              }
 +#endif
        }
  
 +      if (!strcmp(var, "submodule.recurse"))
 +              recurse_submodules = git_config_bool(var, value);
 +
        return st;
  }
  
@@@ -342,7 -328,7 +343,7 @@@ static int grep_oid(struct grep_opt *op
  
  #ifndef NO_PTHREADS
        if (num_threads) {
 -              add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, oid);
 +              add_work(opt, GREP_SOURCE_OID, pathbuf.buf, path, oid);
                strbuf_release(&pathbuf);
                return 0;
        } else
                struct grep_source gs;
                int hit;
  
 -              grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, path, oid);
 +              grep_source_init(&gs, GREP_SOURCE_OID, pathbuf.buf, path, oid);
                strbuf_release(&pathbuf);
                hit = grep_source(opt, &gs);
  
@@@ -510,8 -496,6 +511,8 @@@ static void compile_submodule_options(c
                break;
        case GREP_PATTERN_TYPE_UNSPECIFIED:
                break;
 +      default:
 +              die("BUG: Added a new grep pattern type without updating switch statement");
        }
  
        for (pattern = opt->pattern_list; pattern != NULL;
@@@ -587,7 -571,7 +588,7 @@@ static int grep_submodule_launch(struc
         * with the object's name: 'tree-name:filename'.  In order to
         * provide uniformity of output we want to pass the name of the
         * parent project's object name to the submodule so the submodule can
 -       * prefix its output with the parent's name and not its own SHA1.
 +       * prefix its output with the parent's name and not its own OID.
         */
        if (gs->identifier && end_of_base)
                argv_array_pushf(&cp.args, "--parent-basename=%.*s",
                 * If there is a tree identifier for the submodule, add the
                 * rev after adding the submodule options but before the
                 * pathspecs.  To do this we listen for the '--' and insert the
 -               * sha1 before pushing the '--' onto the child process argv
 +               * oid before pushing the '--' onto the child process argv
                 * array.
                 */
                if (gs->identifier &&
                    !strcmp("--", submodule_options.argv[i])) {
 -                      argv_array_push(&cp.args, sha1_to_hex(gs->identifier));
 +                      argv_array_push(&cp.args, oid_to_hex(gs->identifier));
                }
  
                argv_array_push(&cp.args, submodule_options.argv[i]);
  
  /*
   * Prep grep structures for a submodule grep
 - * sha1: the sha1 of the submodule or NULL if using the working tree
 + * oid: the oid of the submodule or NULL if using the working tree
   * filename: name of the submodule including tree name of parent
   * path: location of the submodule
   */
 -static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1,
 +static int grep_submodule(struct grep_opt *opt, const struct object_id *oid,
                          const char *filename, const char *path)
  {
        if (!is_submodule_initialized(path))
                 * If searching history, check for the presense of the
                 * submodule's gitdir before skipping the submodule.
                 */
 -              if (sha1) {
 +              if (oid) {
                        const struct submodule *sub =
                                        submodule_from_path(null_sha1, path);
                        if (sub)
  
  #ifndef NO_PTHREADS
        if (num_threads) {
 -              add_work(opt, GREP_SOURCE_SUBMODULE, filename, path, sha1);
 +              add_work(opt, GREP_SOURCE_SUBMODULE, filename, path, oid);
                return 0;
        } else
  #endif
                int hit;
  
                grep_source_init(&gs, GREP_SOURCE_SUBMODULE,
 -                               filename, path, sha1);
 +                               filename, path, oid);
                hit = grep_submodule_launch(opt, &gs);
  
                grep_source_clear(&gs);
@@@ -792,7 -776,7 +793,7 @@@ static int grep_tree(struct grep_opt *o
                                         check_attr);
                        free(data);
                } else if (recurse_submodules && S_ISGITLINK(entry.mode)) {
 -                      hit |= grep_submodule(opt, entry.oid->hash, base->buf,
 +                      hit |= grep_submodule(opt, entry.oid, base->buf,
                                              base->buf + tn_len);
                }
  
@@@ -883,7 -867,7 +884,7 @@@ static int grep_directory(struct grep_o
        if (exc_std)
                setup_standard_excludes(&dir);
  
 -      fill_directory(&dir, pathspec);
 +      fill_directory(&dir, &the_index, pathspec);
        for (i = 0; i < dir.nr; i++) {
                if (!dir_path_match(dir.entries[i], pathspec, 0, NULL))
                        continue;
@@@ -1171,6 -1155,8 +1172,6 @@@ int cmd_grep(int argc, const char **arg
        if (!opt.fixed && opt.ignore_case)
                opt.regflags |= REG_ICASE;
  
 -      compile_grep_patterns(&opt);
 -
        /*
         * We have to find "--" in a separate pass, because its presence
         * influences how we will parse arguments that come before it.
                        break;
                }
  
 -              if (get_sha1_with_context(arg, 0, oid.hash, &oc)) {
 +              if (get_sha1_with_context(arg, GET_SHA1_RECORD_PATH,
 +                                        oid.hash, &oc)) {
                        if (seen_dashdash)
                                die(_("unable to resolve revision: %s"), arg);
                        break;
                }
  
 -              object = parse_object_or_die(oid.hash, arg);
 +              object = parse_object_or_die(&oid, arg);
                if (!seen_dashdash)
                        verify_non_filename(prefix, arg);
                add_object_array_with_path(object, arg, &list, oc.mode, oc.path);
 +              free(oc.path);
        }
  
        /*
                num_threads = GREP_NUM_THREADS_DEFAULT;
        else if (num_threads < 0)
                die(_("invalid number of threads specified (%d)"), num_threads);
 +      if (num_threads == 1)
 +              num_threads = 0;
  #else
 +      if (num_threads)
 +              warning(_("no threads support, ignoring --threads"));
        num_threads = 0;
  #endif
  
 +      if (!num_threads)
 +              /*
 +               * The compiled patterns on the main path are only
 +               * used when not using threading. Otherwise
 +               * start_threads() below calls compile_grep_patterns()
 +               * for each thread.
 +               */
 +              compile_grep_patterns(&opt);
 +
  #ifndef NO_PTHREADS
        if (num_threads) {
                if (!(opt.name_only || opt.unmatch_name_only || opt.count)
diff --combined builtin/index-pack.c
index 04b9dcaf0f4ca90712cbb85cace521e226194f3b,dfb3d1296a220b92bffc674701f1b060a946eb08..edc1a91d89b308b1e164c48c1dfb06c8f6ebf0d1
@@@ -1,4 -1,5 +1,5 @@@
  #include "builtin.h"
+ #include "config.h"
  #include "delta.h"
  #include "pack.h"
  #include "csum-file.h"
@@@ -747,13 -748,13 +748,13 @@@ static int compare_objects(const unsign
                ssize_t len = read_istream(data->st, data->buf, size);
                if (len == 0)
                        die(_("SHA1 COLLISION FOUND WITH %s !"),
 -                          sha1_to_hex(data->entry->idx.sha1));
 +                          oid_to_hex(&data->entry->idx.oid));
                if (len < 0)
                        die(_("unable to read %s"),
 -                          sha1_to_hex(data->entry->idx.sha1));
 +                          oid_to_hex(&data->entry->idx.oid));
                if (memcmp(buf, data->buf, len))
                        die(_("SHA1 COLLISION FOUND WITH %s !"),
 -                          sha1_to_hex(data->entry->idx.sha1));
 +                          oid_to_hex(&data->entry->idx.oid));
                size -= len;
                buf += len;
        }
@@@ -771,12 -772,12 +772,12 @@@ static int check_collison(struct object
  
        memset(&data, 0, sizeof(data));
        data.entry = entry;
 -      data.st = open_istream(entry->idx.sha1, &type, &size, NULL);
 +      data.st = open_istream(entry->idx.oid.hash, &type, &size, NULL);
        if (!data.st)
                return -1;
        if (size != entry->size || type != entry->type)
                die(_("SHA1 COLLISION FOUND WITH %s !"),
 -                  sha1_to_hex(entry->idx.sha1));
 +                  oid_to_hex(&entry->idx.oid));
        unpack_data(entry, compare_objects, &data);
        close_istream(data.st);
        free(data.buf);
  
  static void sha1_object(const void *data, struct object_entry *obj_entry,
                        unsigned long size, enum object_type type,
 -                      const unsigned char *sha1)
 +                      const struct object_id *oid)
  {
        void *new_data = NULL;
        int collision_test_needed = 0;
  
        if (startup_info->have_repository) {
                read_lock();
 -              collision_test_needed = has_sha1_file_with_flags(sha1, HAS_SHA1_QUICK);
 +              collision_test_needed = has_sha1_file_with_flags(oid->hash, HAS_SHA1_QUICK);
                read_unlock();
        }
  
                enum object_type has_type;
                unsigned long has_size;
                read_lock();
 -              has_type = sha1_object_info(sha1, &has_size);
 +              has_type = sha1_object_info(oid->hash, &has_size);
                if (has_type < 0)
 -                      die(_("cannot read existing object info %s"), sha1_to_hex(sha1));
 +                      die(_("cannot read existing object info %s"), oid_to_hex(oid));
                if (has_type != type || has_size != size)
 -                      die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1));
 -              has_data = read_sha1_file(sha1, &has_type, &has_size);
 +                      die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid));
 +              has_data = read_sha1_file(oid->hash, &has_type, &has_size);
                read_unlock();
                if (!data)
                        data = new_data = get_data_from_pack(obj_entry);
                if (!has_data)
 -                      die(_("cannot read existing object %s"), sha1_to_hex(sha1));
 +                      die(_("cannot read existing object %s"), oid_to_hex(oid));
                if (size != has_size || type != has_type ||
                    memcmp(data, has_data, size) != 0)
 -                      die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1));
 +                      die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid));
                free(has_data);
        }
  
        if (strict) {
                read_lock();
                if (type == OBJ_BLOB) {
 -                      struct blob *blob = lookup_blob(sha1);
 +                      struct blob *blob = lookup_blob(oid);
                        if (blob)
                                blob->object.flags |= FLAG_CHECKED;
                        else
 -                              die(_("invalid blob object %s"), sha1_to_hex(sha1));
 +                              die(_("invalid blob object %s"), oid_to_hex(oid));
                } else {
                        struct object *obj;
                        int eaten;
                         * we do not need to free the memory here, as the
                         * buf is deleted by the caller.
                         */
 -                      obj = parse_object_buffer(sha1, type, size, buf, &eaten);
 +                      obj = parse_object_buffer(oid, type, size, buf,
 +                                                &eaten);
                        if (!obj)
                                die(_("invalid %s"), typename(type));
                        if (do_fsck_object &&
@@@ -958,10 -958,9 +959,10 @@@ static void resolve_delta(struct object
        if (!result->data)
                bad_object(delta_obj->idx.offset, _("failed to apply delta"));
        hash_sha1_file(result->data, result->size,
 -                     typename(delta_obj->real_type), delta_obj->idx.sha1);
 +                     typename(delta_obj->real_type),
 +                     delta_obj->idx.oid.hash);
        sha1_object(result->data, NULL, result->size, delta_obj->real_type,
 -                  delta_obj->idx.sha1);
 +                  &delta_obj->idx.oid);
        counter_lock();
        nr_resolved_deltas++;
        counter_unlock();
@@@ -991,7 -990,7 +992,7 @@@ static struct base_data *find_unresolve
                                                  struct base_data *prev_base)
  {
        if (base->ref_last == -1 && base->ofs_last == -1) {
 -              find_ref_delta_children(base->obj->idx.sha1,
 +              find_ref_delta_children(base->obj->idx.oid.hash,
                                        &base->ref_first, &base->ref_last,
                                        OBJ_REF_DELTA);
  
@@@ -1132,8 -1131,7 +1133,8 @@@ static void parse_pack_objects(unsigne
        for (i = 0; i < nr_objects; i++) {
                struct object_entry *obj = &objects[i];
                void *data = unpack_raw_entry(obj, &ofs_delta->offset,
 -                                            ref_delta_sha1, obj->idx.sha1);
 +                                            ref_delta_sha1,
 +                                            obj->idx.oid.hash);
                obj->real_type = obj->type;
                if (obj->type == OBJ_OFS_DELTA) {
                        nr_ofs_deltas++;
                        obj->real_type = OBJ_BAD;
                        nr_delays++;
                } else
 -                      sha1_object(data, NULL, obj->size, obj->type, obj->idx.sha1);
 +                      sha1_object(data, NULL, obj->size, obj->type,
 +                                  &obj->idx.oid);
                free(data);
                display_progress(progress, i+1);
        }
                if (obj->real_type != OBJ_BAD)
                        continue;
                obj->real_type = obj->type;
 -              sha1_object(NULL, obj, obj->size, obj->type, obj->idx.sha1);
 +              sha1_object(NULL, obj, obj->size, obj->type,
 +                          &obj->idx.oid);
                nr_delays--;
        }
        if (nr_delays)
@@@ -1335,7 -1331,7 +1336,7 @@@ static struct object_entry *append_obj_
        obj[1].idx.offset += write_compressed(f, buf, size);
        obj[0].idx.crc32 = crc32_end(f);
        sha1flush(f);
 -      hashcpy(obj->idx.sha1, sha1);
 +      hashcpy(obj->idx.oid.hash, sha1);
        return obj;
  }
  
@@@ -1586,14 -1582,13 +1587,14 @@@ static void show_pack_info(int stat_onl
                if (stat_only)
                        continue;
                printf("%s %-6s %lu %lu %"PRIuMAX,
 -                     sha1_to_hex(obj->idx.sha1),
 +                     oid_to_hex(&obj->idx.oid),
                       typename(obj->real_type), obj->size,
                       (unsigned long)(obj[1].idx.offset - obj->idx.offset),
                       (uintmax_t)obj->idx.offset);
                if (is_delta_type(obj->type)) {
                        struct object_entry *bobj = &objects[obj_stat[i].base_object_no];
 -                      printf(" %u %s", obj_stat[i].delta_depth, sha1_to_hex(bobj->idx.sha1));
 +                      printf(" %u %s", obj_stat[i].delta_depth,
 +                             oid_to_hex(&bobj->idx.oid));
                }
                putchar('\n');
        }
diff --combined builtin/log.c
index 998437b23dcb32a45e4d722d695c86d3cc82b4bc,b333d4fea23ccf144b61b41a6faf8e294f8b1402..8ca1de98943bdc62248ddd31708a6632557c61de
@@@ -5,6 -5,7 +5,7 @@@
   *             2006 Junio Hamano
   */
  #include "cache.h"
+ #include "config.h"
  #include "refs.h"
  #include "color.h"
  #include "commit.h"
@@@ -110,8 -111,6 +111,8 @@@ static void init_log_defaults(void
  {
        init_grep_defaults();
        init_diff_ui_defaults();
 +
 +      decoration_style = auto_decoration_style();
  }
  
  static void cmd_log_init_defaults(struct rev_info *rev)
@@@ -412,6 -411,8 +413,6 @@@ static int git_log_config(const char *v
                if (decoration_style < 0)
                        decoration_style = 0; /* maybe warn? */
                return 0;
 -      } else {
 -              decoration_style = auto_decoration_style();
        }
        if (!strcmp(var, "log.showroot")) {
                default_show_root = git_config_bool(var, value);
@@@ -483,20 -484,16 +484,20 @@@ static int show_blob_object(const struc
            !DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV))
                return stream_blob_to_fd(1, oid, NULL, 0);
  
 -      if (get_sha1_with_context(obj_name, 0, oidc.hash, &obj_context))
 +      if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH,
 +                                oidc.hash, &obj_context))
                die(_("Not a valid object name %s"), obj_name);
 -      if (!obj_context.path[0] ||
 -          !textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size))
 +      if (!obj_context.path ||
 +          !textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) {
 +              free(obj_context.path);
                return stream_blob_to_fd(1, oid, NULL, 0);
 +      }
  
        if (!buf)
                die(_("git show %s: bad file"), obj_name);
  
        write_or_die(1, buf, size);
 +      free(obj_context.path);
        return 0;
  }
  
@@@ -600,7 -597,7 +601,7 @@@ int cmd_show(int argc, const char **arg
                        rev.shown_one = 1;
                        if (ret)
                                break;
 -                      o = parse_object(t->tagged->oid.hash);
 +                      o = parse_object(&t->tagged->oid);
                        if (!o)
                                ret = error(_("Could not read object %s"),
                                            oid_to_hex(&t->tagged->oid));
@@@ -846,10 -843,8 +847,10 @@@ static int open_next_file(struct commi
        if (output_directory) {
                strbuf_addstr(&filename, output_directory);
                if (filename.len >=
 -                  PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len)
 +                  PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len) {
 +                      strbuf_release(&filename);
                        return error(_("name of output directory is too long"));
 +              }
                strbuf_complete(&filename, '/');
        }
  
        if (!quiet)
                printf("%s\n", filename.buf + outdir_offset);
  
 -      if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL)
 -              return error(_("Cannot open patch file %s"), filename.buf);
 +      if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL) {
 +              error_errno(_("Cannot open patch file %s"), filename.buf);
 +              strbuf_release(&filename);
 +              return -1;
 +      }
  
        strbuf_release(&filename);
        return 0;
@@@ -887,8 -879,8 +888,8 @@@ static void get_patch_ids(struct rev_in
        o2 = rev->pending.objects[1].item;
        flags1 = o1->flags;
        flags2 = o2->flags;
 -      c1 = lookup_commit_reference(o1->oid.hash);
 -      c2 = lookup_commit_reference(o2->oid.hash);
 +      c1 = lookup_commit_reference(&o1->oid);
 +      c2 = lookup_commit_reference(&o2->oid);
  
        if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
                die(_("Not a range."));
  static void gen_message_id(struct rev_info *info, char *base)
  {
        struct strbuf buf = STRBUF_INIT;
 -      strbuf_addf(&buf, "%s.%lu.git.%s", base,
 -                  (unsigned long) time(NULL),
 +      strbuf_addf(&buf, "%s.%"PRItime".git.%s", base,
 +                  (timestamp_t) time(NULL),
                    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));
        info->message_id = strbuf_detach(&buf, NULL);
  }
@@@ -1052,9 -1044,9 +1053,9 @@@ static void make_cover_letter(struct re
  
        diff_setup_done(&opts);
  
 -      diff_tree_sha1(origin->tree->object.oid.hash,
 -                     head->tree->object.oid.hash,
 -                     "", &opts);
 +      diff_tree_oid(&origin->tree->object.oid,
 +                    &head->tree->object.oid,
 +                    "", &opts);
        diffcore_std(&opts);
        diff_flush(&opts);
  
@@@ -1272,7 -1264,7 +1273,7 @@@ static struct commit *get_base_commit(c
  
                        if (get_oid(upstream, &oid))
                                die(_("Failed to resolve '%s' as a valid ref."), upstream);
 -                      commit = lookup_commit_or_die(oid.hash, "upstream base");
 +                      commit = lookup_commit_or_die(&oid, "upstream base");
                        base_list = get_merge_bases_many(commit, total, list);
                        /* There should be one and only one merge base. */
                        if (!base_list || base_list->next)
@@@ -1363,7 -1355,7 +1364,7 @@@ static void prepare_bases(struct base_t
                struct object_id *patch_id;
                if (commit->util)
                        continue;
 -              if (commit_patch_id(commit, &diffopt, oid.hash, 0))
 +              if (commit_patch_id(commit, &diffopt, &oid, 0))
                        die(_("cannot get patch id"));
                ALLOC_GROW(bases->patch_id, bases->nr_patch_id + 1, bases->alloc_patch_id);
                patch_id = bases->patch_id + bases->nr_patch_id;
@@@ -1828,7 -1820,7 +1829,7 @@@ static int add_pending_commit(const cha
  {
        struct object_id oid;
        if (get_oid(arg, &oid) == 0) {
 -              struct commit *commit = lookup_commit_reference(oid.hash);
 +              struct commit *commit = lookup_commit_reference(&oid);
                if (commit) {
                        commit->object.flags |= flags;
                        add_pending_object(revs, &commit->object, arg);
diff --combined builtin/ls-files.c
index cdc1cfdd26a95c54cc23717ce53c20a9d1607c90,975101078071dc48c09024830c4a621e3891cefb..b12d0bb61240890b3145baa8f051c83005b97dbe
@@@ -6,6 -6,7 +6,7 @@@
   * Copyright (C) Linus Torvalds, 2005
   */
  #include "cache.h"
+ #include "config.h"
  #include "quote.h"
  #include "dir.h"
  #include "builtin.h"
@@@ -53,17 -54,17 +54,17 @@@ static const char *tag_modified = ""
  static const char *tag_skip_worktree = "";
  static const char *tag_resolve_undo = "";
  
 -static void write_eolinfo(const struct cache_entry *ce, const char *path)
 +static void write_eolinfo(const struct index_state *istate,
 +                        const struct cache_entry *ce, const char *path)
  {
 -      if (!show_eol)
 -              return;
 -      else {
 +      if (show_eol) {
                struct stat st;
                const char *i_txt = "";
                const char *w_txt = "";
                const char *a_txt = get_convert_attr_ascii(path);
                if (ce && S_ISREG(ce->ce_mode))
 -                      i_txt = get_cached_convert_stats_ascii(ce->name);
 +                      i_txt = get_cached_convert_stats_ascii(istate,
 +                                                             ce->name);
                if (!lstat(path, &st) && S_ISREG(st.st_mode))
                        w_txt = get_wt_convert_stats_ascii(path);
                printf("i/%-5s w/%-5s attr/%-17s\t", i_txt, w_txt, a_txt);
@@@ -93,73 -94,34 +94,73 @@@ static void write_name(const char *name
        strbuf_release(&full_name);
  }
  
 +static const char *get_tag(const struct cache_entry *ce, const char *tag)
 +{
 +      static char alttag[4];
 +
 +      if (tag && *tag && show_valid_bit && (ce->ce_flags & CE_VALID)) {
 +              memcpy(alttag, tag, 3);
 +
 +              if (isalpha(tag[0])) {
 +                      alttag[0] = tolower(tag[0]);
 +              } else if (tag[0] == '?') {
 +                      alttag[0] = '!';
 +              } else {
 +                      alttag[0] = 'v';
 +                      alttag[1] = tag[0];
 +                      alttag[2] = ' ';
 +                      alttag[3] = 0;
 +              }
 +
 +              tag = alttag;
 +      }
 +
 +      return tag;
 +}
 +
 +static void print_debug(const struct cache_entry *ce)
 +{
 +      if (debug_mode) {
 +              const struct stat_data *sd = &ce->ce_stat_data;
 +
 +              printf("  ctime: %d:%d\n", sd->sd_ctime.sec, sd->sd_ctime.nsec);
 +              printf("  mtime: %d:%d\n", sd->sd_mtime.sec, sd->sd_mtime.nsec);
 +              printf("  dev: %d\tino: %d\n", sd->sd_dev, sd->sd_ino);
 +              printf("  uid: %d\tgid: %d\n", sd->sd_uid, sd->sd_gid);
 +              printf("  size: %d\tflags: %x\n", sd->sd_size, ce->ce_flags);
 +      }
 +}
 +
  static void show_dir_entry(const char *tag, struct dir_entry *ent)
  {
        int len = max_prefix_len;
  
 -      if (len >= ent->len)
 +      if (len > ent->len)
                die("git ls-files: internal error - directory entry not superset of prefix");
  
        if (!dir_path_match(ent, &pathspec, len, ps_matched))
                return;
  
        fputs(tag, stdout);
 -      write_eolinfo(NULL, ent->name);
 +      write_eolinfo(NULL, NULL, ent->name);
        write_name(ent->name);
  }
  
 -static void show_other_files(struct dir_struct *dir)
 +static void show_other_files(const struct index_state *istate,
 +                           const struct dir_struct *dir)
  {
        int i;
  
        for (i = 0; i < dir->nr; i++) {
                struct dir_entry *ent = dir->entries[i];
 -              if (!cache_name_is_other(ent->name, ent->len))
 +              if (!index_name_is_other(istate, ent->name, ent->len))
                        continue;
                show_dir_entry(tag_other, ent);
        }
  }
  
 -static void show_killed_files(struct dir_struct *dir)
 +static void show_killed_files(const struct index_state *istate,
 +                            const struct dir_struct *dir)
  {
        int i;
        for (i = 0; i < dir->nr; i++) {
                                /* If ent->name is prefix of an entry in the
                                 * cache, it will be killed.
                                 */
 -                              pos = cache_name_pos(ent->name, ent->len);
 +                              pos = index_name_pos(istate, ent->name, ent->len);
                                if (0 <= pos)
                                        die("BUG: killed-file %.*s not found",
                                                ent->len, ent->name);
                                pos = -pos - 1;
 -                              while (pos < active_nr &&
 -                                     ce_stage(active_cache[pos]))
 +                              while (pos < istate->cache_nr &&
 +                                     ce_stage(istate->cache[pos]))
                                        pos++; /* skip unmerged */
 -                              if (active_nr <= pos)
 +                              if (istate->cache_nr <= pos)
                                        break;
                                /* pos points at a name immediately after
                                 * ent->name in the cache.  Does it expect
                                 * ent->name to be a directory?
                                 */
 -                              len = ce_namelen(active_cache[pos]);
 +                              len = ce_namelen(istate->cache[pos]);
                                if ((ent->len < len) &&
 -                                  !strncmp(active_cache[pos]->name,
 +                                  !strncmp(istate->cache[pos]->name,
                                             ent->name, ent->len) &&
 -                                  active_cache[pos]->name[ent->len] == '/')
 +                                  istate->cache[pos]->name[ent->len] == '/')
                                        killed = 1;
                                break;
                        }
 -                      if (0 <= cache_name_pos(ent->name, sp - ent->name)) {
 +                      if (0 <= index_name_pos(istate, ent->name, sp - ent->name)) {
                                /* If any of the leading directories in
                                 * ent->name is registered in the cache,
                                 * ent->name will be killed.
@@@ -269,8 -231,7 +270,8 @@@ static void show_gitlink(const struct c
                exit(status);
  }
  
 -static void show_ce_entry(const char *tag, const struct cache_entry *ce)
 +static void show_ce_entry(const struct index_state *istate,
 +                        const char *tag, const struct cache_entry *ce)
  {
        struct strbuf name = STRBUF_INIT;
        int len = max_prefix_len;
                strbuf_addstr(&name, super_prefix);
        strbuf_addstr(&name, ce->name);
  
 -      if (len >= ce_namelen(ce))
 +      if (len > ce_namelen(ce))
                die("git ls-files: internal error - cache entry not superset of prefix");
  
        if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
                                  len, ps_matched,
                                  S_ISDIR(ce->ce_mode) ||
                                  S_ISGITLINK(ce->ce_mode))) {
 -              if (tag && *tag && show_valid_bit &&
 -                  (ce->ce_flags & CE_VALID)) {
 -                      static char alttag[4];
 -                      memcpy(alttag, tag, 3);
 -                      if (isalpha(tag[0]))
 -                              alttag[0] = tolower(tag[0]);
 -                      else if (tag[0] == '?')
 -                              alttag[0] = '!';
 -                      else {
 -                              alttag[0] = 'v';
 -                              alttag[1] = tag[0];
 -                              alttag[2] = ' ';
 -                              alttag[3] = 0;
 -                      }
 -                      tag = alttag;
 -              }
 +              tag = get_tag(ce, tag);
  
                if (!show_stage) {
                        fputs(tag, stdout);
                               find_unique_abbrev(ce->oid.hash, abbrev),
                               ce_stage(ce));
                }
 -              write_eolinfo(ce, ce->name);
 +              write_eolinfo(istate, ce, ce->name);
                write_name(ce->name);
 -              if (debug_mode) {
 -                      const struct stat_data *sd = &ce->ce_stat_data;
 -
 -                      printf("  ctime: %d:%d\n", sd->sd_ctime.sec, sd->sd_ctime.nsec);
 -                      printf("  mtime: %d:%d\n", sd->sd_mtime.sec, sd->sd_mtime.nsec);
 -                      printf("  dev: %d\tino: %d\n", sd->sd_dev, sd->sd_ino);
 -                      printf("  uid: %d\tgid: %d\n", sd->sd_uid, sd->sd_gid);
 -                      printf("  size: %d\tflags: %x\n", sd->sd_size, ce->ce_flags);
 -              }
 +              print_debug(ce);
        }
  
        strbuf_release(&name);
  }
  
 -static void show_ru_info(void)
 +static void show_ru_info(const struct index_state *istate)
  {
        struct string_list_item *item;
  
 -      if (!the_index.resolve_undo)
 +      if (!istate->resolve_undo)
                return;
  
 -      for_each_string_list_item(item, the_index.resolve_undo) {
 +      for_each_string_list_item(item, istate->resolve_undo) {
                const char *path = item->string;
                struct resolve_undo_info *ui = item->util;
                int i, len;
        }
  }
  
 -static int ce_excluded(struct dir_struct *dir, const struct cache_entry *ce)
 +static int ce_excluded(struct dir_struct *dir, struct index_state *istate,
 +                     const struct cache_entry *ce)
  {
        int dtype = ce_to_dtype(ce);
 -      return is_excluded(dir, ce->name, &dtype);
 +      return is_excluded(dir, istate, ce->name, &dtype);
  }
  
 -static void show_files(struct dir_struct *dir)
 +static void show_files(struct index_state *istate, struct dir_struct *dir)
  {
        int i;
  
        if (show_others || show_killed) {
                if (!show_others)
                        dir->flags |= DIR_COLLECT_KILLED_ONLY;
 -              fill_directory(dir, &pathspec);
 +              fill_directory(dir, istate, &pathspec);
                if (show_others)
 -                      show_other_files(dir);
 +                      show_other_files(istate, dir);
                if (show_killed)
 -                      show_killed_files(dir);
 +                      show_killed_files(istate, dir);
        }
        if (show_cached || show_stage) {
 -              for (i = 0; i < active_nr; i++) {
 -                      const struct cache_entry *ce = active_cache[i];
 +              for (i = 0; i < istate->cache_nr; i++) {
 +                      const struct cache_entry *ce = istate->cache[i];
                        if ((dir->flags & DIR_SHOW_IGNORED) &&
 -                          !ce_excluded(dir, ce))
 +                          !ce_excluded(dir, istate, ce))
                                continue;
                        if (show_unmerged && !ce_stage(ce))
                                continue;
                        if (ce->ce_flags & CE_UPDATE)
                                continue;
 -                      show_ce_entry(ce_stage(ce) ? tag_unmerged :
 +                      show_ce_entry(istate, ce_stage(ce) ? tag_unmerged :
                                (ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);
                }
        }
        if (show_deleted || show_modified) {
 -              for (i = 0; i < active_nr; i++) {
 -                      const struct cache_entry *ce = active_cache[i];
 +              for (i = 0; i < istate->cache_nr; i++) {
 +                      const struct cache_entry *ce = istate->cache[i];
                        struct stat st;
                        int err;
                        if ((dir->flags & DIR_SHOW_IGNORED) &&
 -                          !ce_excluded(dir, ce))
 +                          !ce_excluded(dir, istate, ce))
                                continue;
                        if (ce->ce_flags & CE_UPDATE)
                                continue;
                                continue;
                        err = lstat(ce->name, &st);
                        if (show_deleted && err)
 -                              show_ce_entry(tag_removed, ce);
 -                      if (show_modified && ce_modified(ce, &st, 0))
 -                              show_ce_entry(tag_modified, ce);
 +                              show_ce_entry(istate, tag_removed, ce);
 +                      if (show_modified && ie_modified(istate, ce, &st, 0))
 +                              show_ce_entry(istate, tag_modified, ce);
                }
        }
  }
  /*
   * Prune the index to only contain stuff starting with "prefix"
   */
 -static void prune_cache(const char *prefix, size_t prefixlen)
 +static void prune_index(struct index_state *istate,
 +                      const char *prefix, size_t prefixlen)
  {
        int pos;
        unsigned int first, last;
  
        if (!prefix)
                return;
 -      pos = cache_name_pos(prefix, prefixlen);
 +      pos = index_name_pos(istate, prefix, prefixlen);
        if (pos < 0)
                pos = -pos-1;
        first = pos;
 -      last = active_nr;
 +      last = istate->cache_nr;
        while (last > first) {
                int next = (last + first) >> 1;
 -              const struct cache_entry *ce = active_cache[next];
 +              const struct cache_entry *ce = istate->cache[next];
                if (!strncmp(ce->name, prefix, prefixlen)) {
                        first = next+1;
                        continue;
                }
                last = next;
        }
 -      memmove(active_cache, active_cache + pos,
 +      memmove(istate->cache, istate->cache + pos,
                (last - pos) * sizeof(struct cache_entry *));
 -      active_nr = last - pos;
 +      istate->cache_nr = last - pos;
 +}
 +
 +static int get_common_prefix_len(const char *common_prefix)
 +{
 +      int common_prefix_len;
 +
 +      if (!common_prefix)
 +              return 0;
 +
 +      common_prefix_len = strlen(common_prefix);
 +
 +      /*
 +       * If the prefix has a trailing slash, strip it so that submodules wont
 +       * be pruned from the index.
 +       */
 +      if (common_prefix[common_prefix_len - 1] == '/')
 +              common_prefix_len--;
 +
 +      return common_prefix_len;
  }
  
  /*
   * that were given from the command line.  We are not
   * going to write this index out.
   */
 -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)
  {
        struct tree *tree;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        struct pathspec pathspec;
        struct cache_entry *last_stage0 = NULL;
        int i;
  
 -      if (get_sha1(tree_name, sha1))
 +      if (get_oid(tree_name, &oid))
                die("tree-ish %s not found.", tree_name);
 -      tree = parse_tree_indirect(sha1);
 +      tree = parse_tree_indirect(&oid);
        if (!tree)
                die("bad tree-ish %s", tree_name);
  
        /* Hoist the unmerged entries up to stage #3 to make room */
 -      for (i = 0; i < active_nr; i++) {
 -              struct cache_entry *ce = active_cache[i];
 +      for (i = 0; i < istate->cache_nr; i++) {
 +              struct cache_entry *ce = istate->cache[i];
                if (!ce_stage(ce))
                        continue;
                ce->ce_flags |= CE_STAGEMASK;
                               PATHSPEC_PREFER_CWD, prefix, matchbuf);
        } else
                memset(&pathspec, 0, sizeof(pathspec));
 -      if (read_tree(tree, 1, &pathspec))
 +      if (read_tree(tree, 1, &pathspec, istate))
                die("unable to read tree entries %s", tree_name);
  
 -      for (i = 0; i < active_nr; i++) {
 -              struct cache_entry *ce = active_cache[i];
 +      for (i = 0; i < istate->cache_nr; i++) {
 +              struct cache_entry *ce = istate->cache[i];
                switch (ce_stage(ce)) {
                case 0:
                        last_stage0 = ce;
@@@ -663,7 -625,8 +664,7 @@@ int cmd_ls_files(int argc, const char *
                    "--error-unmatch");
  
        parse_pathspec(&pathspec, 0,
 -                     PATHSPEC_PREFER_CWD |
 -                     PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
 +                     PATHSPEC_PREFER_CWD,
                       prefix, argv);
  
        /*
                max_prefix = NULL;
        else
                max_prefix = common_prefix(&pathspec);
 -      max_prefix_len = max_prefix ? strlen(max_prefix) : 0;
 +      max_prefix_len = get_common_prefix_len(max_prefix);
 +
 +      prune_index(&the_index, max_prefix, max_prefix_len);
  
        /* Treat unmatching pathspec elements as errors */
        if (pathspec.nr && error_unmatch)
              show_killed || show_modified || show_resolve_undo))
                show_cached = 1;
  
 -      prune_cache(max_prefix, max_prefix_len);
        if (with_tree) {
                /*
                 * Basic sanity check; show-stages and show-unmerged
                 */
                if (show_stage || show_unmerged)
                        die("ls-files --with-tree is incompatible with -s or -u");
 -              overlay_tree_on_cache(with_tree, max_prefix);
 +              overlay_tree_on_index(&the_index, with_tree, max_prefix);
        }
 -      show_files(&dir);
 +      show_files(&the_index, &dir);
        if (show_resolve_undo)
 -              show_ru_info();
 +              show_ru_info(&the_index);
  
        if (ps_matched) {
                int bad;
diff --combined builtin/ls-tree.c
index ee7b293b11eb5c73dd6fe1ea31c5d3bf52c79656,4b53a8282b84cc5ce0c9b20ce776031ae457551e..ef965408e8fc5d80fa9e9daf0264a91abccd978c
@@@ -4,6 -4,7 +4,7 @@@
   * Copyright (C) Linus Torvalds, 2005
   */
  #include "cache.h"
+ #include "config.h"
  #include "blob.h"
  #include "tree.h"
  #include "commit.h"
@@@ -119,7 -120,7 +120,7 @@@ static int show_tree(const unsigned cha
  
  int cmd_ls_tree(int argc, const char **argv, const char *prefix)
  {
 -      unsigned char sha1[20];
 +      struct object_id oid;
        struct tree *tree;
        int i, full_tree = 0;
        const struct option ls_tree_options[] = {
  
        if (argc < 1)
                usage_with_options(ls_tree_usage, ls_tree_options);
 -      if (get_sha1(argv[0], sha1))
 +      if (get_oid(argv[0], &oid))
                die("Not a valid object name %s", argv[0]);
  
        /*
        for (i = 0; i < pathspec.nr; i++)
                pathspec.items[i].nowildcard_len = pathspec.items[i].len;
        pathspec.has_wildcard = 0;
 -      tree = parse_tree_indirect(sha1);
 +      tree = parse_tree_indirect(&oid);
        if (!tree)
                die("not a tree object");
        return !!read_tree_recursive(tree, "", 0, 0, &pathspec, show_tree, NULL);
diff --combined builtin/merge-base.c
index 0c36a70ad8f4dba1744ba6c4fa93389e2b796925,9c201cbfc0357d622b90714e3d1795a401eda51d..6dbd167d3b0874cd966b4590951a12d01f8f6aeb
@@@ -1,5 -1,6 +1,6 @@@
  #include "builtin.h"
  #include "cache.h"
+ #include "config.h"
  #include "commit.h"
  #include "refs.h"
  #include "diff.h"
@@@ -41,7 -42,7 +42,7 @@@ static struct commit *get_commit_refere
  
        if (get_oid(arg, &revkey))
                die("Not a valid object name %s", arg);
 -      r = lookup_commit_reference(revkey.hash);
 +      r = lookup_commit_reference(&revkey);
        if (!r)
                die("Not a valid commit name %s", arg);
  
@@@ -120,7 -121,7 +121,7 @@@ static void add_one_commit(struct objec
        if (is_null_oid(oid))
                return;
  
 -      commit = lookup_commit(oid->hash);
 +      commit = lookup_commit(oid);
        if (!commit ||
            (commit->object.flags & TMP_MARK) ||
            parse_commit(commit))
  }
  
  static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
 -                                const char *ident, unsigned long timestamp,
 +                                const char *ident, timestamp_t timestamp,
                                  int tz, const char *message, void *cbdata)
  {
        struct rev_collect *revs = cbdata;
@@@ -168,7 -169,7 +169,7 @@@ static int handle_fork_point(int argc, 
        if (get_oid(commitname, &oid))
                die("Not a valid object name: '%s'", commitname);
  
 -      derived = lookup_commit_reference(oid.hash);
 +      derived = lookup_commit_reference(&oid);
        memset(&revs, 0, sizeof(revs));
        revs.initial = 1;
        for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
diff --combined builtin/merge.c
index 84970cd85e8b0788928ff24b47c8c1b3dc3409e2,9bdd577e0959d19ee3f0234b20f375d838cc008e..900bafdb45d0b28ab5497cfd251535266fc92be5
@@@ -7,6 -7,7 +7,7 @@@
   */
  
  #include "cache.h"
+ #include "config.h"
  #include "parse-options.h"
  #include "builtin.h"
  #include "lockfile.h"
@@@ -415,7 -416,7 +416,7 @@@ static void finish(struct commit *head_
                        DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
                opts.detect_rename = DIFF_DETECT_RENAME;
                diff_setup_done(&opts);
 -              diff_tree_sha1(head->hash, new_head->hash, "", &opts);
 +              diff_tree_oid(head, new_head, "", &opts);
                diffcore_std(&opts);
                diff_flush(&opts);
        }
@@@ -605,13 -606,13 +606,13 @@@ static int read_tree_trivial(struct obj
        opts.verbose_update = 1;
        opts.trivial_merges_only = 1;
        opts.merge = 1;
 -      trees[nr_trees] = parse_tree_indirect(common->hash);
 +      trees[nr_trees] = parse_tree_indirect(common);
        if (!trees[nr_trees++])
                return -1;
 -      trees[nr_trees] = parse_tree_indirect(head->hash);
 +      trees[nr_trees] = parse_tree_indirect(head);
        if (!trees[nr_trees++])
                return -1;
 -      trees[nr_trees] = parse_tree_indirect(one->hash);
 +      trees[nr_trees] = parse_tree_indirect(one);
        if (!trees[nr_trees++])
                return -1;
        opts.fn = threeway_merge;
@@@ -839,7 -840,9 +840,7 @@@ static int suggest_conflicts(void
        struct strbuf msgbuf = STRBUF_INIT;
  
        filename = git_path_merge_msg();
 -      fp = fopen(filename, "a");
 -      if (!fp)
 -              die_errno(_("Could not open '%s' for writing"), filename);
 +      fp = xfopen(filename, "a");
  
        append_conflicts_hint(&msgbuf);
        fputs(msgbuf.buf, fp);
@@@ -1121,7 -1124,7 +1122,7 @@@ int cmd_merge(int argc, const char **ar
        if (!branch || is_null_oid(&head_oid))
                head_commit = NULL;
        else
 -              head_commit = lookup_commit_or_die(head_oid.hash, "HEAD");
 +              head_commit = lookup_commit_or_die(&head_oid, "HEAD");
  
        init_diff_ui_defaults();
        git_config(git_merge_config, NULL);
                        goto done;
                }
  
 -              if (checkout_fast_forward(head_commit->object.oid.hash,
 -                                        commit->object.oid.hash,
 +              if (checkout_fast_forward(&head_commit->object.oid,
 +                                        &commit->object.oid,
                                          overwrite_ignore)) {
                        ret = 1;
                        goto done;
diff --combined builtin/name-rev.c
index 7fc7e66e8500b82cbfecc21a1dce77e09de28ab0,c222daaa143fb8bdb9961f42ba7fe8ca2dd9f32d..e21715f1d0874171bcda2486adb4d27ea5cbbc99
@@@ -1,5 -1,6 +1,6 @@@
  #include "builtin.h"
  #include "cache.h"
+ #include "config.h"
  #include "commit.h"
  #include "tag.h"
  #include "refs.h"
  
  typedef struct rev_name {
        const char *tip_name;
 -      unsigned long taggerdate;
 +      timestamp_t taggerdate;
        int generation;
        int distance;
 +      int from_tag;
  } rev_name;
  
 -static long cutoff = LONG_MAX;
 +static timestamp_t cutoff = TIME_MAX;
  
  /* How many generations are maximally preferred over _one_ merge traversal? */
  #define MERGE_TRAVERSAL_WEIGHT 65535
  
 +static int is_better_name(struct rev_name *name,
 +                        const char *tip_name,
 +                        timestamp_t taggerdate,
 +                        int generation,
 +                        int distance,
 +                        int from_tag)
 +{
 +      /*
 +       * When comparing names based on tags, prefer names
 +       * based on the older tag, even if it is farther away.
 +       */
 +      if (from_tag && name->from_tag)
 +              return (name->taggerdate > taggerdate ||
 +                      (name->taggerdate == taggerdate &&
 +                       name->distance > distance));
 +
 +      /*
 +       * We know that at least one of them is a non-tag at this point.
 +       * favor a tag over a non-tag.
 +       */
 +      if (name->from_tag != from_tag)
 +              return from_tag;
 +
 +      /*
 +       * We are now looking at two non-tags.  Tiebreak to favor
 +       * shorter hops.
 +       */
 +      if (name->distance != distance)
 +              return name->distance > distance;
 +
 +      /* ... or tiebreak to favor older date */
 +      if (name->taggerdate != taggerdate)
 +              return name->taggerdate > taggerdate;
 +
 +      /* keep the current one if we cannot decide */
 +      return 0;
 +}
 +
  static void name_rev(struct commit *commit,
 -              const char *tip_name, unsigned long taggerdate,
 -              int generation, int distance,
 +              const char *tip_name, timestamp_t taggerdate,
 +              int generation, int distance, int from_tag,
                int deref)
  {
        struct rev_name *name = (struct rev_name *)commit->util;
        struct commit_list *parents;
        int parent_number = 1;
 +      char *to_free = NULL;
  
        parse_commit(commit);
  
@@@ -75,7 -36,7 +76,7 @@@
                return;
  
        if (deref) {
 -              tip_name = xstrfmt("%s^0", tip_name);
 +              tip_name = to_free = xstrfmt("%s^0", tip_name);
  
                if (generation)
                        die("generation: %d, but deref?", generation);
                name = xmalloc(sizeof(rev_name));
                commit->util = name;
                goto copy_data;
 -      } else if (name->taggerdate > taggerdate ||
 -                      (name->taggerdate == taggerdate &&
 -                       name->distance > distance)) {
 +      } else if (is_better_name(name, tip_name, taggerdate,
 +                                generation, distance, from_tag)) {
  copy_data:
                name->tip_name = tip_name;
                name->taggerdate = taggerdate;
                name->generation = generation;
                name->distance = distance;
 -      } else
 +              name->from_tag = from_tag;
 +      } else {
 +              free(to_free);
                return;
 +      }
  
        for (parents = commit->parents;
                        parents;
                                                   parent_number);
  
                        name_rev(parents->item, new_name, taggerdate, 0,
 -                              distance + MERGE_TRAVERSAL_WEIGHT, 0);
 +                               distance + MERGE_TRAVERSAL_WEIGHT,
 +                               from_tag, 0);
                } else {
                        name_rev(parents->item, tip_name, taggerdate,
 -                              generation + 1, distance + 1, 0);
 +                               generation + 1, distance + 1,
 +                               from_tag, 0);
                }
        }
  }
@@@ -158,7 -115,7 +159,7 @@@ struct name_ref_data 
  
  static struct tip_table {
        struct tip_table_entry {
 -              unsigned char sha1[20];
 +              struct object_id oid;
                const char *refname;
        } *table;
        int nr;
        int sorted;
  } tip_table;
  
 -static void add_to_tip_table(const unsigned char *sha1, const char *refname,
 +static void add_to_tip_table(const struct object_id *oid, const char *refname,
                             int shorten_unambiguous)
  {
        refname = name_ref_abbrev(refname, shorten_unambiguous);
  
        ALLOC_GROW(tip_table.table, tip_table.nr + 1, tip_table.alloc);
 -      hashcpy(tip_table.table[tip_table.nr].sha1, sha1);
 +      oidcpy(&tip_table.table[tip_table.nr].oid, oid);
        tip_table.table[tip_table.nr].refname = xstrdup(refname);
        tip_table.nr++;
        tip_table.sorted = 0;
  static int tipcmp(const void *a_, const void *b_)
  {
        const struct tip_table_entry *a = a_, *b = b_;
 -      return hashcmp(a->sha1, b->sha1);
 +      return oidcmp(&a->oid, &b->oid);
  }
  
  static int name_ref(const char *path, const struct object_id *oid, int flags, void *cb_data)
  {
 -      struct object *o = parse_object(oid->hash);
 +      struct object *o = parse_object(oid);
        struct name_ref_data *data = cb_data;
        int can_abbreviate_output = data->tags_only && data->name_only;
        int deref = 0;
 -      unsigned long taggerdate = ULONG_MAX;
 +      timestamp_t taggerdate = TIME_MAX;
  
        if (data->tags_only && !starts_with(path, "refs/tags/"))
                return 0;
                        return 0;
        }
  
 -      add_to_tip_table(oid->hash, path, can_abbreviate_output);
 +      add_to_tip_table(oid, path, can_abbreviate_output);
  
        while (o && o->type == OBJ_TAG) {
                struct tag *t = (struct tag *) o;
                if (!t->tagged)
                        break; /* broken repository */
 -              o = parse_object(t->tagged->oid.hash);
 +              o = parse_object(&t->tagged->oid);
                deref = 1;
                taggerdate = t->date;
        }
        if (o && o->type == OBJ_COMMIT) {
                struct commit *commit = (struct commit *)o;
 +              int from_tag = starts_with(path, "refs/tags/");
  
 +              if (taggerdate == ULONG_MAX)
 +                      taggerdate = ((struct commit *)o)->date;
                path = name_ref_abbrev(path, can_abbreviate_output);
 -              name_rev(commit, xstrdup(path), taggerdate, 0, 0, deref);
 +              name_rev(commit, xstrdup(path), taggerdate, 0, 0,
 +                       from_tag, deref);
        }
        return 0;
  }
  static const unsigned char *nth_tip_table_ent(size_t ix, void *table_)
  {
        struct tip_table_entry *table = table_;
 -      return table[ix].sha1;
 +      return table[ix].oid.hash;
  }
  
  static const char *get_exact_ref_match(const struct object *o)
@@@ -349,9 -302,9 +350,9 @@@ static void name_rev_line(char *p, stru
  #define ishex(x) (isdigit((x)) || ((x) >= 'a' && (x) <= 'f'))
                if (!ishex(*p))
                        forty = 0;
 -              else if (++forty == 40 &&
 +              else if (++forty == GIT_SHA1_HEXSZ &&
                         !ishex(*(p+1))) {
 -                      unsigned char sha1[40];
 +                      struct object_id oid;
                        const char *name = NULL;
                        char c = *(p+1);
                        int p_len = p - p_start + 1;
                        forty = 0;
  
                        *(p+1) = 0;
 -                      if (!get_sha1(p - 39, sha1)) {
 +                      if (!get_oid(p - (GIT_SHA1_HEXSZ - 1), &oid)) {
                                struct object *o =
 -                                      lookup_object(sha1);
 +                                      lookup_object(oid.hash);
                                if (o)
                                        name = get_rev_name(o, &buf);
                        }
                                continue;
  
                        if (data->name_only)
 -                              printf("%.*s%s", p_len - 40, p_start, name);
 +                              printf("%.*s%s", p_len - GIT_SHA1_HEXSZ, p_start, name);
                        else
                                printf("%.*s (%s)", p_len, p_start, name);
                        p_start = p + 1;
@@@ -422,18 -375,18 +423,18 @@@ int cmd_name_rev(int argc, const char *
                cutoff = 0;
  
        for (; argc; argc--, argv++) {
 -              unsigned char sha1[20];
 +              struct object_id oid;
                struct object *object;
                struct commit *commit;
  
 -              if (get_sha1(*argv, sha1)) {
 +              if (get_oid(*argv, &oid)) {
                        fprintf(stderr, "Could not get sha1 for %s. Skipping.\n",
                                        *argv);
                        continue;
                }
  
                commit = NULL;
 -              object = parse_object(sha1);
 +              object = parse_object(&oid);
                if (object) {
                        struct object *peeled = deref_tag(object, *argv, 0);
                        if (peeled && peeled->type == OBJ_COMMIT)
diff --combined builtin/notes.c
index c939a84b7629cd5d4dda09d427255410d723d95b,dceb681bad19e94f30cd58b901033d472423e8ea..77573cf1ea8cb4d998597e265263487e22fde592
@@@ -8,6 -8,7 +8,7 @@@
   */
  
  #include "cache.h"
+ #include "config.h"
  #include "builtin.h"
  #include "notes.h"
  #include "blob.h"
@@@ -109,11 -110,11 +110,11 @@@ static void free_note_data(struct note_
        strbuf_release(&d->buf);
  }
  
 -static int list_each_note(const unsigned char *object_sha1,
 -              const unsigned char *note_sha1, char *note_path,
 +static int list_each_note(const struct object_id *object_oid,
 +              const struct object_id *note_oid, char *note_path,
                void *cb_data)
  {
 -      printf("%s %s\n", sha1_to_hex(note_sha1), sha1_to_hex(object_sha1));
 +      printf("%s %s\n", oid_to_hex(note_oid), oid_to_hex(object_oid));
        return 0;
  }
  
@@@ -129,10 -130,10 +130,10 @@@ static void copy_obj_to_fd(int fd, cons
        }
  }
  
 -static void write_commented_object(int fd, const unsigned char *object)
 +static void write_commented_object(int fd, const struct object_id *object)
  {
        const char *show_args[5] =
 -              {"show", "--stat", "--no-notes", sha1_to_hex(object), NULL};
 +              {"show", "--stat", "--no-notes", oid_to_hex(object), NULL};
        struct child_process show = CHILD_PROCESS_INIT;
        struct strbuf buf = STRBUF_INIT;
        struct strbuf cbuf = STRBUF_INIT;
        show.git_cmd = 1;
        if (start_command(&show))
                die(_("unable to start 'show' for object '%s'"),
 -                  sha1_to_hex(object));
 +                  oid_to_hex(object));
  
        if (strbuf_read(&buf, show.out, 0) < 0)
                die_errno(_("could not read 'show' output"));
  
        if (finish_command(&show))
                die(_("failed to finish 'show' for object '%s'"),
 -                  sha1_to_hex(object));
 +                  oid_to_hex(object));
  }
  
 -static void prepare_note_data(const unsigned char *object, struct note_data *d,
 +static void prepare_note_data(const struct object_id *object, struct note_data *d,
                const unsigned char *old_note)
  {
        if (d->use_editor || !d->given) {
@@@ -243,16 -244,16 +244,16 @@@ static int parse_reuse_arg(const struc
  {
        struct note_data *d = opt->value;
        char *buf;
 -      unsigned char object[20];
 +      struct object_id object;
        enum object_type type;
        unsigned long len;
  
        if (d->buf.len)
                strbuf_addch(&d->buf, '\n');
  
 -      if (get_sha1(arg, object))
 +      if (get_oid(arg, &object))
                die(_("failed to resolve '%s' as a valid ref."), arg);
 -      if (!(buf = read_sha1_file(object, &type, &len))) {
 +      if (!(buf = read_sha1_file(object.hash, &type, &len))) {
                free(buf);
                die(_("failed to read object '%s'."), arg);
        }
@@@ -292,7 -293,7 +293,7 @@@ static int notes_copy_from_stdin(int fo
        }
  
        while (strbuf_getline_lf(&buf, stdin) != EOF) {
 -              unsigned char from_obj[20], to_obj[20];
 +              struct object_id from_obj, to_obj;
                struct strbuf **split;
                int err;
  
                        die(_("malformed input line: '%s'."), buf.buf);
                strbuf_rtrim(split[0]);
                strbuf_rtrim(split[1]);
 -              if (get_sha1(split[0]->buf, from_obj))
 +              if (get_oid(split[0]->buf, &from_obj))
                        die(_("failed to resolve '%s' as a valid ref."), split[0]->buf);
 -              if (get_sha1(split[1]->buf, to_obj))
 +              if (get_oid(split[1]->buf, &to_obj))
                        die(_("failed to resolve '%s' as a valid ref."), split[1]->buf);
  
                if (rewrite_cmd)
 -                      err = copy_note_for_rewrite(c, from_obj, to_obj);
 +                      err = copy_note_for_rewrite(c, &from_obj, &to_obj);
                else
 -                      err = copy_note(t, from_obj, to_obj, force,
 +                      err = copy_note(t, &from_obj, &to_obj, force,
                                        combine_notes_overwrite);
  
                if (err) {
@@@ -340,10 -341,8 +341,10 @@@ static struct notes_tree *init_notes_ch
  
        ref = (flags & NOTES_INIT_WRITABLE) ? t->update_ref : t->ref;
        if (!starts_with(ref, "refs/notes/"))
 -              /* TRANSLATORS: the first %s will be replaced by a
 -                 git notes command: 'add', 'merge', 'remove', etc.*/
 +              /*
 +               * TRANSLATORS: the first %s will be replaced by a git
 +               * notes command: 'add', 'merge', 'remove', etc.
 +               */
                die(_("refusing to %s notes in %s (outside of refs/notes/)"),
                    subcommand, ref);
        return t;
  static int list(int argc, const char **argv, const char *prefix)
  {
        struct notes_tree *t;
 -      unsigned char object[20];
 -      const unsigned char *note;
 +      struct object_id object;
 +      const struct object_id *note;
        int retval = -1;
        struct option options[] = {
                OPT_END()
  
        t = init_notes_check("list", 0);
        if (argc) {
 -              if (get_sha1(argv[0], object))
 +              if (get_oid(argv[0], &object))
                        die(_("failed to resolve '%s' as a valid ref."), argv[0]);
 -              note = get_note(t, object);
 +              note = get_note(t, &object);
                if (note) {
 -                      puts(sha1_to_hex(note));
 +                      puts(oid_to_hex(note));
                        retval = 0;
                } else
                        retval = error(_("no note found for object %s."),
 -                                     sha1_to_hex(object));
 +                                     oid_to_hex(&object));
        } else
                retval = for_each_note(t, 0, list_each_note, NULL);
  
@@@ -393,8 -392,8 +394,8 @@@ static int add(int argc, const char **a
        int force = 0, allow_empty = 0;
        const char *object_ref;
        struct notes_tree *t;
 -      unsigned char object[20], new_note[20];
 -      const unsigned char *note;
 +      struct object_id object, new_note;
 +      const struct object_id *note;
        struct note_data d = { 0, 0, NULL, STRBUF_INIT };
        struct option options[] = {
                { OPTION_CALLBACK, 'm', "message", &d, N_("message"),
  
        object_ref = argc > 1 ? argv[1] : "HEAD";
  
 -      if (get_sha1(object_ref, object))
 +      if (get_oid(object_ref, &object))
                die(_("failed to resolve '%s' as a valid ref."), object_ref);
  
        t = init_notes_check("add", NOTES_INIT_WRITABLE);
 -      note = get_note(t, object);
 +      note = get_note(t, &object);
  
        if (note) {
                if (!force) {
                                return error(_("Cannot add notes. "
                                        "Found existing notes for object %s. "
                                        "Use '-f' to overwrite existing notes"),
 -                                      sha1_to_hex(object));
 +                                      oid_to_hex(&object));
                        }
                        /*
                         * Redirect to "edit" subcommand.
                        return append_edit(argc, argv, prefix);
                }
                fprintf(stderr, _("Overwriting existing notes for object %s\n"),
 -                      sha1_to_hex(object));
 +                      oid_to_hex(&object));
        }
  
 -      prepare_note_data(object, &d, note);
 +      prepare_note_data(&object, &d, note->hash);
        if (d.buf.len || allow_empty) {
 -              write_note_data(&d, new_note);
 -              if (add_note(t, object, new_note, combine_notes_overwrite))
 +              write_note_data(&d, new_note.hash);
 +              if (add_note(t, &object, &new_note, combine_notes_overwrite))
                        die("BUG: combine_notes_overwrite failed");
                commit_notes(t, "Notes added by 'git notes add'");
        } else {
                fprintf(stderr, _("Removing note for object %s\n"),
 -                      sha1_to_hex(object));
 -              remove_note(t, object);
 +                      oid_to_hex(&object));
 +              remove_note(t, object.hash);
                commit_notes(t, "Notes removed by 'git notes add'");
        }
  
  static int copy(int argc, const char **argv, const char *prefix)
  {
        int retval = 0, force = 0, from_stdin = 0;
 -      const unsigned char *from_note, *note;
 +      const struct object_id *from_note, *note;
        const char *object_ref;
 -      unsigned char object[20], from_obj[20];
 +      struct object_id object, from_obj;
        struct notes_tree *t;
        const char *rewrite_cmd = NULL;
        struct option options[] = {
                usage_with_options(git_notes_copy_usage, options);
        }
  
 -      if (get_sha1(argv[0], from_obj))
 +      if (get_oid(argv[0], &from_obj))
                die(_("failed to resolve '%s' as a valid ref."), argv[0]);
  
        object_ref = 1 < argc ? argv[1] : "HEAD";
  
 -      if (get_sha1(object_ref, object))
 +      if (get_oid(object_ref, &object))
                die(_("failed to resolve '%s' as a valid ref."), object_ref);
  
        t = init_notes_check("copy", NOTES_INIT_WRITABLE);
 -      note = get_note(t, object);
 +      note = get_note(t, &object);
  
        if (note) {
                if (!force) {
                        retval = error(_("Cannot copy notes. Found existing "
                                       "notes for object %s. Use '-f' to "
                                       "overwrite existing notes"),
 -                                     sha1_to_hex(object));
 +                                     oid_to_hex(&object));
                        goto out;
                }
                fprintf(stderr, _("Overwriting existing notes for object %s\n"),
 -                      sha1_to_hex(object));
 +                      oid_to_hex(&object));
        }
  
 -      from_note = get_note(t, from_obj);
 +      from_note = get_note(t, &from_obj);
        if (!from_note) {
                retval = error(_("missing notes on source object %s. Cannot "
 -                             "copy."), sha1_to_hex(from_obj));
 +                             "copy."), oid_to_hex(&from_obj));
                goto out;
        }
  
 -      if (add_note(t, object, from_note, combine_notes_overwrite))
 +      if (add_note(t, &object, from_note, combine_notes_overwrite))
                die("BUG: combine_notes_overwrite failed");
        commit_notes(t, "Notes added by 'git notes copy'");
  out:
@@@ -554,8 -553,8 +555,8 @@@ static int append_edit(int argc, const 
        int allow_empty = 0;
        const char *object_ref;
        struct notes_tree *t;
 -      unsigned char object[20], new_note[20];
 -      const unsigned char *note;
 +      struct object_id object, new_note;
 +      const struct object_id *note;
        char *logmsg;
        const char * const *usage;
        struct note_data d = { 0, 0, NULL, STRBUF_INIT };
  
        object_ref = 1 < argc ? argv[1] : "HEAD";
  
 -      if (get_sha1(object_ref, object))
 +      if (get_oid(object_ref, &object))
                die(_("failed to resolve '%s' as a valid ref."), object_ref);
  
        t = init_notes_check(argv[0], NOTES_INIT_WRITABLE);
 -      note = get_note(t, object);
 +      note = get_note(t, &object);
  
 -      prepare_note_data(object, &d, edit ? note : NULL);
 +      prepare_note_data(&object, &d, edit && note ? note->hash : NULL);
  
        if (note && !edit) {
                /* Append buf to previous note contents */
                unsigned long size;
                enum object_type type;
 -              char *prev_buf = read_sha1_file(note, &type, &size);
 +              char *prev_buf = read_sha1_file(note->hash, &type, &size);
  
                strbuf_grow(&d.buf, size + 1);
                if (d.buf.len && prev_buf && size)
        }
  
        if (d.buf.len || allow_empty) {
 -              write_note_data(&d, new_note);
 -              if (add_note(t, object, new_note, combine_notes_overwrite))
 +              write_note_data(&d, new_note.hash);
 +              if (add_note(t, &object, &new_note, combine_notes_overwrite))
                        die("BUG: combine_notes_overwrite failed");
                logmsg = xstrfmt("Notes added by 'git notes %s'", argv[0]);
        } else {
                fprintf(stderr, _("Removing note for object %s\n"),
 -                      sha1_to_hex(object));
 -              remove_note(t, object);
 +                      oid_to_hex(&object));
 +              remove_note(t, object.hash);
                logmsg = xstrfmt("Notes removed by 'git notes %s'", argv[0]);
        }
        commit_notes(t, logmsg);
@@@ -639,8 -638,8 +640,8 @@@ static int show(int argc, const char **
  {
        const char *object_ref;
        struct notes_tree *t;
 -      unsigned char object[20];
 -      const unsigned char *note;
 +      struct object_id object;
 +      const struct object_id *note;
        int retval;
        struct option options[] = {
                OPT_END()
  
        object_ref = argc ? argv[0] : "HEAD";
  
 -      if (get_sha1(object_ref, object))
 +      if (get_oid(object_ref, &object))
                die(_("failed to resolve '%s' as a valid ref."), object_ref);
  
        t = init_notes_check("show", 0);
 -      note = get_note(t, object);
 +      note = get_note(t, &object);
  
        if (!note)
                retval = error(_("no note found for object %s."),
 -                             sha1_to_hex(object));
 +                             oid_to_hex(&object));
        else {
 -              const char *show_args[3] = {"show", sha1_to_hex(note), NULL};
 +              const char *show_args[3] = {"show", oid_to_hex(note), NULL};
                retval = execv_git_cmd(show_args);
        }
        free_notes(t);
@@@ -708,7 -707,7 +709,7 @@@ static int merge_commit(struct notes_me
  
        if (get_oid("NOTES_MERGE_PARTIAL", &oid))
                die(_("failed to read ref NOTES_MERGE_PARTIAL"));
 -      else if (!(partial = lookup_commit_reference(oid.hash)))
 +      else if (!(partial = lookup_commit_reference(&oid)))
                die(_("could not find commit from NOTES_MERGE_PARTIAL."));
        else if (parse_commit(partial))
                die(_("could not parse commit from NOTES_MERGE_PARTIAL."));
        if (!o->local_ref)
                die(_("failed to resolve NOTES_MERGE_REF"));
  
 -      if (notes_merge_commit(o, t, partial, oid.hash))
 +      if (notes_merge_commit(o, t, partial, &oid))
                die(_("failed to finalize notes merge"));
  
        /* Reuse existing commit message in reflog message */
@@@ -762,7 -761,7 +763,7 @@@ static int git_config_get_notes_strateg
  static int merge(int argc, const char **argv, const char *prefix)
  {
        struct strbuf remote_ref = STRBUF_INIT, msg = STRBUF_INIT;
 -      unsigned char result_sha1[20];
 +      struct object_id result_oid;
        struct notes_tree *t;
        struct notes_merge_options o;
        int do_merge = 0, do_commit = 0, do_abort = 0;
                    remote_ref.buf, default_notes_ref());
        strbuf_add(&(o.commit_msg), msg.buf + 7, msg.len - 7); /* skip "notes: " */
  
 -      result = notes_merge(&o, t, result_sha1);
 +      result = notes_merge(&o, t, &result_oid);
  
 -      if (result >= 0) /* Merge resulted (trivially) in result_sha1 */
 +      if (result >= 0) /* Merge resulted (trivially) in result_oid */
                /* Update default notes ref with new commit */
 -              update_ref(msg.buf, default_notes_ref(), result_sha1, NULL,
 +              update_ref(msg.buf, default_notes_ref(), result_oid.hash, NULL,
                           0, UPDATE_REFS_DIE_ON_ERR);
        else { /* Merge has unresolved conflicts */
                const struct worktree *wt;
                /* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
 -              update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_sha1, NULL,
 +              update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_oid.hash, NULL,
                           0, UPDATE_REFS_DIE_ON_ERR);
                /* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
                wt = find_shared_symref("NOTES_MERGE_REF", default_notes_ref());
  static int remove_one_note(struct notes_tree *t, const char *name, unsigned flag)
  {
        int status;
 -      unsigned char sha1[20];
 -      if (get_sha1(name, sha1))
 +      struct object_id oid;
 +      if (get_oid(name, &oid))
                return error(_("Failed to resolve '%s' as a valid ref."), name);
 -      status = remove_note(t, sha1);
 +      status = remove_note(t, oid.hash);
        if (status)
                fprintf(stderr, _("Object %s has no note\n"), name);
        else
diff --combined builtin/pack-objects.c
index f672225def033595602bc4ff91ee26edd9804944,0e17184354eba004c9f529924b02df979d6bc522..d5e96ed2d0ce0d74a40961f6729896722dacf9a2
@@@ -1,5 -1,6 +1,6 @@@
  #include "builtin.h"
  #include "cache.h"
+ #include "config.h"
  #include "attr.h"
  #include "object.h"
  #include "blob.h"
@@@ -44,7 -45,7 +45,7 @@@ static uint32_t nr_result, nr_written
  static int non_empty;
  static int reuse_delta = 1, reuse_object = 1;
  static int keep_unreachable, unpack_unreachable, include_tag;
 -static unsigned long unpack_unreachable_expiration;
 +static timestamp_t unpack_unreachable_expiration;
  static int pack_loose_unreachable;
  static int local;
  static int have_non_local_packs;
@@@ -106,14 -107,12 +107,14 @@@ static void *get_delta(struct object_en
        void *buf, *base_buf, *delta_buf;
        enum object_type type;
  
 -      buf = read_sha1_file(entry->idx.sha1, &type, &size);
 +      buf = read_sha1_file(entry->idx.oid.hash, &type, &size);
        if (!buf)
 -              die("unable to read %s", sha1_to_hex(entry->idx.sha1));
 -      base_buf = read_sha1_file(entry->delta->idx.sha1, &type, &base_size);
 +              die("unable to read %s", oid_to_hex(&entry->idx.oid));
 +      base_buf = read_sha1_file(entry->delta->idx.oid.hash, &type,
 +                                &base_size);
        if (!base_buf)
 -              die("unable to read %s", sha1_to_hex(entry->delta->idx.sha1));
 +              die("unable to read %s",
 +                  oid_to_hex(&entry->delta->idx.oid));
        delta_buf = diff_delta(base_buf, base_size,
                               buf, size, &delta_size, 0);
        if (!delta_buf || delta_size != entry->delta_size)
@@@ -251,14 -250,12 +252,14 @@@ static unsigned long write_no_reuse_obj
        if (!usable_delta) {
                if (entry->type == OBJ_BLOB &&
                    entry->size > big_file_threshold &&
 -                  (st = open_istream(entry->idx.sha1, &type, &size, NULL)) != NULL)
 +                  (st = open_istream(entry->idx.oid.hash, &type, &size, NULL)) != NULL)
                        buf = NULL;
                else {
 -                      buf = read_sha1_file(entry->idx.sha1, &type, &size);
 +                      buf = read_sha1_file(entry->idx.oid.hash, &type,
 +                                           &size);
                        if (!buf)
 -                              die(_("unable to read %s"), sha1_to_hex(entry->idx.sha1));
 +                              die(_("unable to read %s"),
 +                                  oid_to_hex(&entry->idx.oid));
                }
                /*
                 * make sure no cached delta data remains from a
                        return 0;
                }
                sha1write(f, header, hdrlen);
 -              sha1write(f, entry->delta->idx.sha1, 20);
 +              sha1write(f, entry->delta->idx.oid.hash, 20);
                hdrlen += 20;
        } else {
                if (limit && hdrlen + datalen + 20 >= limit) {
                sha1write(f, header, hdrlen);
        }
        if (st) {
 -              datalen = write_large_blob_data(st, f, entry->idx.sha1);
 +              datalen = write_large_blob_data(st, f, entry->idx.oid.hash);
                close_istream(st);
        } else {
                sha1write(f, buf, datalen);
@@@ -373,8 -370,7 +374,8 @@@ static off_t write_reuse_object(struct 
        datalen = revidx[1].offset - offset;
        if (!pack_to_stdout && p->index_version > 1 &&
            check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) {
 -              error("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
 +              error("bad packed object CRC for %s",
 +                    oid_to_hex(&entry->idx.oid));
                unuse_pack(&w_curs);
                return write_no_reuse_object(f, entry, limit, usable_delta);
        }
  
        if (!pack_to_stdout && p->index_version == 1 &&
            check_pack_inflate(p, &w_curs, offset, datalen, entry->size)) {
 -              error("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
 +              error("corrupt packed object for %s",
 +                    oid_to_hex(&entry->idx.oid));
                unuse_pack(&w_curs);
                return write_no_reuse_object(f, entry, limit, usable_delta);
        }
                        return 0;
                }
                sha1write(f, header, hdrlen);
 -              sha1write(f, entry->delta->idx.sha1, 20);
 +              sha1write(f, entry->delta->idx.oid.hash, 20);
                hdrlen += 20;
                reused_delta++;
        } else {
@@@ -515,7 -510,7 +516,7 @@@ static enum write_one_status write_one(
        recursing = (e->idx.offset == 1);
        if (recursing) {
                warning("recursive delta detected for object %s",
 -                      sha1_to_hex(e->idx.sha1));
 +                      oid_to_hex(&e->idx.oid));
                return WRITE_ONE_RECURSIVE;
        } else if (e->idx.offset || e->preferred_base) {
                /* offset is non zero if object is written already. */
@@@ -1438,7 -1433,7 +1439,7 @@@ static void check_object(struct object_
                                ofs += 1;
                                if (!ofs || MSB(ofs, 7)) {
                                        error("delta base offset overflow in pack for %s",
 -                                            sha1_to_hex(entry->idx.sha1));
 +                                            oid_to_hex(&entry->idx.oid));
                                        goto give_up;
                                }
                                c = buf[used_0++];
                        ofs = entry->in_pack_offset - ofs;
                        if (ofs <= 0 || ofs >= entry->in_pack_offset) {
                                error("delta base offset out of bound for %s",
 -                                    sha1_to_hex(entry->idx.sha1));
 +                                    oid_to_hex(&entry->idx.oid));
                                goto give_up;
                        }
                        if (reuse_delta && !entry->preferred_base) {
                unuse_pack(&w_curs);
        }
  
 -      entry->type = sha1_object_info(entry->idx.sha1, &entry->size);
 +      entry->type = sha1_object_info(entry->idx.oid.hash, &entry->size);
        /*
         * The error condition is checked in prepare_pack().  This is
         * to permit a missing preferred base object to be ignored
@@@ -1520,7 -1515,7 +1521,7 @@@ static int pack_offset_sort(const void 
  
        /* avoid filesystem trashing with loose objects */
        if (!a->in_pack && !b->in_pack)
 -              return hashcmp(a->idx.sha1, b->idx.sha1);
 +              return oidcmp(&a->idx.oid, &b->idx.oid);
  
        if (a->in_pack < b->in_pack)
                return -1;
@@@ -1566,8 -1561,7 +1567,8 @@@ static void drop_reused_delta(struct ob
                 * And if that fails, the error will be recorded in entry->type
                 * and dealt with in prepare_pack().
                 */
 -              entry->type = sha1_object_info(entry->idx.sha1, &entry->size);
 +              entry->type = sha1_object_info(entry->idx.oid.hash,
 +                                             &entry->size);
        }
  }
  
@@@ -1859,29 -1853,26 +1860,29 @@@ static int try_delta(struct unpacked *t
        /* Load data if not already done */
        if (!trg->data) {
                read_lock();
 -              trg->data = read_sha1_file(trg_entry->idx.sha1, &type, &sz);
 +              trg->data = read_sha1_file(trg_entry->idx.oid.hash, &type,
 +                                         &sz);
                read_unlock();
                if (!trg->data)
                        die("object %s cannot be read",
 -                          sha1_to_hex(trg_entry->idx.sha1));
 +                          oid_to_hex(&trg_entry->idx.oid));
                if (sz != trg_size)
                        die("object %s inconsistent object length (%lu vs %lu)",
 -                          sha1_to_hex(trg_entry->idx.sha1), sz, trg_size);
 +                          oid_to_hex(&trg_entry->idx.oid), sz,
 +                          trg_size);
                *mem_usage += sz;
        }
        if (!src->data) {
                read_lock();
 -              src->data = read_sha1_file(src_entry->idx.sha1, &type, &sz);
 +              src->data = read_sha1_file(src_entry->idx.oid.hash, &type,
 +                                         &sz);
                read_unlock();
                if (!src->data) {
                        if (src_entry->preferred_base) {
                                static int warned = 0;
                                if (!warned++)
                                        warning("object %s cannot be read",
 -                                              sha1_to_hex(src_entry->idx.sha1));
 +                                              oid_to_hex(&src_entry->idx.oid));
                                /*
                                 * Those objects are not included in the
                                 * resulting pack.  Be resilient and ignore
                                return 0;
                        }
                        die("object %s cannot be read",
 -                          sha1_to_hex(src_entry->idx.sha1));
 +                          oid_to_hex(&src_entry->idx.oid));
                }
                if (sz != src_size)
                        die("object %s inconsistent object length (%lu vs %lu)",
 -                          sha1_to_hex(src_entry->idx.sha1), sz, src_size);
 +                          oid_to_hex(&src_entry->idx.oid), sz,
 +                          src_size);
                *mem_usage += sz;
        }
        if (!src->index) {
@@@ -2348,7 -2338,7 +2349,7 @@@ static void add_tag_chain(const struct 
        if (packlist_find(&to_pack, oid->hash, NULL))
                return;
  
 -      tag = lookup_tag(oid->hash);
 +      tag = lookup_tag(oid);
        while (1) {
                if (!tag || parse_tag(tag) || !tag->tagged)
                        die("unable to pack objects reachable from tag %s",
@@@ -2417,7 -2407,7 +2418,7 @@@ static void prepare_pack(int window, in
                        nr_deltas++;
                        if (entry->type < 0)
                                die("unable to get type of object %s",
 -                                  sha1_to_hex(entry->idx.sha1));
 +                                  oid_to_hex(&entry->idx.oid));
                } else {
                        if (entry->type < 0) {
                                /*
@@@ -2483,10 -2473,8 +2484,10 @@@ static int git_pack_config(const char *
                        die("invalid number of threads specified (%d)",
                            delta_search_threads);
  #ifdef NO_PTHREADS
 -              if (delta_search_threads != 1)
 +              if (delta_search_threads != 1) {
                        warning("no threads support, ignoring %s", k);
 +                      delta_search_threads = 0;
 +              }
  #endif
                return 0;
        }
@@@ -2688,7 -2676,7 +2689,7 @@@ static int has_sha1_pack_kept_or_nonloc
  static struct oid_array recent_objects;
  
  static int loosened_object_can_be_discarded(const struct object_id *oid,
 -                                          unsigned long mtime)
 +                                          timestamp_t mtime)
  {
        if (!unpack_unreachable_expiration)
                return 0;
@@@ -2730,11 -2718,7 +2731,11 @@@ static void loosen_unused_packed_object
   */
  static int pack_options_allow_reuse(void)
  {
 -      return pack_to_stdout && allow_ofs_delta;
 +      return pack_to_stdout &&
 +             allow_ofs_delta &&
 +             !ignore_packed_keep &&
 +             (!local || !have_non_local_packs) &&
 +             !incremental;
  }
  
  static int get_object_list_from_bitmap(struct rev_info *revs)
@@@ -2794,10 -2778,10 +2795,10 @@@ static void get_object_list(int ac, con
                                continue;
                        }
                        if (starts_with(line, "--shallow ")) {
 -                              unsigned char sha1[20];
 -                              if (get_sha1_hex(line + 10, sha1))
 +                              struct object_id oid;
 +                              if (get_oid_hex(line + 10, &oid))
                                        die("not an SHA-1 '%s'", line + 10);
 -                              register_shallow(sha1);
 +                              register_shallow(&oid);
                                use_bitmap_index = 0;
                                continue;
                        }
diff --combined builtin/pull.c
index 69417e4f362f6d7baa11885bd1cb8c5cbb676b14,3632921f03bb318663617b3923d8f04d21d0126e..2ce311a52eb6111fd16951c860d194dc35300438
@@@ -6,6 -6,7 +6,7 @@@
   * Fetch one or more remote refs and merge it/them into the current HEAD.
   */
  #include "cache.h"
+ #include "config.h"
  #include "builtin.h"
  #include "parse-options.h"
  #include "exec_cmd.h"
@@@ -337,7 -338,8 +338,7 @@@ static void get_merge_heads(struct oid_
        struct strbuf sb = STRBUF_INIT;
        struct object_id oid;
  
 -      if (!(fp = fopen(filename, "r")))
 -              die_errno(_("could not open '%s' for reading"), filename);
 +      fp = xfopen(filename, "r");
        while (strbuf_getline_lf(&sb, fp) != EOF) {
                if (get_oid_hex(sb.buf, &oid))
                        continue;  /* invalid line: does not start with SHA1 */
@@@ -522,7 -524,7 +523,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_SHA1_BIN, merge_head->hash, 0))
 +      if (checkout_fast_forward(&empty_tree_oid, merge_head, 0))
                return 1;
  
        if (update_ref("initial pull", "HEAD", merge_head->hash, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR))
@@@ -697,10 -699,10 +698,10 @@@ static int get_octopus_merge_base(struc
  {
        struct commit_list *revs = NULL, *result;
  
 -      commit_list_insert(lookup_commit_reference(curr_head->hash), &revs);
 -      commit_list_insert(lookup_commit_reference(merge_head->hash), &revs);
 +      commit_list_insert(lookup_commit_reference(curr_head), &revs);
 +      commit_list_insert(lookup_commit_reference(merge_head), &revs);
        if (!is_null_oid(fork_point))
 -              commit_list_insert(lookup_commit_reference(fork_point->hash), &revs);
 +              commit_list_insert(lookup_commit_reference(fork_point), &revs);
  
        result = reduce_heads(get_octopus_merge_bases(revs));
        free_commit_list(revs);
@@@ -771,7 -773,6 +772,7 @@@ int cmd_pull(int argc, const char **arg
        struct oid_array merge_heads = OID_ARRAY_INIT;
        struct object_id orig_head, curr_head;
        struct object_id rebase_fork_point;
 +      int autostash;
  
        if (!getenv("GIT_REFLOG_ACTION"))
                set_reflog_message(argc, argv);
        if (!opt_rebase && opt_autostash != -1)
                die(_("--[no-]autostash option is only valid with --rebase."));
  
 +      autostash = config_autostash;
        if (opt_rebase) {
 -              int autostash = config_autostash;
                if (opt_autostash != -1)
                        autostash = opt_autostash;
  
                        "fast-forwarding your working tree from\n"
                        "commit %s."), oid_to_hex(&orig_head));
  
 -              if (checkout_fast_forward(orig_head.hash, curr_head.hash, 0))
 +              if (checkout_fast_forward(&orig_head, &curr_head, 0))
                        die(_("Cannot fast-forward your working tree.\n"
                                "After making sure that you saved anything precious from\n"
                                "$ git diff %s\n"
                die(_("Cannot rebase onto multiple branches."));
  
        if (opt_rebase) {
 -              struct commit_list *list = NULL;
 -              struct commit *merge_head, *head;
 -
 -              head = lookup_commit_reference(orig_head.hash);
 -              commit_list_insert(head, &list);
 -              merge_head = lookup_commit_reference(merge_heads.oid[0].hash);
 -              if (is_descendant_of(merge_head, list)) {
 -                      /* we can fast-forward this without invoking rebase */
 -                      opt_ff = "--ff-only";
 -                      return run_merge();
 +              if (!autostash) {
 +                      struct commit_list *list = NULL;
 +                      struct commit *merge_head, *head;
 +
 +                      head = lookup_commit_reference(&orig_head);
 +                      commit_list_insert(head, &list);
 +                      merge_head = lookup_commit_reference(&merge_heads.oid[0]);
 +                      if (is_descendant_of(merge_head, list)) {
 +                              /* we can fast-forward this without invoking rebase */
 +                              opt_ff = "--ff-only";
 +                              return run_merge();
 +                      }
                }
                return run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
        } else {
diff --combined builtin/push.c
index 258648d5fd685f4284b3a2bbc0def0076a670b28,76aa713d22357fdd732ae86a99c49b43b0155801..03846e83795c477c8e802d078c5a5ed77140d550
@@@ -2,6 -2,7 +2,7 @@@
   * "git push"
   */
  #include "cache.h"
+ #include "config.h"
  #include "refs.h"
  #include "run-command.h"
  #include "builtin.h"
@@@ -498,10 -499,6 +499,10 @@@ static int git_push_config(const char *
                const char *value;
                if (!git_config_get_value("push.recursesubmodules", &value))
                        recurse_submodules = parse_push_recurse_submodules_arg(k, value);
 +      } else if (!strcmp(k, "submodule.recurse")) {
 +              int val = git_config_bool(k, v) ?
 +                      RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;
 +              recurse_submodules = val;
        }
  
        return git_default_config(k, v, NULL);
diff --combined builtin/read-tree.c
index 5bfd4c9f76d84c177b72a8ed97d3418d111583e9,0a85b6d938806986da06e83afeaa55a6930eca34..d5f618d086365520fcf36ed8db110ba701ba37d3
@@@ -5,6 -5,7 +5,7 @@@
   */
  
  #include "cache.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "object.h"
  #include "tree.h"
  static int nr_trees;
  static int read_empty;
  static struct tree *trees[MAX_UNPACK_TREES];
 -static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
  
 -static int list_tree(unsigned char *sha1)
 +static int list_tree(struct object_id *oid)
  {
        struct tree *tree;
  
        if (nr_trees >= MAX_UNPACK_TREES)
                die("I cannot read more than %d trees", MAX_UNPACK_TREES);
 -      tree = parse_tree_indirect(sha1);
 +      tree = parse_tree_indirect(oid);
        if (!tree)
                return -1;
        trees[nr_trees++] = tree;
@@@ -98,12 -100,21 +99,12 @@@ static int debug_merge(const struct cac
        return 0;
  }
  
 -static int option_parse_recurse_submodules(const struct option *opt,
 -                                         const char *arg, int unset)
 +static int git_read_tree_config(const char *var, const char *value, void *cb)
  {
 -      if (unset) {
 -              recurse_submodules = RECURSE_SUBMODULES_OFF;
 -              return 0;
 -      }
 -      if (arg)
 -              recurse_submodules =
 -                      parse_update_recurse_submodules_arg(opt->long_name,
 -                                                          arg);
 -      else
 -              recurse_submodules = RECURSE_SUBMODULES_ON;
 +      if (!strcmp(var, "submodule.recurse"))
 +              return git_default_submodule_config(var, value, cb);
  
 -      return 0;
 +      return git_default_config(var, value, cb);
  }
  
  static struct lock_file lock_file;
  int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
  {
        int i, stage = 0;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        struct tree_desc t[MAX_UNPACK_TREES];
        struct unpack_trees_options opts;
        int prefix_set = 0;
                         N_("skip applying sparse checkout filter")),
                OPT_BOOL(0, "debug-unpack", &opts.debug_unpack,
                         N_("debug unpack-trees")),
 -              { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules,
 +              { OPTION_CALLBACK, 0, "recurse-submodules", NULL,
                            "checkout", "control recursive updating of submodules",
 -                          PARSE_OPT_OPTARG, option_parse_recurse_submodules },
 +                          PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },
                OPT_END()
        };
  
        opts.src_index = &the_index;
        opts.dst_index = &the_index;
  
 -      git_config(git_default_config, NULL);
 +      git_config(git_read_tree_config, NULL);
  
        argc = parse_options(argc, argv, unused_prefix, read_tree_options,
                             read_tree_usage, 0);
  
 -      hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
 +      load_submodule_cache();
  
 -      if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) {
 -              gitmodules_config();
 -              git_config(submodule_config, NULL);
 -              set_config_update_recurse_submodules(RECURSE_SUBMODULES_ON);
 -      }
 +      hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
  
        prefix_set = opts.prefix ? 1 : 0;
        if (1 < opts.merge + opts.reset + prefix_set)
        for (i = 0; i < argc; i++) {
                const char *arg = argv[i];
  
 -              if (get_sha1(arg, sha1))
 +              if (get_oid(arg, &oid))
                        die("Not a valid object name %s", arg);
 -              if (list_tree(sha1) < 0)
 +              if (list_tree(&oid) < 0)
                        die("failed to unpack tree object %s", arg);
                stage++;
        }
 -      if (nr_trees == 0 && !read_empty)
 +      if (!nr_trees && !read_empty && !opts.merge)
                warning("read-tree: emptying the index with no arguments is deprecated; use --empty");
        else if (nr_trees > 0 && read_empty)
                die("passing trees as arguments contradicts --empty");
                setup_work_tree();
  
        if (opts.merge) {
 -              if (stage < 2)
 -                      die("just how do you expect me to merge %d trees?", stage-1);
                switch (stage - 1) {
 +              case 0:
 +                      die("you must specify at least one tree to merge");
 +                      break;
                case 1:
                        opts.fn = opts.prefix ? bind_merge : oneway_merge;
                        break;
diff --combined builtin/receive-pack.c
index b1706a5731c0e527a8abc1d42ac4f0e6d346c47c,01ae7154e681cd249bdee78507311274fe568628..71c0c768db92378b824951acd6efb7179438017b
@@@ -1,4 -1,5 +1,5 @@@
  #include "builtin.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "pack.h"
  #include "refs.h"
@@@ -78,7 -79,7 +79,7 @@@ static const char *NONCE_OK = "OK"
  static const char *NONCE_SLOP = "SLOP";
  static const char *nonce_status;
  static long nonce_stamp_slop;
 -static unsigned long nonce_stamp_slop_limit;
 +static timestamp_t nonce_stamp_slop_limit;
  static struct ref_transaction *transaction;
  
  static enum {
@@@ -454,17 -455,17 +455,17 @@@ static void hmac_sha1(unsigned char *ou
        git_SHA1_Final(out, &ctx);
  }
  
 -static char *prepare_push_cert_nonce(const char *path, unsigned long stamp)
 +static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)
  {
        struct strbuf buf = STRBUF_INIT;
        unsigned char sha1[20];
  
 -      strbuf_addf(&buf, "%s:%lu", path, stamp);
 +      strbuf_addf(&buf, "%s:%"PRItime, path, stamp);
        hmac_sha1(sha1, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));;
        strbuf_release(&buf);
  
        /* RFC 2104 5. HMAC-SHA1-80 */
 -      strbuf_addf(&buf, "%lu-%.*s", stamp, 20, sha1_to_hex(sha1));
 +      strbuf_addf(&buf, "%"PRItime"-%.*s", stamp, 20, sha1_to_hex(sha1));
        return strbuf_detach(&buf, NULL);
  }
  
   * after dropping "_commit" from its name and possibly moving it out
   * of commit.c
   */
 -static char *find_header(const char *msg, size_t len, const char *key)
 +static char *find_header(const char *msg, size_t len, const char *key,
 +                       const char **next_line)
  {
        int key_len = strlen(key);
        const char *line = msg;
                if (line + key_len < eol &&
                    !memcmp(line, key, key_len) && line[key_len] == ' ') {
                        int offset = key_len + 1;
 +                      if (next_line)
 +                              *next_line = *eol ? eol + 1 : eol;
                        return xmemdupz(line + offset, (eol - line) - offset);
                }
                line = *eol ? eol + 1 : NULL;
  
  static const char *check_nonce(const char *buf, size_t len)
  {
 -      char *nonce = find_header(buf, len, "nonce");
 -      unsigned long stamp, ostamp;
 +      char *nonce = find_header(buf, len, "nonce", NULL);
 +      timestamp_t stamp, ostamp;
        char *bohmac, *expect = NULL;
        const char *retval = NONCE_BAD;
  
                retval = NONCE_BAD;
                goto leave;
        }
 -      stamp = strtoul(nonce, &bohmac, 10);
 +      stamp = parse_timestamp(nonce, &bohmac, 10);
        if (bohmac == nonce || bohmac[0] != '-') {
                retval = NONCE_BAD;
                goto leave;
         * would mean it was issued by another server with its clock
         * skewed in the future.
         */
 -      ostamp = strtoul(push_cert_nonce, NULL, 10);
 +      ostamp = parse_timestamp(push_cert_nonce, NULL, 10);
        nonce_stamp_slop = (long)ostamp - (long)stamp;
  
        if (nonce_stamp_slop_limit &&
@@@ -578,45 -576,6 +579,45 @@@ leave
        return retval;
  }
  
 +/*
 + * Return 1 if there is no push_cert or if the push options in push_cert are
 + * the same as those in the argument; 0 otherwise.
 + */
 +static int check_cert_push_options(const struct string_list *push_options)
 +{
 +      const char *buf = push_cert.buf;
 +      int len = push_cert.len;
 +
 +      char *option;
 +      const char *next_line;
 +      int options_seen = 0;
 +
 +      int retval = 1;
 +
 +      if (!len)
 +              return 1;
 +
 +      while ((option = find_header(buf, len, "push-option", &next_line))) {
 +              len -= (next_line - buf);
 +              buf = next_line;
 +              options_seen++;
 +              if (options_seen > push_options->nr
 +                  || strcmp(option,
 +                            push_options->items[options_seen - 1].string)) {
 +                      retval = 0;
 +                      goto leave;
 +              }
 +              free(option);
 +      }
 +
 +      if (options_seen != push_options->nr)
 +              retval = 0;
 +
 +leave:
 +      free(option);
 +      return retval;
 +}
 +
  static void prepare_push_cert_sha1(struct child_process *proc)
  {
        static int already_done;
@@@ -900,7 -859,7 +901,7 @@@ static int update_shallow_ref(struct co
         * not lose these new roots..
         */
        for (i = 0; i < extra.nr; i++)
 -              register_shallow(extra.oid[i].hash);
 +              register_shallow(&extra.oid[i]);
  
        si->shallow_ref[cmd->index] = 0;
        oid_array_clear(&extra);
@@@ -1028,8 -987,7 +1029,8 @@@ static const char *update(struct comman
  {
        const char *name = cmd->ref_name;
        struct strbuf namespaced_name_buf = STRBUF_INIT;
 -      const char *namespaced_name, *ret;
 +      static char *namespaced_name;
 +      const char *ret;
        struct object_id *old_oid = &cmd->old_oid;
        struct object_id *new_oid = &cmd->new_oid;
  
        }
  
        strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
 +      free(namespaced_name);
        namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
  
        if (is_ref_checked_out(namespaced_name)) {
                struct object *old_object, *new_object;
                struct commit *old_commit, *new_commit;
  
 -              old_object = parse_object(old_oid->hash);
 -              new_object = parse_object(new_oid->hash);
 +              old_object = parse_object(old_oid);
 +              new_object = parse_object(new_oid);
  
                if (!old_object || !new_object ||
                    old_object->type != OBJ_COMMIT ||
  
        if (is_null_oid(new_oid)) {
                struct strbuf err = STRBUF_INIT;
 -              if (!parse_object(old_oid->hash)) {
 +              if (!parse_object(old_oid)) {
                        old_oid = NULL;
                        if (ref_exists(name)) {
                                rp_warning("Allowing deletion of corrupt ref.");
@@@ -1973,11 -1930,6 +1974,11 @@@ int cmd_receive_pack(int argc, const ch
  
                if (use_push_options)
                        read_push_options(&push_options);
 +              if (!check_cert_push_options(&push_options)) {
 +                      struct command *cmd;
 +                      for (cmd = commands; cmd; cmd = cmd->next)
 +                              cmd->error_string = "inconsistent push options";
 +              }
  
                prepare_shallow_info(&si, &shallow);
                if (!si.nr_ours && !si.nr_theirs)
diff --combined builtin/reflog.c
index 920c16dac025b0f5650b0f91511c22359d5bda2d,6e9a8213ea6ab2bbfec95cc24bcc72af8f25dea2..44cdc2dbd0cbf64be1672428e930223425ed7b04
@@@ -1,4 -1,5 +1,5 @@@
  #include "builtin.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "commit.h"
  #include "refs.h"
@@@ -16,14 -17,14 +17,14 @@@ static const char reflog_delete_usage[
  static const char reflog_exists_usage[] =
  "git reflog exists <ref>";
  
 -static unsigned long default_reflog_expire;
 -static unsigned long default_reflog_expire_unreachable;
 +static timestamp_t default_reflog_expire;
 +static timestamp_t default_reflog_expire_unreachable;
  
  struct cmd_reflog_expire_cb {
        struct rev_info revs;
        int stalefix;
 -      unsigned long expire_total;
 -      unsigned long expire_unreachable;
 +      timestamp_t expire_total;
 +      timestamp_t expire_unreachable;
        int recno;
  };
  
@@@ -55,14 -56,14 +56,14 @@@ struct collect_reflog_cb 
  #define STUDYING      (1u<<11)
  #define REACHABLE     (1u<<12)
  
 -static int tree_is_complete(const unsigned char *sha1)
 +static int tree_is_complete(const struct object_id *oid)
  {
        struct tree_desc desc;
        struct name_entry entry;
        int complete;
        struct tree *tree;
  
 -      tree = lookup_tree(sha1);
 +      tree = lookup_tree(oid);
        if (!tree)
                return 0;
        if (tree->object.flags & SEEN)
@@@ -73,7 -74,7 +74,7 @@@
        if (!tree->buffer) {
                enum object_type type;
                unsigned long size;
 -              void *data = read_sha1_file(sha1, &type, &size);
 +              void *data = read_sha1_file(oid->hash, &type, &size);
                if (!data) {
                        tree->object.flags |= INCOMPLETE;
                        return 0;
@@@ -85,7 -86,7 +86,7 @@@
        complete = 1;
        while (tree_entry(&desc, &entry)) {
                if (!has_sha1_file(entry.oid->hash) ||
 -                  (S_ISDIR(entry.mode) && !tree_is_complete(entry.oid->hash))) {
 +                  (S_ISDIR(entry.mode) && !tree_is_complete(entry.oid))) {
                        tree->object.flags |= INCOMPLETE;
                        complete = 0;
                }
@@@ -126,7 -127,7 +127,7 @@@ static int commit_is_complete(struct co
                struct commit_list *parent;
  
                c = (struct commit *)study.objects[--study.nr].item;
 -              if (!c->object.parsed && !parse_object(c->object.oid.hash))
 +              if (!c->object.parsed && !parse_object(&c->object.oid))
                        c->object.flags |= INCOMPLETE;
  
                if (c->object.flags & INCOMPLETE) {
                for (i = 0; i < found.nr; i++) {
                        struct commit *c =
                                (struct commit *)found.objects[i].item;
 -                      if (!tree_is_complete(c->tree->object.oid.hash)) {
 +                      if (!tree_is_complete(&c->tree->object.oid)) {
                                is_incomplete = 1;
                                c->object.flags |= INCOMPLETE;
                        }
        return !is_incomplete;
  }
  
 -static int keep_entry(struct commit **it, unsigned char *sha1)
 +static int keep_entry(struct commit **it, struct object_id *oid)
  {
        struct commit *commit;
  
 -      if (is_null_sha1(sha1))
 +      if (is_null_oid(oid))
                return 1;
 -      commit = lookup_commit_reference_gently(sha1, 1);
 +      commit = lookup_commit_reference_gently(oid, 1);
        if (!commit)
                return 0;
  
  static void mark_reachable(struct expire_reflog_policy_cb *cb)
  {
        struct commit_list *pending;
 -      unsigned long expire_limit = cb->mark_limit;
 +      timestamp_t expire_limit = cb->mark_limit;
        struct commit_list *leftover = NULL;
  
        for (pending = cb->mark_list; pending; pending = pending->next)
        cb->mark_list = leftover;
  }
  
 -static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, unsigned char *sha1)
 +static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, struct object_id *oid)
  {
        /*
         * We may or may not have the commit yet - if not, look it
         * up using the supplied sha1.
         */
        if (!commit) {
 -              if (is_null_sha1(sha1))
 +              if (is_null_oid(oid))
                        return 0;
  
 -              commit = lookup_commit_reference_gently(sha1, 1);
 +              commit = lookup_commit_reference_gently(oid, 1);
  
                /* Not a commit -- keep it */
                if (!commit)
  /*
   * Return true iff the specified reflog entry should be expired.
   */
 -static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
 -                                  const char *email, unsigned long timestamp, int tz,
 +static int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
 +                                  const char *email, timestamp_t timestamp, int tz,
                                    const char *message, void *cb_data)
  {
        struct expire_reflog_policy_cb *cb = cb_data;
  
        old = new = NULL;
        if (cb->cmd.stalefix &&
 -          (!keep_entry(&old, osha1) || !keep_entry(&new, nsha1)))
 +          (!keep_entry(&old, ooid) || !keep_entry(&new, noid)))
                return 1;
  
        if (timestamp < cb->cmd.expire_unreachable) {
                if (cb->unreachable_expire_kind == UE_ALWAYS)
                        return 1;
 -              if (unreachable(cb, old, osha1) || unreachable(cb, new, nsha1))
 +              if (unreachable(cb, old, ooid) || unreachable(cb, new, noid))
                        return 1;
        }
  
@@@ -318,7 -319,7 +319,7 @@@ static int push_tip_to_list(const char 
        struct commit *tip_commit;
        if (flags & REF_ISSYMREF)
                return 0;
 -      tip_commit = lookup_commit_reference_gently(oid->hash, 1);
 +      tip_commit = lookup_commit_reference_gently(oid, 1);
        if (!tip_commit)
                return 0;
        commit_list_insert(tip_commit, list);
  }
  
  static void reflog_expiry_prepare(const char *refname,
 -                                const unsigned char *sha1,
 +                                const struct object_id *oid,
                                  void *cb_data)
  {
        struct expire_reflog_policy_cb *cb = cb_data;
                cb->tip_commit = NULL;
                cb->unreachable_expire_kind = UE_HEAD;
        } else {
 -              cb->tip_commit = lookup_commit_reference_gently(sha1, 1);
 +              cb->tip_commit = lookup_commit_reference_gently(oid, 1);
                if (!cb->tip_commit)
                        cb->unreachable_expire_kind = UE_ALWAYS;
                else
@@@ -392,8 -393,8 +393,8 @@@ static int collect_reflog(const char *r
  
  static struct reflog_expire_cfg {
        struct reflog_expire_cfg *next;
 -      unsigned long expire_total;
 -      unsigned long expire_unreachable;
 +      timestamp_t expire_total;
 +      timestamp_t expire_unreachable;
        char pattern[FLEX_ARRAY];
  } *reflog_expire_cfg, **reflog_expire_cfg_tail;
  
@@@ -415,7 -416,7 +416,7 @@@ static struct reflog_expire_cfg *find_c
        return ent;
  }
  
 -static int parse_expire_cfg_value(const char *var, const char *value, unsigned long *expire)
 +static int parse_expire_cfg_value(const char *var, const char *value, timestamp_t *expire)
  {
        if (!value)
                return config_error_nonbool(var);
@@@ -433,7 -434,7 +434,7 @@@ static int reflog_expire_config(const c
  {
        const char *pattern, *key;
        int pattern_len;
 -      unsigned long expire;
 +      timestamp_t expire;
        int slot;
        struct reflog_expire_cfg *ent;
  
@@@ -515,7 -516,7 +516,7 @@@ static void set_reflog_expiry_param(str
  static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
  {
        struct expire_reflog_policy_cb cb;
 -      unsigned long now = time(NULL);
 +      timestamp_t now = time(NULL);
        int i, status, do_all;
        int explicit_expiry = 0;
        unsigned int flags = 0;
  }
  
  static int count_reflog_ent(struct object_id *ooid, struct object_id *noid,
 -              const char *email, unsigned long timestamp, int tz,
 +              const char *email, timestamp_t timestamp, int tz,
                const char *message, void *cb_data)
  {
        struct expire_reflog_policy_cb *cb = cb_data;
diff --combined builtin/remote.c
index f1a88fe2658986af2e33d3979af1764f6decc43b,a470ed7c628254f76b3e6a46c889e66097f48f4f..6273c0c23c904d5f789ff794458cf0c3f2661d94
@@@ -1,4 -1,5 +1,5 @@@
  #include "builtin.h"
+ #include "config.h"
  #include "parse-options.h"
  #include "transport.h"
  #include "remote.h"
@@@ -786,7 -787,7 +787,7 @@@ static int rm(int argc, const char **ar
        strbuf_release(&buf);
  
        if (!result)
 -              result = delete_refs(&branches, REF_NODEREF);
 +              result = delete_refs("remote: remove", &branches, REF_NODEREF);
        string_list_clear(&branches, 0);
  
        if (skipped.nr) {
@@@ -1151,11 -1152,8 +1152,11 @@@ static int show(int argc, const char **
                        url_nr = states.remote->url_nr;
                }
                for (i = 0; i < url_nr; i++)
 -                      /* TRANSLATORS: the colon ':' should align with
 -                         the one in "  Fetch URL: %s" translation */
 +                      /*
 +                       * TRANSLATORS: the colon ':' should align
 +                       * with the one in " Fetch URL: %s"
 +                       * translation.
 +                       */
                        printf_ln(_("  Push  URL: %s"), url[i]);
                if (!i)
                        printf_ln(_("  Push  URL: %s"), _("(no URL)"));
@@@ -1304,7 -1302,7 +1305,7 @@@ static int prune_remote(const char *rem
        string_list_sort(&refs_to_prune);
  
        if (!dry_run)
 -              result |= delete_refs(&refs_to_prune, 0);
 +              result |= delete_refs("remote: prune", &refs_to_prune, 0);
  
        for_each_string_list_item(item, &states.stale) {
                const char *refname = item->util;
diff --combined builtin/repack.c
index 38ba4ef825ebf4791afb50e72e69bdb61db2aa14,c01ff7c30b20ae3866c81ada2aa859eb9c13cdee..f17a68a17da960813e6e925837638a5d9a26d5ee
@@@ -1,5 -1,6 +1,6 @@@
  #include "builtin.h"
  #include "cache.h"
+ #include "config.h"
  #include "dir.h"
  #include "parse-options.h"
  #include "run-command.h"
@@@ -155,7 -156,6 +156,7 @@@ int cmd_repack(int argc, const char **a
        int keep_unreachable = 0;
        const char *window = NULL, *window_memory = NULL;
        const char *depth = NULL;
 +      const char *threads = NULL;
        const char *max_pack_size = NULL;
        int no_reuse_delta = 0, no_reuse_object = 0;
        int no_update_server_info = 0;
                                N_("same as the above, but limit memory size instead of entries count")),
                OPT_STRING(0, "depth", &depth, N_("n"),
                                N_("limits the maximum delta depth")),
 +              OPT_STRING(0, "threads", &threads, N_("n"),
 +                              N_("limits the maximum number of threads")),
                OPT_STRING(0, "max-pack-size", &max_pack_size, N_("bytes"),
                                N_("maximum size of each packfile")),
                OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects,
                argv_array_pushf(&cmd.args, "--window-memory=%s", window_memory);
        if (depth)
                argv_array_pushf(&cmd.args, "--depth=%s", depth);
 +      if (threads)
 +              argv_array_pushf(&cmd.args, "--threads=%s", threads);
        if (max_pack_size)
                argv_array_pushf(&cmd.args, "--max-pack-size=%s", max_pack_size);
        if (no_reuse_delta)
diff --combined builtin/replace.c
index c921bc976f2299adc39277a21a74abbcc0c100f7,905b1759a4ae4f6819770c832c0b28b7e5fde086..80a15cf35f3fa5a1a7c038924a84e34fdc15aa0b
@@@ -9,6 -9,7 +9,7 @@@
   */
  
  #include "cache.h"
+ #include "config.h"
  #include "builtin.h"
  #include "refs.h"
  #include "parse-options.h"
@@@ -328,7 -329,7 +329,7 @@@ static void replace_parents(struct strb
                struct object_id oid;
                if (get_oid(argv[i], &oid) < 0)
                        die(_("Not a valid object name: '%s'"), argv[i]);
 -              lookup_commit_or_die(oid.hash, argv[i]);
 +              lookup_commit_or_die(&oid, argv[i]);
                strbuf_addf(&new_parents, "parent %s\n", oid_to_hex(&oid));
        }
  
@@@ -355,7 -356,7 +356,7 @@@ static void check_one_mergetag(struct c
        int i;
  
        hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), tag_oid.hash);
 -      tag = lookup_tag(tag_oid.hash);
 +      tag = lookup_tag(&tag_oid);
        if (!tag)
                die(_("bad mergetag in commit '%s'"), ref);
        if (parse_tag_buffer(tag, extra->value, extra->len))
@@@ -394,7 -395,7 +395,7 @@@ static int create_graft(int argc, cons
  
        if (get_oid(old_ref, &old) < 0)
                die(_("Not a valid object name: '%s'"), old_ref);
 -      commit = lookup_commit_or_die(old.hash, old_ref);
 +      commit = lookup_commit_or_die(&old, old_ref);
  
        buffer = get_commit_buffer(commit, &size);
        strbuf_add(&buf, buffer, size);
diff --combined builtin/reset.c
index 45001e5200cb4c5aaf0ad316cf1622f9495d851d,fdd5e5e003484b97a9915540642c34943abb1423..7aeaea2737991f021eb788708c1710305abb4b08
@@@ -8,6 -8,7 +8,7 @@@
   * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
   */
  #include "builtin.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "tag.h"
  #include "object.h"
@@@ -21,8 -22,6 +22,8 @@@
  #include "parse-options.h"
  #include "unpack-trees.h"
  #include "cache-tree.h"
 +#include "submodule.h"
 +#include "submodule-config.h"
  
  static const char * const git_reset_usage[] = {
        N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
@@@ -86,7 -85,7 +87,7 @@@ static int reset_index(const struct obj
                return -1;
  
        if (reset_type == MIXED || reset_type == HARD) {
 -              tree = parse_tree_indirect(oid->hash);
 +              tree = parse_tree_indirect(oid);
                prime_cache_tree(&the_index, tree);
        }
  
@@@ -156,7 -155,7 +157,7 @@@ static int read_from_tree(const struct 
        opt.format_callback = update_index_from_diff;
        opt.format_callback_data = &intent_to_add;
  
 -      if (do_diff_cache(tree_oid->hash, &opt))
 +      if (do_diff_cache(tree_oid, &opt))
                return 1;
        diffcore_std(&opt);
        diff_flush(&opt);
@@@ -238,6 -237,7 +239,6 @@@ static void parse_args(struct pathspec 
  
        parse_pathspec(pathspec, 0,
                       PATHSPEC_PREFER_FULL |
 -                     PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP |
                       (patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0),
                       prefix, argv);
  }
@@@ -265,14 -265,6 +266,14 @@@ static int reset_refs(const char *rev, 
        return update_ref_status;
  }
  
 +static int git_reset_config(const char *var, const char *value, void *cb)
 +{
 +      if (!strcmp(var, "submodule.recurse"))
 +              return git_default_submodule_config(var, value, cb);
 +
 +      return git_default_config(var, value, cb);
 +}
 +
  int cmd_reset(int argc, const char **argv, const char *prefix)
  {
        int reset_type = NONE, update_ref_status = 0, quiet = 0;
                                N_("reset HEAD, index and working tree"), MERGE),
                OPT_SET_INT(0, "keep", &reset_type,
                                N_("reset HEAD but keep local changes"), KEEP),
 +              { OPTION_CALLBACK, 0, "recurse-submodules", NULL,
 +                          "reset", "control recursive updating of submodules",
 +                          PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },
                OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
                OPT_BOOL('N', "intent-to-add", &intent_to_add,
                                N_("record only the fact that removed paths will be added later")),
                OPT_END()
        };
  
 -      git_config(git_default_config, NULL);
 +      git_config(git_reset_config, NULL);
  
        argc = parse_options(argc, argv, prefix, options, git_reset_usage,
                                                PARSE_OPT_KEEP_DASHDASH);
        parse_args(&pathspec, argv, prefix, patch_mode, &rev);
  
 +      load_submodule_cache();
 +
        unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", oid.hash);
        if (unborn) {
                /* reset on unborn branch: treat as reset to empty tree */
                struct commit *commit;
                if (get_sha1_committish(rev, oid.hash))
                        die(_("Failed to resolve '%s' as a valid revision."), rev);
 -              commit = lookup_commit_reference(oid.hash);
 +              commit = lookup_commit_reference(&oid);
                if (!commit)
                        die(_("Could not parse object '%s'."), rev);
                oidcpy(&oid, &commit->object.oid);
                struct tree *tree;
                if (get_sha1_treeish(rev, oid.hash))
                        die(_("Failed to resolve '%s' as a valid tree."), rev);
 -              tree = parse_tree_indirect(oid.hash);
 +              tree = parse_tree_indirect(&oid);
                if (!tree)
                        die(_("Could not parse object '%s'."), rev);
                oidcpy(&oid, &tree->object.oid);
                update_ref_status = reset_refs(rev, &oid);
  
                if (reset_type == HARD && !update_ref_status && !quiet)
 -                      print_new_head_line(lookup_commit_reference(oid.hash));
 +                      print_new_head_line(lookup_commit_reference(&oid));
        }
        if (!pathspec.nr)
                remove_branch_state();
diff --combined builtin/rev-list.c
index b250c515b1aecab2b43aebe591ad7a22d5829271,f9e2caee16c4295f2acdddc9565406cccb5073d1..95d84d5cda1bdb6a699bc74ad57f7f1910946440
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "commit.h"
  #include "diff.h"
  #include "revision.h"
@@@ -80,7 -81,7 +81,7 @@@ static void show_commit(struct commit *
        }
  
        if (info->show_timestamp)
 -              printf("%lu ", commit->date);
 +              printf("%"PRItime" ", commit->date);
        if (info->header_prefix)
                fputs(info->header_prefix, stdout);
  
@@@ -181,7 -182,7 +182,7 @@@ static void finish_object(struct objec
        if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid))
                die("missing blob object '%s'", oid_to_hex(&obj->oid));
        if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT)
 -              parse_object(obj->oid.hash);
 +              parse_object(&obj->oid);
  }
  
  static void show_object(struct object *obj, const char *name, void *cb_data)
@@@ -277,9 -278,6 +278,9 @@@ int cmd_rev_list(int argc, const char *
        int use_bitmap_index = 0;
        const char *show_progress = NULL;
  
 +      if (argc == 2 && !strcmp(argv[1], "-h"))
 +              usage(rev_list_usage);
 +
        git_config(git_default_config, NULL);
        init_revisions(&revs, prefix);
        revs.abbrev = DEFAULT_ABBREV;
diff --combined builtin/rev-parse.c
index efdc14473be53ff79b13012d650ec5fded052fd9,9d18bbd648bcf39b9406ced43a731fe08e83c8b0..c78b7b33d6604bb38a16e30d64cfabee0fd67f40
@@@ -4,6 -4,7 +4,7 @@@
   * Copyright (C) Linus Torvalds, 2005
   */
  #include "cache.h"
+ #include "config.h"
  #include "commit.h"
  #include "refs.h"
  #include "quote.h"
@@@ -121,7 -122,7 +122,7 @@@ static void show_with_type(int type, co
  }
  
  /* Output a revision, only if filter allows it */
 -static void show_rev(int type, const unsigned char *sha1, const char *name)
 +static void show_rev(int type, const struct object_id *oid, const char *name)
  {
        if (!(filter & DO_REVS))
                return;
  
        if ((symbolic || abbrev_ref) && name) {
                if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) {
 -                      unsigned char discard[20];
 +                      struct object_id discard;
                        char *full;
  
 -                      switch (dwim_ref(name, strlen(name), discard, &full)) {
 +                      switch (dwim_ref(name, strlen(name), discard.hash, &full)) {
                        case 0:
                                /*
                                 * Not found -- not a ref.  We could
                }
        }
        else if (abbrev)
 -              show_with_type(type, find_unique_abbrev(sha1, abbrev));
 +              show_with_type(type, find_unique_abbrev(oid->hash, abbrev));
        else
 -              show_with_type(type, sha1_to_hex(sha1));
 +              show_with_type(type, oid_to_hex(oid));
  }
  
  /* Output a flag, only if filter allows it. */
@@@ -180,11 -181,11 +181,11 @@@ static int show_default(void
        const char *s = def;
  
        if (s) {
 -              unsigned char sha1[20];
 +              struct object_id oid;
  
                def = NULL;
 -              if (!get_sha1(s, sha1)) {
 -                      show_rev(NORMAL, sha1, s);
 +              if (!get_oid(s, &oid)) {
 +                      show_rev(NORMAL, &oid, s);
                        return 1;
                }
        }
@@@ -195,19 -196,19 +196,19 @@@ static int show_reference(const char *r
  {
        if (ref_excluded(ref_excludes, refname))
                return 0;
 -      show_rev(NORMAL, oid->hash, refname);
 +      show_rev(NORMAL, oid, refname);
        return 0;
  }
  
  static int anti_reference(const char *refname, const struct object_id *oid, int flag, void *cb_data)
  {
 -      show_rev(REVERSED, oid->hash, refname);
 +      show_rev(REVERSED, oid, refname);
        return 0;
  }
  
  static int show_abbrev(const struct object_id *oid, void *cb_data)
  {
 -      show_rev(NORMAL, oid->hash, NULL);
 +      show_rev(NORMAL, oid, NULL);
        return 0;
  }
  
@@@ -218,7 -219,7 +219,7 @@@ static void show_datestring(const char 
        /* date handling requires both flags and revs */
        if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))
                return;
 -      buffer = xstrfmt("%s%lu", flag, approxidate(datestr));
 +      buffer = xstrfmt("%s%"PRItime, flag, approxidate(datestr));
        show(buffer);
        free(buffer);
  }
@@@ -242,8 -243,8 +243,8 @@@ static int show_file(const char *arg, i
  static int try_difference(const char *arg)
  {
        char *dotdot;
 -      unsigned char sha1[20];
 -      unsigned char end[20];
 +      struct object_id oid;
 +      struct object_id end;
        const char *next;
        const char *this;
        int symmetric;
                return 0;
        }
  
 -      if (!get_sha1_committish(this, sha1) && !get_sha1_committish(next, end)) {
 -              show_rev(NORMAL, end, next);
 -              show_rev(symmetric ? NORMAL : REVERSED, sha1, this);
 +      if (!get_sha1_committish(this, oid.hash) && !get_sha1_committish(next, end.hash)) {
 +              show_rev(NORMAL, &end, next);
 +              show_rev(symmetric ? NORMAL : REVERSED, &oid, this);
                if (symmetric) {
                        struct commit_list *exclude;
                        struct commit *a, *b;
 -                      a = lookup_commit_reference(sha1);
 -                      b = lookup_commit_reference(end);
 +                      a = lookup_commit_reference(&oid);
 +                      b = lookup_commit_reference(&end);
                        exclude = get_merge_bases(a, b);
                        while (exclude) {
                                struct commit *commit = pop_commit(&exclude);
 -                              show_rev(REVERSED, commit->object.oid.hash, NULL);
 +                              show_rev(REVERSED, &commit->object.oid, NULL);
                        }
                }
                *dotdot = '.';
  static int try_parent_shorthands(const char *arg)
  {
        char *dotdot;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        struct commit *commit;
        struct commit_list *parents;
        int parent_number;
                return 0;
  
        *dotdot = 0;
 -      if (get_sha1_committish(arg, sha1)) {
 +      if (get_sha1_committish(arg, oid.hash)) {
                *dotdot = '^';
                return 0;
        }
  
 -      commit = lookup_commit_reference(sha1);
 +      commit = lookup_commit_reference(&oid);
        if (exclude_parent &&
            exclude_parent > commit_list_count(commit->parents)) {
                *dotdot = '^';
        }
  
        if (include_rev)
 -              show_rev(NORMAL, sha1, arg);
 +              show_rev(NORMAL, &oid, arg);
        for (parents = commit->parents, parent_number = 1;
             parents;
             parents = parents->next, parent_number++) {
                if (symbolic)
                        name = xstrfmt("%s^%d", arg, parent_number);
                show_rev(include_parents ? NORMAL : REVERSED,
 -                       parents->item->object.oid.hash, name);
 +                       &parents->item->object.oid, name);
                free(name);
        }
  
@@@ -571,7 -572,7 +572,7 @@@ int cmd_rev_parse(int argc, const char 
        int did_repo_setup = 0;
        int has_dashdash = 0;
        int output_prefix = 0;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        unsigned int flags = 0;
        const char *name = NULL;
        struct object_context unused;
                        name++;
                        type = REVERSED;
                }
 -              if (!get_sha1_with_context(name, flags, sha1, &unused)) {
 +              if (!get_sha1_with_context(name, flags, oid.hash, &unused)) {
                        if (verify)
                                revs_count++;
                        else
 -                              show_rev(type, sha1, name);
 +                              show_rev(type, &oid, name);
                        continue;
                }
                if (verify)
        strbuf_release(&buf);
        if (verify) {
                if (revs_count == 1) {
 -                      show_rev(type, sha1, name);
 +                      show_rev(type, &oid, name);
                        return 0;
                } else if (revs_count == 0 && show_default())
                        return 0;
diff --combined builtin/rm.c
index b39f10fcb64f047090967dbf8b31120d2beb1b67,b1adf1c961632336b1f630e4b3c8d085006d4431..52826d137935ca6698006258ebdb8b207f7161df
@@@ -4,6 -4,7 +4,7 @@@
   * Copyright (C) Linus Torvalds 2006
   */
  #include "builtin.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "dir.h"
  #include "cache-tree.h"
@@@ -129,7 -130,7 +130,7 @@@ static int check_local_mod(struct objec
                ce = active_cache[pos];
  
                if (lstat(ce->name, &st) < 0) {
 -                      if (errno != ENOENT && errno != ENOTDIR)
 +                      if (!is_missing_file_error(errno))
                                warning_errno(_("failed to stat '%s'"), ce->name);
                        /* It already vanished from the working tree */
                        continue;
@@@ -271,7 -272,8 +272,7 @@@ int cmd_rm(int argc, const char **argv
                die(_("index file corrupt"));
  
        parse_pathspec(&pathspec, 0,
 -                     PATHSPEC_PREFER_CWD |
 -                     PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
 +                     PATHSPEC_PREFER_CWD,
                       prefix, argv);
        refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL);
  
diff --combined builtin/show-branch.c
index 3636a05594de18639bced97a1e18a128632bc00d,68254399709c2a0cddfb42717831e198e511ae68..527f69e283fd592c7b862b4ad6467d08d33e561c
@@@ -1,11 -1,11 +1,12 @@@
  #include "cache.h"
+ #include "config.h"
  #include "commit.h"
  #include "refs.h"
  #include "builtin.h"
  #include "color.h"
  #include "argv-array.h"
  #include "parse-options.h"
 +#include "dir.h"
  
  static const char* show_branch_usage[] = {
      N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
@@@ -359,7 -359,7 +360,7 @@@ static void sort_ref_range(int bottom, 
  static int append_ref(const char *refname, const struct object_id *oid,
                      int allow_dups)
  {
 -      struct commit *commit = lookup_commit_reference_gently(oid->hash, 1);
 +      struct commit *commit = lookup_commit_reference_gently(oid, 1);
        int i;
  
        if (!commit)
@@@ -422,6 -422,14 +423,6 @@@ static int append_tag_ref(const char *r
  
  static const char *match_ref_pattern = NULL;
  static int match_ref_slash = 0;
 -static int count_slash(const char *s)
 -{
 -      int cnt = 0;
 -      while (*s)
 -              if (*s++ == '/')
 -                      cnt++;
 -      return cnt;
 -}
  
  static int append_matching_ref(const char *refname, const struct object_id *oid,
                               int flag, void *cb_data)
         * refs/tags/v0.99.9a and friends.
         */
        const char *tail;
 -      int slash = count_slash(refname);
 +      int slash = count_slashes(refname);
        for (tail = refname; *tail && match_ref_slash < slash; )
                if (*tail++ == '/')
                        slash--;
@@@ -522,7 -530,7 +523,7 @@@ static void append_one_rev(const char *
                int saved_matches = ref_name_cnt;
  
                match_ref_pattern = av;
 -              match_ref_slash = count_slash(av);
 +              match_ref_slash = count_slashes(av);
                for_each_ref(append_matching_ref, NULL);
                if (saved_matches == ref_name_cnt &&
                    ref_name_cnt < MAX_REVS)
@@@ -728,7 -736,7 +729,7 @@@ int cmd_show_branch(int ac, const char 
                        base = strtoul(reflog_base, &ep, 10);
                        if (*ep) {
                                /* Ah, that is a date spec... */
 -                              unsigned long at;
 +                              timestamp_t at;
                                at = approxidate(reflog_base);
                                read_ref_at(ref, flags, at, -1, oid.hash, NULL,
                                            NULL, NULL, &base);
                        char *logmsg;
                        char *nth_desc;
                        const char *msg;
 -                      unsigned long timestamp;
 +                      timestamp_t timestamp;
                        int tz;
  
                        if (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,
                               MAX_REVS), MAX_REVS);
                if (get_sha1(ref_name[num_rev], revkey.hash))
                        die(_("'%s' is not a valid ref."), ref_name[num_rev]);
 -              commit = lookup_commit_reference(revkey.hash);
 +              commit = lookup_commit_reference(&revkey);
                if (!commit)
                        die(_("cannot find commit %s (%s)"),
                            ref_name[num_rev], oid_to_hex(&revkey));
index 1b4d2b346762af8e6150d88fed87409e877ca676,700460c3498abbad9e3f087ee50bc5dd8f513b1b..8517032b3e08ded36075ded55dac8ae219cfbc59
@@@ -1,5 -1,6 +1,6 @@@
  #include "builtin.h"
  #include "cache.h"
+ #include "config.h"
  #include "parse-options.h"
  #include "quote.h"
  #include "pathspec.h"
@@@ -233,7 -234,8 +234,7 @@@ static int module_list_compute(int argc
        int i, result = 0;
        char *ps_matched = NULL;
        parse_pathspec(pathspec, 0,
 -                     PATHSPEC_PREFER_FULL |
 -                     PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
 +                     PATHSPEC_PREFER_FULL,
                       prefix, argv);
  
        if (pathspec->nr)
@@@ -1221,8 -1223,9 +1222,8 @@@ static struct cmd_struct commands[] = 
  int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
  {
        int i;
 -      if (argc < 2)
 -              die(_("submodule--helper subcommand must be "
 -                    "called with a subcommand"));
 +      if (argc < 2 || !strcmp(argv[1], "-h"))
 +              usage("git submodule--helper <command>");
  
        for (i = 0; i < ARRAY_SIZE(commands); i++) {
                if (!strcmp(argv[1], commands[i].cmd)) {
diff --combined builtin/tag.c
index 1f74a56db749a5e1ffa06715e347cdc1b041033b,b85bcf680980d6934219fa63c8c0fee374ccfd20..01154ea8dcca869ed635eb433d5afe879b8e883c
@@@ -7,6 -7,7 +7,7 @@@
   */
  
  #include "cache.h"
+ #include "config.h"
  #include "builtin.h"
  #include "refs.h"
  #include "tag.h"
@@@ -66,7 -67,7 +67,7 @@@ static int list_tags(struct ref_filter 
  }
  
  typedef int (*each_tag_name_fn)(const char *name, const char *ref,
 -                              const unsigned char *sha1, const void *cb_data);
 +                              const struct object_id *oid, const void *cb_data);
  
  static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
                             const void *cb_data)
        const char **p;
        struct strbuf ref = STRBUF_INIT;
        int had_error = 0;
 -      unsigned char sha1[20];
 +      struct object_id oid;
  
        for (p = argv; *p; p++) {
                strbuf_reset(&ref);
                strbuf_addf(&ref, "refs/tags/%s", *p);
 -              if (read_ref(ref.buf, sha1)) {
 +              if (read_ref(ref.buf, oid.hash)) {
                        error(_("tag '%s' not found."), *p);
                        had_error = 1;
                        continue;
                }
 -              if (fn(*p, ref.buf, sha1, cb_data))
 +              if (fn(*p, ref.buf, &oid, cb_data))
                        had_error = 1;
        }
        strbuf_release(&ref);
  }
  
  static int delete_tag(const char *name, const char *ref,
 -                    const unsigned char *sha1, const void *cb_data)
 +                    const struct object_id *oid, const void *cb_data)
  {
 -      if (delete_ref(NULL, ref, sha1, 0))
 +      if (delete_ref(NULL, ref, oid->hash, 0))
                return 1;
 -      printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(sha1, DEFAULT_ABBREV));
 +      printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(oid->hash, DEFAULT_ABBREV));
        return 0;
  }
  
  static int verify_tag(const char *name, const char *ref,
 -                    const unsigned char *sha1, const void *cb_data)
 +                    const struct object_id *oid, const void *cb_data)
  {
        int flags;
        const char *fmt_pretty = cb_data;
        if (fmt_pretty)
                flags = GPG_VERIFY_OMIT_STATUS;
  
 -      if (gpg_verify_tag(sha1, name, flags))
 +      if (gpg_verify_tag(oid->hash, name, flags))
                return -1;
  
        if (fmt_pretty)
 -              pretty_print_ref(name, sha1, fmt_pretty);
 +              pretty_print_ref(name, oid->hash, fmt_pretty);
  
        return 0;
  }
@@@ -182,13 -183,13 +183,13 @@@ static int git_tag_config(const char *v
        return git_default_config(var, value, cb);
  }
  
 -static void write_tag_body(int fd, const unsigned char *sha1)
 +static void write_tag_body(int fd, const struct object_id *oid)
  {
        unsigned long size;
        enum object_type type;
        char *buf, *sp;
  
 -      buf = read_sha1_file(sha1, &type, &size);
 +      buf = read_sha1_file(oid->hash, &type, &size);
        if (!buf)
                return;
        /* skip header */
        free(buf);
  }
  
 -static int build_tag_object(struct strbuf *buf, int sign, unsigned char *result)
 +static int build_tag_object(struct strbuf *buf, int sign, struct object_id *result)
  {
        if (sign && do_sign(buf) < 0)
                return error(_("unable to sign the tag"));
 -      if (write_sha1_file(buf->buf, buf->len, tag_type, result) < 0)
 +      if (write_sha1_file(buf->buf, buf->len, tag_type, result->hash) < 0)
                return error(_("unable to write tag file"));
        return 0;
  }
@@@ -223,15 -224,15 +224,15 @@@ struct create_tag_options 
        } cleanup_mode;
  };
  
 -static void create_tag(const unsigned char *object, const char *tag,
 +static void create_tag(const struct object_id *object, const char *tag,
                       struct strbuf *buf, struct create_tag_options *opt,
 -                     unsigned char *prev, unsigned char *result)
 +                     struct object_id *prev, struct object_id *result)
  {
        enum object_type type;
        struct strbuf header = STRBUF_INIT;
        char *path = NULL;
  
 -      type = sha1_object_info(object, NULL);
 +      type = sha1_object_info(object->hash, NULL);
        if (type <= OBJ_NONE)
            die(_("bad object type."));
  
                    "type %s\n"
                    "tag %s\n"
                    "tagger %s\n\n",
 -                  sha1_to_hex(object),
 +                  oid_to_hex(object),
                    typename(type),
                    tag,
                    git_committer_info(IDENT_STRICT));
                if (fd < 0)
                        die_errno(_("could not create file '%s'"), path);
  
 -              if (!is_null_sha1(prev)) {
 +              if (!is_null_oid(prev)) {
                        write_tag_body(fd, prev);
                } else {
                        struct strbuf buf = STRBUF_INIT;
        }
  }
  
 -static void create_reflog_msg(const unsigned char *sha1, struct strbuf *sb)
 +static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
  {
        enum object_type type;
        struct commit *c;
                strbuf_addstr(sb, rla);
        } else {
                strbuf_addstr(sb, "tag: tagging ");
 -              strbuf_add_unique_abbrev(sb, sha1, DEFAULT_ABBREV);
 +              strbuf_add_unique_abbrev(sb, oid->hash, DEFAULT_ABBREV);
        }
  
        strbuf_addstr(sb, " (");
 -      type = sha1_object_info(sha1, NULL);
 +      type = sha1_object_info(oid->hash, NULL);
        switch (type) {
        default:
                strbuf_addstr(sb, "object of unknown type");
                break;
        case OBJ_COMMIT:
 -              if ((buf = read_sha1_file(sha1, &type, &size)) != NULL) {
 +              if ((buf = read_sha1_file(oid->hash, &type, &size)) != NULL) {
                        subject_len = find_commit_subject(buf, &subject_start);
                        strbuf_insert(sb, sb->len, subject_start, subject_len);
                } else {
                }
                free(buf);
  
 -              if ((c = lookup_commit_reference(sha1)) != NULL)
 +              if ((c = lookup_commit_reference(oid)) != NULL)
                        strbuf_addf(sb, ", %s", show_date(c->date, 0, DATE_MODE(SHORT)));
                break;
        case OBJ_TREE:
@@@ -378,7 -379,7 +379,7 @@@ int cmd_tag(int argc, const char **argv
        struct strbuf buf = STRBUF_INIT;
        struct strbuf ref = STRBUF_INIT;
        struct strbuf reflog_msg = STRBUF_INIT;
 -      unsigned char object[20], prev[20];
 +      struct object_id object, prev;
        const char *object_ref, *tag;
        struct create_tag_options opt;
        char *cleanup_arg = NULL;
        if (argc > 2)
                die(_("too many params"));
  
 -      if (get_sha1(object_ref, object))
 +      if (get_oid(object_ref, &object))
                die(_("Failed to resolve '%s' as a valid ref."), object_ref);
  
        if (strbuf_check_tag_ref(&ref, tag))
                die(_("'%s' is not a valid tag name."), tag);
  
 -      if (read_ref(ref.buf, prev))
 -              hashclr(prev);
 +      if (read_ref(ref.buf, prev.hash))
 +              oidclr(&prev);
        else if (!force)
                die(_("tag '%s' already exists"), tag);
  
        else
                die(_("Invalid cleanup mode %s"), cleanup_arg);
  
 -      create_reflog_msg(object, &reflog_msg);
 +      create_reflog_msg(&object, &reflog_msg);
  
        if (create_tag_object) {
                if (force_sign_annotate && !annotate)
                        opt.sign = 1;
 -              create_tag(object, tag, &buf, &opt, prev, object);
 +              create_tag(&object, tag, &buf, &opt, &prev, &object);
        }
  
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
 -          ref_transaction_update(transaction, ref.buf, object, prev,
 +          ref_transaction_update(transaction, ref.buf, object.hash, prev.hash,
                                   create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
                                   reflog_msg.buf, &err) ||
            ref_transaction_commit(transaction, &err))
                die("%s", err.buf);
        ref_transaction_free(transaction);
 -      if (force && !is_null_sha1(prev) && hashcmp(prev, object))
 -              printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev, DEFAULT_ABBREV));
 +      if (force && !is_null_oid(&prev) && oidcmp(&prev, &object))
 +              printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev.hash, DEFAULT_ABBREV));
  
        strbuf_release(&err);
        strbuf_release(&buf);
diff --combined builtin/unpack-objects.c
index 8bc9997767adbb77cc8af81b2b289e22f2b61c5a,9da06548f03224d35f6de12eec481a1449d05b17..193f8b9d57f0759c38004fd1d99f660919ac30e3
@@@ -1,5 -1,6 +1,6 @@@
  #include "builtin.h"
  #include "cache.h"
+ #include "config.h"
  #include "object.h"
  #include "delta.h"
  #include "pack.h"
@@@ -127,7 -128,7 +128,7 @@@ static void *get_data(unsigned long siz
  }
  
  struct delta_info {
 -      unsigned char base_sha1[20];
 +      struct object_id base_oid;
        unsigned nr;
        off_t base_offset;
        unsigned long size;
  
  static struct delta_info *delta_list;
  
 -static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1,
 +static void add_delta_to_list(unsigned nr, const struct object_id *base_oid,
                              off_t base_offset,
                              void *delta, unsigned long size)
  {
        struct delta_info *info = xmalloc(sizeof(*info));
  
 -      hashcpy(info->base_sha1, base_sha1);
 +      oidcpy(&info->base_oid, base_oid);
        info->base_offset = base_offset;
        info->size = size;
        info->delta = delta;
  
  struct obj_info {
        off_t offset;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        struct object *obj;
  };
  
@@@ -170,9 -171,9 +171,9 @@@ static unsigned nr_objects
   */
  static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf)
  {
 -      unsigned char sha1[20];
 +      struct object_id oid;
  
 -      if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), sha1) < 0)
 +      if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), oid.hash) < 0)
                die("failed to write object %s", oid_to_hex(&obj->oid));
        obj->flags |= FLAG_WRITTEN;
  }
@@@ -237,19 -238,19 +238,19 @@@ static void write_object(unsigned nr, e
                         void *buf, unsigned long size)
  {
        if (!strict) {
 -              if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
 +              if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0)
                        die("failed to write object");
                added_object(nr, type, buf, size);
                free(buf);
                obj_list[nr].obj = NULL;
        } else if (type == OBJ_BLOB) {
                struct blob *blob;
 -              if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
 +              if (write_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash) < 0)
                        die("failed to write object");
                added_object(nr, type, buf, size);
                free(buf);
  
 -              blob = lookup_blob(obj_list[nr].sha1);
 +              blob = lookup_blob(&obj_list[nr].oid);
                if (blob)
                        blob->object.flags |= FLAG_WRITTEN;
                else
        } else {
                struct object *obj;
                int eaten;
 -              hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1);
 +              hash_sha1_file(buf, size, typename(type), obj_list[nr].oid.hash);
                added_object(nr, type, buf, size);
 -              obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten);
 +              obj = parse_object_buffer(&obj_list[nr].oid, type, size, buf,
 +                                        &eaten);
                if (!obj)
                        die("invalid %s", typename(type));
                add_object_buffer(obj, buf, size);
@@@ -297,7 -297,7 +298,7 @@@ static void added_object(unsigned nr, e
        struct delta_info *info;
  
        while ((info = *p) != NULL) {
 -              if (!hashcmp(info->base_sha1, obj_list[nr].sha1) ||
 +              if (!oidcmp(&info->base_oid, &obj_list[nr].oid) ||
                    info->base_offset == obj_list[nr].offset) {
                        *p = info->next;
                        p = &delta_list;
@@@ -321,12 -321,12 +322,12 @@@ static void unpack_non_delta_entry(enu
                free(buf);
  }
  
 -static int resolve_against_held(unsigned nr, const unsigned char *base,
 +static int resolve_against_held(unsigned nr, const struct object_id *base,
                                void *delta_data, unsigned long delta_size)
  {
        struct object *obj;
        struct obj_buffer *obj_buffer;
 -      obj = lookup_object(base);
 +      obj = lookup_object(base->hash);
        if (!obj)
                return 0;
        obj_buffer = lookup_object_buffer(obj);
@@@ -342,25 -342,25 +343,25 @@@ static void unpack_delta_entry(enum obj
  {
        void *delta_data, *base;
        unsigned long base_size;
 -      unsigned char base_sha1[20];
 +      struct object_id base_oid;
  
        if (type == OBJ_REF_DELTA) {
 -              hashcpy(base_sha1, fill(20));
 -              use(20);
 +              hashcpy(base_oid.hash, fill(GIT_SHA1_RAWSZ));
 +              use(GIT_SHA1_RAWSZ);
                delta_data = get_data(delta_size);
                if (dry_run || !delta_data) {
                        free(delta_data);
                        return;
                }
 -              if (has_sha1_file(base_sha1))
 +              if (has_object_file(&base_oid))
                        ; /* Ok we have this one */
 -              else if (resolve_against_held(nr, base_sha1,
 +              else if (resolve_against_held(nr, &base_oid,
                                              delta_data, delta_size))
                        return; /* we are done */
                else {
                        /* cannot resolve yet --- queue it */
 -                      hashclr(obj_list[nr].sha1);
 -                      add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
 +                      oidclr(&obj_list[nr].oid);
 +                      add_delta_to_list(nr, &base_oid, 0, delta_data, delta_size);
                        return;
                }
        } else {
                        } else if (base_offset > obj_list[mid].offset) {
                                lo = mid + 1;
                        } else {
 -                              hashcpy(base_sha1, obj_list[mid].sha1);
 -                              base_found = !is_null_sha1(base_sha1);
 +                              oidcpy(&base_oid, &obj_list[mid].oid);
 +                              base_found = !is_null_oid(&base_oid);
                                break;
                        }
                }
                         * The delta base object is itself a delta that
                         * has not been resolved yet.
                         */
 -                      hashclr(obj_list[nr].sha1);
 -                      add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
 +                      oidclr(&obj_list[nr].oid);
 +                      add_delta_to_list(nr, &null_oid, base_offset, delta_data, delta_size);
                        return;
                }
        }
  
 -      if (resolve_against_held(nr, base_sha1, delta_data, delta_size))
 +      if (resolve_against_held(nr, &base_oid, delta_data, delta_size))
                return;
  
 -      base = read_sha1_file(base_sha1, &type, &base_size);
 +      base = read_sha1_file(base_oid.hash, &type, &base_size);
        if (!base) {
                error("failed to read delta-pack base object %s",
 -                    sha1_to_hex(base_sha1));
 +                    oid_to_hex(&base_oid));
                if (!recover)
                        exit(1);
                has_errors = 1;
@@@ -506,7 -506,7 +507,7 @@@ static void unpack_all(void
  int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
  {
        int i;
 -      unsigned char sha1[20];
 +      struct object_id oid;
  
        check_replace_refs = 0;
  
        git_SHA1_Init(&ctx);
        unpack_all();
        git_SHA1_Update(&ctx, buffer, offset);
 -      git_SHA1_Final(sha1, &ctx);
 +      git_SHA1_Final(oid.hash, &ctx);
        if (strict)
                write_rest();
 -      if (hashcmp(fill(20), sha1))
 +      if (hashcmp(fill(GIT_SHA1_RAWSZ), oid.hash))
                die("final sha1 did not match");
 -      use(20);
 +      use(GIT_SHA1_RAWSZ);
  
        /* Write the last part of the buffer to stdout */
        while (len) {
diff --combined builtin/update-index.c
index f99b1e5790b9b6aeafaa88f438a8a50f1538c2fe,0a4c2364879313b9a1a5cae653fee0642b2d403d..56721cf03db23a2f5a1b8e9419422df916d7b00f
@@@ -4,6 -4,7 +4,7 @@@
   * Copyright (C) Linus Torvalds, 2005
   */
  #include "cache.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "quote.h"
  #include "cache-tree.h"
@@@ -257,7 -258,7 +258,7 @@@ static int remove_one_path(const char *
   */
  static int process_lstat_error(const char *path, int err)
  {
 -      if (err == ENOENT || err == ENOTDIR)
 +      if (is_missing_file_error(err))
                return remove_one_path(path);
        return error("lstat(\"%s\"): %s", path, strerror(err));
  }
diff --combined builtin/verify-commit.c
index 05b734e6d1bd469b63aa7b51921622a590730b6d,d5e9a17a77aa0eae71118e1ce27ded90b267a008..ba38ac9b1518884693e2c89ec19cc9e00fce9fa3
@@@ -6,6 -6,7 +6,7 @@@
   * Based on git-verify-tag
   */
  #include "cache.h"
+ #include "config.h"
  #include "builtin.h"
  #include "commit.h"
  #include "run-command.h"
@@@ -18,14 -19,14 +19,14 @@@ static const char * const verify_commit
                NULL
  };
  
 -static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned long size, unsigned flags)
 +static int run_gpg_verify(const struct object_id *oid, const char *buf, unsigned long size, unsigned flags)
  {
        struct signature_check signature_check;
        int ret;
  
        memset(&signature_check, 0, sizeof(signature_check));
  
 -      ret = check_commit_signature(lookup_commit(sha1), &signature_check);
 +      ret = check_commit_signature(lookup_commit(oid), &signature_check);
        print_signature_buffer(&signature_check, flags);
  
        signature_check_clear(&signature_check);
  static int verify_commit(const char *name, unsigned flags)
  {
        enum object_type type;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        char *buf;
        unsigned long size;
        int ret;
  
 -      if (get_sha1(name, sha1))
 +      if (get_oid(name, &oid))
                return error("commit '%s' not found.", name);
  
 -      buf = read_sha1_file(sha1, &type, &size);
 +      buf = read_sha1_file(oid.hash, &type, &size);
        if (!buf)
                return error("%s: unable to read file.", name);
        if (type != OBJ_COMMIT)
                return error("%s: cannot verify a non-commit object of type %s.",
                                name, typename(type));
  
 -      ret = run_gpg_verify(sha1, buf, size, flags);
 +      ret = run_gpg_verify(&oid, buf, size, flags);
  
        free(buf);
        return ret;
diff --combined builtin/worktree.c
index 793306ea5162f1c3e9663c0c99d693b88baaea3d,d414b6870b3109b895c4b4d37ca616a167c3a8c7..0c5476ee9de464cb0fae22c49775bc10efb0731b
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "builtin.h"
  #include "dir.h"
  #include "parse-options.h"
@@@ -31,7 -32,7 +32,7 @@@ struct add_opts 
  
  static int show_only;
  static int verbose;
 -static unsigned long expire;
 +static timestamp_t expire;
  
  static int prune_worktree(const char *id, struct strbuf *reason)
  {
@@@ -131,7 -132,7 +132,7 @@@ static int prune(int ac, const char **a
                OPT_END()
        };
  
 -      expire = ULONG_MAX;
 +      expire = TIME_MAX;
        ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
        if (ac)
                usage_with_options(worktree_usage, options);
@@@ -414,11 -415,9 +415,11 @@@ static void show_worktree(struct worktr
                                find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV));
                if (wt->is_detached)
                        strbuf_addstr(&sb, "(detached HEAD)");
 -              else if (wt->head_ref)
 -                      strbuf_addf(&sb, "[%s]", shorten_unambiguous_ref(wt->head_ref, 0));
 -              else
 +              else if (wt->head_ref) {
 +                      char *ref = shorten_unambiguous_ref(wt->head_ref, 0);
 +                      strbuf_addf(&sb, "[%s]", ref);
 +                      free(ref);
 +              } else
                        strbuf_addstr(&sb, "(error)");
        }
        printf("%s\n", sb.buf);
diff --combined cache.h
index a666aaf9fd0b211954f14fbefa68d2cc440072f5,82f39f7a9e9ad17b39dc52c395eabbc70880325e..96055c222929e4ba307f3162b58740eccf165f2c
+++ b/cache.h
@@@ -525,12 -525,15 +525,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.
-  */
- extern const char *discover_git_directory(struct strbuf *gitdir);
+  * 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 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);
@@@ -597,7 -600,6 +600,7 @@@ extern int read_index_unmerged(struct i
  #define CLOSE_LOCK            (1 << 1)
  extern int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags);
  extern int discard_index(struct index_state *);
 +extern void move_index_extensions(struct index_state *dst, struct index_state *src);
  extern int unmerged_index(const struct index_state *);
  extern int verify_path(const char *path);
  extern int strcmp_offset(const char *s1, const char *s2, size_t *first_change);
@@@ -1026,13 -1028,6 +1029,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);
@@@ -1341,18 -1336,13 +1344,18 @@@ static inline int hex2chr(const char *s
  
  struct object_context {
        unsigned char tree[20];
 -      char path[PATH_MAX];
        unsigned mode;
        /*
         * symlink_path is only used by get_tree_entry_follow_symlinks,
         * and only for symlinks that point outside the repository.
         */
        struct strbuf symlink_path;
 +      /*
 +       * If GET_SHA1_RECORD_PATH is set, this will record path (if any)
 +       * found when resolving the name. The caller is responsible for
 +       * releasing the memory.
 +       */
 +      char *path;
  };
  
  #define GET_SHA1_QUIETLY           01
  #define GET_SHA1_TREEISH          020
  #define GET_SHA1_BLOB             040
  #define GET_SHA1_FOLLOW_SYMLINKS 0100
 +#define GET_SHA1_RECORD_PATH     0200
  #define GET_SHA1_ONLY_TO_DIE    04000
  
  #define GET_SHA1_DISAMBIGUATORS \
@@@ -1377,7 -1366,7 +1380,7 @@@ extern int get_sha1_tree(const char *st
  extern int get_sha1_treeish(const char *str, unsigned char *sha1);
  extern int get_sha1_blob(const char *str, unsigned char *sha1);
  extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
 -extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc);
 +extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *oc);
  
  extern int get_oid(const char *str, struct object_id *oid);
  
@@@ -1493,18 -1482,18 +1496,18 @@@ struct date_mode 
  #define DATE_MODE(t) date_mode_from_type(DATE_##t)
  struct date_mode *date_mode_from_type(enum date_mode_type type);
  
 -const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);
 -void show_date_relative(unsigned long time, int tz, const struct timeval *now,
 +const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);
 +void show_date_relative(timestamp_t time, int tz, const struct timeval *now,
                        struct strbuf *timebuf);
  int parse_date(const char *date, struct strbuf *out);
 -int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);
 -int parse_expiry_date(const char *date, unsigned long *timestamp);
 +int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);
 +int parse_expiry_date(const char *date, timestamp_t *timestamp);
  void datestamp(struct strbuf *out);
  #define approxidate(s) approxidate_careful((s), NULL)
 -unsigned long approxidate_careful(const char *, int *);
 -unsigned long approxidate_relative(const char *date, const struct timeval *now);
 +timestamp_t approxidate_careful(const char *, int *);
 +timestamp_t approxidate_relative(const char *date, const struct timeval *now);
  void parse_date_format(const char *format, struct date_mode *mode);
 -int date_overflows(unsigned long date);
 +int date_overflows(timestamp_t date);
  
  #define IDENT_STRICT         1
  #define IDENT_NO_DATE        2
@@@ -1879,188 -1868,9 +1882,9 @@@ extern int packed_object_info(struct pa
  /* 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);
  
@@@ -2193,8 -1993,7 +2007,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);
@@@ -2213,8 -2012,8 +2027,8 @@@ struct commit_list
  int try_merge_command(const char *strategy, size_t xopts_nr,
                const char **xopts, struct commit_list *common,
                const char *head_arg, struct commit_list *remotes);
 -int checkout_fast_forward(const unsigned char *from,
 -                        const unsigned char *to,
 +int checkout_fast_forward(const struct object_id *from,
 +                        const struct object_id *to,
                          int overwrite_ignore);
  
  
diff --combined config.c
index 547daf87d40ebfe67272e913635826441dd97320,ca9e9efec134a2a9380528e92567cfb3b9b6847e..6f0f8b30f39ba3a32d1a1795bdf12d78c5ea97f9
+++ b/config.c
@@@ -6,6 -6,7 +6,7 @@@
   *
   */
  #include "cache.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "exec_cmd.h"
  #include "strbuf.h"
@@@ -214,12 -215,9 +215,10 @@@ static int include_by_gitdir(const stru
        struct strbuf pattern = STRBUF_INIT;
        int ret = 0, prefix;
        const char *git_dir;
 +      int already_tried_absolute = 0;
  
        if (opts->git_dir)
                git_dir = opts->git_dir;
-       else if (have_git_dir())
-               git_dir = get_git_dir();
        else
                goto done;
  
        strbuf_add(&pattern, cond, cond_len);
        prefix = prepare_include_condition_pattern(&pattern);
  
 +again:
        if (prefix < 0)
                goto done;
  
        ret = !wildmatch(pattern.buf + prefix, text.buf + prefix,
                         icase ? WM_CASEFOLD : 0, NULL);
  
 +      if (!ret && !already_tried_absolute) {
 +              /*
 +               * We've tried e.g. matching gitdir:~/work, but if
 +               * ~/work is a symlink to /mnt/storage/work
 +               * strbuf_realpath() will expand it, so the rule won't
 +               * match. Let's match against a
 +               * strbuf_add_absolute_path() version of the path,
 +               * which'll do the right thing
 +               */
 +              strbuf_reset(&text);
 +              strbuf_add_absolute_path(&text, git_dir);
 +              already_tried_absolute = 1;
 +              goto again;
 +      }
  done:
        strbuf_release(&pattern);
        strbuf_release(&text);
@@@ -1439,7 -1422,7 +1438,7 @@@ int git_config_from_file(config_fn_t fn
        int ret = -1;
        FILE *f;
  
 -      f = fopen(filename, "r");
 +      f = fopen_or_warn(filename, "r");
        if (f) {
                flockfile(f);
                ret = do_config_from_file(fn, CONFIG_ORIGIN_FILE, filename, filename, f, data);
@@@ -1546,10 -1529,8 +1545,8 @@@ static int do_git_config_sequence(cons
        char *user_config = expand_user_path("~/.gitconfig", 0);
        char *repo_config;
  
-       if (opts->git_dir)
-               repo_config = mkpathdup("%s/config", opts->git_dir);
-       else if (have_git_dir())
-               repo_config = git_pathdup("config");
+       if (opts->commondir)
+               repo_config = mkpathdup("%s/config", opts->commondir);
        else
                repo_config = NULL;
  
        return ret;
  }
  
- int git_config_with_options(config_fn_t fn, void *data,
-                           struct git_config_source *config_source,
-                           const struct config_options *opts)
+ int config_with_options(config_fn_t fn, void *data,
+                       struct git_config_source *config_source,
+                       const struct config_options *opts)
  {
        struct config_include_data inc = CONFIG_INCLUDE_INIT;
  
@@@ -1613,9 -1594,14 +1610,14 @@@ static void git_config_raw(config_fn_t 
        struct config_options opts = {0};
  
        opts.respect_includes = 1;
-       if (git_config_with_options(fn, data, NULL, &opts) < 0)
+       if (have_git_dir()) {
+               opts.commondir = get_git_common_dir();
+               opts.git_dir = get_git_dir();
+       }
+       if (config_with_options(fn, data, NULL, &opts) < 0)
                /*
-                * git_config_with_options() normally returns only
+                * config_with_options() normally returns only
                 * zero, as most errors are fatal, and
                 * non-fatal potential errors are guarded by "if"
                 * statements that are entered only when no error is
@@@ -1654,11 -1640,13 +1656,13 @@@ static void configset_iter(struct confi
  void read_early_config(config_fn_t cb, void *data)
  {
        struct config_options opts = {0};
-       struct strbuf buf = STRBUF_INIT;
+       struct strbuf commondir = STRBUF_INIT;
+       struct strbuf gitdir = STRBUF_INIT;
  
        opts.respect_includes = 1;
  
-       if (have_git_dir())
+       if (have_git_dir()) {
+               opts.commondir = get_git_common_dir();
                opts.git_dir = get_git_dir();
        /*
         * When setup_git_directory() was not yet asked to discover the
         * notably, the current working directory is still the same after the
         * call).
         */
-       else if (discover_git_directory(&buf))
-               opts.git_dir = buf.buf;
+       } else if (!discover_git_directory(&commondir, &gitdir)) {
+               opts.commondir = commondir.buf;
+               opts.git_dir = gitdir.buf;
+       }
  
-       git_config_with_options(cb, data, NULL, &opts);
+       config_with_options(cb, data, NULL, &opts);
  
-       strbuf_release(&buf);
+       strbuf_release(&commondir);
+       strbuf_release(&gitdir);
  }
  
  static void git_config_check_init(void);
@@@ -1982,7 -1973,7 +1989,7 @@@ int git_config_get_expiry(const char *k
        if (ret)
                return ret;
        if (strcmp(*output, "now")) {
 -              unsigned long now = approxidate("now");
 +              timestamp_t now = approxidate("now");
                if (approxidate(*output) >= now)
                        git_die_config(key, _("Invalid %s: '%s'"), key, *output);
        }
@@@ -2638,7 -2629,7 +2645,7 @@@ int git_config_rename_section_in_file(c
        struct lock_file *lock;
        int out_fd;
        char buf[1024];
 -      FILE *config_file;
 +      FILE *config_file = NULL;
        struct stat st;
  
        if (new_name && !section_name_is_ok(new_name)) {
        }
  
        if (!(config_file = fopen(config_filename, "rb"))) {
 +              ret = warn_on_fopen_errors(config_filename);
 +              if (ret)
 +                      goto out;
                /* no config file means nothing to rename, no error */
                goto commit_and_out;
        }
                }
        }
        fclose(config_file);
 +      config_file = NULL;
  commit_and_out:
        if (commit_lock_file(lock) < 0)
                ret = error_errno("could not write config file %s",
                                  config_filename);
  out:
 +      if (config_file)
 +              fclose(config_file);
        rollback_lock_file(lock);
  out_no_rollback:
        free(filename_buf);
diff --combined connect.c
index c72b1d1151744c5e7c7b82f453892a1bc9b26021,efddb30ea870ee759dc3d1e6e9084a7b6e6ee23c..e78d3f43d84b7f90f4395cb289c9cf0cb34e8297
+++ b/connect.c
@@@ -1,5 -1,6 +1,6 @@@
  #include "git-compat-util.h"
  #include "cache.h"
+ #include "config.h"
  #include "pkt-line.h"
  #include "quote.h"
  #include "refs.h"
@@@ -71,7 -72,7 +72,7 @@@ static void parse_one_symref_info(struc
            check_refname_format(target, REFNAME_ALLOW_ONELEVEL))
                /* "symref=bogus:pair */
                goto reject;
 -      item = string_list_append(symref, sym);
 +      item = string_list_append_nodup(symref, sym);
        item->util = target;
        return;
  reject:
diff --combined convert.c
index 4097f521f240240fde1a3bfa8519515fdaac75f6,69f23cfcaa90993416eaa76303059f3bd389bf9a..7d2a519dafe5dcf892df10c51e1bfb83bc8a2091
+++ b/convert.c
@@@ -1,11 -1,10 +1,12 @@@
 +#define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
+ #include "config.h"
  #include "attr.h"
  #include "run-command.h"
  #include "quote.h"
  #include "sigchain.h"
  #include "pkt-line.h"
 +#include "sub-process.h"
  
  /*
   * convert.c - convert a file when checking it out and checking it in.
@@@ -135,12 -134,11 +136,12 @@@ static const char *gather_convert_stats
        }
  }
  
 -const char *get_cached_convert_stats_ascii(const char *path)
 +const char *get_cached_convert_stats_ascii(const struct index_state *istate,
 +                                         const char *path)
  {
        const char *ret;
        unsigned long sz;
 -      void *data = read_blob_data_from_cache(path, &sz);
 +      void *data = read_blob_data_from_index(istate, path, &sz);
        ret = gather_convert_stats_ascii(data, sz);
        free(data);
        return ret;
@@@ -219,13 -217,13 +220,13 @@@ static void check_safe_crlf(const char 
        }
  }
  
 -static int has_cr_in_index(const char *path)
 +static int has_cr_in_index(const struct index_state *istate, const char *path)
  {
        unsigned long sz;
        void *data;
        int has_cr;
  
 -      data = read_blob_data_from_cache(path, &sz);
 +      data = read_blob_data_from_index(istate, path, &sz);
        if (!data)
                return 0;
        has_cr = memchr(data, '\r', sz) != NULL;
@@@ -255,8 -253,7 +256,8 @@@ static int will_convert_lf_to_crlf(size
  
  }
  
 -static int crlf_to_git(const char *path, const char *src, size_t len,
 +static int crlf_to_git(const struct index_state *istate,
 +                     const char *path, const char *src, size_t len,
                       struct strbuf *buf,
                       enum crlf_action crlf_action, enum safe_crlf checksafe)
  {
                 * unless we want to renormalize in a merge or
                 * cherry-pick.
                 */
 -              if ((checksafe != SAFE_CRLF_RENORMALIZE) && has_cr_in_index(path))
 +              if ((checksafe != SAFE_CRLF_RENORMALIZE) &&
 +                  has_cr_in_index(istate, path))
                        convert_crlf_into_lf = 0;
        }
        if ((checksafe == SAFE_CRLF_WARN ||
@@@ -502,26 -498,126 +503,26 @@@ static int apply_single_file_filter(con
  #define CAP_SMUDGE   (1u<<1)
  
  struct cmd2process {
 -      struct hashmap_entry ent; /* must be the first member! */
 +      struct subprocess_entry subprocess; /* must be the first member! */
        unsigned int supported_capabilities;
 -      const char *cmd;
 -      struct child_process process;
  };
  
 -static int cmd_process_map_initialized;
 -static struct hashmap cmd_process_map;
 -
 -static int cmd2process_cmp(const struct cmd2process *e1,
 -                         const struct cmd2process *e2,
 -                         const void *unused)
 -{
 -      return strcmp(e1->cmd, e2->cmd);
 -}
 -
 -static struct cmd2process *find_multi_file_filter_entry(struct hashmap *hashmap, const char *cmd)
 -{
 -      struct cmd2process key;
 -      hashmap_entry_init(&key, strhash(cmd));
 -      key.cmd = cmd;
 -      return hashmap_get(hashmap, &key, NULL);
 -}
 -
 -static int packet_write_list(int fd, const char *line, ...)
 -{
 -      va_list args;
 -      int err;
 -      va_start(args, line);
 -      for (;;) {
 -              if (!line)
 -                      break;
 -              if (strlen(line) > LARGE_PACKET_DATA_MAX)
 -                      return -1;
 -              err = packet_write_fmt_gently(fd, "%s\n", line);
 -              if (err)
 -                      return err;
 -              line = va_arg(args, const char*);
 -      }
 -      va_end(args);
 -      return packet_flush_gently(fd);
 -}
 -
 -static void read_multi_file_filter_status(int fd, struct strbuf *status)
 -{
 -      struct strbuf **pair;
 -      char *line;
 -      for (;;) {
 -              line = packet_read_line(fd, NULL);
 -              if (!line)
 -                      break;
 -              pair = strbuf_split_str(line, '=', 2);
 -              if (pair[0] && pair[0]->len && pair[1]) {
 -                      /* the last "status=<foo>" line wins */
 -                      if (!strcmp(pair[0]->buf, "status=")) {
 -                              strbuf_reset(status);
 -                              strbuf_addbuf(status, pair[1]);
 -                      }
 -              }
 -              strbuf_list_free(pair);
 -      }
 -}
 -
 -static void kill_multi_file_filter(struct hashmap *hashmap, struct cmd2process *entry)
 -{
 -      if (!entry)
 -              return;
 -
 -      entry->process.clean_on_exit = 0;
 -      kill(entry->process.pid, SIGTERM);
 -      finish_command(&entry->process);
 +static int subprocess_map_initialized;
 +static struct hashmap subprocess_map;
  
 -      hashmap_remove(hashmap, entry, NULL);
 -      free(entry);
 -}
 -
 -static void stop_multi_file_filter(struct child_process *process)
 -{
 -      sigchain_push(SIGPIPE, SIG_IGN);
 -      /* Closing the pipe signals the filter to initiate a shutdown. */
 -      close(process->in);
 -      close(process->out);
 -      sigchain_pop(SIGPIPE);
 -      /* Finish command will wait until the shutdown is complete. */
 -      finish_command(process);
 -}
 -
 -static struct cmd2process *start_multi_file_filter(struct hashmap *hashmap, const char *cmd)
 +static int start_multi_file_filter_fn(struct subprocess_entry *subprocess)
  {
        int err;
 -      struct cmd2process *entry;
 -      struct child_process *process;
 -      const char *argv[] = { cmd, NULL };
 +      struct cmd2process *entry = (struct cmd2process *)subprocess;
        struct string_list cap_list = STRING_LIST_INIT_NODUP;
        char *cap_buf;
        const char *cap_name;
 -
 -      entry = xmalloc(sizeof(*entry));
 -      entry->cmd = cmd;
 -      entry->supported_capabilities = 0;
 -      process = &entry->process;
 -
 -      child_process_init(process);
 -      process->argv = argv;
 -      process->use_shell = 1;
 -      process->in = -1;
 -      process->out = -1;
 -      process->clean_on_exit = 1;
 -      process->clean_on_exit_handler = stop_multi_file_filter;
 -
 -      if (start_command(process)) {
 -              error("cannot fork to run external filter '%s'", cmd);
 -              return NULL;
 -      }
 -
 -      hashmap_entry_init(entry, strhash(cmd));
 +      struct child_process *process = &subprocess->process;
 +      const char *cmd = subprocess->cmd;
  
        sigchain_push(SIGPIPE, SIG_IGN);
  
 -      err = packet_write_list(process->in, "git-filter-client", "version=2", NULL);
 +      err = packet_writel(process->in, "git-filter-client", "version=2", NULL);
        if (err)
                goto done;
  
        if (err)
                goto done;
  
 -      err = packet_write_list(process->in, "capability=clean", "capability=smudge", NULL);
 +      err = packet_writel(process->in, "capability=clean", "capability=smudge", NULL);
  
        for (;;) {
                cap_buf = packet_read_line(process->out, NULL);
  done:
        sigchain_pop(SIGPIPE);
  
 -      if (err || errno == EPIPE) {
 -              error("initialization for external filter '%s' failed", cmd);
 -              kill_multi_file_filter(hashmap, entry);
 -              return NULL;
 -      }
 -
 -      hashmap_add(hashmap, entry);
 -      return entry;
 +      return err;
  }
  
  static int apply_multi_file_filter(const char *path, const char *src, size_t len,
        struct strbuf filter_status = STRBUF_INIT;
        const char *filter_type;
  
 -      if (!cmd_process_map_initialized) {
 -              cmd_process_map_initialized = 1;
 -              hashmap_init(&cmd_process_map, (hashmap_cmp_fn) cmd2process_cmp, 0);
 +      if (!subprocess_map_initialized) {
 +              subprocess_map_initialized = 1;
 +              hashmap_init(&subprocess_map, (hashmap_cmp_fn) cmd2process_cmp, 0);
                entry = NULL;
        } else {
 -              entry = find_multi_file_filter_entry(&cmd_process_map, cmd);
 +              entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd);
        }
  
        fflush(NULL);
  
        if (!entry) {
 -              entry = start_multi_file_filter(&cmd_process_map, cmd);
 -              if (!entry)
 +              entry = xmalloc(sizeof(*entry));
 +              entry->supported_capabilities = 0;
 +
 +              if (subprocess_start(&subprocess_map, &entry->subprocess, cmd, start_multi_file_filter_fn)) {
 +                      free(entry);
                        return 0;
 +              }
        }
 -      process = &entry->process;
 +      process = &entry->subprocess.process;
  
        if (!(wanted_capability & entry->supported_capabilities))
                return 0;
        if (err)
                goto done;
  
 -      read_multi_file_filter_status(process->out, &filter_status);
 +      err = subprocess_read_status(process->out, &filter_status);
 +      if (err)
 +              goto done;
 +
        err = strcmp(filter_status.buf, "success");
        if (err)
                goto done;
        if (err)
                goto done;
  
 -      read_multi_file_filter_status(process->out, &filter_status);
 +      err = subprocess_read_status(process->out, &filter_status);
 +      if (err)
 +              goto done;
 +
        err = strcmp(filter_status.buf, "success");
  
  done:
        sigchain_pop(SIGPIPE);
  
 -      if (err || errno == EPIPE) {
 +      if (err) {
                if (!strcmp(filter_status.buf, "error")) {
                        /* The filter signaled a problem with the file. */
                } else if (!strcmp(filter_status.buf, "abort")) {
                         * Force shutdown and restart if another blob requires filtering.
                         */
                        error("external filter '%s' failed", cmd);
 -                      kill_multi_file_filter(&cmd_process_map, entry);
 +                      subprocess_stop(&subprocess_map, &entry->subprocess);
 +                      free(entry);
                }
        } else {
                strbuf_swap(dst, &nbuf);
@@@ -1085,8 -1177,7 +1086,8 @@@ const char *get_convert_attr_ascii(cons
        return "";
  }
  
 -int convert_to_git(const char *path, const char *src, size_t len,
 +int convert_to_git(const struct index_state *istate,
 +                 const char *path, const char *src, size_t len,
                     struct strbuf *dst, enum safe_crlf checksafe)
  {
        int ret = 0;
                src = dst->buf;
                len = dst->len;
        }
 -      ret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe);
 +      ret |= crlf_to_git(istate, path, src, len, dst, ca.crlf_action, checksafe);
        if (ret && dst) {
                src = dst->buf;
                len = dst->len;
        return ret | ident_to_git(path, src, len, dst, ca.ident);
  }
  
 -void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,
 +void convert_to_git_filter_fd(const struct index_state *istate,
 +                            const char *path, int fd, struct strbuf *dst,
                              enum safe_crlf checksafe)
  {
        struct conv_attrs ca;
        if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN))
                die("%s: clean filter '%s' failed", path, ca.drv->name);
  
 -      crlf_to_git(path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);
 +      crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);
        ident_to_git(path, dst->buf, dst->len, dst, ca.ident);
  }
  
@@@ -1166,15 -1256,14 +1167,15 @@@ int convert_to_working_tree(const char 
        return convert_to_working_tree_internal(path, src, len, dst, 0);
  }
  
 -int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst)
 +int renormalize_buffer(const struct index_state *istate, const char *path,
 +                     const char *src, size_t len, struct strbuf *dst)
  {
        int ret = convert_to_working_tree_internal(path, src, len, dst, 1);
        if (ret) {
                src = dst->buf;
                len = dst->len;
        }
 -      return ret | convert_to_git(path, src, len, dst, SAFE_CRLF_RENORMALIZE);
 +      return ret | convert_to_git(istate, path, src, len, dst, SAFE_CRLF_RENORMALIZE);
  }
  
  /*****************************************************************
index f3814cc47a059227e24ca52007c7e19fdf2db480,2787b29c05917f120503c8320fc0ec13cf48fd4c..0d5c6250940633e75e2c9fb4b59b242a52188411
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "tempfile.h"
  #include "credential.h"
  #include "unix-socket.h"
@@@ -8,7 -9,7 +9,7 @@@ static struct tempfile socket_file
  
  struct credential_cache_entry {
        struct credential item;
 -      unsigned long expiration;
 +      timestamp_t expiration;
  };
  static struct credential_cache_entry *entries;
  static int entries_nr;
@@@ -47,12 -48,12 +48,12 @@@ static void remove_credential(const str
                e->expiration = 0;
  }
  
 -static int check_expirations(void)
 +static timestamp_t check_expirations(void)
  {
 -      static unsigned long wait_for_entry_until;
 +      static timestamp_t wait_for_entry_until;
        int i = 0;
 -      unsigned long now = time(NULL);
 -      unsigned long next = (unsigned long)-1;
 +      timestamp_t now = time(NULL);
 +      timestamp_t next = TIME_MAX;
  
        /*
         * Initially give the client 30 seconds to actually contact us
@@@ -159,7 -160,7 +160,7 @@@ static void serve_one_client(FILE *in, 
  static int serve_cache_loop(int fd)
  {
        struct pollfd pfd;
 -      unsigned long wakeup;
 +      timestamp_t wakeup;
  
        wakeup = check_expirations();
        if (!wakeup)
diff --combined diff.c
index e3d7e915783dd3a76d7fdc88cad5624fb009776c,4f9b9f83825ab1a79647969d360296b8311a33c8..41295d4ea9ff5564fa73d45aaa3afaab20103d87
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -2,6 -2,7 +2,7 @@@
   * Copyright (C) 2005 Junio C Hamano
   */
  #include "cache.h"
+ #include "config.h"
  #include "tempfile.h"
  #include "quote.h"
  #include "diff.h"
@@@ -27,7 -28,7 +28,7 @@@
  #endif
  
  static int diff_detect_rename_default;
 -static int diff_indent_heuristic; /* experimental */
 +static int diff_indent_heuristic = 1;
  static int diff_rename_limit_default = 400;
  static int diff_suppress_blank_empty;
  static int diff_use_color_default = -1;
@@@ -290,6 -291,9 +291,6 @@@ int git_diff_ui_config(const char *var
                return 0;
        }
  
 -      if (git_diff_heuristic_config(var, value, cb) < 0)
 -              return -1;
 -
        if (!strcmp(var, "diff.wserrorhighlight")) {
                int val = parse_ws_error_highlight(value);
                if (val < 0)
@@@ -348,9 -352,6 +349,9 @@@ int git_diff_basic_config(const char *v
        if (starts_with(var, "submodule."))
                return parse_submodule_config_option(var, value);
  
 +      if (git_diff_heuristic_config(var, value, cb) < 0)
 +              return -1;
 +
        return git_default_config(var, value, cb);
  }
  
@@@ -2702,13 -2703,13 +2703,13 @@@ void free_filespec(struct diff_filespe
        }
  }
  
 -void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
 -                 int sha1_valid, unsigned short mode)
 +void fill_filespec(struct diff_filespec *spec, const struct object_id *oid,
 +                 int oid_valid, unsigned short mode)
  {
        if (mode) {
                spec->mode = canon_mode(mode);
 -              hashcpy(spec->oid.hash, sha1);
 -              spec->oid_valid = sha1_valid;
 +              oidcpy(&spec->oid, oid);
 +              spec->oid_valid = oid_valid;
        }
  }
  
   * the work tree has that object contents, return true, so that
   * prepare_temp_file() does not have to inflate and extract.
   */
 -static int reuse_worktree_file(const char *name, const unsigned char *sha1, int want_file)
 +static int reuse_worktree_file(const char *name, const struct object_id *oid, int want_file)
  {
        const struct cache_entry *ce;
        struct stat st;
         * objects however would tend to be slower as they need
         * to be individually opened and inflated.
         */
 -      if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1))
 +      if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(oid->hash))
                return 0;
  
        /*
         * Similarly, if we'd have to convert the file contents anyway, that
         * makes the optimization not worthwhile.
         */
 -      if (!want_file && would_convert_to_git(name))
 +      if (!want_file && would_convert_to_git(&the_index, name))
                return 0;
  
        len = strlen(name);
         * This is not the sha1 we are looking for, or
         * unreusable because it is not a regular file.
         */
 -      if (hashcmp(sha1, ce->oid.hash) || !S_ISREG(ce->ce_mode))
 +      if (oidcmp(oid, &ce->oid) || !S_ISREG(ce->ce_mode))
                return 0;
  
        /*
@@@ -2842,7 -2843,7 +2843,7 @@@ int diff_populate_filespec(struct diff_
                return diff_populate_gitlink(s, size_only);
  
        if (!s->oid_valid ||
 -          reuse_worktree_file(s->path, s->oid.hash, 0)) {
 +          reuse_worktree_file(s->path, &s->oid, 0)) {
                struct strbuf buf = STRBUF_INIT;
                struct stat st;
                int fd;
                 * point if the path requires us to run the content
                 * conversion.
                 */
 -              if (size_only && !would_convert_to_git(s->path))
 +              if (size_only && !would_convert_to_git(&the_index, s->path))
                        return 0;
  
                /*
                /*
                 * Convert from working tree format to canonical git format
                 */
 -              if (convert_to_git(s->path, s->data, s->size, &buf, crlf_warn)) {
 +              if (convert_to_git(&the_index, s->path, s->data, s->size, &buf, crlf_warn)) {
                        size_t size = 0;
                        munmap(s->data, s->size);
                        s->should_munmap = 0;
@@@ -3008,7 -3009,7 +3009,7 @@@ static struct diff_tempfile *prepare_te
  
        if (!S_ISGITLINK(one->mode) &&
            (!one->oid_valid ||
 -           reuse_worktree_file(name, one->oid.hash, 1))) {
 +           reuse_worktree_file(name, &one->oid, 1))) {
                struct stat st;
                if (lstat(name, &st) < 0) {
                        if (errno == ENOENT)
                        /* we can borrow from the file in the work tree */
                        temp->name = name;
                        if (!one->oid_valid)
 -                              sha1_to_hex_r(temp->hex, null_sha1);
 +                              oid_to_hex_r(temp->hex, &null_oid);
                        else
                                oid_to_hex_r(temp->hex, &one->oid);
                        /* Even though we may sometimes borrow the
                         * contents from the work tree, we always want
                         * one->mode.  mode is trustworthy even when
 -                       * !(one->sha1_valid), as long as
 +                       * !(one->oid_valid), as long as
                         * DIFF_FILE_VALID(one).
                         */
                        xsnprintf(temp->mode, sizeof(temp->mode), "%06o", one->mode);
@@@ -3239,7 -3240,7 +3240,7 @@@ static void run_diff_cmd(const char *pg
                fprintf(o->file, "* Unmerged path %s\n", name);
  }
  
 -static void diff_fill_sha1_info(struct diff_filespec *one)
 +static void diff_fill_oid_info(struct diff_filespec *one)
  {
        if (DIFF_FILE_VALID(one)) {
                if (!one->oid_valid) {
@@@ -3298,8 -3299,8 +3299,8 @@@ static void run_diff(struct diff_filepa
                return;
        }
  
 -      diff_fill_sha1_info(one);
 -      diff_fill_sha1_info(two);
 +      diff_fill_oid_info(one);
 +      diff_fill_oid_info(two);
  
        if (!pgm &&
            DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) &&
@@@ -3344,8 -3345,8 +3345,8 @@@ static void run_diffstat(struct diff_fi
        if (o->prefix_length)
                strip_prefix(o->prefix_length, &name, &other);
  
 -      diff_fill_sha1_info(p->one);
 -      diff_fill_sha1_info(p->two);
 +      diff_fill_oid_info(p->one);
 +      diff_fill_oid_info(p->two);
  
        builtin_diffstat(name, other, p->one, p->two, diffstat, o, p);
  }
@@@ -3368,8 -3369,8 +3369,8 @@@ static void run_checkdiff(struct diff_f
        if (o->prefix_length)
                strip_prefix(o->prefix_length, &name, &other);
  
 -      diff_fill_sha1_info(p->one);
 -      diff_fill_sha1_info(p->two);
 +      diff_fill_oid_info(p->one);
 +      diff_fill_oid_info(p->two);
  
        builtin_checkdiff(name, other, attr_path, p->one, p->two, o);
  }
@@@ -4071,7 -4072,9 +4072,7 @@@ int diff_opt_parse(struct diff_options 
                DIFF_OPT_CLR(options, FUNCCONTEXT);
        else if ((argcount = parse_long_opt("output", av, &optarg))) {
                char *path = prefix_filename(prefix, optarg);
 -              options->file = fopen(path, "w");
 -              if (!options->file)
 -                      die_errno("Could not open '%s'", path);
 +              options->file = xfopen(path, "w");
                options->close_file = 1;
                if (options->use_color != GIT_COLOR_ALWAYS)
                        options->use_color = GIT_COLOR_NEVER;
@@@ -4582,7 -4585,7 +4583,7 @@@ static void patch_id_add_mode(git_SHA_C
  }
  
  /* returns 0 upon success, and writes result into sha1 */
 -static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1, int diff_header_only)
 +static int diff_get_patch_id(struct diff_options *options, struct object_id *oid, int diff_header_only)
  {
        struct diff_queue_struct *q = &diff_queued_diff;
        int i;
                if (DIFF_PAIR_UNMERGED(p))
                        continue;
  
 -              diff_fill_sha1_info(p->one);
 -              diff_fill_sha1_info(p->two);
 +              diff_fill_oid_info(p->one);
 +              diff_fill_oid_info(p->two);
  
                len1 = remove_space(p->one->path, strlen(p->one->path));
                len2 = remove_space(p->two->path, strlen(p->two->path));
                if (diff_filespec_is_binary(p->one) ||
                    diff_filespec_is_binary(p->two)) {
                        git_SHA1_Update(&ctx, oid_to_hex(&p->one->oid),
 -                                      40);
 +                                      GIT_SHA1_HEXSZ);
                        git_SHA1_Update(&ctx, oid_to_hex(&p->two->oid),
 -                                      40);
 +                                      GIT_SHA1_HEXSZ);
                        continue;
                }
  
                                     p->one->path);
        }
  
 -      git_SHA1_Final(sha1, &ctx);
 +      git_SHA1_Final(oid->hash, &ctx);
        return 0;
  }
  
 -int diff_flush_patch_id(struct diff_options *options, unsigned char *sha1, int diff_header_only)
 +int diff_flush_patch_id(struct diff_options *options, struct object_id *oid, int diff_header_only)
  {
        struct diff_queue_struct *q = &diff_queued_diff;
        int i;
 -      int result = diff_get_patch_id(options, sha1, diff_header_only);
 +      int result = diff_get_patch_id(options, oid, diff_header_only);
  
        for (i = 0; i < q->nr; i++)
                diff_free_filepair(q->queue[i]);
@@@ -4805,7 -4808,9 +4806,7 @@@ void diff_flush(struct diff_options *op
                 */
                if (options->close_file)
                        fclose(options->file);
 -              options->file = fopen("/dev/null", "w");
 -              if (!options->file)
 -                      die_errno("Could not open /dev/null");
 +              options->file = xfopen("/dev/null", "w");
                options->close_file = 1;
                for (i = 0; i < q->nr; i++) {
                        struct diff_filepair *p = q->queue[i];
@@@ -5077,8 -5082,8 +5078,8 @@@ static int is_submodule_ignored(const c
  
  void diff_addremove(struct diff_options *options,
                    int addremove, unsigned mode,
 -                  const unsigned char *sha1,
 -                  int sha1_valid,
 +                  const struct object_id *oid,
 +                  int oid_valid,
                    const char *concatpath, unsigned dirty_submodule)
  {
        struct diff_filespec *one, *two;
        two = alloc_filespec(concatpath);
  
        if (addremove != '+')
 -              fill_filespec(one, sha1, sha1_valid, mode);
 +              fill_filespec(one, oid, oid_valid, mode);
        if (addremove != '-') {
 -              fill_filespec(two, sha1, sha1_valid, mode);
 +              fill_filespec(two, oid, oid_valid, mode);
                two->dirty_submodule = dirty_submodule;
        }
  
  
  void diff_change(struct diff_options *options,
                 unsigned old_mode, unsigned new_mode,
 -               const unsigned char *old_sha1,
 -               const unsigned char *new_sha1,
 -               int old_sha1_valid, int new_sha1_valid,
 +               const struct object_id *old_oid,
 +               const struct object_id *new_oid,
 +               int old_oid_valid, int new_oid_valid,
                 const char *concatpath,
                 unsigned old_dirty_submodule, unsigned new_dirty_submodule)
  {
  
        if (DIFF_OPT_TST(options, REVERSE_DIFF)) {
                SWAP(old_mode, new_mode);
 -              SWAP(old_sha1, new_sha1);
 -              SWAP(old_sha1_valid, new_sha1_valid);
 +              SWAP(old_oid, new_oid);
 +              SWAP(old_oid_valid, new_oid_valid);
                SWAP(old_dirty_submodule, new_dirty_submodule);
        }
  
  
        one = alloc_filespec(concatpath);
        two = alloc_filespec(concatpath);
 -      fill_filespec(one, old_sha1, old_sha1_valid, old_mode);
 -      fill_filespec(two, new_sha1, new_sha1_valid, new_mode);
 +      fill_filespec(one, old_oid, old_oid_valid, old_mode);
 +      fill_filespec(two, new_oid, new_oid_valid, new_mode);
        one->dirty_submodule = old_dirty_submodule;
        two->dirty_submodule = new_dirty_submodule;
        p = diff_queue(&diff_queued_diff, one, two);
@@@ -5240,7 -5245,7 +5241,7 @@@ size_t fill_textconv(struct userdiff_dr
  
        if (driver->textconv_cache && df->oid_valid) {
                *outbuf = notes_cache_get(driver->textconv_cache,
 -                                        df->oid.hash,
 +                                        &df->oid,
                                          &size);
                if (*outbuf)
                        return size;
  
        if (driver->textconv_cache && df->oid_valid) {
                /* ignore errors, as we might be in a readonly repository */
 -              notes_cache_put(driver->textconv_cache, df->oid.hash, *outbuf,
 +              notes_cache_put(driver->textconv_cache, &df->oid, *outbuf,
                                size);
                /*
                 * we could save up changes and flush them all at the end,
        return size;
  }
  
 +int textconv_object(const char *path,
 +                  unsigned mode,
 +                  const struct object_id *oid,
 +                  int oid_valid,
 +                  char **buf,
 +                  unsigned long *buf_size)
 +{
 +      struct diff_filespec *df;
 +      struct userdiff_driver *textconv;
 +
 +      df = alloc_filespec(path);
 +      fill_filespec(df, oid, oid_valid, mode);
 +      textconv = get_textconv(df);
 +      if (!textconv) {
 +              free_filespec(df);
 +              return 0;
 +      }
 +
 +      *buf_size = fill_textconv(textconv, df, buf);
 +      free_filespec(df);
 +      return 1;
 +}
 +
  void setup_diff_pager(struct diff_options *opt)
  {
        /*
diff --combined dir.c
index 6687d84dbc8dfb4f6d39028e2b9636278a6146e2,42beb65beaa03dbcf5fb312d7c280a1b3251614b..f6795473f7e52c790605d23628f81e3b295155d8
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -7,8 -7,8 +7,9 @@@
   * Copyright (C) Linus Torvalds, 2005-2006
   *             Junio Hamano, 2005-2006
   */
 +#define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
+ #include "config.h"
  #include "dir.h"
  #include "attr.h"
  #include "refs.h"
@@@ -46,20 -46,9 +47,20 @@@ struct cached_dir 
  };
  
  static enum path_treatment read_directory_recursive(struct dir_struct *dir,
 -      const char *path, int len, struct untracked_cache_dir *untracked,
 +      struct index_state *istate, const char *path, int len,
 +      struct untracked_cache_dir *untracked,
        int check_only, const struct pathspec *pathspec);
 -static int get_dtype(struct dirent *de, const char *path, int len);
 +static int get_dtype(struct dirent *de, struct index_state *istate,
 +                   const char *path, int len);
 +
 +int count_slashes(const char *s)
 +{
 +      int cnt = 0;
 +      while (*s)
 +              if (*s++ == '/')
 +                      cnt++;
 +      return cnt;
 +}
  
  int fspathcmp(const char *a, const char *b)
  {
@@@ -186,9 -175,7 +187,9 @@@ char *common_prefix(const struct pathsp
        return len ? xmemdupz(pathspec->items[0].match, len) : NULL;
  }
  
 -int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)
 +int fill_directory(struct dir_struct *dir,
 +                 struct index_state *istate,
 +                 const struct pathspec *pathspec)
  {
        const char *prefix;
        size_t prefix_len;
        prefix = prefix_len ? pathspec->items[0].match : "";
  
        /* Read the directory and prune it */
 -      read_directory(dir, prefix, prefix_len, pathspec);
 +      read_directory(dir, istate, prefix, prefix_len, pathspec);
  
        return prefix_len;
  }
@@@ -601,8 -588,7 +602,8 @@@ void add_exclude(const char *string, co
        x->el = el;
  }
  
 -static void *read_skip_worktree_file_from_index(const char *path, size_t *size,
 +static void *read_skip_worktree_file_from_index(const struct index_state *istate,
 +                                              const char *path, size_t *size,
                                                struct sha1_stat *sha1_stat)
  {
        int pos, len;
        void *data;
  
        len = strlen(path);
 -      pos = cache_name_pos(path, len);
 +      pos = index_name_pos(istate, path, len);
        if (pos < 0)
                return NULL;
 -      if (!ce_skip_worktree(active_cache[pos]))
 +      if (!ce_skip_worktree(istate->cache[pos]))
                return NULL;
 -      data = read_sha1_file(active_cache[pos]->oid.hash, &type, &sz);
 +      data = read_sha1_file(istate->cache[pos]->oid.hash, &type, &sz);
        if (!data || type != OBJ_BLOB) {
                free(data);
                return NULL;
        *size = xsize_t(sz);
        if (sha1_stat) {
                memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat));
 -              hashcpy(sha1_stat->sha1, active_cache[pos]->oid.hash);
 +              hashcpy(sha1_stat->sha1, istate->cache[pos]->oid.hash);
        }
        return data;
  }
@@@ -742,7 -728,7 +743,7 @@@ static void invalidate_directory(struc
  
  /*
   * Given a file with name "fname", read it (either from disk, or from
 - * the index if "check_index" is non-zero), parse it and store the
 + * an index if 'istate' is non-null), parse it and store the
   * exclude rules in "el".
   *
   * If "ss" is not NULL, compute SHA-1 of the exclude file and fill
   * ss_valid is non-zero, "ss" must contain good value as input.
   */
  static int add_excludes(const char *fname, const char *base, int baselen,
 -                      struct exclude_list *el, int check_index,
 +                      struct exclude_list *el,
 +                      struct index_state *istate,
                        struct sha1_stat *sha1_stat)
  {
        struct stat st;
  
        fd = open(fname, O_RDONLY);
        if (fd < 0 || fstat(fd, &st) < 0) {
 -              if (errno != ENOENT)
 -                      warn_on_inaccessible(fname);
 -              if (0 <= fd)
 +              if (fd < 0)
 +                      warn_on_fopen_errors(fname);
 +              else
                        close(fd);
 -              if (!check_index ||
 -                  (buf = read_skip_worktree_file_from_index(fname, &size, sha1_stat)) == NULL)
 +              if (!istate ||
 +                  (buf = read_skip_worktree_file_from_index(istate, fname, &size, sha1_stat)) == NULL)
                        return -1;
                if (size == 0) {
                        free(buf);
                if (sha1_stat) {
                        int pos;
                        if (sha1_stat->valid &&
 -                          !match_stat_data_racy(&the_index, &sha1_stat->stat, &st))
 +                          !match_stat_data_racy(istate, &sha1_stat->stat, &st))
                                ; /* no content change, ss->sha1 still good */
 -                      else if (check_index &&
 -                               (pos = cache_name_pos(fname, strlen(fname))) >= 0 &&
 -                               !ce_stage(active_cache[pos]) &&
 -                               ce_uptodate(active_cache[pos]) &&
 -                               !would_convert_to_git(fname))
 +                      else if (istate &&
 +                               (pos = index_name_pos(istate, fname, strlen(fname))) >= 0 &&
 +                               !ce_stage(istate->cache[pos]) &&
 +                               ce_uptodate(istate->cache[pos]) &&
 +                               !would_convert_to_git(istate, fname))
                                hashcpy(sha1_stat->sha1,
 -                                      active_cache[pos]->oid.hash);
 +                                      istate->cache[pos]->oid.hash);
                        else
                                hash_sha1_file(buf, size, "blob", sha1_stat->sha1);
                        fill_stat_data(&sha1_stat->stat, &st);
  
  int add_excludes_from_file_to_list(const char *fname, const char *base,
                                   int baselen, struct exclude_list *el,
 -                                 int check_index)
 +                                 struct index_state *istate)
  {
 -      return add_excludes(fname, base, baselen, el, check_index, NULL);
 +      return add_excludes(fname, base, baselen, el, istate, NULL);
  }
  
  struct exclude_list *add_exclude_list(struct dir_struct *dir,
@@@ -871,7 -856,7 +872,7 @@@ static void add_excludes_from_file_1(st
        if (!dir->untracked)
                dir->unmanaged_exclude_files++;
        el = add_exclude_list(dir, EXC_FILE, fname);
 -      if (add_excludes(fname, "", 0, el, 0, sha1_stat) < 0)
 +      if (add_excludes(fname, "", 0, el, NULL, sha1_stat) < 0)
                die("cannot use %s as an exclude file", fname);
  }
  
@@@ -974,8 -959,7 +975,8 @@@ static struct exclude *last_exclude_mat
                                                       int pathlen,
                                                       const char *basename,
                                                       int *dtype,
 -                                                     struct exclude_list *el)
 +                                                     struct exclude_list *el,
 +                                                     struct index_state *istate)
  {
        struct exclude *exc = NULL; /* undecided */
        int i;
  
                if (x->flags & EXC_FLAG_MUSTBEDIR) {
                        if (*dtype == DT_UNKNOWN)
 -                              *dtype = get_dtype(NULL, pathname, pathlen);
 +                              *dtype = get_dtype(NULL, istate, pathname, pathlen);
                        if (*dtype != DT_DIR)
                                continue;
                }
   */
  int is_excluded_from_list(const char *pathname,
                          int pathlen, const char *basename, int *dtype,
 -                        struct exclude_list *el)
 +                        struct exclude_list *el, struct index_state *istate)
  {
        struct exclude *exclude;
 -      exclude = last_exclude_matching_from_list(pathname, pathlen, basename, dtype, el);
 +      exclude = last_exclude_matching_from_list(pathname, pathlen, basename,
 +                                                dtype, el, istate);
        if (exclude)
                return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
        return -1; /* undecided */
  }
  
  static struct exclude *last_exclude_matching_from_lists(struct dir_struct *dir,
 +                                                      struct index_state *istate,
                const char *pathname, int pathlen, const char *basename,
                int *dtype_p)
  {
                for (j = group->nr - 1; j >= 0; j--) {
                        exclude = last_exclude_matching_from_list(
                                pathname, pathlen, basename, dtype_p,
 -                              &group->el[j]);
 +                              &group->el[j], istate);
                        if (exclude)
                                return exclude;
                }
   * Loads the per-directory exclude list for the substring of base
   * which has a char length of baselen.
   */
 -static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
 +static void prep_exclude(struct dir_struct *dir,
 +                       struct index_state *istate,
 +                       const char *base, int baselen)
  {
        struct exclude_list_group *group;
        struct exclude_list *el;
                        int dt = DT_DIR;
                        dir->basebuf.buf[stk->baselen - 1] = 0;
                        dir->exclude = last_exclude_matching_from_lists(dir,
 +                                                                      istate,
                                dir->basebuf.buf, stk->baselen - 1,
                                dir->basebuf.buf + current, &dt);
                        dir->basebuf.buf[stk->baselen - 1] = '/';
                        strbuf_addbuf(&sb, &dir->basebuf);
                        strbuf_addstr(&sb, dir->exclude_per_dir);
                        el->src = strbuf_detach(&sb, NULL);
 -                      add_excludes(el->src, el->src, stk->baselen, el, 1,
 +                      add_excludes(el->src, el->src, stk->baselen, el, istate,
                                     untracked ? &sha1_stat : NULL);
                }
                /*
   * undecided.
   */
  struct exclude *last_exclude_matching(struct dir_struct *dir,
 -                                           const char *pathname,
 -                                           int *dtype_p)
 +                                    struct index_state *istate,
 +                                    const char *pathname,
 +                                    int *dtype_p)
  {
        int pathlen = strlen(pathname);
        const char *basename = strrchr(pathname, '/');
        basename = (basename) ? basename+1 : pathname;
  
 -      prep_exclude(dir, pathname, basename-pathname);
 +      prep_exclude(dir, istate, pathname, basename-pathname);
  
        if (dir->exclude)
                return dir->exclude;
  
 -      return last_exclude_matching_from_lists(dir, pathname, pathlen,
 +      return last_exclude_matching_from_lists(dir, istate, pathname, pathlen,
                        basename, dtype_p);
  }
  
   * scans all exclude lists to determine whether pathname is excluded.
   * Returns 1 if true, otherwise 0.
   */
 -int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
 +int is_excluded(struct dir_struct *dir, struct index_state *istate,
 +              const char *pathname, int *dtype_p)
  {
        struct exclude *exclude =
 -              last_exclude_matching(dir, pathname, dtype_p);
 +              last_exclude_matching(dir, istate, pathname, dtype_p);
        if (exclude)
                return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
        return 0;
@@@ -1257,22 -1234,18 +1258,22 @@@ static struct dir_entry *dir_entry_new(
        return ent;
  }
  
 -static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
 +static struct dir_entry *dir_add_name(struct dir_struct *dir,
 +                                    struct index_state *istate,
 +                                    const char *pathname, int len)
  {
 -      if (cache_file_exists(pathname, len, ignore_case))
 +      if (index_file_exists(istate, pathname, len, ignore_case))
                return NULL;
  
        ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
        return dir->entries[dir->nr++] = dir_entry_new(pathname, len);
  }
  
 -struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len)
 +struct dir_entry *dir_add_ignored(struct dir_struct *dir,
 +                                struct index_state *istate,
 +                                const char *pathname, int len)
  {
 -      if (!cache_name_is_other(pathname, len))
 +      if (!index_name_is_other(istate, pathname, len))
                return NULL;
  
        ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc);
@@@ -1290,15 -1263,14 +1291,15 @@@ enum exist_status 
   * the directory name; instead, use the case insensitive
   * directory hash.
   */
 -static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)
 +static enum exist_status directory_exists_in_index_icase(struct index_state *istate,
 +                                                       const char *dirname, int len)
  {
        struct cache_entry *ce;
  
 -      if (cache_dir_exists(dirname, len))
 +      if (index_dir_exists(istate, dirname, len))
                return index_directory;
  
 -      ce = cache_file_exists(dirname, len, ignore_case);
 +      ce = index_file_exists(istate, dirname, len, ignore_case);
        if (ce && S_ISGITLINK(ce->ce_mode))
                return index_gitdir;
  
   * the files it contains) will sort with the '/' at the
   * end.
   */
 -static enum exist_status directory_exists_in_index(const char *dirname, int len)
 +static enum exist_status directory_exists_in_index(struct index_state *istate,
 +                                                 const char *dirname, int len)
  {
        int pos;
  
        if (ignore_case)
 -              return directory_exists_in_index_icase(dirname, len);
 +              return directory_exists_in_index_icase(istate, dirname, len);
  
 -      pos = cache_name_pos(dirname, len);
 +      pos = index_name_pos(istate, dirname, len);
        if (pos < 0)
                pos = -pos-1;
 -      while (pos < active_nr) {
 -              const struct cache_entry *ce = active_cache[pos++];
 +      while (pos < istate->cache_nr) {
 +              const struct cache_entry *ce = istate->cache[pos++];
                unsigned char endchar;
  
                if (strncmp(ce->name, dirname, len))
   *  (c) otherwise, we recurse into it.
   */
  static enum path_treatment treat_directory(struct dir_struct *dir,
 +      struct index_state *istate,
        struct untracked_cache_dir *untracked,
        const char *dirname, int len, int baselen, int exclude,
        const struct pathspec *pathspec)
  {
        /* The "len-1" is to strip the final '/' */
 -      switch (directory_exists_in_index(dirname, len-1)) {
 +      switch (directory_exists_in_index(istate, dirname, len-1)) {
        case index_directory:
                return path_recurse;
  
  
        untracked = lookup_untracked(dir->untracked, untracked,
                                     dirname + baselen, len - baselen);
 -      return read_directory_recursive(dir, dirname, len,
 +      return read_directory_recursive(dir, istate, dirname, len,
                                        untracked, 1, pathspec);
  }
  
@@@ -1486,13 -1456,12 +1487,13 @@@ static int exclude_matches_pathspec(con
        return 0;
  }
  
 -static int get_index_dtype(const char *path, int len)
 +static int get_index_dtype(struct index_state *istate,
 +                         const char *path, int len)
  {
        int pos;
        const struct cache_entry *ce;
  
 -      ce = cache_file_exists(path, len, 0);
 +      ce = index_file_exists(istate, path, len, 0);
        if (ce) {
                if (!ce_uptodate(ce))
                        return DT_UNKNOWN;
        }
  
        /* Try to look it up as a directory */
 -      pos = cache_name_pos(path, len);
 +      pos = index_name_pos(istate, path, len);
        if (pos >= 0)
                return DT_UNKNOWN;
        pos = -pos-1;
 -      while (pos < active_nr) {
 -              ce = active_cache[pos++];
 +      while (pos < istate->cache_nr) {
 +              ce = istate->cache[pos++];
                if (strncmp(ce->name, path, len))
                        break;
                if (ce->name[len] > '/')
        return DT_UNKNOWN;
  }
  
 -static int get_dtype(struct dirent *de, const char *path, int len)
 +static int get_dtype(struct dirent *de, struct index_state *istate,
 +                   const char *path, int len)
  {
        int dtype = de ? DTYPE(de) : DT_UNKNOWN;
        struct stat st;
  
        if (dtype != DT_UNKNOWN)
                return dtype;
 -      dtype = get_index_dtype(path, len);
 +      dtype = get_index_dtype(istate, path, len);
        if (dtype != DT_UNKNOWN)
                return dtype;
        if (lstat(path, &st))
  
  static enum path_treatment treat_one_path(struct dir_struct *dir,
                                          struct untracked_cache_dir *untracked,
 +                                        struct index_state *istate,
                                          struct strbuf *path,
                                          int baselen,
                                          const struct pathspec *pathspec,
                                          int dtype, struct dirent *de)
  {
        int exclude;
 -      int has_path_in_index = !!cache_file_exists(path->buf, path->len, ignore_case);
 +      int has_path_in_index = !!index_file_exists(istate, path->buf, path->len, ignore_case);
  
        if (dtype == DT_UNKNOWN)
 -              dtype = get_dtype(de, path->buf, path->len);
 +              dtype = get_dtype(de, istate, path->buf, path->len);
  
        /* Always exclude indexed files */
        if (dtype != DT_DIR && has_path_in_index)
        if ((dir->flags & DIR_COLLECT_KILLED_ONLY) &&
            (dtype == DT_DIR) &&
            !has_path_in_index &&
 -          (directory_exists_in_index(path->buf, path->len) == index_nonexistent))
 +          (directory_exists_in_index(istate, path->buf, path->len) == index_nonexistent))
                return path_none;
  
 -      exclude = is_excluded(dir, path->buf, &dtype);
 +      exclude = is_excluded(dir, istate, path->buf, &dtype);
  
        /*
         * Excluded? If we don't explicitly want to show
                return path_none;
        case DT_DIR:
                strbuf_addch(path, '/');
 -              return treat_directory(dir, untracked, path->buf, path->len,
 +              return treat_directory(dir, istate, untracked, path->buf, path->len,
                                       baselen, exclude, pathspec);
        case DT_REG:
        case DT_LNK:
  static enum path_treatment treat_path_fast(struct dir_struct *dir,
                                           struct untracked_cache_dir *untracked,
                                           struct cached_dir *cdir,
 +                                         struct index_state *istate,
                                           struct strbuf *path,
                                           int baselen,
                                           const struct pathspec *pathspec)
                 * to its bottom. Verify again the same set of directories
                 * with check_only set.
                 */
 -              return read_directory_recursive(dir, path->buf, path->len,
 +              return read_directory_recursive(dir, istate, path->buf, path->len,
                                                cdir->ucd, 1, pathspec);
        /*
         * We get path_recurse in the first run when
  static enum path_treatment treat_path(struct dir_struct *dir,
                                      struct untracked_cache_dir *untracked,
                                      struct cached_dir *cdir,
 +                                    struct index_state *istate,
                                      struct strbuf *path,
                                      int baselen,
                                      const struct pathspec *pathspec)
        struct dirent *de = cdir->de;
  
        if (!de)
 -              return treat_path_fast(dir, untracked, cdir, path,
 +              return treat_path_fast(dir, untracked, cdir, istate, path,
                                       baselen, pathspec);
        if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git"))
                return path_none;
                return path_none;
  
        dtype = DTYPE(de);
 -      return treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de);
 +      return treat_one_path(dir, untracked, istate, path, baselen, pathspec, dtype, de);
  }
  
  static void add_untracked(struct untracked_cache_dir *dir, const char *name)
  
  static int valid_cached_dir(struct dir_struct *dir,
                            struct untracked_cache_dir *untracked,
 +                          struct index_state *istate,
                            struct strbuf *path,
                            int check_only)
  {
                return 0;
        }
        if (!untracked->valid ||
 -          match_stat_data_racy(&the_index, &untracked->stat_data, &st)) {
 +          match_stat_data_racy(istate, &untracked->stat_data, &st)) {
                if (untracked->valid)
                        invalidate_directory(dir->untracked, untracked);
                fill_stat_data(&untracked->stat_data, &st);
         */
        if (path->len && path->buf[path->len - 1] != '/') {
                strbuf_addch(path, '/');
 -              prep_exclude(dir, path->buf, path->len);
 +              prep_exclude(dir, istate, path->buf, path->len);
                strbuf_setlen(path, path->len - 1);
        } else
 -              prep_exclude(dir, path->buf, path->len);
 +              prep_exclude(dir, istate, path->buf, path->len);
  
        /* hopefully prep_exclude() haven't invalidated this entry... */
        return untracked->valid;
  static int open_cached_dir(struct cached_dir *cdir,
                           struct dir_struct *dir,
                           struct untracked_cache_dir *untracked,
 +                         struct index_state *istate,
                           struct strbuf *path,
                           int check_only)
  {
        memset(cdir, 0, sizeof(*cdir));
        cdir->untracked = untracked;
 -      if (valid_cached_dir(dir, untracked, path, check_only))
 +      if (valid_cached_dir(dir, untracked, istate, path, check_only))
                return 0;
        cdir->fdir = opendir(path->len ? path->buf : ".");
        if (dir->untracked)
@@@ -1797,9 -1760,9 +1798,9 @@@ static void close_cached_dir(struct cac
   * Returns the most significant path_treatment value encountered in the scan.
   */
  static enum path_treatment read_directory_recursive(struct dir_struct *dir,
 -                                  const char *base, int baselen,
 -                                  struct untracked_cache_dir *untracked, int check_only,
 -                                  const struct pathspec *pathspec)
 +      struct index_state *istate, const char *base, int baselen,
 +      struct untracked_cache_dir *untracked, int check_only,
 +      const struct pathspec *pathspec)
  {
        struct cached_dir cdir;
        enum path_treatment state, subdir_state, dir_state = path_none;
  
        strbuf_add(&path, base, baselen);
  
 -      if (open_cached_dir(&cdir, dir, untracked, &path, check_only))
 +      if (open_cached_dir(&cdir, dir, untracked, istate, &path, check_only))
                goto out;
  
        if (untracked)
  
        while (!read_cached_dir(&cdir)) {
                /* check how the file or directory should be treated */
 -              state = treat_path(dir, untracked, &cdir, &path,
 +              state = treat_path(dir, untracked, &cdir, istate, &path,
                                   baselen, pathspec);
  
                if (state > dir_state)
                        dir_state = state;
  
                /* recurse into subdir if instructed by treat_path */
 -              if (state == path_recurse) {
 +              if ((state == path_recurse) ||
 +                      ((state == path_untracked) &&
 +                       (dir->flags & DIR_SHOW_IGNORED_TOO) &&
 +                       (get_dtype(cdir.de, istate, path.buf, path.len) == DT_DIR))) {
                        struct untracked_cache_dir *ud;
                        ud = lookup_untracked(dir->untracked, untracked,
                                              path.buf + baselen,
                                              path.len - baselen);
                        subdir_state =
 -                              read_directory_recursive(dir, path.buf,
 +                              read_directory_recursive(dir, istate, path.buf,
                                                         path.len, ud,
                                                         check_only, pathspec);
                        if (subdir_state > dir_state)
                switch (state) {
                case path_excluded:
                        if (dir->flags & DIR_SHOW_IGNORED)
 -                              dir_add_name(dir, path.buf, path.len);
 +                              dir_add_name(dir, istate, path.buf, path.len);
                        else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
                                ((dir->flags & DIR_COLLECT_IGNORED) &&
                                exclude_matches_pathspec(path.buf, path.len,
                                                         pathspec)))
 -                              dir_add_ignored(dir, path.buf, path.len);
 +                              dir_add_ignored(dir, istate, path.buf, path.len);
                        break;
  
                case path_untracked:
                        if (dir->flags & DIR_SHOW_IGNORED)
                                break;
 -                      dir_add_name(dir, path.buf, path.len);
 +                      dir_add_name(dir, istate, path.buf, path.len);
                        if (cdir.fdir)
                                add_untracked(untracked, path.buf + baselen);
                        break;
        return dir_state;
  }
  
 -static int cmp_name(const void *p1, const void *p2)
 +int cmp_dir_entry(const void *p1, const void *p2)
  {
        const struct dir_entry *e1 = *(const struct dir_entry **)p1;
        const struct dir_entry *e2 = *(const struct dir_entry **)p2;
        return name_compare(e1->name, e1->len, e2->name, e2->len);
  }
  
 +/* check if *out lexically strictly contains *in */
 +int check_dir_entry_contains(const struct dir_entry *out, const struct dir_entry *in)
 +{
 +      return (out->len < in->len) &&
 +              (out->name[out->len - 1] == '/') &&
 +              !memcmp(out->name, in->name, out->len);
 +}
 +
  static int treat_leading_path(struct dir_struct *dir,
 +                            struct index_state *istate,
                              const char *path, int len,
                              const struct pathspec *pathspec)
  {
                        break;
                if (simplify_away(sb.buf, sb.len, pathspec))
                        break;
 -              if (treat_one_path(dir, NULL, &sb, baselen, pathspec,
 +              if (treat_one_path(dir, NULL, istate, &sb, baselen, pathspec,
                                   DT_DIR, NULL) == path_none)
                        break; /* do not recurse into it */
                if (len <= baselen) {
@@@ -2093,8 -2044,8 +2094,8 @@@ static struct untracked_cache_dir *vali
        return root;
  }
  
 -int read_directory(struct dir_struct *dir, const char *path,
 -                 int len, const struct pathspec *pathspec)
 +int read_directory(struct dir_struct *dir, struct index_state *istate,
 +                 const char *path, int len, const struct pathspec *pathspec)
  {
        struct untracked_cache_dir *untracked;
  
                 * e.g. prep_exclude()
                 */
                dir->untracked = NULL;
 -      if (!len || treat_leading_path(dir, path, len, pathspec))
 -              read_directory_recursive(dir, path, len, untracked, 0, pathspec);
 -      QSORT(dir->entries, dir->nr, cmp_name);
 -      QSORT(dir->ignored, dir->ignored_nr, cmp_name);
 +      if (!len || treat_leading_path(dir, istate, path, len, pathspec))
 +              read_directory_recursive(dir, istate, path, len, untracked, 0, pathspec);
 +      QSORT(dir->entries, dir->nr, cmp_dir_entry);
 +      QSORT(dir->ignored, dir->ignored_nr, cmp_dir_entry);
 +
 +      /*
 +       * If DIR_SHOW_IGNORED_TOO is set, read_directory_recursive() will
 +       * also pick up untracked contents of untracked dirs; by default
 +       * we discard these, but given DIR_KEEP_UNTRACKED_CONTENTS we do not.
 +       */
 +      if ((dir->flags & DIR_SHOW_IGNORED_TOO) &&
 +                   !(dir->flags & DIR_KEEP_UNTRACKED_CONTENTS)) {
 +              int i, j;
 +
 +              /* remove from dir->entries untracked contents of untracked dirs */
 +              for (i = j = 0; j < dir->nr; j++) {
 +                      if (i &&
 +                          check_dir_entry_contains(dir->entries[i - 1], dir->entries[j])) {
 +                              free(dir->entries[j]);
 +                              dir->entries[j] = NULL;
 +                      } else {
 +                              dir->entries[i++] = dir->entries[j];
 +                      }
 +              }
 +
 +              dir->nr = i;
 +      }
 +
        if (dir->untracked) {
                static struct trace_key trace_untracked_stats = TRACE_KEY_INIT(UNTRACKED_STATS);
                trace_printf_key(&trace_untracked_stats,
                                 dir->untracked->gitignore_invalidated,
                                 dir->untracked->dir_invalidated,
                                 dir->untracked->dir_opened);
 -              if (dir->untracked == the_index.untracked &&
 +              if (dir->untracked == istate->untracked &&
                    (dir->untracked->dir_opened ||
                     dir->untracked->gitignore_invalidated ||
                     dir->untracked->dir_invalidated))
 -                      the_index.cache_changed |= UNTRACKED_CHANGED;
 -              if (dir->untracked != the_index.untracked) {
 +                      istate->cache_changed |= UNTRACKED_CHANGED;
 +              if (dir->untracked != istate->untracked) {
                        free(dir->untracked);
                        dir->untracked = NULL;
                }
@@@ -2346,7 -2273,7 +2347,7 @@@ int remove_path(const char *name
  {
        char *slash;
  
 -      if (unlink(name) && errno != ENOENT && errno != ENOTDIR)
 +      if (unlink(name) && !is_missing_file_error(errno))
                return -1;
  
        slash = strrchr(name, '/');
diff --combined environment.c
index aa478e71de9d9c233593de050d6823e96be77b88,9d9b367925d7d517b2240b8d59d8ca802452823e..d40b21fb72168f32f1aaeac553347859e32f90c0
@@@ -8,6 -8,7 +8,7 @@@
   * are.
   */
  #include "cache.h"
+ #include "config.h"
  #include "refs.h"
  #include "fmt-merge-msg.h"
  #include "commit.h"
@@@ -169,7 -170,7 +170,7 @@@ static void setup_git_env(void
        git_dir = getenv(GIT_DIR_ENVIRONMENT);
        if (!git_dir) {
                if (!startup_info->have_repository)
 -                      die("BUG: setup_git_env called without repository");
 +                      BUG("setup_git_env called without repository");
                git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
        }
        gitfile = read_gitfile(git_dir);
@@@ -217,8 -218,6 +218,8 @@@ const char *get_git_dir(void
  
  const char *get_git_common_dir(void)
  {
 +      if (!git_dir)
 +              setup_git_env();
        return git_common_dir;
  }
  
diff --combined fast-import.c
index fc2b22033b0f5748adbc173b6099fa7347bb9088,bbc3e79eaf8ea5cb4d2bf56b530b610193e87924..12b90fe9e34a6431ec241e80398b833264363361
@@@ -154,6 -154,7 +154,7 @@@ Format of STDIN stream
  
  #include "builtin.h"
  #include "cache.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "object.h"
  #include "blob.h"
@@@ -226,7 -227,7 +227,7 @@@ struct tree_entry 
        struct atom_str *name;
        struct tree_entry_ms {
                uint16_t mode;
 -              unsigned char sha1[20];
 +              struct object_id oid;
        } versions[2];
  };
  
@@@ -252,19 -253,19 +253,19 @@@ struct branch 
        unsigned active : 1;
        unsigned delete : 1;
        unsigned pack_id : PACK_ID_BITS;
 -      unsigned char sha1[20];
 +      struct object_id oid;
  };
  
  struct tag {
        struct tag *next_tag;
        const char *name;
        unsigned int pack_id;
 -      unsigned char sha1[20];
 +      struct object_id oid;
  };
  
  struct hash_list {
        struct hash_list *next;
 -      unsigned char sha1[20];
 +      struct object_id oid;
  };
  
  typedef enum {
@@@ -280,7 -281,7 +281,7 @@@ struct recent_command 
  };
  
  /* Configured limits on output */
 -static unsigned long max_depth = 10;
 +static unsigned long max_depth = 50;
  static off_t max_packsize;
  static int unpack_limit = 100;
  static int force_update;
@@@ -386,15 -387,13 +387,15 @@@ static void write_branch_report(FILE *r
                fputs(" active", rpt);
        if (b->branch_tree.tree)
                fputs(" loaded", rpt);
 -      if (is_null_sha1(b->branch_tree.versions[1].sha1))
 +      if (is_null_oid(&b->branch_tree.versions[1].oid))
                fputs(" dirty", rpt);
        fputc('\n', rpt);
  
 -      fprintf(rpt, "  tip commit  : %s\n", sha1_to_hex(b->sha1));
 -      fprintf(rpt, "  old tree    : %s\n", sha1_to_hex(b->branch_tree.versions[0].sha1));
 -      fprintf(rpt, "  cur tree    : %s\n", sha1_to_hex(b->branch_tree.versions[1].sha1));
 +      fprintf(rpt, "  tip commit  : %s\n", oid_to_hex(&b->oid));
 +      fprintf(rpt, "  old tree    : %s\n",
 +              oid_to_hex(&b->branch_tree.versions[0].oid));
 +      fprintf(rpt, "  cur tree    : %s\n",
 +              oid_to_hex(&b->branch_tree.versions[1].oid));
        fprintf(rpt, "  commit clock: %" PRIuMAX "\n", b->last_commit);
  
        fputs("  last pack   : ", rpt);
@@@ -472,7 -471,7 +473,7 @@@ static void write_crash_report(const ch
                fputs("Annotated Tags\n", rpt);
                fputs("--------------\n", rpt);
                for (tg = first_tag; tg; tg = tg->next_tag) {
 -                      fputs(sha1_to_hex(tg->sha1), rpt);
 +                      fputs(oid_to_hex(&tg->oid), rpt);
                        fputc(' ', rpt);
                        fputs(tg->name, rpt);
                        fputc('\n', rpt);
@@@ -557,7 -556,7 +558,7 @@@ static void alloc_objects(unsigned int 
        alloc_count += cnt;
  }
  
 -static struct object_entry *new_object(unsigned char *sha1)
 +static struct object_entry *new_object(struct object_id *oid)
  {
        struct object_entry *e;
  
                alloc_objects(object_entry_alloc);
  
        e = blocks->next_free++;
 -      hashcpy(e->idx.sha1, sha1);
 +      oidcpy(&e->idx.oid, oid);
        return e;
  }
  
 -static struct object_entry *find_object(unsigned char *sha1)
 +static struct object_entry *find_object(struct object_id *oid)
  {
 -      unsigned int h = sha1[0] << 8 | sha1[1];
 +      unsigned int h = oid->hash[0] << 8 | oid->hash[1];
        struct object_entry *e;
        for (e = object_table[h]; e; e = e->next)
 -              if (!hashcmp(sha1, e->idx.sha1))
 +              if (!oidcmp(oid, &e->idx.oid))
                        return e;
        return NULL;
  }
  
 -static struct object_entry *insert_object(unsigned char *sha1)
 +static struct object_entry *insert_object(struct object_id *oid)
  {
 -      unsigned int h = sha1[0] << 8 | sha1[1];
 +      unsigned int h = oid->hash[0] << 8 | oid->hash[1];
        struct object_entry *e = object_table[h];
  
        while (e) {
 -              if (!hashcmp(sha1, e->idx.sha1))
 +              if (!oidcmp(oid, &e->idx.oid))
                        return e;
                e = e->next;
        }
  
 -      e = new_object(sha1);
 +      e = new_object(oid);
        e->next = object_table[h];
        e->idx.offset = 0;
        object_table[h] = e;
@@@ -878,7 -877,7 +879,7 @@@ static struct tree_content *dup_tree_co
                a = s->entries[i];
                b = new_tree_entry();
                memcpy(b, a, sizeof(*a));
 -              if (a->tree && is_null_sha1(b->versions[1].sha1))
 +              if (a->tree && is_null_oid(&b->versions[1].oid))
                        b->tree = dup_tree_content(a->tree);
                else
                        b->tree = NULL;
@@@ -1007,17 -1006,17 +1008,17 @@@ static void end_packfile(void
        clear_delta_base_cache();
        if (object_count) {
                struct packed_git *new_p;
 -              unsigned char cur_pack_sha1[20];
 +              struct object_id cur_pack_oid;
                char *idx_name;
                int i;
                struct branch *b;
                struct tag *t;
  
                close_pack_windows(pack_data);
 -              sha1close(pack_file, cur_pack_sha1, 0);
 +              sha1close(pack_file, cur_pack_oid.hash, 0);
                fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1,
                                    pack_data->pack_name, object_count,
 -                                  cur_pack_sha1, pack_size);
 +                                  cur_pack_oid.hash, pack_size);
  
                if (object_count <= unpack_limit) {
                        if (!loosen_small_pack(pack_data)) {
                        for (i = 0; i < branch_table_sz; i++) {
                                for (b = branch_table[i]; b; b = b->table_next_branch) {
                                        if (b->pack_id == pack_id)
 -                                              fprintf(pack_edges, " %s", sha1_to_hex(b->sha1));
 +                                              fprintf(pack_edges, " %s",
 +                                                      oid_to_hex(&b->oid));
                                }
                        }
                        for (t = first_tag; t; t = t->next_tag) {
                                if (t->pack_id == pack_id)
 -                                      fprintf(pack_edges, " %s", sha1_to_hex(t->sha1));
 +                                      fprintf(pack_edges, " %s",
 +                                              oid_to_hex(&t->oid));
                        }
                        fputc('\n', pack_edges);
                        fflush(pack_edges);
@@@ -1083,13 -1080,13 +1084,13 @@@ static int store_object
        enum object_type type,
        struct strbuf *dat,
        struct last_object *last,
 -      unsigned char *sha1out,
 +      struct object_id *oidout,
        uintmax_t mark)
  {
        void *out, *delta;
        struct object_entry *e;
        unsigned char hdr[96];
 -      unsigned char sha1[20];
 +      struct object_id oid;
        unsigned long hdrlen, deltalen;
        git_SHA_CTX c;
        git_zstream s;
        git_SHA1_Init(&c);
        git_SHA1_Update(&c, hdr, hdrlen);
        git_SHA1_Update(&c, dat->buf, dat->len);
 -      git_SHA1_Final(sha1, &c);
 -      if (sha1out)
 -              hashcpy(sha1out, sha1);
 +      git_SHA1_Final(oid.hash, &c);
 +      if (oidout)
 +              oidcpy(oidout, &oid);
  
 -      e = insert_object(sha1);
 +      e = insert_object(&oid);
        if (mark)
                insert_mark(mark, e);
        if (e->idx.offset) {
                duplicate_count_by_type[type]++;
                return 1;
 -      } else if (find_sha1_pack(sha1, packed_git)) {
 +      } else if (find_sha1_pack(oid.hash, packed_git)) {
                e->type = type;
                e->pack_id = MAX_PACK_ID;
                e->idx.offset = 1; /* just not zero! */
@@@ -1222,13 -1219,13 +1223,13 @@@ static void truncate_pack(struct sha1fi
        pack_size = checkpoint->offset;
  }
  
 -static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
 +static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
  {
        size_t in_sz = 64 * 1024, out_sz = 64 * 1024;
        unsigned char *in_buf = xmalloc(in_sz);
        unsigned char *out_buf = xmalloc(out_sz);
        struct object_entry *e;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        unsigned long hdrlen;
        off_t offset;
        git_SHA_CTX c;
                }
        }
        git_deflate_end(&s);
 -      git_SHA1_Final(sha1, &c);
 +      git_SHA1_Final(oid.hash, &c);
  
 -      if (sha1out)
 -              hashcpy(sha1out, sha1);
 +      if (oidout)
 +              oidcpy(oidout, &oid);
  
 -      e = insert_object(sha1);
 +      e = insert_object(&oid);
  
        if (mark)
                insert_mark(mark, e);
                duplicate_count_by_type[OBJ_BLOB]++;
                truncate_pack(&checkpoint);
  
 -      } else if (find_sha1_pack(sha1, packed_git)) {
 +      } else if (find_sha1_pack(oid.hash, packed_git)) {
                e->type = OBJ_BLOB;
                e->pack_id = MAX_PACK_ID;
                e->idx.offset = 1; /* just not zero! */
@@@ -1389,7 -1386,7 +1390,7 @@@ static const char *get_mode(const char 
  
  static void load_tree(struct tree_entry *root)
  {
 -      unsigned char *sha1 = root->versions[1].sha1;
 +      struct object_id *oid = &root->versions[1].oid;
        struct object_entry *myoe;
        struct tree_content *t;
        unsigned long size;
        const char *c;
  
        root->tree = t = new_tree_content(8);
 -      if (is_null_sha1(sha1))
 +      if (is_null_oid(oid))
                return;
  
 -      myoe = find_object(sha1);
 +      myoe = find_object(oid);
        if (myoe && myoe->pack_id != MAX_PACK_ID) {
                if (myoe->type != OBJ_TREE)
 -                      die("Not a tree: %s", sha1_to_hex(sha1));
 +                      die("Not a tree: %s", oid_to_hex(oid));
                t->delta_depth = myoe->depth;
                buf = gfi_unpack_entry(myoe, &size);
                if (!buf)
 -                      die("Can't load tree %s", sha1_to_hex(sha1));
 +                      die("Can't load tree %s", oid_to_hex(oid));
        } else {
                enum object_type type;
 -              buf = read_sha1_file(sha1, &type, &size);
 +              buf = read_sha1_file(oid->hash, &type, &size);
                if (!buf || type != OBJ_TREE)
 -                      die("Can't load tree %s", sha1_to_hex(sha1));
 +                      die("Can't load tree %s", oid_to_hex(oid));
        }
  
        c = buf;
                e->tree = NULL;
                c = get_mode(c, &e->versions[1].mode);
                if (!c)
 -                      die("Corrupt mode in %s", sha1_to_hex(sha1));
 +                      die("Corrupt mode in %s", oid_to_hex(oid));
                e->versions[0].mode = e->versions[1].mode;
                e->name = to_atom(c, strlen(c));
                c += e->name->str_len + 1;
 -              hashcpy(e->versions[0].sha1, (unsigned char *)c);
 -              hashcpy(e->versions[1].sha1, (unsigned char *)c);
 -              c += 20;
 +              hashcpy(e->versions[0].oid.hash, (unsigned char *)c);
 +              hashcpy(e->versions[1].oid.hash, (unsigned char *)c);
 +              c += GIT_SHA1_RAWSZ;
        }
        free(buf);
  }
@@@ -1479,7 -1476,7 +1480,7 @@@ static void mktree(struct tree_content 
                strbuf_addf(b, "%o %s%c",
                        (unsigned int)(e->versions[v].mode & ~NO_DELTA),
                        e->name->str_dat, '\0');
 -              strbuf_add(b, e->versions[v].sha1, 20);
 +              strbuf_add(b, e->versions[v].oid.hash, GIT_SHA1_RAWSZ);
        }
  }
  
@@@ -1490,7 -1487,7 +1491,7 @@@ static void store_tree(struct tree_entr
        struct last_object lo = { STRBUF_INIT, 0, 0, /* no_swap */ 1 };
        struct object_entry *le = NULL;
  
 -      if (!is_null_sha1(root->versions[1].sha1))
 +      if (!is_null_oid(&root->versions[1].oid))
                return;
  
        if (!root->tree)
        }
  
        if (!(root->versions[0].mode & NO_DELTA))
 -              le = find_object(root->versions[0].sha1);
 +              le = find_object(&root->versions[0].oid);
        if (S_ISDIR(root->versions[0].mode) && le && le->pack_id == pack_id) {
                mktree(t, 0, &old_tree);
                lo.data = old_tree;
        }
  
        mktree(t, 1, &new_tree);
 -      store_object(OBJ_TREE, &new_tree, &lo, root->versions[1].sha1, 0);
 +      store_object(OBJ_TREE, &new_tree, &lo, &root->versions[1].oid, 0);
  
        t->delta_depth = lo.depth;
        for (i = 0, j = 0, del = 0; i < t->entry_count; i++) {
                struct tree_entry *e = t->entries[i];
                if (e->versions[1].mode) {
                        e->versions[0].mode = e->versions[1].mode;
 -                      hashcpy(e->versions[0].sha1, e->versions[1].sha1);
 +                      oidcpy(&e->versions[0].oid, &e->versions[1].oid);
                        t->entries[j++] = e;
                } else {
                        release_tree_entry(e);
  
  static void tree_content_replace(
        struct tree_entry *root,
 -      const unsigned char *sha1,
 +      const struct object_id *oid,
        const uint16_t mode,
        struct tree_content *newtree)
  {
        if (!S_ISDIR(mode))
                die("Root cannot be a non-directory");
 -      hashclr(root->versions[0].sha1);
 -      hashcpy(root->versions[1].sha1, sha1);
 +      oidclr(&root->versions[0].oid);
 +      oidcpy(&root->versions[1].oid, oid);
        if (root->tree)
                release_tree_content_recursive(root->tree);
        root->tree = newtree;
  static int tree_content_set(
        struct tree_entry *root,
        const char *p,
 -      const unsigned char *sha1,
 +      const struct object_id *oid,
        const uint16_t mode,
        struct tree_content *subtree)
  {
                        if (!*slash1) {
                                if (!S_ISDIR(mode)
                                                && e->versions[1].mode == mode
 -                                              && !hashcmp(e->versions[1].sha1, sha1))
 +                                              && !oidcmp(&e->versions[1].oid, oid))
                                        return 0;
                                e->versions[1].mode = mode;
 -                              hashcpy(e->versions[1].sha1, sha1);
 +                              oidcpy(&e->versions[1].oid, oid);
                                if (e->tree)
                                        release_tree_content_recursive(e->tree);
                                e->tree = subtree;
                                if (S_ISDIR(e->versions[0].mode))
                                        e->versions[0].mode |= NO_DELTA;
  
 -                              hashclr(root->versions[1].sha1);
 +                              oidclr(&root->versions[1].oid);
                                return 1;
                        }
                        if (!S_ISDIR(e->versions[1].mode)) {
                        }
                        if (!e->tree)
                                load_tree(e);
 -                      if (tree_content_set(e, slash1 + 1, sha1, mode, subtree)) {
 -                              hashclr(root->versions[1].sha1);
 +                      if (tree_content_set(e, slash1 + 1, oid, mode, subtree)) {
 +                              oidclr(&root->versions[1].oid);
                                return 1;
                        }
                        return 0;
        e = new_tree_entry();
        e->name = to_atom(p, n);
        e->versions[0].mode = 0;
 -      hashclr(e->versions[0].sha1);
 +      oidclr(&e->versions[0].oid);
        t->entries[t->entry_count++] = e;
        if (*slash1) {
                e->tree = new_tree_content(8);
                e->versions[1].mode = S_IFDIR;
 -              tree_content_set(e, slash1 + 1, sha1, mode, subtree);
 +              tree_content_set(e, slash1 + 1, oid, mode, subtree);
        } else {
                e->tree = subtree;
                e->versions[1].mode = mode;
 -              hashcpy(e->versions[1].sha1, sha1);
 +              oidcpy(&e->versions[1].oid, oid);
        }
 -      hashclr(root->versions[1].sha1);
 +      oidclr(&root->versions[1].oid);
        return 1;
  }
  
@@@ -1674,7 -1671,7 +1675,7 @@@ static int tree_content_remove
                        if (tree_content_remove(e, slash1 + 1, backup_leaf, 0)) {
                                for (n = 0; n < e->tree->entry_count; n++) {
                                        if (e->tree->entries[n]->versions[1].mode) {
 -                                              hashclr(root->versions[1].sha1);
 +                                              oidclr(&root->versions[1].oid);
                                                return 1;
                                        }
                                }
@@@ -1693,8 -1690,8 +1694,8 @@@ del_entry
                release_tree_content_recursive(e->tree);
        e->tree = NULL;
        e->versions[1].mode = 0;
 -      hashclr(e->versions[1].sha1);
 -      hashclr(root->versions[1].sha1);
 +      oidclr(&e->versions[1].oid);
 +      oidclr(&root->versions[1].oid);
        return 1;
  }
  
@@@ -1739,7 -1736,7 +1740,7 @@@ static int tree_content_get
  
  found_entry:
        memcpy(leaf, e, sizeof(*leaf));
 -      if (e->tree && is_null_sha1(e->versions[1].sha1))
 +      if (e->tree && is_null_oid(&e->versions[1].oid))
                leaf->tree = dup_tree_content(e->tree);
        else
                leaf->tree = NULL;
@@@ -1750,35 -1747,34 +1751,35 @@@ static int update_branch(struct branch 
  {
        static const char *msg = "fast-import";
        struct ref_transaction *transaction;
 -      unsigned char old_sha1[20];
 +      struct object_id old_oid;
        struct strbuf err = STRBUF_INIT;
  
 -      if (is_null_sha1(b->sha1)) {
 +      if (is_null_oid(&b->oid)) {
                if (b->delete)
                        delete_ref(NULL, b->name, NULL, 0);
                return 0;
        }
 -      if (read_ref(b->name, old_sha1))
 -              hashclr(old_sha1);
 -      if (!force_update && !is_null_sha1(old_sha1)) {
 +      if (read_ref(b->name, old_oid.hash))
 +              oidclr(&old_oid);
 +      if (!force_update && !is_null_oid(&old_oid)) {
                struct commit *old_cmit, *new_cmit;
  
 -              old_cmit = lookup_commit_reference_gently(old_sha1, 0);
 -              new_cmit = lookup_commit_reference_gently(b->sha1, 0);
 +              old_cmit = lookup_commit_reference_gently(&old_oid, 0);
 +              new_cmit = lookup_commit_reference_gently(&b->oid, 0);
                if (!old_cmit || !new_cmit)
                        return error("Branch %s is missing commits.", b->name);
  
                if (!in_merge_bases(old_cmit, new_cmit)) {
                        warning("Not updating %s"
                                " (new tip %s does not contain %s)",
 -                              b->name, sha1_to_hex(b->sha1), sha1_to_hex(old_sha1));
 +                              b->name, oid_to_hex(&b->oid),
 +                              oid_to_hex(&old_oid));
                        return -1;
                }
        }
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
 -          ref_transaction_update(transaction, b->name, b->sha1, old_sha1,
 +          ref_transaction_update(transaction, b->name, b->oid.hash, old_oid.hash,
                                   0, msg, &err) ||
            ref_transaction_commit(transaction, &err)) {
                ref_transaction_free(transaction);
@@@ -1820,7 -1816,7 +1821,7 @@@ static void dump_tags(void
                strbuf_addf(&ref_name, "refs/tags/%s", t->name);
  
                if (ref_transaction_update(transaction, ref_name.buf,
 -                                         t->sha1, NULL, 0, msg, &err)) {
 +                                         t->oid.hash, NULL, 0, msg, &err)) {
                        failure |= error("%s", err.buf);
                        goto cleanup;
                }
@@@ -1849,7 -1845,7 +1850,7 @@@ static void dump_marks_helper(FILE *f
                for (k = 0; k < 1024; k++) {
                        if (m->data.marked[k])
                                fprintf(f, ":%" PRIuMAX " %s\n", base + k,
 -                                      sha1_to_hex(m->data.marked[k]->idx.sha1));
 +                                      oid_to_hex(&m->data.marked[k]->idx.oid));
                }
        }
  }
@@@ -1898,7 -1894,7 +1899,7 @@@ static void read_marks(void
        while (fgets(line, sizeof(line), f)) {
                uintmax_t mark;
                char *end;
 -              unsigned char sha1[20];
 +              struct object_id oid;
                struct object_entry *e;
  
                end = strchr(line, '\n');
                *end = 0;
                mark = strtoumax(line + 1, &end, 10);
                if (!mark || end == line + 1
 -                      || *end != ' ' || get_sha1_hex(end + 1, sha1))
 +                      || *end != ' ' || get_oid_hex(end + 1, &oid))
                        die("corrupt mark line: %s", line);
 -              e = find_object(sha1);
 +              e = find_object(&oid);
                if (!e) {
 -                      enum object_type type = sha1_object_info(sha1, NULL);
 +                      enum object_type type = sha1_object_info(oid.hash, NULL);
                        if (type < 0)
 -                              die("object not found: %s", sha1_to_hex(sha1));
 -                      e = insert_object(sha1);
 +                              die("object not found: %s", oid_to_hex(&oid));
 +                      e = insert_object(&oid);
                        e->type = type;
                        e->pack_id = MAX_PACK_ID;
                        e->idx.offset = 1; /* just not zero! */
@@@ -2122,21 -2118,21 +2123,21 @@@ static char *parse_ident(const char *bu
  
  static void parse_and_store_blob(
        struct last_object *last,
 -      unsigned char *sha1out,
 +      struct object_id *oidout,
        uintmax_t mark)
  {
        static struct strbuf buf = STRBUF_INIT;
        uintmax_t len;
  
        if (parse_data(&buf, big_file_threshold, &len))
 -              store_object(OBJ_BLOB, &buf, last, sha1out, mark);
 +              store_object(OBJ_BLOB, &buf, last, oidout, mark);
        else {
                if (last) {
                        strbuf_release(&last->data);
                        last->offset = 0;
                        last->depth = 0;
                }
 -              stream_blob(len, sha1out, mark);
 +              stream_blob(len, oidout, mark);
                skip_optional_lf();
        }
  }
@@@ -2212,21 -2208,21 +2213,21 @@@ static void construct_path_with_fanout(
                path[i++] = '/';
                fanout--;
        }
 -      memcpy(path + i, hex_sha1 + j, 40 - j);
 -      path[i + 40 - j] = '\0';
 +      memcpy(path + i, hex_sha1 + j, GIT_SHA1_HEXSZ - j);
 +      path[i + GIT_SHA1_HEXSZ - j] = '\0';
  }
  
  static uintmax_t do_change_note_fanout(
                struct tree_entry *orig_root, struct tree_entry *root,
 -              char *hex_sha1, unsigned int hex_sha1_len,
 +              char *hex_oid, unsigned int hex_oid_len,
                char *fullpath, unsigned int fullpath_len,
                unsigned char fanout)
  {
        struct tree_content *t;
        struct tree_entry *e, leaf;
 -      unsigned int i, tmp_hex_sha1_len, tmp_fullpath_len;
 +      unsigned int i, tmp_hex_oid_len, tmp_fullpath_len;
        uintmax_t num_notes = 0;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        char realpath[60];
  
        if (!root->tree)
  
        for (i = 0; t && i < t->entry_count; i++) {
                e = t->entries[i];
 -              tmp_hex_sha1_len = hex_sha1_len + e->name->str_len;
 +              tmp_hex_oid_len = hex_oid_len + e->name->str_len;
                tmp_fullpath_len = fullpath_len;
  
                /*
                 * of 2 chars.
                 */
                if (!e->versions[1].mode ||
 -                  tmp_hex_sha1_len > 40 ||
 +                  tmp_hex_oid_len > GIT_SHA1_HEXSZ ||
                    e->name->str_len % 2)
                        continue;
  
                /* This _may_ be a note entry, or a subdir containing notes */
 -              memcpy(hex_sha1 + hex_sha1_len, e->name->str_dat,
 +              memcpy(hex_oid + hex_oid_len, e->name->str_dat,
                       e->name->str_len);
                if (tmp_fullpath_len)
                        fullpath[tmp_fullpath_len++] = '/';
                tmp_fullpath_len += e->name->str_len;
                fullpath[tmp_fullpath_len] = '\0';
  
 -              if (tmp_hex_sha1_len == 40 && !get_sha1_hex(hex_sha1, sha1)) {
 +              if (tmp_hex_oid_len == GIT_SHA1_HEXSZ && !get_oid_hex(hex_oid, &oid)) {
                        /* This is a note entry */
                        if (fanout == 0xff) {
                                /* Counting mode, no rename */
                                num_notes++;
                                continue;
                        }
 -                      construct_path_with_fanout(hex_sha1, fanout, realpath);
 +                      construct_path_with_fanout(hex_oid, fanout, realpath);
                        if (!strcmp(fullpath, realpath)) {
                                /* Note entry is in correct location */
                                num_notes++;
                        if (!tree_content_remove(orig_root, fullpath, &leaf, 0))
                                die("Failed to remove path %s", fullpath);
                        tree_content_set(orig_root, realpath,
 -                              leaf.versions[1].sha1,
 +                              &leaf.versions[1].oid,
                                leaf.versions[1].mode,
                                leaf.tree);
                } else if (S_ISDIR(e->versions[1].mode)) {
                        /* This is a subdir that may contain note entries */
                        num_notes += do_change_note_fanout(orig_root, e,
 -                              hex_sha1, tmp_hex_sha1_len,
 +                              hex_oid, tmp_hex_oid_len,
                                fullpath, tmp_fullpath_len, fanout);
                }
  
  static uintmax_t change_note_fanout(struct tree_entry *root,
                unsigned char fanout)
  {
 -      char hex_sha1[40], path[60];
 -      return do_change_note_fanout(root, root, hex_sha1, 0, path, 0, fanout);
 +      /*
 +       * The size of path is due to one slash between every two hex digits,
 +       * plus the terminating NUL.  Note that there is no slash at the end, so
 +       * the number of slashes is one less than half the number of hex
 +       * characters.
 +       */
 +      char hex_oid[GIT_MAX_HEXSZ], path[GIT_MAX_HEXSZ + (GIT_MAX_HEXSZ / 2) - 1 + 1];
 +      return do_change_note_fanout(root, root, hex_oid, 0, path, 0, fanout);
  }
  
  /*
@@@ -2366,7 -2356,7 +2367,7 @@@ static void file_change_m(const char *p
        static struct strbuf uq = STRBUF_INIT;
        const char *endp;
        struct object_entry *oe;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        uint16_t mode, inline_data = 0;
  
        p = get_mode(p, &mode);
  
        if (*p == ':') {
                oe = find_mark(parse_mark_ref_space(&p));
 -              hashcpy(sha1, oe->idx.sha1);
 +              oidcpy(&oid, &oe->idx.oid);
        } else if (skip_prefix(p, "inline ", &p)) {
                inline_data = 1;
                oe = NULL; /* not used with inline_data, but makes gcc happy */
        } else {
 -              if (get_sha1_hex(p, sha1))
 +              if (parse_oid_hex(p, &oid, &p))
                        die("Invalid dataref: %s", command_buf.buf);
 -              oe = find_object(sha1);
 -              p += 40;
 +              oe = find_object(&oid);
                if (*p++ != ' ')
                        die("Missing space after SHA1: %s", command_buf.buf);
        }
        }
  
        /* Git does not track empty, non-toplevel directories. */
 -      if (S_ISDIR(mode) && !hashcmp(sha1, EMPTY_TREE_SHA1_BIN) && *p) {
 +      if (S_ISDIR(mode) && is_empty_tree_oid(&oid) && *p) {
                tree_content_remove(&b->branch_tree, p, NULL, 0);
                return;
        }
                        p = uq.buf;
                }
                read_next_command();
 -              parse_and_store_blob(&last_blob, sha1, 0);
 +              parse_and_store_blob(&last_blob, &oid, 0);
        } else {
                enum object_type expected = S_ISDIR(mode) ?
                                                OBJ_TREE: OBJ_BLOB;
                enum object_type type = oe ? oe->type :
 -                                      sha1_object_info(sha1, NULL);
 +                                      sha1_object_info(oid.hash, NULL);
                if (type < 0)
                        die("%s not found: %s",
                                        S_ISDIR(mode) ?  "Tree" : "Blob",
        }
  
        if (!*p) {
 -              tree_content_replace(&b->branch_tree, sha1, mode, NULL);
 +              tree_content_replace(&b->branch_tree, &oid, mode, NULL);
                return;
        }
 -      tree_content_set(&b->branch_tree, p, sha1, mode, NULL);
 +      tree_content_set(&b->branch_tree, p, &oid, mode, NULL);
  }
  
  static void file_change_d(const char *p, struct branch *b)
@@@ -2514,13 -2505,13 +2515,13 @@@ static void file_change_cr(const char *
                die("Path %s not in branch", s);
        if (!*d) {      /* C "path/to/subdir" "" */
                tree_content_replace(&b->branch_tree,
 -                      leaf.versions[1].sha1,
 +                      &leaf.versions[1].oid,
                        leaf.versions[1].mode,
                        leaf.tree);
                return;
        }
        tree_content_set(&b->branch_tree, d,
 -              leaf.versions[1].sha1,
 +              &leaf.versions[1].oid,
                leaf.versions[1].mode,
                leaf.tree);
  }
@@@ -2530,7 -2521,7 +2531,7 @@@ static void note_change_n(const char *p
        static struct strbuf uq = STRBUF_INIT;
        struct object_entry *oe;
        struct branch *s;
 -      unsigned char sha1[20], commit_sha1[20];
 +      struct object_id oid, commit_oid;
        char path[60];
        uint16_t inline_data = 0;
        unsigned char new_fanout;
        /* <dataref> or 'inline' */
        if (*p == ':') {
                oe = find_mark(parse_mark_ref_space(&p));
 -              hashcpy(sha1, oe->idx.sha1);
 +              oidcpy(&oid, &oe->idx.oid);
        } else if (skip_prefix(p, "inline ", &p)) {
                inline_data = 1;
                oe = NULL; /* not used with inline_data, but makes gcc happy */
        } else {
 -              if (get_sha1_hex(p, sha1))
 +              if (parse_oid_hex(p, &oid, &p))
                        die("Invalid dataref: %s", command_buf.buf);
 -              oe = find_object(sha1);
 -              p += 40;
 +              oe = find_object(&oid);
                if (*p++ != ' ')
                        die("Missing space after SHA1: %s", command_buf.buf);
        }
        /* <commit-ish> */
        s = lookup_branch(p);
        if (s) {
 -              if (is_null_sha1(s->sha1))
 +              if (is_null_oid(&s->oid))
                        die("Can't add a note on empty branch.");
 -              hashcpy(commit_sha1, s->sha1);
 +              oidcpy(&commit_oid, &s->oid);
        } else if (*p == ':') {
                uintmax_t commit_mark = parse_mark_ref_eol(p);
                struct object_entry *commit_oe = find_mark(commit_mark);
                if (commit_oe->type != OBJ_COMMIT)
                        die("Mark :%" PRIuMAX " not a commit", commit_mark);
 -              hashcpy(commit_sha1, commit_oe->idx.sha1);
 -      } else if (!get_sha1(p, commit_sha1)) {
 +              oidcpy(&commit_oid, &commit_oe->idx.oid);
 +      } else if (!get_oid(p, &commit_oid)) {
                unsigned long size;
 -              char *buf = read_object_with_reference(commit_sha1,
 -                      commit_type, &size, commit_sha1);
 +              char *buf = read_object_with_reference(commit_oid.hash,
 +                      commit_type, &size, commit_oid.hash);
                if (!buf || size < 46)
                        die("Not a valid commit: %s", p);
                free(buf);
                        p = uq.buf;
                }
                read_next_command();
 -              parse_and_store_blob(&last_blob, sha1, 0);
 +              parse_and_store_blob(&last_blob, &oid, 0);
        } else if (oe) {
                if (oe->type != OBJ_BLOB)
                        die("Not a blob (actually a %s): %s",
                                typename(oe->type), command_buf.buf);
 -      } else if (!is_null_sha1(sha1)) {
 -              enum object_type type = sha1_object_info(sha1, NULL);
 +      } else if (!is_null_oid(&oid)) {
 +              enum object_type type = sha1_object_info(oid.hash, NULL);
                if (type < 0)
                        die("Blob not found: %s", command_buf.buf);
                if (type != OBJ_BLOB)
                            typename(type), command_buf.buf);
        }
  
 -      construct_path_with_fanout(sha1_to_hex(commit_sha1), *old_fanout, path);
 +      construct_path_with_fanout(oid_to_hex(&commit_oid), *old_fanout, path);
        if (tree_content_remove(&b->branch_tree, path, NULL, 0))
                b->num_notes--;
  
 -      if (is_null_sha1(sha1))
 +      if (is_null_oid(&oid))
                return; /* nothing to insert */
  
        b->num_notes++;
        new_fanout = convert_num_notes_to_fanout(b->num_notes);
 -      construct_path_with_fanout(sha1_to_hex(commit_sha1), new_fanout, path);
 -      tree_content_set(&b->branch_tree, path, sha1, S_IFREG | 0644, NULL);
 +      construct_path_with_fanout(oid_to_hex(&commit_oid), new_fanout, path);
 +      tree_content_set(&b->branch_tree, path, &oid, S_IFREG | 0644, NULL);
  }
  
  static void file_change_deleteall(struct branch *b)
  {
        release_tree_content_recursive(b->branch_tree.tree);
 -      hashclr(b->branch_tree.versions[0].sha1);
 -      hashclr(b->branch_tree.versions[1].sha1);
 +      oidclr(&b->branch_tree.versions[0].oid);
 +      oidclr(&b->branch_tree.versions[1].oid);
        load_tree(&b->branch_tree);
        b->num_notes = 0;
  }
  
  static void parse_from_commit(struct branch *b, char *buf, unsigned long size)
  {
 -      if (!buf || size < 46)
 -              die("Not a valid commit: %s", sha1_to_hex(b->sha1));
 +      if (!buf || size < GIT_SHA1_HEXSZ + 6)
 +              die("Not a valid commit: %s", oid_to_hex(&b->oid));
        if (memcmp("tree ", buf, 5)
 -              || get_sha1_hex(buf + 5, b->branch_tree.versions[1].sha1))
 -              die("The commit %s is corrupt", sha1_to_hex(b->sha1));
 -      hashcpy(b->branch_tree.versions[0].sha1,
 -              b->branch_tree.versions[1].sha1);
 +              || get_oid_hex(buf + 5, &b->branch_tree.versions[1].oid))
 +              die("The commit %s is corrupt", oid_to_hex(&b->oid));
 +      oidcpy(&b->branch_tree.versions[0].oid,
 +             &b->branch_tree.versions[1].oid);
  }
  
  static void parse_from_existing(struct branch *b)
  {
 -      if (is_null_sha1(b->sha1)) {
 -              hashclr(b->branch_tree.versions[0].sha1);
 -              hashclr(b->branch_tree.versions[1].sha1);
 +      if (is_null_oid(&b->oid)) {
 +              oidclr(&b->branch_tree.versions[0].oid);
 +              oidclr(&b->branch_tree.versions[1].oid);
        } else {
                unsigned long size;
                char *buf;
  
 -              buf = read_object_with_reference(b->sha1,
 -                      commit_type, &size, b->sha1);
 +              buf = read_object_with_reference(b->oid.hash,
 +                                               commit_type, &size,
 +                                               b->oid.hash);
                parse_from_commit(b, buf, size);
                free(buf);
        }
@@@ -2663,28 -2654,28 +2664,28 @@@ static int parse_from(struct branch *b
  {
        const char *from;
        struct branch *s;
 -      unsigned char sha1[20];
 +      struct object_id oid;
  
        if (!skip_prefix(command_buf.buf, "from ", &from))
                return 0;
  
 -      hashcpy(sha1, b->branch_tree.versions[1].sha1);
 +      oidcpy(&oid, &b->branch_tree.versions[1].oid);
  
        s = lookup_branch(from);
        if (b == s)
                die("Can't create a branch from itself: %s", b->name);
        else if (s) {
 -              unsigned char *t = s->branch_tree.versions[1].sha1;
 -              hashcpy(b->sha1, s->sha1);
 -              hashcpy(b->branch_tree.versions[0].sha1, t);
 -              hashcpy(b->branch_tree.versions[1].sha1, t);
 +              struct object_id *t = &s->branch_tree.versions[1].oid;
 +              oidcpy(&b->oid, &s->oid);
 +              oidcpy(&b->branch_tree.versions[0].oid, t);
 +              oidcpy(&b->branch_tree.versions[1].oid, t);
        } else if (*from == ':') {
                uintmax_t idnum = parse_mark_ref_eol(from);
                struct object_entry *oe = find_mark(idnum);
                if (oe->type != OBJ_COMMIT)
                        die("Mark :%" PRIuMAX " not a commit", idnum);
 -              if (hashcmp(b->sha1, oe->idx.sha1)) {
 -                      hashcpy(b->sha1, oe->idx.sha1);
 +              if (oidcmp(&b->oid, &oe->idx.oid)) {
 +                      oidcpy(&b->oid, &oe->idx.oid);
                        if (oe->pack_id != MAX_PACK_ID) {
                                unsigned long size;
                                char *buf = gfi_unpack_entry(oe, &size);
                        } else
                                parse_from_existing(b);
                }
 -      } else if (!get_sha1(from, b->sha1)) {
 +      } else if (!get_oid(from, &b->oid)) {
                parse_from_existing(b);
 -              if (is_null_sha1(b->sha1))
 +              if (is_null_oid(&b->oid))
                        b->delete = 1;
        }
        else
                die("Invalid ref name or SHA1 expression: %s", from);
  
 -      if (b->branch_tree.tree && hashcmp(sha1, b->branch_tree.versions[1].sha1)) {
 +      if (b->branch_tree.tree && oidcmp(&oid, &b->branch_tree.versions[1].oid)) {
                release_tree_content_recursive(b->branch_tree.tree);
                b->branch_tree.tree = NULL;
        }
@@@ -2721,17 -2712,17 +2722,17 @@@ static struct hash_list *parse_merge(un
                n = xmalloc(sizeof(*n));
                s = lookup_branch(from);
                if (s)
 -                      hashcpy(n->sha1, s->sha1);
 +                      oidcpy(&n->oid, &s->oid);
                else if (*from == ':') {
                        uintmax_t idnum = parse_mark_ref_eol(from);
                        struct object_entry *oe = find_mark(idnum);
                        if (oe->type != OBJ_COMMIT)
                                die("Mark :%" PRIuMAX " not a commit", idnum);
 -                      hashcpy(n->sha1, oe->idx.sha1);
 -              } else if (!get_sha1(from, n->sha1)) {
 +                      oidcpy(&n->oid, &oe->idx.oid);
 +              } else if (!get_oid(from, &n->oid)) {
                        unsigned long size;
 -                      char *buf = read_object_with_reference(n->sha1,
 -                              commit_type, &size, n->sha1);
 +                      char *buf = read_object_with_reference(n->oid.hash,
 +                              commit_type, &size, n->oid.hash);
                        if (!buf || size < 46)
                                die("Not a valid commit: %s", from);
                        free(buf);
@@@ -2818,19 -2809,17 +2819,19 @@@ static void parse_new_commit(const cha
  
        /* build the tree and the commit */
        store_tree(&b->branch_tree);
 -      hashcpy(b->branch_tree.versions[0].sha1,
 -              b->branch_tree.versions[1].sha1);
 +      oidcpy(&b->branch_tree.versions[0].oid,
 +             &b->branch_tree.versions[1].oid);
  
        strbuf_reset(&new_data);
        strbuf_addf(&new_data, "tree %s\n",
 -              sha1_to_hex(b->branch_tree.versions[1].sha1));
 -      if (!is_null_sha1(b->sha1))
 -              strbuf_addf(&new_data, "parent %s\n", sha1_to_hex(b->sha1));
 +              oid_to_hex(&b->branch_tree.versions[1].oid));
 +      if (!is_null_oid(&b->oid))
 +              strbuf_addf(&new_data, "parent %s\n",
 +                          oid_to_hex(&b->oid));
        while (merge_list) {
                struct hash_list *next = merge_list->next;
 -              strbuf_addf(&new_data, "parent %s\n", sha1_to_hex(merge_list->sha1));
 +              strbuf_addf(&new_data, "parent %s\n",
 +                          oid_to_hex(&merge_list->oid));
                free(merge_list);
                merge_list = next;
        }
        free(author);
        free(committer);
  
 -      if (!store_object(OBJ_COMMIT, &new_data, NULL, b->sha1, next_mark))
 +      if (!store_object(OBJ_COMMIT, &new_data, NULL, &b->oid, next_mark))
                b->pack_id = pack_id;
        b->last_commit = object_count_by_type[OBJ_COMMIT];
  }
@@@ -2856,7 -2845,7 +2857,7 @@@ static void parse_new_tag(const char *a
        struct branch *s;
        struct tag *t;
        uintmax_t from_mark = 0;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        enum object_type type;
        const char *v;
  
                die("Expected from command, got %s", command_buf.buf);
        s = lookup_branch(from);
        if (s) {
 -              if (is_null_sha1(s->sha1))
 +              if (is_null_oid(&s->oid))
                        die("Can't tag an empty branch.");
 -              hashcpy(sha1, s->sha1);
 +              oidcpy(&oid, &s->oid);
                type = OBJ_COMMIT;
        } else if (*from == ':') {
                struct object_entry *oe;
                from_mark = parse_mark_ref_eol(from);
                oe = find_mark(from_mark);
                type = oe->type;
 -              hashcpy(sha1, oe->idx.sha1);
 -      } else if (!get_sha1(from, sha1)) {
 -              struct object_entry *oe = find_object(sha1);
 +              oidcpy(&oid, &oe->idx.oid);
 +      } else if (!get_oid(from, &oid)) {
 +              struct object_entry *oe = find_object(&oid);
                if (!oe) {
 -                      type = sha1_object_info(sha1, NULL);
 +                      type = sha1_object_info(oid.hash, NULL);
                        if (type < 0)
                                die("Not a valid object: %s", from);
                } else
                    "object %s\n"
                    "type %s\n"
                    "tag %s\n",
 -                  sha1_to_hex(sha1), typename(type), t->name);
 +                  oid_to_hex(&oid), typename(type), t->name);
        if (tagger)
                strbuf_addf(&new_data,
                            "tagger %s\n", tagger);
        strbuf_addbuf(&new_data, &msg);
        free(tagger);
  
 -      if (store_object(OBJ_TAG, &new_data, NULL, t->sha1, 0))
 +      if (store_object(OBJ_TAG, &new_data, NULL, &t->oid, 0))
                t->pack_id = MAX_PACK_ID;
        else
                t->pack_id = pack_id;
@@@ -2934,9 -2923,9 +2935,9 @@@ static void parse_reset_branch(const ch
  
        b = lookup_branch(arg);
        if (b) {
 -              hashclr(b->sha1);
 -              hashclr(b->branch_tree.versions[0].sha1);
 -              hashclr(b->branch_tree.versions[1].sha1);
 +              oidclr(&b->oid);
 +              oidclr(&b->branch_tree.versions[0].oid);
 +              oidclr(&b->branch_tree.versions[1].oid);
                if (b->branch_tree.tree) {
                        release_tree_content_recursive(b->branch_tree.tree);
                        b->branch_tree.tree = NULL;
@@@ -2956,7 -2945,7 +2957,7 @@@ static void cat_blob_write(const char *
                die_errno("Write to frontend failed");
  }
  
 -static void cat_blob(struct object_entry *oe, unsigned char sha1[20])
 +static void cat_blob(struct object_entry *oe, struct object_id *oid)
  {
        struct strbuf line = STRBUF_INIT;
        unsigned long size;
        char *buf;
  
        if (!oe || oe->pack_id == MAX_PACK_ID) {
 -              buf = read_sha1_file(sha1, &type, &size);
 +              buf = read_sha1_file(oid->hash, &type, &size);
        } else {
                type = oe->type;
                buf = gfi_unpack_entry(oe, &size);
         */
        if (type <= 0) {
                strbuf_reset(&line);
 -              strbuf_addf(&line, "%s missing\n", sha1_to_hex(sha1));
 +              strbuf_addf(&line, "%s missing\n", oid_to_hex(oid));
                cat_blob_write(line.buf, line.len);
                strbuf_release(&line);
                free(buf);
                return;
        }
        if (!buf)
 -              die("Can't read object %s", sha1_to_hex(sha1));
 +              die("Can't read object %s", oid_to_hex(oid));
        if (type != OBJ_BLOB)
                die("Object %s is a %s but a blob was expected.",
 -                  sha1_to_hex(sha1), typename(type));
 +                  oid_to_hex(oid), typename(type));
        strbuf_reset(&line);
 -      strbuf_addf(&line, "%s %s %lu\n", sha1_to_hex(sha1),
 +      strbuf_addf(&line, "%s %s %lu\n", oid_to_hex(oid),
                                                typename(type), size);
        cat_blob_write(line.buf, line.len);
        strbuf_release(&line);
  static void parse_get_mark(const char *p)
  {
        struct object_entry *oe = oe;
 -      char output[42];
 +      char output[GIT_MAX_HEXSZ + 2];
  
        /* get-mark SP <object> LF */
        if (*p != ':')
        if (!oe)
                die("Unknown mark: %s", command_buf.buf);
  
 -      xsnprintf(output, sizeof(output), "%s\n", sha1_to_hex(oe->idx.sha1));
 -      cat_blob_write(output, 41);
 +      xsnprintf(output, sizeof(output), "%s\n", oid_to_hex(&oe->idx.oid));
 +      cat_blob_write(output, GIT_SHA1_HEXSZ + 1);
  }
  
  static void parse_cat_blob(const char *p)
  {
        struct object_entry *oe = oe;
 -      unsigned char sha1[20];
 +      struct object_id oid;
  
        /* cat-blob SP <object> LF */
        if (*p == ':') {
                oe = find_mark(parse_mark_ref_eol(p));
                if (!oe)
                        die("Unknown mark: %s", command_buf.buf);
 -              hashcpy(sha1, oe->idx.sha1);
 +              oidcpy(&oid, &oe->idx.oid);
        } else {
 -              if (get_sha1_hex(p, sha1))
 +              if (parse_oid_hex(p, &oid, &p))
                        die("Invalid dataref: %s", command_buf.buf);
 -              if (p[40])
 +              if (*p)
                        die("Garbage after SHA1: %s", command_buf.buf);
 -              oe = find_object(sha1);
 +              oe = find_object(&oid);
        }
  
 -      cat_blob(oe, sha1);
 +      cat_blob(oe, &oid);
  }
  
  static struct object_entry *dereference(struct object_entry *oe,
 -                                      unsigned char sha1[20])
 +                                      struct object_id *oid)
  {
        unsigned long size;
        char *buf = NULL;
        if (!oe) {
 -              enum object_type type = sha1_object_info(sha1, NULL);
 +              enum object_type type = sha1_object_info(oid->hash, NULL);
                if (type < 0)
 -                      die("object not found: %s", sha1_to_hex(sha1));
 +                      die("object not found: %s", oid_to_hex(oid));
                /* cache it! */
 -              oe = insert_object(sha1);
 +              oe = insert_object(oid);
                oe->type = type;
                oe->pack_id = MAX_PACK_ID;
                oe->idx.offset = 1;
                buf = gfi_unpack_entry(oe, &size);
        } else {
                enum object_type unused;
 -              buf = read_sha1_file(sha1, &unused, &size);
 +              buf = read_sha1_file(oid->hash, &unused, &size);
        }
        if (!buf)
 -              die("Can't load object %s", sha1_to_hex(sha1));
 +              die("Can't load object %s", oid_to_hex(oid));
  
        /* Peel one layer. */
        switch (oe->type) {
        case OBJ_TAG:
 -              if (size < 40 + strlen("object ") ||
 -                  get_sha1_hex(buf + strlen("object "), sha1))
 +              if (size < GIT_SHA1_HEXSZ + strlen("object ") ||
 +                  get_oid_hex(buf + strlen("object "), oid))
                        die("Invalid SHA1 in tag: %s", command_buf.buf);
                break;
        case OBJ_COMMIT:
 -              if (size < 40 + strlen("tree ") ||
 -                  get_sha1_hex(buf + strlen("tree "), sha1))
 +              if (size < GIT_SHA1_HEXSZ + strlen("tree ") ||
 +                  get_oid_hex(buf + strlen("tree "), oid))
                        die("Invalid SHA1 in commit: %s", command_buf.buf);
        }
  
        free(buf);
 -      return find_object(sha1);
 +      return find_object(oid);
  }
  
  static struct object_entry *parse_treeish_dataref(const char **p)
  {
 -      unsigned char sha1[20];
 +      struct object_id oid;
        struct object_entry *e;
  
        if (**p == ':') {       /* <mark> */
                e = find_mark(parse_mark_ref_space(p));
                if (!e)
                        die("Unknown mark: %s", command_buf.buf);
 -              hashcpy(sha1, e->idx.sha1);
 +              oidcpy(&oid, &e->idx.oid);
        } else {        /* <sha1> */
 -              if (get_sha1_hex(*p, sha1))
 +              if (parse_oid_hex(*p, &oid, p))
                        die("Invalid dataref: %s", command_buf.buf);
 -              e = find_object(sha1);
 -              *p += 40;
 +              e = find_object(&oid);
                if (*(*p)++ != ' ')
                        die("Missing space after tree-ish: %s", command_buf.buf);
        }
  
        while (!e || e->type != OBJ_TREE)
 -              e = dereference(e, sha1);
 +              e = dereference(e, &oid);
        return e;
  }
  
@@@ -3154,8 -3144,8 +3155,8 @@@ static void parse_ls(const char *p, str
        } else {
                struct object_entry *e = parse_treeish_dataref(&p);
                root = new_tree_entry();
 -              hashcpy(root->versions[1].sha1, e->idx.sha1);
 -              if (!is_null_sha1(root->versions[1].sha1))
 +              oidcpy(&root->versions[1].oid, &e->idx.oid);
 +              if (!is_null_oid(&root->versions[1].oid))
                        root->versions[1].mode = S_IFDIR;
                load_tree(root);
        }
        if (S_ISDIR(leaf.versions[1].mode))
                store_tree(&leaf);
  
 -      print_ls(leaf.versions[1].mode, leaf.versions[1].sha1, p);
 +      print_ls(leaf.versions[1].mode, leaf.versions[1].oid.hash, p);
        if (leaf.tree)
                release_tree_content_recursive(leaf.tree);
        if (!b || root != &b->branch_tree)
@@@ -3285,7 -3275,9 +3286,7 @@@ static void option_export_pack_edges(co
  {
        if (pack_edges)
                fclose(pack_edges);
 -      pack_edges = fopen(edges, "a");
 -      if (!pack_edges)
 -              die_errno("Cannot open '%s'", edges);
 +      pack_edges = xfopen(edges, "a");
  }
  
  static int parse_one_option(const char *option)
diff --combined fetch-pack.c
index cd86865beba62ffade9f8aa63427781f301e79e7,963d45db911c37010dae86ea53d72ec75f7ef594..fbbc99c88856a773326e4bb310d30fe3021e2333
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "refs.h"
  #include "pkt-line.h"
@@@ -15,7 -16,6 +16,7 @@@
  #include "version.h"
  #include "prio-queue.h"
  #include "sha1-array.h"
 +#include "oidset.h"
  
  static int transfer_unpack_limit = -1;
  static int fetch_unpack_limit = -1;
@@@ -79,7 -79,7 +80,7 @@@ static void cache_one_alternate(const c
                                void *vcache)
  {
        struct alternate_object_cache *cache = vcache;
 -      struct object *obj = parse_object(oid->hash);
 +      struct object *obj = parse_object(oid);
  
        if (!obj || (obj->flags & ALTERNATE))
                return;
@@@ -119,9 -119,9 +120,9 @@@ static void rev_list_push(struct commi
        }
  }
  
 -static int rev_list_insert_ref(const char *refname, const unsigned char *sha1)
 +static int rev_list_insert_ref(const char *refname, const struct object_id *oid)
  {
 -      struct object *o = deref_tag(parse_object(sha1), refname, 0);
 +      struct object *o = deref_tag(parse_object(oid), refname, 0);
  
        if (o && o->type == OBJ_COMMIT)
                rev_list_push((struct commit *)o, SEEN);
  static int rev_list_insert_ref_oid(const char *refname, const struct object_id *oid,
                                   int flag, void *cb_data)
  {
 -      return rev_list_insert_ref(refname, oid->hash);
 +      return rev_list_insert_ref(refname, oid);
  }
  
  static int clear_marks(const char *refname, const struct object_id *oid,
                       int flag, void *cb_data)
  {
 -      struct object *o = deref_tag(parse_object(oid->hash), refname, 0);
 +      struct object *o = deref_tag(parse_object(oid), refname, 0);
  
        if (o && o->type == OBJ_COMMIT)
                clear_commit_marks((struct commit *)o,
@@@ -184,7 -184,7 +185,7 @@@ static void mark_common(struct commit *
    Get the next rev to send, ignoring the common.
  */
  
 -static const unsigned char *get_rev(void)
 +static const struct object_id *get_rev(void)
  {
        struct commit *commit = NULL;
  
                }
        }
  
 -      return commit->object.oid.hash;
 +      return &commit->object.oid;
  }
  
  enum ack_type {
@@@ -252,7 -252,7 +253,7 @@@ static void consume_shallow_list(struc
        }
  }
  
 -static enum ack_type get_ack(int fd, unsigned char *result_sha1)
 +static enum ack_type get_ack(int fd, struct object_id *result_oid)
  {
        int len;
        char *line = packet_read_line(fd, &len);
        if (!strcmp(line, "NAK"))
                return NAK;
        if (skip_prefix(line, "ACK ", &arg)) {
 -              if (!get_sha1_hex(arg, result_sha1)) {
 +              if (!get_oid_hex(arg, result_oid)) {
                        arg += 40;
                        len -= arg - line;
                        if (len < 1)
@@@ -294,7 -294,7 +295,7 @@@ static void send_request(struct fetch_p
  
  static void insert_one_alternate_object(struct object *obj)
  {
 -      rev_list_insert_ref(NULL, obj->oid.hash);
 +      rev_list_insert_ref(NULL, &obj->oid);
  }
  
  #define INITIAL_FLUSH 16
@@@ -318,12 -318,12 +319,12 @@@ static int next_flush(struct fetch_pack
  }
  
  static int find_common(struct fetch_pack_args *args,
 -                     int fd[2], unsigned char *result_sha1,
 +                     int fd[2], struct object_id *result_oid,
                       struct ref *refs)
  {
        int fetching;
        int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval;
 -      const unsigned char *sha1;
 +      const struct object_id *oid;
        unsigned in_vain = 0;
        int got_continue = 0;
        int got_ready = 0;
  
        fetching = 0;
        for ( ; refs ; refs = refs->next) {
 -              unsigned char *remote = refs->old_oid.hash;
 +              struct object_id *remote = &refs->old_oid;
                const char *remote_hex;
                struct object *o;
  
                 * interested in the case we *know* the object is
                 * reachable and we have already scanned it.
                 */
 -              if (((o = lookup_object(remote)) != NULL) &&
 +              if (((o = lookup_object(remote->hash)) != NULL) &&
                                (o->flags & COMPLETE)) {
                        continue;
                }
  
 -              remote_hex = sha1_to_hex(remote);
 +              remote_hex = oid_to_hex(remote);
                if (!fetching) {
                        struct strbuf c = STRBUF_INIT;
                        if (multi_ack == 2)     strbuf_addstr(&c, " multi_ack_detailed");
        if (args->depth > 0)
                packet_buf_write(&req_buf, "deepen %d", args->depth);
        if (args->deepen_since) {
 -              unsigned long max_age = approxidate(args->deepen_since);
 -              packet_buf_write(&req_buf, "deepen-since %lu", max_age);
 +              timestamp_t max_age = approxidate(args->deepen_since);
 +              packet_buf_write(&req_buf, "deepen-since %"PRItime, max_age);
        }
        if (args->deepen_not) {
                int i;
        if (args->deepen) {
                char *line;
                const char *arg;
 -              unsigned char sha1[20];
 +              struct object_id oid;
  
                send_request(args, fd[1], &req_buf);
                while ((line = packet_read_line(fd[0], NULL))) {
                        if (skip_prefix(line, "shallow ", &arg)) {
 -                              if (get_sha1_hex(arg, sha1))
 +                              if (get_oid_hex(arg, &oid))
                                        die(_("invalid shallow line: %s"), line);
 -                              register_shallow(sha1);
 +                              register_shallow(&oid);
                                continue;
                        }
                        if (skip_prefix(line, "unshallow ", &arg)) {
 -                              if (get_sha1_hex(arg, sha1))
 +                              if (get_oid_hex(arg, &oid))
                                        die(_("invalid unshallow line: %s"), line);
 -                              if (!lookup_object(sha1))
 +                              if (!lookup_object(oid.hash))
                                        die(_("object not found: %s"), line);
                                /* make sure that it is parsed as shallow */
 -                              if (!parse_object(sha1))
 +                              if (!parse_object(&oid))
                                        die(_("error in object: %s"), line);
 -                              if (unregister_shallow(sha1))
 +                              if (unregister_shallow(&oid))
                                        die(_("no shallow found: %s"), line);
                                continue;
                        }
  
        flushes = 0;
        retval = -1;
 -      while ((sha1 = get_rev())) {
 -              packet_buf_write(&req_buf, "have %s\n", sha1_to_hex(sha1));
 -              print_verbose(args, "have %s", sha1_to_hex(sha1));
 +      while ((oid = get_rev())) {
 +              packet_buf_write(&req_buf, "have %s\n", oid_to_hex(oid));
 +              print_verbose(args, "have %s", oid_to_hex(oid));
                in_vain++;
                if (flush_at <= ++count) {
                        int ack;
  
                        consume_shallow_list(args, fd[0]);
                        do {
 -                              ack = get_ack(fd[0], result_sha1);
 +                              ack = get_ack(fd[0], result_oid);
                                if (ack)
                                        print_verbose(args, _("got %s %d %s"), "ack",
 -                                                    ack, sha1_to_hex(result_sha1));
 +                                                    ack, oid_to_hex(result_oid));
                                switch (ack) {
                                case ACK:
                                        flushes = 0;
                                case ACK_ready:
                                case ACK_continue: {
                                        struct commit *commit =
 -                                              lookup_commit(result_sha1);
 +                                              lookup_commit(result_oid);
                                        if (!commit)
 -                                              die(_("invalid commit %s"), sha1_to_hex(result_sha1));
 +                                              die(_("invalid commit %s"), oid_to_hex(result_oid));
                                        if (args->stateless_rpc
                                         && ack == ACK_common
                                         && !(commit->object.flags & COMMON)) {
                                                 * on the next RPC request so the peer knows
                                                 * it is in common with us.
                                                 */
 -                                              const char *hex = sha1_to_hex(result_sha1);
 +                                              const char *hex = oid_to_hex(result_oid);
                                                packet_buf_write(&req_buf, "have %s\n", hex);
                                                state_len = req_buf.len;
                                                /*
@@@ -539,10 -539,10 +540,10 @@@ done
        if (!got_ready || !no_done)
                consume_shallow_list(args, fd[0]);
        while (flushes || multi_ack) {
 -              int ack = get_ack(fd[0], result_sha1);
 +              int ack = get_ack(fd[0], result_oid);
                if (ack) {
                        print_verbose(args, _("got %s (%d) %s"), "ack",
 -                                    ack, sha1_to_hex(result_sha1));
 +                                    ack, oid_to_hex(result_oid));
                        if (ack == ACK)
                                return 0;
                        multi_ack = 1;
  
  static struct commit_list *complete;
  
 -static int mark_complete(const unsigned char *sha1)
 +static int mark_complete(const struct object_id *oid)
  {
 -      struct object *o = parse_object(sha1);
 +      struct object *o = parse_object(oid);
  
        while (o && o->type == OBJ_TAG) {
                struct tag *t = (struct tag *) o;
                if (!t->tagged)
                        break; /* broken repository */
                o->flags |= COMPLETE;
 -              o = parse_object(t->tagged->oid.hash);
 +              o = parse_object(&t->tagged->oid);
        }
        if (o && o->type == OBJ_COMMIT) {
                struct commit *commit = (struct commit *)o;
  static int mark_complete_oid(const char *refname, const struct object_id *oid,
                             int flag, void *cb_data)
  {
 -      return mark_complete(oid->hash);
 +      return mark_complete(oid);
  }
  
  static void mark_recent_complete_commits(struct fetch_pack_args *args,
 -                                       unsigned long cutoff)
 +                                       timestamp_t cutoff)
  {
        while (complete && cutoff <= complete->item->date) {
                print_verbose(args, _("Marking %s as complete"),
        }
  }
  
 +static void add_refs_to_oidset(struct oidset *oids, struct ref *refs)
 +{
 +      for (; refs; refs = refs->next)
 +              oidset_insert(oids, &refs->old_oid);
 +}
 +
 +static int tip_oids_contain(struct oidset *tip_oids,
 +                          struct ref *unmatched, struct ref *newlist,
 +                          const struct object_id *id)
 +{
 +      /*
 +       * Note that this only looks at the ref lists the first time it's
 +       * called. This works out in filter_refs() because even though it may
 +       * add to "newlist" between calls, the additions will always be for
 +       * oids that are already in the set.
 +       */
 +      if (!tip_oids->map.tablesize) {
 +              add_refs_to_oidset(tip_oids, unmatched);
 +              add_refs_to_oidset(tip_oids, newlist);
 +      }
 +      return oidset_contains(tip_oids, id);
 +}
 +
  static void filter_refs(struct fetch_pack_args *args,
                        struct ref **refs,
                        struct ref **sought, int nr_sought)
  {
        struct ref *newlist = NULL;
        struct ref **newtail = &newlist;
 +      struct ref *unmatched = NULL;
        struct ref *ref, *next;
 +      struct oidset tip_oids = OIDSET_INIT;
        int i;
  
        i = 0;
                        ref->next = NULL;
                        newtail = &ref->next;
                } else {
 -                      free(ref);
 +                      ref->next = unmatched;
 +                      unmatched = ref;
                }
        }
  
        /* Append unmatched requests to the list */
        for (i = 0; i < nr_sought; i++) {
 -              unsigned char sha1[20];
 +              struct object_id oid;
 +              const char *p;
  
                ref = sought[i];
                if (ref->match_status != REF_NOT_MATCHED)
                        continue;
 -              if (get_sha1_hex(ref->name, sha1) ||
 -                  ref->name[40] != '\0' ||
 -                  hashcmp(sha1, ref->old_oid.hash))
 +              if (parse_oid_hex(ref->name, &oid, &p) ||
 +                  *p != '\0' ||
 +                  oidcmp(&oid, &ref->old_oid))
                        continue;
  
                if ((allow_unadvertised_object_request &
 -                  (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1))) {
 +                   (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1)) ||
 +                  tip_oids_contain(&tip_oids, unmatched, newlist,
 +                                   &ref->old_oid)) {
                        ref->match_status = REF_MATCHED;
                        *newtail = copy_ref(ref);
                        newtail = &(*newtail)->next;
                        ref->match_status = REF_UNADVERTISED_NOT_ALLOWED;
                }
        }
 +
 +      oidset_clear(&tip_oids);
 +      for (ref = unmatched; ref; ref = next) {
 +              next = ref->next;
 +              free(ref);
 +      }
 +
        *refs = newlist;
  }
  
  static void mark_alternate_complete(struct object *obj)
  {
 -      mark_complete(obj->oid.hash);
 +      mark_complete(&obj->oid);
  }
  
  static int everything_local(struct fetch_pack_args *args,
  {
        struct ref *ref;
        int retval;
 -      unsigned long cutoff = 0;
 +      timestamp_t cutoff = 0;
  
        save_commit_buffer = 0;
  
                if (!has_object_file(&ref->old_oid))
                        continue;
  
 -              o = parse_object(ref->old_oid.hash);
 +              o = parse_object(&ref->old_oid);
                if (!o)
                        continue;
  
        filter_refs(args, refs, sought, nr_sought);
  
        for (retval = 1, ref = *refs; ref ; ref = ref->next) {
 -              const unsigned char *remote = ref->old_oid.hash;
 +              const struct object_id *remote = &ref->old_oid;
                struct object *o;
  
 -              o = lookup_object(remote);
 +              o = lookup_object(remote->hash);
                if (!o || !(o->flags & COMPLETE)) {
                        retval = 0;
 -                      print_verbose(args, "want %s (%s)", sha1_to_hex(remote),
 +                      print_verbose(args, "want %s (%s)", oid_to_hex(remote),
                                      ref->name);
                        continue;
                }
 -              print_verbose(args, _("already have %s (%s)"), sha1_to_hex(remote),
 +              print_verbose(args, _("already have %s (%s)"), oid_to_hex(remote),
                              ref->name);
        }
        return retval;
@@@ -910,7 -874,7 +911,7 @@@ static struct ref *do_fetch_pack(struc
                                 char **pack_lockfile)
  {
        struct ref *ref = copy_ref_list(orig_ref);
 -      unsigned char sha1[20];
 +      struct object_id oid;
        const char *agent_feature;
        int agent_len;
  
                packet_flush(fd[1]);
                goto all_done;
        }
 -      if (find_common(args, fd, sha1, ref) < 0)
 +      if (find_common(args, fd, &oid, ref) < 0)
                if (!args->keep_pack)
                        /* When cloning, it is not unusual to have
                         * no common commit.
diff --combined git.c
index 6150d6d281e5f804816bbbbd7d17d1df93aefc7d,c03de2c0900b47ffefede41223d9b069fe36a49d..5be27b07e5146e89ce6497566ec602a3f58bc313
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -1,4 -1,5 +1,5 @@@
  #include "builtin.h"
+ #include "config.h"
  #include "exec_cmd.h"
  #include "help.h"
  #include "run-command.h"
@@@ -17,8 -18,6 +18,8 @@@ const char git_more_info_string[] 
  
  static int use_pager = -1;
  
 +static void list_builtins(void);
 +
  static void commit_pager_choice(void) {
        switch (use_pager) {
        case 0:
@@@ -190,9 -189,6 +191,9 @@@ static int handle_options(const char **
                        }
                        (*argv)++;
                        (*argc)--;
 +              } else if (!strcmp(cmd, "--list-builtins")) {
 +                      list_builtins();
 +                      exit(0);
                } else {
                        fprintf(stderr, "Unknown option: %s\n", cmd);
                        usage(git_usage_string);
@@@ -487,13 -483,6 +488,13 @@@ int is_builtin(const char *s
        return !!get_builtin(s);
  }
  
 +static void list_builtins(void)
 +{
 +      int i;
 +      for (i = 0; i < ARRAY_SIZE(commands); i++)
 +              printf("%s\n", commands[i].cmd);
 +}
 +
  #ifdef STRIP_EXTENSION
  static void strip_extension(const char **argv)
  {
diff --combined grep.c
index 06c4c249266acf5123c2de21a2a68b489e522ca5,d5211fc5a6c0ae86c48f7e17a6be747dfc421f69..1fca83be86525957158fc20d09c91b3208a1974e
--- 1/grep.c
--- 2/grep.c
+++ b/grep.c
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "grep.h"
  #include "userdiff.h"
  #include "xdiff-interface.h"
@@@ -178,38 -179,26 +179,38 @@@ static void grep_set_pattern_type_optio
  
        case GREP_PATTERN_TYPE_BRE:
                opt->fixed = 0;
 -              opt->pcre = 0;
 -              opt->regflags &= ~REG_EXTENDED;
 +              opt->pcre1 = 0;
 +              opt->pcre2 = 0;
                break;
  
        case GREP_PATTERN_TYPE_ERE:
                opt->fixed = 0;
 -              opt->pcre = 0;
 +              opt->pcre1 = 0;
 +              opt->pcre2 = 0;
                opt->regflags |= REG_EXTENDED;
                break;
  
        case GREP_PATTERN_TYPE_FIXED:
                opt->fixed = 1;
 -              opt->pcre = 0;
 -              opt->regflags &= ~REG_EXTENDED;
 +              opt->pcre1 = 0;
 +              opt->pcre2 = 0;
                break;
  
        case GREP_PATTERN_TYPE_PCRE:
                opt->fixed = 0;
 -              opt->pcre = 1;
 -              opt->regflags &= ~REG_EXTENDED;
 +#ifdef USE_LIBPCRE2
 +              opt->pcre1 = 0;
 +              opt->pcre2 = 1;
 +#else
 +              /*
 +               * It's important that pcre1 always be assigned to
 +               * even when there's no USE_LIBPCRE* defined. We still
 +               * call the PCRE stub function, it just dies with
 +               * "cannot use Perl-compatible regexes[...]".
 +               */
 +              opt->pcre1 = 1;
 +              opt->pcre2 = 0;
 +#endif
                break;
        }
  }
@@@ -336,32 -325,8 +337,32 @@@ static NORETURN void compile_regexp_fai
        die("%s'%s': %s", where, p->pattern, error);
  }
  
 -#ifdef USE_LIBPCRE
 -static void compile_pcre_regexp(struct grep_pat *p, const struct grep_opt *opt)
 +static int is_fixed(const char *s, size_t len)
 +{
 +      size_t i;
 +
 +      for (i = 0; i < len; i++) {
 +              if (is_regex_special(s[i]))
 +                      return 0;
 +      }
 +
 +      return 1;
 +}
 +
 +static int has_null(const char *s, size_t len)
 +{
 +      /*
 +       * regcomp cannot accept patterns with NULs so when using it
 +       * we consider any pattern containing a NUL fixed.
 +       */
 +      if (memchr(s, 0, len))
 +              return 1;
 +
 +      return 0;
 +}
 +
 +#ifdef USE_LIBPCRE1
 +static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt)
  {
        const char *error;
        int erroffset;
  
        if (opt->ignore_case) {
                if (has_non_ascii(p->pattern))
 -                      p->pcre_tables = pcre_maketables();
 +                      p->pcre1_tables = pcre_maketables();
                options |= PCRE_CASELESS;
        }
        if (is_utf8_locale() && has_non_ascii(p->pattern))
                options |= PCRE_UTF8;
  
 -      p->pcre_regexp = pcre_compile(p->pattern, options, &error, &erroffset,
 -                                    p->pcre_tables);
 -      if (!p->pcre_regexp)
 +      p->pcre1_regexp = pcre_compile(p->pattern, options, &error, &erroffset,
 +                                    p->pcre1_tables);
 +      if (!p->pcre1_regexp)
                compile_regexp_failed(p, error);
  
 -      p->pcre_extra_info = pcre_study(p->pcre_regexp, 0, &error);
 -      if (!p->pcre_extra_info && error)
 +      p->pcre1_extra_info = pcre_study(p->pcre1_regexp, PCRE_STUDY_JIT_COMPILE, &error);
 +      if (!p->pcre1_extra_info && error)
                die("%s", error);
 +
 +#ifdef GIT_PCRE1_USE_JIT
 +      pcre_config(PCRE_CONFIG_JIT, &p->pcre1_jit_on);
 +      if (p->pcre1_jit_on == 1) {
 +              p->pcre1_jit_stack = pcre_jit_stack_alloc(1, 1024 * 1024);
 +              if (!p->pcre1_jit_stack)
 +                      die("Couldn't allocate PCRE JIT stack");
 +              pcre_assign_jit_stack(p->pcre1_extra_info, NULL, p->pcre1_jit_stack);
 +      } else if (p->pcre1_jit_on != 0) {
 +              die("BUG: The pcre1_jit_on variable should be 0 or 1, not %d",
 +                  p->pcre1_jit_on);
 +      }
 +#endif
  }
  
 -static int pcrematch(struct grep_pat *p, const char *line, const char *eol,
 +static int pcre1match(struct grep_pat *p, const char *line, const char *eol,
                regmatch_t *match, int eflags)
  {
        int ovector[30], ret, flags = 0;
        if (eflags & REG_NOTBOL)
                flags |= PCRE_NOTBOL;
  
 -      ret = pcre_exec(p->pcre_regexp, p->pcre_extra_info, line, eol - line,
 -                      0, flags, ovector, ARRAY_SIZE(ovector));
 +#ifdef GIT_PCRE1_USE_JIT
 +      if (p->pcre1_jit_on) {
 +              ret = pcre_jit_exec(p->pcre1_regexp, p->pcre1_extra_info, line,
 +                                  eol - line, 0, flags, ovector,
 +                                  ARRAY_SIZE(ovector), p->pcre1_jit_stack);
 +      } else
 +#endif
 +      {
 +              ret = pcre_exec(p->pcre1_regexp, p->pcre1_extra_info, line,
 +                              eol - line, 0, flags, ovector,
 +                              ARRAY_SIZE(ovector));
 +      }
 +
        if (ret < 0 && ret != PCRE_ERROR_NOMATCH)
                die("pcre_exec failed with error code %d", ret);
        if (ret > 0) {
        return ret;
  }
  
 -static void free_pcre_regexp(struct grep_pat *p)
 +static void free_pcre1_regexp(struct grep_pat *p)
  {
 -      pcre_free(p->pcre_regexp);
 -      pcre_free(p->pcre_extra_info);
 -      pcre_free((void *)p->pcre_tables);
 +      pcre_free(p->pcre1_regexp);
 +#ifdef GIT_PCRE1_USE_JIT
 +      if (p->pcre1_jit_on) {
 +              pcre_free_study(p->pcre1_extra_info);
 +              pcre_jit_stack_free(p->pcre1_jit_stack);
 +      } else
 +#endif
 +      {
 +              pcre_free(p->pcre1_extra_info);
 +      }
 +      pcre_free((void *)p->pcre1_tables);
  }
 -#else /* !USE_LIBPCRE */
 -static void compile_pcre_regexp(struct grep_pat *p, const struct grep_opt *opt)
 +#else /* !USE_LIBPCRE1 */
 +static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt)
  {
        die("cannot use Perl-compatible regexes when not compiled with USE_LIBPCRE");
  }
  
 -static int pcrematch(struct grep_pat *p, const char *line, const char *eol,
 +static int pcre1match(struct grep_pat *p, const char *line, const char *eol,
                regmatch_t *match, int eflags)
  {
        return 1;
  }
  
 -static void free_pcre_regexp(struct grep_pat *p)
 +static void free_pcre1_regexp(struct grep_pat *p)
  {
  }
 -#endif /* !USE_LIBPCRE */
 +#endif /* !USE_LIBPCRE1 */
  
 -static int is_fixed(const char *s, size_t len)
 +#ifdef USE_LIBPCRE2
 +static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
  {
 -      size_t i;
 +      int error;
 +      PCRE2_UCHAR errbuf[256];
 +      PCRE2_SIZE erroffset;
 +      int options = PCRE2_MULTILINE;
 +      const uint8_t *character_tables = NULL;
 +      int jitret;
  
 -      /* regcomp cannot accept patterns with NULs so we
 -       * consider any pattern containing a NUL fixed.
 -       */
 -      if (memchr(s, 0, len))
 -              return 1;
 +      assert(opt->pcre2);
  
 -      for (i = 0; i < len; i++) {
 -              if (is_regex_special(s[i]))
 -                      return 0;
 +      p->pcre2_compile_context = NULL;
 +
 +      if (opt->ignore_case) {
 +              if (has_non_ascii(p->pattern)) {
 +                      character_tables = pcre2_maketables(NULL);
 +                      p->pcre2_compile_context = pcre2_compile_context_create(NULL);
 +                      pcre2_set_character_tables(p->pcre2_compile_context, character_tables);
 +              }
 +              options |= PCRE2_CASELESS;
 +      }
 +      if (is_utf8_locale() && has_non_ascii(p->pattern))
 +              options |= PCRE2_UTF;
 +
 +      p->pcre2_pattern = pcre2_compile((PCRE2_SPTR)p->pattern,
 +                                       p->patternlen, options, &error, &erroffset,
 +                                       p->pcre2_compile_context);
 +
 +      if (p->pcre2_pattern) {
 +              p->pcre2_match_data = pcre2_match_data_create_from_pattern(p->pcre2_pattern, NULL);
 +              if (!p->pcre2_match_data)
 +                      die("Couldn't allocate PCRE2 match data");
 +      } else {
 +              pcre2_get_error_message(error, errbuf, sizeof(errbuf));
 +              compile_regexp_failed(p, (const char *)&errbuf);
 +      }
 +
 +      pcre2_config(PCRE2_CONFIG_JIT, &p->pcre2_jit_on);
 +      if (p->pcre2_jit_on == 1) {
 +              jitret = pcre2_jit_compile(p->pcre2_pattern, PCRE2_JIT_COMPLETE);
 +              if (jitret)
 +                      die("Couldn't JIT the PCRE2 pattern '%s', got '%d'\n", p->pattern, jitret);
 +              p->pcre2_jit_stack = pcre2_jit_stack_create(1, 1024 * 1024, NULL);
 +              if (!p->pcre2_jit_stack)
 +                      die("Couldn't allocate PCRE2 JIT stack");
 +              p->pcre2_match_context = pcre2_match_context_create(NULL);
 +              if (!p->pcre2_match_context)
 +                      die("Couldn't allocate PCRE2 match context");
 +              pcre2_jit_stack_assign(p->pcre2_match_context, NULL, p->pcre2_jit_stack);
 +      } else if (p->pcre2_jit_on != 0) {
 +              die("BUG: The pcre2_jit_on variable should be 0 or 1, not %d",
 +                  p->pcre1_jit_on);
        }
 +}
 +
 +static int pcre2match(struct grep_pat *p, const char *line, const char *eol,
 +              regmatch_t *match, int eflags)
 +{
 +      int ret, flags = 0;
 +      PCRE2_SIZE *ovector;
 +      PCRE2_UCHAR errbuf[256];
 +
 +      if (eflags & REG_NOTBOL)
 +              flags |= PCRE2_NOTBOL;
  
 +      if (p->pcre2_jit_on)
 +              ret = pcre2_jit_match(p->pcre2_pattern, (unsigned char *)line,
 +                                    eol - line, 0, flags, p->pcre2_match_data,
 +                                    NULL);
 +      else
 +              ret = pcre2_match(p->pcre2_pattern, (unsigned char *)line,
 +                                eol - line, 0, flags, p->pcre2_match_data,
 +                                NULL);
 +
 +      if (ret < 0 && ret != PCRE2_ERROR_NOMATCH) {
 +              pcre2_get_error_message(ret, errbuf, sizeof(errbuf));
 +              die("%s failed with error code %d: %s",
 +                  (p->pcre2_jit_on ? "pcre2_jit_match" : "pcre2_match"), ret,
 +                  errbuf);
 +      }
 +      if (ret > 0) {
 +              ovector = pcre2_get_ovector_pointer(p->pcre2_match_data);
 +              ret = 0;
 +              match->rm_so = (int)ovector[0];
 +              match->rm_eo = (int)ovector[1];
 +      }
 +
 +      return ret;
 +}
 +
 +static void free_pcre2_pattern(struct grep_pat *p)
 +{
 +      pcre2_compile_context_free(p->pcre2_compile_context);
 +      pcre2_code_free(p->pcre2_pattern);
 +      pcre2_match_data_free(p->pcre2_match_data);
 +      pcre2_jit_stack_free(p->pcre2_jit_stack);
 +      pcre2_match_context_free(p->pcre2_match_context);
 +}
 +#else /* !USE_LIBPCRE2 */
 +static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
 +{
 +      /*
 +       * Unreachable until USE_LIBPCRE2 becomes synonymous with
 +       * USE_LIBPCRE. See the sibling comment in
 +       * grep_set_pattern_type_option().
 +       */
 +      die("cannot use Perl-compatible regexes when not compiled with USE_LIBPCRE");
 +}
 +
 +static int pcre2match(struct grep_pat *p, const char *line, const char *eol,
 +              regmatch_t *match, int eflags)
 +{
        return 1;
  }
  
 +static void free_pcre2_pattern(struct grep_pat *p)
 +{
 +}
 +#endif /* !USE_LIBPCRE2 */
 +
  static void compile_fixed_regexp(struct grep_pat *p, struct grep_opt *opt)
  {
        struct strbuf sb = STRBUF_INIT;
        int err;
 -      int regflags;
 +      int regflags = opt->regflags;
  
        basic_regex_quote_buf(&sb, p->pattern);
 -      regflags = opt->regflags & ~REG_EXTENDED;
        if (opt->ignore_case)
                regflags |= REG_ICASE;
        err = regcomp(&p->regexp, sb.buf, regflags);
@@@ -625,9 -456,7 +626,9 @@@ static void compile_regexp(struct grep_
         * simple string match using kws.  p->fixed tells us if we
         * want to use kws.
         */
 -      if (opt->fixed || is_fixed(p->pattern, p->patternlen))
 +      if (opt->fixed ||
 +          has_null(p->pattern, p->patternlen) ||
 +          is_fixed(p->pattern, p->patternlen))
                p->fixed = !icase || ascii_only;
        else
                p->fixed = 0;
                return;
        }
  
 -      if (opt->pcre) {
 -              compile_pcre_regexp(p, opt);
 +      if (opt->pcre2) {
 +              compile_pcre2_pattern(p, opt);
 +              return;
 +      }
 +
 +      if (opt->pcre1) {
 +              compile_pcre1_regexp(p, opt);
                return;
        }
  
@@@ -1009,10 -833,8 +1010,10 @@@ void free_grep_patterns(struct grep_op
                case GREP_PATTERN_BODY:
                        if (p->kws)
                                kwsfree(p->kws);
 -                      else if (p->pcre_regexp)
 -                              free_pcre_regexp(p);
 +                      else if (p->pcre1_regexp)
 +                              free_pcre1_regexp(p);
 +                      else if (p->pcre2_pattern)
 +                              free_pcre2_pattern(p);
                        else
                                regfree(&p->regexp);
                        free(p->pattern);
@@@ -1091,10 -913,8 +1092,10 @@@ static int patmatch(struct grep_pat *p
  
        if (p->fixed)
                hit = !fixmatch(p, line, eol, match);
 -      else if (p->pcre_regexp)
 -              hit = !pcrematch(p, line, eol, match, eflags);
 +      else if (p->pcre1_regexp)
 +              hit = !pcre1match(p, line, eol, match, eflags);
 +      else if (p->pcre2_pattern)
 +              hit = !pcre2match(p, line, eol, match, eflags);
        else
                hit = !regexec_buf(&p->regexp, line, eol - line, 1, match,
                                   eflags);
@@@ -1584,11 -1404,11 +1585,11 @@@ static int fill_textconv_grep(struct us
         */
        df = alloc_filespec(gs->path);
        switch (gs->type) {
 -      case GREP_SOURCE_SHA1:
 +      case GREP_SOURCE_OID:
                fill_filespec(df, gs->identifier, 1, 0100644);
                break;
        case GREP_SOURCE_FILE:
 -              fill_filespec(df, null_sha1, 0, 0100644);
 +              fill_filespec(df, &null_oid, 0, 0100644);
                break;
        default:
                die("BUG: attempt to textconv something without a path?");
@@@ -1928,8 -1748,9 +1929,8 @@@ void grep_source_init(struct grep_sourc
                 * If the identifier is non-NULL (in the submodule case) it
                 * will be a SHA1 that needs to be copied.
                 */
 -      case GREP_SOURCE_SHA1:
 -              gs->identifier = xmalloc(20);
 -              hashcpy(gs->identifier, identifier);
 +      case GREP_SOURCE_OID:
 +              gs->identifier = oiddup(identifier);
                break;
        case GREP_SOURCE_BUF:
                gs->identifier = NULL;
@@@ -1952,7 -1773,7 +1953,7 @@@ void grep_source_clear_data(struct grep
  {
        switch (gs->type) {
        case GREP_SOURCE_FILE:
 -      case GREP_SOURCE_SHA1:
 +      case GREP_SOURCE_OID:
        case GREP_SOURCE_SUBMODULE:
                free(gs->buf);
                gs->buf = NULL;
        }
  }
  
 -static int grep_source_load_sha1(struct grep_source *gs)
 +static int grep_source_load_oid(struct grep_source *gs)
  {
        enum object_type type;
  
        if (!gs->buf)
                return error(_("'%s': unable to read %s"),
                             gs->name,
 -                           sha1_to_hex(gs->identifier));
 +                           oid_to_hex(gs->identifier));
        return 0;
  }
  
@@@ -2021,8 -1842,8 +2022,8 @@@ static int grep_source_load(struct grep
        switch (gs->type) {
        case GREP_SOURCE_FILE:
                return grep_source_load_file(gs);
 -      case GREP_SOURCE_SHA1:
 -              return grep_source_load_sha1(gs);
 +      case GREP_SOURCE_OID:
 +              return grep_source_load_oid(gs);
        case GREP_SOURCE_BUF:
                return gs->buf ? 0 : -1;
        case GREP_SOURCE_SUBMODULE:
diff --combined help.c
index 5cdfac7dc20d23089a1230c885dc1701a2caf1ac,b8f3a98e4cbe09dd903dfb86653938c1d7604e3d..8ba0777410bd6377a1325622f7d73a53a0aa5a60
--- 1/help.c
--- 2/help.c
+++ b/help.c
@@@ -1,7 -1,7 +1,8 @@@
  #include "cache.h"
+ #include "config.h"
  #include "builtin.h"
  #include "exec_cmd.h"
 +#include "run-command.h"
  #include "levenshtein.h"
  #include "help.h"
  #include "common-cmds.h"
@@@ -9,7 -9,6 +10,7 @@@
  #include "column.h"
  #include "version.h"
  #include "refs.h"
 +#include "parse-options.h"
  
  void add_cmdname(struct cmdnames *cmds, const char *name, int len)
  {
@@@ -98,6 -97,48 +99,6 @@@ static void pretty_print_cmdnames(struc
        string_list_clear(&list, 0);
  }
  
 -static int is_executable(const char *name)
 -{
 -      struct stat st;
 -
 -      if (stat(name, &st) || /* stat, not lstat */
 -          !S_ISREG(st.st_mode))
 -              return 0;
 -
 -#if defined(GIT_WINDOWS_NATIVE)
 -      /*
 -       * On Windows there is no executable bit. The file extension
 -       * indicates whether it can be run as an executable, and Git
 -       * has special-handling to detect scripts and launch them
 -       * through the indicated script interpreter. We test for the
 -       * file extension first because virus scanners may make
 -       * it quite expensive to open many files.
 -       */
 -      if (ends_with(name, ".exe"))
 -              return S_IXUSR;
 -
 -{
 -      /*
 -       * Now that we know it does not have an executable extension,
 -       * peek into the file instead.
 -       */
 -      char buf[3] = { 0 };
 -      int n;
 -      int fd = open(name, O_RDONLY);
 -      st.st_mode &= ~S_IXUSR;
 -      if (fd >= 0) {
 -              n = read(fd, buf, 2);
 -              if (n == 2)
 -                      /* look for a she-bang */
 -                      if (!strcmp(buf, "#!"))
 -                              st.st_mode |= S_IXUSR;
 -              close(fd);
 -      }
 -}
 -#endif
 -      return st.st_mode & S_IXUSR;
 -}
 -
  static void list_commands_in_dir(struct cmdnames *cmds,
                                         const char *path,
                                         const char *prefix)
@@@ -371,8 -412,8 +372,8 @@@ const char *help_unknown_cmd(const cha
  
        if (SIMILAR_ENOUGH(best_similarity)) {
                fprintf_ln(stderr,
 -                         Q_("\nDid you mean this?",
 -                            "\nDid you mean one of these?",
 +                         Q_("\nThe most similar command is",
 +                            "\nThe most similar commands are",
                           n));
  
                for (i = 0; i < n; i++)
  
  int cmd_version(int argc, const char **argv, const char *prefix)
  {
 +      int build_options = 0;
 +      const char * const usage[] = {
 +              N_("git version [<options>]"),
 +              NULL
 +      };
 +      struct option options[] = {
 +              OPT_BOOL(0, "build-options", &build_options,
 +                       "also print build options"),
 +              OPT_END()
 +      };
 +
 +      argc = parse_options(argc, argv, prefix, options, usage, 0);
 +
        /*
         * The format of this string should be kept stable for compatibility
         * with external projects that rely on the output of "git version".
 +       *
 +       * Always show the version, even if other options are given.
         */
        printf("git version %s\n", git_version_string);
 -      while (*++argv) {
 -              if (!strcmp(*argv, "--build-options")) {
 -                      printf("sizeof-long: %d\n", (int)sizeof(long));
 -                      /* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
 -              }
 +
 +      if (build_options) {
 +              printf("sizeof-long: %d\n", (int)sizeof(long));
 +              /* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
        }
        return 0;
  }
diff --combined http-backend.c
index ba5ff1aa2994633c055611ce566ea8cf3c09e8cc,109df44e3166259b8b5e67be9b377b15fbbef5b7..519025d2c3d944afb6fdd6ca1f3b091827a67272
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "refs.h"
  #include "pkt-line.h"
  #include "object.h"
@@@ -90,7 -91,7 +91,7 @@@ static void hdr_int(struct strbuf *hdr
        strbuf_addf(hdr, "%s: %" PRIuMAX "\r\n", name, value);
  }
  
 -static void hdr_date(struct strbuf *hdr, const char *name, unsigned long when)
 +static void hdr_date(struct strbuf *hdr, const char *name, timestamp_t when)
  {
        const char *value = show_date(when, 0, DATE_MODE(RFC2822));
        hdr_str(hdr, name, value);
@@@ -105,7 -106,7 +106,7 @@@ static void hdr_nocache(struct strbuf *
  
  static void hdr_cache_forever(struct strbuf *hdr)
  {
 -      unsigned long now = time(NULL);
 +      timestamp_t now = time(NULL);
        hdr_date(hdr, "Date", now);
        hdr_date(hdr, "Expires", now + 31536000);
        hdr_str(hdr, "Cache-Control", "public, max-age=31536000");
@@@ -431,7 -432,7 +432,7 @@@ static int show_text_ref(const char *na
  {
        const char *name_nons = strip_namespace(name);
        struct strbuf *buf = cb_data;
 -      struct object *o = parse_object(oid->hash);
 +      struct object *o = parse_object(oid);
        if (!o)
                return 0;
  
diff --combined ident.c
index 91c7609055bf3e0a4c0b7ae3cb46219ccaad53ef,d41fc91192097bbaa00de4367b1e2c7bda31440a..327abe557f5a66546665664511d3e71b7f0929e7
+++ b/ident.c
@@@ -6,6 -6,7 +6,7 @@@
   * Copyright (C) 2005 Linus Torvalds
   */
  #include "cache.h"
+ #include "config.h"
  
  static struct strbuf git_default_name = STRBUF_INIT;
  static struct strbuf git_default_email = STRBUF_INIT;
@@@ -72,10 -73,12 +73,10 @@@ static int add_mailname_host(struct str
        FILE *mailname;
        struct strbuf mailnamebuf = STRBUF_INIT;
  
 -      mailname = fopen("/etc/mailname", "r");
 -      if (!mailname) {
 -              if (errno != ENOENT)
 -                      warning_errno("cannot open /etc/mailname");
 +      mailname = fopen_or_warn("/etc/mailname", "r");
 +      if (!mailname)
                return -1;
 -      }
 +
        if (strbuf_getline(&mailnamebuf, mailname) == EOF) {
                if (ferror(mailname))
                        warning_errno("cannot read /etc/mailname");
diff --combined ll-merge.c
index d7eafb61a6831020149d0da607bb47b995192296,24ff94e1dd333beab0f2c00748d2fcc63472dfe6..b9576efe97b98d8b7971045b7be3698b9592c5e6
@@@ -5,6 -5,7 +5,7 @@@
   */
  
  #include "cache.h"
+ #include "config.h"
  #include "attr.h"
  #include "xdiff-interface.h"
  #include "run-command.h"
@@@ -339,7 -340,7 +340,7 @@@ static const struct ll_merge_driver *fi
  static void normalize_file(mmfile_t *mm, const char *path)
  {
        struct strbuf strbuf = STRBUF_INIT;
 -      if (renormalize_buffer(path, mm->ptr, mm->size, &strbuf)) {
 +      if (renormalize_buffer(&the_index, path, mm->ptr, mm->size, &strbuf)) {
                free(mm->ptr);
                mm->size = strbuf.len;
                mm->ptr = strbuf_detach(&strbuf, NULL);
diff --combined log-tree.c
index 2903874ecf156c374ae0a120cdc20a5f5e41df53,282510b10507e76ccc02bc68027162c0b721ae99..410ab4f02de5b532485c46b5cceffc3c677df214
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "diff.h"
  #include "commit.h"
  #include "tag.h"
@@@ -105,13 -106,13 +106,13 @@@ static int add_ref_decoration(const cha
                        warning("invalid replace ref %s", refname);
                        return 0;
                }
 -              obj = parse_object(original_oid.hash);
 +              obj = parse_object(&original_oid);
                if (obj)
                        add_name_decoration(DECORATION_GRAFTED, "replaced", obj);
                return 0;
        }
  
 -      obj = parse_object(oid->hash);
 +      obj = parse_object(oid);
        if (!obj)
                return 0;
  
                if (!obj)
                        break;
                if (!obj->parsed)
 -                      parse_object(obj->oid.hash);
 +                      parse_object(&obj->oid);
                add_name_decoration(DECORATION_REF_TAG, refname, obj);
        }
        return 0;
  
  static int add_graft_decoration(const struct commit_graft *graft, void *cb_data)
  {
 -      struct commit *commit = lookup_commit(graft->oid.hash);
 +      struct commit *commit = lookup_commit(&graft->oid);
        if (!commit)
                return 0;
        add_name_decoration(DECORATION_GRAFTED, "grafted", &commit->object);
@@@ -184,7 -185,7 +185,7 @@@ static const struct name_decoration *cu
  {
        const struct name_decoration *list, *head = NULL;
        const char *branch_name = NULL;
 -      unsigned char unused[20];
 +      struct object_id unused;
        int rru_flags;
  
        /* First find HEAD */
                return NULL;
  
        /* Now resolve and find the matching current branch */
 -      branch_name = resolve_ref_unsafe("HEAD", 0, unused, &rru_flags);
 +      branch_name = resolve_ref_unsafe("HEAD", 0, unused.hash, &rru_flags);
        if (!(rru_flags & REF_ISSYMREF))
                return NULL;
  
@@@ -456,13 -457,13 +457,13 @@@ static void show_signature(struct rev_i
        strbuf_release(&signature);
  }
  
 -static int which_parent(const unsigned char *sha1, const struct commit *commit)
 +static int which_parent(const struct object_id *oid, const struct commit *commit)
  {
        int nth;
        const struct commit_list *parent;
  
        for (nth = 0, parent = commit->parents; parent; parent = parent->next) {
 -              if (!hashcmp(parent->item->object.oid.hash, sha1))
 +              if (!oidcmp(&parent->item->object.oid, oid))
                        return nth;
                nth++;
        }
@@@ -481,14 -482,14 +482,14 @@@ static void show_one_mergetag(struct co
                              void *data)
  {
        struct rev_info *opt = (struct rev_info *)data;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        struct tag *tag;
        struct strbuf verify_message;
        int status, nth;
        size_t payload_size, gpg_message_offset;
  
 -      hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), sha1);
 -      tag = lookup_tag(sha1);
 +      hash_sha1_file(extra->value, extra->len, typename(OBJ_TAG), oid.hash);
 +      tag = lookup_tag(&oid);
        if (!tag)
                return; /* error message already given */
  
                          &commit->parents->next->item->object.oid))
                strbuf_addf(&verify_message,
                            "merged tag '%s'\n", tag->tag);
 -      else if ((nth = which_parent(tag->tagged->oid.hash, commit)) < 0)
 +      else if ((nth = which_parent(&tag->tagged->oid, commit)) < 0)
                strbuf_addf(&verify_message, "tag %s names a non-parent %s\n",
                                    tag->tag, tag->tagged->oid.hash);
        else
@@@ -536,7 -537,7 +537,7 @@@ void show_log(struct rev_info *opt
        struct strbuf msgbuf = STRBUF_INIT;
        struct log_info *log = opt->loginfo;
        struct commit *commit = log->commit, *parent = log->parent;
 -      int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40;
 +      int abbrev_commit = opt->abbrev_commit ? opt->abbrev : GIT_SHA1_HEXSZ;
        const char *extra_headers = opt->extra_headers;
        struct pretty_print_context ctx = {0};
  
                struct strbuf notebuf = STRBUF_INIT;
  
                raw = (opt->commit_format == CMIT_FMT_USERFORMAT);
 -              format_display_notes(commit->object.oid.hash, &notebuf,
 +              format_display_notes(&commit->object.oid, &notebuf,
                                     get_log_output_encoding(), raw);
                ctx.notes_message = notebuf.len
                        ? strbuf_detach(&notebuf, NULL)
@@@ -803,7 -804,7 +804,7 @@@ static int log_tree_diff(struct rev_inf
        parents = get_saved_parents(opt, commit);
        if (!parents) {
                if (opt->show_root_diff) {
 -                      diff_root_tree_sha1(oid->hash, "", &opt->diffopt);
 +                      diff_root_tree_oid(oid, "", &opt->diffopt);
                        log_tree_diff_flush(opt);
                }
                return !opt->loginfo;
                         * we merged _in_.
                         */
                        parse_commit_or_die(parents->item);
 -                      diff_tree_sha1(parents->item->tree->object.oid.hash,
 -                                     oid->hash, "", &opt->diffopt);
 +                      diff_tree_oid(&parents->item->tree->object.oid,
 +                                    oid, "", &opt->diffopt);
                        log_tree_diff_flush(opt);
                        return !opt->loginfo;
                }
                struct commit *parent = parents->item;
  
                parse_commit_or_die(parent);
 -              diff_tree_sha1(parent->tree->object.oid.hash,
 -                             oid->hash, "", &opt->diffopt);
 +              diff_tree_oid(&parent->tree->object.oid,
 +                            oid, "", &opt->diffopt);
                log_tree_diff_flush(opt);
  
                showed_log |= !opt->loginfo;
diff --combined mailinfo.c
index f92cb9f729ca05ae1e80c9c27bc102dbb64a8dc0,aaed3870a4618c9fe57875cec6814a3e9e62b811..f59162453eecdfb841383f71911303b594aa81e4
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "utf8.h"
  #include "strbuf.h"
  #include "mailinfo.h"
@@@ -882,10 -883,7 +883,10 @@@ static int read_one_header_line(struct 
        for (;;) {
                int peek;
  
 -              peek = fgetc(in); ungetc(peek, in);
 +              peek = fgetc(in);
 +              if (peek == EOF)
 +                      break;
 +              ungetc(peek, in);
                if (peek != ' ' && peek != '\t')
                        break;
                if (strbuf_getline_lf(&continuation, in))
@@@ -1102,10 -1100,6 +1103,10 @@@ int mailinfo(struct mailinfo *mi, cons
  
        do {
                peek = fgetc(mi->input);
 +              if (peek == EOF) {
 +                      fclose(cmitmsg);
 +                      return error("empty patch: '%s'", patch);
 +              }
        } while (isspace(peek));
        ungetc(peek, mi->input);
  
diff --combined merge-recursive.c
index ce48ed7e86137710283f775d4152c9870cfabeea,a85144c23acd4293d0c87a2e468d2c0136fa4d57..59e5ee41a8cdde0613e5dfa890cb52b21666868f
@@@ -4,6 -4,7 +4,7 @@@
   * The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006
   */
  #include "cache.h"
+ #include "config.h"
  #include "advice.h"
  #include "lockfile.h"
  #include "cache-tree.h"
@@@ -67,7 -68,7 +68,7 @@@ static struct tree *shift_tree_object(s
        }
        if (!oidcmp(&two->object.oid, &shifted))
                return two;
 -      return lookup_tree(shifted.hash);
 +      return lookup_tree(&shifted);
  }
  
  static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
@@@ -304,7 -305,7 +305,7 @@@ struct tree *write_tree_from_memory(str
                return NULL;
        }
  
 -      result = lookup_tree(active_cache_tree->sha1);
 +      result = lookup_tree(&active_cache_tree->oid);
  
        return result;
  }
@@@ -528,7 -529,7 +529,7 @@@ static struct string_list *get_renames(
        opts.show_rename_progress = o->show_rename_progress;
        opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        diff_setup_done(&opts);
 -      diff_tree_sha1(o_tree->object.oid.hash, tree->object.oid.hash, "", &opts);
 +      diff_tree_oid(&o_tree->object.oid, &tree->object.oid, "", &opts);
        diffcore_std(&opts);
        if (opts.needed_rename_limit > o->needed_rename_limit)
                o->needed_rename_limit = opts.needed_rename_limit;
@@@ -994,11 -995,11 +995,11 @@@ static int merge_file_1(struct merge_op
                                return ret;
                        result->clean = (merge_status == 0);
                } else if (S_ISGITLINK(a->mode)) {
 -                      result->clean = merge_submodule(result->oid.hash,
 +                      result->clean = merge_submodule(&result->oid,
                                                       one->path,
 -                                                     one->oid.hash,
 -                                                     a->oid.hash,
 -                                                     b->oid.hash,
 +                                                     &one->oid,
 +                                                     &a->oid,
 +                                                     &b->oid,
                                                       !o->call_depth);
                } else if (S_ISLNK(a->mode)) {
                        oidcpy(&result->oid, &a->oid);
@@@ -1639,8 -1640,8 +1640,8 @@@ static int blob_unchanged(struct merge_
         * performed.  Comparison can be skipped if both files are
         * unchanged since their sha1s have already been compared.
         */
 -      if (renormalize_buffer(path, o.buf, o.len, &o) |
 -          renormalize_buffer(path, a.buf, a.len, &a))
 +      if (renormalize_buffer(&the_index, path, o.buf, o.len, &o) |
 +          renormalize_buffer(&the_index, path, a.buf, a.len, &a))
                ret = (o.len == a.len && !memcmp(o.buf, a.buf, o.len));
  
  error_return:
@@@ -2042,7 -2043,7 +2043,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_SHA1_BIN);
 +              tree = lookup_tree(&empty_tree_oid);
                merged_common_ancestors = make_virtual_commit(tree, "ancestor");
        }
  
@@@ -2103,7 -2104,7 +2104,7 @@@ static struct commit *get_ref(const str
  {
        struct object *object;
  
 -      object = deref_tag(parse_object(oid->hash), name, strlen(name));
 +      object = deref_tag(parse_object(oid), name, strlen(name));
        if (!object)
                return NULL;
        if (object->type == OBJ_TREE)
diff --combined notes-utils.c
index 9ebf8419565019cca42d778be96e2f3b7d6f29df,9d7fdd635401b15d4e76f65ba19a6cc288a32373..9765deb41ab02dba909ec9027701bf2fdc53f310
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "commit.h"
  #include "refs.h"
  #include "notes-utils.h"
@@@ -7,18 -8,18 +8,18 @@@ void create_notes_commit(struct notes_t
                         const char *msg, size_t msg_len,
                         unsigned char *result_sha1)
  {
 -      unsigned char tree_sha1[20];
 +      struct object_id tree_oid;
  
        assert(t->initialized);
  
 -      if (write_notes_tree(t, tree_sha1))
 +      if (write_notes_tree(t, tree_oid.hash))
                die("Failed to write notes tree to database");
  
        if (!parents) {
                /* Deduce parent commit from t->ref */
 -              unsigned char parent_sha1[20];
 -              if (!read_ref(t->ref, parent_sha1)) {
 -                      struct commit *parent = lookup_commit(parent_sha1);
 +              struct object_id parent_oid;
 +              if (!read_ref(t->ref, parent_oid.hash)) {
 +                      struct commit *parent = lookup_commit(&parent_oid);
                        if (parse_commit(parent))
                                die("Failed to find/parse commit %s", t->ref);
                        commit_list_insert(parent, &parents);
                /* else: t->ref points to nothing, assume root/orphan commit */
        }
  
 -      if (commit_tree(msg, msg_len, tree_sha1, parents, result_sha1, NULL, NULL))
 +      if (commit_tree(msg, msg_len, tree_oid.hash, parents, result_sha1, NULL, NULL))
                die("Failed to commit notes tree to database");
  }
  
  void commit_notes(struct notes_tree *t, const char *msg)
  {
        struct strbuf buf = STRBUF_INIT;
 -      unsigned char commit_sha1[20];
 +      struct object_id commit_oid;
  
        if (!t)
                t = &default_notes_tree;
@@@ -46,9 -47,9 +47,9 @@@
        strbuf_addstr(&buf, msg);
        strbuf_complete_line(&buf);
  
 -      create_notes_commit(t, NULL, buf.buf, buf.len, commit_sha1);
 +      create_notes_commit(t, NULL, buf.buf, buf.len, commit_oid.hash);
        strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */
 -      update_ref(buf.buf, t->update_ref, commit_sha1, NULL, 0,
 +      update_ref(buf.buf, t->update_ref, commit_oid.hash, NULL, 0,
                   UPDATE_REFS_DIE_ON_ERR);
  
        strbuf_release(&buf);
@@@ -132,11 -133,8 +133,11 @@@ struct notes_rewrite_cfg *init_copy_not
                c->mode_from_env = 1;
                c->combine = parse_combine_notes_fn(rewrite_mode_env);
                if (!c->combine)
 -                      /* TRANSLATORS: The first %s is the name of the
 -                         environment variable, the second %s is its value */
 +                      /*
 +                       * TRANSLATORS: The first %s is the name of
 +                       * the environment variable, the second %s is
 +                       * its value.
 +                       */
                        error(_("Bad %s value: '%s'"), GIT_NOTES_REWRITE_MODE_ENVIRONMENT,
                                        rewrite_mode_env);
        }
  }
  
  int copy_note_for_rewrite(struct notes_rewrite_cfg *c,
 -                        const unsigned char *from_obj, const unsigned char *to_obj)
 +                        const struct object_id *from_obj, const struct object_id *to_obj)
  {
        int ret = 0;
        int i;
diff --combined notes.c
index 4b3a1adda566bdc82ba7005083f37dff5bd62ed4,dbcfef4d7a435fcb0072cf1a76613c1d3d103c44..8f47c202c58752b6d9d56852ae9c315e2f144769
+++ b/notes.c
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "notes.h"
  #include "blob.h"
  #include "tree.h"
@@@ -35,8 -36,8 +36,8 @@@ struct int_node 
   * subtree.
   */
  struct leaf_node {
 -      unsigned char key_sha1[20];
 -      unsigned char val_sha1[20];
 +      struct object_id key_oid;
 +      struct object_id val_oid;
  };
  
  /*
@@@ -51,7 -52,7 +52,7 @@@ struct non_note 
        struct non_note *next; /* grounded (last->next == NULL) */
        char *path;
        unsigned int mode;
 -      unsigned char sha1[20];
 +      struct object_id oid;
  };
  
  #define PTR_TYPE_NULL     0
  
  #define GET_NIBBLE(n, sha1) (((sha1[(n) >> 1]) >> ((~(n) & 0x01) << 2)) & 0x0f)
  
 +#define KEY_INDEX (GIT_SHA1_RAWSZ - 1)
 +#define FANOUT_PATH_SEPARATORS ((GIT_SHA1_HEXSZ / 2) - 1)
  #define SUBTREE_SHA1_PREFIXCMP(key_sha1, subtree_sha1) \
 -      (memcmp(key_sha1, subtree_sha1, subtree_sha1[19]))
 +      (memcmp(key_sha1, subtree_sha1, subtree_sha1[KEY_INDEX]))
  
  struct notes_tree default_notes_tree;
  
@@@ -102,7 -101,7 +103,7 @@@ static void **note_tree_search(struct n
  
        if (GET_PTR_TYPE(p) == PTR_TYPE_SUBTREE) {
                l = (struct leaf_node *) CLR_PTR_TYPE(p);
 -              if (!SUBTREE_SHA1_PREFIXCMP(key_sha1, l->key_sha1)) {
 +              if (!SUBTREE_SHA1_PREFIXCMP(key_sha1, l->key_oid.hash)) {
                        /* unpack tree and resume search */
                        (*tree)->a[0] = NULL;
                        load_subtree(t, l, *tree, *n);
                return note_tree_search(t, tree, n, key_sha1);
        case PTR_TYPE_SUBTREE:
                l = (struct leaf_node *) CLR_PTR_TYPE(p);
 -              if (!SUBTREE_SHA1_PREFIXCMP(key_sha1, l->key_sha1)) {
 +              if (!SUBTREE_SHA1_PREFIXCMP(key_sha1, l->key_oid.hash)) {
                        /* unpack tree and resume search */
                        (*tree)->a[i] = NULL;
                        load_subtree(t, l, *tree, *n);
@@@ -145,7 -144,7 +146,7 @@@ static struct leaf_node *note_tree_find
        void **p = note_tree_search(t, &tree, &n, key_sha1);
        if (GET_PTR_TYPE(*p) == PTR_TYPE_NOTE) {
                struct leaf_node *l = (struct leaf_node *) CLR_PTR_TYPE(*p);
 -              if (!hashcmp(key_sha1, l->key_sha1))
 +              if (!hashcmp(key_sha1, l->key_oid.hash))
                        return l;
        }
        return NULL;
@@@ -196,19 -195,19 +197,19 @@@ static void note_tree_remove(struct not
                struct leaf_node *entry)
  {
        struct leaf_node *l;
 -      struct int_node *parent_stack[20];
 +      struct int_node *parent_stack[GIT_SHA1_RAWSZ];
        unsigned char i, j;
 -      void **p = note_tree_search(t, &tree, &n, entry->key_sha1);
 +      void **p = note_tree_search(t, &tree, &n, entry->key_oid.hash);
  
        assert(GET_PTR_TYPE(entry) == 0); /* no type bits set */
        if (GET_PTR_TYPE(*p) != PTR_TYPE_NOTE)
                return; /* type mismatch, nothing to remove */
        l = (struct leaf_node *) CLR_PTR_TYPE(*p);
 -      if (hashcmp(l->key_sha1, entry->key_sha1))
 +      if (oidcmp(&l->key_oid, &entry->key_oid))
                return; /* key mismatch, nothing to remove */
  
        /* we have found a matching entry */
 -      hashcpy(entry->val_sha1, l->val_sha1);
 +      oidcpy(&entry->val_oid, &l->val_oid);
        free(l);
        *p = SET_PTR_TYPE(NULL, PTR_TYPE_NULL);
  
        /* first, build stack of ancestors between root and current node */
        parent_stack[0] = t->root;
        for (i = 0; i < n; i++) {
 -              j = GET_NIBBLE(i, entry->key_sha1);
 +              j = GET_NIBBLE(i, entry->key_oid.hash);
                parent_stack[i + 1] = CLR_PTR_TYPE(parent_stack[i]->a[j]);
        }
        assert(i == n && parent_stack[i] == tree);
        /* next, unwind stack until note_tree_consolidate() is done */
        while (i > 0 &&
               !note_tree_consolidate(parent_stack[i], parent_stack[i - 1],
 -                                    GET_NIBBLE(i - 1, entry->key_sha1)))
 +                                    GET_NIBBLE(i - 1, entry->key_oid.hash)))
                i--;
  }
  
@@@ -248,7 -247,7 +249,7 @@@ static int note_tree_insert(struct note
  {
        struct int_node *new_node;
        struct leaf_node *l;
 -      void **p = note_tree_search(t, &tree, &n, entry->key_sha1);
 +      void **p = note_tree_search(t, &tree, &n, entry->key_oid.hash);
        int ret = 0;
  
        assert(GET_PTR_TYPE(entry) == 0); /* no type bits set */
        switch (GET_PTR_TYPE(*p)) {
        case PTR_TYPE_NULL:
                assert(!*p);
 -              if (is_null_sha1(entry->val_sha1))
 +              if (is_null_oid(&entry->val_oid))
                        free(entry);
                else
                        *p = SET_PTR_TYPE(entry, type);
        case PTR_TYPE_NOTE:
                switch (type) {
                case PTR_TYPE_NOTE:
 -                      if (!hashcmp(l->key_sha1, entry->key_sha1)) {
 +                      if (!oidcmp(&l->key_oid, &entry->key_oid)) {
                                /* skip concatenation if l == entry */
 -                              if (!hashcmp(l->val_sha1, entry->val_sha1))
 +                              if (!oidcmp(&l->val_oid, &entry->val_oid))
                                        return 0;
  
 -                              ret = combine_notes(l->val_sha1,
 -                                                  entry->val_sha1);
 -                              if (!ret && is_null_sha1(l->val_sha1))
 +                              ret = combine_notes(l->val_oid.hash,
 +                                                  entry->val_oid.hash);
 +                              if (!ret && is_null_oid(&l->val_oid))
                                        note_tree_remove(t, tree, n, entry);
                                free(entry);
                                return ret;
                        }
                        break;
                case PTR_TYPE_SUBTREE:
 -                      if (!SUBTREE_SHA1_PREFIXCMP(l->key_sha1,
 -                                                  entry->key_sha1)) {
 +                      if (!SUBTREE_SHA1_PREFIXCMP(l->key_oid.hash,
 +                                                  entry->key_oid.hash)) {
                                /* unpack 'entry' */
                                load_subtree(t, entry, tree, n);
                                free(entry);
                }
                break;
        case PTR_TYPE_SUBTREE:
 -              if (!SUBTREE_SHA1_PREFIXCMP(entry->key_sha1, l->key_sha1)) {
 +              if (!SUBTREE_SHA1_PREFIXCMP(entry->key_oid.hash, l->key_oid.hash)) {
                        /* unpack 'l' and restart insert */
                        *p = NULL;
                        load_subtree(t, l, tree, n);
        /* non-matching leaf_node */
        assert(GET_PTR_TYPE(*p) == PTR_TYPE_NOTE ||
               GET_PTR_TYPE(*p) == PTR_TYPE_SUBTREE);
 -      if (is_null_sha1(entry->val_sha1)) { /* skip insertion of empty note */
 +      if (is_null_oid(&entry->val_oid)) { /* skip insertion of empty note */
                free(entry);
                return 0;
        }
@@@ -343,21 -342,21 +344,21 @@@ static void note_tree_free(struct int_n
   * Otherwise, returns number of bytes written to sha1 (i.e. hex_len / 2).
   * Pads sha1 with NULs up to sha1_len (not included in returned length).
   */
 -static int get_sha1_hex_segment(const char *hex, unsigned int hex_len,
 -              unsigned char *sha1, unsigned int sha1_len)
 +static int get_oid_hex_segment(const char *hex, unsigned int hex_len,
 +              unsigned char *oid, unsigned int oid_len)
  {
        unsigned int i, len = hex_len >> 1;
 -      if (hex_len % 2 != 0 || len > sha1_len)
 +      if (hex_len % 2 != 0 || len > oid_len)
                return -1;
        for (i = 0; i < len; i++) {
                unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]);
                if (val & ~0xff)
                        return -1;
 -              *sha1++ = val;
 +              *oid++ = val;
                hex += 2;
        }
 -      for (; i < sha1_len; i++)
 -              *sha1++ = 0;
 +      for (; i < oid_len; i++)
 +              *oid++ = 0;
        return len;
  }
  
@@@ -375,7 -374,7 +376,7 @@@ static void add_non_note(struct notes_t
        n->next = NULL;
        n->path = path;
        n->mode = mode;
 -      hashcpy(n->sha1, sha1);
 +      hashcpy(n->oid.hash, sha1);
        t->prev_non_note = n;
  
        if (!t->first_non_note) {
        if (non_note_cmp(p, n) == 0) { /* n ~= p; overwrite p with n */
                assert(strcmp(p->path, n->path) == 0);
                p->mode = n->mode;
 -              hashcpy(p->sha1, n->sha1);
 +              oidcpy(&p->oid, &n->oid);
                free(n);
                t->prev_non_note = p;
                return;
  static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
                struct int_node *node, unsigned int n)
  {
 -      unsigned char object_sha1[20];
 +      struct object_id object_oid;
        unsigned int prefix_len;
        void *buf;
        struct tree_desc desc;
        unsigned char type;
        struct leaf_node *l;
  
 -      buf = fill_tree_descriptor(&desc, subtree->val_sha1);
 +      buf = fill_tree_descriptor(&desc, subtree->val_oid.hash);
        if (!buf)
                die("Could not read %s for notes-index",
 -                   sha1_to_hex(subtree->val_sha1));
 +                   oid_to_hex(&subtree->val_oid));
  
 -      prefix_len = subtree->key_sha1[19];
 +      prefix_len = subtree->key_oid.hash[KEY_INDEX];
        assert(prefix_len * 2 >= n);
 -      memcpy(object_sha1, subtree->key_sha1, prefix_len);
 +      memcpy(object_oid.hash, subtree->key_oid.hash, prefix_len);
        while (tree_entry(&desc, &entry)) {
                path_len = strlen(entry.path);
 -              len = get_sha1_hex_segment(entry.path, path_len,
 -                              object_sha1 + prefix_len, 20 - prefix_len);
 +              len = get_oid_hex_segment(entry.path, path_len,
 +                              object_oid.hash + prefix_len, GIT_SHA1_RAWSZ - prefix_len);
                if (len < 0)
                        goto handle_non_note; /* entry.path is not a SHA1 */
                len += prefix_len;
                 * If object SHA1 is incomplete (len < 20), and current
                 * component consists of 2 hex chars, assume note subtree
                 */
 -              if (len <= 20) {
 +              if (len <= GIT_SHA1_RAWSZ) {
                        type = PTR_TYPE_NOTE;
                        l = (struct leaf_node *)
                                xcalloc(1, sizeof(struct leaf_node));
 -                      hashcpy(l->key_sha1, object_sha1);
 -                      hashcpy(l->val_sha1, entry.oid->hash);
 -                      if (len < 20) {
 +                      oidcpy(&l->key_oid, &object_oid);
 +                      oidcpy(&l->val_oid, entry.oid);
 +                      if (len < GIT_SHA1_RAWSZ) {
                                if (!S_ISDIR(entry.mode) || path_len != 2)
                                        goto handle_non_note; /* not subtree */
 -                              l->key_sha1[19] = (unsigned char) len;
 +                              l->key_oid.hash[KEY_INDEX] = (unsigned char) len;
                                type = PTR_TYPE_SUBTREE;
                        }
                        if (note_tree_insert(t, node, n, l, type,
                                die("Failed to load %s %s into notes tree "
                                    "from %s",
                                    type == PTR_TYPE_NOTE ? "note" : "subtree",
 -                                  sha1_to_hex(l->key_sha1), t->ref);
 +                                  oid_to_hex(&l->key_oid), t->ref);
                }
                continue;
  
@@@ -488,7 -487,7 +489,7 @@@ handle_non_note
                 */
                {
                        struct strbuf non_note_path = STRBUF_INIT;
 -                      const char *q = sha1_to_hex(subtree->key_sha1);
 +                      const char *q = oid_to_hex(&subtree->key_oid);
                        int i;
                        for (i = 0; i < prefix_len; i++) {
                                strbuf_addch(&non_note_path, *q++);
@@@ -544,14 -543,14 +545,14 @@@ static unsigned char determine_fanout(s
  }
  
  /* hex SHA1 + 19 * '/' + NUL */
 -#define FANOUT_PATH_MAX 40 + 19 + 1
 +#define FANOUT_PATH_MAX GIT_SHA1_HEXSZ + FANOUT_PATH_SEPARATORS + 1
  
  static void construct_path_with_fanout(const unsigned char *sha1,
                unsigned char fanout, char *path)
  {
        unsigned int i = 0, j = 0;
        const char *hex_sha1 = sha1_to_hex(sha1);
 -      assert(fanout < 20);
 +      assert(fanout < GIT_SHA1_RAWSZ);
        while (fanout) {
                path[i++] = hex_sha1[j++];
                path[i++] = hex_sha1[j++];
@@@ -601,17 -600,15 +602,17 @@@ redo
                            flags & FOR_EACH_NOTE_YIELD_SUBTREES) {
                                /* invoke callback with subtree */
                                unsigned int path_len =
 -                                      l->key_sha1[19] * 2 + fanout;
 +                                      l->key_oid.hash[KEY_INDEX] * 2 + fanout;
                                assert(path_len < FANOUT_PATH_MAX - 1);
 -                              construct_path_with_fanout(l->key_sha1, fanout,
 +                              construct_path_with_fanout(l->key_oid.hash,
 +                                                         fanout,
                                                           path);
                                /* Create trailing slash, if needed */
                                if (path[path_len - 1] != '/')
                                        path[path_len++] = '/';
                                path[path_len] = '\0';
 -                              ret = fn(l->key_sha1, l->val_sha1, path,
 +                              ret = fn(&l->key_oid, &l->val_oid,
 +                                       path,
                                         cb_data);
                        }
                        if (n > fanout * 2 ||
                        break;
                case PTR_TYPE_NOTE:
                        l = (struct leaf_node *) CLR_PTR_TYPE(p);
 -                      construct_path_with_fanout(l->key_sha1, fanout, path);
 -                      ret = fn(l->key_sha1, l->val_sha1, path, cb_data);
 +                      construct_path_with_fanout(l->key_oid.hash, fanout,
 +                                                 path);
 +                      ret = fn(&l->key_oid, &l->val_oid, path,
 +                               cb_data);
                        break;
                }
                if (ret)
@@@ -656,7 -651,7 +657,7 @@@ static void write_tree_entry(struct str
                unsigned char *sha1)
  {
        strbuf_addf(buf, "%o %.*s%c", mode, path_len, path, '\0');
 -      strbuf_add(buf, sha1, 20);
 +      strbuf_add(buf, sha1, GIT_SHA1_RAWSZ);
  }
  
  static void tree_write_stack_init_subtree(struct tree_write_stack *tws,
        n = (struct tree_write_stack *)
                xmalloc(sizeof(struct tree_write_stack));
        n->next = NULL;
 -      strbuf_init(&n->buf, 256 * (32 + 40)); /* assume 256 entries per tree */
 +      strbuf_init(&n->buf, 256 * (32 + GIT_SHA1_HEXSZ)); /* assume 256 entries per tree */
        n->path[0] = n->path[1] = '\0';
        tws->next = n;
        tws->path[0] = path[0];
@@@ -679,18 -674,18 +680,18 @@@ static int tree_write_stack_finish_subt
  {
        int ret;
        struct tree_write_stack *n = tws->next;
 -      unsigned char s[20];
 +      struct object_id s;
        if (n) {
                ret = tree_write_stack_finish_subtree(n);
                if (ret)
                        return ret;
 -              ret = write_sha1_file(n->buf.buf, n->buf.len, tree_type, s);
 +              ret = write_sha1_file(n->buf.buf, n->buf.len, tree_type, s.hash);
                if (ret)
                        return ret;
                strbuf_release(&n->buf);
                free(n);
                tws->next = NULL;
 -              write_tree_entry(&tws->buf, 040000, tws->path, 2, s);
 +              write_tree_entry(&tws->buf, 040000, tws->path, 2, s.hash);
                tws->path[0] = tws->path[1] = '\0';
        }
        return 0;
  
  static int write_each_note_helper(struct tree_write_stack *tws,
                const char *path, unsigned int mode,
 -              const unsigned char *sha1)
 +              const struct object_id *oid)
  {
        size_t path_len = strlen(path);
        unsigned int n = 0;
  
        /* Finally add given entry to the current tree object */
        write_tree_entry(&tws->buf, mode, path + 3 * n, path_len - (3 * n),
 -                       sha1);
 +                       oid->hash);
  
        return 0;
  }
@@@ -748,7 -743,7 +749,7 @@@ static int write_each_non_note_until(co
                        ; /* do nothing, prefer note to non-note */
                else {
                        ret = write_each_note_helper(d->root, n->path, n->mode,
 -                                                   n->sha1);
 +                                                   &n->oid);
                        if (ret)
                                return ret;
                }
        return 0;
  }
  
 -static int write_each_note(const unsigned char *object_sha1,
 -              const unsigned char *note_sha1, char *note_path,
 +static int write_each_note(const struct object_id *object_oid,
 +              const struct object_id *note_oid, char *note_path,
                void *cb_data)
  {
        struct write_each_note_data *d =
                note_path[note_path_len] = '\0';
                mode = 040000;
        }
 -      assert(note_path_len <= 40 + 19);
 +      assert(note_path_len <= GIT_SHA1_HEXSZ + FANOUT_PATH_SEPARATORS);
  
        /* Weave non-note entries into note entries */
        return  write_each_non_note_until(note_path, d) ||
 -              write_each_note_helper(d->root, note_path, mode, note_sha1);
 +              write_each_note_helper(d->root, note_path, mode, note_oid);
  }
  
  struct note_delete_list {
        const unsigned char *sha1;
  };
  
 -static int prune_notes_helper(const unsigned char *object_sha1,
 -              const unsigned char *note_sha1, char *note_path,
 +static int prune_notes_helper(const struct object_id *object_oid,
 +              const struct object_id *note_oid, char *note_path,
                void *cb_data)
  {
        struct note_delete_list **l = (struct note_delete_list **) cb_data;
        struct note_delete_list *n;
  
 -      if (has_sha1_file(object_sha1))
 +      if (has_object_file(object_oid))
                return 0; /* nothing to do for this note */
  
        /* failed to find object => prune this note */
        n = (struct note_delete_list *) xmalloc(sizeof(*n));
        n->next = *l;
 -      n->sha1 = object_sha1;
 +      n->sha1 = object_oid->hash;
        *l = n;
        return 0;
  }
@@@ -948,8 -943,8 +949,8 @@@ void string_list_add_refs_by_glob(struc
        if (has_glob_specials(glob)) {
                for_each_glob_ref(string_list_add_one_ref, glob, list);
        } else {
 -              unsigned char sha1[20];
 -              if (get_sha1(glob, sha1))
 +              struct object_id oid;
 +              if (get_oid(glob, &oid))
                        warning("notes ref %s is invalid", glob);
                if (!unsorted_string_list_has_string(list, glob))
                        string_list_append(list, glob);
@@@ -1033,8 -1028,8 +1034,8 @@@ void init_notes(struct notes_tree *t, c
                die("Failed to read notes tree referenced by %s (%s)",
                    notes_ref, oid_to_hex(&object_oid));
  
 -      hashclr(root_tree.key_sha1);
 -      hashcpy(root_tree.val_sha1, oid.hash);
 +      oidclr(&root_tree.key_oid);
 +      oidcpy(&root_tree.val_oid, &oid);
        load_subtree(t, &root_tree, t->root, 0);
  }
  
@@@ -1086,8 -1081,8 +1087,8 @@@ void init_display_notes(struct display_
        string_list_clear(&display_notes_refs, 0);
  }
  
 -int add_note(struct notes_tree *t, const unsigned char *object_sha1,
 -              const unsigned char *note_sha1, combine_notes_fn combine_notes)
 +int add_note(struct notes_tree *t, const struct object_id *object_oid,
 +              const struct object_id *note_oid, combine_notes_fn combine_notes)
  {
        struct leaf_node *l;
  
        if (!combine_notes)
                combine_notes = t->combine_notes;
        l = (struct leaf_node *) xmalloc(sizeof(struct leaf_node));
 -      hashcpy(l->key_sha1, object_sha1);
 -      hashcpy(l->val_sha1, note_sha1);
 +      oidcpy(&l->key_oid, object_oid);
 +      oidcpy(&l->val_oid, note_oid);
        return note_tree_insert(t, t->root, 0, l, PTR_TYPE_NOTE, combine_notes);
  }
  
@@@ -1110,25 -1105,25 +1111,25 @@@ int remove_note(struct notes_tree *t, c
        if (!t)
                t = &default_notes_tree;
        assert(t->initialized);
 -      hashcpy(l.key_sha1, object_sha1);
 -      hashclr(l.val_sha1);
 +      hashcpy(l.key_oid.hash, object_sha1);
 +      oidclr(&l.val_oid);
        note_tree_remove(t, t->root, 0, &l);
 -      if (is_null_sha1(l.val_sha1)) /* no note was removed */
 +      if (is_null_oid(&l.val_oid)) /* no note was removed */
                return 1;
        t->dirty = 1;
        return 0;
  }
  
 -const unsigned char *get_note(struct notes_tree *t,
 -              const unsigned char *object_sha1)
 +const struct object_id *get_note(struct notes_tree *t,
 +              const struct object_id *oid)
  {
        struct leaf_node *found;
  
        if (!t)
                t = &default_notes_tree;
        assert(t->initialized);
 -      found = note_tree_find(t, t->root, 0, object_sha1);
 -      return found ? found->val_sha1 : NULL;
 +      found = note_tree_find(t, t->root, 0, oid->hash);
 +      return found ? &found->val_oid : NULL;
  }
  
  int for_each_note(struct notes_tree *t, int flags, each_note_fn fn,
@@@ -1152,7 -1147,7 +1153,7 @@@ int write_notes_tree(struct notes_tree 
  
        /* Prepare for traversal of current notes tree */
        root.next = NULL; /* last forward entry in list is grounded */
 -      strbuf_init(&root.buf, 256 * (32 + 40)); /* assume 256 entries */
 +      strbuf_init(&root.buf, 256 * (32 + GIT_SHA1_HEXSZ)); /* assume 256 entries */
        root.path[0] = root.path[1] = '\0';
        cb_data.root = &root;
        cb_data.next_non_note = t->first_non_note;
@@@ -1215,11 -1210,11 +1216,11 @@@ void free_notes(struct notes_tree *t
   * (raw != 0) gives the %N userformat; otherwise, the note message is given
   * for human consumption.
   */
 -static void format_note(struct notes_tree *t, const unsigned char *object_sha1,
 +static void format_note(struct notes_tree *t, const struct object_id *object_oid,
                        struct strbuf *sb, const char *output_encoding, int raw)
  {
        static const char utf8[] = "utf-8";
 -      const unsigned char *sha1;
 +      const struct object_id *oid;
        char *msg, *msg_p;
        unsigned long linelen, msglen;
        enum object_type type;
        if (!t->initialized)
                init_notes(t, NULL, NULL, 0);
  
 -      sha1 = get_note(t, object_sha1);
 -      if (!sha1)
 +      oid = get_note(t, object_oid);
 +      if (!oid)
                return;
  
 -      if (!(msg = read_sha1_file(sha1, &type, &msglen)) || type != OBJ_BLOB) {
 +      if (!(msg = read_sha1_file(oid->hash, &type, &msglen)) || type != OBJ_BLOB) {
                free(msg);
                return;
        }
        free(msg);
  }
  
 -void format_display_notes(const unsigned char *object_sha1,
 +void format_display_notes(const struct object_id *object_oid,
                          struct strbuf *sb, const char *output_encoding, int raw)
  {
        int i;
        assert(display_notes_trees);
        for (i = 0; display_notes_trees[i]; i++)
 -              format_note(display_notes_trees[i], object_sha1, sb,
 +              format_note(display_notes_trees[i], object_oid, sb,
                            output_encoding, raw);
  }
  
  int copy_note(struct notes_tree *t,
 -            const unsigned char *from_obj, const unsigned char *to_obj,
 +            const struct object_id *from_obj, const struct object_id *to_obj,
              int force, combine_notes_fn combine_notes)
  {
 -      const unsigned char *note = get_note(t, from_obj);
 -      const unsigned char *existing_note = get_note(t, to_obj);
 +      const struct object_id *note = get_note(t, from_obj);
 +      const struct object_id *existing_note = get_note(t, to_obj);
  
        if (!force && existing_note)
                return 1;
        if (note)
                return add_note(t, to_obj, note, combine_notes);
        else if (existing_note)
 -              return add_note(t, to_obj, null_sha1, combine_notes);
 +              return add_note(t, to_obj, &null_oid, combine_notes);
  
        return 0;
  }
@@@ -1317,9 -1312,9 +1318,9 @@@ void expand_notes_ref(struct strbuf *sb
  
  void expand_loose_notes_ref(struct strbuf *sb)
  {
 -      unsigned char object[20];
 +      struct object_id object;
  
 -      if (get_sha1(sb->buf, object)) {
 +      if (get_oid(sb->buf, &object)) {
                /* fallback to expand_notes_ref */
                expand_notes_ref(sb);
        }
diff --combined parse-options.c
index e5ad34a2c3f7c7d7fdb65171f8a142a2becc64bb,cbf84a60482126a03af0913b88fb297a34eb5b70..0dd9fc6a0dd0a518200d9bbd834decb3c3ee22c6
@@@ -1,6 -1,7 +1,7 @@@
  #include "git-compat-util.h"
  #include "parse-options.h"
  #include "cache.h"
+ #include "config.h"
  #include "commit.h"
  #include "color.h"
  #include "utf8.h"
@@@ -589,10 -590,8 +590,10 @@@ static int usage_with_options_internal(
  
        fprintf_ln(outfile, _("usage: %s"), _(*usagestr++));
        while (*usagestr && **usagestr)
 -              /* TRANSLATORS: the colon here should align with the
 -                 one in "usage: %s" translation */
 +              /*
 +               * TRANSLATORS: the colon here should align with the
 +               * one in "usage: %s" translation.
 +               */
                fprintf_ln(outfile, _("   or: %s"), _(*usagestr++));
        while (*usagestr) {
                if (**usagestr)
diff --combined pathspec.c
index 828405021fca4214585e1d46b65f604d14e61143,e4659b1440c94d0f65ef486a488b604d6195d81c..ecc5331c232ef81f26343fd958a9b66e92a3fa5e
@@@ -1,5 -1,5 +1,6 @@@
 +#define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
+ #include "config.h"
  #include "dir.h"
  #include "pathspec.h"
  #include "attr.h"
@@@ -18,7 -18,6 +19,7 @@@
   * to use find_pathspecs_matching_against_index() instead.
   */
  void add_pathspec_matches_against_index(const struct pathspec *pathspec,
 +                                      const struct index_state *istate,
                                        char *seen)
  {
        int num_unmatched = 0, i;
@@@ -34,8 -33,8 +35,8 @@@
                        num_unmatched++;
        if (!num_unmatched)
                return;
 -      for (i = 0; i < active_nr; i++) {
 -              const struct cache_entry *ce = active_cache[i];
 +      for (i = 0; i < istate->cache_nr; i++) {
 +              const struct cache_entry *ce = istate->cache[i];
                ce_path_match(ce, pathspec, seen);
        }
  }
   * nature of the "closest" (i.e. most specific) matches which each of the
   * given pathspecs achieves against all items in the index.
   */
 -char *find_pathspecs_matching_against_index(const struct pathspec *pathspec)
 +char *find_pathspecs_matching_against_index(const struct pathspec *pathspec,
 +                                          const struct index_state *istate)
  {
        char *seen = xcalloc(pathspec->nr, 1);
 -      add_pathspec_matches_against_index(pathspec, seen);
 +      add_pathspec_matches_against_index(pathspec, istate, seen);
        return seen;
  }
  
@@@ -389,6 -387,65 +390,6 @@@ static const char *parse_element_magic(
                return parse_short_magic(magic, elem);
  }
  
 -static void strip_submodule_slash_cheap(struct pathspec_item *item)
 -{
 -      if (item->len >= 1 && item->match[item->len - 1] == '/') {
 -              int i = cache_name_pos(item->match, item->len - 1);
 -
 -              if (i >= 0 && S_ISGITLINK(active_cache[i]->ce_mode)) {
 -                      item->len--;
 -                      item->match[item->len] = '\0';
 -              }
 -      }
 -}
 -
 -static void strip_submodule_slash_expensive(struct pathspec_item *item)
 -{
 -      int i;
 -
 -      for (i = 0; i < active_nr; i++) {
 -              struct cache_entry *ce = active_cache[i];
 -              int ce_len = ce_namelen(ce);
 -
 -              if (!S_ISGITLINK(ce->ce_mode))
 -                      continue;
 -
 -              if (item->len <= ce_len || item->match[ce_len] != '/' ||
 -                  memcmp(ce->name, item->match, ce_len))
 -                      continue;
 -
 -              if (item->len == ce_len + 1) {
 -                      /* strip trailing slash */
 -                      item->len--;
 -                      item->match[item->len] = '\0';
 -              } else {
 -                      die(_("Pathspec '%s' is in submodule '%.*s'"),
 -                          item->original, ce_len, ce->name);
 -              }
 -      }
 -}
 -
 -static void die_inside_submodule_path(struct pathspec_item *item)
 -{
 -      int i;
 -
 -      for (i = 0; i < active_nr; i++) {
 -              struct cache_entry *ce = active_cache[i];
 -              int ce_len = ce_namelen(ce);
 -
 -              if (!S_ISGITLINK(ce->ce_mode))
 -                      continue;
 -
 -              if (item->len < ce_len ||
 -                  !(item->match[ce_len] == '/' || item->match[ce_len] == '\0') ||
 -                  memcmp(ce->name, item->match, ce_len))
 -                      continue;
 -
 -              die(_("Pathspec '%s' is in submodule '%.*s'"),
 -                  item->original, ce_len, ce->name);
 -      }
 -}
 -
  /*
   * Perform the initialization of a pathspec_item based on a pathspec element.
   */
@@@ -461,6 -518,12 +462,6 @@@ static void init_pathspec_item(struct p
                item->original = xstrdup(elt);
        }
  
 -      if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)
 -              strip_submodule_slash_cheap(item);
 -
 -      if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)
 -              strip_submodule_slash_expensive(item);
 -
        if (magic & PATHSPEC_LITERAL) {
                item->nowildcard_len = item->len;
        } else {
        /* sanity checks, pathspec matchers assume these are sane */
        if (item->nowildcard_len > item->len ||
            item->prefix         > item->len) {
 -              /*
 -               * This case can be triggered by the user pointing us to a
 -               * pathspec inside a submodule, which is an input error.
 -               * Detect that here and complain, but fallback in the
 -               * non-submodule case to a BUG, as we have no idea what
 -               * would trigger that.
 -               */
 -              die_inside_submodule_path(item);
 -              die ("BUG: item->nowildcard_len > item->len || item->prefix > item->len)");
 +              die ("BUG: error initializing pathspec_item");
        }
  }
  
diff --combined pretty.c
index cc099dfdd1b1081fa142255c172bff8ee06c25b8,06a1f13c609d4315b84fe13eacf5132b123fb759..e4b561c5822b7b19878065c77a04ffa0c9e43d61
+++ b/pretty.c
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "commit.h"
  #include "utf8.h"
  #include "diff.h"
@@@ -405,11 -406,11 +406,11 @@@ static void add_rfc2047(struct strbuf *
  const char *show_ident_date(const struct ident_split *ident,
                            const struct date_mode *mode)
  {
 -      unsigned long date = 0;
 +      timestamp_t date = 0;
        long tz = 0;
  
        if (ident->date_begin && ident->date_end)
 -              date = strtoul(ident->date_begin, NULL, 10);
 +              date = parse_timestamp(ident->date_begin, NULL, 10);
        if (date_overflows(date))
                date = 0;
        else {
@@@ -783,9 -784,29 +784,9 @@@ struct format_commit_context 
        size_t body_off;
  
        /* The following ones are relative to the result struct strbuf. */
 -      struct chunk abbrev_commit_hash;
 -      struct chunk abbrev_tree_hash;
 -      struct chunk abbrev_parent_hashes;
        size_t wrap_start;
  };
  
 -static int add_again(struct strbuf *sb, struct chunk *chunk)
 -{
 -      if (chunk->len) {
 -              strbuf_adddup(sb, chunk->off, chunk->len);
 -              return 1;
 -      }
 -
 -      /*
 -       * We haven't seen this chunk before.  Our caller is surely
 -       * going to add it the hard way now.  Remember the most likely
 -       * start of the to-be-added chunk: the current end of the
 -       * struct strbuf.
 -       */
 -      chunk->off = sb->len;
 -      return 0;
 -}
 -
  static void parse_commit_header(struct format_commit_context *context)
  {
        const char *msg = context->message;
@@@ -1117,7 -1138,7 +1118,7 @@@ static size_t format_commit_one(struct 
  
        /* these depend on the commit */
        if (!commit->object.parsed)
 -              parse_object(commit->object.oid.hash);
 +              parse_object(&commit->object.oid);
  
        switch (placeholder[0]) {
        case 'H':               /* commit hash */
                return 1;
        case 'h':               /* abbreviated commit hash */
                strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_COMMIT));
 -              if (add_again(sb, &c->abbrev_commit_hash)) {
 -                      strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
 -                      return 1;
 -              }
                strbuf_add_unique_abbrev(sb, commit->object.oid.hash,
                                         c->pretty_ctx->abbrev);
                strbuf_addstr(sb, diff_get_color(c->auto_color, DIFF_RESET));
 -              c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
                return 1;
        case 'T':               /* tree hash */
                strbuf_addstr(sb, oid_to_hex(&commit->tree->object.oid));
                return 1;
        case 't':               /* abbreviated tree hash */
 -              if (add_again(sb, &c->abbrev_tree_hash))
 -                      return 1;
                strbuf_add_unique_abbrev(sb, commit->tree->object.oid.hash,
                                         c->pretty_ctx->abbrev);
 -              c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off;
                return 1;
        case 'P':               /* parent hashes */
                for (p = commit->parents; p; p = p->next) {
                }
                return 1;
        case 'p':               /* abbreviated parent hashes */
 -              if (add_again(sb, &c->abbrev_parent_hashes))
 -                      return 1;
                for (p = commit->parents; p; p = p->next) {
                        if (p != commit->parents)
                                strbuf_addch(sb, ' ');
                        strbuf_add_unique_abbrev(sb, p->item->object.oid.hash,
                                                 c->pretty_ctx->abbrev);
                }
 -              c->abbrev_parent_hashes.len = sb->len -
 -                                            c->abbrev_parent_hashes.off;
                return 1;
        case 'm':               /* left/right/bottom */
                strbuf_addstr(sb, get_revision_mark(NULL, commit));
diff --combined read-cache.c
index f0269200526bf17f7b9b04b3d0b80383c99e73b8,e623e075de9ad09743da2c329132efa6a8dda231..ad692e198d9b869883017c941be76b05be6f7d7a
@@@ -5,6 -5,7 +5,7 @@@
   */
  #define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
+ #include "config.h"
  #include "tempfile.h"
  #include "lockfile.h"
  #include "cache-tree.h"
@@@ -2187,10 -2188,9 +2188,10 @@@ void update_index_if_able(struct index_
                rollback_lock_file(lockfile);
  }
  
 -static int do_write_index(struct index_state *istate, int newfd,
 +static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                          int strip_extensions)
  {
 +      int newfd = tempfile->fd;
        git_SHA_CTX c;
        struct cache_header hdr;
        int i, err, removed, extended, hdr_version;
        int entries = istate->cache_nr;
        struct stat st;
        struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
 +      int drop_cache_tree = 0;
  
        for (i = removed = extended = 0; i < entries; i++) {
                if (cache[i]->ce_flags & CE_REMOVE)
                                warning(msg, ce->name);
                        else
                                return error(msg, ce->name);
 +
 +                      drop_cache_tree = 1;
                }
                if (ce_write_entry(&c, newfd, ce, previous_name) < 0)
                        return -1;
                if (err)
                        return -1;
        }
 -      if (!strip_extensions && istate->cache_tree) {
 +      if (!strip_extensions && !drop_cache_tree && istate->cache_tree) {
                struct strbuf sb = STRBUF_INIT;
  
                cache_tree_write(&sb, istate->cache_tree);
                        return -1;
        }
  
 -      if (ce_flush(&c, newfd, istate->sha1) || fstat(newfd, &st))
 +      if (ce_flush(&c, newfd, istate->sha1))
 +              return -1;
 +      if (close_tempfile(tempfile))
 +              return error(_("could not close '%s'"), tempfile->filename.buf);
 +      if (stat(tempfile->filename.buf, &st))
                return -1;
        istate->timestamp.sec = (unsigned int)st.st_mtime;
        istate->timestamp.nsec = ST_MTIME_NSEC(st);
@@@ -2329,7 -2322,7 +2330,7 @@@ static int commit_locked_index(struct l
  static int do_write_locked_index(struct index_state *istate, struct lock_file *lock,
                                 unsigned flags)
  {
 -      int ret = do_write_index(istate, get_lock_file_fd(lock), 0);
 +      int ret = do_write_index(istate, &lock->tempfile, 0);
        if (ret)
                return ret;
        assert((flags & (COMMIT_LOCK | CLOSE_LOCK)) !=
@@@ -2426,7 -2419,7 +2427,7 @@@ static int write_shared_index(struct in
                return do_write_locked_index(istate, lock, flags);
        }
        move_cache_to_base_index(istate);
 -      ret = do_write_index(si->base, fd, 1);
 +      ret = do_write_index(si->base, &temporary_sharedindex, 1);
        if (ret) {
                delete_tempfile(&temporary_sharedindex);
                return ret;
@@@ -2636,9 -2629,3 +2637,9 @@@ void stat_validity_update(struct stat_v
                fill_stat_data(sv->sd, &st);
        }
  }
 +
 +void move_index_extensions(struct index_state *dst, struct index_state *src)
 +{
 +      dst->untracked = src->untracked;
 +      src->untracked = NULL;
 +}
diff --combined refs.c
index f0685c92513e306188d89380a1c3020024a4edb4,c0cd259141a8c188c87bf890cde24a0c3776da05..84112c88ee4349ef8c7411f6e046d0f2d289ea04
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -3,6 -3,7 +3,7 @@@
   */
  
  #include "cache.h"
+ #include "config.h"
  #include "hashmap.h"
  #include "lockfile.h"
  #include "iterator.h"
@@@ -11,7 -12,6 +12,7 @@@
  #include "object.h"
  #include "tag.h"
  #include "submodule.h"
 +#include "worktree.h"
  
  /*
   * List of all available backends
@@@ -714,7 -714,7 +715,7 @@@ int is_branch(const char *refname
  
  struct read_ref_at_cb {
        const char *refname;
 -      unsigned long at_time;
 +      timestamp_t at_time;
        int cnt;
        int reccnt;
        unsigned char *sha1;
        unsigned char osha1[20];
        unsigned char nsha1[20];
        int tz;
 -      unsigned long date;
 +      timestamp_t date;
        char **msg;
 -      unsigned long *cutoff_time;
 +      timestamp_t *cutoff_time;
        int *cutoff_tz;
        int *cutoff_cnt;
  };
  
  static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
 -              const char *email, unsigned long timestamp, int tz,
 +              const char *email, timestamp_t timestamp, int tz,
                const char *message, void *cb_data)
  {
        struct read_ref_at_cb *cb = cb_data;
  }
  
  static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid,
 -                                const char *email, unsigned long timestamp,
 +                                const char *email, timestamp_t timestamp,
                                  int tz, const char *message, void *cb_data)
  {
        struct read_ref_at_cb *cb = cb_data;
        return 1;
  }
  
 -int read_ref_at(const char *refname, unsigned int flags, unsigned long at_time, int cnt,
 +int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, int cnt,
                unsigned char *sha1, char **msg,
 -              unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)
 +              timestamp_t *cutoff_time, int *cutoff_tz, int *cutoff_cnt)
  {
        struct read_ref_at_cb cb;
  
@@@ -848,24 -848,11 +849,24 @@@ struct ref_transaction *ref_transaction
  
  void ref_transaction_free(struct ref_transaction *transaction)
  {
 -      int i;
 +      size_t i;
  
        if (!transaction)
                return;
  
 +      switch (transaction->state) {
 +      case REF_TRANSACTION_OPEN:
 +      case REF_TRANSACTION_CLOSED:
 +              /* OK */
 +              break;
 +      case REF_TRANSACTION_PREPARED:
 +              die("BUG: free called on a prepared reference transaction");
 +              break;
 +      default:
 +              die("BUG: unexpected reference transaction state");
 +              break;
 +      }
 +
        for (i = 0; i < transaction->nr; i++) {
                free(transaction->updates[i]->msg);
                free(transaction->updates[i]);
@@@ -896,9 -883,9 +897,9 @@@ struct ref_update *ref_transaction_add_
        update->flags = flags;
  
        if (flags & REF_HAVE_NEW)
 -              hashcpy(update->new_sha1, new_sha1);
 +              hashcpy(update->new_oid.hash, new_sha1);
        if (flags & REF_HAVE_OLD)
 -              hashcpy(update->old_sha1, old_sha1);
 +              hashcpy(update->old_oid.hash, old_sha1);
        update->msg = xstrdup_or_null(msg);
        return update;
  }
@@@ -1259,19 -1246,8 +1260,19 @@@ struct ref_iterator *refs_ref_iterator_
  {
        struct ref_iterator *iter;
  
 +      if (ref_paranoia < 0)
 +              ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 0);
 +      if (ref_paranoia)
 +              flags |= DO_FOR_EACH_INCLUDE_BROKEN;
 +
        iter = refs->be->iterator_begin(refs, prefix, flags);
 -      iter = prefix_ref_iterator_begin(iter, prefix, trim);
 +
 +      /*
 +       * `iterator_begin()` already takes care of prefix, but we
 +       * might need to do some trimming:
 +       */
 +      if (trim)
 +              iter = prefix_ref_iterator_begin(iter, "", trim);
  
        return iter;
  }
@@@ -1502,32 -1478,32 +1503,32 @@@ int resolve_gitlink_ref(const char *sub
        return 0;
  }
  
 -struct submodule_hash_entry
 +struct ref_store_hash_entry
  {
        struct hashmap_entry ent; /* must be the first member! */
  
        struct ref_store *refs;
  
 -      /* NUL-terminated name of submodule: */
 -      char submodule[FLEX_ARRAY];
 +      /* NUL-terminated identifier of the ref store: */
 +      char name[FLEX_ARRAY];
  };
  
 -static int submodule_hash_cmp(const void *entry, const void *entry_or_key,
 +static int ref_store_hash_cmp(const void *entry, const void *entry_or_key,
                              const void *keydata)
  {
 -      const struct submodule_hash_entry *e1 = entry, *e2 = entry_or_key;
 -      const char *submodule = keydata ? keydata : e2->submodule;
 +      const struct ref_store_hash_entry *e1 = entry, *e2 = entry_or_key;
 +      const char *name = keydata ? keydata : e2->name;
  
 -      return strcmp(e1->submodule, submodule);
 +      return strcmp(e1->name, name);
  }
  
 -static struct submodule_hash_entry *alloc_submodule_hash_entry(
 -              const char *submodule, struct ref_store *refs)
 +static struct ref_store_hash_entry *alloc_ref_store_hash_entry(
 +              const char *name, struct ref_store *refs)
  {
 -      struct submodule_hash_entry *entry;
 +      struct ref_store_hash_entry *entry;
  
 -      FLEX_ALLOC_STR(entry, submodule, submodule);
 -      hashmap_entry_init(entry, strhash(submodule));
 +      FLEX_ALLOC_STR(entry, name, name);
 +      hashmap_entry_init(entry, strhash(name));
        entry->refs = refs;
        return entry;
  }
@@@ -1538,23 -1514,20 +1539,23 @@@ static struct ref_store *main_ref_store
  /* A hashmap of ref_stores, stored by submodule name: */
  static struct hashmap submodule_ref_stores;
  
 +/* A hashmap of ref_stores, stored by worktree id: */
 +static struct hashmap worktree_ref_stores;
 +
  /*
 - * Return the ref_store instance for the specified submodule. If that
 - * ref_store hasn't been initialized yet, return NULL.
 + * Look up a ref store by name. If that ref_store hasn't been
 + * registered yet, return NULL.
   */
 -static struct ref_store *lookup_submodule_ref_store(const char *submodule)
 +static struct ref_store *lookup_ref_store_map(struct hashmap *map,
 +                                            const char *name)
  {
 -      struct submodule_hash_entry *entry;
 +      struct ref_store_hash_entry *entry;
  
 -      if (!submodule_ref_stores.tablesize)
 +      if (!map->tablesize)
                /* It's initialized on demand in register_ref_store(). */
                return NULL;
  
 -      entry = hashmap_get_from_hash(&submodule_ref_stores,
 -                                    strhash(submodule), submodule);
 +      entry = hashmap_get_from_hash(map, strhash(name), name);
        return entry ? entry->refs : NULL;
  }
  
@@@ -1581,24 -1554,29 +1582,24 @@@ struct ref_store *get_main_ref_store(vo
        if (main_ref_store)
                return main_ref_store;
  
 -      main_ref_store = ref_store_init(get_git_dir(),
 -                                      (REF_STORE_READ |
 -                                       REF_STORE_WRITE |
 -                                       REF_STORE_ODB |
 -                                       REF_STORE_MAIN));
 +      main_ref_store = ref_store_init(get_git_dir(), REF_STORE_ALL_CAPS);
        return main_ref_store;
  }
  
  /*
 - * Register the specified ref_store to be the one that should be used
 - * for submodule. It is a fatal error to call this function twice for
 - * the same submodule.
 + * Associate a ref store with a name. It is a fatal error to call this
 + * function twice for the same name.
   */
 -static void register_submodule_ref_store(struct ref_store *refs,
 -                                       const char *submodule)
 +static void register_ref_store_map(struct hashmap *map,
 +                                 const char *type,
 +                                 struct ref_store *refs,
 +                                 const char *name)
  {
 -      if (!submodule_ref_stores.tablesize)
 -              hashmap_init(&submodule_ref_stores, submodule_hash_cmp, 0);
 +      if (!map->tablesize)
 +              hashmap_init(map, ref_store_hash_cmp, 0);
  
 -      if (hashmap_put(&submodule_ref_stores,
 -                      alloc_submodule_hash_entry(submodule, refs)))
 -              die("BUG: ref_store for submodule '%s' initialized twice",
 -                  submodule);
 +      if (hashmap_put(map, alloc_ref_store_hash_entry(name, refs)))
 +              die("BUG: %s ref_store '%s' initialized twice", type, name);
  }
  
  struct ref_store *get_submodule_ref_store(const char *submodule)
                return get_main_ref_store();
        }
  
 -      refs = lookup_submodule_ref_store(submodule);
 +      refs = lookup_ref_store_map(&submodule_ref_stores, submodule);
        if (refs)
                return refs;
  
        /* assume that add_submodule_odb() has been called */
        refs = ref_store_init(submodule_sb.buf,
                              REF_STORE_READ | REF_STORE_ODB);
 -      register_submodule_ref_store(refs, submodule);
 +      register_ref_store_map(&submodule_ref_stores, "submodule",
 +                             refs, submodule);
  
        strbuf_release(&submodule_sb);
        return refs;
  }
  
 +struct ref_store *get_worktree_ref_store(const struct worktree *wt)
 +{
 +      struct ref_store *refs;
 +      const char *id;
 +
 +      if (wt->is_current)
 +              return get_main_ref_store();
 +
 +      id = wt->id ? wt->id : "/";
 +      refs = lookup_ref_store_map(&worktree_ref_stores, id);
 +      if (refs)
 +              return refs;
 +
 +      if (wt->id)
 +              refs = ref_store_init(git_common_path("worktrees/%s", wt->id),
 +                                    REF_STORE_ALL_CAPS);
 +      else
 +              refs = ref_store_init(get_git_common_dir(),
 +                                    REF_STORE_ALL_CAPS);
 +
 +      if (refs)
 +              register_ref_store_map(&worktree_ref_stores, "worktree",
 +                                     refs, id);
 +      return refs;
 +}
 +
  void base_ref_store_init(struct ref_store *refs,
                         const struct ref_storage_be *be)
  {
@@@ -1707,108 -1658,18 +1708,108 @@@ int create_symref(const char *ref_targe
                                  refs_heads_master, logmsg);
  }
  
 -int ref_transaction_commit(struct ref_transaction *transaction,
 -                         struct strbuf *err)
 +int ref_update_reject_duplicates(struct string_list *refnames,
 +                               struct strbuf *err)
 +{
 +      size_t i, n = refnames->nr;
 +
 +      assert(err);
 +
 +      for (i = 1; i < n; i++) {
 +              int cmp = strcmp(refnames->items[i - 1].string,
 +                               refnames->items[i].string);
 +
 +              if (!cmp) {
 +                      strbuf_addf(err,
 +                                  "multiple updates for ref '%s' not allowed.",
 +                                  refnames->items[i].string);
 +                      return 1;
 +              } else if (cmp > 0) {
 +                      die("BUG: ref_update_reject_duplicates() received unsorted list");
 +              }
 +      }
 +      return 0;
 +}
 +
 +int ref_transaction_prepare(struct ref_transaction *transaction,
 +                          struct strbuf *err)
  {
        struct ref_store *refs = transaction->ref_store;
  
 +      switch (transaction->state) {
 +      case REF_TRANSACTION_OPEN:
 +              /* Good. */
 +              break;
 +      case REF_TRANSACTION_PREPARED:
 +              die("BUG: prepare called twice on reference transaction");
 +              break;
 +      case REF_TRANSACTION_CLOSED:
 +              die("BUG: prepare called on a closed reference transaction");
 +              break;
 +      default:
 +              die("BUG: unexpected reference transaction state");
 +              break;
 +      }
 +
        if (getenv(GIT_QUARANTINE_ENVIRONMENT)) {
                strbuf_addstr(err,
                              _("ref updates forbidden inside quarantine environment"));
                return -1;
        }
  
 -      return refs->be->transaction_commit(refs, transaction, err);
 +      return refs->be->transaction_prepare(refs, transaction, err);
 +}
 +
 +int ref_transaction_abort(struct ref_transaction *transaction,
 +                        struct strbuf *err)
 +{
 +      struct ref_store *refs = transaction->ref_store;
 +      int ret = 0;
 +
 +      switch (transaction->state) {
 +      case REF_TRANSACTION_OPEN:
 +              /* No need to abort explicitly. */
 +              break;
 +      case REF_TRANSACTION_PREPARED:
 +              ret = refs->be->transaction_abort(refs, transaction, err);
 +              break;
 +      case REF_TRANSACTION_CLOSED:
 +              die("BUG: abort called on a closed reference transaction");
 +              break;
 +      default:
 +              die("BUG: unexpected reference transaction state");
 +              break;
 +      }
 +
 +      ref_transaction_free(transaction);
 +      return ret;
 +}
 +
 +int ref_transaction_commit(struct ref_transaction *transaction,
 +                         struct strbuf *err)
 +{
 +      struct ref_store *refs = transaction->ref_store;
 +      int ret;
 +
 +      switch (transaction->state) {
 +      case REF_TRANSACTION_OPEN:
 +              /* Need to prepare first. */
 +              ret = ref_transaction_prepare(transaction, err);
 +              if (ret)
 +                      return ret;
 +              break;
 +      case REF_TRANSACTION_PREPARED:
 +              /* Fall through to finish. */
 +              break;
 +      case REF_TRANSACTION_CLOSED:
 +              die("BUG: commit called on a closed reference transaction");
 +              break;
 +      default:
 +              die("BUG: unexpected reference transaction state");
 +              break;
 +      }
 +
 +      return refs->be->transaction_finish(refs, transaction, err);
  }
  
  int refs_verify_refname_available(struct ref_store *refs,
@@@ -2010,16 -1871,15 +2011,16 @@@ int initial_ref_transaction_commit(stru
        return refs->be->initial_transaction_commit(refs, transaction, err);
  }
  
 -int refs_delete_refs(struct ref_store *refs, struct string_list *refnames,
 -                   unsigned int flags)
 +int refs_delete_refs(struct ref_store *refs, const char *msg,
 +                   struct string_list *refnames, unsigned int flags)
  {
 -      return refs->be->delete_refs(refs, refnames, flags);
 +      return refs->be->delete_refs(refs, msg, refnames, flags);
  }
  
 -int delete_refs(struct string_list *refnames, unsigned int flags)
 +int delete_refs(const char *msg, struct string_list *refnames,
 +              unsigned int flags)
  {
 -      return refs_delete_refs(get_main_ref_store(), refnames, flags);
 +      return refs_delete_refs(get_main_ref_store(), msg, refnames, flags);
  }
  
  int refs_rename_ref(struct ref_store *refs, const char *oldref,
diff --combined refs/files-backend.c
index d8b3f73147c8af88597ad71259aef0a9f53dd104,1d530f602051be6388344fc113e5f3287ea3e887..621a4086c37362180f151cc1648444d4cfd69d13
@@@ -1,4 -1,5 +1,5 @@@
  #include "../cache.h"
+ #include "../config.h"
  #include "../refs.h"
  #include "refs-internal.h"
  #include "ref-cache.h"
@@@ -43,6 -44,15 +44,6 @@@ struct packed_ref_cache 
         */
        unsigned int referrers;
  
 -      /*
 -       * Iff the packed-refs file associated with this instance is
 -       * currently locked for writing, this points at the associated
 -       * lock (which is owned by somebody else).  The referrer count
 -       * is also incremented when the file is locked and decremented
 -       * when it is unlocked.
 -       */
 -      struct lock_file *lock;
 -
        /* The metadata from when this packed-refs cache was read */
        struct stat_validity validity;
  };
@@@ -61,13 -71,10 +62,13 @@@ struct files_ref_store 
  
        struct ref_cache *loose;
        struct packed_ref_cache *packed;
 -};
  
 -/* Lock used for the main packed-refs file: */
 -static struct lock_file packlock;
 +      /*
 +       * Lock used for the "packed-refs" file. Note that this (and
 +       * thus the enclosing `files_ref_store`) must not be freed.
 +       */
 +      struct lock_file packed_refs_lock;
 +};
  
  /*
   * Increment the reference count of *packed_refs.
@@@ -98,8 -105,8 +99,8 @@@ static void clear_packed_ref_cache(stru
        if (refs->packed) {
                struct packed_ref_cache *packed_refs = refs->packed;
  
 -              if (packed_refs->lock)
 -                      die("internal error: packed-ref cache cleared while locked");
 +              if (is_lock_file_locked(&refs->packed_refs_lock))
 +                      die("BUG: packed-ref cache cleared while locked");
                refs->packed = NULL;
                release_packed_ref_cache(packed_refs);
        }
@@@ -189,15 -196,27 +190,15 @@@ static const char PACKED_REFS_HEADER[] 
   * Return a pointer to the refname within the line (null-terminated),
   * or NULL if there was a problem.
   */
 -static const char *parse_ref_line(struct strbuf *line, unsigned char *sha1)
 +static const char *parse_ref_line(struct strbuf *line, struct object_id *oid)
  {
        const char *ref;
  
 -      /*
 -       * 42: the answer to everything.
 -       *
 -       * In this case, it happens to be the answer to
 -       *  40 (length of sha1 hex representation)
 -       *  +1 (space in between hex and name)
 -       *  +1 (newline at the end of the line)
 -       */
 -      if (line->len <= 42)
 +      if (parse_oid_hex(line->buf, oid, &ref) < 0)
                return NULL;
 -
 -      if (get_sha1_hex(line->buf, sha1) < 0)
 -              return NULL;
 -      if (!isspace(line->buf[40]))
 +      if (!isspace(*ref++))
                return NULL;
  
 -      ref = line->buf + 41;
        if (isspace(*ref))
                return NULL;
  
  }
  
  /*
 - * Read f, which is a packed-refs file, into dir.
 + * Read from `packed_refs_file` into a newly-allocated
 + * `packed_ref_cache` and return it. The return value will already
 + * have its reference count incremented.
   *
   * A comment line of the form "# pack-refs with: " may contain zero or
   * more traits. We interpret the traits as follows:
   *      compatibility with older clients, but we do not require it
   *      (i.e., "peeled" is a no-op if "fully-peeled" is set).
   */
 -static void read_packed_refs(FILE *f, struct ref_dir *dir)
 +static struct packed_ref_cache *read_packed_refs(const char *packed_refs_file)
  {
 +      FILE *f;
 +      struct packed_ref_cache *packed_refs = xcalloc(1, sizeof(*packed_refs));
        struct ref_entry *last = NULL;
        struct strbuf line = STRBUF_INIT;
        enum { PEELED_NONE, PEELED_TAGS, PEELED_FULLY } peeled = PEELED_NONE;
 +      struct ref_dir *dir;
 +
 +      acquire_packed_ref_cache(packed_refs);
 +      packed_refs->cache = create_ref_cache(NULL, NULL);
 +      packed_refs->cache->root->flag &= ~REF_INCOMPLETE;
 +
 +      f = fopen(packed_refs_file, "r");
 +      if (!f) {
 +              if (errno == ENOENT) {
 +                      /*
 +                       * This is OK; it just means that no
 +                       * "packed-refs" file has been written yet,
 +                       * which is equivalent to it being empty.
 +                       */
 +                      return packed_refs;
 +              } else {
 +                      die_errno("couldn't read %s", packed_refs_file);
 +              }
 +      }
 +
 +      stat_validity_update(&packed_refs->validity, fileno(f));
  
 +      dir = get_ref_dir(packed_refs->cache->root);
        while (strbuf_getwholeline(&line, f, '\n') != EOF) {
 -              unsigned char sha1[20];
 +              struct object_id oid;
                const char *refname;
                const char *traits;
  
                        continue;
                }
  
 -              refname = parse_ref_line(&line, sha1);
 +              refname = parse_ref_line(&line, &oid);
                if (refname) {
                        int flag = REF_ISPACKED;
  
                        if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
                                if (!refname_is_safe(refname))
                                        die("packed refname is dangerous: %s", refname);
 -                              hashclr(sha1);
 +                              oidclr(&oid);
                                flag |= REF_BAD_NAME | REF_ISBROKEN;
                        }
 -                      last = create_ref_entry(refname, sha1, flag, 0);
 +                      last = create_ref_entry(refname, &oid, flag);
                        if (peeled == PEELED_FULLY ||
                            (peeled == PEELED_TAGS && starts_with(refname, "refs/tags/")))
                                last->flag |= REF_KNOWS_PEELED;
                    line.buf[0] == '^' &&
                    line.len == PEELED_LINE_LENGTH &&
                    line.buf[PEELED_LINE_LENGTH - 1] == '\n' &&
 -                  !get_sha1_hex(line.buf + 1, sha1)) {
 -                      hashcpy(last->u.value.peeled.hash, sha1);
 +                  !get_oid_hex(line.buf + 1, &oid)) {
 +                      oidcpy(&last->u.value.peeled, &oid);
                        /*
                         * Regardless of what the file header said,
                         * we definitely know the value of *this*
                }
        }
  
 +      fclose(f);
        strbuf_release(&line);
 +
 +      return packed_refs;
  }
  
  static const char *files_packed_refs_path(struct files_ref_store *refs)
@@@ -371,24 -361,30 +372,24 @@@ static void files_ref_path(struct files
  
  /*
   * Get the packed_ref_cache for the specified files_ref_store,
 - * creating it if necessary.
 + * creating and populating it if it hasn't been read before or if the
 + * file has been changed (according to its `validity` field) since it
 + * was last read. On the other hand, if we hold the lock, then assume
 + * that the file hasn't been changed out from under us, so skip the
 + * extra `stat()` call in `stat_validity_check()`.
   */
  static struct packed_ref_cache *get_packed_ref_cache(struct files_ref_store *refs)
  {
        const char *packed_refs_file = files_packed_refs_path(refs);
  
        if (refs->packed &&
 +          !is_lock_file_locked(&refs->packed_refs_lock) &&
            !stat_validity_check(&refs->packed->validity, packed_refs_file))
                clear_packed_ref_cache(refs);
  
 -      if (!refs->packed) {
 -              FILE *f;
 -
 -              refs->packed = xcalloc(1, sizeof(*refs->packed));
 -              acquire_packed_ref_cache(refs->packed);
 -              refs->packed->cache = create_ref_cache(&refs->base, NULL);
 -              refs->packed->cache->root->flag &= ~REF_INCOMPLETE;
 -              f = fopen(packed_refs_file, "r");
 -              if (f) {
 -                      stat_validity_update(&refs->packed->validity, fileno(f));
 -                      read_packed_refs(f, get_ref_dir(refs->packed->cache->root));
 -                      fclose(f);
 -              }
 -      }
 +      if (!refs->packed)
 +              refs->packed = read_packed_refs(packed_refs_file);
 +
        return refs->packed;
  }
  
@@@ -409,18 -405,14 +410,18 @@@ static struct ref_dir *get_packed_refs(
   * commit_packed_refs().
   */
  static void add_packed_ref(struct files_ref_store *refs,
 -                         const char *refname, const unsigned char *sha1)
 +                         const char *refname, const struct object_id *oid)
  {
        struct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(refs);
  
 -      if (!packed_ref_cache->lock)
 -              die("internal error: packed refs not locked");
 +      if (!is_lock_file_locked(&refs->packed_refs_lock))
 +              die("BUG: packed refs not locked");
 +
 +      if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
 +              die("Reference has invalid format: '%s'", refname);
 +
        add_ref_entry(get_packed_ref_dir(packed_ref_cache),
 -                    create_ref_entry(refname, sha1, REF_ISPACKED, 1));
 +                    create_ref_entry(refname, oid, REF_ISPACKED));
  }
  
  /*
@@@ -453,7 -445,7 +454,7 @@@ static void loose_fill_ref_dir(struct r
        strbuf_add(&refname, dirname, dirnamelen);
  
        while ((de = readdir(d)) != NULL) {
 -              unsigned char sha1[20];
 +              struct object_id oid;
                struct stat st;
                int flag;
  
                        if (!refs_resolve_ref_unsafe(&refs->base,
                                                     refname.buf,
                                                     RESOLVE_REF_READING,
 -                                                   sha1, &flag)) {
 -                              hashclr(sha1);
 +                                                   oid.hash, &flag)) {
 +                              oidclr(&oid);
                                flag |= REF_ISBROKEN;
 -                      } else if (is_null_sha1(sha1)) {
 +                      } else if (is_null_oid(&oid)) {
                                /*
                                 * It is so astronomically unlikely
                                 * that NULL_SHA1 is the SHA-1 of an
                                                 REFNAME_ALLOW_ONELEVEL)) {
                                if (!refname_is_safe(refname.buf))
                                        die("loose refname is dangerous: %s", refname.buf);
 -                              hashclr(sha1);
 +                              oidclr(&oid);
                                flag |= REF_BAD_NAME | REF_ISBROKEN;
                        }
                        add_entry_to_dir(dir,
 -                                       create_ref_entry(refname.buf, sha1, flag, 0));
 +                                       create_ref_entry(refname.buf, &oid, flag));
                }
                strbuf_setlen(&refname, dirnamelen);
                strbuf_setlen(&path, path_baselen);
@@@ -1078,12 -1070,15 +1079,12 @@@ static struct ref_iterator *files_ref_i
        struct ref_iterator *loose_iter, *packed_iter;
        struct files_ref_iterator *iter;
        struct ref_iterator *ref_iterator;
 +      unsigned int required_flags = REF_STORE_READ;
  
 -      if (ref_paranoia < 0)
 -              ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 0);
 -      if (ref_paranoia)
 -              flags |= DO_FOR_EACH_INCLUDE_BROKEN;
 +      if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN))
 +              required_flags |= REF_STORE_ODB;
  
 -      refs = files_downcast(ref_store,
 -                            REF_STORE_READ | (ref_paranoia ? 0 : REF_STORE_ODB),
 -                            "ref_iterator_begin");
 +      refs = files_downcast(ref_store, required_flags, "ref_iterator_begin");
  
        iter = xcalloc(1, sizeof(*iter));
        ref_iterator = &iter->base;
@@@ -1308,17 -1303,17 +1309,17 @@@ static int lock_packed_refs(struct file
        }
  
        if (hold_lock_file_for_update_timeout(
 -                          &packlock, files_packed_refs_path(refs),
 +                          &refs->packed_refs_lock, files_packed_refs_path(refs),
                            flags, timeout_value) < 0)
                return -1;
        /*
 -       * Get the current packed-refs while holding the lock.  If the
 -       * packed-refs file has been modified since we last read it,
 -       * this will automatically invalidate the cache and re-read
 -       * the packed-refs file.
 +       * Get the current packed-refs while holding the lock. It is
 +       * important that we call `get_packed_ref_cache()` before
 +       * setting `packed_ref_cache->lock`, because otherwise the
 +       * former will see that the file is locked and assume that the
 +       * cache can't be stale.
         */
        packed_ref_cache = get_packed_ref_cache(refs);
 -      packed_ref_cache->lock = &packlock;
        /* Increment the reference count to prevent it from being freed: */
        acquire_packed_ref_cache(packed_ref_cache);
        return 0;
@@@ -1341,10 -1336,10 +1342,10 @@@ static int commit_packed_refs(struct fi
  
        files_assert_main_repository(refs, "commit_packed_refs");
  
 -      if (!packed_ref_cache->lock)
 -              die("internal error: packed-refs not locked");
 +      if (!is_lock_file_locked(&refs->packed_refs_lock))
 +              die("BUG: packed-refs not locked");
  
 -      out = fdopen_lock_file(packed_ref_cache->lock, "w");
 +      out = fdopen_lock_file(&refs->packed_refs_lock, "w");
        if (!out)
                die_errno("unable to fdopen packed-refs descriptor");
  
        if (ok != ITER_DONE)
                die("error while iterating over references");
  
 -      if (commit_lock_file(packed_ref_cache->lock)) {
 +      if (commit_lock_file(&refs->packed_refs_lock)) {
                save_errno = errno;
                error = -1;
        }
 -      packed_ref_cache->lock = NULL;
        release_packed_ref_cache(packed_ref_cache);
        errno = save_errno;
        return error;
@@@ -1383,9 -1379,10 +1384,9 @@@ static void rollback_packed_refs(struc
  
        files_assert_main_repository(refs, "rollback_packed_refs");
  
 -      if (!packed_ref_cache->lock)
 -              die("internal error: packed-refs not locked");
 -      rollback_lock_file(packed_ref_cache->lock);
 -      packed_ref_cache->lock = NULL;
 +      if (!is_lock_file_locked(&refs->packed_refs_lock))
 +              die("BUG: packed-refs not locked");
 +      rollback_lock_file(&refs->packed_refs_lock);
        release_packed_ref_cache(packed_ref_cache);
        clear_packed_ref_cache(refs);
  }
@@@ -1480,32 -1477,6 +1481,32 @@@ static void prune_refs(struct files_ref
        }
  }
  
 +/*
 + * Return true if the specified reference should be packed.
 + */
 +static int should_pack_ref(const char *refname,
 +                         const struct object_id *oid, unsigned int ref_flags,
 +                         unsigned int pack_flags)
 +{
 +      /* Do not pack per-worktree refs: */
 +      if (ref_type(refname) != REF_TYPE_NORMAL)
 +              return 0;
 +
 +      /* Do not pack non-tags unless PACK_REFS_ALL is set: */
 +      if (!(pack_flags & PACK_REFS_ALL) && !starts_with(refname, "refs/tags/"))
 +              return 0;
 +
 +      /* Do not pack symbolic refs: */
 +      if (ref_flags & REF_ISSYMREF)
 +              return 0;
 +
 +      /* Do not pack broken refs: */
 +      if (!ref_resolves_to_object(refname, oid, ref_flags))
 +              return 0;
 +
 +      return 1;
 +}
 +
  static int files_pack_refs(struct ref_store *ref_store, unsigned int flags)
  {
        struct files_ref_store *refs =
                 * pruned, also add it to refs_to_prune.
                 */
                struct ref_entry *packed_entry;
 -              int is_tag_ref = starts_with(iter->refname, "refs/tags/");
 -
 -              /* Do not pack per-worktree refs: */
 -              if (ref_type(iter->refname) != REF_TYPE_NORMAL)
 -                      continue;
  
 -              /* ALWAYS pack tags */
 -              if (!(flags & PACK_REFS_ALL) && !is_tag_ref)
 -                      continue;
 -
 -              /* Do not pack symbolic or broken refs: */
 -              if (iter->flags & REF_ISSYMREF)
 -                      continue;
 -
 -              if (!ref_resolves_to_object(iter->refname, iter->oid, iter->flags))
 +              if (!should_pack_ref(iter->refname, iter->oid, iter->flags,
 +                                   flags))
                        continue;
  
                /*
                        packed_entry->flag = REF_ISPACKED;
                        oidcpy(&packed_entry->u.value.oid, iter->oid);
                } else {
 -                      packed_entry = create_ref_entry(iter->refname, iter->oid->hash,
 -                                                      REF_ISPACKED, 0);
 +                      packed_entry = create_ref_entry(iter->refname, iter->oid,
 +                                                      REF_ISPACKED);
                        add_ref_entry(packed_refs, packed_entry);
                }
                oidclr(&packed_entry->u.value.peeled);
@@@ -1625,7 -1608,7 +1626,7 @@@ static int repack_without_refs(struct f
        return ret;
  }
  
 -static int files_delete_refs(struct ref_store *ref_store,
 +static int files_delete_refs(struct ref_store *ref_store, const char *msg,
                             struct string_list *refnames, unsigned int flags)
  {
        struct files_ref_store *refs =
        for (i = 0; i < refnames->nr; i++) {
                const char *refname = refnames->items[i].string;
  
 -              if (refs_delete_ref(&refs->base, NULL, refname, NULL, flags))
 +              if (refs_delete_ref(&refs->base, msg, refname, NULL, flags))
                        result |= error(_("could not remove reference %s"), refname);
        }
  
@@@ -1727,10 -1710,10 +1728,10 @@@ static int rename_tmp_log(struct files_
  }
  
  static int write_ref_to_lockfile(struct ref_lock *lock,
 -                               const unsigned char *sha1, struct strbuf *err);
 +                               const struct object_id *oid, struct strbuf *err);
  static int commit_ref_update(struct files_ref_store *refs,
                             struct ref_lock *lock,
 -                           const unsigned char *sha1, const char *logmsg,
 +                           const struct object_id *oid, const char *logmsg,
                             struct strbuf *err);
  
  static int files_rename_ref(struct ref_store *ref_store,
  {
        struct files_ref_store *refs =
                files_downcast(ref_store, REF_STORE_WRITE, "rename_ref");
 -      unsigned char sha1[20], orig_sha1[20];
 +      struct object_id oid, orig_oid;
        int flag = 0, logmoved = 0;
        struct ref_lock *lock;
        struct stat loginfo;
  
        if (!refs_resolve_ref_unsafe(&refs->base, oldrefname,
                                     RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
 -                              orig_sha1, &flag)) {
 +                              orig_oid.hash, &flag)) {
                ret = error("refname %s not found", oldrefname);
                goto out;
        }
        }
  
        if (refs_delete_ref(&refs->base, logmsg, oldrefname,
 -                          orig_sha1, REF_NODEREF)) {
 +                          orig_oid.hash, REF_NODEREF)) {
                error("unable to delete old %s", oldrefname);
                goto rollback;
        }
  
        /*
 -       * Since we are doing a shallow lookup, sha1 is not the
 -       * correct value to pass to delete_ref as old_sha1. But that
 -       * doesn't matter, because an old_sha1 check wouldn't add to
 +       * Since we are doing a shallow lookup, oid is not the
 +       * correct value to pass to delete_ref as old_oid. But that
 +       * doesn't matter, because an old_oid check wouldn't add to
         * the safety anyway; we want to delete the reference whatever
         * its current value.
         */
        if (!refs_read_ref_full(&refs->base, newrefname,
                                RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
 -                              sha1, NULL) &&
 +                              oid.hash, NULL) &&
            refs_delete_ref(&refs->base, NULL, newrefname,
                            NULL, REF_NODEREF)) {
                if (errno == EISDIR) {
                strbuf_release(&err);
                goto rollback;
        }
 -      hashcpy(lock->old_oid.hash, orig_sha1);
 +      oidcpy(&lock->old_oid, &orig_oid);
  
 -      if (write_ref_to_lockfile(lock, orig_sha1, &err) ||
 -          commit_ref_update(refs, lock, orig_sha1, logmsg, &err)) {
 +      if (write_ref_to_lockfile(lock, &orig_oid, &err) ||
 +          commit_ref_update(refs, lock, &orig_oid, logmsg, &err)) {
                error("unable to write current sha1 into %s: %s", newrefname, err.buf);
                strbuf_release(&err);
                goto rollback;
  
        flag = log_all_ref_updates;
        log_all_ref_updates = LOG_REFS_NONE;
 -      if (write_ref_to_lockfile(lock, orig_sha1, &err) ||
 -          commit_ref_update(refs, lock, orig_sha1, NULL, &err)) {
 +      if (write_ref_to_lockfile(lock, &orig_oid, &err) ||
 +          commit_ref_update(refs, lock, &orig_oid, NULL, &err)) {
                error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
                strbuf_release(&err);
        }
@@@ -2004,8 -1987,8 +2005,8 @@@ static int files_create_reflog(struct r
        return 0;
  }
  
 -static int log_ref_write_fd(int fd, const unsigned char *old_sha1,
 -                          const unsigned char *new_sha1,
 +static int log_ref_write_fd(int fd, const struct object_id *old_oid,
 +                          const struct object_id *new_oid,
                            const char *committer, const char *msg)
  {
        int msglen, written;
        maxlen = strlen(committer) + msglen + 100;
        logrec = xmalloc(maxlen);
        len = xsnprintf(logrec, maxlen, "%s %s %s\n",
 -                      sha1_to_hex(old_sha1),
 -                      sha1_to_hex(new_sha1),
 +                      oid_to_hex(old_oid),
 +                      oid_to_hex(new_oid),
                        committer);
        if (msglen)
                len += copy_reflog_msg(logrec + len - 1, msg) - 1;
  }
  
  static int files_log_ref_write(struct files_ref_store *refs,
 -                             const char *refname, const unsigned char *old_sha1,
 -                             const unsigned char *new_sha1, const char *msg,
 +                             const char *refname, const struct object_id *old_oid,
 +                             const struct object_id *new_oid, const char *msg,
                               int flags, struct strbuf *err)
  {
        int logfd, result;
  
        if (logfd < 0)
                return 0;
 -      result = log_ref_write_fd(logfd, old_sha1, new_sha1,
 +      result = log_ref_write_fd(logfd, old_oid, new_oid,
                                  git_committer_info(0), msg);
        if (result) {
                struct strbuf sb = STRBUF_INIT;
   * return -1.
   */
  static int write_ref_to_lockfile(struct ref_lock *lock,
 -                               const unsigned char *sha1, struct strbuf *err)
 +                               const struct object_id *oid, struct strbuf *err)
  {
        static char term = '\n';
        struct object *o;
        int fd;
  
 -      o = parse_object(sha1);
 +      o = parse_object(oid);
        if (!o) {
                strbuf_addf(err,
                            "trying to write ref '%s' with nonexistent object %s",
 -                          lock->ref_name, sha1_to_hex(sha1));
 +                          lock->ref_name, oid_to_hex(oid));
                unlock_ref(lock);
                return -1;
        }
        if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {
                strbuf_addf(err,
                            "trying to write non-commit object %s to branch '%s'",
 -                          sha1_to_hex(sha1), lock->ref_name);
 +                          oid_to_hex(oid), lock->ref_name);
                unlock_ref(lock);
                return -1;
        }
        fd = get_lock_file_fd(lock->lk);
 -      if (write_in_full(fd, sha1_to_hex(sha1), 40) != 40 ||
 +      if (write_in_full(fd, oid_to_hex(oid), GIT_SHA1_HEXSZ) != GIT_SHA1_HEXSZ ||
            write_in_full(fd, &term, 1) != 1 ||
            close_ref(lock) < 0) {
                strbuf_addf(err,
   */
  static int commit_ref_update(struct files_ref_store *refs,
                             struct ref_lock *lock,
 -                           const unsigned char *sha1, const char *logmsg,
 +                           const struct object_id *oid, const char *logmsg,
                             struct strbuf *err)
  {
        files_assert_main_repository(refs, "commit_ref_update");
  
        clear_loose_ref_cache(refs);
        if (files_log_ref_write(refs, lock->ref_name,
 -                              lock->old_oid.hash, sha1,
 +                              &lock->old_oid, oid,
                                logmsg, 0, err)) {
                char *old_msg = strbuf_detach(err, NULL);
                strbuf_addf(err, "cannot update the ref '%s': %s",
                 * check with HEAD only which should cover 99% of all usage
                 * scenarios (even 100% of the default ones).
                 */
 -              unsigned char head_sha1[20];
 +              struct object_id head_oid;
                int head_flag;
                const char *head_ref;
  
                head_ref = refs_resolve_ref_unsafe(&refs->base, "HEAD",
                                                   RESOLVE_REF_READING,
 -                                                 head_sha1, &head_flag);
 +                                                 head_oid.hash, &head_flag);
                if (head_ref && (head_flag & REF_ISSYMREF) &&
                    !strcmp(head_ref, lock->ref_name)) {
                        struct strbuf log_err = STRBUF_INIT;
                        if (files_log_ref_write(refs, "HEAD",
 -                                              lock->old_oid.hash, sha1,
 +                                              &lock->old_oid, oid,
                                                logmsg, 0, &log_err)) {
                                error("%s", log_err.buf);
                                strbuf_release(&log_err);
@@@ -2200,12 -2183,12 +2201,12 @@@ static void update_symref_reflog(struc
                                 const char *target, const char *logmsg)
  {
        struct strbuf err = STRBUF_INIT;
 -      unsigned char new_sha1[20];
 +      struct object_id new_oid;
        if (logmsg &&
            !refs_read_ref_full(&refs->base, target,
 -                              RESOLVE_REF_READING, new_sha1, NULL) &&
 -          files_log_ref_write(refs, refname, lock->old_oid.hash,
 -                              new_sha1, logmsg, 0, &err)) {
 +                              RESOLVE_REF_READING, new_oid.hash, NULL) &&
 +          files_log_ref_write(refs, refname, &lock->old_oid,
 +                              &new_oid, logmsg, 0, &err)) {
                error("%s", err.buf);
                strbuf_release(&err);
        }
@@@ -2258,6 -2241,50 +2259,6 @@@ static int files_create_symref(struct r
        return ret;
  }
  
 -int set_worktree_head_symref(const char *gitdir, const char *target, const char *logmsg)
 -{
 -      /*
 -       * FIXME: this obviously will not work well for future refs
 -       * backends. This function needs to die.
 -       */
 -      struct files_ref_store *refs =
 -              files_downcast(get_main_ref_store(),
 -                             REF_STORE_WRITE,
 -                             "set_head_symref");
 -
 -      static struct lock_file head_lock;
 -      struct ref_lock *lock;
 -      struct strbuf head_path = STRBUF_INIT;
 -      const char *head_rel;
 -      int ret;
 -
 -      strbuf_addf(&head_path, "%s/HEAD", absolute_path(gitdir));
 -      if (hold_lock_file_for_update(&head_lock, head_path.buf,
 -                                    LOCK_NO_DEREF) < 0) {
 -              struct strbuf err = STRBUF_INIT;
 -              unable_to_lock_message(head_path.buf, errno, &err);
 -              error("%s", err.buf);
 -              strbuf_release(&err);
 -              strbuf_release(&head_path);
 -              return -1;
 -      }
 -
 -      /* head_rel will be "HEAD" for the main tree, "worktrees/wt/HEAD" for
 -         linked trees */
 -      head_rel = remove_leading_path(head_path.buf,
 -                                     absolute_path(get_git_common_dir()));
 -      /* to make use of create_symref_locked(), initialize ref_lock */
 -      lock = xcalloc(1, sizeof(struct ref_lock));
 -      lock->lk = &head_lock;
 -      lock->ref_name = xstrdup(head_rel);
 -
 -      ret = create_symref_locked(refs, lock, head_rel, target, logmsg);
 -
 -      unlock_ref(lock); /* will free lock */
 -      strbuf_release(&head_path);
 -      return ret;
 -}
 -
  static int files_reflog_exists(struct ref_store *ref_store,
                               const char *refname)
  {
@@@ -2291,7 -2318,7 +2292,7 @@@ static int show_one_reflog_ent(struct s
  {
        struct object_id ooid, noid;
        char *email_end, *message;
 -      unsigned long timestamp;
 +      timestamp_t timestamp;
        int tz;
        const char *p = sb->buf;
  
            parse_oid_hex(p, &noid, &p) || *p++ != ' ' ||
            !(email_end = strchr(p, '>')) ||
            email_end[1] != ' ' ||
 -          !(timestamp = strtoul(email_end + 2, &message, 10)) ||
 +          !(timestamp = parse_timestamp(email_end + 2, &message, 10)) ||
            !message || message[0] != ' ' ||
            (message[1] != '+' && message[1] != '-') ||
            !isdigit(message[2]) || !isdigit(message[3]) ||
@@@ -2551,6 -2578,23 +2552,6 @@@ static struct ref_iterator *files_reflo
        return ref_iterator;
  }
  
 -static int ref_update_reject_duplicates(struct string_list *refnames,
 -                                      struct strbuf *err)
 -{
 -      int i, n = refnames->nr;
 -
 -      assert(err);
 -
 -      for (i = 1; i < n; i++)
 -              if (!strcmp(refnames->items[i - 1].string, refnames->items[i].string)) {
 -                      strbuf_addf(err,
 -                                  "multiple updates for ref '%s' not allowed.",
 -                                  refnames->items[i].string);
 -                      return 1;
 -              }
 -      return 0;
 -}
 -
  /*
   * If update is a direct update of head_ref (the reference pointed to
   * by HEAD), then add an extra REF_LOG_ONLY update for HEAD.
@@@ -2590,7 -2634,7 +2591,7 @@@ static int split_head_update(struct ref
        new_update = ref_transaction_add_update(
                        transaction, "HEAD",
                        update->flags | REF_LOG_ONLY | REF_NODEREF,
 -                      update->new_sha1, update->old_sha1,
 +                      update->new_oid.hash, update->old_oid.hash,
                        update->msg);
  
        item->util = new_update;
@@@ -2647,7 -2691,7 +2648,7 @@@ static int split_symref_update(struct f
  
        new_update = ref_transaction_add_update(
                        transaction, referent, new_flags,
 -                      update->new_sha1, update->old_sha1,
 +                      update->new_oid.hash, update->old_oid.hash,
                        update->msg);
  
        new_update->parent_update = update;
@@@ -2686,10 -2730,10 +2687,10 @@@ static int check_old_oid(struct ref_upd
                         struct strbuf *err)
  {
        if (!(update->flags & REF_HAVE_OLD) ||
 -                 !hashcmp(oid->hash, update->old_sha1))
 +                 !oidcmp(oid, &update->old_oid))
                return 0;
  
 -      if (is_null_sha1(update->old_sha1))
 +      if (is_null_oid(&update->old_oid))
                strbuf_addf(err, "cannot lock ref '%s': "
                            "reference already exists",
                            original_update_refname(update));
                strbuf_addf(err, "cannot lock ref '%s': "
                            "reference is missing but expected %s",
                            original_update_refname(update),
 -                          sha1_to_hex(update->old_sha1));
 +                          oid_to_hex(&update->old_oid));
        else
                strbuf_addf(err, "cannot lock ref '%s': "
                            "is at %s but expected %s",
                            original_update_refname(update),
                            oid_to_hex(oid),
 -                          sha1_to_hex(update->old_sha1));
 +                          oid_to_hex(&update->old_oid));
  
        return -1;
  }
@@@ -2730,13 -2774,13 +2731,13 @@@ static int lock_ref_for_update(struct f
  {
        struct strbuf referent = STRBUF_INIT;
        int mustexist = (update->flags & REF_HAVE_OLD) &&
 -              !is_null_sha1(update->old_sha1);
 +              !is_null_oid(&update->old_oid);
        int ret;
        struct ref_lock *lock;
  
        files_assert_main_repository(refs, "lock_ref_for_update");
  
 -      if ((update->flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1))
 +      if ((update->flags & REF_HAVE_NEW) && is_null_oid(&update->new_oid))
                update->flags |= REF_DELETING;
  
        if (head_ref) {
            !(update->flags & REF_DELETING) &&
            !(update->flags & REF_LOG_ONLY)) {
                if (!(update->type & REF_ISSYMREF) &&
 -                  !hashcmp(lock->old_oid.hash, update->new_sha1)) {
 +                  !oidcmp(&lock->old_oid, &update->new_oid)) {
                        /*
                         * The reference already has the desired
                         * value, so we don't need to write it.
                         */
 -              } else if (write_ref_to_lockfile(lock, update->new_sha1,
 +              } else if (write_ref_to_lockfile(lock, &update->new_oid,
                                                 err)) {
                        char *write_err = strbuf_detach(err, NULL);
  
        return 0;
  }
  
 -static int files_transaction_commit(struct ref_store *ref_store,
 -                                  struct ref_transaction *transaction,
 -                                  struct strbuf *err)
 +/*
 + * Unlock any references in `transaction` that are still locked, and
 + * mark the transaction closed.
 + */
 +static void files_transaction_cleanup(struct ref_transaction *transaction)
 +{
 +      size_t i;
 +
 +      for (i = 0; i < transaction->nr; i++) {
 +              struct ref_update *update = transaction->updates[i];
 +              struct ref_lock *lock = update->backend_data;
 +
 +              if (lock) {
 +                      unlock_ref(lock);
 +                      update->backend_data = NULL;
 +              }
 +      }
 +
 +      transaction->state = REF_TRANSACTION_CLOSED;
 +}
 +
 +static int files_transaction_prepare(struct ref_store *ref_store,
 +                                   struct ref_transaction *transaction,
 +                                   struct strbuf *err)
  {
        struct files_ref_store *refs =
                files_downcast(ref_store, REF_STORE_WRITE,
 -                             "ref_transaction_commit");
 -      int ret = 0, i;
 -      struct string_list refs_to_delete = STRING_LIST_INIT_NODUP;
 -      struct string_list_item *ref_to_delete;
 +                             "ref_transaction_prepare");
 +      size_t i;
 +      int ret = 0;
        struct string_list affected_refnames = STRING_LIST_INIT_NODUP;
        char *head_ref = NULL;
        int head_type;
        struct object_id head_oid;
 -      struct strbuf sb = STRBUF_INIT;
  
        assert(err);
  
 -      if (transaction->state != REF_TRANSACTION_OPEN)
 -              die("BUG: commit called for transaction that is not open");
 -
 -      if (!transaction->nr) {
 -              transaction->state = REF_TRANSACTION_CLOSED;
 -              return 0;
 -      }
 +      if (!transaction->nr)
 +              goto cleanup;
  
        /*
         * Fail if a refname appears more than once in the
         * that new values are valid, and write new values to the
         * lockfiles, ready to be activated. Only keep one lockfile
         * open at a time to avoid running out of file descriptors.
 +       * Note that lock_ref_for_update() might append more updates
 +       * to the transaction.
         */
        for (i = 0; i < transaction->nr; i++) {
                struct ref_update *update = transaction->updates[i];
                ret = lock_ref_for_update(refs, update, transaction,
                                          head_ref, &affected_refnames, err);
                if (ret)
 -                      goto cleanup;
 +                      break;
 +      }
 +
 +cleanup:
 +      free(head_ref);
 +      string_list_clear(&affected_refnames, 0);
 +
 +      if (ret)
 +              files_transaction_cleanup(transaction);
 +      else
 +              transaction->state = REF_TRANSACTION_PREPARED;
 +
 +      return ret;
 +}
 +
 +static int files_transaction_finish(struct ref_store *ref_store,
 +                                  struct ref_transaction *transaction,
 +                                  struct strbuf *err)
 +{
 +      struct files_ref_store *refs =
 +              files_downcast(ref_store, 0, "ref_transaction_finish");
 +      size_t i;
 +      int ret = 0;
 +      struct string_list refs_to_delete = STRING_LIST_INIT_NODUP;
 +      struct string_list_item *ref_to_delete;
 +      struct strbuf sb = STRBUF_INIT;
 +
 +      assert(err);
 +
 +      if (!transaction->nr) {
 +              transaction->state = REF_TRANSACTION_CLOSED;
 +              return 0;
        }
  
        /* Perform updates first so live commits remain referenced */
                    update->flags & REF_LOG_ONLY) {
                        if (files_log_ref_write(refs,
                                                lock->ref_name,
 -                                              lock->old_oid.hash,
 -                                              update->new_sha1,
 +                                              &lock->old_oid,
 +                                              &update->new_oid,
                                                update->msg, update->flags,
                                                err)) {
                                char *old_msg = strbuf_detach(err, NULL);
        clear_loose_ref_cache(refs);
  
  cleanup:
 -      strbuf_release(&sb);
 -      transaction->state = REF_TRANSACTION_CLOSED;
 +      files_transaction_cleanup(transaction);
  
        for (i = 0; i < transaction->nr; i++) {
                struct ref_update *update = transaction->updates[i];
 -              struct ref_lock *lock = update->backend_data;
 -
 -              if (lock)
 -                      unlock_ref(lock);
  
                if (update->flags & REF_DELETED_LOOSE) {
                        /*
                }
        }
  
 +      strbuf_release(&sb);
        string_list_clear(&refs_to_delete, 0);
 -      free(head_ref);
 -      string_list_clear(&affected_refnames, 0);
 -
        return ret;
  }
  
 +static int files_transaction_abort(struct ref_store *ref_store,
 +                                 struct ref_transaction *transaction,
 +                                 struct strbuf *err)
 +{
 +      files_transaction_cleanup(transaction);
 +      return 0;
 +}
 +
  static int ref_present(const char *refname,
                       const struct object_id *oid, int flags, void *cb_data)
  {
@@@ -3118,8 -3114,7 +3119,8 @@@ static int files_initial_transaction_co
        struct files_ref_store *refs =
                files_downcast(ref_store, REF_STORE_WRITE,
                               "initial_ref_transaction_commit");
 -      int ret = 0, i;
 +      size_t i;
 +      int ret = 0;
        struct string_list affected_refnames = STRING_LIST_INIT_NODUP;
  
        assert(err);
                struct ref_update *update = transaction->updates[i];
  
                if ((update->flags & REF_HAVE_OLD) &&
 -                  !is_null_sha1(update->old_sha1))
 +                  !is_null_oid(&update->old_oid))
                        die("BUG: initial ref transaction with old_sha1 set");
                if (refs_verify_refname_available(&refs->base, update->refname,
                                                  &affected_refnames, NULL,
                struct ref_update *update = transaction->updates[i];
  
                if ((update->flags & REF_HAVE_NEW) &&
 -                  !is_null_sha1(update->new_sha1))
 -                      add_packed_ref(refs, update->refname, update->new_sha1);
 +                  !is_null_oid(&update->new_oid))
 +                      add_packed_ref(refs, update->refname,
 +                                     &update->new_oid);
        }
  
        if (commit_packed_refs(refs)) {
@@@ -3205,7 -3199,7 +3206,7 @@@ struct expire_reflog_cb 
  };
  
  static int expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
 -                           const char *email, unsigned long timestamp, int tz,
 +                           const char *email, timestamp_t timestamp, int tz,
                             const char *message, void *cb_data)
  {
        struct expire_reflog_cb *cb = cb_data;
        if (cb->flags & EXPIRE_REFLOGS_REWRITE)
                ooid = &cb->last_kept_oid;
  
 -      if ((*cb->should_prune_fn)(ooid->hash, noid->hash, email, timestamp, tz,
 +      if ((*cb->should_prune_fn)(ooid, noid, email, timestamp, tz,
                                   message, policy_cb)) {
                if (!cb->newlog)
                        printf("would prune %s", message);
                        printf("prune %s", message);
        } else {
                if (cb->newlog) {
 -                      fprintf(cb->newlog, "%s %s %s %lu %+05d\t%s",
 +                      fprintf(cb->newlog, "%s %s %s %"PRItime" %+05d\t%s",
                                oid_to_hex(ooid), oid_to_hex(noid),
                                email, timestamp, tz, message);
                        oidcpy(&cb->last_kept_oid, noid);
@@@ -3251,7 -3245,6 +3252,7 @@@ static int files_reflog_expire(struct r
        int status = 0;
        int type;
        struct strbuf err = STRBUF_INIT;
 +      struct object_id oid;
  
        memset(&cb, 0, sizeof(cb));
        cb.flags = flags;
                }
        }
  
 -      (*prepare_fn)(refname, sha1, cb.policy_cb);
 +      hashcpy(oid.hash, sha1);
 +
 +      (*prepare_fn)(refname, &oid, cb.policy_cb);
        refs_for_each_reflog_ent(ref_store, refname, expire_reflog_ent, &cb);
        (*cleanup_fn)(cb.policy_cb);
  
@@@ -3373,9 -3364,7 +3374,9 @@@ struct ref_storage_be refs_be_files = 
        "files",
        files_ref_store_create,
        files_init_db,
 -      files_transaction_commit,
 +      files_transaction_prepare,
 +      files_transaction_finish,
 +      files_transaction_abort,
        files_initial_transaction_commit,
  
        files_pack_refs,
diff --combined remote.c
index f998f989e92a6eb919828c72d444f091d5fdfa6a,6ef03bb73066067fce9878e237c774da7c0ad14e..d87482573d38b057257c08024fbe6b4339661481
+++ b/remote.c
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "remote.h"
  #include "refs.h"
  #include "commit.h"
@@@ -251,7 -252,7 +252,7 @@@ static const char *skip_spaces(const ch
  static void read_remotes_file(struct remote *remote)
  {
        struct strbuf buf = STRBUF_INIT;
 -      FILE *f = fopen(git_path("remotes/%s", remote->name), "r");
 +      FILE *f = fopen_or_warn(git_path("remotes/%s", remote->name), "r");
  
        if (!f)
                return;
@@@ -277,7 -278,7 +278,7 @@@ static void read_branches_file(struct r
  {
        char *frag;
        struct strbuf buf = STRBUF_INIT;
 -      FILE *f = fopen(git_path("branches/%s", remote->name), "r");
 +      FILE *f = fopen_or_warn(git_path("branches/%s", remote->name), "r");
  
        if (!f)
                return;
@@@ -477,6 -478,26 +478,6 @@@ static void read_config(void
        alias_all_urls();
  }
  
 -/*
 - * This function frees a refspec array.
 - * Warning: code paths should be checked to ensure that the src
 - *          and dst pointers are always freeable pointers as well
 - *          as the refspec pointer itself.
 - */
 -static void free_refspecs(struct refspec *refspec, int nr_refspec)
 -{
 -      int i;
 -
 -      if (!refspec)
 -              return;
 -
 -      for (i = 0; i < nr_refspec; i++) {
 -              free(refspec[i].src);
 -              free(refspec[i].dst);
 -      }
 -      free(refspec);
 -}
 -
  static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
  {
        int i;
                 * since it is only possible to reach this point from within
                 * the for loop above.
                 */
 -              free_refspecs(rs, i+1);
 +              free_refspec(i+1, rs);
                return NULL;
        }
        die("Invalid refspec '%s'", refspec[i]);
@@@ -601,7 -622,7 +602,7 @@@ int valid_fetch_refspec(const char *fet
        struct refspec *refspec;
  
        refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
 -      free_refspecs(refspec, 1);
 +      free_refspec(1, refspec);
        return !!refspec;
  }
  
@@@ -618,10 -639,6 +619,10 @@@ struct refspec *parse_push_refspec(int 
  void free_refspec(int nr_refspec, struct refspec *refspec)
  {
        int i;
 +
 +      if (!refspec)
 +              return;
 +
        for (i = 0; i < nr_refspec; i++) {
                free(refspec[i].src);
                free(refspec[i].dst);
@@@ -633,12 -650,7 +634,12 @@@ static int valid_remote_nick(const cha
  {
        if (!name[0] || is_dot_or_dotdot(name))
                return 0;
 -      return !strchr(name, '/'); /* no slash */
 +
 +      /* remote nicknames cannot contain slashes */
 +      while (*name)
 +              if (is_dir_sep(*name++))
 +                      return 0;
 +      return 1;
  }
  
  const char *remote_for_branch(struct branch *branch, int *explicit)
@@@ -1180,10 -1192,9 +1181,10 @@@ static int match_explicit(struct ref *s
                else if (is_null_oid(&matched_src->new_oid))
                        error("unable to delete '%s': remote ref does not exist",
                              dst_value);
 -              else if ((dst_guess = guess_ref(dst_value, matched_src)))
 +              else if ((dst_guess = guess_ref(dst_value, matched_src))) {
                        matched_dst = make_linked_ref(dst_guess, dst_tail);
 -              else
 +                      free(dst_guess);
 +              } else
                        error("unable to push to unqualified destination: %s\n"
                              "The destination refspec neither matches an "
                              "existing ref on the remote nor\n"
@@@ -1286,7 -1297,7 +1287,7 @@@ static void add_to_tips(struct tips *ti
  
        if (is_null_oid(oid))
                return;
 -      commit = lookup_commit_reference_gently(oid->hash, 1);
 +      commit = lookup_commit_reference_gently(oid, 1);
        if (!commit || (commit->object.flags & TMP_MARK))
                return;
        commit->object.flags |= TMP_MARK;
@@@ -1348,8 -1359,7 +1349,8 @@@ static void add_missing_tags(struct re
  
                        if (is_null_oid(&ref->new_oid))
                                continue;
 -                      commit = lookup_commit_reference_gently(ref->new_oid.hash, 1);
 +                      commit = lookup_commit_reference_gently(&ref->new_oid,
 +                                                              1);
                        if (!commit)
                                /* not pushing a commit, which is not an error */
                                continue;
@@@ -1576,8 -1586,8 +1577,8 @@@ void set_ref_status_for_push(struct re
                                reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS;
                        else if (!has_object_file(&ref->old_oid))
                                reject_reason = REF_STATUS_REJECT_FETCH_FIRST;
 -                      else if (!lookup_commit_reference_gently(ref->old_oid.hash, 1) ||
 -                               !lookup_commit_reference_gently(ref->new_oid.hash, 1))
 +                      else if (!lookup_commit_reference_gently(&ref->old_oid, 1) ||
 +                               !lookup_commit_reference_gently(&ref->new_oid, 1))
                                reject_reason = REF_STATUS_REJECT_NEEDS_FORCE;
                        else if (!ref_newer(&ref->new_oid, &ref->old_oid))
                                reject_reason = REF_STATUS_REJECT_NONFASTFORWARD;
@@@ -1944,12 -1954,12 +1945,12 @@@ int ref_newer(const struct object_id *n
         * Both new and old must be commit-ish and new is descendant of
         * old.  Otherwise we require --force.
         */
 -      o = deref_tag(parse_object(old_oid->hash), NULL, 0);
 +      o = deref_tag(parse_object(old_oid), NULL, 0);
        if (!o || o->type != OBJ_COMMIT)
                return 0;
        old = (struct commit *) o;
  
 -      o = deref_tag(parse_object(new_oid->hash), NULL, 0);
 +      o = deref_tag(parse_object(new_oid), NULL, 0);
        if (!o || o->type != OBJ_COMMIT)
                return 0;
        new = (struct commit *) o;
@@@ -2000,13 -2010,13 +2001,13 @@@ int stat_tracking_info(struct branch *b
        /* Cannot stat if what we used to build on no longer exists */
        if (read_ref(base, oid.hash))
                return -1;
 -      theirs = lookup_commit_reference(oid.hash);
 +      theirs = lookup_commit_reference(&oid);
        if (!theirs)
                return -1;
  
        if (read_ref(branch->refname, oid.hash))
                return -1;
 -      ours = lookup_commit_reference(oid.hash);
 +      ours = lookup_commit_reference(&oid);
        if (!ours)
                return -1;
  
diff --combined rerere.c
index c26c29f87a6f35d2efffd226fa8922f36cd0bb37,344d6aa818eacf65a4ce7fbfdc380bc02cea2df9..829b3b0f08f7546c168e2728687d5729c4607cfa
+++ b/rerere.c
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "string-list.h"
  #include "rerere.h"
@@@ -200,7 -201,7 +201,7 @@@ static struct rerere_id *new_rerere_id(
  static void read_rr(struct string_list *rr)
  {
        struct strbuf buf = STRBUF_INIT;
 -      FILE *in = fopen(git_path_merge_rr(), "r");
 +      FILE *in = fopen_or_warn(git_path_merge_rr(), "r");
  
        if (!in)
                return;
@@@ -484,14 -485,13 +485,14 @@@ static int handle_file(const char *path
        io.input = fopen(path, "r");
        io.io.wrerror = 0;
        if (!io.input)
 -              return error("Could not open %s", path);
 +              return error_errno("Could not open %s", path);
  
        if (output) {
                io.io.output = fopen(output, "w");
                if (!io.io.output) {
 +                      error_errno("Could not write %s", output);
                        fclose(io.input);
 -                      return error("Could not write %s", output);
 +                      return -1;
                }
        }
  
diff --combined sequencer.c
index d63099d50fc4e23cb3585b12c61ba8863d2688f6,7356a935622427c9721cb067d1cab9e179749ee7..224afe79b96c89a70a36db85aa6c61826b2ebec1
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "lockfile.h"
  #include "sequencer.h"
  #include "dir.h"
@@@ -344,7 -345,7 +345,7 @@@ static int read_oneliner(struct strbuf 
  
  static struct tree *empty_tree(void)
  {
 -      return lookup_tree(EMPTY_TREE_SHA1_BIN);
 +      return lookup_tree(&empty_tree_oid);
  }
  
  static int error_dirty_index(struct replay_opts *opts)
@@@ -374,7 -375,7 +375,7 @@@ static void update_abort_safety_file(vo
                write_file(git_path_abort_safety_file(), "%s", "");
  }
  
 -static int fast_forward_to(const unsigned char *to, const unsigned char *from,
 +static int fast_forward_to(const struct object_id *to, const struct object_id *from,
                        int unborn, struct replay_opts *opts)
  {
        struct ref_transaction *transaction;
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_update(transaction, "HEAD",
 -                                 to, unborn ? null_sha1 : from,
 +                                 to->hash, unborn ? null_sha1 : from->hash,
                                   0, sb.buf, &err) ||
            ref_transaction_commit(transaction, &err)) {
                ref_transaction_free(transaction);
@@@ -426,7 -427,7 +427,7 @@@ void append_conflicts_hint(struct strbu
  
  static int do_recursive_merge(struct commit *base, struct commit *next,
                              const char *base_label, const char *next_label,
 -                            unsigned char *head, struct strbuf *msgbuf,
 +                            struct object_id *head, struct strbuf *msgbuf,
                              struct replay_opts *opts)
  {
        struct merge_options o;
  
        if (active_cache_changed &&
            write_locked_index(&the_index, &index_lock, COMMIT_LOCK))
 -              /* TRANSLATORS: %s will be "revert", "cherry-pick" or
 +              /*
 +               * TRANSLATORS: %s will be "revert", "cherry-pick" or
                 * "rebase -i".
                 */
                return error(_("%s: Unable to write new index file"),
  
  static int is_index_unchanged(void)
  {
 -      unsigned char head_sha1[20];
 +      struct object_id head_oid;
        struct commit *head_commit;
  
 -      if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL))
 +      if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
                return error(_("could not resolve HEAD commit\n"));
  
 -      head_commit = lookup_commit(head_sha1);
 +      head_commit = lookup_commit(&head_oid);
  
        /*
         * If head_commit is NULL, check_commit, called from
                if (cache_tree_update(&the_index, 0))
                        return error(_("unable to update cache tree\n"));
  
 -      return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);
 +      return !oidcmp(&active_cache_tree->oid,
 +                     &head_commit->tree->object.oid);
  }
  
  static int write_author_script(const char *message)
@@@ -836,13 -835,13 +837,13 @@@ static int update_squash_messages(enum 
                strbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);
                strbuf_release(&header);
        } else {
 -              unsigned char head[20];
 +              struct object_id head;
                struct commit *head_commit;
                const char *head_message, *body;
  
 -              if (get_sha1("HEAD", head))
 +              if (get_oid("HEAD", &head))
                        return error(_("need a HEAD to fixup"));
 -              if (!(head_commit = lookup_commit_reference(head)))
 +              if (!(head_commit = lookup_commit_reference(&head)))
                        return error(_("could not read HEAD"));
                if (!(head_message = get_commit_buffer(head_commit, NULL)))
                        return error(_("could not read HEAD's commit message"));
@@@ -899,8 -898,8 +900,8 @@@ static void flush_rewritten_pending(voi
        FILE *out;
  
        if (strbuf_read_file(&buf, rebase_path_rewritten_pending(), 82) > 0 &&
 -                      !get_sha1("HEAD", newsha1) &&
 -                      (out = fopen(rebase_path_rewritten_list(), "a"))) {
 +          !get_sha1("HEAD", newsha1) &&
 +          (out = fopen_or_warn(rebase_path_rewritten_list(), "a"))) {
                char *bol = buf.buf, *eol;
  
                while (*bol) {
  
  static void record_in_rewritten(struct object_id *oid,
                enum todo_command next_command) {
 -      FILE *out = fopen(rebase_path_rewritten_pending(), "a");
 +      FILE *out = fopen_or_warn(rebase_path_rewritten_pending(), "a");
  
        if (!out)
                return;
@@@ -936,7 -935,7 +937,7 @@@ static int do_pick_commit(enum todo_com
  {
        unsigned int flags = opts->edit ? EDIT_MSG : 0;
        const char *msg_file = opts->edit ? NULL : git_path_merge_msg();
 -      unsigned char head[20];
 +      struct object_id head;
        struct commit *base, *next, *parent;
        const char *base_label, *next_label;
        struct commit_message msg = { NULL, NULL, NULL, NULL };
                 * that represents the "current" state for merge-recursive
                 * to work on.
                 */
 -              if (write_cache_as_tree(head, 0, NULL))
 +              if (write_cache_as_tree(head.hash, 0, NULL))
                        return error(_("your index file is unmerged."));
        } else {
 -              unborn = get_sha1("HEAD", head);
 +              unborn = get_oid("HEAD", &head);
                if (unborn)
 -                      hashcpy(head, EMPTY_TREE_SHA1_BIN);
 +                      oidcpy(&head, &empty_tree_oid);
                if (index_differs_from(unborn ? EMPTY_TREE_SHA1_HEX : "HEAD", 0, 0))
                        return error_dirty_index(opts);
        }
                        oid_to_hex(&commit->object.oid));
  
        if (opts->allow_ff && !is_fixup(command) &&
 -          ((parent && !hashcmp(parent->object.oid.hash, head)) ||
 +          ((parent && !oidcmp(&parent->object.oid, &head)) ||
             (!parent && unborn))) {
                if (is_rebase_i(opts))
                        write_author_script(msg.message);
 -              res = fast_forward_to(commit->object.oid.hash, head, unborn,
 +              res = fast_forward_to(&commit->object.oid, &head, unborn,
                        opts);
                if (res || command != TODO_REWORD)
                        goto leave;
                        strbuf_addstr(&msgbuf, p);
  
                if (opts->record_origin) {
 +                      strbuf_complete_line(&msgbuf);
                        if (!has_conforming_footer(&msgbuf, NULL, 0))
                                strbuf_addch(&msgbuf, '\n');
                        strbuf_addstr(&msgbuf, cherry_picked_prefix);
                res = -1;
        else if (!opts->strategy || !strcmp(opts->strategy, "recursive") || command == TODO_REVERT) {
                res = do_recursive_merge(base, next, base_label, next_label,
 -                                       head, &msgbuf, opts);
 +                                       &head, &msgbuf, opts);
                if (res < 0)
                        return res;
                res |= write_message(msgbuf.buf, msgbuf.len,
                commit_list_insert(next, &remotes);
                res |= try_merge_command(opts->strategy,
                                         opts->xopts_nr, (const char **)opts->xopts,
 -                                      common, sha1_to_hex(head), remotes);
 +                                      common, oid_to_hex(&head), remotes);
                free_commit_list(common);
                free_commit_list(remotes);
        }
@@@ -1224,7 -1222,7 +1225,7 @@@ static struct todo_item *append_new_tod
  
  static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
  {
 -      unsigned char commit_sha1[20];
 +      struct object_id commit_oid;
        char *end_of_object_name;
        int i, saved, status, padding;
  
        end_of_object_name = (char *) bol + strcspn(bol, " \t\n");
        saved = *end_of_object_name;
        *end_of_object_name = '\0';
 -      status = get_sha1(bol, commit_sha1);
 +      status = get_oid(bol, &commit_oid);
        *end_of_object_name = saved;
  
        item->arg = end_of_object_name + strspn(end_of_object_name, " \t");
        if (status < 0)
                return -1;
  
 -      item->commit = lookup_commit_reference(commit_sha1);
 +      item->commit = lookup_commit_reference(&commit_oid);
        return !item->commit;
  }
  
@@@ -1381,7 -1379,7 +1382,7 @@@ static int read_populate_todo(struct to
  
        if (is_rebase_i(opts)) {
                struct todo_list done = TODO_LIST_INIT;
 -              FILE *f = fopen(rebase_path_msgtotal(), "w");
 +              FILE *f = fopen_or_warn(rebase_path_msgtotal(), "w");
  
                if (strbuf_read_file(&done.buf, rebase_path_done(), 0) > 0 &&
                                !parse_insn_buffer(done.buf.buf, &done))
@@@ -1916,13 -1914,11 +1917,13 @@@ static int apply_autostash(struct repla
        strbuf_trim(&stash_sha1);
  
        child.git_cmd = 1;
 +      child.no_stdout = 1;
 +      child.no_stderr = 1;
        argv_array_push(&child.args, "stash");
        argv_array_push(&child.args, "apply");
        argv_array_push(&child.args, stash_sha1.buf);
        if (!run_command(&child))
 -              printf(_("Applied autostash."));
 +              printf(_("Applied autostash.\n"));
        else {
                struct child_process store = CHILD_PROCESS_INIT;
  
@@@ -2093,7 -2089,6 +2094,7 @@@ cleanup_head_ref
                                res = error(_("could not read orig-head"));
                                goto cleanup_head_ref;
                        }
 +                      strbuf_reset(&buf);
                        if (!read_oneliner(&buf, rebase_path_onto(), 0)) {
                                res = error(_("could not read 'onto'"));
                                goto cleanup_head_ref;
                        if (read_oneliner(&buf, rebase_path_orig_head(), 0) &&
                            !get_sha1(buf.buf, orig.hash) &&
                            !get_sha1("HEAD", head.hash)) {
 -                              diff_tree_sha1(orig.hash, head.hash,
 -                                             "", &log_tree_opt.diffopt);
 +                              diff_tree_oid(&orig, &head, "",
 +                                            &log_tree_opt.diffopt);
                                log_tree_diff_flush(&log_tree_opt);
                        }
                }
@@@ -2286,7 -2281,7 +2287,7 @@@ static int single_pick(struct commit *c
  int sequencer_pick_revisions(struct replay_opts *opts)
  {
        struct todo_list todo_list = TODO_LIST_INIT;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        int i, res;
  
        assert(opts->revs);
                return -1;
  
        for (i = 0; i < opts->revs->pending.nr; i++) {
 -              unsigned char sha1[20];
 +              struct object_id oid;
                const char *name = opts->revs->pending.objects[i].name;
  
                /* This happens when using --stdin. */
                if (!strlen(name))
                        continue;
  
 -              if (!get_sha1(name, sha1)) {
 -                      if (!lookup_commit_reference_gently(sha1, 1)) {
 -                              enum object_type type = sha1_object_info(sha1, NULL);
 +              if (!get_oid(name, &oid)) {
 +                      if (!lookup_commit_reference_gently(&oid, 1)) {
 +                              enum object_type type = sha1_object_info(oid.hash, NULL);
                                return error(_("%s: can't cherry-pick a %s"),
                                        name, typename(type));
                        }
        if (walk_revs_populate_todo(&todo_list, opts) ||
                        create_seq_dir() < 0)
                return -1;
 -      if (get_sha1("HEAD", sha1) && (opts->action == REPLAY_REVERT))
 +      if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
                return error(_("can't revert as initial commit"));
 -      if (save_head(sha1_to_hex(sha1)))
 +      if (save_head(oid_to_hex(&oid)))
                return -1;
        if (save_opts(opts))
                return -1;
@@@ -2363,9 -2358,6 +2364,9 @@@ void append_signoff(struct strbuf *msgb
                                getenv("GIT_COMMITTER_EMAIL")));
        strbuf_addch(&sob, '\n');
  
 +      if (!ignore_footer)
 +              strbuf_complete_line(msgbuf);
 +
        /*
         * If the whole message buffer is equal to the sob, pretend that we
         * found a conforming footer with a matching sob
                         * the title and body to be filled in by the user.
                         */
                        append_newlines = "\n\n";
 -              } else if (msgbuf->buf[len - 1] != '\n') {
 -                      /*
 -                       * Incomplete line.  Complete the line and add a
 -                       * blank one so that there is an empty line between
 -                       * the message body and the sob.
 -                       */
 -                      append_newlines = "\n\n";
                } else if (len == 1) {
                        /*
                         * Buffer contains a single newline.  Add another
diff --combined setup.c
index ae3e0ddda22d9b517485a5c91b8d191c3e9ef92e,4e38cf2a4f3782b92d92adf34a9ea83963bff339..358fbc2e5301d9412b55463065b912b5708c3ceb
+++ b/setup.c
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "dir.h"
  #include "string-list.h"
  
@@@ -134,27 -135,23 +135,27 @@@ int path_inside_repo(const char *prefix
  
  int check_filename(const char *prefix, const char *arg)
  {
 -      const char *name;
        char *to_free = NULL;
        struct stat st;
  
 -      if (starts_with(arg, ":/")) {
 -              if (arg[2] == '\0') /* ":/" is root dir, always exists */
 +      if (skip_prefix(arg, ":/", &arg)) {
 +              if (!*arg) /* ":/" is root dir, always exists */
                        return 1;
 -              name = arg + 2;
 -      } else if (prefix)
 -              name = to_free = prefix_filename(prefix, arg);
 -      else
 -              name = arg;
 -      if (!lstat(name, &st)) {
 +              prefix = NULL;
 +      } else if (skip_prefix(arg, ":!", &arg) ||
 +                 skip_prefix(arg, ":^", &arg)) {
 +              if (!*arg) /* excluding everything is silly, but allowed */
 +                      return 1;
 +      }
 +
 +      if (prefix)
 +              arg = to_free = prefix_filename(prefix, arg);
 +
 +      if (!lstat(arg, &st)) {
                free(to_free);
                return 1; /* file exists */
        }
 -      if (errno == ENOENT || errno == ENOTDIR) {
 +      if (is_missing_file_error(errno)) {
                free(to_free);
                return 0; /* file does not exist */
        }
@@@ -185,24 -182,6 +186,24 @@@ static void NORETURN die_verify_filenam
  
  }
  
 +/*
 + * Check for arguments that don't resolve as actual files,
 + * but which look sufficiently like pathspecs that we'll consider
 + * them such for the purposes of rev/pathspec DWIM parsing.
 + */
 +static int looks_like_pathspec(const char *arg)
 +{
 +      /* anything with a wildcard character */
 +      if (!no_wildcard(arg))
 +              return 1;
 +
 +      /* long-form pathspec magic */
 +      if (starts_with(arg, ":("))
 +              return 1;
 +
 +      return 0;
 +}
 +
  /*
   * Verify a filename that we got as an argument for a pathspec
   * entry. Note that a filename that begins with "-" never verifies
@@@ -229,7 -208,7 +230,7 @@@ void verify_filename(const char *prefix
  {
        if (*arg == '-')
                die("bad flag '%s' used after filename", arg);
 -      if (check_filename(prefix, arg) || !no_wildcard(arg))
 +      if (looks_like_pathspec(arg) || check_filename(prefix, arg))
                return;
        die_verify_filename(prefix, arg, diagnose_misspelt_rev);
  }
@@@ -725,16 -704,11 +726,16 @@@ static const char *setup_discovered_git
  
        /* --work-tree is set without --git-dir; use discovered one */
        if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
 +              char *to_free = NULL;
 +              const char *ret;
 +
                if (offset != cwd->len && !is_absolute_path(gitdir))
 -                      gitdir = real_pathdup(gitdir, 1);
 +                      gitdir = to_free = real_pathdup(gitdir, 1);
                if (chdir(cwd->buf))
                        die_errno("Could not come back to cwd");
 -              return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
 +              ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok);
 +              free(to_free);
 +              return ret;
        }
  
        /* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
@@@ -775,7 -749,7 +776,7 @@@ static const char *setup_bare_git_dir(s
  
        /* --work-tree is set without --git-dir; use discovered one */
        if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
 -              const char *gitdir;
 +              static const char *gitdir;
  
                gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
                if (chdir(cwd->buf))
@@@ -967,19 -941,21 +968,21 @@@ static enum discovery_result setup_git_
        }
  }
  
- const char *discover_git_directory(struct strbuf *gitdir)
+ int discover_git_directory(struct strbuf *commondir,
+                          struct strbuf *gitdir)
  {
        struct strbuf dir = STRBUF_INIT, err = STRBUF_INIT;
        size_t gitdir_offset = gitdir->len, cwd_len;
+       size_t commondir_offset = commondir->len;
        struct repository_format candidate;
  
        if (strbuf_getcwd(&dir))
-               return NULL;
+               return -1;
  
        cwd_len = dir.len;
        if (setup_git_directory_gently_1(&dir, gitdir, 0) <= 0) {
                strbuf_release(&dir);
-               return NULL;
+               return -1;
        }
  
        /*
                strbuf_insert(gitdir, gitdir_offset, dir.buf, dir.len);
        }
  
+       get_common_dir(commondir, gitdir->buf + gitdir_offset);
        strbuf_reset(&dir);
-       strbuf_addf(&dir, "%s/config", gitdir->buf + gitdir_offset);
+       strbuf_addf(&dir, "%s/config", commondir->buf + commondir_offset);
        read_repository_format(&candidate, dir.buf);
        strbuf_release(&dir);
  
                warning("ignoring git dir '%s': %s",
                        gitdir->buf + gitdir_offset, err.buf);
                strbuf_release(&err);
+               strbuf_setlen(commondir, commondir_offset);
                strbuf_setlen(gitdir, gitdir_offset);
-               return NULL;
+               return -1;
        }
  
-       return gitdir->buf + gitdir_offset;
+       return 0;
  }
  
  const char *setup_git_directory_gently(int *nongit_ok)
diff --combined sha1_file.c
index feb227a8377cd3ca5fb524fd04ebccb713dede4b,44561e0b92c0008653ed3d8da97336b98617cf37..a900b280428fa4931b1a60a9ac788edaff89634e
@@@ -7,6 -7,7 +7,7 @@@
   * creation etc.
   */
  #include "cache.h"
+ #include "config.h"
  #include "string-list.h"
  #include "lockfile.h"
  #include "delta.h"
@@@ -3546,7 -3547,7 +3547,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 -3581,7 +3581,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 -3669,7 +3669,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
diff --combined sha1_name.c
index 5126853bb5bda5f291039588db96064ffbd1ee5c,7e1e86c97aeceacec7fe9b1e29be8a3e5fb3d69a..d2d732c19b62dd13c27852fcbf2385b29dd58b1d
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "tag.h"
  #include "commit.h"
  #include "tree.h"
@@@ -241,7 -242,7 +242,7 @@@ static int disambiguate_committish_only
                return 0;
  
        /* We need to do this the hard way... */
 -      obj = deref_tag(parse_object(oid->hash), NULL, 0);
 +      obj = deref_tag(parse_object(oid), NULL, 0);
        if (obj && obj->type == OBJ_COMMIT)
                return 1;
        return 0;
@@@ -265,7 -266,7 +266,7 @@@ static int disambiguate_treeish_only(co
                return 0;
  
        /* We need to do this the hard way... */
 -      obj = deref_tag(parse_object(oid->hash), NULL, 0);
 +      obj = deref_tag(parse_object(oid), NULL, 0);
        if (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT))
                return 1;
        return 0;
@@@ -354,14 -355,14 +355,14 @@@ static int show_ambiguous_object(const 
  
        type = sha1_object_info(oid->hash, NULL);
        if (type == OBJ_COMMIT) {
 -              struct commit *commit = lookup_commit(oid->hash);
 +              struct commit *commit = lookup_commit(oid);
                if (commit) {
                        struct pretty_print_context pp = {0};
                        pp.date_mode.type = DATE_SHORT;
                        format_commit_message(commit, " %ad - %s", &desc, &pp);
                }
        } else if (type == OBJ_TAG) {
 -              struct tag *tag = lookup_tag(oid->hash);
 +              struct tag *tag = lookup_tag(oid);
                if (!parse_tag(tag) && tag->tag)
                        strbuf_addf(&desc, " %s", tag->tag);
        }
@@@ -660,8 -661,8 +661,8 @@@ static int get_sha1_basic(const char *s
  
        if (reflog_len) {
                int nth, i;
 -              unsigned long at_time;
 -              unsigned long co_time;
 +              timestamp_t at_time;
 +              timestamp_t co_time;
                int co_tz, co_cnt;
  
                /* Is it asking for N-th entry, or approxidate? */
  static int get_parent(const char *name, int len,
                      unsigned char *result, int idx)
  {
 -      unsigned char sha1[20];
 -      int ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH);
 +      struct object_id oid;
 +      int ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH);
        struct commit *commit;
        struct commit_list *p;
  
        if (ret)
                return ret;
 -      commit = lookup_commit_reference(sha1);
 +      commit = lookup_commit_reference(&oid);
        if (parse_commit(commit))
                return -1;
        if (!idx) {
  static int get_nth_ancestor(const char *name, int len,
                            unsigned char *result, int generation)
  {
 -      unsigned char sha1[20];
 +      struct object_id oid;
        struct commit *commit;
        int ret;
  
 -      ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH);
 +      ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH);
        if (ret)
                return ret;
 -      commit = lookup_commit_reference(sha1);
 +      commit = lookup_commit_reference(&oid);
        if (!commit)
                return -1;
  
@@@ -776,7 -777,7 +777,7 @@@ struct object *peel_to_type(const char 
        if (name && !namelen)
                namelen = strlen(name);
        while (1) {
 -              if (!o || (!o->parsed && !parse_object(o->oid.hash)))
 +              if (!o || (!o->parsed && !parse_object(&o->oid)))
                        return NULL;
                if (expected_type == OBJ_ANY || o->type == expected_type)
                        return o;
  static int peel_onion(const char *name, int len, unsigned char *sha1,
                      unsigned lookup_flags)
  {
 -      unsigned char outer[20];
 +      struct object_id outer;
        const char *sp;
        unsigned int expected_type = 0;
        struct object *o;
        else if (expected_type == OBJ_TREE)
                lookup_flags |= GET_SHA1_TREEISH;
  
 -      if (get_sha1_1(name, sp - name - 2, outer, lookup_flags))
 +      if (get_sha1_1(name, sp - name - 2, outer.hash, lookup_flags))
                return -1;
  
 -      o = parse_object(outer);
 +      o = parse_object(&outer);
        if (!o)
                return -1;
        if (!expected_type) {
                o = deref_tag(o, name, sp - name - 2);
 -              if (!o || (!o->parsed && !parse_object(o->oid.hash)))
 +              if (!o || (!o->parsed && !parse_object(&o->oid)))
                        return -1;
                hashcpy(sha1, o->oid.hash);
                return 0;
@@@ -981,7 -982,7 +982,7 @@@ static int handle_one_ref(const char *p
                          int flag, void *cb_data)
  {
        struct commit_list **list = cb_data;
 -      struct object *object = parse_object(oid->hash);
 +      struct object *object = parse_object(oid);
        if (!object)
                return 0;
        if (object->type == OBJ_TAG) {
@@@ -1027,7 -1028,7 +1028,7 @@@ static int get_sha1_oneline(const char 
                int matches;
  
                commit = pop_most_recent_commit(&list, ONELINE_SEEN);
 -              if (!parse_object(commit->object.oid.hash))
 +              if (!parse_object(&commit->object.oid))
                        continue;
                buf = get_commit_buffer(commit, NULL);
                p = strstr(buf, "\n\n");
@@@ -1054,7 -1055,7 +1055,7 @@@ struct grab_nth_branch_switch_cbdata 
  };
  
  static int grab_nth_branch_switch(struct object_id *ooid, struct object_id *noid,
 -                                const char *email, unsigned long timestamp, int tz,
 +                                const char *email, timestamp_t timestamp, int tz,
                                  const char *message, void *cb_data)
  {
        struct grab_nth_branch_switch_cbdata *cb = cb_data;
@@@ -1136,13 -1137,13 +1137,13 @@@ int get_oid_mb(const char *name, struc
        }
        if (st)
                return st;
 -      one = lookup_commit_reference_gently(oid_tmp.hash, 0);
 +      one = lookup_commit_reference_gently(&oid_tmp, 0);
        if (!one)
                return -1;
  
        if (get_sha1_committish(dots[3] ? (dots + 3) : "HEAD", oid_tmp.hash))
                return -1;
 -      two = lookup_commit_reference_gently(oid_tmp.hash, 0);
 +      two = lookup_commit_reference_gently(&oid_tmp, 0);
        if (!two)
                return -1;
        mbs = get_merge_bases(one, two);
@@@ -1408,7 -1409,7 +1409,7 @@@ static void diagnose_invalid_sha1_path(
        if (file_exists(filename))
                die("Path '%s' exists on disk, but not in '%.*s'.",
                    filename, object_name_len, object_name);
 -      if (errno == ENOENT || errno == ENOTDIR) {
 +      if (is_missing_file_error(errno)) {
                char *fullname = xstrfmt("%s%s", prefix, filename);
  
                if (!get_tree_entry(tree_sha1, fullname,
@@@ -1473,7 -1474,7 +1474,7 @@@ static void diagnose_invalid_index_path
  
        if (file_exists(filename))
                die("Path '%s' exists on disk, but not in the index.", filename);
 -      if (errno == ENOENT || errno == ENOTDIR)
 +      if (is_missing_file_error(errno))
                die("Path '%s' does not exist (neither on disk nor in the index).",
                    filename);
  
@@@ -1511,7 -1512,6 +1512,7 @@@ static int get_sha1_with_context_1(cons
  
        memset(oc, 0, sizeof(*oc));
        oc->mode = S_IFINVALID;
 +      strbuf_init(&oc->symlink_path, 0);
        ret = get_sha1_1(name, namelen, sha1, flags);
        if (!ret)
                return ret;
                        namelen = strlen(cp);
                }
  
 -              strlcpy(oc->path, cp, sizeof(oc->path));
 +              if (flags & GET_SHA1_RECORD_PATH)
 +                      oc->path = xstrdup(cp);
  
                if (!active_cache)
                        read_cache();
                                }
                        }
                        hashcpy(oc->tree, tree_sha1);
 -                      strlcpy(oc->path, filename, sizeof(oc->path));
 +                      if (flags & GET_SHA1_RECORD_PATH)
 +                              oc->path = xstrdup(filename);
  
                        free(new_filename);
                        return ret;
@@@ -1641,9 -1639,9 +1642,9 @@@ void maybe_die_on_misspelt_object_name(
        get_sha1_with_context_1(name, GET_SHA1_ONLY_TO_DIE, prefix, sha1, &oc);
  }
  
 -int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc)
 +int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *oc)
  {
        if (flags & GET_SHA1_FOLLOW_SYMLINKS && flags & GET_SHA1_ONLY_TO_DIE)
                die("BUG: incompatible flags for get_sha1_with_context");
 -      return get_sha1_with_context_1(str, flags, NULL, sha1, orc);
 +      return get_sha1_with_context_1(str, flags, NULL, sha1, oc);
  }
diff --combined submodule.c
index 1b8a3b575db6c85a42e9c9e285617113ecac4a84,8cfcb3bedd8fea4429d628ad4fcac3764a49b4ac..da0b805493b9e7cd4c26f027a9f24c823109850a
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "submodule-config.h"
  #include "submodule.h"
  #include "dir.h"
  #include "quote.h"
  #include "remote.h"
  #include "worktree.h"
 +#include "parse-options.h"
  
  static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;
 -static int config_update_recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 +static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
  static int parallel_jobs = 1;
 -static struct string_list changed_submodule_paths = STRING_LIST_INIT_NODUP;
 +static struct string_list changed_submodule_paths = STRING_LIST_INIT_DUP;
  static int initialized_fetch_ref_tips;
  static struct oid_array ref_tips_before_fetch;
  static struct oid_array ref_tips_after_fetch;
@@@ -154,8 -154,7 +155,8 @@@ void set_diffopt_flags_from_submodule_c
        }
  }
  
 -int submodule_config(const char *var, const char *value, void *cb)
 +/* For loading from the .gitmodules file. */
 +static int git_modules_config(const char *var, const char *value, void *cb)
  {
        if (!strcmp(var, "submodule.fetchjobs")) {
                parallel_jobs = git_config_int(var, value);
        return 0;
  }
  
 +/* Loads all submodule settings from the config. */
 +int submodule_config(const char *var, const char *value, void *cb)
 +{
 +      if (!strcmp(var, "submodule.recurse")) {
 +              int v = git_config_bool(var, value) ?
 +                      RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
 +              config_update_recurse_submodules = v;
 +              return 0;
 +      } else {
 +              return git_modules_config(var, value, cb);
 +      }
 +}
 +
 +/* Cheap function that only determines if we're interested in submodules at all */
 +int git_default_submodule_config(const char *var, const char *value, void *cb)
 +{
 +      if (!strcmp(var, "submodule.recurse")) {
 +              int v = git_config_bool(var, value) ?
 +                      RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
 +              config_update_recurse_submodules = v;
 +      }
 +      return 0;
 +}
 +
 +int option_parse_recurse_submodules_worktree_updater(const struct option *opt,
 +                                                   const char *arg, int unset)
 +{
 +      if (unset) {
 +              config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
 +              return 0;
 +      }
 +      if (arg)
 +              config_update_recurse_submodules =
 +                      parse_update_recurse_submodules_arg(opt->long_name,
 +                                                          arg);
 +      else
 +              config_update_recurse_submodules = RECURSE_SUBMODULES_ON;
 +
 +      return 0;
 +}
 +
 +void load_submodule_cache(void)
 +{
 +      if (config_update_recurse_submodules == RECURSE_SUBMODULES_OFF)
 +              return;
 +
 +      gitmodules_config();
 +      git_config(submodule_config, NULL);
 +}
 +
  void gitmodules_config(void)
  {
        const char *work_tree = get_git_work_tree();
                }
  
                if (!gitmodules_is_unmerged)
 -                      git_config_from_file(submodule_config, gitmodules_path.buf, NULL);
 +                      git_config_from_file(git_modules_config,
 +                              gitmodules_path.buf, NULL);
                strbuf_release(&gitmodules_path);
        }
  }
@@@ -260,7 -208,7 +261,7 @@@ void gitmodules_config_sha1(const unsig
        unsigned char sha1[20];
  
        if (gitmodule_sha1_from_commit(commit_sha1, sha1, &rev)) {
 -              git_config_from_blob_sha1(submodule_config, rev.buf,
 +              git_config_from_blob_sha1(git_modules_config, rev.buf,
                                          sha1, NULL);
        }
        strbuf_release(&rev);
@@@ -335,69 -283,6 +336,69 @@@ int is_submodule_populated_gently(cons
        return ret;
  }
  
 +/*
 + * Dies if the provided 'prefix' corresponds to an unpopulated submodule
 + */
 +void die_in_unpopulated_submodule(const struct index_state *istate,
 +                                const char *prefix)
 +{
 +      int i, prefixlen;
 +
 +      if (!prefix)
 +              return;
 +
 +      prefixlen = strlen(prefix);
 +
 +      for (i = 0; i < istate->cache_nr; i++) {
 +              struct cache_entry *ce = istate->cache[i];
 +              int ce_len = ce_namelen(ce);
 +
 +              if (!S_ISGITLINK(ce->ce_mode))
 +                      continue;
 +              if (prefixlen <= ce_len)
 +                      continue;
 +              if (strncmp(ce->name, prefix, ce_len))
 +                      continue;
 +              if (prefix[ce_len] != '/')
 +                      continue;
 +
 +              die(_("in unpopulated submodule '%s'"), ce->name);
 +      }
 +}
 +
 +/*
 + * Dies if any paths in the provided pathspec descends into a submodule
 + */
 +void die_path_inside_submodule(const struct index_state *istate,
 +                             const struct pathspec *ps)
 +{
 +      int i, j;
 +
 +      for (i = 0; i < istate->cache_nr; i++) {
 +              struct cache_entry *ce = istate->cache[i];
 +              int ce_len = ce_namelen(ce);
 +
 +              if (!S_ISGITLINK(ce->ce_mode))
 +                      continue;
 +
 +              for (j = 0; j < ps->nr ; j++) {
 +                      const struct pathspec_item *item = &ps->items[j];
 +
 +                      if (item->len <= ce_len)
 +                              continue;
 +                      if (item->match[ce_len] != '/')
 +                              continue;
 +                      if (strncmp(ce->name, item->match, ce_len))
 +                              continue;
 +                      if (item->len == ce_len + 1)
 +                              continue;
 +
 +                      die(_("Pathspec '%s' is in submodule '%.*s'"),
 +                          item->original, ce_len, ce->name);
 +              }
 +      }
 +}
 +
  int parse_submodule_update_strategy(const char *value,
                struct submodule_update_strategy *dst)
  {
@@@ -563,8 -448,8 +564,8 @@@ static void show_submodule_header(FILE 
         * Attempt to lookup the commit references, and determine if this is
         * a fast forward or fast backwards update.
         */
 -      *left = lookup_commit_reference(one->hash);
 -      *right = lookup_commit_reference(two->hash);
 +      *left = lookup_commit_reference(one);
 +      *right = lookup_commit_reference(two);
  
        /*
         * Warn about missing commits in the submodule project, but only if
@@@ -670,8 -555,7 +671,8 @@@ void show_submodule_inline_diff(FILE *f
        cp.no_stdin = 1;
  
        /* TODO: other options may need to be passed here. */
 -      argv_array_push(&cp.args, "diff");
 +      argv_array_pushl(&cp.args, "diff", "--submodule=diff", NULL);
 +
        argv_array_pushf(&cp.args, "--line-prefix=%s", line_prefix);
        if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
                argv_array_pushf(&cp.args, "--src-prefix=%s%s/",
@@@ -713,6 -597,11 +714,6 @@@ void set_config_fetch_recurse_submodule
        config_fetch_recurse_submodules = value;
  }
  
 -void set_config_update_recurse_submodules(int value)
 -{
 -      config_update_recurse_submodules = value;
 -}
 -
  int should_update_submodules(void)
  {
        return config_update_recurse_submodules == RECURSE_SUBMODULES_ON;
@@@ -729,94 -618,6 +730,94 @@@ const struct submodule *submodule_from_
        return submodule_from_path(null_sha1, ce->name);
  }
  
 +static struct oid_array *submodule_commits(struct string_list *submodules,
 +                                         const char *path)
 +{
 +      struct string_list_item *item;
 +
 +      item = string_list_insert(submodules, path);
 +      if (item->util)
 +              return (struct oid_array *) item->util;
 +
 +      /* NEEDSWORK: should we have oid_array_init()? */
 +      item->util = xcalloc(1, sizeof(struct oid_array));
 +      return (struct oid_array *) item->util;
 +}
 +
 +static void collect_changed_submodules_cb(struct diff_queue_struct *q,
 +                                        struct diff_options *options,
 +                                        void *data)
 +{
 +      int i;
 +      struct string_list *changed = data;
 +
 +      for (i = 0; i < q->nr; i++) {
 +              struct diff_filepair *p = q->queue[i];
 +              struct oid_array *commits;
 +              if (!S_ISGITLINK(p->two->mode))
 +                      continue;
 +
 +              if (S_ISGITLINK(p->one->mode)) {
 +                      /*
 +                       * NEEDSWORK: We should honor the name configured in
 +                       * the .gitmodules file of the commit we are examining
 +                       * here to be able to correctly follow submodules
 +                       * being moved around.
 +                       */
 +                      commits = submodule_commits(changed, p->two->path);
 +                      oid_array_append(commits, &p->two->oid);
 +              } else {
 +                      /* Submodule is new or was moved here */
 +                      /*
 +                       * NEEDSWORK: When the .git directories of submodules
 +                       * live inside the superprojects .git directory some
 +                       * day we should fetch new submodules directly into
 +                       * that location too when config or options request
 +                       * that so they can be checked out from there.
 +                       */
 +                      continue;
 +              }
 +      }
 +}
 +
 +/*
 + * Collect the paths of submodules in 'changed' which have changed based on
 + * the revisions as specified in 'argv'.  Each entry in 'changed' will also
 + * have a corresponding 'struct oid_array' (in the 'util' field) which lists
 + * what the submodule pointers were updated to during the change.
 + */
 +static void collect_changed_submodules(struct string_list *changed,
 +                                     struct argv_array *argv)
 +{
 +      struct rev_info rev;
 +      const struct commit *commit;
 +
 +      init_revisions(&rev, NULL);
 +      setup_revisions(argv->argc, argv->argv, &rev, NULL);
 +      if (prepare_revision_walk(&rev))
 +              die("revision walk setup failed");
 +
 +      while ((commit = get_revision(&rev))) {
 +              struct rev_info diff_rev;
 +
 +              init_revisions(&diff_rev, NULL);
 +              diff_rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
 +              diff_rev.diffopt.format_callback = collect_changed_submodules_cb;
 +              diff_rev.diffopt.format_callback_data = changed;
 +              diff_tree_combined_merge(commit, 1, &diff_rev);
 +      }
 +
 +      reset_revision_walk();
 +}
 +
 +static void free_submodules_oids(struct string_list *submodules)
 +{
 +      struct string_list_item *item;
 +      for_each_string_list_item(item, submodules)
 +              oid_array_clear((struct oid_array *) item->util);
 +      string_list_clear(submodules, 1);
 +}
 +
  static int has_remote(const char *refname, const struct object_id *oid,
                      int flags, void *cb_data)
  {
@@@ -834,7 -635,7 +835,7 @@@ static int check_has_commit(const struc
  {
        int *has_commit = data;
  
 -      if (!lookup_commit_reference(oid->hash))
 +      if (!lookup_commit_reference(oid))
                *has_commit = 0;
  
        return 0;
@@@ -844,44 -645,10 +845,44 @@@ static int submodule_has_commits(const 
  {
        int has_commit = 1;
  
 +      /*
 +       * Perform a cheap, but incorrect check for the existance of 'commits'.
 +       * This is done by adding the submodule's object store to the in-core
 +       * object store, and then querying for each commit's existance.  If we
 +       * do not have the commit object anywhere, there is no chance we have
 +       * it in the object store of the correct submodule and have it
 +       * reachable from a ref, so we can fail early without spawning rev-list
 +       * which is expensive.
 +       */
        if (add_submodule_odb(path))
                return 0;
  
        oid_array_for_each_unique(commits, check_has_commit, &has_commit);
 +
 +      if (has_commit) {
 +              /*
 +               * Even if the submodule is checked out and the commit is
 +               * present, make sure it exists in the submodule's object store
 +               * and that it is reachable from a ref.
 +               */
 +              struct child_process cp = CHILD_PROCESS_INIT;
 +              struct strbuf out = STRBUF_INIT;
 +
 +              argv_array_pushl(&cp.args, "rev-list", "-n", "1", NULL);
 +              oid_array_for_each_unique(commits, append_oid_to_argv, &cp.args);
 +              argv_array_pushl(&cp.args, "--not", "--all", NULL);
 +
 +              prepare_submodule_repo_env(&cp.env_array);
 +              cp.git_cmd = 1;
 +              cp.no_stdin = 1;
 +              cp.dir = path;
 +
 +              if (capture_command(&cp, &out, GIT_MAX_HEXSZ + 1) || out.len)
 +                      has_commit = 0;
 +
 +              strbuf_release(&out);
 +      }
 +
        return has_commit;
  }
  
@@@ -929,31 -696,91 +930,31 @@@ static int submodule_needs_pushing(cons
        return 0;
  }
  
 -static struct oid_array *submodule_commits(struct string_list *submodules,
 -                                          const char *path)
 -{
 -      struct string_list_item *item;
 -
 -      item = string_list_insert(submodules, path);
 -      if (item->util)
 -              return (struct oid_array *) item->util;
 -
 -      /* NEEDSWORK: should we have oid_array_init()? */
 -      item->util = xcalloc(1, sizeof(struct oid_array));
 -      return (struct oid_array *) item->util;
 -}
 -
 -static void collect_submodules_from_diff(struct diff_queue_struct *q,
 -                                       struct diff_options *options,
 -                                       void *data)
 -{
 -      int i;
 -      struct string_list *submodules = data;
 -
 -      for (i = 0; i < q->nr; i++) {
 -              struct diff_filepair *p = q->queue[i];
 -              struct oid_array *commits;
 -              if (!S_ISGITLINK(p->two->mode))
 -                      continue;
 -              commits = submodule_commits(submodules, p->two->path);
 -              oid_array_append(commits, &p->two->oid);
 -      }
 -}
 -
 -static void find_unpushed_submodule_commits(struct commit *commit,
 -              struct string_list *needs_pushing)
 -{
 -      struct rev_info rev;
 -
 -      init_revisions(&rev, NULL);
 -      rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
 -      rev.diffopt.format_callback = collect_submodules_from_diff;
 -      rev.diffopt.format_callback_data = needs_pushing;
 -      diff_tree_combined_merge(commit, 1, &rev);
 -}
 -
 -static void free_submodules_sha1s(struct string_list *submodules)
 -{
 -      struct string_list_item *item;
 -      for_each_string_list_item(item, submodules)
 -              oid_array_clear((struct oid_array *) item->util);
 -      string_list_clear(submodules, 1);
 -}
 -
  int find_unpushed_submodules(struct oid_array *commits,
                const char *remotes_name, struct string_list *needs_pushing)
  {
 -      struct rev_info rev;
 -      struct commit *commit;
        struct string_list submodules = STRING_LIST_INIT_DUP;
        struct string_list_item *submodule;
        struct argv_array argv = ARGV_ARRAY_INIT;
  
 -      init_revisions(&rev, NULL);
 -
        /* argv.argv[0] will be ignored by setup_revisions */
        argv_array_push(&argv, "find_unpushed_submodules");
        oid_array_for_each_unique(commits, append_oid_to_argv, &argv);
        argv_array_push(&argv, "--not");
        argv_array_pushf(&argv, "--remotes=%s", remotes_name);
  
 -      setup_revisions(argv.argc, argv.argv, &rev, NULL);
 -      if (prepare_revision_walk(&rev))
 -              die("revision walk setup failed");
 -
 -      while ((commit = get_revision(&rev)) != NULL)
 -              find_unpushed_submodule_commits(commit, &submodules);
 -
 -      reset_revision_walk();
 -      argv_array_clear(&argv);
 +      collect_changed_submodules(&submodules, &argv);
  
        for_each_string_list_item(submodule, &submodules) {
 -              struct oid_array *commits = (struct oid_array *) submodule->util;
 +              struct oid_array *commits = submodule->util;
 +              const char *path = submodule->string;
  
 -              if (submodule_needs_pushing(submodule->string, commits))
 -                      string_list_insert(needs_pushing, submodule->string);
 +              if (submodule_needs_pushing(path, commits))
 +                      string_list_insert(needs_pushing, path);
        }
 -      free_submodules_sha1s(&submodules);
 +
 +      free_submodules_oids(&submodules);
 +      argv_array_clear(&argv);
  
        return needs_pushing->nr;
  }
@@@ -1070,56 -897,125 +1071,56 @@@ int push_unpushed_submodules(struct oid
        return ret;
  }
  
 -static int is_submodule_commit_present(const char *path, unsigned char sha1[20])
 -{
 -      int is_present = 0;
 -      if (!add_submodule_odb(path) && lookup_commit_reference(sha1)) {
 -              /* Even if the submodule is checked out and the commit is
 -               * present, make sure it is reachable from a ref. */
 -              struct child_process cp = CHILD_PROCESS_INIT;
 -              const char *argv[] = {"rev-list", "-n", "1", NULL, "--not", "--all", NULL};
 -              struct strbuf buf = STRBUF_INIT;
 -
 -              argv[3] = sha1_to_hex(sha1);
 -              cp.argv = argv;
 -              prepare_submodule_repo_env(&cp.env_array);
 -              cp.git_cmd = 1;
 -              cp.no_stdin = 1;
 -              cp.dir = path;
 -              if (!capture_command(&cp, &buf, 1024) && !buf.len)
 -                      is_present = 1;
 -
 -              strbuf_release(&buf);
 -      }
 -      return is_present;
 -}
 -
 -static void submodule_collect_changed_cb(struct diff_queue_struct *q,
 -                                       struct diff_options *options,
 -                                       void *data)
 -{
 -      int i;
 -      for (i = 0; i < q->nr; i++) {
 -              struct diff_filepair *p = q->queue[i];
 -              if (!S_ISGITLINK(p->two->mode))
 -                      continue;
 -
 -              if (S_ISGITLINK(p->one->mode)) {
 -                      /* NEEDSWORK: We should honor the name configured in
 -                       * the .gitmodules file of the commit we are examining
 -                       * here to be able to correctly follow submodules
 -                       * being moved around. */
 -                      struct string_list_item *path;
 -                      path = unsorted_string_list_lookup(&changed_submodule_paths, p->two->path);
 -                      if (!path && !is_submodule_commit_present(p->two->path, p->two->oid.hash))
 -                              string_list_append(&changed_submodule_paths, xstrdup(p->two->path));
 -              } else {
 -                      /* Submodule is new or was moved here */
 -                      /* NEEDSWORK: When the .git directories of submodules
 -                       * live inside the superprojects .git directory some
 -                       * day we should fetch new submodules directly into
 -                       * that location too when config or options request
 -                       * that so they can be checked out from there. */
 -                      continue;
 -              }
 -      }
 -}
 -
 -static int add_sha1_to_array(const char *ref, const struct object_id *oid,
 -                           int flags, void *data)
 +static int append_oid_to_array(const char *ref, const struct object_id *oid,
 +                             int flags, void *data)
  {
 -      oid_array_append(data, oid);
 +      struct oid_array *array = data;
 +      oid_array_append(array, oid);
        return 0;
  }
  
  void check_for_new_submodule_commits(struct object_id *oid)
  {
        if (!initialized_fetch_ref_tips) {
 -              for_each_ref(add_sha1_to_array, &ref_tips_before_fetch);
 +              for_each_ref(append_oid_to_array, &ref_tips_before_fetch);
                initialized_fetch_ref_tips = 1;
        }
  
        oid_array_append(&ref_tips_after_fetch, oid);
  }
  
 -static int add_oid_to_argv(const struct object_id *oid, void *data)
 -{
 -      argv_array_push(data, oid_to_hex(oid));
 -      return 0;
 -}
 -
  static void calculate_changed_submodule_paths(void)
  {
 -      struct rev_info rev;
 -      struct commit *commit;
        struct argv_array argv = ARGV_ARRAY_INIT;
 +      struct string_list changed_submodules = STRING_LIST_INIT_DUP;
 +      const struct string_list_item *item;
  
        /* No need to check if there are no submodules configured */
        if (!submodule_from_path(NULL, NULL))
                return;
  
 -      init_revisions(&rev, NULL);
        argv_array_push(&argv, "--"); /* argv[0] program name */
        oid_array_for_each_unique(&ref_tips_after_fetch,
 -                                 add_oid_to_argv, &argv);
 +                                 append_oid_to_argv, &argv);
        argv_array_push(&argv, "--not");
        oid_array_for_each_unique(&ref_tips_before_fetch,
 -                                 add_oid_to_argv, &argv);
 -      setup_revisions(argv.argc, argv.argv, &rev, NULL);
 -      if (prepare_revision_walk(&rev))
 -              die("revision walk setup failed");
 +                                 append_oid_to_argv, &argv);
  
        /*
         * Collect all submodules (whether checked out or not) for which new
         * commits have been recorded upstream in "changed_submodule_paths".
         */
 -      while ((commit = get_revision(&rev))) {
 -              struct commit_list *parent = commit->parents;
 -              while (parent) {
 -                      struct diff_options diff_opts;
 -                      diff_setup(&diff_opts);
 -                      DIFF_OPT_SET(&diff_opts, RECURSIVE);
 -                      diff_opts.output_format |= DIFF_FORMAT_CALLBACK;
 -                      diff_opts.format_callback = submodule_collect_changed_cb;
 -                      diff_setup_done(&diff_opts);
 -                      diff_tree_sha1(parent->item->object.oid.hash, commit->object.oid.hash, "", &diff_opts);
 -                      diffcore_std(&diff_opts);
 -                      diff_flush(&diff_opts);
 -                      parent = parent->next;
 -              }
 +      collect_changed_submodules(&changed_submodules, &argv);
 +
 +      for_each_string_list_item(item, &changed_submodules) {
 +              struct oid_array *commits = item->util;
 +              const char *path = item->string;
 +
 +              if (!submodule_has_commits(path, commits))
 +                      string_list_append(&changed_submodule_paths, path);
        }
  
 +      free_submodules_oids(&changed_submodules);
        argv_array_clear(&argv);
        oid_array_clear(&ref_tips_before_fetch);
        oid_array_clear(&ref_tips_after_fetch);
@@@ -1468,7 -1364,7 +1469,7 @@@ static int submodule_has_dirty_index(co
  {
        struct child_process cp = CHILD_PROCESS_INIT;
  
 -      prepare_submodule_repo_env_no_git_dir(&cp.env_array);
 +      prepare_submodule_repo_env(&cp.env_array);
  
        cp.git_cmd = 1;
        argv_array_pushl(&cp.args, "diff-index", "--quiet",
  static void submodule_reset_index(const char *path)
  {
        struct child_process cp = CHILD_PROCESS_INIT;
 -      prepare_submodule_repo_env_no_git_dir(&cp.env_array);
 +      prepare_submodule_repo_env(&cp.env_array);
  
        cp.git_cmd = 1;
        cp.no_stdin = 1;
@@@ -1514,23 -1410,6 +1515,23 @@@ int submodule_move_head(const char *pat
        int ret = 0;
        struct child_process cp = CHILD_PROCESS_INIT;
        const struct submodule *sub;
 +      int *error_code_ptr, error_code;
 +
 +      if (!is_submodule_initialized(path))
 +              return 0;
 +
 +      if (flags & SUBMODULE_MOVE_HEAD_FORCE)
 +              /*
 +               * Pass non NULL pointer to is_submodule_populated_gently
 +               * to prevent die()-ing. We'll use connect_work_tree_and_git_dir
 +               * to fixup the submodule in the force case later.
 +               */
 +              error_code_ptr = &error_code;
 +      else
 +              error_code_ptr = NULL;
 +
 +      if (old && !is_submodule_populated_gently(path, error_code_ptr))
 +              return 0;
  
        sub = submodule_from_path(null_sha1, path);
  
                                absorb_git_dir_into_superproject("", path,
                                        ABSORB_GITDIR_RECURSE_SUBMODULES);
                } else {
 -                      struct strbuf sb = STRBUF_INIT;
 -                      strbuf_addf(&sb, "%s/modules/%s",
 +                      char *gitdir = xstrfmt("%s/modules/%s",
                                    get_git_common_dir(), sub->name);
 -                      connect_work_tree_and_git_dir(path, sb.buf);
 -                      strbuf_release(&sb);
 +                      connect_work_tree_and_git_dir(path, gitdir);
 +                      free(gitdir);
  
                        /* make sure the index is clean as well */
                        submodule_reset_index(path);
                }
 +
 +              if (old && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {
 +                      char *gitdir = xstrfmt("%s/modules/%s",
 +                                  get_git_common_dir(), sub->name);
 +                      connect_work_tree_and_git_dir(path, gitdir);
 +                      free(gitdir);
 +              }
        }
  
 -      prepare_submodule_repo_env_no_git_dir(&cp.env_array);
 +      prepare_submodule_repo_env(&cp.env_array);
  
        cp.git_cmd = 1;
        cp.no_stdin = 1;
  
        argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
                        get_super_prefix_or_empty(), path);
 -      argv_array_pushl(&cp.args, "read-tree", NULL);
 +      argv_array_pushl(&cp.args, "read-tree", "--recurse-submodules", NULL);
  
        if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)
                argv_array_push(&cp.args, "-n");
  
        if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
                if (new) {
 -                      struct child_process cp1 = CHILD_PROCESS_INIT;
 +                      child_process_init(&cp);
                        /* also set the HEAD accordingly */
 -                      cp1.git_cmd = 1;
 -                      cp1.no_stdin = 1;
 -                      cp1.dir = path;
 +                      cp.git_cmd = 1;
 +                      cp.no_stdin = 1;
 +                      cp.dir = path;
  
 -                      argv_array_pushl(&cp1.args, "update-ref", "HEAD", new, NULL);
 +                      prepare_submodule_repo_env(&cp.env_array);
 +                      argv_array_pushl(&cp.args, "update-ref", "HEAD", new, NULL);
  
 -                      if (run_command(&cp1)) {
 +                      if (run_command(&cp)) {
                                ret = -1;
                                goto out;
                        }
@@@ -1695,9 -1567,9 +1696,9 @@@ static void print_commit(struct commit 
  #define MERGE_WARNING(path, msg) \
        warning("Failed to merge submodule %s (%s)", path, msg);
  
 -int merge_submodule(unsigned char result[20], const char *path,
 -                  const unsigned char base[20], const unsigned char a[20],
 -                  const unsigned char b[20], int search)
 +int merge_submodule(struct object_id *result, const char *path,
 +                  const struct object_id *base, const struct object_id *a,
 +                  const struct object_id *b, int search)
  {
        struct commit *commit_base, *commit_a, *commit_b;
        int parent_count;
        int i;
  
        /* store a in result in case we fail */
 -      hashcpy(result, a);
 +      oidcpy(result, a);
  
        /* we can not handle deletion conflicts */
 -      if (is_null_sha1(base))
 +      if (is_null_oid(base))
                return 0;
 -      if (is_null_sha1(a))
 +      if (is_null_oid(a))
                return 0;
 -      if (is_null_sha1(b))
 +      if (is_null_oid(b))
                return 0;
  
        if (add_submodule_odb(path)) {
  
        /* Case #1: a is contained in b or vice versa */
        if (in_merge_bases(commit_a, commit_b)) {
 -              hashcpy(result, b);
 +              oidcpy(result, b);
                return 1;
        }
        if (in_merge_bases(commit_b, commit_a)) {
 -              hashcpy(result, a);
 +              oidcpy(result, a);
                return 1;
        }
  
diff --combined transport.c
index 9bfcf870f9078f75349bd3b4976c71bbf5c49ebf,6096f8258670cb2d651f73d945f60281883d11d1..b9995306f259da0a929babdfe1fb5b99eaacead8
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "transport.h"
  #include "run-command.h"
  #include "pkt-line.h"
@@@ -87,7 -88,7 +88,7 @@@ static struct ref *get_refs_from_bundle
        for (i = 0; i < data->header.references.nr; i++) {
                struct ref_list_entry *e = data->header.references.list + i;
                struct ref *ref = alloc_ref(e->name);
 -              hashcpy(ref->old_oid.hash, e->sha1);
 +              oidcpy(&ref->old_oid, &e->oid);
                ref->next = result;
                result = ref;
        }
diff --combined unpack-trees.c
index d38c37e38cf183cf878a9f35b19544d1da0bc438,e7b5a21ef78daf6aebe1bf4630e4baeb11ffea0f..dd535bc8497e5d8202a94923fd0a68c3f46907fd
@@@ -1,5 -1,6 +1,6 @@@
  #define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
+ #include "config.h"
  #include "dir.h"
  #include "tree.h"
  #include "tree-walk.h"
@@@ -252,18 -253,14 +253,18 @@@ static int check_submodule_move_head(co
                                     const char *new_id,
                                     struct unpack_trees_options *o)
  {
 +      unsigned flags = SUBMODULE_MOVE_HEAD_DRY_RUN;
        const struct submodule *sub = submodule_from_ce(ce);
        if (!sub)
                return 0;
  
 +      if (o->reset)
 +              flags |= SUBMODULE_MOVE_HEAD_FORCE;
 +
        switch (sub->update_strategy.type) {
        case SM_UPDATE_UNSPECIFIED:
        case SM_UPDATE_CHECKOUT:
 -              if (submodule_move_head(ce->name, old_id, new_id, SUBMODULE_MOVE_HEAD_DRY_RUN))
 +              if (submodule_move_head(ce->name, old_id, new_id, flags))
                        return o->gently ? -1 :
                                add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
                return 0;
@@@ -312,7 -309,6 +313,7 @@@ static void unlink_entry(const struct c
                case SM_UPDATE_CHECKOUT:
                case SM_UPDATE_REBASE:
                case SM_UPDATE_MERGE:
 +                      /* state.force is set at the caller. */
                        submodule_move_head(ce->name, "HEAD", NULL,
                                            SUBMODULE_MOVE_HEAD_FORCE);
                        break;
@@@ -1073,7 -1069,7 +1074,7 @@@ static int clear_ce_flags_dir(struct ca
        struct cache_entry **cache_end;
        int dtype = DT_DIR;
        int ret = is_excluded_from_list(prefix->buf, prefix->len,
 -                                      basename, &dtype, el);
 +                                      basename, &dtype, el, &the_index);
        int rc;
  
        strbuf_addch(prefix, '/');
@@@ -1176,7 -1172,7 +1177,7 @@@ static int clear_ce_flags_1(struct cach
                /* Non-directory */
                dtype = ce_to_dtype(ce);
                ret = is_excluded_from_list(ce->name, ce_namelen(ce),
 -                                          name, &dtype, el);
 +                                          name, &dtype, el, &the_index);
                if (ret < 0)
                        ret = defval;
                if (ret > 0)
@@@ -1256,7 -1252,7 +1257,7 @@@ int unpack_trees(unsigned len, struct t
                o->skip_sparse_checkout = 1;
        if (!o->skip_sparse_checkout) {
                char *sparse = git_pathdup("info/sparse-checkout");
 -              if (add_excludes_from_file_to_list(sparse, "", 0, &el, 0) < 0)
 +              if (add_excludes_from_file_to_list(sparse, "", 0, &el, NULL) < 0)
                        o->skip_sparse_checkout = 1;
                else
                        o->el = &el;
                                                  WRITE_TREE_SILENT |
                                                  WRITE_TREE_REPAIR);
                }
 +              move_index_extensions(&o->result, o->dst_index);
                discard_index(o->dst_index);
                *o->dst_index = o->result;
        } else {
@@@ -1598,7 -1593,7 +1599,7 @@@ static int verify_clean_subdirectory(co
        memset(&d, 0, sizeof(d));
        if (o->dir)
                d.exclude_per_dir = o->dir->exclude_per_dir;
 -      i = read_directory(&d, pathbuf, namelen+1, NULL);
 +      i = read_directory(&d, &the_index, pathbuf, namelen+1, NULL);
        if (i)
                return o->gently ? -1 :
                        add_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name);
@@@ -1640,7 -1635,7 +1641,7 @@@ static int check_ok_to_remove(const cha
                return 0;
  
        if (o->dir &&
 -          is_excluded(o->dir, name, &dtype))
 +          is_excluded(o->dir, &the_index, name, &dtype))
                /*
                 * ce->name is explicitly excluded, so it is Ok to
                 * overwrite it.
diff --combined upload-pack.c
index 5330c02c1427862be1eea61c8d8e4127909d13fe,7581a51960a58114601dad08a788a47270c9bf0e..7efff2fbfd76380fd448d53173f8295d7c9c9d87
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "refs.h"
  #include "pkt-line.h"
  #include "sideband.h"
@@@ -35,7 -36,7 +36,7 @@@ static const char * const upload_pack_u
  #define CLIENT_SHALLOW        (1u << 18)
  #define HIDDEN_REF    (1u << 19)
  
 -static unsigned long oldest_have;
 +static timestamp_t oldest_have;
  
  static int deepen_relative;
  static int multi_ack;
@@@ -286,19 -287,19 +287,19 @@@ static void create_pack_file(void
        die("git upload-pack: %s", abort_msg);
  }
  
 -static int got_sha1(const char *hex, unsigned char *sha1)
 +static int got_oid(const char *hex, struct object_id *oid)
  {
        struct object *o;
        int we_knew_they_have = 0;
  
 -      if (get_sha1_hex(hex, sha1))
 +      if (get_oid_hex(hex, oid))
                die("git upload-pack: expected SHA1 object, got '%s'", hex);
 -      if (!has_sha1_file(sha1))
 +      if (!has_object_file(oid))
                return -1;
  
 -      o = parse_object(sha1);
 +      o = parse_object(oid);
        if (!o)
 -              die("oops (%s)", sha1_to_hex(sha1));
 +              die("oops (%s)", oid_to_hex(oid));
        if (o->type == OBJ_COMMIT) {
                struct commit_list *parents;
                struct commit *commit = (struct commit *)o;
@@@ -334,7 -335,7 +335,7 @@@ static int reachable(struct commit *wan
                        break;
                }
                if (!commit->object.parsed)
 -                      parse_object(commit->object.oid.hash);
 +                      parse_object(&commit->object.oid);
                if (commit->object.flags & REACHABLE)
                        continue;
                commit->object.flags |= REACHABLE;
@@@ -382,8 -383,8 +383,8 @@@ static int ok_to_give_up(void
  
  static int get_common_commits(void)
  {
 -      unsigned char sha1[20];
 -      char last_hex[41];
 +      struct object_id oid;
 +      char last_hex[GIT_MAX_HEXSZ + 1];
        int got_common = 0;
        int got_other = 0;
        int sent_ready = 0;
                        continue;
                }
                if (skip_prefix(line, "have ", &arg)) {
 -                      switch (got_sha1(arg, sha1)) {
 +                      switch (got_oid(arg, &oid)) {
                        case -1: /* they have what we do not */
                                got_other = 1;
                                if (multi_ack && ok_to_give_up()) {
 -                                      const char *hex = sha1_to_hex(sha1);
 +                                      const char *hex = oid_to_hex(&oid);
                                        if (multi_ack == 2) {
                                                sent_ready = 1;
                                                packet_write_fmt(1, "ACK %s ready\n", hex);
                                break;
                        default:
                                got_common = 1;
 -                              memcpy(last_hex, sha1_to_hex(sha1), 41);
 +                              memcpy(last_hex, oid_to_hex(&oid), 41);
                                if (multi_ack == 2)
                                        packet_write_fmt(1, "ACK %s common\n", last_hex);
                                else if (multi_ack)
@@@ -492,7 -493,7 +493,7 @@@ static int do_reachable_revlist(struct 
                goto error;
  
        namebuf[0] = '^';
 -      namebuf[41] = '\n';
 +      namebuf[GIT_SHA1_HEXSZ + 1] = '\n';
        for (i = get_max_object_index(); 0 < i; ) {
                o = get_indexed_object(--i);
                if (!o)
                if (!is_our_ref(o))
                        continue;
                memcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);
 -              if (write_in_full(cmd->in, namebuf, 42) < 0)
 +              if (write_in_full(cmd->in, namebuf, GIT_SHA1_HEXSZ + 2) < 0)
                        goto error;
        }
 -      namebuf[40] = '\n';
 +      namebuf[GIT_SHA1_HEXSZ] = '\n';
        for (i = 0; i < src->nr; i++) {
                o = src->objects[i].item;
                if (is_our_ref(o)) {
                if (reachable && o->type == OBJ_COMMIT)
                        o->flags |= TMP_MARK;
                memcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);
 -              if (write_in_full(cmd->in, namebuf, 41) < 0)
 +              if (write_in_full(cmd->in, namebuf, GIT_SHA1_HEXSZ + 1) < 0)
                        goto error;
        }
        close(cmd->in);
@@@ -642,7 -643,7 +643,7 @@@ static void send_shallow(struct commit_
                if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {
                        packet_write_fmt(1, "shallow %s",
                                         oid_to_hex(&object->oid));
 -                      register_shallow(object->oid.hash);
 +                      register_shallow(&object->oid);
                        shallow_nr++;
                }
                result = result->next;
@@@ -667,7 -668,7 +668,7 @@@ static void send_unshallow(const struc
                         * parse and add the parents to the want list, then
                         * re-register it.
                         */
 -                      unregister_shallow(object->oid.hash);
 +                      unregister_shallow(&object->oid);
                        object->parsed = 0;
                        parse_commit_or_die((struct commit *)object);
                        parents = ((struct commit *)object)->parents;
                        add_object_array(object, NULL, &extra_edge_obj);
                }
                /* make sure commit traversal conforms to client */
 -              register_shallow(object->oid.hash);
 +              register_shallow(&object->oid);
        }
  }
  
@@@ -735,14 -736,14 +736,14 @@@ static void receive_needs(void
        struct string_list deepen_not = STRING_LIST_INIT_DUP;
        int depth = 0;
        int has_non_tip = 0;
 -      unsigned long deepen_since = 0;
 +      timestamp_t deepen_since = 0;
        int deepen_rev_list = 0;
  
        shallow_nr = 0;
        for (;;) {
                struct object *o;
                const char *features;
 -              unsigned char sha1_buf[20];
 +              struct object_id oid_buf;
                char *line = packet_read_line(0, NULL);
                const char *arg;
  
                        break;
  
                if (skip_prefix(line, "shallow ", &arg)) {
 -                      unsigned char sha1[20];
 +                      struct object_id oid;
                        struct object *object;
 -                      if (get_sha1_hex(arg, sha1))
 +                      if (get_oid_hex(arg, &oid))
                                die("invalid shallow line: %s", line);
 -                      object = parse_object(sha1);
 +                      object = parse_object(&oid);
                        if (!object)
                                continue;
                        if (object->type != OBJ_COMMIT)
 -                              die("invalid shallow object %s", sha1_to_hex(sha1));
 +                              die("invalid shallow object %s", oid_to_hex(&oid));
                        if (!(object->flags & CLIENT_SHALLOW)) {
                                object->flags |= CLIENT_SHALLOW;
                                add_object_array(object, NULL, &shallows);
                }
                if (skip_prefix(line, "deepen-since ", &arg)) {
                        char *end = NULL;
 -                      deepen_since = strtoul(arg, &end, 0);
 +                      deepen_since = parse_timestamp(arg, &end, 0);
                        if (!end || *end || !deepen_since ||
                            /* revisions.c's max_age -1 is special */
                            deepen_since == -1)
                }
                if (skip_prefix(line, "deepen-not ", &arg)) {
                        char *ref = NULL;
 -                      unsigned char sha1[20];
 -                      if (expand_ref(arg, strlen(arg), sha1, &ref) != 1)
 +                      struct object_id oid;
 +                      if (expand_ref(arg, strlen(arg), oid.hash, &ref) != 1)
                                die("git upload-pack: ambiguous deepen-not: %s", line);
                        string_list_append(&deepen_not, ref);
                        free(ref);
                        continue;
                }
                if (!skip_prefix(line, "want ", &arg) ||
 -                  get_sha1_hex(arg, sha1_buf))
 +                  get_oid_hex(arg, &oid_buf))
                        die("git upload-pack: protocol error, "
                            "expected to get sha, not '%s'", line);
  
                if (parse_feature_request(features, "include-tag"))
                        use_include_tag = 1;
  
 -              o = parse_object(sha1_buf);
 +              o = parse_object(&oid_buf);
                if (!o) {
                        packet_write_fmt(1,
                                         "ERR upload-pack: not our ref %s",
 -                                       sha1_to_hex(sha1_buf));
 +                                       oid_to_hex(&oid_buf));
                        die("git upload-pack: not our ref %s",
 -                          sha1_to_hex(sha1_buf));
 +                          oid_to_hex(&oid_buf));
                }
                if (!(o->flags & WANTED)) {
                        o->flags |= WANTED;
  
                argv_array_push(&av, "rev-list");
                if (deepen_since)
 -                      argv_array_pushf(&av, "--max-age=%lu", deepen_since);
 +                      argv_array_pushf(&av, "--max-age=%"PRItime, deepen_since);
                if (deepen_not.nr) {
                        argv_array_push(&av, "--not");
                        for (i = 0; i < deepen_not.nr; i++) {
                if (shallows.nr > 0) {
                        int i;
                        for (i = 0; i < shallows.nr; i++)
 -                              register_shallow(shallows.objects[i].item->oid.hash);
 +                              register_shallow(&shallows.objects[i].item->oid);
                }
  
        shallow_nr += shallows.nr;
diff --combined wrapper.c
index 4632c7d4c08c3127c4017c98c0983871f0236d93,487a9f753272ff27f54baaece755738beae3b947..36630e5d1855a41407e217e610aa1f293288abe1
+++ b/wrapper.c
@@@ -2,6 -2,7 +2,7 @@@
   * Various trivial helper wrappers around standard functions
   */
  #include "cache.h"
+ #include "config.h"
  
  static void do_nothing(size_t size)
  {
@@@ -418,32 -419,6 +419,32 @@@ FILE *fopen_for_writing(const char *pat
        return ret;
  }
  
 +static void warn_on_inaccessible(const char *path)
 +{
 +      warning_errno(_("unable to access '%s'"), path);
 +}
 +
 +int warn_on_fopen_errors(const char *path)
 +{
 +      if (errno != ENOENT && errno != ENOTDIR) {
 +              warn_on_inaccessible(path);
 +              return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +FILE *fopen_or_warn(const char *path, const char *mode)
 +{
 +      FILE *fp = fopen(path, mode);
 +
 +      if (fp)
 +              return fp;
 +
 +      warn_on_fopen_errors(path);
 +      return NULL;
 +}
 +
  int xmkstemp(char *template)
  {
        int fd;
@@@ -602,10 -577,15 +603,10 @@@ int remove_or_warn(unsigned int mode, c
        return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file);
  }
  
 -void warn_on_inaccessible(const char *path)
 -{
 -      warning_errno(_("unable to access '%s'"), path);
 -}
 -
  static int access_error_is_ok(int err, unsigned flag)
  {
 -      return err == ENOENT || err == ENOTDIR ||
 -              ((flag & ACCESS_EACCES_OK) && err == EACCES);
 +      return (is_missing_file_error(err) ||
 +              ((flag & ACCESS_EACCES_OK) && err == EACCES));
  }
  
  int access_or_warn(const char *path, int mode, unsigned flag)
diff --combined xdiff-interface.c
index d3f78ca2a718d3e4928aa90067e24d19988514c1,5ac07d7348c3c8b5cb4e4decf8a19cd3881b6c82..018e03308921e3b44bb75b8bc1e005424ca4fc1b
@@@ -1,4 -1,5 +1,5 @@@
  #include "cache.h"
+ #include "config.h"
  #include "xdiff-interface.h"
  #include "xdiff/xtypes.h"
  #include "xdiff/xdiffi.h"
@@@ -164,9 -165,9 +165,9 @@@ int read_mmfile(mmfile_t *ptr, const ch
        size_t sz;
  
        if (stat(filename, &st))
 -              return error("Could not stat %s", filename);
 +              return error_errno("Could not stat %s", filename);
        if ((f = fopen(filename, "rb")) == NULL)
 -              return error("Could not open %s", filename);
 +              return error_errno("Could not open %s", filename);
        sz = xsize_t(st.st_size);
        ptr->ptr = xmalloc(sz ? sz : 1);
        if (sz && fread(ptr->ptr, sz, 1, f) != 1) {