Merge branch 'nd/fopen-errors'
authorJunio C Hamano <gitster@pobox.com>
Tue, 13 Jun 2017 20:47:09 +0000 (13:47 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 13 Jun 2017 20:47:09 +0000 (13:47 -0700)
We often try to open a file for reading whose existence is
optional, and silently ignore errors from open/fopen; report such
errors if they are not due to missing files.

* nd/fopen-errors:
mingw_fopen: report ENOENT for invalid file names
mingw: verify that paths are not mistaken for remote nicknames
log: fix memory leak in open_next_file()
rerere.c: move error_errno() closer to the source system call
print errno when reporting a system call error
wrapper.c: make warn_on_inaccessible() static
wrapper.c: add and use fopen_or_warn()
wrapper.c: add and use warn_on_fopen_errors()
config.mak.uname: set FREAD_READS_DIRECTORIES for Darwin, too
config.mak.uname: set FREAD_READS_DIRECTORIES for Linux and FreeBSD
clone: use xfopen() instead of fopen()
use xfopen() in more places
git_fopen: fix a sparse 'not declared' warning

23 files changed:
1  2 
bisect.c
builtin/am.c
builtin/blame.c
builtin/clone.c
builtin/commit.c
builtin/fast-export.c
builtin/fsck.c
builtin/log.c
builtin/merge.c
builtin/pull.c
commit.c
compat/mingw.c
config.c
config.mak.uname
diff.c
dir.c
fast-import.c
git-compat-util.h
remote.c
sequencer.c
server-info.c
wrapper.c
wt-status.c
diff --combined bisect.c
index c952df692bef9ba1638e55448050db33ba76d399,bb28bf63b28198ab98dc361ba56738083c738d25..2a2b9b7267acbb8752015d64ec477f64c6047875
+++ b/bisect.c
@@@ -438,10 -438,7 +438,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);
@@@ -546,7 -543,7 +543,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)
  {
@@@ -669,7 -666,7 +666,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;
  
@@@ -705,7 -702,7 +702,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;
@@@ -995,10 -992,8 +992,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 builtin/am.c
index 5ee146bfb31df8e3d8edf356f4817e3f53f8ad3b,f5dac7783e551c1dc7d3a23a39b5e8bdd8cbe0f0..8881d736151bf266cc8544a717cba960c078eff5
@@@ -879,12 -879,12 +879,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 +1145,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,12 -1275,8 +1275,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);
        }
  
@@@ -1351,16 -1347,19 +1347,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);
  }
  
  /**
@@@ -1444,9 -1449,9 +1440,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);
@@@ -1479,7 -1484,7 +1475,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);
  
@@@ -1609,7 -1614,7 +1605,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);
        }
@@@ -1674,7 -1679,7 +1670,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"));
@@@ -1931,8 -1936,7 +1927,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);
        }
  
@@@ -2037,11 -2041,11 +2033,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));
  
@@@ -2148,7 -2152,7 +2144,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);
  
@@@ -2311,9 -2315,6 +2307,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 d7a2df3b47439c5564a716402e815e0da4f0d8a9,34445d789420eddd53b06ba274445a65026f898d..749ad7f05b657ba34534a4ae6601dd5d85649b36
@@@ -6,13 -6,21 +6,13 @@@
   */
  
  #include "cache.h"
 -#include "refs.h"
  #include "builtin.h"
 -#include "blob.h"
  #include "commit.h"
 -#include "tag.h"
 -#include "tree-walk.h"
  #include "diff.h"
 -#include "diffcore.h"
  #include "revision.h"
  #include "quote.h"
 -#include "xdiff-interface.h"
 -#include "cache-tree.h"
  #include "string-list.h"
  #include "mailmap.h"
 -#include "mergesort.h"
  #include "parse-options.h"
  #include "prio-queue.h"
  #include "utf8.h"
@@@ -21,7 -29,6 +21,7 @@@
  #include "line-log.h"
  #include "dir.h"
  #include "progress.h"
 +#include "blame.h"
  
  static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
  
@@@ -55,21 -62,1497 +55,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 -1699,10 +216,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 -2224,301 +615,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 -2556,13 +652,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 -2688,12 +782,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/clone.c
index 743f16ae2aad7d71789f2b38287aea13cf29fc26,dde4fe73afca7201741ec299af7229edd6031323..a2ea019c590190a00d1a7cf51a917c7ebdc7886c
@@@ -40,7 -40,6 +40,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 -120,6 +121,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 -357,7 +360,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 -563,7 +566,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 -652,7 +655,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 -682,7 +685,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 -739,7 +742,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 -1035,6 +1040,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.c
index da1ba4c86205ca55ae1880cb768b093b101bd85a,eda0d3231165b54a12339fe2550c1e6688fc3843..ef52457effc1f519a53c105efcb24d5e19048f6c
@@@ -313,7 -313,7 +313,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 -1263,6 +1263,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 -1430,7 +1434,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 -1654,7 +1658,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"));
diff --combined builtin/fast-export.c
index 24e29ad7eab5edc0964a51f32602b062daabb907,128b99e6daa46aa1bac48f52a3d5b226f274eb44..2dfed874546efc1135e09199dbfb7f803d02d91a
@@@ -232,7 -232,7 +232,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)
@@@ -734,7 -734,6 +734,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,9 -905,7 +907,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/fsck.c
index cb2ba6cd1be46635ca8416a7d3f2b006f964190b,00beaaa4e6edc7d644f43a6503aa895eb6d934c4..3a2c27f2413e5e377926e0e7df339549c37a76b3
@@@ -280,8 -280,7 +280,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);
@@@ -377,7 -376,7 +376,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;
@@@ -444,7 -443,7 +443,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;
@@@ -506,7 -505,7 +505,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);
@@@ -599,10 -598,10 +598,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;
                }
@@@ -781,7 -780,7 +780,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/log.c
index e89ec941ce2c97de7f8233a5e7e6f9010fabdb64,f075838df9cb23fd7fc2babed49ef3726896d1bd..a33c1a70abe1c01ae408bf23d01a3d1d455f1f8e
@@@ -110,8 -110,6 +110,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 -410,8 +412,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,16 +483,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 -596,7 +600,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,8 -842,10 +846,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;
@@@ -882,8 -883,8 +887,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);
  }
@@@ -1267,7 -1268,7 +1272,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)
@@@ -1823,7 -1824,7 +1828,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/merge.c
index a4a098f40f8e3e61c3f8b730a6b22a83c3c23566,65a15018585ace678ef344bf4f1282fb46a00cbc..eab03a026d26aaf6b42fb43a363b67857660a763
@@@ -605,13 -605,13 +605,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,9 -839,7 +839,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);
@@@ -1123,7 -1121,7 +1121,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/pull.c
index da8b60fc85e93da880fb955992b8b753715fafda,589c25becf270d24140ba5d2ddaf0251746fa170..69417e4f362f6d7baa11885bd1cb8c5cbb676b14
@@@ -337,8 -337,7 +337,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 */
@@@ -523,7 -522,7 +522,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))
@@@ -698,10 -697,10 +697,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);
@@@ -772,7 -771,6 +771,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 commit.c
index 713f09feb04116fc1529cbca1ca9cbd38e4e4379,3eeda081f9bf9a765f41d44579cf5ee016bae129..99846d9bf467be8e737341795054588475c65855
+++ b/commit.c
@@@ -11,7 -11,6 +11,7 @@@
  #include "commit-slab.h"
  #include "prio-queue.h"
  #include "sha1-lookup.h"
 +#include "wt-status.h"
  
  static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
  
@@@ -19,38 -18,38 +19,38 @@@ int save_commit_buffer = 1
  
  const char *commit_type = "commit";
  
 -struct commit *lookup_commit_reference_gently(const unsigned char *sha1,
 +struct commit *lookup_commit_reference_gently(const struct object_id *oid,
                                              int quiet)
  {
 -      struct object *obj = deref_tag(parse_object(sha1), NULL, 0);
 +      struct object *obj = deref_tag(parse_object(oid), NULL, 0);
  
        if (!obj)
                return NULL;
        return object_as_type(obj, OBJ_COMMIT, quiet);
  }
  
 -struct commit *lookup_commit_reference(const unsigned char *sha1)
 +struct commit *lookup_commit_reference(const struct object_id *oid)
  {
 -      return lookup_commit_reference_gently(sha1, 0);
 +      return lookup_commit_reference_gently(oid, 0);
  }
  
 -struct commit *lookup_commit_or_die(const unsigned char *sha1, const char *ref_name)
 +struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name)
  {
 -      struct commit *c = lookup_commit_reference(sha1);
 +      struct commit *c = lookup_commit_reference(oid);
        if (!c)
                die(_("could not parse %s"), ref_name);
 -      if (hashcmp(sha1, c->object.oid.hash)) {
 +      if (oidcmp(oid, &c->object.oid)) {
                warning(_("%s %s is not a commit!"),
 -                      ref_name, sha1_to_hex(sha1));
 +                      ref_name, oid_to_hex(oid));
        }
        return c;
  }
  
 -struct commit *lookup_commit(const unsigned char *sha1)
 +struct commit *lookup_commit(const struct object_id *oid)
  {
 -      struct object *obj = lookup_object(sha1);
 +      struct object *obj = lookup_object(oid->hash);
        if (!obj)
 -              return create_object(sha1, alloc_commit_node());
 +              return create_object(oid->hash, alloc_commit_node());
        return object_as_type(obj, OBJ_COMMIT, 0);
  }
  
@@@ -61,13 -60,13 +61,13 @@@ struct commit *lookup_commit_reference_
  
        if (get_sha1_committish(name, oid.hash))
                return NULL;
 -      commit = lookup_commit_reference(oid.hash);
 +      commit = lookup_commit_reference(&oid);
        if (parse_commit(commit))
                return NULL;
        return commit;
  }
  
 -static unsigned long parse_commit_date(const char *buf, const char *tail)
 +static timestamp_t parse_commit_date(const char *buf, const char *tail)
  {
        const char *dateptr;
  
@@@ -90,8 -89,8 +90,8 @@@
                /* nada */;
        if (buf >= tail)
                return 0;
 -      /* dateptr < buf && buf[-1] == '\n', so strtoul will stop at buf-1 */
 -      return strtoul(dateptr, NULL, 10);
 +      /* dateptr < buf && buf[-1] == '\n', so parsing will stop at buf-1 */
 +      return parse_timestamp(dateptr, NULL, 10);
  }
  
  static struct commit_graft **commit_graft;
@@@ -168,7 -167,7 +168,7 @@@ bad_graft_data
  
  static int read_graft_file(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;
@@@ -217,9 -216,9 +217,9 @@@ int for_each_commit_graft(each_commit_g
        return ret;
  }
  
 -int unregister_shallow(const unsigned char *sha1)
 +int unregister_shallow(const struct object_id *oid)
  {
 -      int pos = commit_graft_pos(sha1);
 +      int pos = commit_graft_pos(oid->hash);
        if (pos < 0)
                return -1;
        if (pos + 1 < commit_graft_nr)
@@@ -332,7 -331,7 +332,7 @@@ int parse_commit_buffer(struct commit *
        if (get_sha1_hex(bufptr + 5, parent.hash) < 0)
                return error("bad tree pointer in commit %s",
                             oid_to_hex(&item->object.oid));
 -      item->tree = lookup_tree(parent.hash);
 +      item->tree = lookup_tree(&parent);
        bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
        pptr = &item->parents;
  
                 */
                if (graft && (graft->nr_parent < 0 || grafts_replace_parents))
                        continue;
 -              new_parent = lookup_commit(parent.hash);
 +              new_parent = lookup_commit(&parent);
                if (new_parent)
                        pptr = &commit_list_insert(new_parent, pptr)->next;
        }
                int i;
                struct commit *new_parent;
                for (i = 0; i < graft->nr_parent; i++) {
 -                      new_parent = lookup_commit(graft->parent[i].hash);
 +                      new_parent = lookup_commit(&graft->parent[i]);
                        if (!new_parent)
                                continue;
                        pptr = &commit_list_insert(new_parent, pptr)->next;
@@@ -474,8 -473,8 +474,8 @@@ struct commit_list * commit_list_insert
  
  static int commit_list_compare_by_date(const void *a, const void *b)
  {
 -      unsigned long a_date = ((const struct commit_list *)a)->item->date;
 -      unsigned long b_date = ((const struct commit_list *)b)->item->date;
 +      timestamp_t a_date = ((const struct commit_list *)a)->item->date;
 +      timestamp_t b_date = ((const struct commit_list *)b)->item->date;
        if (a_date < b_date)
                return 1;
        if (a_date > b_date)
@@@ -563,7 -562,7 +563,7 @@@ void clear_commit_marks_for_object_arra
  
        for (i = 0; i < a->nr; i++) {
                object = a->objects[i].item;
 -              commit = lookup_commit_reference_gently(object->oid.hash, 1);
 +              commit = lookup_commit_reference_gently(&object->oid, 1);
                if (commit)
                        clear_commit_marks(commit, mark);
        }
@@@ -599,7 -598,7 +599,7 @@@ static void record_author_date(struct a
        const char *ident_line;
        size_t ident_len;
        char *date_end;
 -      unsigned long date;
 +      timestamp_t date;
  
        ident_line = find_commit_header(buffer, "author", &ident_len);
        if (!ident_line)
            !ident.date_begin || !ident.date_end)
                goto fail_exit; /* malformed "author" line */
  
 -      date = strtoul(ident.date_begin, &date_end, 10);
 +      date = parse_timestamp(ident.date_begin, &date_end, 10);
        if (date_end != ident.date_end)
                goto fail_exit; /* malformed date */
        *(author_date_slab_at(author_date, commit)) = date;
@@@ -622,8 -621,8 +622,8 @@@ static int compare_commits_by_author_da
  {
        const struct commit *a = a_, *b = b_;
        struct author_date_slab *author_date = cb_data;
 -      unsigned long a_date = *(author_date_slab_at(author_date, a));
 -      unsigned long b_date = *(author_date_slab_at(author_date, b));
 +      timestamp_t a_date = *(author_date_slab_at(author_date, a));
 +      timestamp_t b_date = *(author_date_slab_at(author_date, b));
  
        /* newer commits with larger date first */
        if (a_date < b_date)
@@@ -1590,7 -1589,7 +1590,7 @@@ struct commit *get_merge_parent(const c
        struct object_id oid;
        if (get_sha1(name, oid.hash))
                return NULL;
 -      obj = parse_object(oid.hash);
 +      obj = parse_object(&oid);
        commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
        if (commit && !commit->util)
                set_merge_remote_desc(commit, name, obj);
@@@ -1649,9 -1648,10 +1649,9 @@@ const char *find_commit_header(const ch
  /*
   * Inspect the given string and determine the true "end" of the log message, in
   * order to find where to put a new Signed-off-by: line.  Ignored are
 - * trailing comment lines and blank lines, and also the traditional
 - * "Conflicts:" block that is not commented out, so that we can use
 - * "git commit -s --amend" on an existing commit that forgot to remove
 - * it.
 + * trailing comment lines and blank lines.  To support "git commit -s
 + * --amend" on an existing commit, we also ignore "Conflicts:".  To
 + * support "git commit -v", we truncate at cut lines.
   *
   * Returns the number of bytes from the tail to ignore, to be fed as
   * the second parameter to append_signoff().
@@@ -1661,9 -1661,8 +1661,9 @@@ int ignore_non_trailer(const char *buf
        int boc = 0;
        int bol = 0;
        int in_old_conflicts_block = 0;
 +      size_t cutoff = wt_status_locate_end(buf, len);
  
 -      while (bol < len) {
 +      while (bol < cutoff) {
                const char *next_line = memchr(buf + bol, '\n', len - bol);
  
                if (!next_line)
                }
                bol = next_line - buf;
        }
 -      return boc ? len - boc : 0;
 +      return boc ? len - boc : len - cutoff;
  }
diff --combined compat/mingw.c
index c6134f7c810072106026577d8ee306df9311ef24,b604a827e88249ea003ffa685026a7d78436dbd4..8b6fa0db446aee9888ff6484560131143c7e22e5
@@@ -423,6 -423,8 +423,8 @@@ FILE *mingw_fopen (const char *filename
                return NULL;
        }
        file = _wfopen(wfilename, wotype);
+       if (!file && GetLastError() == ERROR_INVALID_NAME)
+               errno = ENOENT;
        if (file && hide && set_hidden_flag(wfilename, 1))
                warning("could not mark '%s' as hidden.", filename);
        return file;
@@@ -940,15 -942,65 +942,15 @@@ static const char *parse_interpreter(co
        return p+1;
  }
  
 -/*
 - * Splits the PATH into parts.
 - */
 -static char **get_path_split(void)
 -{
 -      char *p, **path, *envpath = mingw_getenv("PATH");
 -      int i, n = 0;
 -
 -      if (!envpath || !*envpath)
 -              return NULL;
 -
 -      envpath = xstrdup(envpath);
 -      p = envpath;
 -      while (p) {
 -              char *dir = p;
 -              p = strchr(p, ';');
 -              if (p) *p++ = '\0';
 -              if (*dir) {     /* not earlier, catches series of ; */
 -                      ++n;
 -              }
 -      }
 -      if (!n)
 -              return NULL;
 -
 -      ALLOC_ARRAY(path, n + 1);
 -      p = envpath;
 -      i = 0;
 -      do {
 -              if (*p)
 -                      path[i++] = xstrdup(p);
 -              p = p+strlen(p)+1;
 -      } while (i < n);
 -      path[i] = NULL;
 -
 -      free(envpath);
 -
 -      return path;
 -}
 -
 -static void free_path_split(char **path)
 -{
 -      char **p = path;
 -
 -      if (!path)
 -              return;
 -
 -      while (*p)
 -              free(*p++);
 -      free(path);
 -}
 -
  /*
   * exe_only means that we only want to detect .exe files, but not scripts
   * (which do not have an extension)
   */
 -static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
 +static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
 +                       int isexe, int exe_only)
  {
        char path[MAX_PATH];
 -      snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
 +      snprintf(path, sizeof(path), "%.*s\\%s.exe", dirlen, dir, cmd);
  
        if (!isexe && access(path, F_OK) == 0)
                return xstrdup(path);
   * Determines the absolute path of cmd using the split path in path.
   * If cmd contains a slash or backslash, no lookup is performed.
   */
 -static char *path_lookup(const char *cmd, char **path, int exe_only)
 +static char *path_lookup(const char *cmd, int exe_only)
  {
 +      const char *path;
        char *prog = NULL;
        int len = strlen(cmd);
        int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe");
  
        if (strchr(cmd, '/') || strchr(cmd, '\\'))
 -              prog = xstrdup(cmd);
 +              return xstrdup(cmd);
 +
 +      path = mingw_getenv("PATH");
 +      if (!path)
 +              return NULL;
  
 -      while (!prog && *path)
 -              prog = lookup_prog(*path++, cmd, isexe, exe_only);
 +      while (!prog) {
 +              const char *sep = strchrnul(path, ';');
 +              int dirlen = sep - path;
 +              if (dirlen)
 +                      prog = lookup_prog(path, dirlen, cmd, isexe, exe_only);
 +              if (!*sep)
 +                      break;
 +              path = sep + 1;
 +      }
  
        return prog;
  }
@@@ -1152,7 -1192,8 +1154,7 @@@ pid_t mingw_spawnvpe(const char *cmd, c
                     int fhin, int fhout, int fherr)
  {
        pid_t pid;
 -      char **path = get_path_split();
 -      char *prog = path_lookup(cmd, path, 0);
 +      char *prog = path_lookup(cmd, 0);
  
        if (!prog) {
                errno = ENOENT;
  
                if (interpr) {
                        const char *argv0 = argv[0];
 -                      char *iprog = path_lookup(interpr, path, 1);
 +                      char *iprog = path_lookup(interpr, 1);
                        argv[0] = prog;
                        if (!iprog) {
                                errno = ENOENT;
                                               fhin, fhout, fherr);
                free(prog);
        }
 -      free_path_split(path);
        return pid;
  }
  
  static int try_shell_exec(const char *cmd, char *const *argv)
  {
        const char *interpr = parse_interpreter(cmd);
 -      char **path;
        char *prog;
        int pid = 0;
  
        if (!interpr)
                return 0;
 -      path = get_path_split();
 -      prog = path_lookup(interpr, path, 1);
 +      prog = path_lookup(interpr, 1);
        if (prog) {
                int argc = 0;
                const char **argv2;
                free(prog);
                free(argv2);
        }
 -      free_path_split(path);
        return pid;
  }
  
@@@ -1232,7 -1277,8 +1234,7 @@@ int mingw_execv(const char *cmd, char *
  
  int mingw_execvp(const char *cmd, char *const *argv)
  {
 -      char **path = get_path_split();
 -      char *prog = path_lookup(cmd, path, 0);
 +      char *prog = path_lookup(cmd, 0);
  
        if (prog) {
                mingw_execv(prog, argv);
        } else
                errno = ENOENT;
  
 -      free_path_split(path);
        return -1;
  }
  
diff --combined config.c
index 146cb3452adab3115f15d30c2b0f9f5480344279,e54d99d519ae841dc915846fc41aeecf00d7d9ab..34a139c40bd57ff2dd23318beca53fd2e2948000
+++ b/config.c
@@@ -214,7 -214,6 +214,7 @@@ 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;
        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);
@@@ -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);
@@@ -1981,7 -1965,7 +1981,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 -2621,7 +2637,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 config.mak.uname
index 192629f1431072f242f10a8528f1853b8bbaddeb,1743890164168bdf17fb0f4fce0f04c163883240..d2cabe7fb485c04557c8327efbca5f365c631e99
@@@ -36,6 -36,7 +36,7 @@@ ifeq ($(uname_S),Linux
        NEEDS_LIBRT = YesPlease
        HAVE_GETDELIM = YesPlease
        SANE_TEXT_GREP=-a
+       FREAD_READS_DIRECTORIES = UnfortunatelyYes
  endif
  ifeq ($(uname_S),GNU/kFreeBSD)
        HAVE_ALLOCA_H = YesPlease
@@@ -43,6 -44,7 +44,7 @@@
        HAVE_PATHS_H = YesPlease
        DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
        LIBC_CONTAINS_LIBINTL = YesPlease
+       FREAD_READS_DIRECTORIES = UnfortunatelyYes
  endif
  ifeq ($(uname_S),UnixWare)
        CC = cc
@@@ -108,6 -110,7 +110,7 @@@ ifeq ($(uname_S),Darwin
        BASIC_CFLAGS += -DPRECOMPOSE_UNICODE
        BASIC_CFLAGS += -DPROTECT_HFS_DEFAULT=1
        HAVE_BSD_SYSCTL = YesPlease
+       FREAD_READS_DIRECTORIES = UnfortunatelyYes
  endif
  ifeq ($(uname_S),SunOS)
        NEEDS_SOCKET = YesPlease
@@@ -201,6 -204,7 +204,7 @@@ ifeq ($(uname_S),FreeBSD
        GMTIME_UNRELIABLE_ERRORS = UnfortunatelyYes
        HAVE_BSD_SYSCTL = YesPlease
        PAGER_ENV = LESS=FRX LV=-c MORE=FRX
+       FREAD_READS_DIRECTORIES = UnfortunatelyYes
  endif
  ifeq ($(uname_S),OpenBSD)
        NO_STRCASESTR = YesPlease
@@@ -237,7 -241,6 +241,7 @@@ ifeq ($(uname_S),AIX
        NO_MKDTEMP = YesPlease
        NO_STRLCPY = YesPlease
        NO_NSEC = YesPlease
 +      NO_REGEX = NeedsStartEnd
        FREAD_READS_DIRECTORIES = UnfortunatelyYes
        INTERNAL_QSORT = UnfortunatelyYes
        NEEDS_LIBICONV = YesPlease
diff --combined diff.c
index 5275c4b78011e90627c073f487f3f8298b483352,b6597ce56889589f194256bb15b7f11f54584625..e35cf6c704505f4a56dc39f0dd39c6691acd1c9b
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -27,7 -27,7 +27,7 @@@
  #endif
  
  static int diff_detect_rename_default;
 -static int diff_indent_heuristic; /* experimental */
 +static int diff_indent_heuristic = 1;
  static int diff_rename_limit_default = 400;
  static int diff_suppress_blank_empty;
  static int diff_use_color_default = -1;
@@@ -290,6 -290,9 +290,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 -351,6 +348,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);
  }
  
@@@ -911,7 -911,7 +911,7 @@@ static int fn_out_diff_words_write_help
  /*
   * '--color-words' algorithm can be described as:
   *
 - *   1. collect the minus/plus lines of a diff hunk, divided into
 + *   1. collect the minus/plus lines of a diff hunk, divided into
   *      minus-lines and plus-lines;
   *
   *   2. break both minus-lines and plus-lines into words and
@@@ -4071,9 -4071,7 +4071,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;
@@@ -4807,9 -4805,7 +4805,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];
@@@ -5244,7 -5240,7 +5240,7 @@@ size_t fill_textconv(struct userdiff_dr
  
        if (driver->textconv_cache && df->oid_valid) {
                *outbuf = notes_cache_get(driver->textconv_cache,
 -                                        df->oid.hash,
 +                                        &df->oid,
                                          &size);
                if (*outbuf)
                        return size;
  
        if (driver->textconv_cache && df->oid_valid) {
                /* ignore errors, as we might be in a readonly repository */
 -              notes_cache_put(driver->textconv_cache, df->oid.hash, *outbuf,
 +              notes_cache_put(driver->textconv_cache, &df->oid, *outbuf,
                                size);
                /*
                 * we could save up changes and flush them all at the end,
        return size;
  }
  
 +int textconv_object(const char *path,
 +                  unsigned mode,
 +                  const struct object_id *oid,
 +                  int oid_valid,
 +                  char **buf,
 +                  unsigned long *buf_size)
 +{
 +      struct diff_filespec *df;
 +      struct userdiff_driver *textconv;
 +
 +      df = alloc_filespec(path);
 +      fill_filespec(df, oid->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;
 +}
 +
  void setup_diff_pager(struct diff_options *opt)
  {
        /*
diff --combined dir.c
index 70f2de38f23ce5f9e4c107cfdb0f7901dfd22b84,be616e884e8dbbebe95d361267b12212bce2fd9d..17590638176f26e35f3a728e5cd56917e0568541
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -7,7 -7,6 +7,7 @@@
   * Copyright (C) Linus Torvalds, 2005-2006
   *             Junio Hamano, 2005-2006
   */
 +#define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
  #include "dir.h"
  #include "attr.h"
@@@ -46,11 -45,9 +46,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 -174,7 +177,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 -587,7 +592,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 -727,7 +733,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]) &&
 +                      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))
                                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 -855,7 +862,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 -958,7 +965,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 -1233,18 +1248,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 -1262,14 +1281,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 -1455,12 +1477,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 -1759,9 +1788,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 -2043,8 +2084,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 -2272,7 +2337,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 fast-import.c
index e69d219682e7929b6e8441ba620e708704471ff3,420b3a00d30c9f02a93527e41478cd326914ce54..9a22fc92c0d029cf2a1362ea846f75f59978e870
@@@ -226,7 -226,7 +226,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 +252,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,13 +386,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 -470,7 +472,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 -555,7 +557,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 -876,7 +878,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 -1005,17 +1007,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 -1079,13 +1083,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 -1218,13 +1222,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 -1385,7 +1389,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 -1475,7 +1479,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 -1486,7 +1490,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 -1670,7 +1674,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 -1689,8 +1693,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 -1735,7 +1739,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 -1746,34 +1750,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 -1815,7 +1820,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 -1844,7 +1849,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 -1893,7 +1898,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 -2117,21 +2122,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 -2207,21 +2212,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 -2355,7 +2366,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 -2504,13 +2514,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 -2520,7 +2530,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 -2653,28 +2663,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 -2711,17 +2721,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 -2808,17 +2818,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 -2844,7 +2856,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 -2922,9 +2934,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 -2944,7 +2956,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 -3143,8 +3154,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,9 -3274,7 +3285,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 git-compat-util.h
index e83fd2eb07729561d03566cdc312636525a83ee6,87f47828a591c5774ddbaa01054159ac6d37236b..51ba4e6b3b7822915e3867722ec0b54b314111f7
@@@ -319,11 -319,6 +319,11 @@@ extern char *gitdirname(char *)
  #define PRIo32 "o"
  #endif
  
 +typedef uintmax_t timestamp_t;
 +#define PRItime PRIuMAX
 +#define parse_timestamp strtoumax
 +#define TIME_MAX UINTMAX_MAX
 +
  #ifndef PATH_SEP
  #define PATH_SEP ':'
  #endif
@@@ -450,6 -445,7 +450,6 @@@ extern void (*get_error_routine(void))(
  extern void set_warn_routine(void (*routine)(const char *warn, va_list params));
  extern void (*get_warn_routine(void))(const char *warn, va_list params);
  extern void set_die_is_recursing_routine(int (*routine)(void));
 -extern void set_error_handle(FILE *);
  
  extern int starts_with(const char *str, const char *prefix);
  
@@@ -620,7 -616,7 +620,7 @@@ extern int git_lstat(const char *, stru
  #endif
  
  #define DEFAULT_PACKED_GIT_LIMIT \
 -      ((1024L * 1024L) * (size_t)(sizeof(void*) >= 8 ? 8192 : 256))
 +      ((1024L * 1024L) * (size_t)(sizeof(void*) >= 8 ? (32 * 1024L * 1024L) : 256))
  
  #ifdef NO_PREAD
  #define pread git_pread
@@@ -693,10 -689,12 +693,12 @@@ char *gitstrdup(const char *s)
  #endif
  
  #ifdef FREAD_READS_DIRECTORIES
- #ifdef fopen
- #undef fopen
- #endif
- #define fopen(a,b) git_fopen(a,b)
+ # if !defined(SUPPRESS_FOPEN_REDEFINITION)
+ #  ifdef fopen
+ #   undef fopen
+ #  endif
+ #  define fopen(a,b) git_fopen(a,b)
+ # endif
  extern FILE *git_fopen(const char*, const char*);
  #endif
  
@@@ -804,6 -802,7 +806,7 @@@ extern int xmkstemp(char *template)
  extern int xmkstemp_mode(char *template, int mode);
  extern char *xgetcwd(void);
  extern FILE *fopen_for_writing(const char *path);
+ extern FILE *fopen_or_warn(const char *path, const char *mode);
  
  #define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc)))
  #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))
@@@ -1068,15 -1067,6 +1071,15 @@@ static inline int regexec_buf(const reg
  #define HAVE_VARIADIC_MACROS 1
  #endif
  
 +#ifdef HAVE_VARIADIC_MACROS
 +__attribute__((format (printf, 3, 4))) NORETURN
 +void BUG_fl(const char *file, int line, const char *fmt, ...);
 +#define BUG(...) BUG_fl(__FILE__, __LINE__, __VA_ARGS__)
 +#else
 +__attribute__((format (printf, 1, 2))) NORETURN
 +void BUG(const char *fmt, ...);
 +#endif
 +
  /*
   * Preserves errno, prints a message, but gives no warning for ENOENT.
   * Returns 0 on success, which includes trying to unlink an object that does
@@@ -1110,8 -1100,8 +1113,8 @@@ int remove_or_warn(unsigned int mode, c
  int access_or_warn(const char *path, int mode, unsigned flag);
  int access_or_die(const char *path, int mode, unsigned flag);
  
- /* Warn on an inaccessible file that ought to be accessible */
void warn_on_inaccessible(const char *path);
+ /* Warn on an inaccessible file if errno indicates this is an error */
int warn_on_fopen_errors(const char *path);
  
  #ifdef GMTIME_UNRELIABLE_ERRORS
  struct tm *git_gmtime(const time_t *);
@@@ -1134,21 -1124,6 +1137,21 @@@ struct tm *git_gmtime_r(const time_t *
  #define getc_unlocked(fh) getc(fh)
  #endif
  
 +/*
 + * Our code often opens a path to an optional file, to work on its
 + * contents when we can successfully open it.  We can ignore a failure
 + * to open if such an optional file does not exist, but we do want to
 + * report a failure in opening for other reasons (e.g. we got an I/O
 + * error, or the file is there, but we lack the permission to open).
 + *
 + * Call this function after seeing an error from open() or fopen() to
 + * see if the errno indicates a missing file that we can safely ignore.
 + */
 +static inline int is_missing_file_error(int errno_)
 +{
 +      return (errno_ == ENOENT || errno_ == ENOTDIR);
 +}
 +
  extern int cmd_main(int, const char **);
  
  #endif
diff --combined remote.c
index 3649d60cdce7335f6bc5bcca4810ce869dacfdcf,1f2453d0f6e0b818d3b0554b72fcd91bbed929a5..f998f989e92a6eb919828c72d444f091d5fdfa6a
+++ b/remote.c
@@@ -251,7 -251,7 +251,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 +277,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,26 +477,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 -621,7 +601,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 -638,6 +618,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 -649,7 +633,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 -1191,9 +1180,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 -1296,7 +1286,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 -1358,7 +1348,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 -1585,8 +1576,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 -1953,12 +1944,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 -2009,13 +2000,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 sequencer.c
index 924fb1d0c3c84dd823393d7dea21af2d70a8d54e,11b5c7c114137dde6e36f872b532bb9f7029af54..5282fb849c5c27e98bbe1b506340c906aa37995c
@@@ -344,7 -344,7 +344,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 +374,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 +426,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 -834,13 +836,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 -897,8 +899,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 -934,7 +936,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 -1221,7 +1224,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 -1378,7 +1381,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 -1913,11 +1916,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 -2088,6 +2093,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;
@@@ -2286,7 -2280,7 +2286,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 -2357,6 +2363,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 server-info.c
index 6f865b73a3aa014a9cecb13dbf86dede70a02a59,e01ac154a843ddf72737ffa45704e3940edab229..5ec5b1d827a54486c83efc802ebc6eb1f40062c4
@@@ -53,7 -53,7 +53,7 @@@ static int add_info_ref(const char *pat
                        int flag, void *cb_data)
  {
        FILE *fp = cb_data;
 -      struct object *o = parse_object(oid->hash);
 +      struct object *o = parse_object(oid);
        if (!o)
                return -1;
  
@@@ -133,7 -133,7 +133,7 @@@ static int read_pack_info_file(const ch
        char line[1000];
        int old_cnt = 0;
  
-       fp = fopen(infofile, "r");
+       fp = fopen_or_warn(infofile, "r");
        if (!fp)
                return 1; /* nonexistent is not an error. */
  
diff --combined wrapper.c
index 708e98a96585f8f9a800e9ddae942b94ea7372b8,b117eb14a47ab8f6e3c1424241040f3930367524..4632c7d4c08c3127c4017c98c0983871f0236d93
+++ b/wrapper.c
@@@ -418,6 -418,32 +418,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;
@@@ -576,15 -602,10 +602,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 wt-status.c
index 25aafc35c8332a311ce89002e7c17b200ccbfde6,cdf9f5eed2dad046beb9794a2675a56aaffb1ae9..bf651f16fae83ffe30676790685799e8f2280082
@@@ -665,7 -665,7 +665,7 @@@ static void wt_status_collect_untracked
                dir.untracked = the_index.untracked;
        setup_standard_excludes(&dir);
  
 -      fill_directory(&dir, &s->pathspec);
 +      fill_directory(&dir, &the_index, &s->pathspec);
  
        for (i = 0; i < dir.nr; i++) {
                struct dir_entry *ent = dir.entries[i];
@@@ -896,18 -896,17 +896,18 @@@ conclude
        status_printf_ln(s, GIT_COLOR_NORMAL, "%s", "");
  }
  
 -void wt_status_truncate_message_at_cut_line(struct strbuf *buf)
 +size_t wt_status_locate_end(const char *s, size_t len)
  {
        const char *p;
        struct strbuf pattern = STRBUF_INIT;
  
        strbuf_addf(&pattern, "\n%c %s", comment_line_char, cut_line);
 -      if (starts_with(buf->buf, pattern.buf + 1))
 -              strbuf_setlen(buf, 0);
 -      else if ((p = strstr(buf->buf, pattern.buf)))
 -              strbuf_setlen(buf, p - buf->buf + 1);
 +      if (starts_with(s, pattern.buf + 1))
 +              len = 0;
 +      else if ((p = strstr(s, pattern.buf)))
 +              len = p - s + 1;
        strbuf_release(&pattern);
 +      return len;
  }
  
  void wt_status_add_cut_line(FILE *fp)
@@@ -1003,7 -1002,7 +1003,7 @@@ static void wt_longstatus_print_trackin
                color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%c",
                                 comment_line_char);
        else
 -              fputs("", s->fp);
 +              fputs("\n", s->fp);
  }
  
  static int has_unmerged(struct wt_status *s)
@@@ -1066,7 -1065,8 +1066,8 @@@ static void show_am_in_progress(struct 
  static char *read_line_from_git_path(const char *filename)
  {
        struct strbuf buf = STRBUF_INIT;
-       FILE *fp = fopen(git_path("%s", filename), "r");
+       FILE *fp = fopen_or_warn(git_path("%s", filename), "r");
        if (!fp) {
                strbuf_release(&buf);
                return NULL;
  static int split_commit_in_progress(struct wt_status *s)
  {
        int split_in_progress = 0;
 -      char *head = read_line_from_git_path("HEAD");
 -      char *orig_head = read_line_from_git_path("ORIG_HEAD");
 -      char *rebase_amend = read_line_from_git_path("rebase-merge/amend");
 -      char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
 +      char *head, *orig_head, *rebase_amend, *rebase_orig_head;
  
 -      if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
 +      if ((!s->amend && !s->nowarn && !s->workdir_dirty) ||
            !s->branch || strcmp(s->branch, "HEAD"))
 -              return split_in_progress;
 +              return 0;
  
 -      if (!strcmp(rebase_amend, rebase_orig_head)) {
 -              if (strcmp(head, rebase_amend))
 -                      split_in_progress = 1;
 -      } else if (strcmp(orig_head, rebase_orig_head)) {
 -              split_in_progress = 1;
 -      }
 +      head = read_line_from_git_path("HEAD");
 +      orig_head = read_line_from_git_path("ORIG_HEAD");
 +      rebase_amend = read_line_from_git_path("rebase-merge/amend");
 +      rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
  
 -      if (!s->amend && !s->nowarn && !s->workdir_dirty)
 -              split_in_progress = 0;
 +      if (!head || !orig_head || !rebase_amend || !rebase_orig_head)
 +              ; /* fall through, no split in progress */
 +      else if (!strcmp(rebase_amend, rebase_orig_head))
 +              split_in_progress = !!strcmp(head, rebase_amend);
 +      else if (strcmp(orig_head, rebase_orig_head))
 +              split_in_progress = 1;
  
        free(head);
        free(orig_head);
        free(rebase_amend);
        free(rebase_orig_head);
 +
        return split_in_progress;
  }
  
@@@ -1169,7 -1169,6 +1170,7 @@@ static int read_rebase_todolist(const c
                abbrev_sha1_in_line(&line);
                string_list_append(lines, line.buf);
        }
 +      fclose(f);
        return 0;
  }
  
@@@ -1389,7 -1388,7 +1390,7 @@@ struct grab_1st_switch_cbdata 
  };
  
  static int grab_1st_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_1st_switch_cbdata *cb = cb_data;
@@@ -1430,7 -1429,7 +1431,7 @@@ static void wt_status_get_detached_from
            /* sha1 is a commit? match without further lookup */
            (!oidcmp(&cb.noid, &oid) ||
             /* perhaps sha1 is a tag, try to dereference to a commit */
 -           ((commit = lookup_commit_reference_gently(oid.hash, 1)) != NULL &&
 +           ((commit = lookup_commit_reference_gently(&oid, 1)) != NULL &&
              !oidcmp(&cb.noid, &commit->object.oid)))) {
                const char *from = ref;
                if (!skip_prefix(from, "refs/tags/", &from))