Merge branches 'bw/ls-files-sans-the-index' and 'bw/config-h' into bw/repo-object
authorJunio C Hamano <gitster@pobox.com>
Wed, 21 Jun 2017 22:20:44 +0000 (15:20 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 24 Jun 2017 01:24:00 +0000 (18:24 -0700)
* bw/ls-files-sans-the-index:
ls-files: factor out tag calculation
ls-files: factor out debug info into a function
ls-files: convert show_files to take an index
ls-files: convert show_ce_entry to take an index
ls-files: convert prune_cache to take an index
ls-files: convert ce_excluded to take an index
ls-files: convert show_ru_info to take an index
ls-files: convert show_other_files to take an index
ls-files: convert show_killed_files to take an index
ls-files: convert write_eolinfo to take an index
ls-files: convert overlay_tree_on_cache to take an index
tree: convert read_tree to take an index parameter
convert: convert renormalize_buffer to take an index
convert: convert convert_to_git to take an index
convert: convert convert_to_git_filter_fd to take an index
convert: convert crlf_to_git to take an index
convert: convert get_cached_convert_stats_ascii to take an index

* 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
alias: use the early config machinery to expand aliases
t7006: demonstrate a problem with aliases in subdirectories
t1308: relax the test verifying that empty alias values are disallowed
help: use early config when autocorrecting aliases
config: report correct line number upon error
discover_git_directory(): avoid setting invalid git_dir

102 files changed:
1  2  3 
apply.c
archive-tar.c
archive-zip.c
archive.c
attr.c
bisect.c
blame.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
combine-diff.c
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
t/t1300-repo-config.sh
t/t1308-config-set.sh
transport.c
unpack-trees.c
upload-pack.c
wrapper.c
xdiff-interface.c
diff --combined apply.c
index 854faa67795bcd356b33420f46260f208c2ec047,97afb6f60a28b8b42d36b4d376db6156757f8c80,5b442860df2f4fdb0137ac8036269308bc173624..65063785c1651ed288133788980a1a8d0a410cbd
+++ b/apply.c
@@@@ -8,6 -8,6 -8,7 +8,7 @@@@
    */
   
   #include "cache.h"
++ #include "config.h"
   #include "blob.h"
   #include "delta.h"
   #include "diff.h"
@@@@ -2267,7 -2267,7 -2268,7 +2268,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;
@@@@ -3741,7 -3741,7 -3742,7 +3742,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;
@@@@ -4091,181 -4091,181 -4092,181 +4092,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 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 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)) {
                        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,073e60ebd3c366b42298ae443eee230407d4e3a7,d65ac016df09ccdb7bc7952291de12ec5912bc8d..c6ed96ee74ec10f5c9ffb6f520193326d4704b6b
@@@@ -2,6 -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 -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,27563e9e2602108997033e6fa79c660bc08aa863,04fcd86872496837ddcc9bf354ce5ff5e878236d..e8913e5a26c6e97216c4b79ad96b5e3ddf906c45
@@@@ -2,6 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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,b15a922dab56a525ca3ce7f1143d215fe39f3132,0cba5b4096fe9ec7b1919bf099a667806f16f36c..60b3035a7a6a9e7c2e69b4ba7de00ebdf8bfdbb8
+++ b/archive.c
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "refs.h"
   #include "commit.h"
   #include "tree-walk.h"
@@@@ -360,7 -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,7e2134471cb4afc1b891208ebe4bebd6ad55571d,9f8b029363f3dca3ffd968c5649581b3654a622e..6e4b247acd91d30ac5a879183332725d54e756a0
--- 1/attr.c
--- 2/attr.c
--- 3/attr.c
+++ b/attr.c
@@@@ -9,6 -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 -720,16 -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,c952df692bef9ba1638e55448050db33ba76d399,e8f03a08c494f30e4fa6af7138b4f1ba7dadfd77..a9fd9fbc61a661ab19e18713b115f868daab2f98
+++ b/bisect.c
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "commit.h"
   #include "diff.h"
   #include "revision.h"
@@@@ -438,7 -438,10 -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 -546,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 -669,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 -705,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 -995,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 blame.c
index 194b58e96066f9620005f64a57ca9ecc618c86f4,a6f3d72df8fbc45a14214029491d5c06a73cefa5,0000000000000000000000000000000000000000..6d57ab9715665a8bc6a2ba02015342ad851b6d2f
mode 100644,100644,000000..100644
--- /dev/null
+++ b/blame.c
@@@@ -1,1863 -1,1863 -1,0 +1,1863 @@@@
-       convert_to_git(path, buf.buf, buf.len, &buf, 0);
  +#include "cache.h"
  +#include "refs.h"
  +#include "cache-tree.h"
  +#include "mergesort.h"
  +#include "diff.h"
  +#include "diffcore.h"
  +#include "tag.h"
  +#include "blame.h"
  +
  +void blame_origin_decref(struct blame_origin *o)
  +{
  +     if (o && --o->refcnt <= 0) {
  +             struct blame_origin *p, *l = NULL;
  +             if (o->previous)
  +                     blame_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");
  +     }
  +}
  +
  +/*
  + * 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 blame_origin *make_origin(struct commit *commit, const char *path)
  +{
  +     struct blame_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 blame_origin *get_origin(struct commit *commit, const char *path)
  +{
  +     struct blame_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 blame_origin_incref(o);
  +             }
  +     }
  +     return make_origin(commit, path);
  +}
  +
  +
  +
  +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);
  +     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 blame_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");
  +     }
 -              diff_tree_sha1(parent->tree->object.oid.hash,
 -                             origin->commit->tree->object.oid.hash,
 -                             "", &diff_opts);
+ +     convert_to_git(&the_index, 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 int diff_hunks(mmfile_t *file_a, mmfile_t *file_b,
  +                   xdl_emit_hunk_consume_func_t hunk_func, void *cb_data, int xdl_opts)
  +{
  +     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);
  +}
  +
  +/*
  + * Given an origin, prepare mmfile_t structure to be used by the
  + * diff machinery
  + */
  +static void fill_origin_blob(struct diff_options *opt,
  +                          struct blame_origin *o, mmfile_t *file, int *num_read_blob)
  +{
  +     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;
  +}
  +
  +static void drop_origin_blob(struct blame_origin *o)
  +{
  +     if (o->file.ptr) {
  +             free(o->file.ptr);
  +             o->file.ptr = NULL;
  +     }
  +}
  +
  +/*
  + * 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;
  +}
  +
  +void blame_sort_final(struct blame_scoreboard *sb)
  +{
  +     sb->ent = llist_mergesort(sb->ent, get_next_blame, set_next_blame,
  +                               compare_blame_final);
  +}
  +
  +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);
  +}
  +
  +/*
  + * For debugging -- origin is refcounted, and this asserts that
  + * we do not underflow.
  + */
  +static void sanity_check_refcnt(struct blame_scoreboard *sb)
  +{
  +     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)
  +             sb->on_sanity_fail(sb, baa);
  +}
  +
  +/*
  + * 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.
  + */
  +void blame_coalesce(struct blame_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;
  +                     blame_origin_decref(next->suspect);
  +                     free(next);
  +                     ent->score = 0;
  +                     next = ent; /* again */
  +             }
  +     }
  +
  +     if (sb->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 blame_scoreboard *sb, struct blame_origin *porigin,
  +                      struct blame_entry *sorted)
  +{
  +     if (porigin->suspects)
  +             porigin->suspects = blame_merge(porigin->suspects, sorted);
  +     else {
  +             struct blame_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);
  +     }
  +}
  +
  +/*
  + * 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 blame_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 blame_origin *find_origin(struct commit *parent,
  +                               struct blame_origin *origin)
  +{
  +     struct blame_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 blame_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, &diff_opts);
  +     else
 -              diff_tree_sha1(parent->tree->object.oid.hash,
 -                             origin->commit->tree->object.oid.hash,
 -                             "", &diff_opts);
 ++             diff_tree_oid(&parent->tree->object.oid,
 ++                           &origin->commit->tree->object.oid,
 ++                           "", &diff_opts);
  +     diffcore_std(&diff_opts);
  +
  +     if (!diff_queued_diff.nr) {
  +             /* The path is the same as parent */
  +             porigin = get_origin(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(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 blame_origin *find_rename(struct commit *parent,
  +                               struct blame_origin *origin)
  +{
  +     struct blame_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, &diff_opts);
  +     else
 -       * force diff_tree_sha1() to feed all filepairs to diff_queue,
 ++             diff_tree_oid(&parent->tree->object.oid,
 ++                           &origin->commit->tree->object.oid,
 ++                           "", &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(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));
  +     blame_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)
  +{
  +     blame_origin_incref(src->suspect);
  +     blame_origin_decref(dst->suspect);
  +     memcpy(dst, src, sizeof(*src));
  +     dst->next = **queue;
  +     **queue = dst;
  +     *queue = &dst->next;
  +}
  +
  +const char *blame_nth_line(struct blame_scoreboard *sb, long lno)
  +{
  +     return sb->final_buf + sb->lineno[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 blame_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 = blame_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 = blame_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 = blame_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++)
  +             blame_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 blame_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
  +                     blame_origin_decref(e->suspect);
  +             /* Pass blame for everything before the differing
  +              * chunk to the parent */
  +             e->suspect = blame_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 = blame_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 blame_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 blame_scoreboard *sb,
  +                              struct blame_origin *target,
  +                              struct blame_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, &sb->num_read_blob);
  +     fill_origin_blob(&sb->revs->diffopt, target, &file_o, &sb->num_read_blob);
  +     sb->num_get_patch++;
  +
  +     if (diff_hunks(&file_p, &file_o, blame_chunk_cb, &d, sb->xdl_opts))
  +             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.
  + */
  +unsigned blame_entry_score(struct blame_scoreboard *sb, struct blame_entry *e)
  +{
  +     unsigned score;
  +     const char *cp, *ep;
  +
  +     if (e->score)
  +             return e->score;
  +
  +     score = 1;
  +     cp = blame_nth_line(sb, e->lno);
  +     ep = blame_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 blame_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 (blame_entry_score(sb, &this[1]) < blame_entry_score(sb, &best_so_far[1]))
  +                     return;
  +     }
  +
  +     for (i = 0; i < 3; i++)
  +             blame_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 blame_scoreboard *sb,
  +                      struct blame_entry *ent,
  +                      int tlno, int plno, int same,
  +                      struct blame_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 blame_scoreboard *sb;
  +     struct blame_entry *ent;
  +     struct blame_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 blame_scoreboard *sb,
  +                           struct blame_entry *ent,
  +                           struct blame_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 = blame_nth_line(sb, ent->lno);
  +     file_o.ptr = (char *) cp;
  +     file_o.size = blame_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, sb->xdl_opts))
  +             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 blame_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 (blame_entry_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 blame_scoreboard *sb,
  +                             struct blame_entry ***blamed,
  +                             struct blame_entry **toosmall,
  +                             struct blame_origin *target,
  +                             struct blame_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, &sb->num_read_blob);
  +     if (!file_p.ptr)
  +             return;
  +
  +     /* 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 &&
  +                         sb->move_score < blame_entry_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, sb->move_score);
  +     } while (unblamed);
  +     target->suspects = reverse_blame(leftover, NULL);
  +}
  +
  +struct blame_list {
  +     struct blame_entry *ent;
  +     struct blame_entry split[3];
  +};
  +
  +/*
  + * 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 blame_scoreboard *sb,
  +                             struct blame_entry ***blamed,
  +                             struct blame_entry **toosmall,
  +                             struct blame_origin *target,
  +                             struct commit *parent,
  +                             struct blame_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
 -              diff_tree_sha1(parent->tree->object.oid.hash,
 -                             target->commit->tree->object.oid.hash,
 -                             "", &diff_opts);
 ++      * force diff_tree_oid() 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, &diff_opts);
  +     else
 ++             diff_tree_oid(&parent->tree->object.oid,
 ++                           &target->commit->tree->object.oid,
 ++                           "", &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 blame_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(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, &sb->num_read_blob);
  +                     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);
  +                     }
  +                     blame_origin_decref(norigin);
  +             }
  +
  +             for (j = 0; j < num_ents; j++) {
  +                     struct blame_entry *split = blame_list[j].split;
  +                     if (split[1].suspect &&
  +                         sb->copy_score < blame_entry_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, sb->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 blame_scoreboard *sb,
  +                          struct blame_origin *origin, struct blame_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) {
  +             blame_origin_incref(porigin);
  +             blame_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,
  +                                     int reverse)
  +{
  +     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, int reverse)
  +{
  +     struct commit_list *l = first_scapegoat(revs, commit, reverse);
  +     return commit_list_count(l);
  +}
  +
  +/* Distribute collected unsorted blames to the respected sorted lists
  + * in the various origins.
  + */
  +static void distribute_blame(struct blame_scoreboard *sb, struct blame_entry *blamed)
  +{
  +     blamed = llist_mergesort(blamed, get_next_blame, set_next_blame,
  +                              compare_blame_suspect);
  +     while (blamed)
  +     {
  +             struct blame_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 blame_scoreboard *sb, struct blame_origin *origin, int opt)
  +{
  +     struct rev_info *revs = sb->revs;
  +     int i, pass, num_sg;
  +     struct commit *commit = origin->commit;
  +     struct commit_list *sg;
  +     struct blame_origin *sg_buf[MAXSG];
  +     struct blame_origin *porigin, **sg_origin = sg_buf;
  +     struct blame_entry *toosmall = NULL;
  +     struct blame_entry *blames, **blametail = &blames;
  +
  +     num_sg = num_scapegoats(revs, commit, sb->reverse);
  +     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 - sb->no_whole_file_rename; pass++) {
  +             struct blame_origin *(*find)(struct commit *, struct blame_origin *);
  +             find = pass ? find_rename : find_origin;
  +
  +             for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
  +                  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(p, origin);
  +                     if (!porigin)
  +                             continue;
  +                     if (!oidcmp(&porigin->blob_oid, &origin->blob_oid)) {
  +                             pass_whole_blame(sb, origin, porigin);
  +                             blame_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
  +                             blame_origin_decref(porigin);
  +             }
  +     }
  +
  +     sb->num_commits++;
  +     for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
  +          i < num_sg && sg;
  +          sg = sg->next, i++) {
  +             struct blame_origin *porigin = sg_origin[i];
  +             if (!porigin)
  +                     continue;
  +             if (!origin->previous) {
  +                     blame_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, sb->move_score);
  +             if (origin->suspects) {
  +                     for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
  +                          i < num_sg && sg;
  +                          sg = sg->next, i++) {
  +                             struct blame_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 (sb->copy_score > sb->move_score)
  +                     filter_small(sb, &toosmall, &origin->suspects, sb->copy_score);
  +             else if (sb->copy_score < sb->move_score) {
  +                     origin->suspects = blame_merge(origin->suspects, toosmall);
  +                     toosmall = NULL;
  +                     filter_small(sb, &toosmall, &origin->suspects, sb->copy_score);
  +             }
  +             if (!origin->suspects)
  +                     goto finish;
  +
  +             for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
  +                  i < num_sg && sg;
  +                  sg = sg->next, i++) {
  +                     struct blame_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]);
  +                     blame_origin_decref(sg_origin[i]);
  +             }
  +     }
  +     drop_origin_blob(origin);
  +     if (sg_buf != sg_origin)
  +             free(sg_origin);
  +}
  +
  +/*
  + * 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. */
  +void assign_blame(struct blame_scoreboard *sb, int opt)
  +{
  +     struct rev_info *revs = sb->revs;
  +     struct commit *commit = prio_queue_get(&sb->commits);
  +
  +     while (commit) {
  +             struct blame_entry *ent;
  +             struct blame_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.
  +              */
  +             blame_origin_incref(suspect);
  +             parse_commit(commit);
  +             if (sb->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 && !sb->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;
  +                             if (sb->found_guilty_entry)
  +                                     sb->found_guilty_entry(ent, sb->found_guilty_entry_data);
  +                             if (next) {
  +                                     ent = next;
  +                                     continue;
  +                             }
  +                             ent->next = sb->ent;
  +                             sb->ent = suspect->suspects;
  +                             suspect->suspects = NULL;
  +                             break;
  +                     }
  +             }
  +             blame_origin_decref(suspect);
  +
  +             if (sb->debug) /* sanity */
  +                     sanity_check_refcnt(sb);
  +     }
  +}
  +
  +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 blame_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;
  +}
  +
  +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 struct commit *dwim_reverse_initial(struct rev_info *revs,
  +                                        const char **name_p)
  +{
  +     /*
  +      * 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;
  +     struct object_id head_oid;
  +
  +     if (revs->pending.nr != 1)
  +             return NULL;
  +
  +     /* Is that sole rev a committish? */
  +     obj = 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_oid.hash, NULL))
  +             return NULL;
  +     head_commit = lookup_commit_reference_gently(&head_oid, 1);
  +     if (!head_commit)
  +             return NULL;
  +
  +     /* Turn "ONE" into "ONE..HEAD" then */
  +     obj->flags |= UNINTERESTING;
  +     add_pending_object(revs, &head_commit->object, "HEAD");
  +
  +     if (name_p)
  +             *name_p = revs->pending.objects[0].name;
  +     return (struct commit *)obj;
  +}
  +
  +static struct commit *find_single_initial(struct rev_info *revs,
  +                                       const char **name_p)
  +{
  +     int i;
  +     struct commit *found = NULL;
  +     const char *name = NULL;
  +
  +     /*
  +      * 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 (found)
  +                     die("More than one commit to dig up from, %s and %s?",
  +                         revs->pending.objects[i].name, name);
  +             found = (struct commit *) obj;
  +             name = revs->pending.objects[i].name;
  +     }
  +
  +     if (!name)
  +             found = dwim_reverse_initial(revs, &name);
  +     if (!name)
  +             die("No commit to dig up from?");
  +
  +     if (name_p)
  +             *name_p = name;
  +     return found;
  +}
  +
  +void init_scoreboard(struct blame_scoreboard *sb)
  +{
  +     memset(sb, 0, sizeof(struct blame_scoreboard));
  +     sb->move_score = BLAME_DEFAULT_MOVE_SCORE;
  +     sb->copy_score = BLAME_DEFAULT_COPY_SCORE;
  +}
  +
  +void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blame_origin **orig)
  +{
  +     const char *final_commit_name = NULL;
  +     struct blame_origin *o;
  +     struct commit *final_commit = NULL;
  +     enum object_type type;
  +
  +     if (sb->reverse && sb->contents_from)
  +             die(_("--contents and --reverse do not blend well."));
  +
  +     if (!sb->reverse) {
  +             sb->final = find_single_final(sb->revs, &final_commit_name);
  +             sb->commits.compare = compare_commits_by_commit_date;
  +     } else {
  +             sb->final = find_single_initial(sb->revs, &final_commit_name);
  +             sb->commits.compare = compare_commits_by_reverse_commit_date;
  +     }
  +
  +     if (sb->final && sb->contents_from)
  +             die(_("cannot use --contents with final commit object name"));
  +
  +     if (sb->reverse && sb->revs->first_parent_only)
  +             sb->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, sb->contents_from);
  +             add_pending_object(sb->revs, &(sb->final->object), ":");
  +     }
  +
  +     if (sb->reverse && sb->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(sb->revs))
  +             die(_("revision walk setup failed"));
  +
  +     if (sb->reverse && sb->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->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);
  +     }
  +     sb->num_read_blob++;
  +     prepare_lines(sb);
  +
  +     if (orig)
  +             *orig = o;
  +}
  +
  +
  +
  +struct blame_entry *blame_entry_prepend(struct blame_entry *head,
  +                                     long start, long end,
  +                                     struct blame_origin *o)
  +{
  +     struct blame_entry *new_head = xcalloc(1, sizeof(struct blame_entry));
  +     new_head->lno = start;
  +     new_head->num_lines = end - start;
  +     new_head->suspect = o;
  +     new_head->s_lno = start;
  +     new_head->next = head;
  +     blame_origin_incref(o);
  +     return new_head;
  +}
diff --combined branch.c
index 985316eb76505a60bca0aa303322bef35e7defaa,985316eb76505a60bca0aa303322bef35e7defaa,5532b4218f086372ee6601b08d4a2caaec5dc7bf..a8a548ccf2870c99bbdbcdc7036003aa648faa0c
+++ b/branch.c
@@@@ -1,5 -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 -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 -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 -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,d9a2491e48f16d9ef7de5c05008f8c7e6a5e64b2,55759a6a78ab540562370e7af30864e0366ac04c..f2415e99f37d48e562913c17d8917bda4f892c09
@@@@ -4,6 -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"
   #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 -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,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,5ee146bfb31df8e3d8edf356f4817e3f53f8ad3b,59f46a29eea99665a94dcde31b885f61b5f6305d..7c7b916d2328be8e6dc7abb7e08bb9416b21d2e6
@@@@ -4,6 -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 -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 -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 -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 -1275,12 -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 -1351,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 -1444,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 -1479,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 -1609,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 -1674,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 -1931,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 -2037,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 -2148,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 -2311,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,d7a2df3b47439c5564a716402e815e0da4f0d8a9,1a7371808ad4615052e92b792149ad7f84845776..bda1a787265e6d44d2ec0bec1e4dee5bf8de9c3b
    */
   
   #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"
   #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 -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 -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 -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 -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 -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,83fcda43dceec0255c6164eb42a35d3d89011efb,50b59238d4d3683f955321c0f58c5947a82aca6b..c958e93257910816bd8d40673805e8553f921f3f
@@@@ -6,6 -6,6 -6,7 +6,7 @@@@
    */
   
   #include "cache.h"
++ #include "config.h"
   #include "color.h"
   #include "refs.h"
   #include "commit.h"
@@@@ -124,7 -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 -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 -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,4bffd7a2d8eee2ea251afef70f63f646f184a339,12451205cf8929c25c57f6a2d7f7a1a0a5f11fa4..7efbc4019ac59a16ae4f147889e6f489dac1e661
@@@@ -4,8 -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,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,c7b8c08897193e225d8da32f4d402def3f16fe50,a2da09f4aec3bd68e26587250763648c1efb181b..3e280b9c7aa9c93c8e7572a4fe3f7ef3ac92b3af
   #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,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,a6b2af39d3e881480193a38ff1ca3b65cdc55d94,e0b58ddc0b6c7dcfc05b7576eaf2eec77e31616f..9661e1bcba31ffa4f7b8a2fb1a9d2060cb8efda7
@@@@ -1,4 -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 -235,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 -395,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 -529,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 -723,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 -809,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 -835,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 -876,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 -1050,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 -1184,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,142bf668cffe814006fae791f1bdc6b20fe6f366,57093db8be9953c37bd480bdb237cd08871ac535..ed954134d2dd03242a06eef88bcaec71cc41ffe9
@@@@ -8,6 -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 -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 -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,743f16ae2aad7d71789f2b38287aea13cf29fc26,eaacac221b193b2243416a320e1125c63881b310..08b5cc433c6fcad5eea2dfc3321aea28a599d51f
@@@@ -9,6 -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 -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,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 -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 -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 -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 -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 -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 -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,f39c2b27375fcd70f050e56174b0966053652eef,e1c17ba64b0346a35778dac48a66203418c119aa..a4a923d7c0b688e162c8e4d0411ff9b72748fb5c
@@@@ -4,6 -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 -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 e3c9e190b06a63250a9c7eff3e256efcb10660f7,78ef319a2418066a34f1f3c47049b7500f3f0f07,929a45abed7067c80ca05662124fe962cd0f61bf..021070e693e78fe49a168f842f64aeea73de4a8b
@@@@ -6,6 -6,6 -6,7 +6,7 @@@@
    */
   
   #include "cache.h"
++ #include "config.h"
   #include "lockfile.h"
   #include "cache-tree.h"
   #include "color.h"
@@@@ -253,7 -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);
        }
   
@@@@ -313,7 -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);
@@@@ -1263,10 -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;
   }
   
@@@@ -1434,7 -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))
@@@@ -1658,7 -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,7f6c25d4d95b37f7785e0b6872d059095548c87f,1fc6471f37a061318ea16442a15c378c49648188..82db29fae71551a44150c64a4c1187ef4ebd572a
@@@@ -1,5 -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 -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 -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 -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 -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 -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,893c8789f4f563c58041040740384322e6ea205b,3eddfd37061ebe5a347cc65a829a2edf65883a80..70eb1446089583cd859ea1f05b260283cd78067f
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "lockfile.h"
   #include "commit.h"
   #include "tag.h"
@@@@ -79,13 -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 -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 -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,a572da9d5152ddf541f71e1aaf8abdb3c98f8ffe,29d3e4f416746eda53c9d599d4adf92966ffff09..17bf84d18f802d3f223e7408fee644b94878b35f
@@@@ -4,6 -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 -20,9 -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,f084826a293f96870d0cf6be05e3e346672fc5dc,e3d418361c7db8b4206019898d4373f31169652f..185e6f9b582fdcf15072038b570463a0cfb1bbf2
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "diff.h"
   #include "commit.h"
   #include "revision.h"
@@@@ -17,12 -17,9 -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,e401112045023e990537a4ffe25c19487b31a30b,c81063d534f87a0d6d6ee768fab2253144674279..31d2cb410738d335d9f6431d6901ea1c0f8b67ff
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "diff.h"
   #include "commit.h"
   #include "log-tree.h"
@@@@ -7,9 -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 -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 -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 -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 -98,16 -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,0c8f86e40da6537d57f5ed6ca0ecdd005e29c8f5,1ce40c63b23cdec6f0f9c22bbce351acdf3effed..7cde6abbcf7651af8313bd3d70eb1944e72c9cb3
@@@@ -4,6 -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->hash, old_oid_valid, old_mode);
 -      fill_filespec(two, new_oid->hash, new_oid_valid, new_mode);
 ++     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 -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 -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 -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,b9a892f2693efe01a08c958f7064f13ba6ec43aa,538b0187faf8738b7056ba4999a2082232bf0ee1..9199227f6e9dc0b6d0c3e350f701aeaf9caaddd3
    * Copyright (C) 2016 Johannes Schindelin
    */
   #include "cache.h"
++ #include "config.h"
   #include "builtin.h"
   #include "run-command.h"
   #include "exec_cmd.h"
@@@@ -226,7 -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,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,24e29ad7eab5edc0964a51f32602b062daabb907,e4304e2dd6550d434138c9e2b9261f66645146c5..12d501bfde3aac09c411169f99ff28ad35593a3b
@@@@ -5,6 -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 -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 -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 -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 -907,9 -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,47708451bc5e124f9c6da4de60cc476a5d2c1f10,1fe8f6238557d932b02fb2f5dabf85eb863450b1..16cf8421ce4cc2221e6ed59110928328693481fb
@@@@ -2,6 -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 -73,6 -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 -636,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 -770,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 -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,70137b0b7e56e6319872fddc3527fe1094009dee,2e30b514f2d19c6a87ad6f0ebcde7a27a54f0be5..10cbb434163f2f6e60e0cc9cb55bab220004a549
@@@@ -1,5 -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 -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 -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 -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,cb2ba6cd1be46635ca8416a7d3f2b006f964190b,0c63f6259f4912cdaca446c1097164455cc5f70f..87c675689986413f4c2ace09701adccf6e836942
@@@@ -1,5 -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 -280,8 -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 -377,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 -444,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 -506,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 -599,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 -781,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,f484eda43ca06046924931d2055b50c2f89ea8d7,0a6790d7144aae8258048b111effe9c1fc361cf0..bd91f136fed125ab06502c22b74b4f193f60773a
    */
   
   #include "builtin.h"
++ #include "config.h"
   #include "tempfile.h"
   #include "lockfile.h"
   #include "parse-options.h"
@@@@ -33,7 -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,7df9c253eebb3053693769d14efe0551393dfd4d,3df9e08f0368024dd067d5897bf46c83a7cbfdfc..f61a9d938b44424414812c57eecc309bd563f4b3
@@@@ -4,6 -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 -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 -224,7 -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 -289,19 -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 -338,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 -506,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 -583,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 -788,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 -879,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 -1167,8 -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,04b9dcaf0f4ca90712cbb85cace521e226194f3b,dfb3d1296a220b92bffc674701f1b060a946eb08..edc1a91d89b308b1e164c48c1dfb06c8f6ebf0d1
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "builtin.h"
++ #include "config.h"
   #include "delta.h"
   #include "pack.h"
   #include "csum-file.h"
@@@@ -747,13 -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 -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,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 -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 -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 -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 -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,e89ec941ce2c97de7f8233a5e7e6f9010fabdb64,b333d4fea23ccf144b61b41a6faf8e294f8b1402..8ca1de98943bdc62248ddd31708a6632557c61de
@@@@ -5,6 -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 -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 -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 -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 -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 -846,8 -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 -882,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 -1047,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 -1267,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 -1358,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 -1823,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 b376afc3124c3240f4f249ccc206efa0b064675e,cdc1cfdd26a95c54cc23717ce53c20a9d1607c90,975101078071dc48c09024830c4a621e3891cefb..b12d0bb61240890b3145baa8f051c83005b97dbe
@@@@ -6,6 -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 -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,34 -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.
@@@@ -230,7 -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, &the_index, ce->name, &dtype);
  -     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, &the_index, &pathspec);
  -             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;
@@@@ -643,7 -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_cache(max_prefix, max_prefix_len);
+ +     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,ee7b293b11eb5c73dd6fe1ea31c5d3bf52c79656,4b53a8282b84cc5ce0c9b20ce776031ae457551e..ef965408e8fc5d80fa9e9daf0264a91abccd978c
@@@@ -4,6 -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 -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,0c36a70ad8f4dba1744ba6c4fa93389e2b796925,9c201cbfc0357d622b90714e3d1795a401eda51d..6dbd167d3b0874cd966b4590951a12d01f8f6aeb
@@@@ -1,5 -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 -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 -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 -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,a4a098f40f8e3e61c3f8b730a6b22a83c3c23566,9bdd577e0959d19ee3f0234b20f375d838cc008e..900bafdb45d0b28ab5497cfd251535266fc92be5
@@@@ -7,6 -7,6 -7,7 +7,7 @@@@
    */
   
   #include "cache.h"
++ #include "config.h"
   #include "parse-options.h"
   #include "builtin.h"
   #include "lockfile.h"
@@@@ -415,7 -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 -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 -839,9 -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 -1123,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,7fc7e66e8500b82cbfecc21a1dce77e09de28ab0,c222daaa143fb8bdb9961f42ba7fe8ca2dd9f32d..e21715f1d0874171bcda2486adb4d27ea5cbbc99
@@@@ -1,5 -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);
   
                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 -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 -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 -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,7196bff0eb2454eee86f87241706523c0266e66e,dceb681bad19e94f30cd58b901033d472423e8ea..77573cf1ea8cb4d998597e265263487e22fde592
@@@@ -8,6 -8,6 -8,7 +8,7 @@@@
    */
   
   #include "cache.h"
++ #include "config.h"
   #include "builtin.h"
   #include "notes.h"
   #include "blob.h"
@@@@ -109,11 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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,f672225def033595602bc4ff91ee26edd9804944,0e17184354eba004c9f529924b02df979d6bc522..d5e96ed2d0ce0d74a40961f6729896722dacf9a2
@@@@ -1,5 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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,da8b60fc85e93da880fb955992b8b753715fafda,3632921f03bb318663617b3923d8f04d21d0126e..2ce311a52eb6111fd16951c860d194dc35300438
@@@@ -6,6 -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 -337,8 -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 -523,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 -698,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 -772,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,a597759d8fac205f41c406d0a0e32f9240941190,76aa713d22357fdd732ae86a99c49b43b0155801..03846e83795c477c8e802d078c5a5ed77140d550
@@@@ -2,6 -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 -498,6 -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,78d3193659e06b4969324153689f219f1cd1c1b3,0a85b6d938806986da06e83afeaa55a6930eca34..d5f618d086365520fcf36ed8db110ba701ba37d3
@@@@ -5,6 -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 -99,21 -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,b1706a5731c0e527a8abc1d42ac4f0e6d346c47c,01ae7154e681cd249bdee78507311274fe568628..71c0c768db92378b824951acd6efb7179438017b
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "builtin.h"
++ #include "config.h"
   #include "lockfile.h"
   #include "pack.h"
   #include "refs.h"
@@@@ -78,7 -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 -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 -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 -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 -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 -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,920c16dac025b0f5650b0f91511c22359d5bda2d,6e9a8213ea6ab2bbfec95cc24bcc72af8f25dea2..44cdc2dbd0cbf64be1672428e930223425ed7b04
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "builtin.h"
++ #include "config.h"
   #include "lockfile.h"
   #include "commit.h"
   #include "refs.h"
@@@@ -16,14 -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 -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)
        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;
        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 -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 -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 -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 -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 -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 -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,f1a88fe2658986af2e33d3979af1764f6decc43b,a470ed7c628254f76b3e6a46c889e66097f48f4f..6273c0c23c904d5f789ff794458cf0c3f2661d94
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "builtin.h"
++ #include "config.h"
   #include "parse-options.h"
   #include "transport.h"
   #include "remote.h"
@@@@ -786,7 -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 -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 -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,38ba4ef825ebf4791afb50e72e69bdb61db2aa14,c01ff7c30b20ae3866c81ada2aa859eb9c13cdee..f17a68a17da960813e6e925837638a5d9a26d5ee
@@@@ -1,5 -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 -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,c921bc976f2299adc39277a21a74abbcc0c100f7,905b1759a4ae4f6819770c832c0b28b7e5fde086..80a15cf35f3fa5a1a7c038924a84e34fdc15aa0b
@@@@ -9,6 -9,6 -9,7 +9,7 @@@@
    */
   
   #include "cache.h"
++ #include "config.h"
   #include "builtin.h"
   #include "refs.h"
   #include "parse-options.h"
@@@@ -328,7 -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 -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 -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,430602d102133d125009e8c8068ce5547c24cab7,fdd5e5e003484b97a9915540642c34943abb1423..7aeaea2737991f021eb788708c1710305abb4b08
@@@@ -8,6 -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"
   #include "parse-options.h"
   #include "unpack-trees.h"
   #include "cache-tree.h"
  +#include "submodule.h"
  +#include "submodule-config.h"
   
 - static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 - 
 - 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;
 - }
 - 
   static const char * const git_reset_usage[] = {
        N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
        N_("git reset [-q] [<tree-ish>] [--] <paths>..."),
@@@@ -86,7 -105,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 -175,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 -257,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 -284,6 -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", &recurse_submodules,
 ++             { OPTION_CALLBACK, 0, "recurse-submodules", NULL,
  +                         "reset", "control recursive updating of submodules",
 -                          PARSE_OPT_OPTARG, option_parse_recurse_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);
   
 -      if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) {
 -              gitmodules_config();
 -              git_config(submodule_config, NULL);
 -              set_config_update_recurse_submodules(RECURSE_SUBMODULES_ON);
 -      }
 ++     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,718c6059c9f570d94b0bdba46d33ed1b065a34f7,f9e2caee16c4295f2acdddc9565406cccb5073d1..95d84d5cda1bdb6a699bc74ad57f7f1910946440
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "commit.h"
   #include "diff.h"
   #include "revision.h"
@@@@ -80,7 -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 -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 -277,6 -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,efdc14473be53ff79b13012d650ec5fded052fd9,9d18bbd648bcf39b9406ced43a731fe08e83c8b0..c78b7b33d6604bb38a16e30d64cfabee0fd67f40
@@@@ -4,6 -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 -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 -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 -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 -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 -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 -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,7c323d01235bf8bbb341004c843761dad99590d2,b1adf1c961632336b1f630e4b3c8d085006d4431..52826d137935ca6698006258ebdb8b207f7161df
@@@@ -4,6 -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 -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 -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 4a6cc6f490f4e7b8a98adb362213535b6a9ae97d,4a6cc6f490f4e7b8a98adb362213535b6a9ae97d,68254399709c2a0cddfb42717831e198e511ae68..e4cf1b5bb25e14b54e29d0b467e94a374ec9c9d5
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "commit.h"
   #include "refs.h"
   #include "builtin.h"
@@@@ -358,7 -358,7 -359,7 +359,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)
@@@@ -735,7 -735,7 -736,7 +736,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,8cc648d85b586752d39079e75cf81a4ee685b622,700460c3498abbad9e3f087ee50bc5dd8f513b1b..8517032b3e08ded36075ded55dac8ae219cfbc59
@@@@ -1,5 -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 -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 -1221,9 -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,1f74a56db749a5e1ffa06715e347cdc1b041033b,b85bcf680980d6934219fa63c8c0fee374ccfd20..01154ea8dcca869ed635eb433d5afe879b8e883c
@@@@ -7,6 -7,6 -7,7 +7,7 @@@@
    */
   
   #include "cache.h"
++ #include "config.h"
   #include "builtin.h"
   #include "refs.h"
   #include "tag.h"
@@@@ -66,7 -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 -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 -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 -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,8bc9997767adbb77cc8af81b2b289e22f2b61c5a,9da06548f03224d35f6de12eec481a1449d05b17..193f8b9d57f0759c38004fd1d99f660919ac30e3
@@@@ -1,5 -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 -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 -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 -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 -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 -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 -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 -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,ebfc09faa0d604218af8f5815af5e5fee5915158,0a4c2364879313b9a1a5cae653fee0642b2d403d..56721cf03db23a2f5a1b8e9419422df916d7b00f
@@@@ -4,6 -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 -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,05b734e6d1bd469b63aa7b51921622a590730b6d,d5e9a17a77aa0eae71118e1ce27ded90b267a008..ba38ac9b1518884693e2c89ec19cc9e00fce9fa3
@@@@ -6,6 -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 -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,793306ea5162f1c3e9663c0c99d693b88baaea3d,d414b6870b3109b895c4b4d37ca616a167c3a8c7..0c5476ee9de464cb0fae22c49775bc10efb0731b
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "builtin.h"
   #include "dir.h"
   #include "parse-options.h"
@@@@ -31,7 -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 -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 -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 d6ba8a2f11a63d4d9ec5257a75532414d22526c0,5a0e0a9e5d59a46b06058778c1f078a55e64edea,82f39f7a9e9ad17b39dc52c395eabbc70880325e..96055c222929e4ba307f3162b58740eccf165f2c
+++ b/cache.h
@@@@ -525,12 -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 -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 -1026,6 -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 -1334,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 -1370,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 -1486,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 -1872,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,7 -2186,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);
@@@@ -2212,8 -2206,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 combine-diff.c
index ec9d930440993b265fe74aacd2a3fdb768dccf64,74f723af3d08937a852a572c437605408dc0e30e,2848034fe9c3f3cc1d930347e892cee1cbed4f52..9e163d5adabd93fd48a6b563c5f31c32740e01c7
@@@@ -302,7 -302,7 -302,7 +302,7 @@@@ static char *grab_blob(const struct obj
                return xcalloc(1, 1);
        } else if (textconv) {
                struct diff_filespec *df = alloc_filespec(path);
 --             fill_filespec(df, oid->hash, 1, mode);
 ++             fill_filespec(df, oid, 1, mode);
                *size = fill_textconv(textconv, df, &blob);
                free_filespec(df);
        } else {
@@@@ -1022,7 -1022,7 -1022,7 +1022,7 @@@@ static void show_patch_diff(struct comb
                                                   &result_size, NULL, NULL);
                } else if (textconv) {
                        struct diff_filespec *df = alloc_filespec(elem->path);
 --                     fill_filespec(df, null_sha1, 0, st.st_mode);
 ++                     fill_filespec(df, &null_oid, 0, st.st_mode);
                        result_size = fill_textconv(textconv, df, &result);
                        free_filespec(df);
                } else if (0 <= (fd = open(elem->path, O_RDONLY))) {
                        if (is_file) {
                                struct strbuf buf = STRBUF_INIT;
   
- -                             if (convert_to_git(elem->path, result, len, &buf, safe_crlf)) {
+ +                             if (convert_to_git(&the_index, elem->path, result, len, &buf, safe_crlf)) {
                                        free(result);
                                        result = strbuf_detach(&buf, &len);
                                        result_size = len;
@@@@ -1311,7 -1311,7 -1311,7 +1311,7 @@@@ static const char *path_path(void *obj
   
   
   /* find set of paths that every parent touches */
 --static struct combine_diff_path *find_paths_generic(const unsigned char *sha1,
 ++static struct combine_diff_path *find_paths_generic(const struct object_id *oid,
        const struct oid_array *parents, struct diff_options *opt)
   {
        struct combine_diff_path *paths = NULL;
                        opt->output_format = stat_opt;
                else
                        opt->output_format = DIFF_FORMAT_NO_OUTPUT;
 --             diff_tree_sha1(parents->oid[i].hash, sha1, "", opt);
 ++             diff_tree_oid(&parents->oid[i], oid, "", opt);
                diffcore_std(opt);
                paths = intersect_paths(paths, i, num_parent);
   
    * rename/copy detection, etc, comparing all trees simultaneously (= faster).
    */
   static struct combine_diff_path *find_paths_multitree(
 --     const unsigned char *sha1, const struct oid_array *parents,
 ++     const struct object_id *oid, const struct oid_array *parents,
        struct diff_options *opt)
   {
        int i, nparent = parents->nr;
 --     const unsigned char **parents_sha1;
 ++     const struct object_id **parents_oid;
        struct combine_diff_path paths_head;
        struct strbuf base;
   
 --     ALLOC_ARRAY(parents_sha1, nparent);
 ++     ALLOC_ARRAY(parents_oid, nparent);
        for (i = 0; i < nparent; i++)
 --             parents_sha1[i] = parents->oid[i].hash;
 ++             parents_oid[i] = &parents->oid[i];
   
        /* fake list head, so worker can assume it is non-NULL */
        paths_head.next = NULL;
   
        strbuf_init(&base, PATH_MAX);
 --     diff_tree_paths(&paths_head, sha1, parents_sha1, nparent, &base, opt);
 ++     diff_tree_paths(&paths_head, oid, parents_oid, nparent, &base, opt);
   
        strbuf_release(&base);
 --     free(parents_sha1);
 ++     free(parents_oid);
        return paths_head.next;
   }
   
   
 --void diff_tree_combined(const unsigned char *sha1,
 ++void diff_tree_combined(const struct object_id *oid,
                        const struct oid_array *parents,
                        int dense,
                        struct rev_info *rev)
                 * diff(sha1,parent_i) for all i to do the job, specifically
                 * for parent0.
                 */
 --             paths = find_paths_generic(sha1, parents, &diffopts);
 ++             paths = find_paths_generic(oid, parents, &diffopts);
        }
        else {
                int stat_opt;
 --             paths = find_paths_multitree(sha1, parents, &diffopts);
 ++             paths = find_paths_multitree(oid, parents, &diffopts);
   
                /*
                 * show stat against the first parent even
                if (stat_opt) {
                        diffopts.output_format = stat_opt;
   
 --                     diff_tree_sha1(parents->oid[0].hash, sha1, "", &diffopts);
 ++                     diff_tree_oid(&parents->oid[0], oid, "", &diffopts);
                        diffcore_std(&diffopts);
                        if (opt->orderfile)
                                diffcore_order(opt->orderfile);
@@@@ -1539,6 -1539,6 -1539,6 +1539,6 @@@@ void diff_tree_combined_merge(const str
                oid_array_append(&parents, &parent->item->object.oid);
                parent = parent->next;
        }
 --     diff_tree_combined(commit->object.oid.hash, &parents, dense, rev);
 ++     diff_tree_combined(&commit->object.oid, &parents, dense, rev);
        oid_array_clear(&parents);
   }
diff --combined config.c
index 34a139c40bd57ff2dd23318beca53fd2e2948000,146cb3452adab3115f15d30c2b0f9f5480344279,ca9e9efec134a2a9380528e92567cfb3b9b6847e..6f0f8b30f39ba3a32d1a1795bdf12d78c5ea97f9
+++ b/config.c
@@@@ -6,6 -6,6 -6,7 +6,7 @@@@
    *
    */
   #include "cache.h"
++ #include "config.h"
   #include "lockfile.h"
   #include "exec_cmd.h"
   #include "strbuf.h"
@@@@ -214,12 -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);
@@@@ -604,7 -604,7 -587,8 +603,8 @@@@ static int get_value(config_fn_t fn, vo
         */
        cf->linenr--;
        ret = fn(name->buf, value, data);
--      cf->linenr++;
++      if (ret >= 0)
++              cf->linenr++;
        return ret;
   }
   
@@@@ -1438,7 -1438,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);
@@@@ -1545,10 -1545,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;
   
@@@@ -1612,9 -1612,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
@@@@ -1653,11 -1653,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);
@@@@ -1981,7 -1981,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);
        }
@@@@ -2637,7 -2637,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,c72b1d1151744c5e7c7b82f453892a1bc9b26021,efddb30ea870ee759dc3d1e6e9084a7b6e6ee23c..e78d3f43d84b7f90f4395cb289c9cf0cb34e8297
+++ b/connect.c
@@@@ -1,5 -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 -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 f1e168bc303c71542b692b2b9d08cdb2e2c98669,4097f521f240240fde1a3bfa8519515fdaac75f6,69f23cfcaa90993416eaa76303059f3bd389bf9a..7d2a519dafe5dcf892df10c51e1bfb83bc8a2091
+++ b/convert.c
+ +#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.
@@@@ -134,11 -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;
@@@@ -217,13 -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;
@@@@ -253,7 -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 ||
@@@@ -498,26 -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);
@@@@ -1081,7 -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);
   }
   
@@@@ -1160,14 -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,f3814cc47a059227e24ca52007c7e19fdf2db480,2787b29c05917f120503c8320fc0ec13cf48fd4c..0d5c6250940633e75e2c9fb4b59b242a52188411
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "tempfile.h"
   #include "credential.h"
   #include "unix-socket.h"
@@@@ -8,7 -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 -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 -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 acedf86aecc151112898ff54575151f157776281,976a6f91b189914570d1c688525a9ca5e3ef6505,4f9b9f83825ab1a79647969d360296b8311a33c8..41295d4ea9ff5564fa73d45aaa3afaab20103d87
--- 1/diff.c
--- 2/diff.c
--- 3/diff.c
+++ b/diff.c
@@@@ -2,6 -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"
   #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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -4071,9 -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 -4584,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 -4807,9 -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 -5081,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 -5244,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;
   }
   
 -      fill_filespec(df, oid->hash, oid_valid, mode);
  +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 17590638176f26e35f3a728e5cd56917e0568541,f673b86f31eb841ce0ecc34f49ab9ece2dd4d128,42beb65beaa03dbcf5fb312d7c280a1b3251614b..34445374ba60b5a2e8d1c2b6e96ba7dbdb18eb4c
--- 1/dir.c
--- 2/dir.c
--- 3/dir.c
+++ b/dir.c
@@@@ -7,8 -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,11 -46,11 -46,9 +47,11 @@@@ 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 fspathcmp(const char *a, const char *b)
   {
@@@@ -177,9 -177,9 -175,7 +178,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;
   }
@@@@ -592,8 -592,8 -588,7 +593,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;
   }
@@@@ -733,7 -733,7 -728,7 +734,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(fname))
+ +                              !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,
@@@@ -862,7 -862,7 -856,7 +863,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);
   }
   
@@@@ -965,8 -965,8 -959,7 +966,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;
@@@@ -1248,22 -1248,22 -1234,18 +1249,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);
@@@@ -1281,15 -1281,15 -1263,14 +1282,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);
   }
   
@@@@ -1477,13 -1477,13 -1456,12 +1478,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)
@@@@ -1788,9 -1788,9 -1760,9 +1789,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) {
@@@@ -2084,8 -2084,8 -2044,8 +2085,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;
                }
@@@@ -2337,7 -2337,7 -2273,7 +2338,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,aa478e71de9d9c233593de050d6823e96be77b88,9d9b367925d7d517b2240b8d59d8ca802452823e..d40b21fb72168f32f1aaeac553347859e32f90c0
@@@@ -8,6 -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 -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 -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 9a22fc92c0d029cf2a1362ea846f75f59978e870,e69d219682e7929b6e8441ba620e708704471ff3,bbc3e79eaf8ea5cb4d2bf56b530b610193e87924..94a1b06149479a11f3aa222cc7b0dba4cb94b1f0
@@@@ -154,6 -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 -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 -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 {
@@@@ -386,15 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -3285,9 -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,cd86865beba62ffade9f8aa63427781f301e79e7,963d45db911c37010dae86ea53d72ec75f7ef594..fbbc99c88856a773326e4bb310d30fe3021e2333
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "lockfile.h"
   #include "refs.h"
   #include "pkt-line.h"
   #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 -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 -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 -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 -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 -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 -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 -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 -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 1b8b7f51a65fa2a8e62d11d7ad99f19e2926977f,8ff44f081d43176474b267de5451f2c2e88089d0,c03de2c0900b47ffefede41223d9b069fe36a49d..5be27b07e5146e89ce6497566ec602a3f58bc313
--- 1/git.c
--- 2/git.c
--- 3/git.c
+++ b/git.c
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "builtin.h"
++ #include "config.h"
   #include "exec_cmd.h"
   #include "help.h"
   #include "run-command.h"
@@@@ -16,53 -16,51 -17,7 +17,9 @@@@ const char git_more_info_string[] 
           "to read about a specific subcommand or concept.");
   
   static int use_pager = -1;
-- static char *orig_cwd;
-- static const char *env_names[] = {
--      GIT_DIR_ENVIRONMENT,
--      GIT_WORK_TREE_ENVIRONMENT,
--      GIT_IMPLICIT_WORK_TREE_ENVIRONMENT,
--      GIT_PREFIX_ENVIRONMENT
-- };
-- static char *orig_env[4];
-- static int save_restore_env_balance;
 - 
 - static void save_env_before_alias(void)
 - {
 -      int i;
 - 
 -      assert(save_restore_env_balance == 0);
 -      save_restore_env_balance = 1;
 -      orig_cwd = xgetcwd();
 -      for (i = 0; i < ARRAY_SIZE(env_names); i++) {
 -              orig_env[i] = getenv(env_names[i]);
 -              orig_env[i] = xstrdup_or_null(orig_env[i]);
 -      }
 - }
   
 - static void restore_env(int external_alias)
 - {
 -      int i;
 - 
 -      assert(save_restore_env_balance == 1);
 -      save_restore_env_balance = 0;
 -      if (!external_alias && orig_cwd && chdir(orig_cwd))
 -              die_errno("could not move to %s", orig_cwd);
 -      free(orig_cwd);
 -      for (i = 0; i < ARRAY_SIZE(env_names); i++) {
 -              if (external_alias &&
 -                  !strcmp(env_names[i], GIT_PREFIX_ENVIRONMENT))
 -                      continue;
 -              if (orig_env[i]) {
 -                      setenv(env_names[i], orig_env[i], 1);
 -                      free(orig_env[i]);
 -              } else {
 -                      unsetenv(env_names[i]);
 -              }
 -      }
 - }
 ++static void list_builtins(void);
  +
-  static void save_env_before_alias(void)
-  {
-       int i;
-  
-       assert(save_restore_env_balance == 0);
-       save_restore_env_balance = 1;
-       orig_cwd = xgetcwd();
-       for (i = 0; i < ARRAY_SIZE(env_names); i++) {
-               orig_env[i] = getenv(env_names[i]);
-               orig_env[i] = xstrdup_or_null(orig_env[i]);
-       }
-  }
-  
-  static void restore_env(int external_alias)
-  {
-       int i;
-  
-       assert(save_restore_env_balance == 1);
-       save_restore_env_balance = 0;
-       if (!external_alias && orig_cwd && chdir(orig_cwd))
-               die_errno("could not move to %s", orig_cwd);
-       free(orig_cwd);
-       for (i = 0; i < ARRAY_SIZE(env_names); i++) {
-               if (external_alias &&
-                   !strcmp(env_names[i], GIT_PREFIX_ENVIRONMENT))
-                       continue;
-               if (orig_env[i]) {
-                       setenv(env_names[i], orig_env[i], 1);
-                       free(orig_env[i]);
-               } else {
-                       unsetenv(env_names[i]);
-               }
-       }
-  }
-  
   static void commit_pager_choice(void) {
        switch (use_pager) {
        case 0:
@@@@ -234,9 -232,6 -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);
@@@@ -255,19 -250,19 -207,18 +212,18 @@@@ static int handle_alias(int *argcp, con
        const char **new_argv;
        const char *alias_command;
        char *alias_string;
--      int unused_nongit;
-- 
--      save_env_before_alias();
--      setup_git_directory_gently(&unused_nongit);
   
        alias_command = (*argv)[0];
        alias_string = alias_lookup(alias_command);
        if (alias_string) {
                if (alias_string[0] == '!') {
                        struct child_process child = CHILD_PROCESS_INIT;
++                      int nongit_ok;
++ 
++                      /* Aliases expect GIT_PREFIX, GIT_DIR etc to be set */
++                      setup_git_directory_gently(&nongit_ok);
   
                        commit_pager_choice();
--                      restore_env(1);
   
                        child.use_shell = 1;
                        argv_array_push(&child.args, alias_string + 1);
                ret = 1;
        }
   
--      restore_env(0);
-- 
        errno = saved_errno;
   
        return ret;
@@@@ -534,13 -529,6 -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 d7ef21358ea7f592dffff98884eb34169e097880,d03d424e5cf8d32d91e3082555d8add674e01486,d5211fc5a6c0ae86c48f7e17a6be747dfc421f69..30d317a122eb5adc2c6d63eddaa12ca14cafba78
--- 1/grep.c
--- 2/grep.c
--- 3/grep.c
+++ b/grep.c
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "grep.h"
   #include "userdiff.h"
   #include "xdiff-interface.h"
@@@@ -178,38 -178,23 -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 -321,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->pcre1_extra_info = pcre_study(p->pcre1_regexp, 0, &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->pcre1_regexp, p->pcre1_extra_info, line, eol - line,
  -     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);
 -      pcre_free(p->pcre1_extra_info);
 ++#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_jit_stack)
 ++                     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 -457,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 -836,8 -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 -916,8 -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 -1407,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 -1751,9 -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 -1776,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 -1845,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 f637fc80062094784d5734df91523642933ddcfc,db7f3d79a016881639a8c0640451afe35b011e5e,b8f3a98e4cbe09dd903dfb86653938c1d7604e3d..8ba0777410bd6377a1325622f7d73a53a0aa5a60
--- 1/help.c
--- 2/help.c
--- 3/help.c
+++ b/help.c
@@@@ -1,7 -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 -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,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)
@@@@ -290,7 -289,7 -331,7 +291,7 @@@@ const char *help_unknown_cmd(const cha
        memset(&other_cmds, 0, sizeof(other_cmds));
        memset(&aliases, 0, sizeof(aliases));
   
--      git_config(git_unknown_cmd_config, NULL);
++      read_early_config(git_unknown_cmd_config, NULL);
   
        load_command_list("git-", &main_cmds, &other_cmds);
   
   
        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,ba5ff1aa2994633c055611ce566ea8cf3c09e8cc,109df44e3166259b8b5e67be9b377b15fbbef5b7..519025d2c3d944afb6fdd6ca1f3b091827a67272
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "refs.h"
   #include "pkt-line.h"
   #include "object.h"
@@@@ -90,7 -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 -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 -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,bea871c8e02b7173eeba5527d22f5ae7783c011e,d41fc91192097bbaa00de4367b1e2c7bda31440a..327abe557f5a66546665664511d3e71b7f0929e7
+++ b/ident.c
@@@@ -6,6 -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 -72,12 -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 ac0d4a5d78d956f09aa0082b286babc36f04b593,d7eafb61a6831020149d0da607bb47b995192296,24ff94e1dd333beab0f2c00748d2fcc63472dfe6..b9576efe97b98d8b7971045b7be3698b9592c5e6
@@@@ -5,6 -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 -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,a4ec11c2bf62bbda4304d19913f25965247d4027,282510b10507e76ccc02bc68027162c0b721ae99..410ab4f02de5b532485c46b5cceffc3c677df214
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "diff.h"
   #include "commit.h"
   #include "tag.h"
@@@@ -105,13 -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 -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 -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 -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 -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 -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,f92cb9f729ca05ae1e80c9c27bc102dbb64a8dc0,aaed3870a4618c9fe57875cec6814a3e9e62b811..f59162453eecdfb841383f71911303b594aa81e4
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "utf8.h"
   #include "strbuf.h"
   #include "mailinfo.h"
@@@@ -882,10 -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 -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 5cc86df2d15729e9b0e8b36fdb151d5986f42a10,eac12d4888993ebf4fde5194e19704db885824ee,a85144c23acd4293d0c87a2e468d2c0136fa4d57..59e5ee41a8cdde0613e5dfa890cb52b21666868f
@@@@ -4,6 -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 -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 -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 -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 -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 -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 -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 -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,031503d7b2ba9217cffa52652b57aa063208fb1a,9d7fdd635401b15d4e76f65ba19a6cc288a32373..9765deb41ab02dba909ec9027701bf2fdc53f310
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "commit.h"
   #include "refs.h"
   #include "notes-utils.h"
@@@@ -7,18 -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;
        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 -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,542563b280ad305da1452d57653728b9005874e6,dbcfef4d7a435fcb0072cf1a76613c1d3d103c44..8f47c202c58752b6d9d56852ae9c315e2f144769
+++ b/notes.c
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "notes.h"
   #include "blob.h"
   #include "tree.h"
@@@@ -35,8 -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 -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 -100,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 -143,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 -194,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 -246,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 -341,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 -373,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 -486,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 -542,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 -599,15 -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 -650,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 -673,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 -742,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 -942,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 -1027,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 -1080,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 -1104,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 -1146,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 -1209,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 -1311,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,e5ad34a2c3f7c7d7fdb65171f8a142a2becc64bb,cbf84a60482126a03af0913b88fb297a34eb5b70..0dd9fc6a0dd0a518200d9bbd834decb3c3ee22c6
@@@@ -1,6 -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 -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,828405021fca4214585e1d46b65f604d14e61143,e4659b1440c94d0f65ef486a488b604d6195d81c..ecc5331c232ef81f26343fd958a9b66e92a3fa5e
@@@@ -1,5 -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"
    * 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;
                        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 -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 -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 09701bd2ffef3eb6d9104916e4119f757c06c244,09701bd2ffef3eb6d9104916e4119f757c06c244,06a1f13c609d4315b84fe13eacf5132b123fb759..9c9f81b5b0e0560e05da3ec3fa62c05eae92d1e3
+++ b/pretty.c
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "commit.h"
   #include "utf8.h"
   #include "diff.h"
@@@@ -405,11 -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 {
@@@@ -1137,7 -1137,7 -1138,7 +1138,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 */
diff --combined read-cache.c
index bc156a133e9ff197e3d98c63d66f2d958f47f564,bc156a133e9ff197e3d98c63d66f2d958f47f564,e623e075de9ad09743da2c329132efa6a8dda231..c8c766dab020472d5f318c247e376f27373a5261
@@@@ -5,6 -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"
@@@@ -1877,9 -1877,9 -1878,15 +1878,9 @@@@ int discard_index(struct index_state *i
   {
        int i;
   
  -     for (i = 0; i < istate->cache_nr; i++) {
  -             if (istate->cache[i]->index &&
  -                 istate->split_index &&
  -                 istate->split_index->base &&
  -                 istate->cache[i]->index <= istate->split_index->base->cache_nr &&
  -                 istate->cache[i] == istate->split_index->base->cache[istate->cache[i]->index - 1])
  -                     continue;
  +     unshare_split_index(istate, 1);
  +     for (i = 0; i < istate->cache_nr; i++)
                free(istate->cache[i]);
  -     }
        resolve_undo_clear_index(istate);
        istate->cache_nr = 0;
        istate->cache_changed = 0;
@@@@ -2181,10 -2181,10 -2188,9 +2182,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);
@@@@ -2323,7 -2323,7 -2322,7 +2324,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)) !=
@@@@ -2420,7 -2420,7 -2419,7 +2421,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;
@@@@ -2630,9 -2630,9 -2629,3 +2631,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,f0685c92513e306188d89380a1c3020024a4edb4,c0cd259141a8c188c87bf890cde24a0c3776da05..84112c88ee4349ef8c7411f6e046d0f2d289ea04
--- 1/refs.c
--- 2/refs.c
--- 3/refs.c
+++ b/refs.c
@@@@ -3,6 -3,6 -3,7 +3,7 @@@@
    */
   
   #include "cache.h"
++ #include "config.h"
   #include "hashmap.h"
   #include "lockfile.h"
   #include "iterator.h"
   #include "object.h"
   #include "tag.h"
   #include "submodule.h"
  +#include "worktree.h"
   
   /*
    * List of all available backends
@@@@ -714,7 -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,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 -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 -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 -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 -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 -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 -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 -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,d8b3f73147c8af88597ad71259aef0a9f53dd104,1d530f602051be6388344fc113e5f3287ea3e887..621a4086c37362180f151cc1648444d4cfd69d13
@@@@ -1,4 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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,3649d60cdce7335f6bc5bcca4810ce869dacfdcf,6ef03bb73066067fce9878e237c774da7c0ad14e..d87482573d38b057257c08024fbe6b4339661481
+++ b/remote.c
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "remote.h"
   #include "refs.h"
   #include "commit.h"
@@@@ -251,7 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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,3bd55caf3b0961888bcca06d3c54577cb25f5223,344d6aa818eacf65a4ce7fbfdc380bc02cea2df9..829b3b0f08f7546c168e2728687d5729c4607cfa
+++ b/rerere.c
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "lockfile.h"
   #include "string-list.h"
   #include "rerere.h"
@@@@ -200,7 -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 -484,13 -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,924fb1d0c3c84dd823393d7dea21af2d70a8d54e,7356a935622427c9721cb067d1cab9e179749ee7..224afe79b96c89a70a36db85aa6c61826b2ebec1
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "lockfile.h"
   #include "sequencer.h"
   #include "dir.h"
@@@@ -344,7 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 751d02b9be627176009cdda4f1b20a3674b0dc95,e3f7699a902aed20a83820067cf913df2f3750a9,4e38cf2a4f3782b92d92adf34a9ea83963bff339..358fbc2e5301d9412b55463065b912b5708c3ceb
+++ b/setup.c
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "dir.h"
   #include "string-list.h"
   
@@@@ -134,27 -134,23 -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 -181,6 -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 -207,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 -703,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 -753,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 -945,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);
--              return NULL;
++              strbuf_setlen(commondir, commondir_offset);
++              strbuf_setlen(gitdir, gitdir_offset);
++              return -1;
        }
   
--      return gitdir->buf + gitdir_offset;
++      return 0;
   }
   
   const char *setup_git_directory_gently(int *nongit_ok)
diff --combined sha1_file.c
index 59a4ed2ed32336b41ab8f3b1d4aca30f045aa084,feb227a8377cd3ca5fb524fd04ebccb713dede4b,44561e0b92c0008653ed3d8da97336b98617cf37..a900b280428fa4931b1a60a9ac788edaff89634e
@@@@ -7,6 -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 -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 -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 -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,e9ffe685d58366dc3802986519e3e2fd22c151a4,7e1e86c97aeceacec7fe9b1e29be8a3e5fb3d69a..d2d732c19b62dd13c27852fcbf2385b29dd58b1d
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "tag.h"
   #include "commit.h"
   #include "tree.h"
@@@@ -241,7 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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,bf5a93d16fb71cdeb87f589732b6f95f4a83fbe0,8cfcb3bedd8fea4429d628ad4fcac3764a49b4ac..da0b805493b9e7cd4c26f027a9f24c823109850a
@@@@ -1,4 -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 -153,7 -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 -207,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 -282,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 -510,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 -617,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 -660,11 -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 -681,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 -786,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 -796,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 -881,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 -1022,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 -1420,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 -1466,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 -1647,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 t/t1300-repo-config.sh
index 13b7851f7c2feb87f63449d917380452e85c1f84,13b7851f7c2feb87f63449d917380452e85c1f84,f664bfc67148a738be4a0ec58fc71b88344022b7..a37ef0422212eafdae4b4c0fae9e28d4a183117f
@@@@ -703,6 -703,6 -703,12 +703,12 @@@@ test_expect_success 'invalid unit' 
        test_i18ngrep "bad numeric config value .1auto. for .aninvalid.unit. in file .git/config: invalid unit" actual
   '
   
++ test_expect_success 'line number is reported correctly' '
++      printf "[bool]\n\tvar\n" >invalid &&
++      test_must_fail git config -f invalid --path bool.var 2>actual &&
++      test_i18ngrep "line 2" actual
++ '
++ 
   test_expect_success 'invalid stdin config' '
        echo "[broken" | test_must_fail git config --list --file - >output 2>&1 &&
        test_i18ngrep "bad config line 1 in standard input" output
@@@@ -1539,10 -1539,10 -1545,4 +1545,10 @@@@ test_expect_success !MINGW '--show-orig
        test_cmp expect output
   '
   
  +test_expect_success '--local requires a repo' '
  +     # we expect 128 to ensure that we do not simply
  +     # fail to find anything and return code "1"
  +     test_expect_code 128 nongit git config --local foo.bar
  +'
  +
   test_done
diff --combined t/t1308-config-set.sh
index e495a616161660bcade644dea42b5c8e53cc64b3,ff50960ccaed9953c5738c9bbf602bf0d326e15a,69a0aa56d6d7b759e71a57d24b838fe21a544777..bafed5c9b88481992ca6cf4cd6c13596c7baf16b
@@@@ -183,22 -183,11 -183,11 +183,22 @@@@ test_expect_success 'proper error on no
        test_cmp expect actual
   '
   
 ++test_expect_success 'proper error on directory "files"' '
 ++     echo "Error (-1) reading configuration file a-directory." >expect &&
 ++     mkdir a-directory &&
 ++     test_expect_code 2 test-config configset_get_value foo.bar a-directory 2>output &&
 ++     grep "^warning:" output &&
 ++     grep "^Error" output >actual &&
 ++     test_cmp expect actual
 ++'
 ++
   test_expect_success POSIXPERM,SANITY 'proper error on non-accessible files' '
        chmod -r .git/config &&
        test_when_finished "chmod +r .git/config" &&
        echo "Error (-1) reading configuration file .git/config." >expect &&
 --     test_expect_code 2 test-config configset_get_value foo.bar .git/config 2>actual &&
 ++     test_expect_code 2 test-config configset_get_value foo.bar .git/config 2>output &&
 ++     grep "^warning:" output &&
 ++     grep "^Error" output >actual &&
        test_cmp expect actual
   '
   
@@@@ -226,7 -215,7 -215,9 +226,9 @@@@ test_expect_success 'check line errors 
                br
        EOF
        test_expect_code 128 git br 2>result &&
--      test_i18ngrep "fatal: .*alias\.br.*\.git/config.*line 2" result
++      test_i18ngrep "missing value for .alias\.br" result &&
++      test_i18ngrep "fatal: .*\.git/config" result &&
++      test_i18ngrep "fatal: .*line 2" result
   '
   
   test_expect_success 'error on modifying repo config without repo' '
diff --combined transport.c
index 9bfcf870f9078f75349bd3b4976c71bbf5c49ebf,9bfcf870f9078f75349bd3b4976c71bbf5c49ebf,6096f8258670cb2d651f73d945f60281883d11d1..b9995306f259da0a929babdfe1fb5b99eaacead8
@@@@ -1,4 -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 -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,d38c37e38cf183cf878a9f35b19544d1da0bc438,e7b5a21ef78daf6aebe1bf4630e4baeb11ffea0f..dd535bc8497e5d8202a94923fd0a68c3f46907fd
@@@@ -1,5 -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 -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 -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 -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 -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 -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 -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 -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,5330c02c1427862be1eea61c8d8e4127909d13fe,7581a51960a58114601dad08a788a47270c9bf0e..7efff2fbfd76380fd448d53173f8295d7c9c9d87
@@@@ -1,4 -1,4 -1,5 +1,5 @@@@
   #include "cache.h"
++ #include "config.h"
   #include "refs.h"
   #include "pkt-line.h"
   #include "sideband.h"
@@@@ -35,7 -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 -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 -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 -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 -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 -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 -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 -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,d83741770949f457b364896b6ff8632c0a700d69,487a9f753272ff27f54baaece755738beae3b947..36630e5d1855a41407e217e610aa1f293288abe1
+++ b/wrapper.c
@@@@ -2,6 -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 -418,6 -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 -576,15 -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,060038c2d6b92512e6625d0f5d94ed5439cd249c,5ac07d7348c3c8b5cb4e4decf8a19cd3881b6c82..018e03308921e3b44bb75b8bc1e005424ca4fc1b
@@@@ -1,4 -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 -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) {