Merge branch 'jk/cocci'
authorJunio C Hamano <gitster@pobox.com>
Mon, 17 Sep 2018 20:53:57 +0000 (13:53 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 17 Sep 2018 20:53:57 +0000 (13:53 -0700)
spatch transformation to replace boolean uses of !hashcmp() to
newly introduced oideq() is added, and applied, to regain
performance lost due to support of multiple hash algorithms.

* jk/cocci:
show_dirstat: simplify same-content check
read-cache: use oideq() in ce_compare functions
convert hashmap comparison functions to oideq()
convert "hashcmp() != 0" to "!hasheq()"
convert "oidcmp() != 0" to "!oideq()"
convert "hashcmp() == 0" to hasheq()
convert "oidcmp() == 0" to oideq()
introduce hasheq() and oideq()
coccinelle: use <...> for function exclusion

32 files changed:
1  2 
bisect.c
builtin/am.c
builtin/checkout.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/log.c
builtin/merge.c
builtin/pack-objects.c
builtin/pull.c
builtin/receive-pack.c
builtin/remote.c
cache-tree.c
cache.h
commit-graph.c
commit.c
diff-lib.c
diff.c
dir.c
fast-import.c
http-push.c
log-tree.c
merge-recursive.c
notes-merge.c
pack-objects.c
packfile.c
read-cache.c
remote.c
revision.c
sequencer.c
sha1-name.c
submodule.c
unpack-trees.c
diff --combined bisect.c
index d023543c911d040b651f343a05b818b053def808,7c1d8f1a6dbb6f08b003ad858889c4d59e204923..958e72c6b902730cdeec0e4696e44635f072f1b2
+++ b/bisect.c
@@@ -13,7 -13,6 +13,7 @@@
  #include "sha1-array.h"
  #include "argv-array.h"
  #include "commit-slab.h"
 +#include "commit-reach.h"
  
  static struct oid_array good_revs;
  static struct oid_array skipped_revs;
@@@ -596,7 -595,7 +596,7 @@@ static struct commit_list *skip_away(st
  
        for (i = 0; cur; cur = cur->next, i++) {
                if (i == index) {
-                       if (oidcmp(&cur->item->object.oid, current_bad_oid))
+                       if (!oideq(&cur->item->object.oid, current_bad_oid))
                                return cur;
                        if (previous)
                                return previous;
@@@ -808,7 -807,7 +808,7 @@@ static void check_merge_bases(int rev_n
  
        for (; result; result = result->next) {
                const struct object_id *mb = &result->item->object.oid;
-               if (!oidcmp(mb, current_bad_oid)) {
+               if (oideq(mb, current_bad_oid)) {
                        handle_bad_merge_base();
                } else if (0 <= oid_array_lookup(&good_revs, mb)) {
                        continue;
@@@ -989,7 -988,7 +989,7 @@@ int bisect_next_all(const char *prefix
  
        bisect_rev = &revs.commits->item->object.oid;
  
-       if (!oidcmp(bisect_rev, current_bad_oid)) {
+       if (oideq(bisect_rev, current_bad_oid)) {
                exit_if_skipped_commits(tried, current_bad_oid);
                printf("%s is the first %s commit\n", oid_to_hex(bisect_rev),
                        term_bad);
diff --combined builtin/am.c
index 5e866d17c7c7b46ccf671916c853be228bf38ad6,e54110d4742e19b55a49ab569650d4a9b4511786..162a048bf7a6399b3ab1b5a33045ba726803ff0e
@@@ -1598,7 -1598,6 +1598,7 @@@ static int fall_back_threeway(const str
        o.branch1 = "HEAD";
        their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg);
        o.branch2 = their_tree_name;
 +      o.detect_directory_renames = 0;
  
        if (state->quiet)
                o.verbosity = 0;
@@@ -2078,7 -2077,7 +2078,7 @@@ static int safe_to_abort(const struct a
        if (get_oid("HEAD", &head))
                oidclr(&head);
  
-       if (!oidcmp(&head, &abort_safety))
+       if (oideq(&head, &abort_safety))
                return 1;
  
        warning(_("You seem to have moved HEAD since the last 'am' failure.\n"
diff --combined builtin/checkout.c
index 67a83fb95bb5a11acef857bdcd4e07535bb3f073,082e3a9f19f71f628d0529262bc9fecfcd47b5ee..b30b48767e54a93f18ef0d341a04f14cc390e9a9
@@@ -25,8 -25,6 +25,8 @@@
  #include "submodule.h"
  #include "advice.h"
  
 +static int checkout_optimize_new_branch;
 +
  static const char * const checkout_usage[] = {
        N_("git checkout [<options>] <branch>"),
        N_("git checkout [<options>] [<branch>] -- <file>..."),
@@@ -44,10 -42,6 +44,10 @@@ struct checkout_opts 
        int ignore_skipworktree;
        int ignore_other_worktrees;
        int show_progress;
 +      /*
 +       * If new checkout options are added, skip_merge_working_tree
 +       * should be updated accordingly.
 +       */
  
        const char *new_branch;
        const char *new_branch_force;
@@@ -102,7 -96,7 +102,7 @@@ static int update_some(const struct obj
        if (pos >= 0) {
                struct cache_entry *old = active_cache[pos];
                if (ce->ce_mode == old->ce_mode &&
-                   !oidcmp(&ce->oid, &old->oid)) {
+                   oideq(&ce->oid, &old->oid)) {
                        old->ce_flags |= CE_UPDATE;
                        discard_cache_entry(ce);
                        return 0;
@@@ -478,98 -472,6 +478,98 @@@ static void setup_branch_path(struct br
        branch->path = strbuf_detach(&buf, NULL);
  }
  
 +/*
 + * Skip merging the trees, updating the index and working directory if and
 + * only if we are creating a new branch via "git checkout -b <new_branch>."
 + */
 +static int skip_merge_working_tree(const struct checkout_opts *opts,
 +      const struct branch_info *old_branch_info,
 +      const struct branch_info *new_branch_info)
 +{
 +      /*
 +       * Do the merge if sparse checkout is on and the user has not opted in
 +       * to the optimized behavior
 +       */
 +      if (core_apply_sparse_checkout && !checkout_optimize_new_branch)
 +              return 0;
 +
 +      /*
 +       * We must do the merge if we are actually moving to a new commit.
 +       */
 +      if (!old_branch_info->commit || !new_branch_info->commit ||
 +              oidcmp(&old_branch_info->commit->object.oid, &new_branch_info->commit->object.oid))
 +              return 0;
 +
 +      /*
 +       * opts->patch_mode cannot be used with switching branches so is
 +       * not tested here
 +       */
 +
 +      /*
 +       * opts->quiet only impacts output so doesn't require a merge
 +       */
 +
 +      /*
 +       * Honor the explicit request for a three-way merge or to throw away
 +       * local changes
 +       */
 +      if (opts->merge || opts->force)
 +              return 0;
 +
 +      /*
 +       * --detach is documented as "updating the index and the files in the
 +       * working tree" but this optimization skips those steps so fall through
 +       * to the regular code path.
 +       */
 +      if (opts->force_detach)
 +              return 0;
 +
 +      /*
 +       * opts->writeout_stage cannot be used with switching branches so is
 +       * not tested here
 +       */
 +
 +      /*
 +       * Honor the explicit ignore requests
 +       */
 +      if (!opts->overwrite_ignore || opts->ignore_skipworktree ||
 +              opts->ignore_other_worktrees)
 +              return 0;
 +
 +      /*
 +       * opts->show_progress only impacts output so doesn't require a merge
 +       */
 +
 +      /*
 +       * If we aren't creating a new branch any changes or updates will
 +       * happen in the existing branch.  Since that could only be updating
 +       * the index and working directory, we don't want to skip those steps
 +       * or we've defeated any purpose in running the command.
 +       */
 +      if (!opts->new_branch)
 +              return 0;
 +
 +      /*
 +       * new_branch_force is defined to "create/reset and checkout a branch"
 +       * so needs to go through the merge to do the reset
 +       */
 +      if (opts->new_branch_force)
 +              return 0;
 +
 +      /*
 +       * A new orphaned branch requrires the index and the working tree to be
 +       * adjusted to <start_point>
 +       */
 +      if (opts->new_orphan_branch)
 +              return 0;
 +
 +      /*
 +       * Remaining variables are not checkout options but used to track state
 +       */
 +
 +      return 1;
 +}
 +
  static int merge_working_tree(const struct checkout_opts *opts,
                              struct branch_info *old_branch_info,
                              struct branch_info *new_branch_info,
@@@ -944,19 -846,10 +944,19 @@@ static int switch_branches(const struc
                parse_commit_or_die(new_branch_info->commit);
        }
  
 -      ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error);
 -      if (ret) {
 -              free(path_to_free);
 -              return ret;
 +      /* optimize the "checkout -b <new_branch> path */
 +      if (skip_merge_working_tree(opts, &old_branch_info, new_branch_info)) {
 +              if (!checkout_optimize_new_branch && !opts->quiet) {
 +                      if (read_cache_preload(NULL) < 0)
 +                              return error(_("index file corrupt"));
 +                      show_local_changes(&new_branch_info->commit->object, &opts->diff_options);
 +              }
 +      } else {
 +              ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error);
 +              if (ret) {
 +                      free(path_to_free);
 +                      return ret;
 +              }
        }
  
        if (!opts->quiet && !old_branch_info.path && old_branch_info.commit && new_branch_info->commit != old_branch_info.commit)
  
  static int git_checkout_config(const char *var, const char *value, void *cb)
  {
 +      if (!strcmp(var, "checkout.optimizenewbranch")) {
 +              checkout_optimize_new_branch = git_config_bool(var, value);
 +              return 0;
 +      }
 +
        if (!strcmp(var, "diff.ignoresubmodules")) {
                struct checkout_opts *opts = cb;
                handle_ignore_submodules_arg(&opts->diff_options, value);
diff --combined builtin/fetch.c
index eed15c78137a7e86be3ad7600b0001e33b1f7aa7,84e0e8080f3189468a78b9fd13564a5ed812ff65..dc0931fb464e5b81badf3a0a81f5dfd4b52129bf
@@@ -22,7 -22,6 +22,7 @@@
  #include "utf8.h"
  #include "packfile.h"
  #include "list-objects-filter-options.h"
 +#include "commit-reach.h"
  
  static const char * const builtin_fetch_usage[] = {
        N_("git fetch [<options>] [<repository> [<refspec>...]]"),
@@@ -239,7 -238,7 +239,7 @@@ static int will_fetch(struct ref **head
  {
        struct ref *rm = *head;
        while (rm) {
-               if (!hashcmp(rm->old_oid.hash, sha1))
+               if (hasheq(rm->old_oid.hash, sha1))
                        return 1;
                rm = rm->next;
        }
@@@ -508,7 -507,7 +508,7 @@@ static void adjust_refcol_width(const s
        int max, rlen, llen, len;
  
        /* uptodate lines are only shown on high verbosity level */
-       if (!verbosity && !oidcmp(&ref->peer_ref->old_oid, &ref->old_oid))
+       if (!verbosity && oideq(&ref->peer_ref->old_oid, &ref->old_oid))
                return;
  
        max    = term_columns();
@@@ -645,7 -644,7 +645,7 @@@ static int update_local_ref(struct ref 
        if (type < 0)
                die(_("object %s not found"), oid_to_hex(&ref->new_oid));
  
-       if (!oidcmp(&ref->old_oid, &ref->new_oid)) {
+       if (oideq(&ref->old_oid, &ref->new_oid)) {
                if (verbosity > 0)
                        format_display(display, '=', _("[up to date]"), NULL,
                                       remote, pretty_ref, summary_width);
diff --combined builtin/fmt-merge-msg.c
index e5668f27d8df7deee8705587e3c9eddb0be61818,268f0c20ca8a17ae595ca363e421c0f814be956a..59a40342b675130de6a2ddd76451bff8818e9623
@@@ -12,7 -12,6 +12,7 @@@
  #include "fmt-merge-msg.h"
  #include "gpg-interface.h"
  #include "repository.h"
 +#include "commit-reach.h"
  
  static const char * const fmt_merge_msg_usage[] = {
        N_("git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"),
@@@ -79,9 -78,9 +79,9 @@@ static struct merge_parent *find_merge_
  {
        int i;
        for (i = 0; i < table->nr; i++) {
-               if (given && oidcmp(&table->item[i].given, given))
+               if (given && !oideq(&table->item[i].given, given))
                        continue;
-               if (commit && oidcmp(&table->item[i].commit, commit))
+               if (commit && !oideq(&table->item[i].commit, commit))
                        continue;
                return &table->item[i];
        }
@@@ -583,7 -582,7 +583,7 @@@ static void find_merge_parents(struct m
        while (parents) {
                struct commit *cmit = pop_commit(&parents);
                for (i = 0; i < result->nr; i++)
-                       if (!oidcmp(&result->item[i].commit, &cmit->object.oid))
+                       if (oideq(&result->item[i].commit, &cmit->object.oid))
                                result->item[i].used = 1;
        }
  
diff --combined builtin/log.c
index f09a5789f8a5a5252e9629b6c949adb2c365bf7e,98d668b56f73a377afd69854fb78106a0630ebac..1dbb9d829bffcb25739737783c4fd4fd734f5940
@@@ -31,9 -31,6 +31,9 @@@
  #include "progress.h"
  #include "commit-slab.h"
  #include "repository.h"
 +#include "commit-reach.h"
 +#include "interdiff.h"
 +#include "range-diff.h"
  
  #define MAIL_DEFAULT_WRAP 72
  
@@@ -995,32 -992,12 +995,32 @@@ static char *find_branch_name(struct re
        tip_oid = &rev->cmdline.rev[positive].item->oid;
        if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref) &&
            skip_prefix(full_ref, "refs/heads/", &v) &&
-           !oidcmp(tip_oid, &branch_oid))
+           oideq(tip_oid, &branch_oid))
                branch = xstrdup(v);
        free(full_ref);
        return branch;
  }
  
 +static void show_diffstat(struct rev_info *rev,
 +                        struct commit *origin, struct commit *head)
 +{
 +      struct diff_options opts;
 +
 +      memcpy(&opts, &rev->diffopt, sizeof(opts));
 +      opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
 +      opts.stat_width = MAIL_DEFAULT_WRAP;
 +
 +      diff_setup_done(&opts);
 +
 +      diff_tree_oid(get_commit_tree_oid(origin),
 +                    get_commit_tree_oid(head),
 +                    "", &opts);
 +      diffcore_std(&opts);
 +      diff_flush(&opts);
 +
 +      fprintf(rev->diffopt.file, "\n");
 +}
 +
  static void make_cover_letter(struct rev_info *rev, int use_stdout,
                              struct commit *origin,
                              int nr, struct commit **list,
        struct strbuf sb = STRBUF_INIT;
        int i;
        const char *encoding = "UTF-8";
 -      struct diff_options opts;
        int need_8bit_cte = 0;
        struct pretty_print_context pp = {0};
        struct commit *head = list[0];
  
        shortlog_output(&log);
  
 -      /*
 -       * We can only do diffstat with a unique reference point
 -       */
 -      if (!origin)
 -              return;
 -
 -      memcpy(&opts, &rev->diffopt, sizeof(opts));
 -      opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
 -      opts.stat_width = MAIL_DEFAULT_WRAP;
 +      /* We can only do diffstat with a unique reference point */
 +      if (origin)
 +              show_diffstat(rev, origin, head);
  
 -      diff_setup_done(&opts);
 -
 -      diff_tree_oid(get_commit_tree_oid(origin),
 -                    get_commit_tree_oid(head),
 -                    "", &opts);
 -      diffcore_std(&opts);
 -      diff_flush(&opts);
 +      if (rev->idiff_oid1) {
 +              fprintf_ln(rev->diffopt.file, "%s", rev->idiff_title);
 +              show_interdiff(rev, 0);
 +      }
  
 -      fprintf(rev->diffopt.file, "\n");
 +      if (rev->rdiff1) {
 +              fprintf_ln(rev->diffopt.file, "%s", rev->rdiff_title);
 +              show_range_diff(rev->rdiff1, rev->rdiff2,
 +                              rev->creation_factor, 1, &rev->diffopt);
 +      }
  }
  
  static const char *clean_message_id(const char *msg_id)
@@@ -1436,36 -1419,6 +1436,36 @@@ static void print_bases(struct base_tre
        oidclr(&bases->base_commit);
  }
  
 +static const char *diff_title(struct strbuf *sb, int reroll_count,
 +                     const char *generic, const char *rerolled)
 +{
 +      if (reroll_count <= 0)
 +              strbuf_addstr(sb, generic);
 +      else /* RFC may be v0, so allow -v1 to diff against v0 */
 +              strbuf_addf(sb, rerolled, reroll_count - 1);
 +      return sb->buf;
 +}
 +
 +static void infer_range_diff_ranges(struct strbuf *r1,
 +                                  struct strbuf *r2,
 +                                  const char *prev,
 +                                  struct commit *origin,
 +                                  struct commit *head)
 +{
 +      const char *head_oid = oid_to_hex(&head->object.oid);
 +
 +      if (!strstr(prev, "..")) {
 +              strbuf_addf(r1, "%s..%s", head_oid, prev);
 +              strbuf_addf(r2, "%s..%s", prev, head_oid);
 +      } else if (!origin) {
 +              die(_("failed to infer range-diff ranges"));
 +      } else {
 +              strbuf_addstr(r1, prev);
 +              strbuf_addf(r2, "%s..%s",
 +                          oid_to_hex(&origin->object.oid), head_oid);
 +      }
 +}
 +
  int cmd_format_patch(int argc, const char **argv, const char *prefix)
  {
        struct commit *commit;
        struct base_tree_info bases;
        int show_progress = 0;
        struct progress *progress = NULL;
 +      struct oid_array idiff_prev = OID_ARRAY_INIT;
 +      struct strbuf idiff_title = STRBUF_INIT;
 +      const char *rdiff_prev = NULL;
 +      struct strbuf rdiff1 = STRBUF_INIT;
 +      struct strbuf rdiff2 = STRBUF_INIT;
 +      struct strbuf rdiff_title = STRBUF_INIT;
 +      int creation_factor = -1;
  
        const struct option builtin_format_patch_options[] = {
                { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
                OPT__QUIET(&quiet, N_("don't print the patch filenames")),
                OPT_BOOL(0, "progress", &show_progress,
                         N_("show progress while generating patches")),
 +              OPT_CALLBACK(0, "interdiff", &idiff_prev, N_("rev"),
 +                           N_("show changes against <rev> in cover letter or single patch"),
 +                           parse_opt_object_name),
 +              OPT_STRING(0, "range-diff", &rdiff_prev, N_("refspec"),
 +                         N_("show changes against <refspec> in cover letter or single patch")),
 +              OPT_INTEGER(0, "creation-factor", &creation_factor,
 +                          N_("percentage by which creation is weighted")),
                OPT_END()
        };
  
                /* Don't say anything if head and upstream are the same. */
                if (rev.pending.nr == 2) {
                        struct object_array_entry *o = rev.pending.objects;
-                       if (oidcmp(&o[0].item->oid, &o[1].item->oid) == 0)
+                       if (oideq(&o[0].item->oid, &o[1].item->oid))
 -                              return 0;
 +                              goto done;
                }
                get_patch_ids(&rev, &ids);
        }
        }
        if (nr == 0)
                /* nothing to do */
 -              return 0;
 +              goto done;
        total = nr;
        if (cover_letter == -1) {
                if (config_cover_letter == COVER_AUTO)
        if (numbered)
                rev.total = total + start_number - 1;
  
 +      if (idiff_prev.nr) {
 +              if (!cover_letter && total != 1)
 +                      die(_("--interdiff requires --cover-letter or single patch"));
 +              rev.idiff_oid1 = &idiff_prev.oid[idiff_prev.nr - 1];
 +              rev.idiff_oid2 = get_commit_tree_oid(list[0]);
 +              rev.idiff_title = diff_title(&idiff_title, reroll_count,
 +                                           _("Interdiff:"),
 +                                           _("Interdiff against v%d:"));
 +      }
 +
 +      if (creation_factor < 0)
 +              creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT;
 +      else if (!rdiff_prev)
 +              die(_("--creation-factor requires --range-diff"));
 +
 +      if (rdiff_prev) {
 +              if (!cover_letter && total != 1)
 +                      die(_("--range-diff requires --cover-letter or single patch"));
 +
 +              infer_range_diff_ranges(&rdiff1, &rdiff2, rdiff_prev,
 +                                      origin, list[0]);
 +              rev.rdiff1 = rdiff1.buf;
 +              rev.rdiff2 = rdiff2.buf;
 +              rev.creation_factor = creation_factor;
 +              rev.rdiff_title = diff_title(&rdiff_title, reroll_count,
 +                                           _("Range-diff:"),
 +                                           _("Range-diff against v%d:"));
 +      }
 +
        if (!signature) {
                ; /* --no-signature inhibits all signatures */
        } else if (signature && signature != git_version_string) {
                print_signature(rev.diffopt.file);
                total++;
                start_number--;
 +              /* interdiff/range-diff in cover-letter; omit from patches */
 +              rev.idiff_oid1 = NULL;
 +              rev.rdiff1 = NULL;
        }
        rev.add_signoff = do_signoff;
  
        string_list_clear(&extra_hdr, 0);
        if (ignore_if_in_upstream)
                free_patch_ids(&ids);
 +
 +done:
 +      oid_array_clear(&idiff_prev);
 +      strbuf_release(&idiff_title);
 +      strbuf_release(&rdiff1);
 +      strbuf_release(&rdiff2);
 +      strbuf_release(&rdiff_title);
        return 0;
  }
  
@@@ -2049,7 -1949,7 +2049,7 @@@ int cmd_cherry(int argc, const char **a
        /* Don't say anything if head and upstream are the same. */
        if (revs.pending.nr == 2) {
                struct object_array_entry *o = revs.pending.objects;
-               if (oidcmp(&o[0].item->oid, &o[1].item->oid) == 0)
+               if (oideq(&o[0].item->oid, &o[1].item->oid))
                        return 0;
        }
  
diff --combined builtin/merge.c
index 7a8e3e274f43c6b184defe24d9d4c09a76d63a3e,8d85d31a61b8fbb53b04a9f506c0d7aca93e35d9..e331ca6d481005f6122fa6fda6075728f893632d
@@@ -36,7 -36,6 +36,7 @@@
  #include "packfile.h"
  #include "tag.h"
  #include "alias.h"
 +#include "commit-reach.h"
  
  #define DEFAULT_TWOHEAD (1<<0)
  #define DEFAULT_OCTOPUS (1<<1)
@@@ -1190,7 -1189,7 +1190,7 @@@ static int merging_a_throwaway_tag(stru
        tag_ref = xstrfmt("refs/tags/%s",
                          ((struct tag *)merge_remote_util(commit)->obj)->tag);
        if (!read_ref(tag_ref, &oid) &&
-           !oidcmp(&oid, &merge_remote_util(commit)->obj->oid))
+           oideq(&oid, &merge_remote_util(commit)->obj->oid))
                is_throwaway_tag = 0;
        else
                is_throwaway_tag = 1;
@@@ -1449,7 -1448,7 +1449,7 @@@ int cmd_merge(int argc, const char **ar
                goto done;
        } else if (fast_forward != FF_NO && !remoteheads->next &&
                        !common->next &&
-                       !oidcmp(&common->item->object.oid, &head_commit->object.oid)) {
+                       oideq(&common->item->object.oid, &head_commit->object.oid)) {
                /* Again the most common case of merging one remote. */
                struct strbuf msg = STRBUF_INIT;
                struct commit *commit;
                         * HEAD^^" would be missed.
                         */
                        common_one = get_merge_bases(head_commit, j->item);
-                       if (oidcmp(&common_one->item->object.oid, &j->item->object.oid)) {
+                       if (!oideq(&common_one->item->object.oid, &j->item->object.oid)) {
                                up_to_date = 0;
                                break;
                        }
diff --combined builtin/pack-objects.c
index 425bdc8ac5f7b341b18e387eb4df922ebea085ba,64156f676bdedd76a4e0a45dcab60e14a8e66ef8..5041818ddf1843ade5aca00ba3247cbe45f32c68
@@@ -24,7 -24,6 +24,7 @@@
  #include "streaming.h"
  #include "thread-utils.h"
  #include "pack-bitmap.h"
 +#include "delta-islands.h"
  #include "reachable.h"
  #include "sha1-array.h"
  #include "argv-array.h"
@@@ -32,7 -31,6 +32,7 @@@
  #include "packfile.h"
  #include "object-store.h"
  #include "dir.h"
 +#include "midx.h"
  
  #define IN_PACK(obj) oe_in_pack(&to_pack, obj)
  #define SIZE(obj) oe_size(&to_pack, obj)
@@@ -42,7 -40,6 +42,7 @@@
  #define DELTA_CHILD(obj) oe_delta_child(&to_pack, obj)
  #define DELTA_SIBLING(obj) oe_delta_sibling(&to_pack, obj)
  #define SET_DELTA(obj, val) oe_set_delta(&to_pack, obj, val)
 +#define SET_DELTA_EXT(obj, oid) oe_set_delta_ext(&to_pack, obj, oid)
  #define SET_DELTA_SIZE(obj, val) oe_set_delta_size(&to_pack, obj, val)
  #define SET_DELTA_CHILD(obj, val) oe_set_delta_child(&to_pack, obj, val)
  #define SET_DELTA_SIBLING(obj, val) oe_set_delta_sibling(&to_pack, obj, val)
@@@ -62,8 -59,6 +62,8 @@@ static struct packing_data to_pack
  
  static struct pack_idx_entry **written_list;
  static uint32_t nr_result, nr_written, nr_seen;
 +static struct bitmap_index *bitmap_git;
 +static uint32_t write_layer;
  
  static int non_empty;
  static int reuse_delta = 1, reuse_object = 1;
@@@ -84,7 -79,6 +84,7 @@@ static unsigned long pack_size_limit
  static int depth = 50;
  static int delta_search_threads;
  static int pack_to_stdout;
 +static int thin;
  static int num_preferred_base;
  static struct progress *progress_state;
  
@@@ -99,8 -93,6 +99,8 @@@ static uint16_t write_bitmap_options
  
  static int exclude_promisor_objects;
  
 +static int use_delta_islands;
 +
  static unsigned long delta_cache_size = 0;
  static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
  static unsigned long cache_max_small_delta_size = 1000;
@@@ -620,7 -612,7 +620,7 @@@ static inline void add_to_write_order(s
                               unsigned int *endp,
                               struct object_entry *e)
  {
 -      if (e->filled)
 +      if (e->filled || oe_layer(&to_pack, e) != write_layer)
                return;
        wo[(*endp)++] = e;
        e->filled = 1;
@@@ -680,15 -672,48 +680,15 @@@ static void add_family_to_write_order(s
        add_descendants_to_write_order(wo, endp, root);
  }
  
 -static struct object_entry **compute_write_order(void)
 +static void compute_layer_order(struct object_entry **wo, unsigned int *wo_end)
  {
 -      unsigned int i, wo_end, last_untagged;
 -
 -      struct object_entry **wo;
 +      unsigned int i, last_untagged;
        struct object_entry *objects = to_pack.objects;
  
        for (i = 0; i < to_pack.nr_objects; i++) {
 -              objects[i].tagged = 0;
 -              objects[i].filled = 0;
 -              SET_DELTA_CHILD(&objects[i], NULL);
 -              SET_DELTA_SIBLING(&objects[i], NULL);
 -      }
 -
 -      /*
 -       * Fully connect delta_child/delta_sibling network.
 -       * Make sure delta_sibling is sorted in the original
 -       * recency order.
 -       */
 -      for (i = to_pack.nr_objects; i > 0;) {
 -              struct object_entry *e = &objects[--i];
 -              if (!DELTA(e))
 -                      continue;
 -              /* Mark me as the first child */
 -              e->delta_sibling_idx = DELTA(e)->delta_child_idx;
 -              SET_DELTA_CHILD(DELTA(e), e);
 -      }
 -
 -      /*
 -       * Mark objects that are at the tip of tags.
 -       */
 -      for_each_tag_ref(mark_tagged, NULL);
 -
 -      /*
 -       * Give the objects in the original recency order until
 -       * we see a tagged tip.
 -       */
 -      ALLOC_ARRAY(wo, to_pack.nr_objects);
 -      for (i = wo_end = 0; i < to_pack.nr_objects; i++) {
                if (objects[i].tagged)
                        break;
 -              add_to_write_order(wo, &wo_end, &objects[i]);
 +              add_to_write_order(wo, wo_end, &objects[i]);
        }
        last_untagged = i;
  
         */
        for (; i < to_pack.nr_objects; i++) {
                if (objects[i].tagged)
 -                      add_to_write_order(wo, &wo_end, &objects[i]);
 +                      add_to_write_order(wo, wo_end, &objects[i]);
        }
  
        /*
                if (oe_type(&objects[i]) != OBJ_COMMIT &&
                    oe_type(&objects[i]) != OBJ_TAG)
                        continue;
 -              add_to_write_order(wo, &wo_end, &objects[i]);
 +              add_to_write_order(wo, wo_end, &objects[i]);
        }
  
        /*
        for (i = last_untagged; i < to_pack.nr_objects; i++) {
                if (oe_type(&objects[i]) != OBJ_TREE)
                        continue;
 -              add_to_write_order(wo, &wo_end, &objects[i]);
 +              add_to_write_order(wo, wo_end, &objects[i]);
        }
  
        /*
         * Finally all the rest in really tight order
         */
        for (i = last_untagged; i < to_pack.nr_objects; i++) {
 -              if (!objects[i].filled)
 -                      add_family_to_write_order(wo, &wo_end, &objects[i]);
 +              if (!objects[i].filled && oe_layer(&to_pack, &objects[i]) == write_layer)
 +                      add_family_to_write_order(wo, wo_end, &objects[i]);
 +      }
 +}
 +
 +static struct object_entry **compute_write_order(void)
 +{
 +      uint32_t max_layers = 1;
 +      unsigned int i, wo_end;
 +
 +      struct object_entry **wo;
 +      struct object_entry *objects = to_pack.objects;
 +
 +      for (i = 0; i < to_pack.nr_objects; i++) {
 +              objects[i].tagged = 0;
 +              objects[i].filled = 0;
 +              SET_DELTA_CHILD(&objects[i], NULL);
 +              SET_DELTA_SIBLING(&objects[i], NULL);
        }
  
 +      /*
 +       * Fully connect delta_child/delta_sibling network.
 +       * Make sure delta_sibling is sorted in the original
 +       * recency order.
 +       */
 +      for (i = to_pack.nr_objects; i > 0;) {
 +              struct object_entry *e = &objects[--i];
 +              if (!DELTA(e))
 +                      continue;
 +              /* Mark me as the first child */
 +              e->delta_sibling_idx = DELTA(e)->delta_child_idx;
 +              SET_DELTA_CHILD(DELTA(e), e);
 +      }
 +
 +      /*
 +       * Mark objects that are at the tip of tags.
 +       */
 +      for_each_tag_ref(mark_tagged, NULL);
 +
 +      if (use_delta_islands)
 +              max_layers = compute_pack_layers(&to_pack);
 +
 +      ALLOC_ARRAY(wo, to_pack.nr_objects);
 +      wo_end = 0;
 +
 +      for (; write_layer < max_layers; ++write_layer)
 +              compute_layer_order(wo, &wo_end);
 +
        if (wo_end != to_pack.nr_objects)
                die(_("ordered %u objects, expected %"PRIu32),
                    wo_end, to_pack.nr_objects);
@@@ -1059,7 -1040,6 +1059,7 @@@ static int want_object_in_pack(const st
  {
        int want;
        struct list_head *pos;
 +      struct multi_pack_index *m;
  
        if (!exclude && local && has_loose_object_nonlocal(oid))
                return 0;
                if (want != -1)
                        return want;
        }
 +
 +      for (m = get_multi_pack_index(the_repository); m; m = m->next) {
 +              struct pack_entry e;
 +              if (fill_midx_entry(oid, &e, m)) {
 +                      struct packed_git *p = e.p;
 +                      off_t offset;
 +
 +                      if (p == *found_pack)
 +                              offset = *found_offset;
 +                      else
 +                              offset = find_pack_entry_one(oid->hash, p);
 +
 +                      if (offset) {
 +                              if (!*found_pack) {
 +                                      if (!is_pack_valid(p))
 +                                              continue;
 +                                      *found_offset = offset;
 +                                      *found_pack = p;
 +                              }
 +                              want = want_found_object(exclude, p);
 +                              if (want != -1)
 +                                      return want;
 +                      }
 +              }
 +      }
 +
        list_for_each(pos, get_packed_git_mru(the_repository)) {
                struct packed_git *p = list_entry(pos, struct packed_git, mru);
                off_t offset;
@@@ -1248,7 -1202,7 +1248,7 @@@ static struct pbase_tree_cache *pbase_t
         */
        for (neigh = 0; neigh < 8; neigh++) {
                ent = pbase_tree_cache[my_ix];
-               if (ent && !oidcmp(&ent->oid, oid)) {
+               if (ent && oideq(&ent->oid, oid)) {
                        ent->ref++;
                        return ent;
                }
@@@ -1430,7 -1384,7 +1430,7 @@@ static void add_preferred_base(struct o
                return;
  
        for (it = pbase_tree; it; it = it->next) {
-               if (!oidcmp(&it->pcache.oid, &tree_oid)) {
+               if (oideq(&it->pcache.oid, &tree_oid)) {
                        free(data);
                        return;
                }
@@@ -1556,16 -1510,11 +1556,16 @@@ static void check_object(struct object_
                        break;
                }
  
 -              if (base_ref && (base_entry = packlist_find(&to_pack, base_ref, NULL))) {
 +              if (base_ref && (
 +                  (base_entry = packlist_find(&to_pack, base_ref, NULL)) ||
 +                  (thin &&
 +                   bitmap_has_sha1_in_uninteresting(bitmap_git, base_ref))) &&
 +                  in_same_island(&entry->idx.oid, &base_entry->idx.oid)) {
                        /*
                         * If base_ref was set above that means we wish to
 -                       * reuse delta data, and we even found that base
 -                       * in the list of objects we want to pack. Goodie!
 +                       * reuse delta data, and either we found that object in
 +                       * the list of objects we want to pack, or it's one we
 +                       * know the receiver has.
                         *
                         * Depth value does not matter - find_deltas() will
                         * never consider reused delta as the base object to
                         */
                        oe_set_type(entry, entry->in_pack_type);
                        SET_SIZE(entry, in_pack_size); /* delta size */
 -                      SET_DELTA(entry, base_entry);
                        SET_DELTA_SIZE(entry, in_pack_size);
 -                      entry->delta_sibling_idx = base_entry->delta_child_idx;
 -                      SET_DELTA_CHILD(base_entry, entry);
 +
 +                      if (base_entry) {
 +                              SET_DELTA(entry, base_entry);
 +                              entry->delta_sibling_idx = base_entry->delta_child_idx;
 +                              SET_DELTA_CHILD(base_entry, entry);
 +                      } else {
 +                              SET_DELTA_EXT(entry, base_ref);
 +                      }
 +
                        unuse_pack(&w_curs);
                        return;
                }
@@@ -1883,11 -1826,6 +1883,11 @@@ static int type_size_sort(const void *_
                return -1;
        if (a->preferred_base < b->preferred_base)
                return 1;
 +      if (use_delta_islands) {
 +              int island_cmp = island_delta_cmp(&a->idx.oid, &b->idx.oid);
 +              if (island_cmp)
 +                      return island_cmp;
 +      }
        if (a_size > b_size)
                return -1;
        if (a_size < b_size)
@@@ -2048,9 -1986,6 +2048,9 @@@ static int try_delta(struct unpacked *t
        if (trg_size < src_size / 32)
                return 0;
  
 +      if (!in_same_island(&trg->entry->idx.oid, &src->entry->idx.oid))
 +              return 0;
 +
        /* Load data if not already done */
        if (!trg->data) {
                read_lock();
@@@ -2593,9 -2528,6 +2593,9 @@@ static void prepare_pack(int window, in
        uint32_t i, nr_deltas;
        unsigned n;
  
 +      if (use_delta_islands)
 +              resolve_tree_islands(progress, &to_pack);
 +
        get_object_details();
  
        /*
@@@ -2759,9 -2691,6 +2759,9 @@@ static void show_commit(struct commit *
  
        if (write_bitmap_index)
                index_commit_for_bitmap(commit);
 +
 +      if (use_delta_islands)
 +              propagate_island_marks(commit);
  }
  
  static void show_object(struct object *obj, const char *name, void *data)
        add_preferred_base_object(name);
        add_object_entry(&obj->oid, obj->type, name, 0);
        obj->flags |= OBJECT_ADDED;
 +
 +      if (use_delta_islands) {
 +              const char *p;
 +              unsigned depth = 0;
 +              struct object_entry *ent;
 +
 +              for (p = strchr(name, '/'); p; p = strchr(p + 1, '/'))
 +                      depth++;
 +
 +              ent = packlist_find(&to_pack, obj->oid.hash, NULL);
 +              if (ent && depth > oe_tree_depth(&to_pack, ent))
 +                      oe_set_tree_depth(&to_pack, ent, depth);
 +      }
  }
  
  static void show_object__ma_allow_any(struct object *obj, const char *name, void *data)
@@@ -2890,7 -2806,7 +2890,7 @@@ static void add_objects_in_unpacked_pac
  
        memset(&in_pack, 0, sizeof(in_pack));
  
 -      for (p = get_packed_git(the_repository); p; p = p->next) {
 +      for (p = get_all_packs(the_repository); p; p = p->next) {
                struct object_id oid;
                struct object *o;
  
@@@ -2954,7 -2870,7 +2954,7 @@@ static int has_sha1_pack_kept_or_nonloc
        struct packed_git *p;
  
        p = (last_found != (void *)1) ? last_found :
 -                                      get_packed_git(the_repository);
 +                                      get_all_packs(the_repository);
  
        while (p) {
                if ((!p->pack_local || p->pack_keep ||
                        return 1;
                }
                if (p == last_found)
 -                      p = get_packed_git(the_repository);
 +                      p = get_all_packs(the_repository);
                else
                        p = p->next;
                if (p == last_found)
@@@ -3000,7 -2916,7 +3000,7 @@@ static void loosen_unused_packed_object
        uint32_t i;
        struct object_id oid;
  
 -      for (p = get_packed_git(the_repository); p; p = p->next) {
 +      for (p = get_all_packs(the_repository); p; p = p->next) {
                if (!p->pack_local || p->pack_keep || p->pack_keep_in_core)
                        continue;
  
@@@ -3035,6 -2951,7 +3035,6 @@@ static int pack_options_allow_reuse(voi
  
  static int get_object_list_from_bitmap(struct rev_info *revs)
  {
 -      struct bitmap_index *bitmap_git;
        if (!(bitmap_git = prepare_bitmap_walk(revs)))
                return -1;
  
        }
  
        traverse_bitmap_commit_list(bitmap_git, &add_object_entry_from_bitmap);
 -      free_bitmap_index(bitmap_git);
        return 0;
  }
  
@@@ -3107,9 -3025,6 +3107,9 @@@ static void get_object_list(int ac, con
        if (use_bitmap_index && !get_object_list_from_bitmap(&revs))
                return;
  
 +      if (use_delta_islands)
 +              load_delta_islands();
 +
        if (prepare_revision_walk(&revs))
                die(_("revision walk setup failed"));
        mark_edges_uninteresting(&revs, show_edge);
@@@ -3148,7 -3063,7 +3148,7 @@@ static void add_extra_kept_packs(const 
        if (!names->nr)
                return;
  
 -      for (p = get_packed_git(the_repository); p; p = p->next) {
 +      for (p = get_all_packs(the_repository); p; p = p->next) {
                const char *name = basename(p->pack_name);
                int i;
  
@@@ -3200,6 -3115,7 +3200,6 @@@ static int option_parse_unpack_unreacha
  int cmd_pack_objects(int argc, const char **argv, const char *prefix)
  {
        int use_internal_rev_list = 0;
 -      int thin = 0;
        int shallow = 0;
        int all_progress_implied = 0;
        struct argv_array rp = ARGV_ARRAY_INIT;
                  option_parse_missing_action },
                OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
                         N_("do not pack objects in promisor packfiles")),
 +              OPT_BOOL(0, "delta-islands", &use_delta_islands,
 +                       N_("respect islands during delta compression")),
                OPT_END(),
        };
  
        if (pack_to_stdout || !rev_list_all)
                write_bitmap_index = 0;
  
 +      if (use_delta_islands)
 +              argv_array_push(&rp, "--topo-order");
 +
        if (progress && all_progress_implied)
                progress = 2;
  
        add_extra_kept_packs(&keep_pack_list);
        if (ignore_packed_keep_on_disk) {
                struct packed_git *p;
 -              for (p = get_packed_git(the_repository); p; p = p->next)
 +              for (p = get_all_packs(the_repository); p; p = p->next)
                        if (p->pack_local && p->pack_keep)
                                break;
                if (!p) /* no keep-able packs found */
                 * it also covers non-local objects
                 */
                struct packed_git *p;
 -              for (p = get_packed_git(the_repository); p; p = p->next) {
 +              for (p = get_all_packs(the_repository); p; p = p->next) {
                        if (!p->pack_local) {
                                have_non_local_packs = 1;
                                break;
diff --combined builtin/pull.c
index 2514bfb9cd6b4288bcda5e1676e3d4e20f10f281,09b02695de682bf41bcbe3ef51c1179b69e105de..b2055d1dd6f180ec2383ee6f569045e5a55cb4b4
@@@ -22,7 -22,6 +22,7 @@@
  #include "tempfile.h"
  #include "lockfile.h"
  #include "wt-status.h"
 +#include "commit-reach.h"
  
  enum rebase_type {
        REBASE_INVALID = -1,
@@@ -800,7 -799,7 +800,7 @@@ static int run_rebase(const struct obje
        struct argv_array args = ARGV_ARRAY_INIT;
  
        if (!get_octopus_merge_base(&oct_merge_base, curr_head, merge_head, fork_point))
-               if (!is_null_oid(fork_point) && !oidcmp(&oct_merge_base, fork_point))
+               if (!is_null_oid(fork_point) && oideq(&oct_merge_base, fork_point))
                        fork_point = NULL;
  
        argv_array_push(&args, "rebase");
@@@ -903,7 -902,7 +903,7 @@@ int cmd_pull(int argc, const char **arg
                oidclr(&curr_head);
  
        if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) &&
-                       oidcmp(&orig_head, &curr_head)) {
+                       !oideq(&orig_head, &curr_head)) {
                /*
                 * The fetch involved updating the current branch.
                 *
diff --combined builtin/receive-pack.c
index 35a3fcfbd96bbc18a777be5a70e21edb35decffb,5bb163d4d2a1de3aebe4951fdc7a731b6c999acb..a3bb13af1038d2fdbade292c05589507099b1731
@@@ -27,7 -27,6 +27,7 @@@
  #include "packfile.h"
  #include "object-store.h"
  #include "protocol.h"
 +#include "commit-reach.h"
  
  static const char * const receive_pack_usage[] = {
        N_("git receive-pack <git-dir>"),
@@@ -1223,8 -1222,8 +1223,8 @@@ static void check_aliased_update(struc
  
        dst_cmd = (struct command *) item->util;
  
-       if (!oidcmp(&cmd->old_oid, &dst_cmd->old_oid) &&
-           !oidcmp(&cmd->new_oid, &dst_cmd->new_oid))
+       if (oideq(&cmd->old_oid, &dst_cmd->old_oid) &&
+           oideq(&cmd->new_oid, &dst_cmd->new_oid))
                return;
  
        dst_cmd->skip_update = 1;
diff --combined builtin/remote.c
index 61479bc428c80ef0b976cd46aa8cb60c1d1550f8,c171323e0eb8a782a6eb170d557df8895f8d6e8d..40c6f8a1bd511f4f498ef534fe8299bda9fa2779
@@@ -10,7 -10,6 +10,7 @@@
  #include "refspec.h"
  #include "object-store.h"
  #include "argv-array.h"
 +#include "commit-reach.h"
  
  static const char * const builtin_remote_usage[] = {
        N_("git remote [-v | --verbose]"),
@@@ -413,7 -412,7 +413,7 @@@ static int get_push_ref_states(const st
  
                if (is_null_oid(&ref->new_oid)) {
                        info->status = PUSH_STATUS_DELETE;
-               } else if (!oidcmp(&ref->old_oid, &ref->new_oid))
+               } else if (oideq(&ref->old_oid, &ref->new_oid))
                        info->status = PUSH_STATUS_UPTODATE;
                else if (is_null_oid(&ref->old_oid))
                        info->status = PUSH_STATUS_CREATE;
diff --combined cache-tree.c
index 490a25adf06e4e1fcd70530943f604bc7c9f1b58,b49bb5c5be08636cda324087cb11ebafea39561d..5ce51468f0b402fd2121e2c8b51ff12703d431ba
@@@ -4,7 -4,6 +4,7 @@@
  #include "tree-walk.h"
  #include "cache-tree.h"
  #include "object-store.h"
 +#include "replace-object.h"
  
  #ifndef DEBUG
  #define DEBUG 0
@@@ -434,9 -433,7 +434,9 @@@ int cache_tree_update(struct index_stat
  
        if (i)
                return i;
 +      trace_performance_enter();
        i = update_one(it, cache, entries, "", 0, &skip, flags);
 +      trace_performance_leave("cache_tree_update");
        if (i < 0)
                return i;
        istate->cache_changed |= CACHE_TREE_CHANGED;
@@@ -717,84 -714,7 +717,84 @@@ int cache_tree_matches_traversal(struc
  
        it = find_cache_tree_from_traversal(root, info);
        it = cache_tree_find(it, ent->path);
-       if (it && it->entry_count > 0 && !oidcmp(ent->oid, &it->oid))
+       if (it && it->entry_count > 0 && oideq(ent->oid, &it->oid))
                return it->entry_count;
        return 0;
  }
 +
 +static void verify_one(struct index_state *istate,
 +                     struct cache_tree *it,
 +                     struct strbuf *path)
 +{
 +      int i, pos, len = path->len;
 +      struct strbuf tree_buf = STRBUF_INIT;
 +      struct object_id new_oid;
 +
 +      for (i = 0; i < it->subtree_nr; i++) {
 +              strbuf_addf(path, "%s/", it->down[i]->name);
 +              verify_one(istate, it->down[i]->cache_tree, path);
 +              strbuf_setlen(path, len);
 +      }
 +
 +      if (it->entry_count < 0 ||
 +          /* no verification on tests (t7003) that replace trees */
 +          lookup_replace_object(the_repository, &it->oid) != &it->oid)
 +              return;
 +
 +      if (path->len) {
 +              pos = index_name_pos(istate, path->buf, path->len);
 +              pos = -pos - 1;
 +      } else {
 +              pos = 0;
 +      }
 +
 +      i = 0;
 +      while (i < it->entry_count) {
 +              struct cache_entry *ce = istate->cache[pos + i];
 +              const char *slash;
 +              struct cache_tree_sub *sub = NULL;
 +              const struct object_id *oid;
 +              const char *name;
 +              unsigned mode;
 +              int entlen;
 +
 +              if (ce->ce_flags & (CE_STAGEMASK | CE_INTENT_TO_ADD | CE_REMOVE))
 +                      BUG("%s with flags 0x%x should not be in cache-tree",
 +                          ce->name, ce->ce_flags);
 +              name = ce->name + path->len;
 +              slash = strchr(name, '/');
 +              if (slash) {
 +                      entlen = slash - name;
 +                      sub = find_subtree(it, ce->name + path->len, entlen, 0);
 +                      if (!sub || sub->cache_tree->entry_count < 0)
 +                              BUG("bad subtree '%.*s'", entlen, name);
 +                      oid = &sub->cache_tree->oid;
 +                      mode = S_IFDIR;
 +                      i += sub->cache_tree->entry_count;
 +              } else {
 +                      oid = &ce->oid;
 +                      mode = ce->ce_mode;
 +                      entlen = ce_namelen(ce) - path->len;
 +                      i++;
 +              }
 +              strbuf_addf(&tree_buf, "%o %.*s%c", mode, entlen, name, '\0');
 +              strbuf_add(&tree_buf, oid->hash, the_hash_algo->rawsz);
 +      }
 +      hash_object_file(tree_buf.buf, tree_buf.len, tree_type, &new_oid);
 +      if (oidcmp(&new_oid, &it->oid))
 +              BUG("cache-tree for path %.*s does not match. "
 +                  "Expected %s got %s", len, path->buf,
 +                  oid_to_hex(&new_oid), oid_to_hex(&it->oid));
 +      strbuf_setlen(path, len);
 +      strbuf_release(&tree_buf);
 +}
 +
 +void cache_tree_verify(struct index_state *istate)
 +{
 +      struct strbuf path = STRBUF_INIT;
 +
 +      if (!istate->cache_tree)
 +              return;
 +      verify_one(istate, istate->cache_tree, &path);
 +      strbuf_release(&path);
 +}
diff --combined cache.h
index b7166e45ed8c20c627dc741e4b66fa4201c8ec53,d97db26bb671418e391c74f34f1e319170f87903..d508f3d4f8837caef469389c71950ee96eea709b
+++ b/cache.h
@@@ -1041,14 -1041,24 +1041,24 @@@ static inline int oidcmp(const struct o
        return hashcmp(oid1->hash, oid2->hash);
  }
  
+ static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2)
+ {
+       return !hashcmp(sha1, sha2);
+ }
+ static inline int oideq(const struct object_id *oid1, const struct object_id *oid2)
+ {
+       return hasheq(oid1->hash, oid2->hash);
+ }
  static inline int is_null_sha1(const unsigned char *sha1)
  {
-       return !hashcmp(sha1, null_sha1);
+       return hasheq(sha1, null_sha1);
  }
  
  static inline int is_null_oid(const struct object_id *oid)
  {
-       return !hashcmp(oid->hash, null_sha1);
+       return hasheq(oid->hash, null_sha1);
  }
  
  static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
@@@ -1085,22 -1095,22 +1095,22 @@@ static inline void oidread(struct objec
  
  static inline int is_empty_blob_sha1(const unsigned char *sha1)
  {
-       return !hashcmp(sha1, the_hash_algo->empty_blob->hash);
+       return hasheq(sha1, the_hash_algo->empty_blob->hash);
  }
  
  static inline int is_empty_blob_oid(const struct object_id *oid)
  {
-       return !oidcmp(oid, the_hash_algo->empty_blob);
+       return oideq(oid, the_hash_algo->empty_blob);
  }
  
  static inline int is_empty_tree_sha1(const unsigned char *sha1)
  {
-       return !hashcmp(sha1, the_hash_algo->empty_tree->hash);
+       return hasheq(sha1, the_hash_algo->empty_tree->hash);
  }
  
  static inline int is_empty_tree_oid(const struct object_id *oid)
  {
-       return !oidcmp(oid, the_hash_algo->empty_tree);
+       return oideq(oid, the_hash_algo->empty_tree);
  }
  
  const char *empty_tree_oid_hex(void);
@@@ -1518,7 -1528,6 +1528,7 @@@ struct checkout 
        unsigned force:1,
                 quiet:1,
                 not_new:1,
 +               clone:1,
                 refresh_cache:1;
  };
  #define CHECKOUT_INIT { NULL, "" }
diff --combined commit-graph.c
index 0cad55eec2d5603ccd375e093206f0c971c3524a,64ce79420d384662742170ea36adb46595def753..ae6cabb4cda46a74d5f4f59bbf54a550361fd10f
@@@ -233,24 -233,6 +233,24 @@@ static int prepare_commit_graph(struct 
        return !!r->objects->commit_graph;
  }
  
 +int generation_numbers_enabled(struct repository *r)
 +{
 +      uint32_t first_generation;
 +      struct commit_graph *g;
 +      if (!prepare_commit_graph(r))
 +             return 0;
 +
 +      g = r->objects->commit_graph;
 +
 +      if (!g->num_commits)
 +              return 0;
 +
 +      first_generation = get_be32(g->chunk_commit_data +
 +                                  g->hash_len + 8) >> 2;
 +
 +      return !!first_generation;
 +}
 +
  static void close_commit_graph(void)
  {
        free_commit_graph(the_repository->objects->commit_graph);
@@@ -783,7 -765,7 +783,7 @@@ void write_commit_graph(const char *obj
  
        count_distinct = 1;
        for (i = 1; i < oids.nr; i++) {
-               if (oidcmp(&oids.list[i-1], &oids.list[i]))
+               if (!oideq(&oids.list[i - 1], &oids.list[i]))
                        count_distinct++;
        }
  
        num_extra_edges = 0;
        for (i = 0; i < oids.nr; i++) {
                int num_parents = 0;
-               if (i > 0 && !oidcmp(&oids.list[i-1], &oids.list[i]))
+               if (i > 0 && oideq(&oids.list[i - 1], &oids.list[i]))
                        continue;
  
                commits.list[commits.nr] = lookup_commit(the_repository, &oids.list[i]);
@@@ -918,7 -900,7 +918,7 @@@ int verify_commit_graph(struct reposito
        f = hashfd(devnull, NULL);
        hashwrite(f, g->data, g->data_len - g->hash_len);
        finalize_hashfile(f, checksum.hash, CSUM_CLOSE);
-       if (hashcmp(checksum.hash, g->data + g->data_len - g->hash_len)) {
+       if (!hasheq(checksum.hash, g->data + g->data_len - g->hash_len)) {
                graph_report(_("the commit-graph file has incorrect checksum and is likely corrupt"));
                verify_commit_graph_error = VERIFY_COMMIT_GRAPH_ERROR_HASH;
        }
                        continue;
                }
  
-               if (oidcmp(&get_commit_tree_in_graph_one(g, graph_commit)->object.oid,
+               if (!oideq(&get_commit_tree_in_graph_one(g, graph_commit)->object.oid,
                           get_commit_tree_oid(odb_commit)))
                        graph_report("root tree OID for commit %s in commit-graph is %s != %s",
                                     oid_to_hex(&cur_oid),
                                break;
                        }
  
-                       if (oidcmp(&graph_parents->item->object.oid, &odb_parents->item->object.oid))
+                       if (!oideq(&graph_parents->item->object.oid, &odb_parents->item->object.oid))
                                graph_report("commit-graph parent for %s is %s != %s",
                                             oid_to_hex(&cur_oid),
                                             oid_to_hex(&graph_parents->item->object.oid),
diff --combined commit.c
index d6f7f5e4d2d7facc20fc8f8d2fadfa25c47f68be,1b94a8c96fa6cd87531846be9a50fa30d890aa50..d0f199e12286983c3f9f23b6567dc78a2ceeaf79
+++ b/commit.c
@@@ -46,7 -46,7 +46,7 @@@ struct commit *lookup_commit_or_die(con
        struct commit *c = lookup_commit_reference(the_repository, oid);
        if (!c)
                die(_("could not parse %s"), ref_name);
-       if (oidcmp(oid, &c->object.oid)) {
+       if (!oideq(oid, &c->object.oid)) {
                warning(_("%s %s is not a commit!"),
                        ref_name, oid_to_hex(oid));
        }
@@@ -843,6 -843,364 +843,6 @@@ void sort_in_topological_order(struct c
                clear_author_date_slab(&author_date);
  }
  
 -/* merge-base stuff */
 -
 -/* Remember to update object flag allocation in object.h */
 -#define PARENT1               (1u<<16)
 -#define PARENT2               (1u<<17)
 -#define STALE         (1u<<18)
 -#define RESULT                (1u<<19)
 -
 -static const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT);
 -
 -static int queue_has_nonstale(struct prio_queue *queue)
 -{
 -      int i;
 -      for (i = 0; i < queue->nr; i++) {
 -              struct commit *commit = queue->array[i].data;
 -              if (!(commit->object.flags & STALE))
 -                      return 1;
 -      }
 -      return 0;
 -}
 -
 -/* all input commits in one and twos[] must have been parsed! */
 -static struct commit_list *paint_down_to_common(struct commit *one, int n,
 -                                              struct commit **twos,
 -                                              int min_generation)
 -{
 -      struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
 -      struct commit_list *result = NULL;
 -      int i;
 -      uint32_t last_gen = GENERATION_NUMBER_INFINITY;
 -
 -      one->object.flags |= PARENT1;
 -      if (!n) {
 -              commit_list_append(one, &result);
 -              return result;
 -      }
 -      prio_queue_put(&queue, one);
 -
 -      for (i = 0; i < n; i++) {
 -              twos[i]->object.flags |= PARENT2;
 -              prio_queue_put(&queue, twos[i]);
 -      }
 -
 -      while (queue_has_nonstale(&queue)) {
 -              struct commit *commit = prio_queue_get(&queue);
 -              struct commit_list *parents;
 -              int flags;
 -
 -              if (commit->generation > last_gen)
 -                      BUG("bad generation skip %8x > %8x at %s",
 -                          commit->generation, last_gen,
 -                          oid_to_hex(&commit->object.oid));
 -              last_gen = commit->generation;
 -
 -              if (commit->generation < min_generation)
 -                      break;
 -
 -              flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
 -              if (flags == (PARENT1 | PARENT2)) {
 -                      if (!(commit->object.flags & RESULT)) {
 -                              commit->object.flags |= RESULT;
 -                              commit_list_insert_by_date(commit, &result);
 -                      }
 -                      /* Mark parents of a found merge stale */
 -                      flags |= STALE;
 -              }
 -              parents = commit->parents;
 -              while (parents) {
 -                      struct commit *p = parents->item;
 -                      parents = parents->next;
 -                      if ((p->object.flags & flags) == flags)
 -                              continue;
 -                      if (parse_commit(p))
 -                              return NULL;
 -                      p->object.flags |= flags;
 -                      prio_queue_put(&queue, p);
 -              }
 -      }
 -
 -      clear_prio_queue(&queue);
 -      return result;
 -}
 -
 -static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos)
 -{
 -      struct commit_list *list = NULL;
 -      struct commit_list *result = NULL;
 -      int i;
 -
 -      for (i = 0; i < n; i++) {
 -              if (one == twos[i])
 -                      /*
 -                       * We do not mark this even with RESULT so we do not
 -                       * have to clean it up.
 -                       */
 -                      return commit_list_insert(one, &result);
 -      }
 -
 -      if (parse_commit(one))
 -              return NULL;
 -      for (i = 0; i < n; i++) {
 -              if (parse_commit(twos[i]))
 -                      return NULL;
 -      }
 -
 -      list = paint_down_to_common(one, n, twos, 0);
 -
 -      while (list) {
 -              struct commit *commit = pop_commit(&list);
 -              if (!(commit->object.flags & STALE))
 -                      commit_list_insert_by_date(commit, &result);
 -      }
 -      return result;
 -}
 -
 -struct commit_list *get_octopus_merge_bases(struct commit_list *in)
 -{
 -      struct commit_list *i, *j, *k, *ret = NULL;
 -
 -      if (!in)
 -              return ret;
 -
 -      commit_list_insert(in->item, &ret);
 -
 -      for (i = in->next; i; i = i->next) {
 -              struct commit_list *new_commits = NULL, *end = NULL;
 -
 -              for (j = ret; j; j = j->next) {
 -                      struct commit_list *bases;
 -                      bases = get_merge_bases(i->item, j->item);
 -                      if (!new_commits)
 -                              new_commits = bases;
 -                      else
 -                              end->next = bases;
 -                      for (k = bases; k; k = k->next)
 -                              end = k;
 -              }
 -              ret = new_commits;
 -      }
 -      return ret;
 -}
 -
 -static int remove_redundant(struct commit **array, int cnt)
 -{
 -      /*
 -       * Some commit in the array may be an ancestor of
 -       * another commit.  Move such commit to the end of
 -       * the array, and return the number of commits that
 -       * are independent from each other.
 -       */
 -      struct commit **work;
 -      unsigned char *redundant;
 -      int *filled_index;
 -      int i, j, filled;
 -
 -      work = xcalloc(cnt, sizeof(*work));
 -      redundant = xcalloc(cnt, 1);
 -      ALLOC_ARRAY(filled_index, cnt - 1);
 -
 -      for (i = 0; i < cnt; i++)
 -              parse_commit(array[i]);
 -      for (i = 0; i < cnt; i++) {
 -              struct commit_list *common;
 -              uint32_t min_generation = array[i]->generation;
 -
 -              if (redundant[i])
 -                      continue;
 -              for (j = filled = 0; j < cnt; j++) {
 -                      if (i == j || redundant[j])
 -                              continue;
 -                      filled_index[filled] = j;
 -                      work[filled++] = array[j];
 -
 -                      if (array[j]->generation < min_generation)
 -                              min_generation = array[j]->generation;
 -              }
 -              common = paint_down_to_common(array[i], filled, work,
 -                                            min_generation);
 -              if (array[i]->object.flags & PARENT2)
 -                      redundant[i] = 1;
 -              for (j = 0; j < filled; j++)
 -                      if (work[j]->object.flags & PARENT1)
 -                              redundant[filled_index[j]] = 1;
 -              clear_commit_marks(array[i], all_flags);
 -              clear_commit_marks_many(filled, work, all_flags);
 -              free_commit_list(common);
 -      }
 -
 -      /* Now collect the result */
 -      COPY_ARRAY(work, array, cnt);
 -      for (i = filled = 0; i < cnt; i++)
 -              if (!redundant[i])
 -                      array[filled++] = work[i];
 -      for (j = filled, i = 0; i < cnt; i++)
 -              if (redundant[i])
 -                      array[j++] = work[i];
 -      free(work);
 -      free(redundant);
 -      free(filled_index);
 -      return filled;
 -}
 -
 -static struct commit_list *get_merge_bases_many_0(struct commit *one,
 -                                                int n,
 -                                                struct commit **twos,
 -                                                int cleanup)
 -{
 -      struct commit_list *list;
 -      struct commit **rslt;
 -      struct commit_list *result;
 -      int cnt, i;
 -
 -      result = merge_bases_many(one, n, twos);
 -      for (i = 0; i < n; i++) {
 -              if (one == twos[i])
 -                      return result;
 -      }
 -      if (!result || !result->next) {
 -              if (cleanup) {
 -                      clear_commit_marks(one, all_flags);
 -                      clear_commit_marks_many(n, twos, all_flags);
 -              }
 -              return result;
 -      }
 -
 -      /* There are more than one */
 -      cnt = commit_list_count(result);
 -      rslt = xcalloc(cnt, sizeof(*rslt));
 -      for (list = result, i = 0; list; list = list->next)
 -              rslt[i++] = list->item;
 -      free_commit_list(result);
 -
 -      clear_commit_marks(one, all_flags);
 -      clear_commit_marks_many(n, twos, all_flags);
 -
 -      cnt = remove_redundant(rslt, cnt);
 -      result = NULL;
 -      for (i = 0; i < cnt; i++)
 -              commit_list_insert_by_date(rslt[i], &result);
 -      free(rslt);
 -      return result;
 -}
 -
 -struct commit_list *get_merge_bases_many(struct commit *one,
 -                                       int n,
 -                                       struct commit **twos)
 -{
 -      return get_merge_bases_many_0(one, n, twos, 1);
 -}
 -
 -struct commit_list *get_merge_bases_many_dirty(struct commit *one,
 -                                             int n,
 -                                             struct commit **twos)
 -{
 -      return get_merge_bases_many_0(one, n, twos, 0);
 -}
 -
 -struct commit_list *get_merge_bases(struct commit *one, struct commit *two)
 -{
 -      return get_merge_bases_many_0(one, 1, &two, 1);
 -}
 -
 -/*
 - * Is "commit" a descendant of one of the elements on the "with_commit" list?
 - */
 -int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
 -{
 -      if (!with_commit)
 -              return 1;
 -      while (with_commit) {
 -              struct commit *other;
 -
 -              other = with_commit->item;
 -              with_commit = with_commit->next;
 -              if (in_merge_bases(other, commit))
 -                      return 1;
 -      }
 -      return 0;
 -}
 -
 -/*
 - * Is "commit" an ancestor of one of the "references"?
 - */
 -int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit **reference)
 -{
 -      struct commit_list *bases;
 -      int ret = 0, i;
 -      uint32_t min_generation = GENERATION_NUMBER_INFINITY;
 -
 -      if (parse_commit(commit))
 -              return ret;
 -      for (i = 0; i < nr_reference; i++) {
 -              if (parse_commit(reference[i]))
 -                      return ret;
 -              if (reference[i]->generation < min_generation)
 -                      min_generation = reference[i]->generation;
 -      }
 -
 -      if (commit->generation > min_generation)
 -              return ret;
 -
 -      bases = paint_down_to_common(commit, nr_reference, reference, commit->generation);
 -      if (commit->object.flags & PARENT2)
 -              ret = 1;
 -      clear_commit_marks(commit, all_flags);
 -      clear_commit_marks_many(nr_reference, reference, all_flags);
 -      free_commit_list(bases);
 -      return ret;
 -}
 -
 -/*
 - * Is "commit" an ancestor of (i.e. reachable from) the "reference"?
 - */
 -int in_merge_bases(struct commit *commit, struct commit *reference)
 -{
 -      return in_merge_bases_many(commit, 1, &reference);
 -}
 -
 -struct commit_list *reduce_heads(struct commit_list *heads)
 -{
 -      struct commit_list *p;
 -      struct commit_list *result = NULL, **tail = &result;
 -      struct commit **array;
 -      int num_head, i;
 -
 -      if (!heads)
 -              return NULL;
 -
 -      /* Uniquify */
 -      for (p = heads; p; p = p->next)
 -              p->item->object.flags &= ~STALE;
 -      for (p = heads, num_head = 0; p; p = p->next) {
 -              if (p->item->object.flags & STALE)
 -                      continue;
 -              p->item->object.flags |= STALE;
 -              num_head++;
 -      }
 -      array = xcalloc(num_head, sizeof(*array));
 -      for (p = heads, i = 0; p; p = p->next) {
 -              if (p->item->object.flags & STALE) {
 -                      array[i++] = p->item;
 -                      p->item->object.flags &= ~STALE;
 -              }
 -      }
 -      num_head = remove_redundant(array, num_head);
 -      for (i = 0; i < num_head; i++)
 -              tail = &commit_list_insert(array[i], tail)->next;
 -      free(array);
 -      return result;
 -}
 -
 -void reduce_heads_replace(struct commit_list **heads)
 -{
 -      struct commit_list *result = reduce_heads(*heads);
 -      free_commit_list(*heads);
 -      *heads = result;
 -}
 -
  static const char gpg_sig_header[] = "gpgsig";
  static const int gpg_sig_header_len = sizeof(gpg_sig_header) - 1;
  
@@@ -1426,10 -1784,10 +1426,10 @@@ const char *find_commit_header(const ch
   * Returns the number of bytes from the tail to ignore, to be fed as
   * the second parameter to append_signoff().
   */
 -int ignore_non_trailer(const char *buf, size_t len)
 +size_t ignore_non_trailer(const char *buf, size_t len)
  {
 -      int boc = 0;
 -      int bol = 0;
 +      size_t boc = 0;
 +      size_t bol = 0;
        int in_old_conflicts_block = 0;
        size_t cutoff = wt_status_locate_end(buf, len);
  
diff --combined diff-lib.c
index 70cddbf43664a42b5647ed21af279c1492abb790,8866b1d60c0e390160f5cbc5bee1189736775e52..30bf9a2399fa392b31338489278e0363a55eb726
@@@ -342,7 -342,7 +342,7 @@@ static int show_modified(struct rev_inf
        }
  
        if (revs->combine_merges && !cached &&
-           (oidcmp(oid, &old_entry->oid) || oidcmp(&old_entry->oid, &new_entry->oid))) {
+           (!oideq(oid, &old_entry->oid) || !oideq(&old_entry->oid, &new_entry->oid))) {
                struct combine_diff_path *p;
                int pathlen = ce_namelen(new_entry);
  
        }
  
        oldmode = old_entry->ce_mode;
-       if (mode == oldmode && !oidcmp(oid, &old_entry->oid) && !dirty_submodule &&
+       if (mode == oldmode && oideq(oid, &old_entry->oid) && !dirty_submodule &&
            !revs->diffopt.flags.find_copies_harder)
                return 0;
  
@@@ -518,11 -518,11 +518,11 @@@ static int diff_cache(struct rev_info *
  int run_diff_index(struct rev_info *revs, int cached)
  {
        struct object_array_entry *ent;
 -      uint64_t start = getnanotime();
  
        if (revs->pending.nr != 1)
                BUG("run_diff_index must be passed exactly one tree");
  
 +      trace_performance_enter();
        ent = revs->pending.objects;
        if (diff_cache(revs, &ent->item->oid, ent->name, cached))
                exit(128);
        diffcore_fix_diff_index(&revs->diffopt);
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
 -      trace_performance_since(start, "diff-index");
 +      trace_performance_leave("diff-index");
        return 0;
  }
  
diff --combined diff.c
index 0549fc6e2cf3e0ea2610921be5ee0bdf990f2670,605ba4b6b8893fadca09f58e398aa3729e036600..71ff247702048f70dbfaec59090132461c70642d
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -624,54 -624,42 +624,54 @@@ static void check_blank_at_eof(mmfile_
  }
  
  static void emit_line_0(struct diff_options *o,
 -                      const char *set, unsigned reverse, const char *reset,
 +                      const char *set_sign, const char *set, unsigned reverse, const char *reset,
                        int first, const char *line, int len)
  {
        int has_trailing_newline, has_trailing_carriage_return;
 -      int nofirst;
 +      int needs_reset = 0; /* at the end of the line */
        FILE *file = o->file;
  
 -      if (first)
 -              fputs(diff_line_prefix(o), file);
 -      else if (!len)
 -              return;
 +      fputs(diff_line_prefix(o), file);
  
 -      if (len == 0) {
 -              has_trailing_newline = (first == '\n');
 -              has_trailing_carriage_return = (!has_trailing_newline &&
 -                                              (first == '\r'));
 -              nofirst = has_trailing_newline || has_trailing_carriage_return;
 -      } else {
 -              has_trailing_newline = (len > 0 && line[len-1] == '\n');
 -              if (has_trailing_newline)
 -                      len--;
 -              has_trailing_carriage_return = (len > 0 && line[len-1] == '\r');
 -              if (has_trailing_carriage_return)
 -                      len--;
 -              nofirst = 0;
 +      has_trailing_newline = (len > 0 && line[len-1] == '\n');
 +      if (has_trailing_newline)
 +              len--;
 +
 +      has_trailing_carriage_return = (len > 0 && line[len-1] == '\r');
 +      if (has_trailing_carriage_return)
 +              len--;
 +
 +      if (!len && !first)
 +              goto end_of_line;
 +
 +      if (reverse && want_color(o->use_color)) {
 +              fputs(GIT_COLOR_REVERSE, file);
 +              needs_reset = 1;
        }
  
 -      if (len || !nofirst) {
 -              if (reverse && want_color(o->use_color))
 -                      fputs(GIT_COLOR_REVERSE, file);
 +      if (set_sign) {
 +              fputs(set_sign, file);
 +              needs_reset = 1;
 +      }
 +
 +      if (first)
 +              fputc(first, file);
 +
 +      if (!len)
 +              goto end_of_line;
 +
 +      if (set) {
 +              if (set_sign && set != set_sign)
 +                      fputs(reset, file);
                fputs(set, file);
 -              if (first && !nofirst)
 -                      fputc(first, file);
 -              fwrite(line, len, 1, file);
 -              fputs(reset, file);
 +              needs_reset = 1;
        }
 +      fwrite(line, len, 1, file);
 +      needs_reset = 1; /* 'line' may contain color codes. */
 +
 +end_of_line:
 +      if (needs_reset)
 +              fputs(reset, file);
        if (has_trailing_carriage_return)
                fputc('\r', file);
        if (has_trailing_newline)
  static void emit_line(struct diff_options *o, const char *set, const char *reset,
                      const char *line, int len)
  {
 -      emit_line_0(o, set, 0, reset, line[0], line+1, len-1);
 +      emit_line_0(o, set, NULL, 0, reset, 0, line, len);
  }
  
  enum diff_symbol {
@@@ -1199,9 -1187,9 +1199,9 @@@ static void dim_moved_lines(struct diff
  }
  
  static void emit_line_ws_markup(struct diff_options *o,
 -                              const char *set, const char *reset,
 -                              const char *line, int len,
 -                              const char *set_sign, char sign,
 +                              const char *set_sign, const char *set,
 +                              const char *reset,
 +                              char sign, const char *line, int len,
                                unsigned ws_rule, int blank_at_eof)
  {
        const char *ws = NULL;
        }
  
        if (!ws && !set_sign)
 -              emit_line_0(o, set, 0, reset, sign, line, len);
 +              emit_line_0(o, set, NULL, 0, reset, sign, line, len);
        else if (!ws) {
 -              /* Emit just the prefix, then the rest. */
 -              emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset,
 -                          sign, "", 0);
 -              emit_line_0(o, set, 0, reset, 0, line, len);
 +              emit_line_0(o, set_sign, set, !!set_sign, reset, sign, line, len);
        } else if (blank_at_eof)
                /* Blank line at EOF - paint '+' as well */
 -              emit_line_0(o, ws, 0, reset, sign, line, len);
 +              emit_line_0(o, ws, NULL, 0, reset, sign, line, len);
        else {
                /* Emit just the prefix, then the rest. */
 -              emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset,
 +              emit_line_0(o, set_sign ? set_sign : set, NULL, !!set_sign, reset,
                            sign, "", 0);
                ws_check_emit(line, len, ws_rule,
                              o->file, set, reset, ws);
@@@ -1245,7 -1236,7 +1245,7 @@@ static void emit_diff_symbol_from_struc
                context = diff_get_color_opt(o, DIFF_CONTEXT);
                reset = diff_get_color_opt(o, DIFF_RESET);
                putc('\n', o->file);
 -              emit_line_0(o, context, 0, reset, '\\',
 +              emit_line_0(o, context, NULL, 0, reset, '\\',
                            nneof, strlen(nneof));
                break;
        case DIFF_SYMBOL_SUBMODULE_HEADER:
                        else if (c == '-')
                                set = diff_get_color_opt(o, DIFF_FILE_OLD);
                }
 -              emit_line_ws_markup(o, set, reset, line, len, set_sign, ' ',
 +              emit_line_ws_markup(o, set_sign, set, reset,
 +                                  o->output_indicators[OUTPUT_INDICATOR_CONTEXT],
 +                                  line, len,
                                    flags & (DIFF_SYMBOL_CONTENT_WS_MASK), 0);
                break;
        case DIFF_SYMBOL_PLUS:
                                set = diff_get_color_opt(o, DIFF_CONTEXT_BOLD);
                        flags &= ~DIFF_SYMBOL_CONTENT_WS_MASK;
                }
 -              emit_line_ws_markup(o, set, reset, line, len, set_sign, '+',
 +              emit_line_ws_markup(o, set_sign, set, reset,
 +                                  o->output_indicators[OUTPUT_INDICATOR_NEW],
 +                                  line, len,
                                    flags & DIFF_SYMBOL_CONTENT_WS_MASK,
                                    flags & DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF);
                break;
                        else
                                set = diff_get_color_opt(o, DIFF_CONTEXT_DIM);
                }
 -              emit_line_ws_markup(o, set, reset, line, len, set_sign, '-',
 +              emit_line_ws_markup(o, set_sign, set, reset,
 +                                  o->output_indicators[OUTPUT_INDICATOR_OLD],
 +                                  line, len,
                                    flags & DIFF_SYMBOL_CONTENT_WS_MASK, 0);
                break;
        case DIFF_SYMBOL_WORDS_PORCELAIN:
@@@ -2948,16 -2933,11 +2948,11 @@@ static void show_dirstat(struct diff_op
                struct diff_filepair *p = q->queue[i];
                const char *name;
                unsigned long copied, added, damage;
-               int content_changed;
  
                name = p->two->path ? p->two->path : p->one->path;
  
-               if (p->one->oid_valid && p->two->oid_valid)
-                       content_changed = oidcmp(&p->one->oid, &p->two->oid);
-               else
-                       content_changed = 1;
-               if (!content_changed) {
+               if (p->one->oid_valid && p->two->oid_valid &&
+                   oideq(&p->one->oid, &p->two->oid)) {
                        /*
                         * The SHA1 has not changed, so pre-/post-content is
                         * identical. We can therefore skip looking at the
                 * made to the preimage.
                 * If the resulting damage is zero, we know that
                 * diffcore_count_changes() considers the two entries to
-                * be identical, but since content_changed is true, we
+                * be identical, but since the oid changed, we
                 * know that there must have been _some_ kind of change,
                 * so we force all entries to have damage > 0.
                 */
@@@ -3419,7 -3399,7 +3414,7 @@@ static void builtin_diff(const char *na
                if (!one->data && !two->data &&
                    S_ISREG(one->mode) && S_ISREG(two->mode) &&
                    !o->flags.binary) {
-                       if (!oidcmp(&one->oid, &two->oid)) {
+                       if (oideq(&one->oid, &two->oid)) {
                                if (must_show_header)
                                        emit_diff_symbol(o, DIFF_SYMBOL_HEADER,
                                                         header.buf, header.len,
@@@ -3584,7 -3564,7 +3579,7 @@@ static void builtin_diffstat(const cha
                return;
        }
  
-       same_contents = !oidcmp(&one->oid, &two->oid);
+       same_contents = oideq(&one->oid, &two->oid);
  
        if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) {
                data->is_binary = 1;
@@@ -3780,7 -3760,7 +3775,7 @@@ static int reuse_worktree_file(const ch
         * This is not the sha1 we are looking for, or
         * unreusable because it is not a regular file.
         */
-       if (oidcmp(oid, &ce->oid) || !S_ISREG(ce->ce_mode))
+       if (!oideq(oid, &ce->oid) || !S_ISREG(ce->ce_mode))
                return 0;
  
        /*
@@@ -4185,7 -4165,7 +4180,7 @@@ static void fill_metainfo(struct strbu
        default:
                *must_show_header = 0;
        }
-       if (one && two && oidcmp(&one->oid, &two->oid)) {
+       if (one && two && !oideq(&one->oid, &two->oid)) {
                const unsigned hexsz = the_hash_algo->hexsz;
                int abbrev = o->flags.full_index ? hexsz : DEFAULT_ABBREV;
  
@@@ -4390,9 -4370,6 +4385,9 @@@ void diff_setup(struct diff_options *op
  
        options->file = stdout;
  
 +      options->output_indicators[OUTPUT_INDICATOR_NEW] = '+';
 +      options->output_indicators[OUTPUT_INDICATOR_OLD] = '-';
 +      options->output_indicators[OUTPUT_INDICATOR_CONTEXT] = ' ';
        options->abbrev = DEFAULT_ABBREV;
        options->line_termination = '\n';
        options->break_opt = -1;
@@@ -4870,12 -4847,6 +4865,12 @@@ int diff_opt_parse(struct diff_options 
                 options->output_format |= DIFF_FORMAT_DIFFSTAT;
        } else if (!strcmp(arg, "--no-compact-summary"))
                 options->flags.stat_with_summary = 0;
 +      else if (skip_prefix(arg, "--output-indicator-new=", &arg))
 +              options->output_indicators[OUTPUT_INDICATOR_NEW] = arg[0];
 +      else if (skip_prefix(arg, "--output-indicator-old=", &arg))
 +              options->output_indicators[OUTPUT_INDICATOR_OLD] = arg[0];
 +      else if (skip_prefix(arg, "--output-indicator-context=", &arg))
 +              options->output_indicators[OUTPUT_INDICATOR_CONTEXT] = arg[0];
  
        /* renames options */
        else if (starts_with(arg, "-B") ||
@@@ -5347,7 -5318,7 +5342,7 @@@ int diff_unmodified_pair(struct diff_fi
         * dealing with a change.
         */
        if (one->oid_valid && two->oid_valid &&
-           !oidcmp(&one->oid, &two->oid) &&
+           oideq(&one->oid, &two->oid) &&
            !one->dirty_submodule && !two->dirty_submodule)
                return 1; /* no change */
        if (!one->oid_valid && !two->oid_valid)
@@@ -5481,7 -5452,7 +5476,7 @@@ static void diff_resolve_rename_copy(vo
                        else
                                p->status = DIFF_STATUS_RENAMED;
                }
-               else if (oidcmp(&p->one->oid, &p->two->oid) ||
+               else if (!oideq(&p->one->oid, &p->two->oid) ||
                         p->one->mode != p->two->mode ||
                         p->one->dirty_submodule ||
                         p->two->dirty_submodule ||
diff --combined dir.c
index 995b8e32616055cdb228d30e3e82e9d70d24512e,8ee9fe81b460c39d071e55e89421fd747afe115d..47c2fca8dc33970a1f4f041360ef954da6fa75a8
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -1282,7 -1282,7 +1282,7 @@@ static void prep_exclude(struct dir_str
                 * order, though, if you do that.
                 */
                if (untracked &&
-                   oidcmp(&oid_stat.oid, &untracked->exclude_oid)) {
+                   !oideq(&oid_stat.oid, &untracked->exclude_oid)) {
                        invalidate_gitignore(dir->untracked, untracked);
                        oidcpy(&untracked->exclude_oid, &oid_stat.oid);
                }
@@@ -2248,12 -2248,12 +2248,12 @@@ static struct untracked_cache_dir *vali
  
        /* Validate $GIT_DIR/info/exclude and core.excludesfile */
        root = dir->untracked->root;
-       if (oidcmp(&dir->ss_info_exclude.oid,
+       if (!oideq(&dir->ss_info_exclude.oid,
                   &dir->untracked->ss_info_exclude.oid)) {
                invalidate_gitignore(dir->untracked, root);
                dir->untracked->ss_info_exclude = dir->ss_info_exclude;
        }
-       if (oidcmp(&dir->ss_excludes_file.oid,
+       if (!oideq(&dir->ss_excludes_file.oid,
                   &dir->untracked->ss_excludes_file.oid)) {
                invalidate_gitignore(dir->untracked, root);
                dir->untracked->ss_excludes_file = dir->ss_excludes_file;
@@@ -2268,13 -2268,10 +2268,13 @@@ int read_directory(struct dir_struct *d
                   const char *path, int len, const struct pathspec *pathspec)
  {
        struct untracked_cache_dir *untracked;
 -      uint64_t start = getnanotime();
  
 -      if (has_symlink_leading_path(path, len))
 +      trace_performance_enter();
 +
 +      if (has_symlink_leading_path(path, len)) {
 +              trace_performance_leave("read directory %.*s", len, path);
                return dir->nr;
 +      }
  
        untracked = validate_untracked_cache(dir, len, pathspec);
        if (!untracked)
                dir->nr = i;
        }
  
 -      trace_performance_since(start, "read directory %.*s", len, path);
 +      trace_performance_leave("read directory %.*s", len, path);
        if (dir->untracked) {
                static int force_untracked_cache = -1;
                static struct trace_key trace_untracked_stats = TRACE_KEY_INIT(UNTRACKED_STATS);
diff --combined fast-import.c
index af6514fdea9959b26355b328221ceb67eaf1432f,67a53b79cb17388863ec2c0c17c0aea3d1d01358..95600c78e048f9d3d28672737d4bc2a941073abc
@@@ -171,7 -171,6 +171,7 @@@ Format of STDIN stream
  #include "packfile.h"
  #include "object-store.h"
  #include "mem-pool.h"
 +#include "commit-reach.h"
  
  #define PACK_ID_BITS 16
  #define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
@@@ -573,7 -572,7 +573,7 @@@ static struct object_entry *find_object
        unsigned int h = oid->hash[0] << 8 | oid->hash[1];
        struct object_entry *e;
        for (e = object_table[h]; e; e = e->next)
-               if (!oidcmp(oid, &e->idx.oid))
+               if (oideq(oid, &e->idx.oid))
                        return e;
        return NULL;
  }
@@@ -584,7 -583,7 +584,7 @@@ static struct object_entry *insert_obje
        struct object_entry *e = object_table[h];
  
        while (e) {
-               if (!oidcmp(oid, &e->idx.oid))
+               if (oideq(oid, &e->idx.oid))
                        return e;
                e = e->next;
        }
@@@ -1069,7 -1068,7 +1069,7 @@@ static int store_object
                duplicate_count_by_type[type]++;
                return 1;
        } else if (find_sha1_pack(oid.hash,
 -                                get_packed_git(the_repository))) {
 +                                get_all_packs(the_repository))) {
                e->type = type;
                e->pack_id = MAX_PACK_ID;
                e->idx.offset = 1; /* just not zero! */
@@@ -1267,7 -1266,7 +1267,7 @@@ static void stream_blob(uintmax_t len, 
                truncate_pack(&checkpoint);
  
        } else if (find_sha1_pack(oid.hash,
 -                                get_packed_git(the_repository))) {
 +                                get_all_packs(the_repository))) {
                e->type = OBJ_BLOB;
                e->pack_id = MAX_PACK_ID;
                e->idx.offset = 1; /* just not zero! */
@@@ -1534,7 -1533,7 +1534,7 @@@ static int tree_content_set
                        if (!*slash1) {
                                if (!S_ISDIR(mode)
                                                && e->versions[1].mode == mode
-                                               && !oidcmp(&e->versions[1].oid, oid))
+                                               && oideq(&e->versions[1].oid, oid))
                                        return 0;
                                e->versions[1].mode = mode;
                                oidcpy(&e->versions[1].oid, oid);
@@@ -2650,7 -2649,7 +2650,7 @@@ static int parse_from(struct branch *b
                struct object_entry *oe = find_mark(idnum);
                if (oe->type != OBJ_COMMIT)
                        die("Mark :%" PRIuMAX " not a commit", idnum);
-               if (oidcmp(&b->oid, &oe->idx.oid)) {
+               if (!oideq(&b->oid, &oe->idx.oid)) {
                        oidcpy(&b->oid, &oe->idx.oid);
                        if (oe->pack_id != MAX_PACK_ID) {
                                unsigned long size;
        else
                die("Invalid ref name or SHA1 expression: %s", from);
  
-       if (b->branch_tree.tree && oidcmp(&oid, &b->branch_tree.versions[1].oid)) {
+       if (b->branch_tree.tree && !oideq(&oid, &b->branch_tree.versions[1].oid)) {
                release_tree_content_recursive(b->branch_tree.tree);
                b->branch_tree.tree = NULL;
        }
diff --combined http-push.c
index 91fdc7e1d5d987203d9df3a6c6a86b917f27b939,283495c18a31d3e2acba9f06e7e0605e111a25fb..1bbb0cdb6d03353fbc145d6ba748a30c9eabcec0
@@@ -14,7 -14,7 +14,7 @@@
  #include "argv-array.h"
  #include "packfile.h"
  #include "object-store.h"
 -
 +#include "commit-reach.h"
  
  #ifdef EXPAT_NEEDS_XMLPARSE_H
  #include <xmlparse.h>
@@@ -1859,7 -1859,7 +1859,7 @@@ int cmd_main(int argc, const char **arg
                        continue;
                }
  
-               if (!oidcmp(&ref->old_oid, &ref->peer_ref->new_oid)) {
+               if (oideq(&ref->old_oid, &ref->peer_ref->new_oid)) {
                        if (push_verbosely)
                                fprintf(stderr, "'%s': up-to-date\n", ref->name);
                        if (helper_status)
diff --combined log-tree.c
index e5b353ea2d587c091b841e92f7ddcde4c4266a1a,2edff78cff02ec5cdcc2056b57483f336b568c25..7a83e99250c5245bbbbd43908f3c116567f39b62
@@@ -15,8 -15,6 +15,8 @@@
  #include "sequencer.h"
  #include "line-log.h"
  #include "help.h"
 +#include "interdiff.h"
 +#include "range-diff.h"
  
  static struct decoration name_decoration = { "object names" };
  static int decoration_loaded;
@@@ -474,7 -472,7 +474,7 @@@ static int which_parent(const struct ob
        const struct commit_list *parent;
  
        for (nth = 0, parent = commit->parents; parent; parent = parent->next) {
-               if (!oidcmp(&parent->item->object.oid, oid))
+               if (oideq(&parent->item->object.oid, oid))
                        return nth;
                nth++;
        }
@@@ -508,8 -506,8 +508,8 @@@ static int show_one_mergetag(struct com
        if (parse_tag_buffer(the_repository, tag, extra->value, extra->len))
                strbuf_addstr(&verify_message, "malformed mergetag\n");
        else if (is_common_merge(commit) &&
-                !oidcmp(&tag->tagged->oid,
-                         &commit->parents->next->item->object.oid))
+                oideq(&tag->tagged->oid,
+                      &commit->parents->next->item->object.oid))
                strbuf_addf(&verify_message,
                            "merged tag '%s'\n", tag->tag);
        else if ((nth = which_parent(&tag->tagged->oid, commit)) < 0)
@@@ -544,16 -542,6 +544,16 @@@ static int show_mergetag(struct rev_inf
        return for_each_mergetag(show_one_mergetag, commit, opt);
  }
  
 +static void next_commentary_block(struct rev_info *opt, struct strbuf *sb)
 +{
 +      const char *x = opt->shown_dashes ? "\n" : "---\n";
 +      if (sb)
 +              strbuf_addstr(sb, x);
 +      else
 +              fputs(x, opt->diffopt.file);
 +      opt->shown_dashes = 1;
 +}
 +
  void show_log(struct rev_info *opt)
  {
        struct strbuf msgbuf = STRBUF_INIT;
  
        if ((ctx.fmt != CMIT_FMT_USERFORMAT) &&
            ctx.notes_message && *ctx.notes_message) {
 -              if (cmit_fmt_is_mail(ctx.fmt)) {
 -                      strbuf_addstr(&msgbuf, "---\n");
 -                      opt->shown_dashes = 1;
 -              }
 +              if (cmit_fmt_is_mail(ctx.fmt))
 +                      next_commentary_block(opt, &msgbuf);
                strbuf_addstr(&msgbuf, ctx.notes_message);
        }
  
  
        strbuf_release(&msgbuf);
        free(ctx.notes_message);
 +
 +      if (cmit_fmt_is_mail(ctx.fmt) && opt->idiff_oid1) {
 +              struct diff_queue_struct dq;
 +
 +              memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));
 +              DIFF_QUEUE_CLEAR(&diff_queued_diff);
 +
 +              next_commentary_block(opt, NULL);
 +              fprintf_ln(opt->diffopt.file, "%s", opt->idiff_title);
 +              show_interdiff(opt, 2);
 +
 +              memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
 +      }
 +
 +      if (cmit_fmt_is_mail(ctx.fmt) && opt->rdiff1) {
 +              struct diff_queue_struct dq;
 +
 +              memcpy(&dq, &diff_queued_diff, sizeof(diff_queued_diff));
 +              DIFF_QUEUE_CLEAR(&diff_queued_diff);
 +
 +              next_commentary_block(opt, NULL);
 +              fprintf_ln(opt->diffopt.file, "%s", opt->rdiff_title);
 +              show_range_diff(opt->rdiff1, opt->rdiff2,
 +                              opt->creation_factor, 1, &opt->diffopt);
 +
 +              memcpy(&diff_queued_diff, &dq, sizeof(diff_queued_diff));
 +      }
  }
  
  int log_tree_diff_flush(struct rev_info *opt)
  
                        /*
                         * We may have shown three-dashes line early
 -                       * between notes and the log message, in which
 -                       * case we only want a blank line after the
 -                       * notes without (an extra) three-dashes line.
 +                       * between generated commentary (notes, etc.)
 +                       * and the log message, in which case we only
 +                       * want a blank line after the commentary
 +                       * without (an extra) three-dashes line.
                         * Otherwise, we show the three-dashes line if
                         * we are showing the patch with diffstat, but
                         * in that case, there is no extra blank line
diff --combined merge-recursive.c
index d9d78ec3832c54cae373e9fb688d5153e66830e2,2904cb825eea64bef30d99417f343fe63ddcb12a..45a163c5556d0a40767f8d9fc5fd32ff86a514d6
@@@ -27,7 -27,6 +27,7 @@@
  #include "dir.h"
  #include "submodule.h"
  #include "revision.h"
 +#include "commit-reach.h"
  
  struct path_hashmap_entry {
        struct hashmap_entry e;
@@@ -157,7 -156,7 +157,7 @@@ static struct tree *shift_tree_object(s
                shift_tree_by(&one->object.oid, &two->object.oid, &shifted,
                              subtree_shift);
        }
-       if (!oidcmp(&two->object.oid, &shifted))
+       if (oideq(&two->object.oid, &shifted))
                return two;
        return lookup_tree(the_repository, &shifted);
  }
@@@ -180,7 -179,7 +180,7 @@@ static int oid_eq(const struct object_i
  {
        if (!a && !b)
                return 2;
-       return a && b && oidcmp(a, b) == 0;
+       return a && b && oideq(a, b);
  }
  
  enum rename_type {
@@@ -2870,19 -2869,12 +2870,19 @@@ static int detect_and_process_renames(s
        head_pairs = get_diffpairs(o, common, head);
        merge_pairs = get_diffpairs(o, common, merge);
  
 -      dir_re_head = get_directory_renames(head_pairs, head);
 -      dir_re_merge = get_directory_renames(merge_pairs, merge);
 +      if (o->detect_directory_renames) {
 +              dir_re_head = get_directory_renames(head_pairs, head);
 +              dir_re_merge = get_directory_renames(merge_pairs, merge);
  
 -      handle_directory_level_conflicts(o,
 -                                       dir_re_head, head,
 -                                       dir_re_merge, merge);
 +              handle_directory_level_conflicts(o,
 +                                               dir_re_head, head,
 +                                               dir_re_merge, merge);
 +      } else {
 +              dir_re_head  = xmalloc(sizeof(*dir_re_head));
 +              dir_re_merge = xmalloc(sizeof(*dir_re_merge));
 +              dir_rename_init(dir_re_head);
 +              dir_rename_init(dir_re_merge);
 +      }
  
        ri->head_renames  = get_renames(o, head_pairs,
                                        dir_re_merge, dir_re_head, head,
@@@ -3594,7 -3586,6 +3594,7 @@@ void init_merge_options(struct merge_op
        o->renormalize = 0;
        o->diff_detect_rename = -1;
        o->merge_detect_rename = -1;
 +      o->detect_directory_renames = 1;
        merge_recursive_config(o);
        merge_verbosity = getenv("GIT_MERGE_VERBOSITY");
        if (merge_verbosity)
diff --combined notes-merge.c
index 12dfdf6c17015442d51577a0b621ec20d344ca20,0a47e54cf8919cef468e63adab2deaac868ec5e7..5764e2b0ef06a3251d93e5535e85861ad3503fe9
@@@ -12,7 -12,6 +12,7 @@@
  #include "notes-merge.h"
  #include "strbuf.h"
  #include "notes-utils.h"
 +#include "commit-reach.h"
  
  struct notes_merge_pair {
        struct object_id obj, base, local, remote;
@@@ -152,7 -151,7 +152,7 @@@ static struct notes_merge_pair *diff_tr
                mp = find_notes_merge_pair_pos(changes, len, &obj, 1, &occupied);
                if (occupied) {
                        /* We've found an addition/deletion pair */
-                       assert(!oidcmp(&mp->obj, &obj));
+                       assert(oideq(&mp->obj, &obj));
                        if (is_null_oid(&p->one->oid)) { /* addition */
                                assert(is_null_oid(&mp->remote));
                                oidcpy(&mp->remote, &p->two->oid);
@@@ -219,7 -218,7 +219,7 @@@ static void diff_tree_local(struct note
                        continue;
                }
  
-               assert(!oidcmp(&mp->obj, &obj));
+               assert(oideq(&mp->obj, &obj));
                if (is_null_oid(&p->two->oid)) { /* deletion */
                        /*
                         * Either this is a true deletion (1), or it is part
                         * (3) mp->local is uninitialized; set it to null_sha1
                         *     (will be overwritten by following addition)
                         */
-                       if (!oidcmp(&mp->local, &uninitialized))
+                       if (oideq(&mp->local, &uninitialized))
                                oidclr(&mp->local);
                } else if (is_null_oid(&p->one->oid)) { /* addition */
                        /*
                         * (3) mp->local is null_sha1;     set to p->two->sha1
                         */
                        assert(is_null_oid(&mp->local) ||
-                              !oidcmp(&mp->local, &uninitialized));
+                              oideq(&mp->local, &uninitialized));
                        oidcpy(&mp->local, &p->two->oid);
                } else { /* modification */
                        /*
                         * match mp->base, and mp->local shall be uninitialized.
                         * Set mp->local to p->two->sha1.
                         */
-                       assert(!oidcmp(&p->one->oid, &mp->base));
-                       assert(!oidcmp(&mp->local, &uninitialized));
+                       assert(oideq(&p->one->oid, &mp->base));
+                       assert(oideq(&mp->local, &uninitialized));
                        oidcpy(&mp->local, &p->two->oid);
                }
                trace_printf("\t\tStored local change for %s: %.7s -> %.7s\n",
@@@ -481,14 -480,14 +481,14 @@@ static int merge_changes(struct notes_m
                       oid_to_hex(&p->local),
                       oid_to_hex(&p->remote));
  
-               if (!oidcmp(&p->base, &p->remote)) {
+               if (oideq(&p->base, &p->remote)) {
                        /* no remote change; nothing to do */
                        trace_printf("\t\t\tskipping (no remote change)\n");
-               } else if (!oidcmp(&p->local, &p->remote)) {
+               } else if (oideq(&p->local, &p->remote)) {
                        /* same change in local and remote; nothing to do */
                        trace_printf("\t\t\tskipping (local == remote)\n");
-               } else if (!oidcmp(&p->local, &uninitialized) ||
-                          !oidcmp(&p->local, &p->base)) {
+               } else if (oideq(&p->local, &uninitialized) ||
+                          oideq(&p->local, &p->base)) {
                        /* no local change; adopt remote change */
                        trace_printf("\t\t\tno local change, adopted remote\n");
                        if (add_note(t, &p->obj, &p->remote,
@@@ -622,14 -621,14 +622,14 @@@ int notes_merge(struct notes_merge_opti
                        oid_to_hex(&local->object.oid),
                        oid_to_hex(base_oid));
  
-       if (!oidcmp(&remote->object.oid, base_oid)) {
+       if (oideq(&remote->object.oid, base_oid)) {
                /* Already merged; result == local commit */
                if (o->verbosity >= 2)
                        printf("Already up to date!\n");
                oidcpy(result_oid, &local->object.oid);
                goto found_result;
        }
-       if (!oidcmp(&local->object.oid, base_oid)) {
+       if (oideq(&local->object.oid, base_oid)) {
                /* Fast-forward; result == remote commit */
                if (o->verbosity >= 2)
                        printf("Fast-forward\n");
diff --combined pack-objects.c
index 7f7b7dddf6955b2f791e2d97cd90381e5edfd339,2bc762699770d80a55d80a0231c04040973558cd..7e624c30ebd7f344d711b608b29b2d48d21a1ba0
@@@ -16,7 -16,7 +16,7 @@@ static uint32_t locate_object_entry_has
        while (pdata->index[i] > 0) {
                uint32_t pos = pdata->index[i] - 1;
  
-               if (!hashcmp(sha1, pdata->objects[pos].idx.oid.hash)) {
+               if (hasheq(sha1, pdata->objects[pos].idx.oid.hash)) {
                        *found = 1;
                        return i;
                }
@@@ -99,7 -99,7 +99,7 @@@ static void prepare_in_pack_by_idx(stru
         * (i.e. in_pack_idx also zero) should return NULL.
         */
        mapping[cnt++] = NULL;
 -      for (p = get_packed_git(the_repository); p; p = p->next, cnt++) {
 +      for (p = get_all_packs(the_repository); p; p = p->next, cnt++) {
                if (cnt == nr) {
                        free(mapping);
                        return;
@@@ -164,12 -164,6 +164,12 @@@ struct object_entry *packlist_alloc(str
                        REALLOC_ARRAY(pdata->in_pack, pdata->nr_alloc);
                if (pdata->delta_size)
                        REALLOC_ARRAY(pdata->delta_size, pdata->nr_alloc);
 +
 +              if (pdata->tree_depth)
 +                      REALLOC_ARRAY(pdata->tree_depth, pdata->nr_alloc);
 +
 +              if (pdata->layer)
 +                      REALLOC_ARRAY(pdata->layer, pdata->nr_alloc);
        }
  
        new_entry = pdata->objects + pdata->nr_objects++;
        if (pdata->in_pack)
                pdata->in_pack[pdata->nr_objects - 1] = NULL;
  
 +      if (pdata->tree_depth)
 +              pdata->tree_depth[pdata->nr_objects - 1] = 0;
 +
 +      if (pdata->layer)
 +              pdata->layer[pdata->nr_objects - 1] = 0;
 +
        return new_entry;
  }
 +
 +void oe_set_delta_ext(struct packing_data *pdata,
 +                    struct object_entry *delta,
 +                    const unsigned char *sha1)
 +{
 +      struct object_entry *base;
 +
 +      ALLOC_GROW(pdata->ext_bases, pdata->nr_ext + 1, pdata->alloc_ext);
 +      base = &pdata->ext_bases[pdata->nr_ext++];
 +      memset(base, 0, sizeof(*base));
 +      hashcpy(base->idx.oid.hash, sha1);
 +
 +      /* These flags mark that we are not part of the actual pack output. */
 +      base->preferred_base = 1;
 +      base->filled = 1;
 +
 +      delta->ext_base = 1;
 +      delta->delta_idx = base - pdata->ext_bases + 1;
 +}
diff --combined packfile.c
index cbef7033c3b8ea96e716dbe693bb40182cacdcf0,1e9eacd9b34ee9014d09eef01d538a73b47b1696..841b36182fcd938da5ee0a4b065e0717ef4a18ed
@@@ -15,7 -15,6 +15,7 @@@
  #include "tree-walk.h"
  #include "tree.h"
  #include "object-store.h"
 +#include "midx.h"
  
  char *odb_pack_name(struct strbuf *buf,
                    const unsigned char *sha1,
@@@ -197,23 -196,6 +197,23 @@@ int open_pack_index(struct packed_git *
        return ret;
  }
  
 +uint32_t get_pack_fanout(struct packed_git *p, uint32_t value)
 +{
 +      const uint32_t *level1_ofs = p->index_data;
 +
 +      if (!level1_ofs) {
 +              if (open_pack_index(p))
 +                      return 0;
 +              level1_ofs = p->index_data;
 +      }
 +
 +      if (p->index_version > 1) {
 +              level1_ofs += 2;
 +      }
 +
 +      return ntohl(level1_ofs[value]);
 +}
 +
  static struct packed_git *alloc_packed_git(int extra)
  {
        struct packed_git *p = xmalloc(st_add(sizeof(*p), extra));
@@@ -469,19 -451,8 +469,19 @@@ static int open_packed_git_1(struct pac
        ssize_t read_result;
        const unsigned hashsz = the_hash_algo->rawsz;
  
 -      if (!p->index_data && open_pack_index(p))
 -              return error("packfile %s index unavailable", p->pack_name);
 +      if (!p->index_data) {
 +              struct multi_pack_index *m;
 +              const char *pack_name = strrchr(p->pack_name, '/');
 +
 +              for (m = the_repository->objects->multi_pack_index;
 +                   m; m = m->next) {
 +                      if (midx_contains_pack(m, pack_name))
 +                              break;
 +              }
 +
 +              if (!m && open_pack_index(p))
 +                      return error("packfile %s index unavailable", p->pack_name);
 +      }
  
        if (!pack_max_fds) {
                unsigned int max_fds = get_max_fd_limit();
                        " supported (try upgrading GIT to a newer version)",
                        p->pack_name, ntohl(hdr.hdr_version));
  
 +      /* Skip index checking if in multi-pack-index */
 +      if (!p->index_data)
 +              return 0;
 +
        /* Verify the pack matches its index. */
        if (p->num_objects != ntohl(hdr.hdr_entries))
                return error("packfile %s claims to have %"PRIu32" objects"
        if (read_result != hashsz)
                return error("packfile %s signature is unavailable", p->pack_name);
        idx_hash = ((unsigned char *)p->index_data) + p->index_size - hashsz * 2;
-       if (hashcmp(hash, idx_hash))
+       if (!hasheq(hash, idx_hash))
                return error("packfile %s does not match index", p->pack_name);
        return 0;
  }
@@@ -771,14 -738,13 +771,14 @@@ static void report_pack_garbage(struct 
        report_helper(list, seen_bits, first, list->nr);
  }
  
 -static void prepare_packed_git_one(struct repository *r, char *objdir, int local)
 +void for_each_file_in_pack_dir(const char *objdir,
 +                             each_file_in_pack_dir_fn fn,
 +                             void *data)
  {
        struct strbuf path = STRBUF_INIT;
        size_t dirnamelen;
        DIR *dir;
        struct dirent *de;
 -      struct string_list garbage = STRING_LIST_INIT_DUP;
  
        strbuf_addstr(&path, objdir);
        strbuf_addstr(&path, "/pack");
        strbuf_addch(&path, '/');
        dirnamelen = path.len;
        while ((de = readdir(dir)) != NULL) {
 -              struct packed_git *p;
 -              size_t base_len;
 -
                if (is_dot_or_dotdot(de->d_name))
                        continue;
  
                strbuf_setlen(&path, dirnamelen);
                strbuf_addstr(&path, de->d_name);
  
 -              base_len = path.len;
 -              if (strip_suffix_mem(path.buf, &base_len, ".idx")) {
 -                      /* Don't reopen a pack we already have. */
 -                      for (p = r->objects->packed_git; p;
 -                           p = p->next) {
 -                              size_t len;
 -                              if (strip_suffix(p->pack_name, ".pack", &len) &&
 -                                  len == base_len &&
 -                                  !memcmp(p->pack_name, path.buf, len))
 -                                      break;
 -                      }
 -                      if (p == NULL &&
 -                          /*
 -                           * See if it really is a valid .idx file with
 -                           * corresponding .pack file that we can map.
 -                           */
 -                          (p = add_packed_git(path.buf, path.len, local)) != NULL)
 -                              install_packed_git(r, p);
 -              }
 -
 -              if (!report_garbage)
 -                      continue;
 -
 -              if (ends_with(de->d_name, ".idx") ||
 -                  ends_with(de->d_name, ".pack") ||
 -                  ends_with(de->d_name, ".bitmap") ||
 -                  ends_with(de->d_name, ".keep") ||
 -                  ends_with(de->d_name, ".promisor"))
 -                      string_list_append(&garbage, path.buf);
 -              else
 -                      report_garbage(PACKDIR_FILE_GARBAGE, path.buf);
 +              fn(path.buf, path.len, de->d_name, data);
        }
 +
        closedir(dir);
 -      report_pack_garbage(&garbage);
 -      string_list_clear(&garbage, 0);
        strbuf_release(&path);
  }
  
 +struct prepare_pack_data {
 +      struct repository *r;
 +      struct string_list *garbage;
 +      int local;
 +      struct multi_pack_index *m;
 +};
 +
 +static void prepare_pack(const char *full_name, size_t full_name_len,
 +                       const char *file_name, void *_data)
 +{
 +      struct prepare_pack_data *data = (struct prepare_pack_data *)_data;
 +      struct packed_git *p;
 +      size_t base_len = full_name_len;
 +
 +      if (strip_suffix_mem(full_name, &base_len, ".idx") &&
 +          !(data->m && midx_contains_pack(data->m, file_name))) {
 +              /* Don't reopen a pack we already have. */
 +              for (p = data->r->objects->packed_git; p; p = p->next) {
 +                      size_t len;
 +                      if (strip_suffix(p->pack_name, ".pack", &len) &&
 +                          len == base_len &&
 +                          !memcmp(p->pack_name, full_name, len))
 +                              break;
 +              }
 +
 +              if (!p) {
 +                      p = add_packed_git(full_name, full_name_len, data->local);
 +                      if (p)
 +                              install_packed_git(data->r, p);
 +              }
 +      }
 +
 +      if (!report_garbage)
 +              return;
 +
 +      if (!strcmp(file_name, "multi-pack-index"))
 +              return;
 +      if (ends_with(file_name, ".idx") ||
 +          ends_with(file_name, ".pack") ||
 +          ends_with(file_name, ".bitmap") ||
 +          ends_with(file_name, ".keep") ||
 +          ends_with(file_name, ".promisor"))
 +              string_list_append(data->garbage, full_name);
 +      else
 +              report_garbage(PACKDIR_FILE_GARBAGE, full_name);
 +}
 +
 +static void prepare_packed_git_one(struct repository *r, char *objdir, int local)
 +{
 +      struct prepare_pack_data data;
 +      struct string_list garbage = STRING_LIST_INIT_DUP;
 +
 +      data.m = r->objects->multi_pack_index;
 +
 +      /* look for the multi-pack-index for this object directory */
 +      while (data.m && strcmp(data.m->object_dir, objdir))
 +              data.m = data.m->next;
 +
 +      data.r = r;
 +      data.garbage = &garbage;
 +      data.local = local;
 +
 +      for_each_file_in_pack_dir(objdir, prepare_pack, &data);
 +
 +      report_pack_garbage(data.garbage);
 +      string_list_clear(data.garbage, 0);
 +}
 +
  static void prepare_packed_git(struct repository *r);
  /*
   * Give a fast, rough count of the number of objects in the repository. This
@@@ -886,13 -818,10 +886,13 @@@ unsigned long approximate_object_count(
  {
        if (!the_repository->objects->approximate_object_count_valid) {
                unsigned long count;
 +              struct multi_pack_index *m;
                struct packed_git *p;
  
                prepare_packed_git(the_repository);
                count = 0;
 +              for (m = get_multi_pack_index(the_repository); m; m = m->next)
 +                      count += m->num_objects;
                for (p = the_repository->objects->packed_git; p; p = p->next) {
                        if (open_pack_index(p))
                                continue;
@@@ -964,17 -893,11 +964,17 @@@ static void prepare_packed_git(struct r
  
        if (r->objects->packed_git_initialized)
                return;
 +      prepare_multi_pack_index_one(r, r->objects->objectdir, 1);
        prepare_packed_git_one(r, r->objects->objectdir, 1);
        prepare_alt_odb(r);
 -      for (alt = r->objects->alt_odb_list; alt; alt = alt->next)
 +      for (alt = r->objects->alt_odb_list; alt; alt = alt->next) {
 +              prepare_multi_pack_index_one(r, alt->path, 0);
                prepare_packed_git_one(r, alt->path, 0);
 +      }
        rearrange_packed_git(r);
 +
 +      r->objects->all_packs = NULL;
 +
        prepare_packed_git_mru(r);
        r->objects->packed_git_initialized = 1;
  }
@@@ -992,36 -915,6 +992,36 @@@ struct packed_git *get_packed_git(struc
        return r->objects->packed_git;
  }
  
 +struct multi_pack_index *get_multi_pack_index(struct repository *r)
 +{
 +      prepare_packed_git(r);
 +      return r->objects->multi_pack_index;
 +}
 +
 +struct packed_git *get_all_packs(struct repository *r)
 +{
 +      prepare_packed_git(r);
 +
 +      if (!r->objects->all_packs) {
 +              struct packed_git *p = r->objects->packed_git;
 +              struct multi_pack_index *m;
 +
 +              for (m = r->objects->multi_pack_index; m; m = m->next) {
 +                      uint32_t i;
 +                      for (i = 0; i < m->num_packs; i++) {
 +                              if (!prepare_midx_pack(m, i)) {
 +                                      m->packs[i]->next = p;
 +                                      p = m->packs[i];
 +                              }
 +                      }
 +              }
 +
 +              r->objects->all_packs = p;
 +      }
 +
 +      return r->objects->all_packs;
 +}
 +
  struct list_head *get_packed_git_mru(struct repository *r)
  {
        prepare_packed_git(r);
@@@ -1122,7 -1015,7 +1122,7 @@@ void mark_bad_packed_object(struct pack
  {
        unsigned i;
        for (i = 0; i < p->num_bad_objects; i++)
-               if (!hashcmp(sha1, p->bad_object_sha1 + GIT_SHA1_RAWSZ * i))
+               if (hasheq(sha1, p->bad_object_sha1 + GIT_SHA1_RAWSZ * i))
                        return;
        p->bad_object_sha1 = xrealloc(p->bad_object_sha1,
                                      st_mult(GIT_MAX_RAWSZ,
@@@ -1138,8 -1031,8 +1138,8 @@@ const struct packed_git *has_packed_and
  
        for (p = the_repository->objects->packed_git; p; p = p->next)
                for (i = 0; i < p->num_bad_objects; i++)
-                       if (!hashcmp(sha1,
-                                    p->bad_object_sha1 + the_hash_algo->rawsz * i))
+                       if (hasheq(sha1,
+                                  p->bad_object_sha1 + the_hash_algo->rawsz * i))
                                return p;
        return NULL;
  }
@@@ -1937,8 -1830,8 +1937,8 @@@ static int fill_pack_entry(const struc
        if (p->num_bad_objects) {
                unsigned i;
                for (i = 0; i < p->num_bad_objects; i++)
-                       if (!hashcmp(oid->hash,
-                                    p->bad_object_sha1 + the_hash_algo->rawsz * i))
+                       if (hasheq(oid->hash,
+                                  p->bad_object_sha1 + the_hash_algo->rawsz * i))
                                return 0;
        }
  
  int find_pack_entry(struct repository *r, const struct object_id *oid, struct pack_entry *e)
  {
        struct list_head *pos;
 +      struct multi_pack_index *m;
  
        prepare_packed_git(r);
 -      if (!r->objects->packed_git)
 +      if (!r->objects->packed_git && !r->objects->multi_pack_index)
                return 0;
  
 +      for (m = r->objects->multi_pack_index; m; m = m->next) {
 +              if (fill_midx_entry(oid, e, m))
 +                      return 1;
 +      }
 +
        list_for_each(pos, &r->objects->packed_git_mru) {
                struct packed_git *p = list_entry(pos, struct packed_git, mru);
                if (fill_pack_entry(oid, e, p)) {
@@@ -2036,7 -1923,7 +2036,7 @@@ int for_each_packed_object(each_packed_
        int pack_errors = 0;
  
        prepare_packed_git(the_repository);
 -      for (p = the_repository->objects->packed_git; p; p = p->next) {
 +      for (p = get_all_packs(the_repository); p; p = p->next) {
                if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
                        continue;
                if ((flags & FOR_EACH_OBJECT_PROMISOR_ONLY) &&
diff --combined read-cache.c
index d7b617f320939ad2e3659223d04e7537b2707658,eb7cea6272970685456e72ad78afb483e024124e..8d04d78a5877aab74dd35e24a31bcfe3e0a3417d
@@@ -213,7 -213,7 +213,7 @@@ static int ce_compare_data(const struc
        if (fd >= 0) {
                struct object_id oid;
                if (!index_fd(&oid, fd, st, OBJ_BLOB, ce->name, 0))
-                       match = oidcmp(&oid, &ce->oid);
+                       match = !oideq(&oid, &ce->oid);
                /* index_fd() closed the file descriptor already */
        }
        return match;
@@@ -254,7 -254,7 +254,7 @@@ static int ce_compare_gitlink(const str
         */
        if (resolve_gitlink_ref(ce->name, "HEAD", &oid) < 0)
                return 0;
-       return oidcmp(&oid, &ce->oid);
+       return !oideq(&oid, &ce->oid);
  }
  
  static int ce_modified_check_fs(const struct cache_entry *ce, struct stat *st)
@@@ -767,7 -767,7 +767,7 @@@ int add_to_index(struct index_state *is
        /* It was suspected to be racily clean, but it turns out to be Ok */
        was_same = (alias &&
                    !ce_stage(alias) &&
-                   !oidcmp(&alias->oid, &ce->oid) &&
+                   oideq(&alias->oid, &ce->oid) &&
                    ce->ce_mode == alias->ce_mode);
  
        if (pretend)
@@@ -1476,8 -1476,8 +1476,8 @@@ int refresh_index(struct index_state *i
        const char *typechange_fmt;
        const char *added_fmt;
        const char *unmerged_fmt;
 -      uint64_t start = getnanotime();
  
 +      trace_performance_enter();
        modified_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
        deleted_fmt = (in_porcelain ? "D\t%s\n" : "%s: needs update\n");
        typechange_fmt = (in_porcelain ? "T\t%s\n" : "%s needs update\n");
  
                replace_index_entry(istate, i, new_entry);
        }
 -      trace_performance_since(start, "refresh index");
 +      trace_performance_leave("refresh index");
        return has_errors;
  }
  
@@@ -1668,7 -1668,7 +1668,7 @@@ static int verify_hdr(struct cache_head
        the_hash_algo->init_fn(&c);
        the_hash_algo->update_fn(&c, hdr, size - the_hash_algo->rawsz);
        the_hash_algo->final_fn(hash, &c);
-       if (hashcmp(hash, (unsigned char *)hdr + size - the_hash_algo->rawsz))
+       if (!hasheq(hash, (unsigned char *)hdr + size - the_hash_algo->rawsz))
                return error("bad index file sha1 signature");
        return 0;
  }
@@@ -2002,6 -2002,7 +2002,6 @@@ static void freshen_shared_index(const 
  int read_index_from(struct index_state *istate, const char *path,
                    const char *gitdir)
  {
 -      uint64_t start = getnanotime();
        struct split_index *split_index;
        int ret;
        char *base_oid_hex;
        if (istate->initialized)
                return istate->cache_nr;
  
 +      trace_performance_enter();
        ret = do_read_index(istate, path, 0);
 -      trace_performance_since(start, "read cache %s", path);
 +      trace_performance_leave("read cache %s", path);
  
        split_index = istate->split_index;
        if (!split_index || is_null_oid(&split_index->base_oid)) {
                return ret;
        }
  
 +      trace_performance_enter();
        if (split_index->base)
                discard_index(split_index->base);
        else
        base_oid_hex = oid_to_hex(&split_index->base_oid);
        base_path = xstrfmt("%s/sharedindex.%s", gitdir, base_oid_hex);
        ret = do_read_index(split_index->base, base_path, 1);
-       if (oidcmp(&split_index->base_oid, &split_index->base->oid))
+       if (!oideq(&split_index->base_oid, &split_index->base->oid))
                die("broken index, expect %s in %s, got %s",
                    base_oid_hex, base_path,
                    oid_to_hex(&split_index->base->oid));
        freshen_shared_index(base_path, 0);
        merge_base_index(istate);
        post_read_index_from(istate);
 -      trace_performance_since(start, "read cache %s", base_path);
        free(base_path);
 +      trace_performance_leave("read cache %s", base_path);
        return ret;
  }
  
@@@ -2396,7 -2395,7 +2396,7 @@@ static int verify_index_from(const stru
        if (n != the_hash_algo->rawsz)
                goto out;
  
-       if (hashcmp(istate->oid.hash, hash))
+       if (!hasheq(istate->oid.hash, hash))
                goto out;
  
        close(fd);
@@@ -2744,9 -2743,6 +2744,9 @@@ int write_locked_index(struct index_sta
        int new_shared_index, ret;
        struct split_index *si = istate->split_index;
  
 +      if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
 +              cache_tree_verify(istate);
 +
        if ((flags & SKIP_IF_UNCHANGED) && !istate->cache_changed) {
                if (flags & COMMIT_LOCK)
                        rollback_lock_file(lock);
@@@ -2943,8 -2939,6 +2943,8 @@@ void move_index_extensions(struct index
  {
        dst->untracked = src->untracked;
        src->untracked = NULL;
 +      dst->cache_tree = src->cache_tree;
 +      src->cache_tree = NULL;
  }
  
  struct cache_entry *dup_cache_entry(const struct cache_entry *ce,
diff --combined remote.c
index 9a079517691331fae9cfc46d796c2d296081a7cc,e23b7675c889e5052add668f986fcd0cb7904e3a..682f2a01f949ce942597a9190cecfc991db0108e
+++ b/remote.c
@@@ -12,7 -12,6 +12,7 @@@
  #include "string-list.h"
  #include "mergesort.h"
  #include "argv-array.h"
 +#include "commit-reach.h"
  
  enum map_direction { FROM_SRC, FROM_DST };
  
@@@ -1389,7 -1388,7 +1389,7 @@@ void set_ref_status_for_push(struct re
  
                ref->deletion = is_null_oid(&ref->new_oid);
                if (!ref->deletion &&
-                       !oidcmp(&ref->old_oid, &ref->new_oid)) {
+                       oideq(&ref->old_oid, &ref->new_oid)) {
                        ref->status = REF_STATUS_UPTODATE;
                        continue;
                }
                 * branch.
                 */
                if (ref->expect_old_sha1) {
-                       if (oidcmp(&ref->old_oid, &ref->old_oid_expect))
+                       if (!oideq(&ref->old_oid, &ref->old_oid_expect))
                                reject_reason = REF_STATUS_REJECT_STALE;
                        else
                                /* If the ref isn't stale then force the update. */
@@@ -1792,6 -1791,55 +1792,6 @@@ int resolve_remote_symref(struct ref *r
        return 1;
  }
  
 -static void unmark_and_free(struct commit_list *list, unsigned int mark)
 -{
 -      while (list) {
 -              struct commit *commit = pop_commit(&list);
 -              commit->object.flags &= ~mark;
 -      }
 -}
 -
 -int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
 -{
 -      struct object *o;
 -      struct commit *old_commit, *new_commit;
 -      struct commit_list *list, *used;
 -      int found = 0;
 -
 -      /*
 -       * Both new_commit and old_commit must be commit-ish and new_commit is descendant of
 -       * old_commit.  Otherwise we require --force.
 -       */
 -      o = deref_tag(the_repository, parse_object(the_repository, old_oid),
 -                    NULL, 0);
 -      if (!o || o->type != OBJ_COMMIT)
 -              return 0;
 -      old_commit = (struct commit *) o;
 -
 -      o = deref_tag(the_repository, parse_object(the_repository, new_oid),
 -                    NULL, 0);
 -      if (!o || o->type != OBJ_COMMIT)
 -              return 0;
 -      new_commit = (struct commit *) o;
 -
 -      if (parse_commit(new_commit) < 0)
 -              return 0;
 -
 -      used = list = NULL;
 -      commit_list_insert(new_commit, &list);
 -      while (list) {
 -              new_commit = pop_most_recent_commit(&list, TMP_MARK);
 -              commit_list_insert(new_commit, &used);
 -              if (new_commit == old_commit) {
 -                      found = 1;
 -                      break;
 -              }
 -      }
 -      unmark_and_free(list, TMP_MARK);
 -      unmark_and_free(used, TMP_MARK);
 -      return found;
 -}
 -
  /*
   * Lookup the upstream branch for the given branch and if present, optionally
   * compute the commit ahead/behind values for the pair.
@@@ -2001,7 -2049,7 +2001,7 @@@ struct ref *guess_remote_head(const str
        /* If refs/heads/master could be right, it is. */
        if (!all) {
                r = find_ref_by_name(refs, "refs/heads/master");
-               if (r && !oidcmp(&r->old_oid, &head->old_oid))
+               if (r && oideq(&r->old_oid, &head->old_oid))
                        return copy_ref(r);
        }
  
        for (r = refs; r; r = r->next) {
                if (r != head &&
                    starts_with(r->name, "refs/heads/") &&
-                   !oidcmp(&r->old_oid, &head->old_oid)) {
+                   oideq(&r->old_oid, &head->old_oid)) {
                        *tail = copy_ref(r);
                        tail = &((*tail)->next);
                        if (!all)
diff --combined revision.c
index 494cc041faba7921781cfa7b35c3bd56e877ec6f,a2a569bb3bf3c5130a12f2a81c98a0598e5e405a..e18bd530e4c50d0f5a1887714b074a6c2c63875b
@@@ -24,7 -24,6 +24,7 @@@
  #include "packfile.h"
  #include "worktree.h"
  #include "argv-array.h"
 +#include "commit-reach.h"
  
  volatile show_early_output_fn_t show_early_output;
  
@@@ -2319,7 -2318,7 +2319,7 @@@ static void NORETURN diagnose_missing_d
   */
  int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt)
  {
 -      int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0, revarg_opt;
 +      int i, flags, left, seen_dashdash, got_rev_arg = 0, revarg_opt;
        struct argv_array prune_data = ARGV_ARRAY_INIT;
        const char *submodule = NULL;
  
        revarg_opt = opt ? opt->revarg_opt : 0;
        if (seen_dashdash)
                revarg_opt |= REVARG_CANNOT_BE_FILENAME;
 -      read_from_stdin = 0;
        for (left = i = 1; i < argc; i++) {
                const char *arg = argv[i];
                if (*arg == '-') {
                                        argv[left++] = arg;
                                        continue;
                                }
 -                              if (read_from_stdin++)
 +                              if (revs->read_from_stdin++)
                                        die("--stdin given twice?");
                                read_revisions_from_stdin(revs, &prune_data);
                                continue;
@@@ -3238,7 -3238,7 +3238,7 @@@ static void track_linear(struct rev_inf
                struct commit_list *p;
                for (p = revs->previous_parents; p; p = p->next)
                        if (p->item == NULL || /* first commit */
-                           !oidcmp(&p->item->object.oid, &commit->object.oid))
+                           oideq(&p->item->object.oid, &commit->object.oid))
                                break;
                revs->linear = p != NULL;
        }
diff --combined sequencer.c
index 9ba873b8752a62577c5e510e98af561d7335f43a,b14e5dc13ce17b215e44f58aafaeb47dd8e56681..00cefd129e4a9be73f3003186c90de439ba7d988
@@@ -30,7 -30,6 +30,7 @@@
  #include "oidset.h"
  #include "commit-slab.h"
  #include "alias.h"
 +#include "commit-reach.h"
  
  #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
  
@@@ -226,16 -225,13 +226,16 @@@ static const char *get_todo_path(const 
   * Returns 3 when sob exists within conforming footer as last entry
   */
  static int has_conforming_footer(struct strbuf *sb, struct strbuf *sob,
 -      int ignore_footer)
 +      size_t ignore_footer)
  {
 +      struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
        struct trailer_info info;
 -      int i;
 +      size_t i;
        int found_sob = 0, found_sob_last = 0;
  
 -      trailer_info_get(&info, sb->buf);
 +      opts.no_divider = 1;
 +
 +      trailer_info_get(&info, sb->buf, &opts);
  
        if (info.trailer_start == info.trailer_end)
                return 0;
@@@ -614,7 -610,7 +614,7 @@@ static int is_index_unchanged(void
        if (!(cache_tree_oid = get_cache_tree_oid()))
                return -1;
  
-       return !oidcmp(cache_tree_oid, get_commit_tree_oid(head_commit));
+       return oideq(cache_tree_oid, get_commit_tree_oid(head_commit));
  }
  
  static int write_author_script(const char *message)
@@@ -643,7 -639,7 +643,7 @@@ missing_author
                else if (*message != '\'')
                        strbuf_addch(&buf, *(message++));
                else
 -                      strbuf_addf(&buf, "'\\\\%c'", *(message++));
 +                      strbuf_addf(&buf, "'\\%c'", *(message++));
        strbuf_addstr(&buf, "'\nGIT_AUTHOR_EMAIL='");
        while (*message && *message != '\n' && *message != '\r')
                if (skip_prefix(message, "> ", &message))
                else if (*message != '\'')
                        strbuf_addch(&buf, *(message++));
                else
 -                      strbuf_addf(&buf, "'\\\\%c'", *(message++));
 +                      strbuf_addf(&buf, "'\\%c'", *(message++));
        strbuf_addstr(&buf, "'\nGIT_AUTHOR_DATE='@");
        while (*message && *message != '\n' && *message != '\r')
                if (*message != '\'')
                        strbuf_addch(&buf, *(message++));
                else
 -                      strbuf_addf(&buf, "'\\\\%c'", *(message++));
 +                      strbuf_addf(&buf, "'\\%c'", *(message++));
        strbuf_addch(&buf, '\'');
        res = write_message(buf.buf, buf.len, rebase_path_author_script(), 1);
        strbuf_release(&buf);
        return res;
  }
  
 +
 +/*
 + * write_author_script() used to fail to terminate the last line with a "'" and
 + * also escaped "'" incorrectly as "'\\\\''" rather than "'\\''". We check for
 + * the terminating "'" on the last line to see how "'" has been escaped in case
 + * git was upgraded while rebase was stopped.
 + */
 +static int quoting_is_broken(const char *s, size_t n)
 +{
 +      /* Skip any empty lines in case the file was hand edited */
 +      while (n > 0 && s[--n] == '\n')
 +              ; /* empty */
 +      if (n > 0 && s[n] != '\'')
 +              return 1;
 +
 +      return 0;
 +}
 +
  /*
   * Read a list of environment variable assignments (such as the author-script
   * file) into an environment block. Returns -1 on error, 0 otherwise.
  static int read_env_script(struct argv_array *env)
  {
        struct strbuf script = STRBUF_INIT;
 -      int i, count = 0;
 -      char *p, *p2;
 +      int i, count = 0, sq_bug;
 +      const char *p2;
 +      char *p;
  
        if (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)
                return -1;
 -
 +      /* write_author_script() used to quote incorrectly */
 +      sq_bug = quoting_is_broken(script.buf, script.len);
        for (p = script.buf; *p; p++)
 -              if (skip_prefix(p, "'\\\\''", (const char **)&p2))
 +              if (sq_bug && skip_prefix(p, "'\\\\''", &p2))
 +                      strbuf_splice(&script, p - script.buf, p2 - p, "'", 1);
 +              else if (skip_prefix(p, "'\\''", &p2))
                        strbuf_splice(&script, p - script.buf, p2 - p, "'", 1);
                else if (*p == '\'')
                        strbuf_splice(&script, p-- - script.buf, 1, "", 0);
@@@ -824,18 -798,11 +824,18 @@@ static int run_git_commit(const char *d
  
        if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
                struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT;
 -              const char *author = is_rebase_i(opts) ?
 -                      read_author_ident(&script) : NULL;
 +              const char *author = NULL;
                struct object_id root_commit, *cache_tree_oid;
                int res = 0;
  
 +              if (is_rebase_i(opts)) {
 +                      author = read_author_ident(&script);
 +                      if (!author) {
 +                              strbuf_release(&script);
 +                              return -1;
 +                      }
 +              }
 +
                if (!defmsg)
                        BUG("root commit without message");
  
@@@ -1221,7 -1188,7 +1221,7 @@@ static int parse_head(struct commit **h
                current_head = lookup_commit_reference(the_repository, &oid);
                if (!current_head)
                        return error(_("could not parse HEAD"));
-               if (oidcmp(&oid, &current_head->object.oid)) {
+               if (!oideq(&oid, &current_head->object.oid)) {
                        warning(_("HEAD %s is not a commit!"),
                                oid_to_hex(&oid));
                }
@@@ -1291,9 -1258,9 +1291,9 @@@ static int try_to_commit(struct strbuf 
                goto out;
        }
  
-       if (!(flags & ALLOW_EMPTY) && !oidcmp(current_head ?
-                                             get_commit_tree_oid(current_head) :
-                                             the_hash_algo->empty_tree, &tree)) {
+       if (!(flags & ALLOW_EMPTY) && oideq(current_head ?
+                                           get_commit_tree_oid(current_head) :
+                                           the_hash_algo->empty_tree, &tree)) {
                res = 1; /* run 'git commit' to display error message */
                goto out;
        }
@@@ -1398,7 -1365,7 +1398,7 @@@ static int is_original_commit_empty(str
                ptree_oid = the_hash_algo->empty_tree; /* commit is root */
        }
  
-       return !oidcmp(ptree_oid, get_commit_tree_oid(commit));
+       return oideq(ptree_oid, get_commit_tree_oid(commit));
  }
  
  /*
@@@ -1678,7 -1645,7 +1678,7 @@@ static int do_pick_commit(enum todo_com
                unborn = get_oid("HEAD", &head);
                /* Do we want to generate a root commit? */
                if (is_pick_or_similar(command) && opts->have_squash_onto &&
-                   !oidcmp(&head, &opts->squash_onto)) {
+                   oideq(&head, &opts->squash_onto)) {
                        if (is_fixup(command))
                                return error(_("cannot fixup root commit"));
                        flags |= CREATE_ROOT_COMMIT;
                        oid_to_hex(&commit->object.oid));
  
        if (opts->allow_ff && !is_fixup(command) &&
-           ((parent && !oidcmp(&parent->object.oid, &head)) ||
+           ((parent && oideq(&parent->object.oid, &head)) ||
             (!parent && unborn))) {
                if (is_rebase_i(opts))
                        write_author_script(msg.message);
@@@ -2426,7 -2393,7 +2426,7 @@@ static int rollback_is_safe(void
        if (get_oid("HEAD", &actual_head))
                oidclr(&actual_head);
  
-       return !oidcmp(&actual_head, &expected_head);
+       return oideq(&actual_head, &expected_head);
  }
  
  static int reset_for_rollback(const struct object_id *oid)
@@@ -2987,7 -2954,7 +2987,7 @@@ static int do_merge(struct commit *comm
        }
  
        if (opts->have_squash_onto &&
-           !oidcmp(&head_commit->object.oid, &opts->squash_onto)) {
+           oideq(&head_commit->object.oid, &opts->squash_onto)) {
                /*
                 * When the user tells us to "merge" something into a
                 * "[new root]", let's simply fast-forward to the merge head.
         * commit, we cannot fast-forward.
         */
        can_fast_forward = opts->allow_ff && commit && commit->parents &&
-               !oidcmp(&commit->parents->item->object.oid,
-                       &head_commit->object.oid);
+               oideq(&commit->parents->item->object.oid,
+                     &head_commit->object.oid);
  
        /*
         * If any merge head is different from the original one, we cannot
                struct commit_list *p = commit->parents->next;
  
                for (j = to_merge; j && p; j = j->next, p = p->next)
-                       if (oidcmp(&j->item->object.oid,
+                       if (!oideq(&j->item->object.oid,
                                   &p->item->object.oid)) {
                                can_fast_forward = 0;
                                break;
        write_message("no-ff", 5, git_path_merge_mode(the_repository), 0);
  
        bases = get_merge_bases(head_commit, merge_commit);
-       if (bases && !oidcmp(&merge_commit->object.oid,
-                            &bases->item->object.oid)) {
+       if (bases && oideq(&merge_commit->object.oid,
+                          &bases->item->object.oid)) {
                ret = 0;
                /* skip merging an ancestor of HEAD */
                goto leave_merge;
@@@ -3382,9 -3349,9 +3382,9 @@@ static int pick_commits(struct todo_lis
                                 */
                                if (item->command == TODO_REWORD &&
                                    !get_oid("HEAD", &oid) &&
-                                   (!oidcmp(&item->commit->object.oid, &oid) ||
+                                   (oideq(&item->commit->object.oid, &oid) ||
                                     (opts->have_squash_onto &&
-                                     !oidcmp(&opts->squash_onto, &oid))))
+                                     oideq(&opts->squash_onto, &oid))))
                                        to_amend = 1;
  
                                return res | error_with_patch(item->commit,
@@@ -3599,7 -3566,7 +3599,7 @@@ static int commit_staged_changes(struc
                if (get_oid_hex(rev.buf, &to_amend))
                        return error(_("invalid contents: '%s'"),
                                rebase_path_amend());
-               if (!is_clean && oidcmp(&head, &to_amend))
+               if (!is_clean && !oideq(&head, &to_amend))
                        return error(_("\nYou have uncommitted changes in your "
                                       "working tree. Please, commit them\n"
                                       "first and then run 'git rebase "
                 * the commit message and if there was a squash, let the user
                 * edit it.
                 */
-               if (is_clean && !oidcmp(&head, &to_amend) &&
+               if (is_clean && oideq(&head, &to_amend) &&
                    opts->current_fixup_count > 0 &&
                    file_exists(rebase_path_stopped_sha())) {
                        const char *p = opts->current_fixups.buf;
@@@ -3832,7 -3799,7 +3832,7 @@@ int sequencer_pick_revisions(struct rep
        return res;
  }
  
 -void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag)
 +void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag)
  {
        unsigned no_dup_sob = flag & APPEND_SIGNOFF_DEDUP;
        struct strbuf sob = STRBUF_INIT;
@@@ -4578,7 -4545,7 +4578,7 @@@ int skip_unnecessary_picks(void
                if (item->commit->parents->next)
                        break; /* merge commit */
                parent_oid = &item->commit->parents->item->object.oid;
-               if (hashcmp(parent_oid->hash, oid->hash))
+               if (!oideq(parent_oid, oid))
                        break;
                oid = &item->commit->object.oid;
        }
diff --combined sha1-name.c
index fbcd2f78eb3fafc84748063d46e14f5153ffe4bc,a0c8451d55261f433483f8cdc7b5f254996926a1..faa60f69e311f5f09cd5b91a8fbbaf3e3e744ab0
@@@ -12,8 -12,6 +12,8 @@@
  #include "packfile.h"
  #include "object-store.h"
  #include "repository.h"
 +#include "midx.h"
 +#include "commit-reach.h"
  
  static int get_oid_oneline(const char *, struct object_id *, struct commit_list *);
  
@@@ -46,7 -44,7 +46,7 @@@ static void update_candidates(struct di
                oidcpy(&ds->candidate, current);
                ds->candidate_exists = 1;
                return;
-       } else if (!oidcmp(&ds->candidate, current)) {
+       } else if (oideq(&ds->candidate, current)) {
                /* the same as what we already have seen */
                return;
        }
@@@ -151,32 -149,6 +151,32 @@@ static int match_sha(unsigned len, cons
        return 1;
  }
  
 +static void unique_in_midx(struct multi_pack_index *m,
 +                         struct disambiguate_state *ds)
 +{
 +      uint32_t num, i, first = 0;
 +      const struct object_id *current = NULL;
 +      num = m->num_objects;
 +
 +      if (!num)
 +              return;
 +
 +      bsearch_midx(&ds->bin_pfx, m, &first);
 +
 +      /*
 +       * At this point, "first" is the location of the lowest object
 +       * with an object name that could match "bin_pfx".  See if we have
 +       * 0, 1 or more objects that actually match(es).
 +       */
 +      for (i = first; i < num && !ds->ambiguous; i++) {
 +              struct object_id oid;
 +              current = nth_midxed_object_oid(&oid, m, i);
 +              if (!match_sha(ds->len, ds->bin_pfx.hash, current->hash))
 +                      break;
 +              update_candidates(ds, current);
 +      }
 +}
 +
  static void unique_in_pack(struct packed_git *p,
                           struct disambiguate_state *ds)
  {
  
  static void find_short_packed_object(struct disambiguate_state *ds)
  {
 +      struct multi_pack_index *m;
        struct packed_git *p;
  
 +      for (m = get_multi_pack_index(the_repository); m && !ds->ambiguous;
 +           m = m->next)
 +              unique_in_midx(m, ds);
        for (p = get_packed_git(the_repository); p && !ds->ambiguous;
             p = p->next)
                unique_in_pack(p, ds);
@@@ -561,42 -529,6 +561,42 @@@ static int extend_abbrev_len(const stru
        return 0;
  }
  
 +static void find_abbrev_len_for_midx(struct multi_pack_index *m,
 +                                   struct min_abbrev_data *mad)
 +{
 +      int match = 0;
 +      uint32_t num, first = 0;
 +      struct object_id oid;
 +      const struct object_id *mad_oid;
 +
 +      if (!m->num_objects)
 +              return;
 +
 +      num = m->num_objects;
 +      mad_oid = mad->oid;
 +      match = bsearch_midx(mad_oid, m, &first);
 +
 +      /*
 +       * first is now the position in the packfile where we would insert
 +       * mad->hash if it does not exist (or the position of mad->hash if
 +       * it does exist). Hence, we consider a maximum of two objects
 +       * nearby for the abbreviation length.
 +       */
 +      mad->init_len = 0;
 +      if (!match) {
 +              if (nth_midxed_object_oid(&oid, m, first))
 +                      extend_abbrev_len(&oid, mad);
 +      } else if (first < num - 1) {
 +              if (nth_midxed_object_oid(&oid, m, first + 1))
 +                      extend_abbrev_len(&oid, mad);
 +      }
 +      if (first > 0) {
 +              if (nth_midxed_object_oid(&oid, m, first - 1))
 +                      extend_abbrev_len(&oid, mad);
 +      }
 +      mad->init_len = mad->cur_len;
 +}
 +
  static void find_abbrev_len_for_pack(struct packed_git *p,
                                     struct min_abbrev_data *mad)
  {
  
  static void find_abbrev_len_packed(struct min_abbrev_data *mad)
  {
 +      struct multi_pack_index *m;
        struct packed_git *p;
  
 +      for (m = get_multi_pack_index(the_repository); m; m = m->next)
 +              find_abbrev_len_for_midx(m, mad);
        for (p = get_packed_git(the_repository); p; p = p->next)
                find_abbrev_len_for_pack(p, mad);
  }
diff --combined submodule.c
index 058fc9f8855d7719cbc9bb17d646b63d99772c87,a2ce58e9e775f041add8b13f16be9bbd313108a7..ed05339b5889a3add4210a7ef7cfabe0322c54ef
@@@ -22,7 -22,6 +22,7 @@@
  #include "worktree.h"
  #include "parse-options.h"
  #include "object-store.h"
 +#include "commit-reach.h"
  
  static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
  static struct string_list changed_submodule_names = STRING_LIST_INIT_DUP;
@@@ -537,7 -536,7 +537,7 @@@ static void show_submodule_header(struc
                        fast_backward = 1;
        }
  
-       if (!oidcmp(one, two)) {
+       if (oideq(one, two)) {
                strbuf_release(&sb);
                return;
        }
@@@ -1535,6 -1534,18 +1535,6 @@@ out
        return ret;
  }
  
 -void submodule_unset_core_worktree(const struct submodule *sub)
 -{
 -      char *config_path = xstrfmt("%s/modules/%s/config",
 -                                  get_git_common_dir(), sub->name);
 -
 -      if (git_config_set_in_file_gently(config_path, "core.worktree", NULL))
 -              warning(_("Could not unset core.worktree setting in submodule '%s'"),
 -                        sub->path);
 -
 -      free(config_path);
 -}
 -
  static const char *get_super_prefix_or_empty(void)
  {
        const char *s = get_super_prefix();
@@@ -1700,6 -1711,8 +1700,6 @@@ int submodule_move_head(const char *pat
  
                        if (is_empty_dir(path))
                                rmdir_or_warn(path);
 -
 -                      submodule_unset_core_worktree(sub);
                }
        }
  out:
diff --combined unpack-trees.c
index 55f864ac577e5951db5345c358a0ec8bb8291919,4056a92d558a5af45e76cbfd1eb7ef8aebcc5933..65f157b9de5c75809980c1722ac67081dc2f92a1
@@@ -336,46 -336,6 +336,46 @@@ static struct progress *get_progress(st
        return start_delayed_progress(_("Checking out files"), total);
  }
  
 +static void setup_collided_checkout_detection(struct checkout *state,
 +                                            struct index_state *index)
 +{
 +      int i;
 +
 +      state->clone = 1;
 +      for (i = 0; i < index->cache_nr; i++)
 +              index->cache[i]->ce_flags &= ~CE_MATCHED;
 +}
 +
 +static void report_collided_checkout(struct index_state *index)
 +{
 +      struct string_list list = STRING_LIST_INIT_NODUP;
 +      int i;
 +
 +      for (i = 0; i < index->cache_nr; i++) {
 +              struct cache_entry *ce = index->cache[i];
 +
 +              if (!(ce->ce_flags & CE_MATCHED))
 +                      continue;
 +
 +              string_list_append(&list, ce->name);
 +              ce->ce_flags &= ~CE_MATCHED;
 +      }
 +
 +      list.cmp = fspathcmp;
 +      string_list_sort(&list);
 +
 +      if (list.nr) {
 +              warning(_("the following paths have collided (e.g. case-sensitive paths\n"
 +                        "on a case-insensitive filesystem) and only one from the same\n"
 +                        "colliding group is in the working tree:\n"));
 +
 +              for (i = 0; i < list.nr; i++)
 +                      fprintf(stderr, "  '%s'\n", list.items[i].string);
 +      }
 +
 +      string_list_clear(&list, 0);
 +}
 +
  static int check_updates(struct unpack_trees_options *o)
  {
        unsigned cnt = 0;
        struct checkout state = CHECKOUT_INIT;
        int i;
  
 +      trace_performance_enter();
        state.force = 1;
        state.quiet = 1;
        state.refresh_cache = 1;
        state.istate = index;
  
 +      if (o->clone)
 +              setup_collided_checkout_detection(&state, index);
 +
        progress = get_progress(o);
  
        if (o->update)
        errs |= finish_delayed_checkout(&state);
        if (o->update)
                git_attr_set_direction(GIT_ATTR_CHECKIN);
 +
 +      if (o->clone)
 +              report_collided_checkout(index);
 +
 +      trace_performance_leave("check_updates");
        return errs != 0;
  }
  
@@@ -679,116 -630,9 +679,116 @@@ static int switch_cache_bottom(struct t
  
  static inline int are_same_oid(struct name_entry *name_j, struct name_entry *name_k)
  {
-       return name_j->oid && name_k->oid && !oidcmp(name_j->oid, name_k->oid);
+       return name_j->oid && name_k->oid && oideq(name_j->oid, name_k->oid);
  }
  
 +static int all_trees_same_as_cache_tree(int n, unsigned long dirmask,
 +                                      struct name_entry *names,
 +                                      struct traverse_info *info)
 +{
 +      struct unpack_trees_options *o = info->data;
 +      int i;
 +
 +      if (!o->merge || dirmask != ((1 << n) - 1))
 +              return 0;
 +
 +      for (i = 1; i < n; i++)
 +              if (!are_same_oid(names, names + i))
 +                      return 0;
 +
 +      return cache_tree_matches_traversal(o->src_index->cache_tree, names, info);
 +}
 +
 +static int index_pos_by_traverse_info(struct name_entry *names,
 +                                    struct traverse_info *info)
 +{
 +      struct unpack_trees_options *o = info->data;
 +      int len = traverse_path_len(info, names);
 +      char *name = xmalloc(len + 1 /* slash */ + 1 /* NUL */);
 +      int pos;
 +
 +      make_traverse_path(name, info, names);
 +      name[len++] = '/';
 +      name[len] = '\0';
 +      pos = index_name_pos(o->src_index, name, len);
 +      if (pos >= 0)
 +              BUG("This is a directory and should not exist in index");
 +      pos = -pos - 1;
 +      if (!starts_with(o->src_index->cache[pos]->name, name) ||
 +          (pos > 0 && starts_with(o->src_index->cache[pos-1]->name, name)))
 +              BUG("pos must point at the first entry in this directory");
 +      free(name);
 +      return pos;
 +}
 +
 +/*
 + * Fast path if we detect that all trees are the same as cache-tree at this
 + * path. We'll walk these trees in an iterative loop using cache-tree/index
 + * instead of ODB since we already know what these trees contain.
 + */
 +static int traverse_by_cache_tree(int pos, int nr_entries, int nr_names,
 +                                struct name_entry *names,
 +                                struct traverse_info *info)
 +{
 +      struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, };
 +      struct unpack_trees_options *o = info->data;
 +      struct cache_entry *tree_ce = NULL;
 +      int ce_len = 0;
 +      int i, d;
 +
 +      if (!o->merge)
 +              BUG("We need cache-tree to do this optimization");
 +
 +      /*
 +       * Do what unpack_callback() and unpack_nondirectories() normally
 +       * do. But we walk all paths in an iterative loop instead.
 +       *
 +       * D/F conflicts and higher stage entries are not a concern
 +       * because cache-tree would be invalidated and we would never
 +       * get here in the first place.
 +       */
 +      for (i = 0; i < nr_entries; i++) {
 +              int new_ce_len, len, rc;
 +
 +              src[0] = o->src_index->cache[pos + i];
 +
 +              len = ce_namelen(src[0]);
 +              new_ce_len = cache_entry_size(len);
 +
 +              if (new_ce_len > ce_len) {
 +                      new_ce_len <<= 1;
 +                      tree_ce = xrealloc(tree_ce, new_ce_len);
 +                      memset(tree_ce, 0, new_ce_len);
 +                      ce_len = new_ce_len;
 +
 +                      tree_ce->ce_flags = create_ce_flags(0);
 +
 +                      for (d = 1; d <= nr_names; d++)
 +                              src[d] = tree_ce;
 +              }
 +
 +              tree_ce->ce_mode = src[0]->ce_mode;
 +              tree_ce->ce_namelen = len;
 +              oidcpy(&tree_ce->oid, &src[0]->oid);
 +              memcpy(tree_ce->name, src[0]->name, len + 1);
 +
 +              rc = call_unpack_fn((const struct cache_entry * const *)src, o);
 +              if (rc < 0) {
 +                      free(tree_ce);
 +                      return rc;
 +              }
 +
 +              mark_ce_used(src[0], o);
 +      }
 +      free(tree_ce);
 +      if (o->debug_unpack)
 +              printf("Unpacked %d entries from %s to %s using cache-tree\n",
 +                     nr_entries,
 +                     o->src_index->cache[pos]->name,
 +                     o->src_index->cache[pos + nr_entries - 1]->name);
 +      return 0;
 +}
 +
  static int traverse_trees_recursive(int n, unsigned long dirmask,
                                    unsigned long df_conflicts,
                                    struct name_entry *names,
        void *buf[MAX_UNPACK_TREES];
        struct traverse_info newinfo;
        struct name_entry *p;
 +      int nr_entries;
 +
 +      nr_entries = all_trees_same_as_cache_tree(n, dirmask, names, info);
 +      if (nr_entries > 0) {
 +              struct unpack_trees_options *o = info->data;
 +              int pos = index_pos_by_traverse_info(names, info);
 +
 +              if (!o->merge || df_conflicts)
 +                      BUG("Wrong condition to get here buddy");
 +
 +              /*
 +               * All entries up to 'pos' must have been processed
 +               * (i.e. marked CE_UNPACKED) at this point. But to be safe,
 +               * save and restore cache_bottom anyway to not miss
 +               * unprocessed entries before 'pos'.
 +               */
 +              bottom = o->cache_bottom;
 +              ret = traverse_by_cache_tree(pos, nr_entries, n, names, info);
 +              o->cache_bottom = bottom;
 +              return ret;
 +      }
  
        p = names;
        while (!p->mode)
@@@ -987,11 -810,6 +987,11 @@@ static struct cache_entry *create_ce_en
        return ce;
  }
  
 +/*
 + * Note that traverse_by_cache_tree() duplicates some logic in this function
 + * without actually calling it. If you change the logic here you may need to
 + * check and change there as well.
 + */
  static int unpack_nondirectories(int n, unsigned long mask,
                                 unsigned long dirmask,
                                 struct cache_entry **src,
@@@ -1184,11 -1002,6 +1184,11 @@@ static void debug_unpack_callback(int n
                debug_name_entry(i, names + i);
  }
  
 +/*
 + * Note that traverse_by_cache_tree() duplicates some logic in this function
 + * without actually calling it. If you change the logic here you may need to
 + * check and change there as well.
 + */
  static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, struct name_entry *names, struct traverse_info *info)
  {
        struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, };
@@@ -1476,7 -1289,6 +1476,7 @@@ int unpack_trees(unsigned len, struct t
        if (len > MAX_UNPACK_TREES)
                die("unpack_trees takes at most %d trees", MAX_UNPACK_TREES);
  
 +      trace_performance_enter();
        memset(&el, 0, sizeof(el));
        if (!core_apply_sparse_checkout || !o->update)
                o->skip_sparse_checkout = 1;
                        }
                }
  
 -              if (traverse_trees(len, t, &info) < 0)
 +              trace_performance_enter();
 +              ret = traverse_trees(len, t, &info);
 +              trace_performance_leave("traverse_trees");
 +              if (ret < 0)
                        goto return_failed;
        }
  
  
        ret = check_updates(o) ? (-2) : 0;
        if (o->dst_index) {
 +              move_index_extensions(&o->result, o->src_index);
                if (!ret) {
 +                      if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
 +                              cache_tree_verify(&o->result);
                        if (!o->result.cache_tree)
                                o->result.cache_tree = cache_tree();
                        if (!cache_tree_fully_valid(o->result.cache_tree))
                                                  WRITE_TREE_SILENT |
                                                  WRITE_TREE_REPAIR);
                }
 -              move_index_extensions(&o->result, o->src_index);
                discard_index(o->dst_index);
                *o->dst_index = o->result;
        } else {
        o->src_index = NULL;
  
  done:
 +      trace_performance_leave("unpack_trees");
        clear_exclude_list(&el);
        return ret;
  
@@@ -1678,7 -1484,7 +1678,7 @@@ static int same(const struct cache_entr
        if ((a->ce_flags | b->ce_flags) & CE_CONFLICTED)
                return 0;
        return a->ce_mode == b->ce_mode &&
-              !oidcmp(&a->oid, &b->oid);
+              oideq(&a->oid, &b->oid);
  }
  
  
@@@ -1810,7 -1616,7 +1810,7 @@@ static int verify_clean_subdirectory(co
                 * If we are not going to update the submodule, then
                 * we don't care.
                 */
-               if (!sub_head && !oidcmp(&oid, &ce->oid))
+               if (!sub_head && oideq(&oid, &ce->oid))
                        return 0;
                return verify_clean_submodule(sub_head ? NULL : oid_to_hex(&oid),
                                              ce, error_type, o);
                        if (verify_uptodate(ce2, o))
                                return -1;
                        add_entry(o, ce2, CE_REMOVE, 0);
 +                      invalidate_ce_path(ce, o);
                        mark_ce_used(ce2, o);
                }
                cnt++;
@@@ -2098,8 -1903,6 +2098,8 @@@ static int keep_entry(const struct cach
                      struct unpack_trees_options *o)
  {
        add_entry(o, ce, 0, 0);
 +      if (ce_stage(ce))
 +              invalidate_ce_path(ce, o);
        return 1;
  }