Merge branch 'nd/the-index'
authorJunio C Hamano <gitster@pobox.com>
Fri, 19 Oct 2018 04:34:02 +0000 (13:34 +0900)
committerJunio C Hamano <gitster@pobox.com>
Fri, 19 Oct 2018 04:34:02 +0000 (13:34 +0900)
Various codepaths in the core-ish part learn to work on an
arbitrary in-core index structure, not necessarily the default
instance "the_index".

* nd/the-index: (23 commits)
revision.c: reduce implicit dependency the_repository
revision.c: remove implicit dependency on the_index
ws.c: remove implicit dependency on the_index
tree-diff.c: remove implicit dependency on the_index
submodule.c: remove implicit dependency on the_index
line-range.c: remove implicit dependency on the_index
userdiff.c: remove implicit dependency on the_index
rerere.c: remove implicit dependency on the_index
sha1-file.c: remove implicit dependency on the_index
patch-ids.c: remove implicit dependency on the_index
merge.c: remove implicit dependency on the_index
merge-blobs.c: remove implicit dependency on the_index
ll-merge.c: remove implicit dependency on the_index
diff-lib.c: remove implicit dependency on the_index
read-cache.c: remove implicit dependency on the_index
diff.c: remove implicit dependency on the_index
grep.c: remove implicit dependency on the_index
diff.c: remove the_index dependency in textconv() functions
blame.c: rename "repo" argument to "r"
combine-diff.c: remove implicit dependency on the_index
...

52 files changed:
1  2 
archive.c
bisect.c
blame.c
builtin/add.c
builtin/am.c
builtin/checkout.c
builtin/commit.c
builtin/describe.c
builtin/diff.c
builtin/difftool.c
builtin/fast-export.c
builtin/fmt-merge-msg.c
builtin/log.c
builtin/merge-tree.c
builtin/merge.c
builtin/pack-objects.c
builtin/pull.c
builtin/range-diff.c
builtin/replace.c
builtin/rerere.c
builtin/rev-list.c
builtin/submodule--helper.c
builtin/update-index.c
bundle.c
cache.h
combine-diff.c
diff-lib.c
diff.c
diff.h
diffcore-break.c
diffcore-rename.c
http-push.c
ll-merge.c
merge-recursive.c
notes-merge.c
pack-bitmap-write.c
patch-ids.c
read-cache.c
ref-filter.c
remote.c
rerere.c
revision.c
revision.h
sequencer.c
sha1-file.c
shallow.c
submodule.c
transport.c
tree-diff.c
userdiff.c
ws.c
wt-status.c
diff --combined archive.c
index c1870105eb453980ce421f937e9615d1d9dcd3b3,994495af05bf89ad7f476d85cb43419f826955ca..9d16b7fadfc8d30b8a96dd0c908f02783adb791f
+++ b/archive.c
@@@ -110,8 -110,7 +110,8 @@@ static const struct attr_check *get_arc
        static struct attr_check *check;
        if (!check)
                check = attr_check_initl("export-ignore", "export-subst", NULL);
 -      return git_check_attr(istate, path, check) ? NULL : check;
 +      git_check_attr(istate, path, check);
 +      return check;
  }
  
  static int check_attr_export_ignore(const struct attr_check *check)
@@@ -392,7 -391,7 +392,7 @@@ static void parse_treeish_arg(const cha
        if (get_oid(name, &oid))
                die("Not a valid object name");
  
-       commit = lookup_commit_reference_gently(the_repository, &oid, 1);
+       commit = lookup_commit_reference_gently(ar_args->repo, &oid, 1);
        if (commit) {
                commit_sha1 = commit->object.oid.hash;
                archive_time = commit->date;
diff --combined bisect.c
index e8b17cf7e1d8d2bf7895e2fa33d0cf0cbc47ae63,6ae5e5b49eccd0420696e73a21420e9709bd276e..487675c67249a3164294aae71c1c2a650f3c4947
+++ b/bisect.c
@@@ -13,8 -13,6 +13,8 @@@
  #include "sha1-array.h"
  #include "argv-array.h"
  #include "commit-slab.h"
 +#include "commit-reach.h"
 +#include "object-store.h"
  
  static struct oid_array good_revs;
  static struct oid_array skipped_revs;
@@@ -122,14 -120,14 +122,14 @@@ static inline int halfway(struct commit
        }
  }
  
 -#if !DEBUG_BISECT
 -#define show_list(a,b,c,d) do { ; } while (0)
 -#else
  static void show_list(const char *debug, int counted, int nr,
                      struct commit_list *list)
  {
        struct commit_list *p;
  
 +      if (!DEBUG_BISECT)
 +              return;
 +
        fprintf(stderr, "%s (%d/%d)\n", debug, counted, nr);
  
        for (p = list; p; p = p->next) {
                        (flags & TREESAME) ? ' ' : 'T',
                        (flags & UNINTERESTING) ? 'U' : ' ',
                        (flags & COUNTED) ? 'C' : ' ');
 -              if (commit->util)
 +              if (*commit_weight_at(&commit_weight, p->item))
                        fprintf(stderr, "%3d", weight(p));
                else
                        fprintf(stderr, "---");
                fprintf(stderr, "\n");
        }
  }
 -#endif /* DEBUG_BISECT */
  
  static struct commit_list *best_bisection(struct commit_list *list, int nr)
  {
@@@ -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;
@@@ -633,7 -632,7 +633,7 @@@ static void bisect_rev_setup(struct rev
        struct argv_array rev_argv = ARGV_ARRAY_INIT;
        int i;
  
-       init_revisions(revs, prefix);
+       repo_init_revisions(the_repository, revs, prefix);
        revs->abbrev = 0;
        revs->commit_format = CMIT_FMT_UNSPECIFIED;
  
@@@ -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;
@@@ -890,7 -889,7 +890,7 @@@ static void show_diff_tree(const char *
        struct rev_info opt;
  
        /* diff-tree init */
-       init_revisions(&opt, prefix);
+       repo_init_revisions(the_repository, &opt, prefix);
        git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
        opt.abbrev = 0;
        opt.diff = 1;
@@@ -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 blame.c
index d5f7b7237c4e9f9dcb6ad37504a98a0fcff66f80,c229a10c0e3c9e809286ee8af8694dc135c340f2..d84c937780801f51b8eb98b7e367c8017701ba5c
+++ b/blame.c
@@@ -90,7 -90,7 +90,7 @@@ static struct blame_origin *get_origin(
  
  
  
- static void verify_working_tree_path(struct repository *repo,
+ static void verify_working_tree_path(struct repository *r,
                                     struct commit *work_tree, const char *path)
  {
        struct commit_list *parents;
                unsigned mode;
  
                if (!get_tree_entry(commit_oid, path, &blob_oid, &mode) &&
-                   oid_object_info(repo, &blob_oid, NULL) == OBJ_BLOB)
+                   oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
                        return;
        }
  
-       pos = index_name_pos(repo->index, path, strlen(path));
+       pos = index_name_pos(r->index, path, strlen(path));
        if (pos >= 0)
                ; /* path is in the index */
-       else if (-1 - pos < repo->index->cache_nr &&
-                !strcmp(repo->index->cache[-1 - pos]->name, path))
+       else if (-1 - pos < r->index->cache_nr &&
+                !strcmp(r->index->cache[-1 - pos]->name, path))
                ; /* path is in the index, unmerged */
        else
                die("no such path '%s' in HEAD", path);
@@@ -166,7 -166,7 +166,7 @@@ static void set_commit_buffer_from_strb
   * Prepare a dummy commit that represents the work tree (or staged) item.
   * Note that annotating work tree item never works in the reverse.
   */
- static struct commit *fake_working_tree_commit(struct repository *repo,
+ static struct commit *fake_working_tree_commit(struct repository *r,
                                               struct diff_options *opt,
                                               const char *path,
                                               const char *contents_from)
        unsigned mode;
        struct strbuf msg = STRBUF_INIT;
  
-       read_index(repo->index);
+       read_index(r->index);
        time(&now);
        commit = alloc_commit_node(the_repository);
        commit->object.parsed = 1;
  
        parent_tail = append_parent(parent_tail, &head_oid);
        append_merge_parents(parent_tail);
-       verify_working_tree_path(repo, commit, path);
+       verify_working_tree_path(r, commit, path);
  
        origin = make_origin(commit, path);
  
                switch (st.st_mode & S_IFMT) {
                case S_IFREG:
                        if (opt->flags.allow_textconv &&
-                           textconv_object(read_from, mode, &null_oid, 0, &buf_ptr, &buf_len))
+                           textconv_object(r, read_from, mode, &null_oid, 0, &buf_ptr, &buf_len))
                                strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
                        else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
                                die_errno("cannot open or read '%s'", read_from);
                if (strbuf_read(&buf, 0, 0) < 0)
                        die_errno("failed to read from stdin");
        }
-       convert_to_git(repo->index, path, buf.buf, buf.len, &buf, 0);
+       convert_to_git(r->index, path, buf.buf, buf.len, &buf, 0);
        origin->file.ptr = buf.buf;
        origin->file.size = buf.len;
        pretend_object_file(buf.buf, buf.len, OBJ_BLOB, &origin->blob_oid);
         * bits; we are not going to write this index out -- we just
         * want to run "diff-index --cached".
         */
-       discard_index(repo->index);
-       read_index(repo->index);
+       discard_index(r->index);
+       read_index(r->index);
  
        len = strlen(path);
        if (!mode) {
-               int pos = index_name_pos(repo->index, path, len);
+               int pos = index_name_pos(r->index, path, len);
                if (0 <= pos)
-                       mode = repo->index->cache[pos]->ce_mode;
+                       mode = r->index->cache[pos]->ce_mode;
                else
                        /* Let's not bother reading from HEAD tree */
                        mode = S_IFREG | 0644;
        }
-       ce = make_empty_cache_entry(repo->index, len);
+       ce = make_empty_cache_entry(r->index, len);
        oidcpy(&ce->oid, &origin->blob_oid);
        memcpy(ce->name, path, len);
        ce->ce_flags = create_ce_flags(0);
        ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
-       add_index_entry(repo->index, ce,
+       add_index_entry(r->index, ce,
                        ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
  
-       cache_tree_invalidate_path(repo->index, path);
+       cache_tree_invalidate_path(r->index, path);
  
        return commit;
  }
@@@ -318,7 -318,8 +318,8 @@@ static void fill_origin_blob(struct dif
  
                (*num_read_blob)++;
                if (opt->flags.allow_textconv &&
-                   textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size))
+                   textconv_object(opt->repo, o->path, o->mode,
+                                   &o->blob_oid, 1, &file->ptr, &file_size))
                        ;
                else
                        file->ptr = read_object_file(&o->blob_oid, &type,
@@@ -520,14 -521,14 +521,14 @@@ static void queue_blames(struct blame_s
   *
   * This also fills origin->mode for corresponding tree path.
   */
- static int fill_blob_sha1_and_mode(struct repository *repo,
+ static int fill_blob_sha1_and_mode(struct repository *r,
                                   struct blame_origin *origin)
  {
        if (!is_null_oid(&origin->blob_oid))
                return 0;
        if (get_tree_entry(&origin->commit->object.oid, origin->path, &origin->blob_oid, &origin->mode))
                goto error_out;
-       if (oid_object_info(repo, &origin->blob_oid, NULL) != OBJ_BLOB)
+       if (oid_object_info(r, &origin->blob_oid, NULL) != OBJ_BLOB)
                goto error_out;
        return 0;
   error_out:
   * We have an origin -- check if the same path exists in the
   * parent and return an origin structure to represent it.
   */
- static struct blame_origin *find_origin(struct commit *parent,
-                                 struct blame_origin *origin)
+ static struct blame_origin *find_origin(struct repository *r,
+                                       struct commit *parent,
+                                       struct blame_origin *origin)
  {
        struct blame_origin *porigin;
        struct diff_options diff_opts;
         * and origin first.  Most of the time they are the
         * same and diff-tree is fairly efficient about this.
         */
-       diff_setup(&diff_opts);
+       repo_diff_setup(r, &diff_opts);
        diff_opts.flags.recursive = 1;
        diff_opts.detect_rename = 0;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
   * We have an origin -- find the path that corresponds to it in its
   * parent and return an origin structure to represent it.
   */
- static struct blame_origin *find_rename(struct commit *parent,
-                                 struct blame_origin *origin)
+ static struct blame_origin *find_rename(struct repository *r,
+                                       struct commit *parent,
+                                       struct blame_origin *origin)
  {
        struct blame_origin *porigin = NULL;
        struct diff_options diff_opts;
        int i;
  
-       diff_setup(&diff_opts);
+       repo_diff_setup(r, &diff_opts);
        diff_opts.flags.recursive = 1;
        diff_opts.detect_rename = DIFF_DETECT_RENAME;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
@@@ -1259,7 -1262,7 +1262,7 @@@ static void find_copy_in_parent(struct 
        if (!unblamed)
                return; /* nothing remains for this target */
  
-       diff_setup(&diff_opts);
+       repo_diff_setup(sb->repo, &diff_opts);
        diff_opts.flags.recursive = 1;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
  
@@@ -1441,7 -1444,7 +1444,7 @@@ static void pass_blame(struct blame_sco
         * common cases, then we look for renames in the second pass.
         */
        for (pass = 0; pass < 2 - sb->no_whole_file_rename; pass++) {
-               struct blame_origin *(*find)(struct commit *, struct blame_origin *);
+               struct blame_origin *(*find)(struct repository *, struct commit *, struct blame_origin *);
                find = pass ? find_rename : find_origin;
  
                for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
                                continue;
                        if (parse_commit(p))
                                continue;
-                       porigin = find(p, origin);
+                       porigin = find(sb->repo, p, origin);
                        if (!porigin)
                                continue;
 -                      if (!oidcmp(&porigin->blob_oid, &origin->blob_oid)) {
 +                      if (oideq(&porigin->blob_oid, &origin->blob_oid)) {
                                pass_whole_blame(sb, origin, porigin);
                                blame_origin_decref(porigin);
                                goto finish;
                        }
                        for (j = same = 0; j < i; j++)
                                if (sg_origin[j] &&
 -                                  !oidcmp(&sg_origin[j]->blob_oid, &porigin->blob_oid)) {
 +                                  oideq(&sg_origin[j]->blob_oid, &porigin->blob_oid)) {
                                        same = 1;
                                        break;
                                }
@@@ -1832,7 -1835,7 +1835,7 @@@ void setup_scoreboard(struct blame_scor
  
                sb->revs->children.name = "children";
                while (c->parents &&
 -                     oidcmp(&c->object.oid, &sb->final->object.oid)) {
 +                     !oideq(&c->object.oid, &sb->final->object.oid)) {
                        struct commit_list *l = xcalloc(1, sizeof(*l));
  
                        l->item = c;
                        c = c->parents->item;
                }
  
 -              if (oidcmp(&c->object.oid, &sb->final->object.oid))
 +              if (!oideq(&c->object.oid, &sb->final->object.oid))
                        die(_("--reverse --first-parent together require range along first-parent chain"));
        }
  
                        die(_("no such path %s in %s"), path, final_commit_name);
  
                if (sb->revs->diffopt.flags.allow_textconv &&
-                   textconv_object(path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf,
+                   textconv_object(sb->repo, path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf,
                                    &sb->final_buf_size))
                        ;
                else
diff --combined builtin/add.c
index 0b64bcdebe0f4581953adccf8addf1c3fd1eb61e,f94b614c1c333a8fc35161cb2cb27b9e7384a4fc..ad49806ebf92208e25a69ac9bff3f0e0a3b96570
@@@ -110,7 -110,7 +110,7 @@@ int add_files_to_cache(const char *pref
        memset(&data, 0, sizeof(data));
        data.flags = flags;
  
-       init_revisions(&rev, prefix);
+       repo_init_revisions(the_repository, &rev, prefix);
        setup_revisions(0, NULL, &rev, NULL);
        if (pathspec)
                copy_pathspec(&rev.prune_data, pathspec);
@@@ -232,7 -232,7 +232,7 @@@ static int edit_patch(int argc, const c
        if (read_cache() < 0)
                die(_("Could not read the index"));
  
-       init_revisions(&rev, prefix);
+       repo_init_revisions(the_repository, &rev, prefix);
        rev.diffopt.context = 7;
  
        argc = setup_revisions(argc, argv, &rev, NULL);
@@@ -454,7 -454,7 +454,7 @@@ int cmd_add(int argc, const char **argv
         * Check the "pathspec '%s' did not match any files" block
         * below before enabling new magic.
         */
 -      parse_pathspec(&pathspec, 0,
 +      parse_pathspec(&pathspec, PATHSPEC_ATTR,
                       PATHSPEC_PREFER_FULL |
                       PATHSPEC_SYMLINK_LEADING_PATH,
                       prefix, argv);
diff --combined builtin/am.c
index 5e643e2a3e3d70d9c674d3edab2eb1f2f08f3392,601570dbef383fd5a614f65eecf31eeab447fbc5..d79f092a96f8e9aab59c6d6c623c8fd7fbcb677d
@@@ -1244,10 -1244,6 +1244,10 @@@ static int parse_mail(struct am_state *
        fclose(mi.input);
        fclose(mi.output);
  
 +      if (mi.format_flowed)
 +              warning(_("Patch sent with format=flowed; "
 +                        "space at the end of lines might be lost."));
 +
        /* Extract message and author information */
        fp = xfopen(am_path(state, "info"), "r");
        while (!strbuf_getline_lf(&sb, fp)) {
@@@ -1376,7 -1372,7 +1376,7 @@@ static void write_commit_patch(const st
        FILE *fp;
  
        fp = xfopen(am_path(state, "patch"), "w");
-       init_revisions(&rev_info, NULL);
+       repo_init_revisions(the_repository, &rev_info, NULL);
        rev_info.diff = 1;
        rev_info.abbrev = 0;
        rev_info.disable_stdin = 1;
@@@ -1411,7 -1407,7 +1411,7 @@@ static void write_index_patch(const str
                                   the_repository->hash_algo->empty_tree);
  
        fp = xfopen(am_path(state, "patch"), "w");
-       init_revisions(&rev_info, NULL);
+       repo_init_revisions(the_repository, &rev_info, NULL);
        rev_info.diff = 1;
        rev_info.disable_stdin = 1;
        rev_info.no_commit_id = 1;
@@@ -1569,7 -1565,7 +1569,7 @@@ static int fall_back_threeway(const str
                struct rev_info rev_info;
                const char *diff_filter_str = "--diff-filter=AM";
  
-               init_revisions(&rev_info, NULL);
+               repo_init_revisions(the_repository, &rev_info, NULL);
                rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS;
                diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1, rev_info.prefix);
                add_pending_oid(&rev_info, "HEAD", &our_tree, 0);
                o.verbosity = 0;
  
        if (merge_recursive_generic(&o, &our_tree, &their_tree, 1, bases, &result)) {
-               rerere(state->allow_rerere_autoupdate);
+               repo_rerere(the_repository, state->allow_rerere_autoupdate);
                free(their_tree_name);
                return error(_("Failed to merge in the changes."));
        }
@@@ -1903,7 -1899,7 +1903,7 @@@ static void am_resolve(struct am_state 
                        goto next;
        }
  
-       rerere(0);
+       repo_rerere(the_repository, 0);
  
        do_commit(state);
  
@@@ -2082,7 -2078,7 +2082,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 902c06702c62258384692f94ed6b55ecf6381a4e,ae28478ff89cb5d3ec5e9f7a5772273b3fcd32e1..acdafc6e4c4d104aadcbe7492a8045e16e83ba50
@@@ -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;
@@@ -214,7 -208,8 +214,8 @@@ static int checkout_merged(int pos, con
         * merge.renormalize set, too
         */
        status = ll_merge(&result_buf, path, &ancestor, "base",
-                         &ours, "ours", &theirs, "theirs", NULL);
+                         &ours, "ours", &theirs, "theirs",
+                         state->istate, NULL);
        free(ancestor.ptr);
        free(ours.ptr);
        free(theirs.ptr);
@@@ -397,7 -392,7 +398,7 @@@ static void show_local_changes(struct o
  {
        struct rev_info rev;
        /* I think we want full paths, even if we're in a subdirectory. */
-       init_revisions(&rev, NULL);
+       repo_init_revisions(the_repository, &rev, NULL);
        rev.diffopt.flags = opts->flags;
        rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
        diff_setup_done(&rev.diffopt);
@@@ -478,99 -473,6 +479,99 @@@ 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 ||
 +              !oideq(&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,
@@@ -899,7 -801,7 +900,7 @@@ static void orphaned_commit_warning(str
        struct rev_info revs;
        struct object *object = &old_commit->object;
  
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
        setup_revisions(0, NULL, &revs, NULL);
  
        object->flags &= ~UNINTERESTING;
@@@ -945,19 -847,10 +946,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/commit.c
index 1d5292e4d827312d3a08ceb44f6a120cbd0c4576,9d8ce6cb3baf8ab20fc1220758e815987db6c609..79d557fb2bb84a0174d40fe73e9137f5089c018a
@@@ -33,8 -33,6 +33,8 @@@
  #include "sequencer.h"
  #include "mailmap.h"
  #include "help.h"
 +#include "commit-reach.h"
 +#include "commit-graph.h"
  
  static const char * const builtin_commit_usage[] = {
        N_("git commit [<options>] [--] <pathspec>..."),
@@@ -874,7 -872,6 +874,7 @@@ static int prepare_to_commit(const cha
                s->use_color = 0;
                commitable = run_status(s->fp, index_file, prefix, 1, s);
                s->use_color = saved_color_setting;
 +              string_list_clear(&s->change, 1);
        } else {
                struct object_id oid;
                const char *parent = "HEAD";
@@@ -983,7 -980,7 +983,7 @@@ static const char *find_author_by_nickn
        const char *av[20];
        int ac = 0;
  
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
        strbuf_addf(&buf, "--author=%s", name);
        av[++ac] = "--all";
        av[++ac] = "-i";
@@@ -1654,10 -1651,7 +1654,10 @@@ int cmd_commit(int argc, const char **a
                      "new_index file. Check that disk is not full and quota is\n"
                      "not exceeded, and then \"git reset HEAD\" to recover."));
  
-       rerere(0);
 +      if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0))
 +              write_commit_graph_reachable(get_object_directory(), 0, 0);
 +
+       repo_rerere(the_repository, 0);
        run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
        run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
        if (amend && !no_post_rewrite) {
diff --combined builtin/describe.c
index 22c0541da552c8135e21a6f3c9d3f7829fc0d31a,1fde0563fe1056550450a6557b36ae683c6d0f1f..c48c34e8667c36a42101fffe51bd96f1a4d36842
@@@ -62,7 -62,7 +62,7 @@@ static const char *prio_names[] = 
        N_("head"), N_("lightweight"), N_("annotated"),
  };
  
 -static int commit_name_cmp(const void *unused_cmp_data,
 +static int commit_name_neq(const void *unused_cmp_data,
                           const void *entry,
                           const void *entry_or_key,
                           const void *peeled)
@@@ -70,7 -70,7 +70,7 @@@
        const struct commit_name *cn1 = entry;
        const struct commit_name *cn2 = entry_or_key;
  
 -      return oidcmp(&cn1->peeled, peeled ? peeled : &cn2->peeled);
 +      return !oideq(&cn1->peeled, peeled ? peeled : &cn2->peeled);
  }
  
  static inline struct commit_name *find_commit_name(const struct object_id *peeled)
@@@ -190,7 -190,7 +190,7 @@@ static int get_name(const char *path, c
  
        /* Is it annotated? */
        if (!peel_ref(path, &peeled)) {
 -              is_annotated = !!oidcmp(oid, &peeled);
 +              is_annotated = !oideq(oid, &peeled);
        } else {
                oidcpy(&peeled, oid);
                is_annotated = 0;
@@@ -469,7 -469,7 +469,7 @@@ static void process_object(struct objec
  {
        struct process_commit_data *pcd = data;
  
 -      if (!oidcmp(&pcd->looking_for, &obj->oid) && !pcd->dst->len) {
 +      if (oideq(&pcd->looking_for, &obj->oid) && !pcd->dst->len) {
                reset_revision_walk();
                describe_commit(&pcd->current_commit, pcd->dst);
                strbuf_addf(pcd->dst, ":%s", path);
@@@ -488,7 -488,7 +488,7 @@@ static void describe_blob(struct object
                "--objects", "--in-commit-order", "--reverse", "HEAD",
                NULL);
  
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
        if (setup_revisions(args.argc, args.argv, &revs, NULL) > 1)
                BUG("setup_revisions could not handle all args?");
  
@@@ -596,7 -596,7 +596,7 @@@ int cmd_describe(int argc, const char *
                return cmd_name_rev(args.argc, args.argv, prefix);
        }
  
 -      hashmap_init(&names, commit_name_cmp, NULL, 0);
 +      hashmap_init(&names, commit_name_neq, NULL, 0);
        for_each_rawref(get_name, NULL);
        if (!hashmap_get_size(&names) && !always)
                die(_("No names found, cannot describe anything."));
                        if (0 <= fd)
                                update_index_if_able(&the_index, &index_lock);
  
-                       init_revisions(&revs, prefix);
+                       repo_init_revisions(the_repository, &revs, prefix);
                        argv_array_pushv(&args, diff_index_args);
                        if (setup_revisions(args.argc, args.argv, &revs, NULL) != 1)
                                BUG("malformed internal diff-index command line");
diff --combined builtin/diff.c
index b3a8ba488ff824e2feda6b24df362f662fe5ddde,43bb71c1e0a124fdc7d90e053ce2b391c62d01b2..f0393bba23a7d95c67470508a6b63e4e41e8d46b
@@@ -41,7 -41,7 +41,7 @@@ static void stuff_change(struct diff_op
        struct diff_filespec *one, *two;
  
        if (!is_null_oid(old_oid) && !is_null_oid(new_oid) &&
 -          !oidcmp(old_oid, new_oid) && (old_mode == new_mode))
 +          oideq(old_oid, new_oid) && (old_mode == new_mode))
                return;
  
        if (opt->flags.reverse_diff) {
@@@ -318,7 -318,7 +318,7 @@@ int cmd_diff(int argc, const char **arg
        git_config(git_diff_ui_config, NULL);
        precompose_argv(argc, argv);
  
-       init_revisions(&rev, prefix);
+       repo_init_revisions(the_repository, &rev, prefix);
  
        if (no_index && argc != i + 2) {
                if (no_index == DIFF_NO_INDEX_IMPLICIT) {
        }
        if (no_index)
                /* If this is a no-index diff, just run it and exit there. */
-               diff_no_index(&rev, argc, argv);
+               diff_no_index(the_repository, &rev, argc, argv);
  
        /* Otherwise, we are doing the usual "git" diff */
        rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
diff --combined builtin/difftool.c
index b41a9199ff441579655c91fc692211257e4e91ed,e7023e3adff0b3f7ab24b055e9234aeaecb6111f..544b0e86397cb98ddfdad3cffdd983905ee36029
@@@ -112,11 -112,11 +112,11 @@@ static int use_wt_file(const char *work
                int fd = open(buf.buf, O_RDONLY);
  
                if (fd >= 0 &&
-                   !index_fd(&wt_oid, fd, &st, OBJ_BLOB, name, 0)) {
+                   !index_fd(&the_index, &wt_oid, fd, &st, OBJ_BLOB, name, 0)) {
                        if (is_null_oid(oid)) {
                                oidcpy(oid, &wt_oid);
                                use = 1;
 -                      } else if (!oidcmp(oid, &wt_oid))
 +                      } else if (oideq(oid, &wt_oid))
                                use = 1;
                }
        }
@@@ -438,7 -438,7 +438,7 @@@ static int run_dir_diff(const char *ext
                        strbuf_reset(&buf);
                        strbuf_addf(&buf, "Subproject commit %s",
                                    oid_to_hex(&roid));
 -                      if (!oidcmp(&loid, &roid))
 +                      if (oideq(&loid, &roid))
                                strbuf_addstr(&buf, "-dirty");
                        add_left_or_right(&submodules, dst_path, buf.buf, 1);
                        continue;
diff --combined builtin/fast-export.c
index 74f3bf5c96974a5f76c8b50c26915b582e780bb7,9bd4a95a4773474be1ac649623ef5a73028d7b78..456797c12a41a468a0b6dd25153403f6cfd7bb2f
@@@ -384,7 -384,7 +384,7 @@@ static void show_filemodify(struct diff
                                string_list_insert(changed, spec->path);
                                putchar('\n');
  
 -                              if (!oidcmp(&ospec->oid, &spec->oid) &&
 +                              if (oideq(&ospec->oid, &spec->oid) &&
                                    ospec->mode == spec->mode)
                                        break;
                        }
@@@ -1033,7 -1033,7 +1033,7 @@@ int cmd_fast_export(int argc, const cha
        /* we handle encodings */
        git_config(git_default_config, NULL);
  
-       init_revisions(&revs, prefix);
+       repo_init_revisions(the_repository, &revs, prefix);
        init_revision_sources(&revision_sources);
        revs.topo_order = 1;
        revs.sources = &revision_sources;
diff --combined builtin/fmt-merge-msg.c
index 59a40342b675130de6a2ddd76451bff8818e9623,1adc84ed8744c9c15a8fc1850a29433746c96788..a4615587fd7929e8fb49e65dbda30a40b8599cfd
@@@ -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;
        }
  
@@@ -643,7 -642,7 +643,7 @@@ int fmt_merge_msg(struct strbuf *in, st
                struct rev_info rev;
  
                head = lookup_commit_or_die(&head_oid, "HEAD");
-               init_revisions(&rev, NULL);
+               repo_init_revisions(the_repository, &rev, NULL);
                rev.commit_format = CMIT_FMT_ONELINE;
                rev.ignore_merges = 1;
                rev.limited = 1;
diff --combined builtin/log.c
index 1dbb9d829bffcb25739737783c4fd4fd734f5940,717d20e11512f06614145380fb88ba17305083e0..061d4fd864f3fb479e2877e3bbf25928ad1fb9d3
@@@ -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
  
@@@ -118,7 -115,7 +118,7 @@@ static int log_line_range_callback(cons
  
  static void init_log_defaults(void)
  {
-       init_grep_defaults();
+       init_grep_defaults(the_repository);
        init_diff_ui_defaults();
  
        decoration_style = auto_decoration_style();
@@@ -470,7 -467,7 +470,7 @@@ int cmd_whatchanged(int argc, const cha
        init_log_defaults();
        git_config(git_log_config, NULL);
  
-       init_revisions(&rev, prefix);
+       repo_init_revisions(the_repository, &rev, prefix);
        rev.diff = 1;
        rev.simplify_history = 0;
        memset(&opt, 0, sizeof(opt));
@@@ -510,7 -507,8 +510,8 @@@ static int show_blob_object(const struc
                                 &oidc, &obj_context))
                die(_("Not a valid object name %s"), obj_name);
        if (!obj_context.path ||
-           !textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) {
+           !textconv_object(the_repository, obj_context.path,
+                            obj_context.mode, &oidc, 1, &buf, &size)) {
                free(obj_context.path);
                return stream_blob_to_fd(1, oid, NULL, 0);
        }
@@@ -587,7 -585,7 +588,7 @@@ int cmd_show(int argc, const char **arg
        git_config(git_log_config, NULL);
  
        memset(&match_all, 0, sizeof(match_all));
-       init_revisions(&rev, prefix);
+       repo_init_revisions(the_repository, &rev, prefix);
        rev.diff = 1;
        rev.always_show_header = 1;
        rev.no_walk = REVISION_WALK_NO_WALK_SORTED;
@@@ -667,7 -665,7 +668,7 @@@ int cmd_log_reflog(int argc, const cha
        init_log_defaults();
        git_config(git_log_config, NULL);
  
-       init_revisions(&rev, prefix);
+       repo_init_revisions(the_repository, &rev, prefix);
        init_reflog_walk(&rev.reflog_info);
        rev.verbose_header = 1;
        memset(&opt, 0, sizeof(opt));
@@@ -706,7 -704,7 +707,7 @@@ int cmd_log(int argc, const char **argv
        init_log_defaults();
        git_config(git_log_config, NULL);
  
-       init_revisions(&rev, prefix);
+       repo_init_revisions(the_repository, &rev, prefix);
        rev.always_show_header = 1;
        memset(&opt, 0, sizeof(opt));
        opt.def = "HEAD";
@@@ -916,10 -914,10 +917,10 @@@ static void get_patch_ids(struct rev_in
        if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
                die(_("Not a range."));
  
-       init_patch_ids(ids);
+       init_patch_ids(the_repository, ids);
  
        /* given a range a..b get all patch ids for b..a */
-       init_revisions(&check_rev, rev->prefix);
+       repo_init_revisions(the_repository, &check_rev, rev->prefix);
        check_rev.max_parents = 1;
        o1->flags ^= UNINTERESTING;
        o2->flags ^= UNINTERESTING;
@@@ -995,32 -993,12 +996,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)
@@@ -1377,13 -1361,13 +1378,13 @@@ static void prepare_bases(struct base_t
                return;
  
        init_commit_base(&commit_base);
-       diff_setup(&diffopt);
+       repo_diff_setup(the_repository, &diffopt);
        diffopt.flags.recursive = 1;
        diff_setup_done(&diffopt);
  
        oidcpy(&bases->base_commit, &base->object.oid);
  
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
        revs.max_parents = 1;
        revs.topo_order = 1;
        for (i = 0; i < total; i++) {
@@@ -1436,36 -1420,6 +1437,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()
        };
  
        extra_cc.strdup_strings = 1;
        init_log_defaults();
        git_config(git_format_config, NULL);
-       init_revisions(&rev, prefix);
+       repo_init_revisions(the_repository, &rev, prefix);
        rev.commit_format = CMIT_FMT_EMAIL;
        rev.expand_tabs_in_log_default = 0;
        rev.verbose_header = 1;
                /* 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)
 -                              return 0;
 +                      if (oideq(&o[0].item->oid, &o[1].item->oid))
 +                              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;
  }
  
@@@ -2038,7 -1939,7 +2039,7 @@@ int cmd_cherry(int argc, const char **a
                }
        }
  
-       init_revisions(&revs, prefix);
+       repo_init_revisions(the_repository, &revs, prefix);
        revs.max_parents = 1;
  
        if (add_pending_commit(head, &revs, 0))
        /* 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-tree.c
index 8cea8a74f2b7e89dfedca3688f2b9d8863055010,f32941fdabf7a1e0e89442264b225becab60c882..8fc108d305a33c4ba615837b60bda8175f2fb882
@@@ -76,7 -76,7 +76,7 @@@ static void *result(struct merge_list *
        their = NULL;
        if (entry)
                their = entry->blob;
-       return merge_blobs(path, base, our, their, size);
+       return merge_blobs(&the_index, path, base, our, their, size);
  }
  
  static void *origin(struct merge_list *entry, unsigned long *size)
@@@ -155,7 -155,7 +155,7 @@@ static int same_entry(struct name_entr
  {
        return  a->oid &&
                b->oid &&
 -              !oidcmp(a->oid, b->oid) &&
 +              oideq(a->oid, b->oid) &&
                a->mode == b->mode;
  }
  
diff --combined builtin/merge.c
index e331ca6d481005f6122fa6fda6075728f893632d,a493f8d86611a11a58f15bd1b0112d96965b47f2..4aa60715980f2f226d752e9d7fe0df4ecdcc369d
@@@ -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)
@@@ -390,7 -389,7 +390,7 @@@ static void squash_message(struct commi
  
        printf(_("Squash commit -- not updating HEAD\n"));
  
-       init_revisions(&rev, NULL);
+       repo_init_revisions(the_repository, &rev, NULL);
        rev.ignore_merges = 1;
        rev.commit_format = CMIT_FMT_MEDIUM;
  
@@@ -453,7 -452,7 +453,7 @@@ static void finish(struct commit *head_
        }
        if (new_head && show_diffstat) {
                struct diff_options opts;
-               diff_setup(&opts);
+               repo_diff_setup(the_repository, &opts);
                opts.stat_width = -1; /* use full terminal width */
                opts.stat_graph_width = -1; /* respect statGraphWidth config */
                opts.output_format |=
@@@ -729,8 -728,9 +729,9 @@@ static int try_merge_strategy(const cha
                        die(_("unable to write %s"), get_index_file());
                return clean ? 0 : 1;
        } else {
-               return try_merge_command(strategy, xopts_nr, xopts,
-                                               common, head_arg, remoteheads);
+               return try_merge_command(the_repository,
+                                        strategy, xopts_nr, xopts,
+                                        common, head_arg, remoteheads);
        }
  }
  
@@@ -899,7 -899,7 +900,7 @@@ static int suggest_conflicts(void
        fputs(msgbuf.buf, fp);
        strbuf_release(&msgbuf);
        fclose(fp);
-       rerere(allow_rerere_auto);
+       repo_rerere(the_repository, allow_rerere_auto);
        printf(_("Automatic merge failed; "
                        "fix conflicts and then commit the result.\n"));
        return 1;
@@@ -911,7 -911,7 +912,7 @@@ static int evaluate_result(void
        struct rev_info rev;
  
        /* Check how many files differ. */
-       init_revisions(&rev, "");
+       repo_init_revisions(the_repository, &rev, "");
        setup_revisions(0, NULL, &rev, NULL);
        rev.diffopt.output_format |=
                DIFF_FORMAT_CALLBACK;
@@@ -1190,7 -1190,7 +1191,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 -1449,7 +1450,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;
                        goto done;
                }
  
-               if (checkout_fast_forward(&head_commit->object.oid,
+               if (checkout_fast_forward(the_repository,
+                                         &head_commit->object.oid,
                                          &commit->object.oid,
                                          overwrite_ignore)) {
                        ret = 1;
                         * 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 c6370f2716a7d5a9f78ea6e6627a87b40ab32cc9,3383ba43d088231524b8001c80ee670fa52a38ab..b059b86aee68ceb63e06bc0d8e9ec680686e6bd4
@@@ -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);
@@@ -970,7 -951,8 +970,7 @@@ static int no_try_delta(const char *pat
  
        if (!check)
                check = attr_check_initl("delta", NULL);
 -      if (git_check_attr(&the_index, path, check))
 -              return 0;
 +      git_check_attr(&the_index, path, check);
        if (ATTR_FALSE(check->items[0].value))
                return 1;
        return 0;
@@@ -1058,7 -1040,6 +1058,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;
@@@ -1247,7 -1202,7 +1247,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;
                }
@@@ -1429,7 -1384,7 +1429,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;
                }
@@@ -1469,57 -1424,6 +1469,57 @@@ static void cleanup_preferred_base(void
        done_pbase_paths_num = done_pbase_paths_alloc = 0;
  }
  
 +/*
 + * Return 1 iff the object specified by "delta" can be sent
 + * literally as a delta against the base in "base_sha1". If
 + * so, then *base_out will point to the entry in our packing
 + * list, or NULL if we must use the external-base list.
 + *
 + * Depth value does not matter - find_deltas() will
 + * never consider reused delta as the base object to
 + * deltify other objects against, in order to avoid
 + * circular deltas.
 + */
 +static int can_reuse_delta(const unsigned char *base_sha1,
 +                         struct object_entry *delta,
 +                         struct object_entry **base_out)
 +{
 +      struct object_entry *base;
 +
 +      if (!base_sha1)
 +              return 0;
 +
 +      /*
 +       * First see if we're already sending the base (or it's explicitly in
 +       * our "excluded" list).
 +       */
 +      base = packlist_find(&to_pack, base_sha1, NULL);
 +      if (base) {
 +              if (!in_same_island(&delta->idx.oid, &base->idx.oid))
 +                      return 0;
 +              *base_out = base;
 +              return 1;
 +      }
 +
 +      /*
 +       * Otherwise, reachability bitmaps may tell us if the receiver has it,
 +       * even if it was buried too deep in history to make it into the
 +       * packing list.
 +       */
 +      if (thin && bitmap_has_sha1_in_uninteresting(bitmap_git, base_sha1)) {
 +              if (use_delta_islands) {
 +                      struct object_id base_oid;
 +                      hashcpy(base_oid.hash, base_sha1);
 +                      if (!in_same_island(&delta->idx.oid, &base_oid))
 +                              return 0;
 +              }
 +              *base_out = NULL;
 +              return 1;
 +      }
 +
 +      return 0;
 +}
 +
  static void check_object(struct object_entry *entry)
  {
        unsigned long canonical_size;
                        break;
                }
  
 -              if (base_ref && (base_entry = packlist_find(&to_pack, base_ref, NULL))) {
 -                      /*
 -                       * 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!
 -                       *
 -                       * Depth value does not matter - find_deltas() will
 -                       * never consider reused delta as the base object to
 -                       * deltify other objects against, in order to avoid
 -                       * circular deltas.
 -                       */
 +              if (can_reuse_delta(base_ref, entry, &base_entry)) {
                        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;
                }
@@@ -1918,11 -1826,6 +1918,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)
@@@ -2083,9 -1986,6 +2083,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();
@@@ -2628,9 -2528,6 +2628,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();
  
        /*
@@@ -2794,9 -2691,6 +2794,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)
@@@ -2925,7 -2806,7 +2925,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;
  
@@@ -2989,7 -2870,7 +2989,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)
@@@ -3035,7 -2916,7 +3035,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;
  
@@@ -3070,6 -2951,7 +3070,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;
  }
  
@@@ -3106,7 -2989,7 +3106,7 @@@ static void get_object_list(int ac, con
        char line[1000];
        int flags = 0;
  
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
        save_commit_buffer = 0;
        setup_revisions(ac, av, &revs, NULL);
  
        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);
@@@ -3183,7 -3063,7 +3183,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;
  
@@@ -3235,6 -3115,7 +3235,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 b2055d1dd6f180ec2383ee6f569045e5a55cb4b4,9c455984d1b64ce19db937ca503a6aedf4d4acbf..798ecf7faf186ba337cc73e945ac0c7fefd94866
@@@ -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,
@@@ -563,7 -562,9 +563,9 @@@ static int pull_into_void(const struct 
         * index/worktree changes that the user already made on the unborn
         * branch.
         */
-       if (checkout_fast_forward(the_hash_algo->empty_tree, merge_head, 0))
+       if (checkout_fast_forward(the_repository,
+                                 the_hash_algo->empty_tree,
+                                 merge_head, 0))
                return 1;
  
        if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
@@@ -800,7 -801,7 +802,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 -904,7 +905,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.
                 *
                        "fast-forwarding your working tree from\n"
                        "commit %s."), oid_to_hex(&orig_head));
  
-               if (checkout_fast_forward(&orig_head, &curr_head, 0))
+               if (checkout_fast_forward(the_repository, &orig_head,
+                                         &curr_head, 0))
                        die(_("Cannot fast-forward your working tree.\n"
                                "After making sure that you saved anything precious from\n"
                                "$ git diff %s\n"
                int ret = 0;
                if ((recurse_submodules == RECURSE_SUBMODULES_ON ||
                     recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) &&
-                   submodule_touches_in_range(&rebase_fork_point, &curr_head))
+                   submodule_touches_in_range(&the_index, &rebase_fork_point, &curr_head))
                        die(_("cannot rebase with locally recorded submodule modifications"));
                if (!autostash) {
                        struct commit_list *list = NULL;
diff --combined builtin/range-diff.c
index 96af5374937e5b8b99343e8d324e54e98fb11743,1c477c4dc5ee80d29c7e01f0a88b466782810fc2..f01a0be8513412789ca49e28b0cc2519b7c04760
@@@ -11,9 -11,14 +11,9 @@@ N_("git range-diff [<options>] <base> <
  NULL
  };
  
 -static struct strbuf *output_prefix_cb(struct diff_options *opt, void *data)
 -{
 -      return data;
 -}
 -
  int cmd_range_diff(int argc, const char **argv, const char *prefix)
  {
 -      int creation_factor = 60;
 +      int creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT;
        struct diff_options diffopt = { NULL };
        int simple_color = -1;
        struct option options[] = {
                OPT_END()
        };
        int i, j, res = 0;
 -      struct strbuf four_spaces = STRBUF_INIT;
        struct strbuf range1 = STRBUF_INIT, range2 = STRBUF_INIT;
  
        git_config(git_diff_ui_config, NULL);
  
-       diff_setup(&diffopt);
+       repo_diff_setup(the_repository, &diffopt);
 -      diffopt.output_format = DIFF_FORMAT_PATCH;
 -      diffopt.flags.suppress_diff_headers = 1;
 -      diffopt.output_prefix = output_prefix_cb;
 -      strbuf_addstr(&four_spaces, "    ");
 -      diffopt.output_prefix_data = &four_spaces;
  
        argc = parse_options(argc, argv, NULL, options,
                             builtin_range_diff_usage, PARSE_OPT_KEEP_UNKNOWN |
                             options + ARRAY_SIZE(options) - 1, /* OPT_END */
                             builtin_range_diff_usage, 0);
  
 -      if (simple_color < 1) {
 -              if (!simple_color)
 -                      /* force color when --dual-color was used */
 -                      diffopt.use_color = 1;
 -              diffopt.flags.dual_color_diffed_diffs = 1;
 -      }
 +      /* force color when --dual-color was used */
 +      if (!simple_color)
 +              diffopt.use_color = 1;
  
        if (argc == 2) {
                if (!strstr(argv[0], ".."))
        }
  
        res = show_range_diff(range1.buf, range2.buf, creation_factor,
 -                            &diffopt);
 +                            simple_color < 1, &diffopt);
  
        strbuf_release(&range1);
        strbuf_release(&range2);
 -      strbuf_release(&four_spaces);
  
        return res;
  }
diff --combined builtin/replace.c
index 30a661ea0c71f058cdb8bc7626334cb03747fa7c,e0b16ad44b498dd0b8a6fed68eb7d5093f9b696f..a58b9c6d130568602ac7928bd1da4a83724ff4f1
@@@ -39,8 -39,7 +39,8 @@@ struct show_data 
        enum replace_format format;
  };
  
 -static int show_reference(const char *refname, const struct object_id *oid,
 +static int show_reference(struct repository *r, const char *refname,
 +                        const struct object_id *oid,
                          int flag, void *cb_data)
  {
        struct show_data *data = cb_data;
@@@ -57,8 -56,9 +57,8 @@@
                        if (get_oid(refname, &object))
                                return error(_("failed to resolve '%s' as a valid ref"), refname);
  
 -                      obj_type = oid_object_info(the_repository, &object,
 -                                                 NULL);
 -                      repl_type = oid_object_info(the_repository, oid, NULL);
 +                      obj_type = oid_object_info(r, &object, NULL);
 +                      repl_type = oid_object_info(r, oid, NULL);
  
                        printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type),
                               oid_to_hex(oid), type_name(repl_type));
@@@ -295,7 -295,7 +295,7 @@@ static int import_object(struct object_
                        close(fd);
                        return -1;
                }
-               if (index_fd(oid, fd, &st, type, NULL, flags) < 0)
+               if (index_fd(&the_index, oid, fd, &st, type, NULL, flags) < 0)
                        return error(_("unable to write object to database"));
                /* index_fd close()s fd for us */
        }
@@@ -343,7 -343,7 +343,7 @@@ static int edit_and_replace(const char 
        }
        free(tmpfile);
  
 -      if (!oidcmp(&old_oid, &new_oid))
 +      if (oideq(&old_oid, &new_oid))
                return error(_("new object is the same as the old one: '%s'"), oid_to_hex(&old_oid));
  
        return replace_object_oid(object_ref, &old_oid, "replacement", &new_oid, force);
@@@ -414,7 -414,7 +414,7 @@@ static int check_one_mergetag(struct co
                if (get_oid(mergetag_data->argv[i], &oid) < 0)
                        return error(_("not a valid object name: '%s'"),
                                     mergetag_data->argv[i]);
 -              if (!oidcmp(&tag->tagged->oid, &oid))
 +              if (oideq(&tag->tagged->oid, &oid))
                        return 0; /* found */
        }
  
@@@ -474,7 -474,7 +474,7 @@@ static int create_graft(int argc, cons
  
        strbuf_release(&buf);
  
 -      if (!oidcmp(&old_oid, &new_oid)) {
 +      if (oideq(&old_oid, &new_oid)) {
                if (gentle) {
                        warning(_("graft for '%s' unnecessary"), oid_to_hex(&old_oid));
                        return 0;
diff --combined builtin/rerere.c
index 5ed941b91f2c1498a3f28f0c6415437f79133432,1ca271b7114566a5884fe49968cdd6bb4aeed43a..e89ccbc524a62d5a8760311a2797dfa49fe8525d
@@@ -70,15 -70,15 +70,15 @@@ int cmd_rerere(int argc, const char **a
                flags = RERERE_NOAUTOUPDATE;
  
        if (argc < 1)
-               return rerere(flags);
+               return repo_rerere(the_repository, flags);
  
        if (!strcmp(argv[0], "forget")) {
                struct pathspec pathspec;
                if (argc < 2)
 -                      warning("'git rerere forget' without paths is deprecated");
 +                      warning(_("'git rerere forget' without paths is deprecated"));
                parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD,
                               prefix, argv + 1);
-               return rerere_forget(&pathspec);
+               return rerere_forget(the_repository, &pathspec);
        }
  
        if (!strcmp(argv[0], "clear")) {
@@@ -91,7 -91,7 +91,7 @@@
                for (i = 0; i < merge_rr.nr; i++)
                        printf("%s\n", merge_rr.items[i].string);
        } else if (!strcmp(argv[0], "remaining")) {
-               rerere_remaining(&merge_rr);
+               rerere_remaining(the_repository, &merge_rr);
                for (i = 0; i < merge_rr.nr; i++) {
                        if (merge_rr.items[i].util != RERERE_RESOLVED)
                                printf("%s\n", merge_rr.items[i].string);
                        const char *path = merge_rr.items[i].string;
                        const struct rerere_id *id = merge_rr.items[i].util;
                        if (diff_two(rerere_path(id, "preimage"), path, path, path))
 -                              die("unable to generate diff for %s", rerere_path(id, NULL));
 +                              die(_("unable to generate diff for '%s'"), rerere_path(id, NULL));
                }
        } else
                usage_with_options(rerere_usage, options);
diff --combined builtin/rev-list.c
index ed0ea7dc5b5bed0c3cb926725b2f70cbf9b93d35,c60504891a56088454574297602bc4fcb1343743..cc1b70522f7bcdb77fd33ccd9d9948926b8333ad
@@@ -370,7 -370,7 +370,7 @@@ int cmd_rev_list(int argc, const char *
                usage(rev_list_usage);
  
        git_config(git_default_config, NULL);
-       init_revisions(&revs, prefix);
+       repo_init_revisions(the_repository, &revs, prefix);
        revs.abbrev = DEFAULT_ABBREV;
        revs.commit_format = CMIT_FMT_UNSPECIFIED;
  
        if ((!revs.commits && reflog_walk_empty(revs.reflog_info) &&
             (!(revs.tag_objects || revs.tree_objects || revs.blob_objects) &&
              !revs.pending.nr) &&
 -           !revs.rev_input_given) ||
 +           !revs.rev_input_given && !revs.read_from_stdin) ||
            revs.diff)
                usage(rev_list_usage);
  
index 247881189fde2a910bbd993342bb74fe10e06b0e,063cc0b6b67a15686e6b87670d374f2a8b5c9ece..80474c3ff5651f06df3394cb3f059ac0d7cb19f8
@@@ -792,7 -792,7 +792,7 @@@ static void status_submodule(const cha
                         path, NULL);
  
        git_config(git_diff_basic_config, NULL);
-       init_revisions(&rev, prefix);
+       repo_init_revisions(the_repository, &rev, prefix);
        rev.abbrev = 0;
        diff_files_args.argc = setup_revisions(diff_files_args.argc,
                                               diff_files_args.argv,
@@@ -1233,7 -1233,6 +1233,7 @@@ static int clone_submodule(const char *
        if (gitdir && *gitdir)
                argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL);
  
 +      argv_array_push(&cp.args, "--");
        argv_array_push(&cp.args, url);
        argv_array_push(&cp.args, path);
  
@@@ -1444,72 -1443,6 +1444,72 @@@ static int module_clone(int argc, cons
        return 0;
  }
  
 +static void determine_submodule_update_strategy(struct repository *r,
 +                                              int just_cloned,
 +                                              const char *path,
 +                                              const char *update,
 +                                              struct submodule_update_strategy *out)
 +{
 +      const struct submodule *sub = submodule_from_path(r, &null_oid, path);
 +      char *key;
 +      const char *val;
 +
 +      key = xstrfmt("submodule.%s.update", sub->name);
 +
 +      if (update) {
 +              trace_printf("parsing update");
 +              if (parse_submodule_update_strategy(update, out) < 0)
 +                      die(_("Invalid update mode '%s' for submodule path '%s'"),
 +                              update, path);
 +      } else if (!repo_config_get_string_const(r, key, &val)) {
 +              if (parse_submodule_update_strategy(val, out) < 0)
 +                      die(_("Invalid update mode '%s' configured for submodule path '%s'"),
 +                              val, path);
 +      } else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
 +              trace_printf("loaded thing");
 +              out->type = sub->update_strategy.type;
 +              out->command = sub->update_strategy.command;
 +      } else
 +              out->type = SM_UPDATE_CHECKOUT;
 +
 +      if (just_cloned &&
 +          (out->type == SM_UPDATE_MERGE ||
 +           out->type == SM_UPDATE_REBASE ||
 +           out->type == SM_UPDATE_NONE))
 +              out->type = SM_UPDATE_CHECKOUT;
 +
 +      free(key);
 +}
 +
 +static int module_update_module_mode(int argc, const char **argv, const char *prefix)
 +{
 +      const char *path, *update = NULL;
 +      int just_cloned;
 +      struct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };
 +
 +      if (argc < 3 || argc > 4)
 +              die("submodule--helper update-module-clone expects <just-cloned> <path> [<update>]");
 +
 +      just_cloned = git_config_int("just_cloned", argv[1]);
 +      path = argv[2];
 +
 +      if (argc == 4)
 +              update = argv[3];
 +
 +      determine_submodule_update_strategy(the_repository,
 +                                          just_cloned, path, update,
 +                                          &update_strategy);
 +      fputs(submodule_strategy_to_string(&update_strategy), stdout);
 +
 +      return 0;
 +}
 +
 +struct update_clone_data {
 +      const struct submodule *sub;
 +      struct object_id oid;
 +      unsigned just_cloned;
 +};
 +
  struct submodule_update_clone {
        /* index into 'list', the list of submodules to look into for cloning */
        int current;
        const char *recursive_prefix;
        const char *prefix;
  
 -      /* Machine-readable status lines to be consumed by git-submodule.sh */
 -      struct string_list projectlines;
 +      /* to be consumed by git-submodule.sh */
 +      struct update_clone_data *update_clone;
 +      int update_clone_nr; int update_clone_alloc;
  
        /* If we want to stop as fast as possible and return an error */
        unsigned quickstop : 1;
        /* failed clones to be retried again */
        const struct cache_entry **failed_clones;
        int failed_clones_nr, failed_clones_alloc;
 +
 +      int max_jobs;
  };
  #define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
        SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \
        NULL, NULL, NULL, \
 -      STRING_LIST_INIT_DUP, 0, NULL, 0, 0}
 +      NULL, 0, 0, 0, NULL, 0, 0, 0}
  
  
  static void next_submodule_warn_missing(struct submodule_update_clone *suc,
@@@ -1639,12 -1569,11 +1639,12 @@@ static int prepare_to_clone_next_submod
        strbuf_addf(&sb, "%s/.git", ce->name);
        needs_cloning = !file_exists(sb.buf);
  
 -      strbuf_reset(&sb);
 -      strbuf_addf(&sb, "%06o %s %d %d\t%s\n", ce->ce_mode,
 -                      oid_to_hex(&ce->oid), ce_stage(ce),
 -                      needs_cloning, ce->name);
 -      string_list_append(&suc->projectlines, sb.buf);
 +      ALLOC_GROW(suc->update_clone, suc->update_clone_nr + 1,
 +                 suc->update_clone_alloc);
 +      oidcpy(&suc->update_clone[suc->update_clone_nr].oid, &ce->oid);
 +      suc->update_clone[suc->update_clone_nr].just_cloned = needs_cloning;
 +      suc->update_clone[suc->update_clone_nr].sub = sub;
 +      suc->update_clone_nr++;
  
        if (!needs_cloning)
                goto cleanup;
@@@ -1785,44 -1714,11 +1785,44 @@@ static int git_update_clone_config(cons
        return 0;
  }
  
 +static void update_submodule(struct update_clone_data *ucd)
 +{
 +      fprintf(stdout, "dummy %s %d\t%s\n",
 +              oid_to_hex(&ucd->oid),
 +              ucd->just_cloned,
 +              ucd->sub->path);
 +}
 +
 +static int update_submodules(struct submodule_update_clone *suc)
 +{
 +      int i;
 +
 +      run_processes_parallel(suc->max_jobs,
 +                             update_clone_get_next_task,
 +                             update_clone_start_failure,
 +                             update_clone_task_finished,
 +                             suc);
 +
 +      /*
 +       * We saved the output and put it out all at once now.
 +       * That means:
 +       * - the listener does not have to interleave their (checkout)
 +       *   work with our fetching.  The writes involved in a
 +       *   checkout involve more straightforward sequential I/O.
 +       * - the listener can avoid doing any work if fetching failed.
 +       */
 +      if (suc->quickstop)
 +              return 1;
 +
 +      for (i = 0; i < suc->update_clone_nr; i++)
 +              update_submodule(&suc->update_clone[i]);
 +
 +      return 0;
 +}
 +
  static int update_clone(int argc, const char **argv, const char *prefix)
  {
        const char *update = NULL;
 -      int max_jobs = 1;
 -      struct string_list_item *item;
        struct pathspec pathspec;
        struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
  
                OPT_STRING(0, "depth", &suc.depth, "<depth>",
                           N_("Create a shallow clone truncated to the "
                              "specified number of revisions")),
 -              OPT_INTEGER('j', "jobs", &max_jobs,
 +              OPT_INTEGER('j', "jobs", &suc.max_jobs,
                            N_("parallel jobs")),
                OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
                            N_("whether the initial clone should follow the shallow recommendation")),
        };
        suc.prefix = prefix;
  
 -      update_clone_config_from_gitmodules(&max_jobs);
 -      git_config(git_update_clone_config, &max_jobs);
 +      update_clone_config_from_gitmodules(&suc.max_jobs);
 +      git_config(git_update_clone_config, &suc.max_jobs);
  
        argc = parse_options(argc, argv, prefix, module_update_clone_options,
                             git_submodule_helper_usage, 0);
        if (pathspec.nr)
                suc.warn_if_uninitialized = 1;
  
 -      run_processes_parallel(max_jobs,
 -                             update_clone_get_next_task,
 -                             update_clone_start_failure,
 -                             update_clone_task_finished,
 -                             &suc);
 -
 -      /*
 -       * We saved the output and put it out all at once now.
 -       * That means:
 -       * - the listener does not have to interleave their (checkout)
 -       *   work with our fetching.  The writes involved in a
 -       *   checkout involve more straightforward sequential I/O.
 -       * - the listener can avoid doing any work if fetching failed.
 -       */
 -      if (suc.quickstop)
 -              return 1;
 -
 -      for_each_string_list_item(item, &suc.projectlines)
 -              fprintf(stdout, "%s", item->string);
 -
 -      return 0;
 +      return update_submodules(&suc);
  }
  
  static int resolve_relative_path(int argc, const char **argv, const char *prefix)
@@@ -2022,45 -1938,6 +2022,45 @@@ static int push_check(int argc, const c
        return 0;
  }
  
 +static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
 +{
 +      const struct submodule *sub;
 +      const char *path;
 +      char *cw;
 +      struct repository subrepo;
 +
 +      if (argc != 2)
 +              BUG("submodule--helper connect-gitdir-workingtree <name> <path>");
 +
 +      path = argv[1];
 +
 +      sub = submodule_from_path(the_repository, &null_oid, path);
 +      if (!sub)
 +              BUG("We could get the submodule handle before?");
 +
 +      if (repo_submodule_init(&subrepo, the_repository, path))
 +              die(_("could not get a repository handle for submodule '%s'"), path);
 +
 +      if (!repo_config_get_string(&subrepo, "core.worktree", &cw)) {
 +              char *cfg_file, *abs_path;
 +              const char *rel_path;
 +              struct strbuf sb = STRBUF_INIT;
 +
 +              cfg_file = repo_git_path(&subrepo, "config");
 +
 +              abs_path = absolute_pathdup(path);
 +              rel_path = relative_path(abs_path, subrepo.gitdir, &sb);
 +
 +              git_config_set_in_file(cfg_file, "core.worktree", rel_path);
 +
 +              free(cfg_file);
 +              free(abs_path);
 +              strbuf_release(&sb);
 +      }
 +
 +      return 0;
 +}
 +
  static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
  {
        int i;
@@@ -2138,9 -2015,7 +2138,9 @@@ static struct cmd_struct commands[] = 
        {"list", module_list, 0},
        {"name", module_name, 0},
        {"clone", module_clone, 0},
 +      {"update-module-mode", module_update_module_mode, 0},
        {"update-clone", update_clone, 0},
 +      {"ensure-core-worktree", ensure_core_worktree, 0},
        {"relative-path", resolve_relative_path, 0},
        {"resolve-relative-url", resolve_relative_url, 0},
        {"resolve-relative-url-test", resolve_relative_url_test, 0},
diff --combined builtin/update-index.c
index e7fab78b3b9cf2433342e195a206d8ff3087f9b9,3086212fdb8ffbed6ccebedba9cd344d0bc761a7..07c10bcb7d82c19becf424f9ab63954c9e58f93f
@@@ -282,7 -282,7 +282,7 @@@ static int add_one_path(const struct ca
        fill_stat_cache_info(ce, st);
        ce->ce_mode = ce_mode_from_stat(old, st->st_mode);
  
-       if (index_path(&ce->oid, path, st,
+       if (index_path(&the_index, &ce->oid, path, st,
                       info_only ? 0 : HASH_WRITE_OBJECT)) {
                discard_cache_entry(ce);
                return -1;
@@@ -669,7 -669,7 +669,7 @@@ static int unresolve_one(const char *pa
                ret = -1;
                goto free_return;
        }
 -      if (!oidcmp(&ce_2->oid, &ce_3->oid) &&
 +      if (oideq(&ce_2->oid, &ce_3->oid) &&
            ce_2->ce_mode == ce_3->ce_mode) {
                fprintf(stderr, "%s: identical in both, skipping.\n",
                        path);
@@@ -754,7 -754,7 +754,7 @@@ static int do_reupdate(int ac, const ch
                        old = read_one_ent(NULL, &head_oid,
                                           ce->name, ce_namelen(ce), 0);
                if (old && ce->ce_mode == old->ce_mode &&
 -                  !oidcmp(&ce->oid, &old->oid)) {
 +                  oideq(&ce->oid, &old->oid)) {
                        discard_cache_entry(old);
                        continue; /* unchanged */
                }
diff --combined bundle.c
index 14f2cfc24836b4a526df935e83d8e5899055f483,a5a71d059ecfb28bfce99605e19c094cedc47dce..1ef584b93b87491dca873429f1fbbbadf19622d4
+++ b/bundle.c
@@@ -140,7 -140,7 +140,7 @@@ int verify_bundle(struct bundle_header 
        int i, ret = 0, req_nr;
        const char *message = _("Repository lacks these prerequisite commits:");
  
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
        for (i = 0; i < p->nr; i++) {
                struct ref_list_entry *e = p->list + i;
                struct object *o = parse_object(the_repository, &e->oid);
@@@ -369,7 -369,7 +369,7 @@@ static int write_bundle_refs(int bundle
                 * commit that is referenced by the tag, and not the tag
                 * itself.
                 */
 -              if (oidcmp(&oid, &e->item->oid)) {
 +              if (!oideq(&oid, &e->item->oid)) {
                        /*
                         * Is this the positive end of a range expressed
                         * in terms of a tag (e.g. v2.0 from the range
@@@ -441,7 -441,7 +441,7 @@@ int create_bundle(struct bundle_header 
  
        /* init revs to list objects for pack-objects later */
        save_commit_buffer = 0;
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
  
        /* write prerequisites */
        if (compute_and_write_prerequisites(bundle_fd, &revs, argc, argv))
diff --combined cache.h
index d508f3d4f8837caef469389c71950ee96eea709b,eb0f7d5470119d16b85bc0d5d79484d1a4860075..1d749abf6916831fe81ea6e256e515ae8fcd149b
+++ b/cache.h
@@@ -703,7 -703,7 +703,7 @@@ extern int unmerged_index(const struct 
   * provided, the space-separated list of files that differ will be appended
   * to it.
   */
- extern int index_has_changes(const struct index_state *istate,
+ extern int index_has_changes(struct index_state *istate,
                             struct tree *tree,
                             struct strbuf *sb);
  
@@@ -787,8 -787,8 +787,8 @@@ extern int ie_modified(struct index_sta
  #define HASH_WRITE_OBJECT 1
  #define HASH_FORMAT_CHECK 2
  #define HASH_RENORMALIZE  4
- extern int index_fd(struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
- extern int index_path(struct object_id *oid, const char *path, struct stat *st, unsigned flags);
+ extern int index_fd(struct index_state *istate, struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
+ extern int index_path(struct index_state *istate, struct object_id *oid, const char *path, struct stat *st, unsigned flags);
  
  /*
   * Record to sd the data from st that we use to check whether a file
@@@ -1041,24 -1041,14 +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)
@@@ -1095,22 -1085,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);
@@@ -1528,7 -1518,6 +1528,7 @@@ struct checkout 
        unsigned force:1,
                 quiet:1,
                 not_new:1,
 +               clone:1,
                 refresh_cache:1;
  };
  #define CHECKOUT_INIT { NULL, "" }
@@@ -1705,7 -1694,7 +1705,7 @@@ void shift_tree_by(const struct object_
  /* All WS_* -- when extended, adapt diff.c emit_symbol */
  #define WS_RULE_MASK           07777
  extern unsigned whitespace_rule_cfg;
- extern unsigned whitespace_rule(const char *);
+ extern unsigned whitespace_rule(struct index_state *, const char *);
  extern unsigned parse_whitespace_rule(const char *);
  extern unsigned ws_check(const char *line, int len, unsigned ws_rule);
  extern void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws);
@@@ -1727,10 -1716,12 +1727,12 @@@ extern struct startup_info *startup_inf
  
  /* merge.c */
  struct commit_list;
- int try_merge_command(const char *strategy, size_t xopts_nr,
+ int try_merge_command(struct repository *r,
+               const char *strategy, size_t xopts_nr,
                const char **xopts, struct commit_list *common,
                const char *head_arg, struct commit_list *remotes);
- int checkout_fast_forward(const struct object_id *from,
+ int checkout_fast_forward(struct repository *r,
+                         const struct object_id *from,
                          const struct object_id *to,
                          int overwrite_ignore);
  
diff --combined combine-diff.c
index 0fed4ca529c7da81cde2b84bbe276e55ad87d0e4,41ab5b01deafc44b1c526c883cd4438839c0e9d5..10155e0ec8b18fa80ea96f90a508250bdc5bb9f0
@@@ -285,7 -285,8 +285,8 @@@ static struct lline *coalesce_lines(str
        return base;
  }
  
- static char *grab_blob(const struct object_id *oid, unsigned int mode,
+ static char *grab_blob(struct repository *r,
+                      const struct object_id *oid, unsigned int mode,
                       unsigned long *size, struct userdiff_driver *textconv,
                       const char *path)
  {
        } else if (textconv) {
                struct diff_filespec *df = alloc_filespec(path);
                fill_filespec(df, oid, 1, mode);
-               *size = fill_textconv(textconv, df, &blob);
+               *size = fill_textconv(r, textconv, df, &blob);
                free_filespec(df);
        } else {
                blob = read_object_file(oid, &type, size);
@@@ -389,7 -390,8 +390,8 @@@ static void consume_line(void *state_, 
        }
  }
  
- static void combine_diff(const struct object_id *parent, unsigned int mode,
+ static void combine_diff(struct repository *r,
+                        const struct object_id *parent, unsigned int mode,
                         mmfile_t *result_file,
                         struct sline *sline, unsigned int cnt, int n,
                         int num_parent, int result_deleted,
        if (result_deleted)
                return; /* result deleted */
  
-       parent_file.ptr = grab_blob(parent, mode, &sz, textconv, path);
+       parent_file.ptr = grab_blob(r, parent, mode, &sz, textconv, path);
        parent_file.size = sz;
        memset(&xpp, 0, sizeof(xpp));
        xpp.flags = flags;
@@@ -985,7 -987,7 +987,7 @@@ static void show_patch_diff(struct comb
        const char *line_prefix = diff_line_prefix(opt);
  
        context = opt->context;
-       userdiff = userdiff_find_by_path(elem->path);
+       userdiff = userdiff_find_by_path(opt->repo->index, elem->path);
        if (!userdiff)
                userdiff = userdiff_find_by_name("default");
        if (opt->flags.allow_textconv)
  
        /* Read the result of merge first */
        if (!working_tree_file)
-               result = grab_blob(&elem->oid, elem->mode, &result_size,
+               result = grab_blob(opt->repo, &elem->oid, elem->mode, &result_size,
                                   textconv, elem->path);
        else {
                /* Used by diff-tree to read from the working tree */
                } else if (S_ISDIR(st.st_mode)) {
                        struct object_id oid;
                        if (resolve_gitlink_ref(elem->path, "HEAD", &oid) < 0)
-                               result = grab_blob(&elem->oid, elem->mode,
-                                                  &result_size, NULL, NULL);
+                               result = grab_blob(opt->repo, &elem->oid,
+                                                  elem->mode, &result_size,
+                                                  NULL, NULL);
                        else
-                               result = grab_blob(&oid, elem->mode,
+                               result = grab_blob(opt->repo, &oid, elem->mode,
                                                   &result_size, NULL, NULL);
                } else if (textconv) {
                        struct diff_filespec *df = alloc_filespec(elem->path);
                        fill_filespec(df, &null_oid, 0, st.st_mode);
-                       result_size = fill_textconv(textconv, df, &result);
+                       result_size = fill_textconv(opt->repo, textconv, df, &result);
                        free_filespec(df);
                } else if (0 <= (fd = open(elem->path, O_RDONLY))) {
                        size_t len = xsize_t(st.st_size);
                        if (is_file) {
                                struct strbuf buf = STRBUF_INIT;
  
-                               if (convert_to_git(&the_index, elem->path, result, len, &buf, global_conv_flags_eol)) {
+                               if (convert_to_git(rev->diffopt.repo->index,
+                                                  elem->path, result, len, &buf, global_conv_flags_eol)) {
                                        free(result);
                                        result = strbuf_detach(&buf, &len);
                                        result_size = len;
                for (i = 0; !is_binary && i < num_parent; i++) {
                        char *buf;
                        unsigned long size;
-                       buf = grab_blob(&elem->parent[i].oid,
+                       buf = grab_blob(opt->repo,
+                                       &elem->parent[i].oid,
                                        elem->parent[i].mode,
                                        &size, NULL, NULL);
                        if (buffer_is_binary(buf, size))
        for (i = 0; i < num_parent; i++) {
                int j;
                for (j = 0; j < i; j++) {
 -                      if (!oidcmp(&elem->parent[i].oid,
 -                                   &elem->parent[j].oid)) {
 +                      if (oideq(&elem->parent[i].oid,
 +                                &elem->parent[j].oid)) {
                                reuse_combine_diff(sline, cnt, i, j);
                                break;
                        }
                }
                if (i <= j)
-                       combine_diff(&elem->parent[i].oid,
+                       combine_diff(opt->repo,
+                                    &elem->parent[i].oid,
                                     elem->parent[i].mode,
                                     &result_file, sline,
                                     cnt, i, num_parent, result_deleted,
diff --combined diff-lib.c
index 30bf9a2399fa392b31338489278e0363a55eb726,9a3b798cb546909b546de3afc0d4e75e02430ced..83fce51518854754ee6f4d95cca86d61cc10e4cf
@@@ -70,7 -70,7 +70,7 @@@ static int match_stat_with_submodule(st
                                     struct stat *st, unsigned ce_option,
                                     unsigned *dirty_submodule)
  {
-       int changed = ce_match_stat(ce, st, ce_option);
+       int changed = ie_match_stat(diffopt->repo->index, ce, st, ce_option);
        if (S_ISGITLINK(ce->ce_mode)) {
                struct diff_flags orig_flags = diffopt->flags;
                if (!diffopt->flags.override_submodule_config)
@@@ -93,15 -93,16 +93,16 @@@ int run_diff_files(struct rev_info *rev
        unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
                              ? CE_MATCH_RACY_IS_DIRTY : 0);
        uint64_t start = getnanotime();
+       struct index_state *istate = revs->diffopt.repo->index;
  
        diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/");
  
        if (diff_unmerged_stage < 0)
                diff_unmerged_stage = 2;
-       entries = active_nr;
+       entries = istate->cache_nr;
        for (i = 0; i < entries; i++) {
                unsigned int oldmode, newmode;
-               struct cache_entry *ce = active_cache[i];
+               struct cache_entry *ce = istate->cache[i];
                int changed;
                unsigned dirty_submodule = 0;
                const struct object_id *old_oid, *new_oid;
                if (diff_can_quit_early(&revs->diffopt))
                        break;
  
-               if (!ce_path_match(&the_index, ce, &revs->prune_data, NULL))
+               if (!ce_path_match(istate, ce, &revs->prune_data, NULL))
                        continue;
  
                if (ce_stage(ce)) {
                        dpath->mode = wt_mode;
  
                        while (i < entries) {
-                               struct cache_entry *nce = active_cache[i];
+                               struct cache_entry *nce = istate->cache[i];
                                int stage;
  
                                if (strcmp(ce->name, nce->name))
@@@ -342,7 -343,7 +343,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;
  
@@@ -474,7 -475,9 +475,9 @@@ static int oneway_diff(const struct cac
        if (tree == o->df_conflict_entry)
                tree = NULL;
  
-       if (ce_path_match(&the_index, idx ? idx : tree, &revs->prune_data, NULL)) {
+       if (ce_path_match(revs->diffopt.repo->index,
+                         idx ? idx : tree,
+                         &revs->prune_data, NULL)) {
                do_oneway_diff(o, idx, tree);
                if (diff_can_quit_early(&revs->diffopt)) {
                        o->exiting_early = 1;
@@@ -506,7 -509,7 +509,7 @@@ static int diff_cache(struct rev_info *
        opts.merge = 1;
        opts.fn = oneway_diff;
        opts.unpack_data = revs;
-       opts.src_index = &the_index;
+       opts.src_index = revs->diffopt.repo->index;
        opts.dst_index = NULL;
        opts.pathspec = &revs->diffopt.pathspec;
        opts.pathspec->recursive = 1;
  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;
  }
  
@@@ -539,7 -542,7 +542,7 @@@ int do_diff_cache(const struct object_i
  {
        struct rev_info revs;
  
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
        copy_pathspec(&revs.prune_data, &opt->pathspec);
        revs.diffopt = *opt;
  
@@@ -554,7 -557,7 +557,7 @@@ int index_differs_from(const char *def
        struct rev_info rev;
        struct setup_revision_opt opt;
  
-       init_revisions(&rev, NULL);
+       repo_init_revisions(the_repository, &rev, NULL);
        memset(&opt, 0, sizeof(opt));
        opt.def = def;
        setup_revisions(0, NULL, &rev, &opt);
diff --combined diff.c
index f0c7557b40443da060c3070c602dd03f49b0d689,c5b5e7ac41bf17b16249ce52726fe87b732d71e5..42ba9e48d72a20f2a5961e37f86bb6c4c3b2ba39
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -554,14 -554,15 +554,15 @@@ static int count_lines(const char *data
        return count;
  }
  
- static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
+ static int fill_mmfile(struct repository *r, mmfile_t *mf,
+                      struct diff_filespec *one)
  {
        if (!DIFF_FILE_VALID(one)) {
                mf->ptr = (char *)""; /* does not matter */
                mf->size = 0;
                return 0;
        }
-       else if (diff_populate_filespec(one, 0))
+       else if (diff_populate_filespec(r, one, 0))
                return -1;
  
        mf->ptr = one->data;
  }
  
  /* like fill_mmfile, but only for size, so we can avoid retrieving blob */
- static unsigned long diff_filespec_size(struct diff_filespec *one)
+ static unsigned long diff_filespec_size(struct repository *r,
+                                       struct diff_filespec *one)
  {
        if (!DIFF_FILE_VALID(one))
                return 0;
-       diff_populate_filespec(one, CHECK_SIZE_ONLY);
+       diff_populate_filespec(r, one, CHECK_SIZE_ONLY);
        return one->size;
  }
  
@@@ -624,54 -626,42 +626,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 {
@@@ -980,13 -970,8 +982,13 @@@ static void pmb_advance_or_null_multi_m
                        /* Carry the white space delta forward */
                        pmb[i]->next_line->wsd = pmb[i]->wsd;
                        pmb[i] = pmb[i]->next_line;
 -              } else
 +              } else {
 +                      if (pmb[i]->wsd) {
 +                              free(pmb[i]->wsd->string);
 +                              FREE_AND_NULL(pmb[i]->wsd);
 +                      }
                        pmb[i] = NULL;
 +              }
        }
  }
  
@@@ -1007,6 -992,10 +1009,6 @@@ static int shrink_potential_moved_block
  
                if (lp < pmb_nr && rp > -1 && lp < rp) {
                        pmb[lp] = pmb[rp];
 -                      if (pmb[rp]->wsd) {
 -                              free(pmb[rp]->wsd->string);
 -                              FREE_AND_NULL(pmb[rp]->wsd);
 -                      }
                        pmb[rp] = NULL;
                        rp--;
                        lp++;
@@@ -1200,9 -1189,9 +1202,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);
@@@ -1246,7 -1238,7 +1248,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:
@@@ -1714,12 -1700,12 +1716,12 @@@ static void emit_rewrite_diff(const cha
        quote_two_c_style(&a_name, a_prefix, name_a, 0);
        quote_two_c_style(&b_name, b_prefix, name_b, 0);
  
-       size_one = fill_textconv(textconv_one, one, &data_one);
-       size_two = fill_textconv(textconv_two, two, &data_two);
+       size_one = fill_textconv(o->repo, textconv_one, one, &data_one);
+       size_two = fill_textconv(o->repo, textconv_two, two, &data_two);
  
        memset(&ecbdata, 0, sizeof(ecbdata));
        ecbdata.color_diff = want_color(o->use_color);
-       ecbdata.ws_rule = whitespace_rule(name_b);
+       ecbdata.ws_rule = whitespace_rule(o->repo->index, name_b);
        ecbdata.opt = o;
        if (ecbdata.ws_rule & WS_BLANK_AT_EOF) {
                mmfile_t mf1, mf2;
@@@ -2107,23 -2093,25 +2109,25 @@@ static void diff_words_flush(struct emi
        }
  }
  
- static void diff_filespec_load_driver(struct diff_filespec *one)
+ static void diff_filespec_load_driver(struct diff_filespec *one,
+                                     struct index_state *istate)
  {
        /* Use already-loaded driver */
        if (one->driver)
                return;
  
        if (S_ISREG(one->mode))
-               one->driver = userdiff_find_by_path(one->path);
+               one->driver = userdiff_find_by_path(istate, one->path);
  
        /* Fallback to default settings */
        if (!one->driver)
                one->driver = userdiff_find_by_name("default");
  }
  
- static const char *userdiff_word_regex(struct diff_filespec *one)
+ static const char *userdiff_word_regex(struct diff_filespec *one,
+                                      struct index_state *istate)
  {
-       diff_filespec_load_driver(one);
+       diff_filespec_load_driver(one, istate);
        return one->driver->word_regex;
  }
  
@@@ -2146,9 -2134,9 +2150,9 @@@ static void init_diff_words_data(struc
                        xcalloc(1, sizeof(struct emitted_diff_symbols));
  
        if (!o->word_regex)
-               o->word_regex = userdiff_word_regex(one);
+               o->word_regex = userdiff_word_regex(one, o->repo->index);
        if (!o->word_regex)
-               o->word_regex = userdiff_word_regex(two);
+               o->word_regex = userdiff_word_regex(two, o->repo->index);
        if (!o->word_regex)
                o->word_regex = diff_word_regex_cfg;
        if (o->word_regex) {
@@@ -2949,11 -2937,16 +2953,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
                }
  
                if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) {
-                       diff_populate_filespec(p->one, 0);
-                       diff_populate_filespec(p->two, 0);
-                       diffcore_count_changes(p->one, p->two, NULL, NULL,
+                       diff_populate_filespec(options->repo, p->one, 0);
+                       diff_populate_filespec(options->repo, p->two, 0);
+                       diffcore_count_changes(options->repo,
+                                              p->one, p->two, NULL, NULL,
                                               &copied, &added);
                        diff_free_filespec_data(p->one);
                        diff_free_filespec_data(p->two);
                } else if (DIFF_FILE_VALID(p->one)) {
-                       diff_populate_filespec(p->one, CHECK_SIZE_ONLY);
+                       diff_populate_filespec(options->repo, p->one, CHECK_SIZE_ONLY);
                        copied = added = 0;
                        diff_free_filespec_data(p->one);
                } else if (DIFF_FILE_VALID(p->two)) {
-                       diff_populate_filespec(p->two, CHECK_SIZE_ONLY);
+                       diff_populate_filespec(options->repo, p->two, CHECK_SIZE_ONLY);
                        copied = 0;
                        added = p->two->size;
                        diff_free_filespec_data(p->two);
                 * 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.
                 */
@@@ -3261,15 -3255,16 +3266,16 @@@ static void emit_binary_diff(struct dif
        emit_binary_diff_body(o, two, one);
  }
  
- int diff_filespec_is_binary(struct diff_filespec *one)
+ int diff_filespec_is_binary(struct repository *r,
+                           struct diff_filespec *one)
  {
        if (one->is_binary == -1) {
-               diff_filespec_load_driver(one);
+               diff_filespec_load_driver(one, r->index);
                if (one->driver->binary != -1)
                        one->is_binary = one->driver->binary;
                else {
                        if (!one->data && DIFF_FILE_VALID(one))
-                               diff_populate_filespec(one, CHECK_BINARY);
+                               diff_populate_filespec(r, one, CHECK_BINARY);
                        if (one->is_binary == -1 && one->data)
                                one->is_binary = buffer_is_binary(one->data,
                                                one->size);
        return one->is_binary;
  }
  
- static const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespec *one)
+ static const struct userdiff_funcname *
+ diff_funcname_pattern(struct diff_options *o, struct diff_filespec *one)
  {
-       diff_filespec_load_driver(one);
+       diff_filespec_load_driver(one, o->repo->index);
        return one->driver->funcname.pattern ? &one->driver->funcname : NULL;
  }
  
@@@ -3294,12 -3290,13 +3301,13 @@@ void diff_set_mnemonic_prefix(struct di
                options->b_prefix = b;
  }
  
- struct userdiff_driver *get_textconv(struct diff_filespec *one)
+ struct userdiff_driver *get_textconv(struct index_state *istate,
+                                    struct diff_filespec *one)
  {
        if (!DIFF_FILE_VALID(one))
                return NULL;
  
-       diff_filespec_load_driver(one);
+       diff_filespec_load_driver(one, istate);
        return userdiff_get_textconv(one->driver);
  }
  
@@@ -3349,8 -3346,8 +3357,8 @@@ static void builtin_diff(const char *na
        }
  
        if (o->flags.allow_textconv) {
-               textconv_one = get_textconv(one);
-               textconv_two = get_textconv(two);
+               textconv_one = get_textconv(o->repo->index, one);
+               textconv_two = get_textconv(o->repo->index, two);
        }
  
        /* Never use a non-valid filename anywhere if at all possible */
                if ((one->mode ^ two->mode) & S_IFMT)
                        goto free_ab_and_return;
                if (complete_rewrite &&
-                   (textconv_one || !diff_filespec_is_binary(one)) &&
-                   (textconv_two || !diff_filespec_is_binary(two))) {
+                   (textconv_one || !diff_filespec_is_binary(o->repo, one)) &&
+                   (textconv_two || !diff_filespec_is_binary(o->repo, two))) {
                        emit_diff_symbol(o, DIFF_SYMBOL_HEADER,
                                         header.buf, header.len, 0);
                        strbuf_reset(&header);
                        emit_rewrite_diff(name_a, name_b, one, two,
-                                               textconv_one, textconv_two, o);
+                                         textconv_one, textconv_two, o);
                        o->found_changes = 1;
                        goto free_ab_and_return;
                }
                strbuf_reset(&header);
                goto free_ab_and_return;
        } else if (!o->flags.text &&
-           ( (!textconv_one && diff_filespec_is_binary(one)) ||
-             (!textconv_two && diff_filespec_is_binary(two)) )) {
+                  ( (!textconv_one && diff_filespec_is_binary(o->repo, one)) ||
+                    (!textconv_two && diff_filespec_is_binary(o->repo, two)) )) {
                struct strbuf sb = STRBUF_INIT;
                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,
                        strbuf_release(&sb);
                        goto free_ab_and_return;
                }
-               if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
+               if (fill_mmfile(o->repo, &mf1, one) < 0 ||
+                   fill_mmfile(o->repo, &mf2, two) < 0)
                        die("unable to read files to diff");
                /* Quite common confusing case */
                if (mf1.size == mf2.size &&
                        strbuf_reset(&header);
                }
  
-               mf1.size = fill_textconv(textconv_one, one, &mf1.ptr);
-               mf2.size = fill_textconv(textconv_two, two, &mf2.ptr);
+               mf1.size = fill_textconv(o->repo, textconv_one, one, &mf1.ptr);
+               mf2.size = fill_textconv(o->repo, textconv_two, two, &mf2.ptr);
  
-               pe = diff_funcname_pattern(one);
+               pe = diff_funcname_pattern(o, one);
                if (!pe)
-                       pe = diff_funcname_pattern(two);
+                       pe = diff_funcname_pattern(o, two);
  
                memset(&xpp, 0, sizeof(xpp));
                memset(&xecfg, 0, sizeof(xecfg));
                        lbl[0] = NULL;
                ecbdata.label_path = lbl;
                ecbdata.color_diff = want_color(o->use_color);
-               ecbdata.ws_rule = whitespace_rule(name_b);
+               ecbdata.ws_rule = whitespace_rule(o->repo->index, name_b);
                if (ecbdata.ws_rule & WS_BLANK_AT_EOF)
                        check_blank_at_eof(&mf1, &mf2, &ecbdata);
                ecbdata.opt = o;
@@@ -3580,22 -3578,23 +3589,23 @@@ 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)) {
+       if (diff_filespec_is_binary(o->repo, one) ||
+           diff_filespec_is_binary(o->repo, two)) {
                data->is_binary = 1;
                if (same_contents) {
                        data->added = 0;
                        data->deleted = 0;
                } else {
-                       data->added = diff_filespec_size(two);
-                       data->deleted = diff_filespec_size(one);
+                       data->added = diff_filespec_size(o->repo, two);
+                       data->deleted = diff_filespec_size(o->repo, one);
                }
        }
  
        else if (complete_rewrite) {
-               diff_populate_filespec(one, 0);
-               diff_populate_filespec(two, 0);
+               diff_populate_filespec(o->repo, one, 0);
+               diff_populate_filespec(o->repo, two, 0);
                data->deleted = count_lines(one->data, one->size);
                data->added = count_lines(two->data, two->size);
        }
                xpparam_t xpp;
                xdemitconf_t xecfg;
  
-               if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
+               if (fill_mmfile(o->repo, &mf1, one) < 0 ||
+                   fill_mmfile(o->repo, &mf2, two) < 0)
                        die("unable to read files to diff");
  
                memset(&xpp, 0, sizeof(xpp));
@@@ -3640,10 -3640,11 +3651,11 @@@ static void builtin_checkdiff(const cha
        data.filename = name_b ? name_b : name_a;
        data.lineno = 0;
        data.o = o;
-       data.ws_rule = whitespace_rule(attr_path);
-       data.conflict_marker_size = ll_merge_marker_size(attr_path);
+       data.ws_rule = whitespace_rule(o->repo->index, attr_path);
+       data.conflict_marker_size = ll_merge_marker_size(o->repo->index, attr_path);
  
-       if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
+       if (fill_mmfile(o->repo, &mf1, one) < 0 ||
+           fill_mmfile(o->repo, &mf2, two) < 0)
                die("unable to read files to diff");
  
        /*
         * introduced changes, and as long as the "new" side is text, we
         * can and should check what it introduces.
         */
-       if (diff_filespec_is_binary(two))
+       if (diff_filespec_is_binary(o->repo, two))
                goto free_and_return;
        else {
                /* Crazy xdl interfaces.. */
@@@ -3725,7 -3726,10 +3737,10 @@@ void fill_filespec(struct diff_filespe
   * the work tree has that object contents, return true, so that
   * prepare_temp_file() does not have to inflate and extract.
   */
- static int reuse_worktree_file(const char *name, const struct object_id *oid, int want_file)
+ static int reuse_worktree_file(struct index_state *istate,
+                              const char *name,
+                              const struct object_id *oid,
+                              int want_file)
  {
        const struct cache_entry *ce;
        struct stat st;
         * by diff-cache --cached, which does read the cache before
         * calling us.
         */
-       if (!active_cache)
+       if (!istate->cache)
                return 0;
  
        /* We want to avoid the working directory if our caller
         * Similarly, if we'd have to convert the file contents anyway, that
         * makes the optimization not worthwhile.
         */
-       if (!want_file && would_convert_to_git(&the_index, name))
+       if (!want_file && would_convert_to_git(istate, name))
                return 0;
  
        len = strlen(name);
-       pos = cache_name_pos(name, len);
+       pos = index_name_pos(istate, name, len);
        if (pos < 0)
                return 0;
-       ce = active_cache[pos];
+       ce = istate->cache[pos];
  
        /*
         * 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;
  
        /*
         * If ce matches the file in the work tree, we can reuse it.
         */
        if (ce_uptodate(ce) ||
-           (!lstat(name, &st) && !ce_match_stat(ce, &st, 0)))
+           (!lstat(name, &st) && !ie_match_stat(istate, ce, &st, 0)))
                return 1;
  
        return 0;
@@@ -3823,7 -3827,9 +3838,9 @@@ static int diff_populate_gitlink(struc
   * grab the data for the blob (or file) for our own in-core comparison.
   * diff_filespec has data and size fields for this purpose.
   */
- int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)
+ int diff_populate_filespec(struct repository *r,
+                          struct diff_filespec *s,
+                          unsigned int flags)
  {
        int size_only = flags & CHECK_SIZE_ONLY;
        int err = 0;
                return diff_populate_gitlink(s, size_only);
  
        if (!s->oid_valid ||
-           reuse_worktree_file(s->path, &s->oid, 0)) {
+           reuse_worktree_file(r->index, s->path, &s->oid, 0)) {
                struct strbuf buf = STRBUF_INIT;
                struct stat st;
                int fd;
                 * point if the path requires us to run the content
                 * conversion.
                 */
-               if (size_only && !would_convert_to_git(&the_index, s->path))
+               if (size_only && !would_convert_to_git(r->index, s->path))
                        return 0;
  
                /*
                /*
                 * Convert from working tree format to canonical git format
                 */
-               if (convert_to_git(&the_index, s->path, s->data, s->size, &buf, conv_flags)) {
+               if (convert_to_git(r->index, s->path, s->data, s->size, &buf, conv_flags)) {
                        size_t size = 0;
                        munmap(s->data, s->size);
                        s->should_munmap = 0;
        else {
                enum object_type type;
                if (size_only || (flags & CHECK_BINARY)) {
-                       type = oid_object_info(the_repository, &s->oid,
-                                              &s->size);
+                       type = oid_object_info(r, &s->oid, &s->size);
                        if (type < 0)
                                die("unable to read %s",
                                    oid_to_hex(&s->oid));
@@@ -3961,7 -3966,8 +3977,8 @@@ void diff_free_filespec_data(struct dif
        FREE_AND_NULL(s->cnt_data);
  }
  
- static void prep_temp_blob(const char *path, struct diff_tempfile *temp,
+ static void prep_temp_blob(struct index_state *istate,
+                          const char *path, struct diff_tempfile *temp,
                           void *blob,
                           unsigned long size,
                           const struct object_id *oid,
        temp->tempfile = mks_tempfile_ts(tempfile.buf, strlen(base) + 1);
        if (!temp->tempfile)
                die_errno("unable to create temp-file");
-       if (convert_to_working_tree(&the_index, path,
+       if (convert_to_working_tree(istate, path,
                        (const char *)blob, (size_t)size, &buf)) {
                blob = buf.buf;
                size = buf.len;
        free(path_dup);
  }
  
- static struct diff_tempfile *prepare_temp_file(const char *name,
-               struct diff_filespec *one)
+ static struct diff_tempfile *prepare_temp_file(struct repository *r,
+                                              const char *name,
+                                              struct diff_filespec *one)
  {
        struct diff_tempfile *temp = claim_diff_tempfile();
  
  
        if (!S_ISGITLINK(one->mode) &&
            (!one->oid_valid ||
-            reuse_worktree_file(name, &one->oid, 1))) {
+            reuse_worktree_file(r->index, name, &one->oid, 1))) {
                struct stat st;
                if (lstat(name, &st) < 0) {
                        if (errno == ENOENT)
                        struct strbuf sb = STRBUF_INIT;
                        if (strbuf_readlink(&sb, name, st.st_size) < 0)
                                die_errno("readlink(%s)", name);
-                       prep_temp_blob(name, temp, sb.buf, sb.len,
+                       prep_temp_blob(r->index, name, temp, sb.buf, sb.len,
                                       (one->oid_valid ?
                                        &one->oid : &null_oid),
                                       (one->oid_valid ?
                return temp;
        }
        else {
-               if (diff_populate_filespec(one, 0))
+               if (diff_populate_filespec(r, one, 0))
                        die("cannot read data blob for %s", one->path);
-               prep_temp_blob(name, temp, one->data, one->size,
+               prep_temp_blob(r->index, name, temp,
+                              one->data, one->size,
                               &one->oid, one->mode);
        }
        return temp;
  }
  
- static void add_external_diff_name(struct argv_array *argv,
+ static void add_external_diff_name(struct repository *r,
+                                  struct argv_array *argv,
                                   const char *name,
                                   struct diff_filespec *df)
  {
-       struct diff_tempfile *temp = prepare_temp_file(name, df);
+       struct diff_tempfile *temp = prepare_temp_file(r, name, df);
        argv_array_push(argv, temp->name);
        argv_array_push(argv, temp->hex);
        argv_array_push(argv, temp->mode);
@@@ -4090,11 -4099,11 +4110,11 @@@ static void run_external_diff(const cha
        argv_array_push(&argv, name);
  
        if (one && two) {
-               add_external_diff_name(&argv, name, one);
+               add_external_diff_name(o->repo, &argv, name, one);
                if (!other)
-                       add_external_diff_name(&argv, name, two);
+                       add_external_diff_name(o->repo, &argv, name, two);
                else {
-                       add_external_diff_name(&argv, other, two);
+                       add_external_diff_name(o->repo, &argv, other, two);
                        argv_array_push(&argv, other);
                        argv_array_push(&argv, xfrm_msg);
                }
@@@ -4181,14 -4190,16 +4201,16 @@@ 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;
  
                if (o->flags.binary) {
                        mmfile_t mf;
-                       if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) ||
-                           (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
+                       if ((!fill_mmfile(o->repo, &mf, one) &&
+                            diff_filespec_is_binary(o->repo, one)) ||
+                           (!fill_mmfile(o->repo, &mf, two) &&
+                            diff_filespec_is_binary(o->repo, two)))
                                abbrev = hexsz;
                }
                strbuf_addf(msg, "%s%sindex %s..%s", line_prefix, set,
@@@ -4216,7 -4227,9 +4238,9 @@@ static void run_diff_cmd(const char *pg
  
  
        if (o->flags.allow_external) {
-               struct userdiff_driver *drv = userdiff_find_by_path(attr_path);
+               struct userdiff_driver *drv;
+               drv = userdiff_find_by_path(o->repo->index, attr_path);
                if (drv && drv->external)
                        pgm = drv->external;
        }
                fprintf(o->file, "* Unmerged path %s\n", name);
  }
  
- static void diff_fill_oid_info(struct diff_filespec *one)
+ static void diff_fill_oid_info(struct diff_filespec *one, struct index_state *istate)
  {
        if (DIFF_FILE_VALID(one)) {
                if (!one->oid_valid) {
                        }
                        if (lstat(one->path, &st) < 0)
                                die_errno("stat '%s'", one->path);
-                       if (index_path(&one->oid, one->path, &st, 0))
+                       if (index_path(istate, &one->oid, one->path, &st, 0))
                                die("cannot hash %s", one->path);
                }
        }
@@@ -4304,8 -4317,8 +4328,8 @@@ static void run_diff(struct diff_filepa
                return;
        }
  
-       diff_fill_oid_info(one);
-       diff_fill_oid_info(two);
+       diff_fill_oid_info(one, o->repo->index);
+       diff_fill_oid_info(two, o->repo->index);
  
        if (!pgm &&
            DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) &&
                 */
                struct diff_filespec *null = alloc_filespec(two->path);
                run_diff_cmd(NULL, name, other, attr_path,
-                            one, null, &msg, o, p);
+                            one, null, &msg,
+                            o, p);
                free(null);
                strbuf_release(&msg);
  
@@@ -4340,7 -4354,8 +4365,8 @@@ static void run_diffstat(struct diff_fi
  
        if (DIFF_PAIR_UNMERGED(p)) {
                /* unmerged */
-               builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, p);
+               builtin_diffstat(p->one->path, NULL, NULL, NULL,
+                                diffstat, o, p);
                return;
        }
  
        if (o->prefix_length)
                strip_prefix(o->prefix_length, &name, &other);
  
-       diff_fill_oid_info(p->one);
-       diff_fill_oid_info(p->two);
+       diff_fill_oid_info(p->one, o->repo->index);
+       diff_fill_oid_info(p->two, o->repo->index);
  
-       builtin_diffstat(name, other, p->one, p->two, diffstat, o, p);
+       builtin_diffstat(name, other, p->one, p->two,
+                        diffstat, o, p);
  }
  
  static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)
        if (o->prefix_length)
                strip_prefix(o->prefix_length, &name, &other);
  
-       diff_fill_oid_info(p->one);
-       diff_fill_oid_info(p->two);
+       diff_fill_oid_info(p->one, o->repo->index);
+       diff_fill_oid_info(p->two, o->repo->index);
  
        builtin_checkdiff(name, other, attr_path, p->one, p->two, o);
  }
  
- void diff_setup(struct diff_options *options)
+ void repo_diff_setup(struct repository *r, struct diff_options *options)
  {
        memcpy(options, &default_diff_options, sizeof(*options));
  
        options->file = stdout;
+       options->repo = r;
  
 +      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;
@@@ -4866,12 -4880,6 +4894,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") ||
@@@ -5343,7 -5351,7 +5371,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)
@@@ -5477,7 -5485,7 +5505,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 ||
@@@ -5683,8 -5691,8 +5711,8 @@@ static int diff_get_patch_id(struct dif
                if (DIFF_PAIR_UNMERGED(p))
                        continue;
  
-               diff_fill_oid_info(p->one);
-               diff_fill_oid_info(p->two);
+               diff_fill_oid_info(p->one, options->repo->index);
+               diff_fill_oid_info(p->two, options->repo->index);
  
                len1 = remove_space(p->one->path, strlen(p->one->path));
                len2 = remove_space(p->two->path, strlen(p->two->path));
                if (diff_header_only)
                        continue;
  
-               if (fill_mmfile(&mf1, p->one) < 0 ||
-                   fill_mmfile(&mf2, p->two) < 0)
+               if (fill_mmfile(options->repo, &mf1, p->one) < 0 ||
+                   fill_mmfile(options->repo, &mf2, p->two) < 0)
                        return error("unable to read files to diff");
  
-               if (diff_filespec_is_binary(p->one) ||
-                   diff_filespec_is_binary(p->two)) {
+               if (diff_filespec_is_binary(options->repo, p->one) ||
+                   diff_filespec_is_binary(options->repo, p->two)) {
                        git_SHA1_Update(&ctx, oid_to_hex(&p->one->oid),
                                        GIT_SHA1_HEXSZ);
                        git_SHA1_Update(&ctx, oid_to_hex(&p->two->oid),
@@@ -6024,19 -6032,21 +6052,21 @@@ static void diffcore_apply_filter(struc
  }
  
  /* Check whether two filespecs with the same mode and size are identical */
- static int diff_filespec_is_identical(struct diff_filespec *one,
+ static int diff_filespec_is_identical(struct repository *r,
+                                     struct diff_filespec *one,
                                      struct diff_filespec *two)
  {
        if (S_ISGITLINK(one->mode))
                return 0;
-       if (diff_populate_filespec(one, 0))
+       if (diff_populate_filespec(r, one, 0))
                return 0;
-       if (diff_populate_filespec(two, 0))
+       if (diff_populate_filespec(r, two, 0))
                return 0;
        return !memcmp(one->data, two->data, one->size);
  }
  
- static int diff_filespec_check_stat_unmatch(struct diff_filepair *p)
+ static int diff_filespec_check_stat_unmatch(struct repository *r,
+                                           struct diff_filepair *p)
  {
        if (p->done_skip_stat_unmatch)
                return p->skip_stat_unmatch_result;
            !DIFF_FILE_VALID(p->two) ||
            (p->one->oid_valid && p->two->oid_valid) ||
            (p->one->mode != p->two->mode) ||
-           diff_populate_filespec(p->one, CHECK_SIZE_ONLY) ||
-           diff_populate_filespec(p->two, CHECK_SIZE_ONLY) ||
+           diff_populate_filespec(r, p->one, CHECK_SIZE_ONLY) ||
+           diff_populate_filespec(r, p->two, CHECK_SIZE_ONLY) ||
            (p->one->size != p->two->size) ||
-           !diff_filespec_is_identical(p->one, p->two)) /* (2) */
+           !diff_filespec_is_identical(r, p->one, p->two)) /* (2) */
                p->skip_stat_unmatch_result = 1;
        return p->skip_stat_unmatch_result;
  }
@@@ -6078,7 -6088,7 +6108,7 @@@ static void diffcore_skip_stat_unmatch(
        for (i = 0; i < q->nr; i++) {
                struct diff_filepair *p = q->queue[i];
  
-               if (diff_filespec_check_stat_unmatch(p))
+               if (diff_filespec_check_stat_unmatch(diffopt->repo, p))
                        diff_q(&outq, p);
                else {
                        /*
@@@ -6120,7 -6130,8 +6150,8 @@@ void diffcore_std(struct diff_options *
        if (!options->found_follow) {
                /* See try_to_follow_renames() in tree-diff.c */
                if (options->break_opt != -1)
-                       diffcore_break(options->break_opt);
+                       diffcore_break(options->repo,
+                                      options->break_opt);
                if (options->detect_rename)
                        diffcore_rename(options);
                if (options->break_opt != -1)
@@@ -6271,7 -6282,7 +6302,7 @@@ void diff_change(struct diff_options *o
                return;
  
        if (options->flags.quick && options->skip_stat_unmatch &&
-           !diff_filespec_check_stat_unmatch(p))
+           !diff_filespec_check_stat_unmatch(options->repo, p))
                return;
  
        options->flags.has_changes = 1;
@@@ -6293,8 -6304,10 +6324,10 @@@ struct diff_filepair *diff_unmerge(stru
        return pair;
  }
  
- static char *run_textconv(const char *pgm, struct diff_filespec *spec,
-               size_t *outsize)
+ static char *run_textconv(struct repository *r,
+                         const char *pgm,
+                         struct diff_filespec *spec,
+                         size_t *outsize)
  {
        struct diff_tempfile *temp;
        const char *argv[3];
        struct strbuf buf = STRBUF_INIT;
        int err = 0;
  
-       temp = prepare_temp_file(spec->path, spec);
+       temp = prepare_temp_file(r, spec->path, spec);
        *arg++ = pgm;
        *arg++ = temp->name;
        *arg = NULL;
        return strbuf_detach(&buf, outsize);
  }
  
- size_t fill_textconv(struct userdiff_driver *driver,
+ size_t fill_textconv(struct repository *r,
+                    struct userdiff_driver *driver,
                     struct diff_filespec *df,
                     char **outbuf)
  {
                        *outbuf = "";
                        return 0;
                }
-               if (diff_populate_filespec(df, 0))
+               if (diff_populate_filespec(r, df, 0))
                        die("unable to read files to diff");
                *outbuf = df->data;
                return df->size;
                        return size;
        }
  
-       *outbuf = run_textconv(driver->textconv, df, &size);
+       *outbuf = run_textconv(r, driver->textconv, df, &size);
        if (!*outbuf)
                die("unable to read files to diff");
  
        return size;
  }
  
- int textconv_object(const char *path,
+ int textconv_object(struct repository *r,
+                   const char *path,
                    unsigned mode,
                    const struct object_id *oid,
                    int oid_valid,
  
        df = alloc_filespec(path);
        fill_filespec(df, oid, oid_valid, mode);
-       textconv = get_textconv(df);
+       textconv = get_textconv(r->index, df);
        if (!textconv) {
                free_filespec(df);
                return 0;
        }
  
-       *buf_size = fill_textconv(textconv, df, buf);
+       *buf_size = fill_textconv(r, textconv, df, buf);
        free_filespec(df);
        return 1;
  }
diff --combined diff.h
index a30cc35ec3b4cb525340691a39ca88e89e379e4c,af261962240de8d1a1adfa62a8ff60b9d3ca0fd4..ce5e8a8183e848b2e36d50bea271f687a450e3af
--- 1/diff.h
--- 2/diff.h
+++ b/diff.h
@@@ -18,6 -18,7 +18,7 @@@ struct userdiff_driver
  struct oid_array;
  struct commit;
  struct combine_diff_path;
+ struct repository;
  
  typedef int (*pathchange_fn_t)(struct diff_options *options,
                 struct combine_diff_path *path);
@@@ -194,11 -195,6 +195,11 @@@ struct diff_options 
        FILE *file;
        int close_file;
  
 +#define OUTPUT_INDICATOR_NEW 0
 +#define OUTPUT_INDICATOR_OLD 1
 +#define OUTPUT_INDICATOR_CONTEXT 2
 +      char output_indicators[3];
 +
        struct pathspec pathspec;
        pathchange_fn_t pathchange;
        change_fn_t change;
        /* XDF_WHITESPACE_FLAGS regarding block detection are set at 2, 3, 4 */
        #define COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE (1<<5)
        int color_moved_ws_handling;
+       struct repository *repo;
  };
  
  void diff_emit_submodule_del(struct diff_options *o, const char *line);
@@@ -338,7 -336,10 +341,10 @@@ int git_diff_basic_config(const char *v
  int git_diff_heuristic_config(const char *var, const char *value, void *cb);
  void init_diff_ui_defaults(void);
  int git_diff_ui_config(const char *var, const char *value, void *cb);
- void diff_setup(struct diff_options *);
+ #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
+ #define diff_setup(diffopts) repo_diff_setup(the_repository, diffopts)
+ #endif
+ void repo_diff_setup(struct repository *, struct diff_options *);
  int diff_opt_parse(struct diff_options *, const char **, int, const char *);
  void diff_setup_done(struct diff_options *);
  int git_config_rename(const char *var, const char *value);
@@@ -428,7 -429,7 +434,7 @@@ int diff_flush_patch_id(struct diff_opt
  
  int diff_result_code(struct diff_options *, int);
  
- void diff_no_index(struct rev_info *, int, const char **);
+ void diff_no_index(struct repository *, struct rev_info *, int, const char **);
  
  int index_differs_from(const char *def, const struct diff_flags *flags,
                       int ita_invisible_in_index);
   * struct. If it is non-NULL, then "outbuf" points to a newly allocated buffer
   * that should be freed by the caller.
   */
- size_t fill_textconv(struct userdiff_driver *driver,
+ size_t fill_textconv(struct repository *r,
+                    struct userdiff_driver *driver,
                     struct diff_filespec *df,
                     char **outbuf);
  
   * and only if it has textconv enabled (otherwise return NULL). The result
   * can be passed to fill_textconv().
   */
- struct userdiff_driver *get_textconv(struct diff_filespec *one);
+ struct userdiff_driver *get_textconv(struct index_state *istate,
+                                    struct diff_filespec *one);
  
  /*
   * Prepare diff_filespec and convert it using diff textconv API
   * if the textconv driver exists.
   * Return 1 if the conversion succeeds, 0 otherwise.
   */
- int textconv_object(const char *path, unsigned mode, const struct object_id *oid, int oid_valid, char **buf, unsigned long *buf_size);
+ int textconv_object(struct repository *repo,
+                   const char *path,
+                   unsigned mode,
+                   const struct object_id *oid, int oid_valid,
+                   char **buf, unsigned long *buf_size);
  
  int parse_rename_score(const char **cp_p);
  
diff --combined diffcore-break.c
index e11fcfdb391425ac9efaea829d4756891dcb941e,b580d92154497cec67913143d719a3ac79bf2096..875aefd3febf46771cc56c1f2b9f26318cfc732b
@@@ -5,7 -5,8 +5,8 @@@
  #include "diff.h"
  #include "diffcore.h"
  
- static int should_break(struct diff_filespec *src,
+ static int should_break(struct repository *r,
+                       struct diff_filespec *src,
                        struct diff_filespec *dst,
                        int break_score,
                        int *merge_score_p)
        }
  
        if (src->oid_valid && dst->oid_valid &&
 -          !oidcmp(&src->oid, &dst->oid))
 +          oideq(&src->oid, &dst->oid))
                return 0; /* they are the same */
  
-       if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0))
+       if (diff_populate_filespec(r, src, 0) ||
+           diff_populate_filespec(r, dst, 0))
                return 0; /* error but caught downstream */
  
        max_size = ((src->size > dst->size) ? src->size : dst->size);
@@@ -71,7 -73,7 +73,7 @@@
        if (!src->size)
                return 0; /* we do not let empty files get renamed */
  
-       if (diffcore_count_changes(src, dst,
+       if (diffcore_count_changes(r, src, dst,
                                   &src->cnt_data, &dst->cnt_data,
                                   &src_copied, &literal_added))
                return 0;
        return 1;
  }
  
- void diffcore_break(int break_score)
+ void diffcore_break(struct repository *r, int break_score)
  {
        struct diff_queue_struct *q = &diff_queued_diff;
        struct diff_queue_struct outq;
                    object_type(p->one->mode) == OBJ_BLOB &&
                    object_type(p->two->mode) == OBJ_BLOB &&
                    !strcmp(p->one->path, p->two->path)) {
-                       if (should_break(p->one, p->two,
+                       if (should_break(r, p->one, p->two,
                                         break_score, &score)) {
                                /* Split this into delete and create */
                                struct diff_filespec *null_one, *null_two;
diff --combined diffcore-rename.c
index daddd9b28af1e20fe82aefa654bad04f4b52c1d3,f85758b23346d220907a41a632bb0ba445a98dc7..07bd34b63145e1dc179afebcc7af351c34c2ab07
@@@ -128,7 -128,8 +128,8 @@@ struct diff_score 
        short name_score;
  };
  
- static int estimate_similarity(struct diff_filespec *src,
+ static int estimate_similarity(struct repository *r,
+                              struct diff_filespec *src,
                               struct diff_filespec *dst,
                               int minimum_score)
  {
         * say whether the size is valid or not!)
         */
        if (!src->cnt_data &&
-           diff_populate_filespec(src, CHECK_SIZE_ONLY))
+           diff_populate_filespec(r, src, CHECK_SIZE_ONLY))
                return 0;
        if (!dst->cnt_data &&
-           diff_populate_filespec(dst, CHECK_SIZE_ONLY))
+           diff_populate_filespec(r, dst, CHECK_SIZE_ONLY))
                return 0;
  
        max_size = ((src->size > dst->size) ? src->size : dst->size);
        if (max_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE)
                return 0;
  
-       if (!src->cnt_data && diff_populate_filespec(src, 0))
+       if (!src->cnt_data && diff_populate_filespec(r, src, 0))
                return 0;
-       if (!dst->cnt_data && diff_populate_filespec(dst, 0))
+       if (!dst->cnt_data && diff_populate_filespec(r, dst, 0))
                return 0;
  
-       if (diffcore_count_changes(src, dst,
+       if (diffcore_count_changes(r, src, dst,
                                   &src->cnt_data, &dst->cnt_data,
                                   &src_copied, &literal_added))
                return 0;
@@@ -256,10 -257,11 +257,11 @@@ struct file_similarity 
        struct diff_filespec *filespec;
  };
  
- static unsigned int hash_filespec(struct diff_filespec *filespec)
+ static unsigned int hash_filespec(struct repository *r,
+                                 struct diff_filespec *filespec)
  {
        if (!filespec->oid_valid) {
-               if (diff_populate_filespec(filespec, 0))
+               if (diff_populate_filespec(r, filespec, 0))
                        return 0;
                hash_object_file(filespec->data, filespec->size, "blob",
                                 &filespec->oid);
@@@ -280,13 -282,15 +282,15 @@@ static int find_identical_files(struct 
        /*
         * Find the best source match for specified destination.
         */
-       p = hashmap_get_from_hash(srcs, hash_filespec(target), NULL);
+       p = hashmap_get_from_hash(srcs,
+                                 hash_filespec(options->repo, target),
+                                 NULL);
        for (; p; p = hashmap_get_next(srcs, p)) {
                int score;
                struct diff_filespec *source = p->filespec;
  
                /* False hash collision? */
 -              if (oidcmp(&source->oid, &target->oid))
 +              if (!oideq(&source->oid, &target->oid))
                        continue;
                /* Non-regular files? If so, the modes must match! */
                if (!S_ISREG(source->mode) || !S_ISREG(target->mode)) {
        return renames;
  }
  
- static void insert_file_table(struct hashmap *table, int index, struct diff_filespec *filespec)
+ static void insert_file_table(struct repository *r,
+                             struct hashmap *table, int index,
+                             struct diff_filespec *filespec)
  {
        struct file_similarity *entry = xmalloc(sizeof(*entry));
  
        entry->index = index;
        entry->filespec = filespec;
  
-       hashmap_entry_init(entry, hash_filespec(filespec));
+       hashmap_entry_init(entry, hash_filespec(r, filespec));
        hashmap_add(table, entry);
  }
  
@@@ -344,7 -350,9 +350,9 @@@ static int find_exact_renames(struct di
         */
        hashmap_init(&file_table, NULL, NULL, rename_src_nr);
        for (i = rename_src_nr-1; i >= 0; i--)
-               insert_file_table(&file_table, i, rename_src[i].p->one);
+               insert_file_table(options->repo,
+                                 &file_table, i,
+                                 rename_src[i].p->one);
  
        /* Walk the destinations and find best source match */
        for (i = 0; i < rename_dst_nr; i++)
@@@ -557,7 -565,8 +565,8 @@@ void diffcore_rename(struct diff_option
                            diff_unmodified_pair(rename_src[j].p))
                                continue;
  
-                       this_src.score = estimate_similarity(one, two,
+                       this_src.score = estimate_similarity(options->repo,
+                                                            one, two,
                                                             minimum_score);
                        this_src.name_score = basename_same(one, two);
                        this_src.dst = i;
diff --combined http-push.c
index 1bbb0cdb6d03353fbc145d6ba748a30c9eabcec0,df504ab6a320278c911fd06cb881692ce62acd27..d1f52cbdf698ef3ac48d3c599d28d6ba7dfa13aa
@@@ -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)
                if (!push_all && !is_null_oid(&ref->old_oid))
                        argv_array_pushf(&commit_argv, "^%s",
                                         oid_to_hex(&ref->old_oid));
-               init_revisions(&revs, setup_git_directory());
+               repo_init_revisions(the_repository, &revs, setup_git_directory());
                setup_revisions(commit_argv.argc, commit_argv.argv, &revs, NULL);
                revs.edge_hint = 0; /* just in case */
  
diff --combined ll-merge.c
index 1936fee9e1c54e8c0dc049ba48ef1cd209967d31,c339ef8ae87b316f39ba25a47da42c38d965cabd..3c8fb917e9748b1950d5df8c85aa310149f1f8df
@@@ -336,10 -336,10 +336,10 @@@ static const struct ll_merge_driver *fi
        return &ll_merge_drv[LL_TEXT_MERGE];
  }
  
- static void normalize_file(mmfile_t *mm, const char *path)
+ static void normalize_file(mmfile_t *mm, const char *path, struct index_state *istate)
  {
        struct strbuf strbuf = STRBUF_INIT;
-       if (renormalize_buffer(&the_index, path, mm->ptr, mm->size, &strbuf)) {
+       if (renormalize_buffer(istate, path, mm->ptr, mm->size, &strbuf)) {
                free(mm->ptr);
                mm->size = strbuf.len;
                mm->ptr = strbuf_detach(&strbuf, NULL);
@@@ -351,6 -351,7 +351,7 @@@ int ll_merge(mmbuffer_t *result_buf
             mmfile_t *ancestor, const char *ancestor_label,
             mmfile_t *ours, const char *our_label,
             mmfile_t *theirs, const char *their_label,
+            struct index_state *istate,
             const struct ll_merge_options *opts)
  {
        static struct attr_check *check;
                opts = &default_opts;
  
        if (opts->renormalize) {
-               normalize_file(ancestor, path);
-               normalize_file(ours, path);
-               normalize_file(theirs, path);
+               normalize_file(ancestor, path, istate);
+               normalize_file(ours, path, istate);
+               normalize_file(theirs, path, istate);
        }
  
        if (!check)
                check = attr_check_initl("merge", "conflict-marker-size", NULL);
  
-       git_check_attr(&the_index, path, check);
 -      if (!git_check_attr(istate, path, check)) {
 -              ll_driver_name = check->items[0].value;
 -              if (check->items[1].value) {
 -                      marker_size = atoi(check->items[1].value);
 -                      if (marker_size <= 0)
 -                              marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
 -              }
++      git_check_attr(istate, path, check);
 +      ll_driver_name = check->items[0].value;
 +      if (check->items[1].value) {
 +              marker_size = atoi(check->items[1].value);
 +              if (marker_size <= 0)
 +                      marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
        }
        driver = find_ll_merge_driver(ll_driver_name);
  
                          opts, marker_size);
  }
  
- int ll_merge_marker_size(const char *path)
+ int ll_merge_marker_size(struct index_state *istate, const char *path)
  {
        static struct attr_check *check;
        int marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
  
        if (!check)
                check = attr_check_initl("conflict-marker-size", NULL);
-       git_check_attr(&the_index, path, check);
 -      if (!git_check_attr(istate, path, check) && check->items[0].value) {
++      git_check_attr(istate, path, check);
 +      if (check->items[0].value) {
                marker_size = atoi(check->items[0].value);
                if (marker_size <= 0)
                        marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
diff --combined merge-recursive.c
index 0684dab77965b6abd0f8429bc53cd936a826482b,82e9f1d24a37f84aba4287beee74c3c11d5db41f..c0fb83d2858c056633f306b2c3d49b9fd587b767
@@@ -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 {
@@@ -1084,7 -1083,8 +1084,8 @@@ static int merge_3way(struct merge_opti
        read_mmblob(&src2, &b->oid);
  
        merge_status = ll_merge(result_buf, a->path, &orig, base_name,
-                               &src1, name1, &src2, name2, &ll_opts);
+                               &src1, name1, &src2, name2,
+                               &the_index, &ll_opts);
  
        free(base_name);
        free(name1);
@@@ -1115,7 -1115,7 +1116,7 @@@ static int find_first_merges(struct obj
        /* get all revisions that merge commit a */
        xsnprintf(merged_revision, sizeof(merged_revision), "^%s",
                  oid_to_hex(&a->object.oid));
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
        rev_opts.submodule = path;
        /* FIXME: can't handle linked worktrees in submodules yet */
        revs.single_worktree = path != NULL;
@@@ -1274,14 -1274,14 +1275,14 @@@ static int merge_submodule(struct merge
        return 0;
  }
  
 -static int merge_file_1(struct merge_options *o,
 -                      const struct diff_filespec *one,
 -                      const struct diff_filespec *a,
 -                      const struct diff_filespec *b,
 -                      const char *filename,
 -                      const char *branch1,
 -                      const char *branch2,
 -                      struct merge_file_info *result)
 +static int merge_mode_and_contents(struct merge_options *o,
 +                                 const struct diff_filespec *one,
 +                                 const struct diff_filespec *a,
 +                                 const struct diff_filespec *b,
 +                                 const char *filename,
 +                                 const char *branch1,
 +                                 const char *branch2,
 +                                 struct merge_file_info *result)
  {
        result->merge = 0;
        result->clean = 1;
        return 0;
  }
  
 -static int merge_file_special_markers(struct merge_options *o,
 -                                    const struct diff_filespec *one,
 -                                    const struct diff_filespec *a,
 -                                    const struct diff_filespec *b,
 -                                    const char *target_filename,
 -                                    const char *branch1,
 -                                    const char *filename1,
 -                                    const char *branch2,
 -                                    const char *filename2,
 -                                    struct merge_file_info *mfi)
 -{
 -      char *side1 = NULL;
 -      char *side2 = NULL;
 -      int ret;
 -
 -      if (filename1)
 -              side1 = xstrfmt("%s:%s", branch1, filename1);
 -      if (filename2)
 -              side2 = xstrfmt("%s:%s", branch2, filename2);
 -
 -      ret = merge_file_1(o, one, a, b, target_filename,
 -                         side1 ? side1 : branch1,
 -                         side2 ? side2 : branch2, mfi);
 -
 -      free(side1);
 -      free(side2);
 -      return ret;
 -}
 -
 -static int merge_file_one(struct merge_options *o,
 -                        const char *path,
 -                        const struct object_id *o_oid, int o_mode,
 -                        const struct object_id *a_oid, int a_mode,
 -                        const struct object_id *b_oid, int b_mode,
 -                        const char *branch1,
 -                        const char *branch2,
 -                        struct merge_file_info *mfi)
 -{
 -      struct diff_filespec one, a, b;
 -
 -      one.path = a.path = b.path = (char *)path;
 -      oidcpy(&one.oid, o_oid);
 -      one.mode = o_mode;
 -      oidcpy(&a.oid, a_oid);
 -      a.mode = a_mode;
 -      oidcpy(&b.oid, b_oid);
 -      b.mode = b_mode;
 -      return merge_file_1(o, &one, &a, &b, path, branch1, branch2, mfi);
 -}
 -
  static int handle_rename_via_dir(struct merge_options *o,
                                 struct diff_filepair *pair,
                                 const char *rename_branch,
@@@ -1609,8 -1659,11 +1610,8 @@@ static int handle_rename_rename_1to2(st
                struct merge_file_info mfi;
                struct diff_filespec other;
                struct diff_filespec *add;
 -              if (merge_file_one(o, one->path,
 -                               &one->oid, one->mode,
 -                               &a->oid, a->mode,
 -                               &b->oid, b->mode,
 -                               ci->branch1, ci->branch2, &mfi))
 +              if (merge_mode_and_contents(o, one, a, b, one->path,
 +                                          ci->branch1, ci->branch2, &mfi))
                        return -1;
  
                /*
@@@ -1676,10 -1729,14 +1677,10 @@@ static int handle_rename_rename_2to1(st
  
        path_side_1_desc = xstrfmt("%s (was %s)", path, a->path);
        path_side_2_desc = xstrfmt("%s (was %s)", path, b->path);
 -      if (merge_file_special_markers(o, a, c1, &ci->ren1_other,
 -                                     path_side_1_desc,
 -                                     o->branch1, c1->path,
 -                                     o->branch2, ci->ren1_other.path, &mfi_c1) ||
 -          merge_file_special_markers(o, b, &ci->ren2_other, c2,
 -                                     path_side_2_desc,
 -                                     o->branch1, ci->ren2_other.path,
 -                                     o->branch2, c2->path, &mfi_c2))
 +      if (merge_mode_and_contents(o, a, c1, &ci->ren1_other, path_side_1_desc,
 +                                  o->branch1, o->branch2, &mfi_c1) ||
 +          merge_mode_and_contents(o, b, &ci->ren2_other, c2, path_side_2_desc,
 +                                  o->branch1, o->branch2, &mfi_c2))
                return -1;
        free(path_side_1_desc);
        free(path_side_2_desc);
@@@ -1756,7 -1813,7 +1757,7 @@@ static struct diff_queue_struct *get_di
        struct diff_queue_struct *ret;
        struct diff_options opts;
  
-       diff_setup(&opts);
+       repo_diff_setup(the_repository, &opts);
        opts.flags.recursive = 1;
        opts.flags.rename_empty = 0;
        opts.detect_rename = merge_detect_rename(o);
@@@ -2183,7 -2240,7 +2184,7 @@@ static struct dir_rename_entry *check_d
  {
        char *temp = xstrdup(path);
        char *end;
 -      struct dir_rename_entry *entry = NULL;;
 +      struct dir_rename_entry *entry = NULL;
  
        while ((end = strrchr(temp, '/'))) {
                *end = '\0';
@@@ -2709,23 -2766,12 +2710,23 @@@ static int process_renames(struct merge
                                       ren1_dst, branch2);
                                if (o->call_depth) {
                                        struct merge_file_info mfi;
 -                                      if (merge_file_one(o, ren1_dst, &null_oid, 0,
 -                                                         &ren1->pair->two->oid,
 -                                                         ren1->pair->two->mode,
 -                                                         &dst_other.oid,
 -                                                         dst_other.mode,
 -                                                         branch1, branch2, &mfi)) {
 +                                      struct diff_filespec one, a, b;
 +
 +                                      oidcpy(&one.oid, &null_oid);
 +                                      one.mode = 0;
 +                                      one.path = ren1->pair->two->path;
 +
 +                                      oidcpy(&a.oid, &ren1->pair->two->oid);
 +                                      a.mode = ren1->pair->two->mode;
 +                                      a.path = one.path;
 +
 +                                      oidcpy(&b.oid, &dst_other.oid);
 +                                      b.mode = dst_other.mode;
 +                                      b.path = one.path;
 +
 +                                      if (merge_mode_and_contents(o, &one, &a, &b, ren1_dst,
 +                                                                  branch1, branch2,
 +                                                                  &mfi)) {
                                                clean_merge = -1;
                                                goto cleanup_and_return;
                                        }
@@@ -2975,13 -3021,13 +2976,13 @@@ static int handle_modify_delete(struct 
                                    _("modify"), _("modified"));
  }
  
 -static int merge_content(struct merge_options *o,
 -                       const char *path,
 -                       int is_dirty,
 -                       struct object_id *o_oid, int o_mode,
 -                       struct object_id *a_oid, int a_mode,
 -                       struct object_id *b_oid, int b_mode,
 -                       struct rename_conflict_info *rename_conflict_info)
 +static int handle_content_merge(struct merge_options *o,
 +                              const char *path,
 +                              int is_dirty,
 +                              struct object_id *o_oid, int o_mode,
 +                              struct object_id *a_oid, int a_mode,
 +                              struct object_id *b_oid, int b_mode,
 +                              struct rename_conflict_info *rename_conflict_info)
  {
        const char *reason = _("content");
        const char *path1 = NULL, *path2 = NULL;
                path2 = (rename_conflict_info->pair2 ||
                         o->branch2 == rename_conflict_info->branch1) ?
                        pair1->two->path : pair1->one->path;
 +              one.path = pair1->one->path;
 +              a.path = (char *)path1;
 +              b.path = (char *)path2;
  
                if (dir_in_way(path, !o->call_depth,
                               S_ISGITLINK(pair1->two->mode)))
                        df_conflict_remains = 1;
        }
 -      if (merge_file_special_markers(o, &one, &a, &b, path,
 -                                     o->branch1, path1,
 -                                     o->branch2, path2, &mfi))
 +      if (merge_mode_and_contents(o, &one, &a, &b, path,
 +                                  o->branch1, o->branch2, &mfi))
                return -1;
  
        /*
@@@ -3113,9 -3157,9 +3114,9 @@@ static int handle_rename_normal(struct 
                                struct rename_conflict_info *ci)
  {
        /* Merge the content and write it out */
 -      return merge_content(o, path, was_dirty(o, path),
 -                           o_oid, o_mode, a_oid, a_mode, b_oid, b_mode,
 -                           ci);
 +      return handle_content_merge(o, path, was_dirty(o, path),
 +                                  o_oid, o_mode, a_oid, a_mode, b_oid, b_mode,
 +                                  ci);
  }
  
  /* Per entry merge function */
@@@ -3239,11 -3283,9 +3240,11 @@@ static int process_entry(struct merge_o
                /* Case C: Added in both (check for same permissions) and */
                /* case D: Modified in both, but differently. */
                int is_dirty = 0; /* unpack_trees would have bailed if dirty */
 -              clean_merge = merge_content(o, path, is_dirty,
 -                                          o_oid, o_mode, a_oid, a_mode, b_oid, b_mode,
 -                                          NULL);
 +              clean_merge = handle_content_merge(o, path, is_dirty,
 +                                                 o_oid, o_mode,
 +                                                 a_oid, a_mode,
 +                                                 b_oid, b_mode,
 +                                                 NULL);
        } else if (!o_oid && !a_oid && !b_oid) {
                /*
                 * this entry was deleted altogether. a_mode == 0 means
diff --combined notes-merge.c
index 5764e2b0ef06a3251d93e5535e85861ad3503fe9,13dd9ba1582b68c2a8e6083fab4b4ee86f9026c6..bd05d50b051288cb466de5afed52993a1edf3b1d
@@@ -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;
@@@ -127,7 -126,7 +127,7 @@@ static struct notes_merge_pair *diff_tr
        trace_printf("\tdiff_tree_remote(base = %.7s, remote = %.7s)\n",
               oid_to_hex(base), oid_to_hex(remote));
  
-       diff_setup(&opt);
+       repo_diff_setup(the_repository, &opt);
        opt.flags.recursive = 1;
        opt.output_format = DIFF_FORMAT_NO_OUTPUT;
        diff_setup_done(&opt);
                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);
@@@ -190,7 -189,7 +190,7 @@@ static void diff_tree_local(struct note
        trace_printf("\tdiff_tree_local(len = %i, base = %.7s, local = %.7s)\n",
               len, oid_to_hex(base), oid_to_hex(local));
  
-       diff_setup(&opt);
+       repo_diff_setup(the_repository, &opt);
        opt.flags.recursive = 1;
        opt.output_format = DIFF_FORMAT_NO_OUTPUT;
        diff_setup_done(&opt);
                        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",
@@@ -349,7 -348,8 +349,8 @@@ static int ll_merge_in_worktree(struct 
        read_mmblob(&remote, &p->remote);
  
        status = ll_merge(&result_buf, oid_to_hex(&p->obj), &base, NULL,
-                         &local, o->local_ref, &remote, o->remote_ref, NULL);
+                         &local, o->local_ref, &remote, o->remote_ref,
+                         &the_index, NULL);
  
        free(base.ptr);
        free(local.ptr);
@@@ -481,14 -481,14 +482,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 -622,14 +623,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");
@@@ -710,7 -710,7 +711,7 @@@ int notes_merge_commit(struct notes_mer
                /* write file as blob, and add to partial_tree */
                if (stat(path.buf, &st))
                        die_errno("Failed to stat '%s'", path.buf);
-               if (index_path(&blob_oid, path.buf, &st, HASH_WRITE_OBJECT))
+               if (index_path(&the_index, &blob_oid, path.buf, &st, HASH_WRITE_OBJECT))
                        die("Failed to write blob object from '%s'", path.buf);
                if (add_note(partial_tree, &obj_oid, &blob_oid, NULL))
                        die("Failed to add resolved note '%s' to notes tree",
diff --combined pack-bitmap-write.c
index fc82f37a02772244ee93aee41bef9238075c07ba,198fd13097a7e45c0cf04495b39f7f5c11a47cb3..f2fd9d81ef6a95612f86a05ce4eb183436d7bab8
@@@ -11,7 -11,6 +11,7 @@@
  #include "pack-bitmap.h"
  #include "sha1-lookup.h"
  #include "pack-objects.h"
 +#include "commit-reach.h"
  
  struct bitmapped_commit {
        struct commit *commit;
@@@ -262,7 -261,7 +262,7 @@@ void bitmap_writer_build(struct packing
        if (writer.show_progress)
                writer.progress = start_progress("Building bitmaps", writer.selected_nr);
  
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
        revs.tag_objects = 1;
        revs.tree_objects = 1;
        revs.blob_objects = 1;
diff --combined patch-ids.c
index 960ea2405412cc5100e1bda4cb179248d04284df,7da86047d926694775756c601f96362bf8a8490c..c262e1be9c9c912cc12c5b60a08e69f8cf9a30c9
@@@ -28,14 -28,14 +28,14 @@@ int commit_patch_id(struct commit *comm
  /*
   * When we cannot load the full patch-id for both commits for whatever
   * reason, the function returns -1 (i.e. return error(...)). Despite
 - * the "cmp" in the name of this function, the caller only cares about
 + * the "neq" in the name of this function, the caller only cares about
   * the return value being zero (a and b are equivalent) or non-zero (a
   * and b are different), and returning non-zero would keep both in the
   * result, even if they actually were equivalent, in order to err on
   * the side of safety.  The actual value being negative does not have
   * any significance; only that it is non-zero matters.
   */
 -static int patch_id_cmp(const void *cmpfn_data,
 +static int patch_id_neq(const void *cmpfn_data,
                        const void *entry,
                        const void *entry_or_key,
                        const void *unused_keydata)
            commit_patch_id(b->commit, opt, &b->patch_id, 0))
                return error("Could not get patch ID for %s",
                        oid_to_hex(&b->commit->object.oid));
 -      return oidcmp(&a->patch_id, &b->patch_id);
 +      return !oideq(&a->patch_id, &b->patch_id);
  }
  
- int init_patch_ids(struct patch_ids *ids)
+ int init_patch_ids(struct repository *r, struct patch_ids *ids)
  {
        memset(ids, 0, sizeof(*ids));
-       diff_setup(&ids->diffopts);
+       repo_diff_setup(r, &ids->diffopts);
        ids->diffopts.detect_rename = 0;
        ids->diffopts.flags.recursive = 1;
        diff_setup_done(&ids->diffopts);
 -      hashmap_init(&ids->patches, patch_id_cmp, &ids->diffopts, 256);
 +      hashmap_init(&ids->patches, patch_id_neq, &ids->diffopts, 256);
        return 0;
  }
  
diff --combined read-cache.c
index 8d04d78a5877aab74dd35e24a31bcfe3e0a3417d,b707edd044d7234ec5a2569ba227b01c5a3290eb..01859b77036e00eba1ab04b02ad6bf77cfb0da51
@@@ -205,15 -205,17 +205,17 @@@ void fill_stat_cache_info(struct cache_
        }
  }
  
- static int ce_compare_data(const struct cache_entry *ce, struct stat *st)
+ static int ce_compare_data(struct index_state *istate,
+                          const struct cache_entry *ce,
+                          struct stat *st)
  {
        int match = -1;
        int fd = git_open_cloexec(ce->name, O_RDONLY);
  
        if (fd >= 0) {
                struct object_id oid;
-               if (!index_fd(&oid, fd, st, OBJ_BLOB, ce->name, 0))
+               if (!index_fd(istate, &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,14 -256,16 +256,16 @@@ 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)
+ static int ce_modified_check_fs(struct index_state *istate,
+                               const struct cache_entry *ce,
+                               struct stat *st)
  {
        switch (st->st_mode & S_IFMT) {
        case S_IFREG:
-               if (ce_compare_data(ce, st))
+               if (ce_compare_data(istate, ce, st))
                        return DATA_CHANGED;
                break;
        case S_IFLNK:
@@@ -407,7 -411,7 +411,7 @@@ int ie_match_stat(struct index_state *i
                if (assume_racy_is_modified)
                        changed |= DATA_CHANGED;
                else
-                       changed |= ce_modified_check_fs(ce, st);
+                       changed |= ce_modified_check_fs(istate, ce, st);
        }
  
        return changed;
@@@ -447,7 -451,7 +451,7 @@@ int ie_modified(struct index_state *ist
            (S_ISGITLINK(ce->ce_mode) || ce->ce_stat_data.sd_size != 0))
                return changed;
  
-       changed_fs = ce_modified_check_fs(ce, st);
+       changed_fs = ce_modified_check_fs(istate, ce, st);
        if (changed_fs)
                return changed | changed_fs;
        return 0;
@@@ -753,7 -757,7 +757,7 @@@ int add_to_index(struct index_state *is
                }
        }
        if (!intent_only) {
-               if (index_path(&ce->oid, path, st, newflags)) {
+               if (index_path(istate, &ce->oid, path, st, newflags)) {
                        discard_cache_entry(ce);
                        return error("unable to index file %s", path);
                }
        /* 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)
@@@ -823,7 -827,7 +827,7 @@@ struct cache_entry *make_cache_entry(st
        ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
  
-       ret = refresh_cache_entry(&the_index, ce, refresh_options);
+       ret = refresh_cache_entry(istate, ce, refresh_options);
        if (ret != ce)
                discard_cache_entry(ce);
        return ret;
@@@ -1476,8 -1480,8 +1480,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");
                if (ignore_submodules && S_ISGITLINK(ce->ce_mode))
                        continue;
  
-               if (pathspec && !ce_path_match(&the_index, ce, pathspec, seen))
+               if (pathspec && !ce_path_match(istate, ce, pathspec, seen))
                        filtered = 1;
  
                if (ce_stage(ce)) {
  
                replace_index_entry(istate, i, new_entry);
        }
 -      trace_performance_since(start, "refresh index");
 +      trace_performance_leave("refresh index");
        return has_errors;
  }
  
@@@ -1668,7 -1672,7 +1672,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 -2006,7 +2006,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;
  }
  
@@@ -2123,7 -2126,7 +2127,7 @@@ int unmerged_index(const struct index_s
        return 0;
  }
  
- int index_has_changes(const struct index_state *istate,
+ int index_has_changes(struct index_state *istate,
                      struct tree *tree,
                      struct strbuf *sb)
  {
        if (tree || !get_oid_tree("HEAD", &cmp)) {
                struct diff_options opt;
  
-               diff_setup(&opt);
+               repo_diff_setup(the_repository, &opt);
                opt.flags.exit_with_status = 1;
                if (!sb)
                        opt.flags.quick = 1;
@@@ -2231,7 -2234,8 +2235,8 @@@ static int ce_flush(git_hash_ctx *conte
        return (write_in_full(fd, write_buffer, left) < 0) ? -1 : 0;
  }
  
- static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
+ static void ce_smudge_racily_clean_entry(struct index_state *istate,
+                                        struct cache_entry *ce)
  {
        /*
         * The only thing we care about in this function is to smudge the
                return;
        if (ce_match_stat_basic(ce, &st))
                return;
-       if (ce_modified_check_fs(ce, &st)) {
+       if (ce_modified_check_fs(istate, ce, &st)) {
                /* This is "racily clean"; smudge it.  Note that this
                 * is a tricky code.  At first glance, it may appear
                 * that it can break with this sequence:
@@@ -2396,7 -2400,7 +2401,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);
@@@ -2495,7 -2499,7 +2500,7 @@@ static int do_write_index(struct index_
                if (ce->ce_flags & CE_REMOVE)
                        continue;
                if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce))
-                       ce_smudge_racily_clean_entry(ce);
+                       ce_smudge_racily_clean_entry(istate, ce);
                if (is_null_oid(&ce->oid)) {
                        static const char msg[] = "cache entry has null sha1: %s";
                        static int allow = -1;
@@@ -2744,9 -2748,6 +2749,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 -2944,6 +2948,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 ref-filter.c
index e1bcb4ca8a1977e97b26da47962dfcd3781a021e,f081a290cb2e246d7774f2cbb266fcd4781280c6..2a056192117b0d119dcd4cf9da0de982a0444b33
@@@ -19,7 -19,6 +19,7 @@@
  #include "wt-status.h"
  #include "commit-slab.h"
  #include "commit-graph.h"
 +#include "commit-reach.h"
  
  static struct ref_msg {
        const char *gone;
@@@ -264,8 -263,6 +264,8 @@@ static int trailers_atom_parser(const s
        struct string_list params = STRING_LIST_INIT_DUP;
        int i;
  
 +      atom->u.contents.trailer_opts.no_divider = 1;
 +
        if (arg) {
                string_list_split(&params, arg, ',', -1);
                for (i = 0; i < params.nr; i++) {
@@@ -1676,6 -1673,144 +1676,6 @@@ static int get_ref_atom_value(struct re
        return 0;
  }
  
 -/*
 - * Unknown has to be "0" here, because that's the default value for
 - * contains_cache slab entries that have not yet been assigned.
 - */
 -enum contains_result {
 -      CONTAINS_UNKNOWN = 0,
 -      CONTAINS_NO,
 -      CONTAINS_YES
 -};
 -
 -define_commit_slab(contains_cache, enum contains_result);
 -
 -struct ref_filter_cbdata {
 -      struct ref_array *array;
 -      struct ref_filter *filter;
 -      struct contains_cache contains_cache;
 -      struct contains_cache no_contains_cache;
 -};
 -
 -/*
 - * Mimicking the real stack, this stack lives on the heap, avoiding stack
 - * overflows.
 - *
 - * At each recursion step, the stack items points to the commits whose
 - * ancestors are to be inspected.
 - */
 -struct contains_stack {
 -      int nr, alloc;
 -      struct contains_stack_entry {
 -              struct commit *commit;
 -              struct commit_list *parents;
 -      } *contains_stack;
 -};
 -
 -static int in_commit_list(const struct commit_list *want, struct commit *c)
 -{
 -      for (; want; want = want->next)
 -              if (!oidcmp(&want->item->object.oid, &c->object.oid))
 -                      return 1;
 -      return 0;
 -}
 -
 -/*
 - * Test whether the candidate is contained in the list.
 - * Do not recurse to find out, though, but return -1 if inconclusive.
 - */
 -static enum contains_result contains_test(struct commit *candidate,
 -                                        const struct commit_list *want,
 -                                        struct contains_cache *cache,
 -                                        uint32_t cutoff)
 -{
 -      enum contains_result *cached = contains_cache_at(cache, candidate);
 -
 -      /* If we already have the answer cached, return that. */
 -      if (*cached)
 -              return *cached;
 -
 -      /* or are we it? */
 -      if (in_commit_list(want, candidate)) {
 -              *cached = CONTAINS_YES;
 -              return CONTAINS_YES;
 -      }
 -
 -      /* Otherwise, we don't know; prepare to recurse */
 -      parse_commit_or_die(candidate);
 -
 -      if (candidate->generation < cutoff)
 -              return CONTAINS_NO;
 -
 -      return CONTAINS_UNKNOWN;
 -}
 -
 -static void push_to_contains_stack(struct commit *candidate, struct contains_stack *contains_stack)
 -{
 -      ALLOC_GROW(contains_stack->contains_stack, contains_stack->nr + 1, contains_stack->alloc);
 -      contains_stack->contains_stack[contains_stack->nr].commit = candidate;
 -      contains_stack->contains_stack[contains_stack->nr++].parents = candidate->parents;
 -}
 -
 -static enum contains_result contains_tag_algo(struct commit *candidate,
 -                                            const struct commit_list *want,
 -                                            struct contains_cache *cache)
 -{
 -      struct contains_stack contains_stack = { 0, 0, NULL };
 -      enum contains_result result;
 -      uint32_t cutoff = GENERATION_NUMBER_INFINITY;
 -      const struct commit_list *p;
 -
 -      for (p = want; p; p = p->next) {
 -              struct commit *c = p->item;
 -              load_commit_graph_info(the_repository, c);
 -              if (c->generation < cutoff)
 -                      cutoff = c->generation;
 -      }
 -
 -      result = contains_test(candidate, want, cache, cutoff);
 -      if (result != CONTAINS_UNKNOWN)
 -              return result;
 -
 -      push_to_contains_stack(candidate, &contains_stack);
 -      while (contains_stack.nr) {
 -              struct contains_stack_entry *entry = &contains_stack.contains_stack[contains_stack.nr - 1];
 -              struct commit *commit = entry->commit;
 -              struct commit_list *parents = entry->parents;
 -
 -              if (!parents) {
 -                      *contains_cache_at(cache, commit) = CONTAINS_NO;
 -                      contains_stack.nr--;
 -              }
 -              /*
 -               * If we just popped the stack, parents->item has been marked,
 -               * therefore contains_test will return a meaningful yes/no.
 -               */
 -              else switch (contains_test(parents->item, want, cache, cutoff)) {
 -              case CONTAINS_YES:
 -                      *contains_cache_at(cache, commit) = CONTAINS_YES;
 -                      contains_stack.nr--;
 -                      break;
 -              case CONTAINS_NO:
 -                      entry->parents = parents->next;
 -                      break;
 -              case CONTAINS_UNKNOWN:
 -                      push_to_contains_stack(parents->item, &contains_stack);
 -                      break;
 -              }
 -      }
 -      free(contains_stack.contains_stack);
 -      return contains_test(candidate, want, cache, cutoff);
 -}
 -
 -static int commit_contains(struct ref_filter *filter, struct commit *commit,
 -                         struct commit_list *list, struct contains_cache *cache)
 -{
 -      if (filter->with_commit_tag_algo)
 -              return contains_tag_algo(commit, list, cache) == CONTAINS_YES;
 -      return is_descendant_of(commit, list);
 -}
 -
  /*
   * Return 1 if the refname matches one of the patterns, otherwise 0.
   * A pattern can be a literal prefix (e.g. a refname "refs/heads/master"
@@@ -1911,13 -2046,6 +1911,13 @@@ static int filter_ref_kind(struct ref_f
        return ref_kind_from_refname(refname);
  }
  
 +struct ref_filter_cbdata {
 +      struct ref_array *array;
 +      struct ref_filter *filter;
 +      struct contains_cache contains_cache;
 +      struct contains_cache no_contains_cache;
 +};
 +
  /*
   * A call-back given to for_each_ref().  Filter refs and keep them for
   * later object processing.
@@@ -2010,7 -2138,7 +2010,7 @@@ static void do_merge_filter(struct ref_
        struct ref_array *array = ref_cbdata->array;
        struct commit **to_clear = xcalloc(sizeof(struct commit *), array->nr);
  
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
  
        for (i = 0; i < array->nr; i++) {
                struct ref_array_item *item = array->items[i];
diff --combined remote.c
index 682f2a01f949ce942597a9190cecfc991db0108e,348417f0a768c0c93d583044c649eda93eb47a76..81f4f01b00715b38f0d10fc03fad75f17aa1cf47
+++ 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.
@@@ -1855,7 -1903,7 +1855,7 @@@ int stat_tracking_info(struct branch *b
                         oid_to_hex(&theirs->object.oid));
        argv_array_push(&argv, "--");
  
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
        setup_revisions(argv.argc, argv.argv, &revs, NULL);
        if (prepare_revision_walk(&revs))
                die("revision walk setup failed");
@@@ -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 rerere.c
index 7aa149e849775f110231a54cda7b71f60e75cb4f,8d4ac8426be80ed9dd8721db883c75fbb9630621..887e26d45bfa1071736ef016d82c69de90b14f8d
+++ b/rerere.c
@@@ -213,7 -213,7 +213,7 @@@ static void read_rr(struct string_list 
  
                /* There has to be the hash, tab, path and then NUL */
                if (buf.len < 42 || get_sha1_hex(buf.buf, sha1))
 -                      die("corrupt MERGE_RR");
 +                      die(_("corrupt MERGE_RR"));
  
                if (buf.buf[40] != '.') {
                        variant = 0;
                        errno = 0;
                        variant = strtol(buf.buf + 41, &path, 10);
                        if (errno)
 -                              die("corrupt MERGE_RR");
 +                              die(_("corrupt MERGE_RR"));
                }
                if (*(path++) != '\t')
 -                      die("corrupt MERGE_RR");
 +                      die(_("corrupt MERGE_RR"));
                buf.buf[40] = '\0';
                id = new_rerere_id_hex(buf.buf);
                id->variant = variant;
@@@ -260,12 -260,12 +260,12 @@@ static int write_rr(struct string_list 
                                    rr->items[i].string, 0);
  
                if (write_in_full(out_fd, buf.buf, buf.len) < 0)
 -                      die("unable to write rerere record");
 +                      die(_("unable to write rerere record"));
  
                strbuf_release(&buf);
        }
        if (commit_lock_file(&write_lock) != 0)
 -              die("unable to write rerere record");
 +              die(_("unable to write rerere record"));
        return 0;
  }
  
@@@ -303,6 -303,38 +303,6 @@@ static void rerere_io_putstr(const cha
                ferr_puts(str, io->output, &io->wrerror);
  }
  
 -/*
 - * Write a conflict marker to io->output (if defined).
 - */
 -static void rerere_io_putconflict(int ch, int size, struct rerere_io *io)
 -{
 -      char buf[64];
 -
 -      while (size) {
 -              if (size <= sizeof(buf) - 2) {
 -                      memset(buf, ch, size);
 -                      buf[size] = '\n';
 -                      buf[size + 1] = '\0';
 -                      size = 0;
 -              } else {
 -                      int sz = sizeof(buf) - 1;
 -
 -                      /*
 -                       * Make sure we will not write everything out
 -                       * in this round by leaving at least 1 byte
 -                       * for the next round, giving the next round
 -                       * a chance to add the terminating LF.  Yuck.
 -                       */
 -                      if (size <= sz)
 -                              sz -= (sz - size) + 1;
 -                      memset(buf, ch, sz);
 -                      buf[sz] = '\0';
 -                      size -= sz;
 -              }
 -              rerere_io_putstr(buf, io);
 -      }
 -}
 -
  static void rerere_io_putmem(const char *mem, size_t sz, struct rerere_io *io)
  {
        if (io->output)
@@@ -353,154 -385,135 +353,155 @@@ static int is_cmarker(char *buf, int ma
        return isspace(*buf);
  }
  
 -/*
 - * Read contents a file with conflicts, normalize the conflicts
 - * by (1) discarding the common ancestor version in diff3-style,
 - * (2) reordering our side and their side so that whichever sorts
 - * alphabetically earlier comes before the other one, while
 - * computing the "conflict ID", which is just an SHA-1 hash of
 - * one side of the conflict, NUL, the other side of the conflict,
 - * and NUL concatenated together.
 - *
 - * Return the number of conflict hunks found.
 - *
 - * NEEDSWORK: the logic and theory of operation behind this conflict
 - * normalization may deserve to be documented somewhere, perhaps in
 - * Documentation/technical/rerere.txt.
 - */
 -static int handle_path(unsigned char *sha1, struct rerere_io *io, int marker_size)
 +static void rerere_strbuf_putconflict(struct strbuf *buf, int ch, size_t size)
 +{
 +      strbuf_addchars(buf, ch, size);
 +      strbuf_addch(buf, '\n');
 +}
 +
 +static int handle_conflict(struct strbuf *out, struct rerere_io *io,
 +                         int marker_size, git_SHA_CTX *ctx)
  {
 -      git_SHA_CTX ctx;
 -      int hunk_no = 0;
        enum {
 -              RR_CONTEXT = 0, RR_SIDE_1, RR_SIDE_2, RR_ORIGINAL
 -      } hunk = RR_CONTEXT;
 +              RR_SIDE_1 = 0, RR_SIDE_2, RR_ORIGINAL
 +      } hunk = RR_SIDE_1;
        struct strbuf one = STRBUF_INIT, two = STRBUF_INIT;
 -      struct strbuf buf = STRBUF_INIT;
 -
 -      if (sha1)
 -              git_SHA1_Init(&ctx);
 +      struct strbuf buf = STRBUF_INIT, conflict = STRBUF_INIT;
 +      int has_conflicts = -1;
  
        while (!io->getline(&buf, io)) {
                if (is_cmarker(buf.buf, '<', marker_size)) {
 -                      if (hunk != RR_CONTEXT)
 -                              goto bad;
 -                      hunk = RR_SIDE_1;
 +                      if (handle_conflict(&conflict, io, marker_size, NULL) < 0)
 +                              break;
 +                      if (hunk == RR_SIDE_1)
 +                              strbuf_addbuf(&one, &conflict);
 +                      else
 +                              strbuf_addbuf(&two, &conflict);
 +                      strbuf_release(&conflict);
                } else if (is_cmarker(buf.buf, '|', marker_size)) {
                        if (hunk != RR_SIDE_1)
 -                              goto bad;
 +                              break;
                        hunk = RR_ORIGINAL;
                } else if (is_cmarker(buf.buf, '=', marker_size)) {
                        if (hunk != RR_SIDE_1 && hunk != RR_ORIGINAL)
 -                              goto bad;
 +                              break;
                        hunk = RR_SIDE_2;
                } else if (is_cmarker(buf.buf, '>', marker_size)) {
                        if (hunk != RR_SIDE_2)
 -                              goto bad;
 +                              break;
                        if (strbuf_cmp(&one, &two) > 0)
                                strbuf_swap(&one, &two);
 -                      hunk_no++;
 -                      hunk = RR_CONTEXT;
 -                      rerere_io_putconflict('<', marker_size, io);
 -                      rerere_io_putmem(one.buf, one.len, io);
 -                      rerere_io_putconflict('=', marker_size, io);
 -                      rerere_io_putmem(two.buf, two.len, io);
 -                      rerere_io_putconflict('>', marker_size, io);
 -                      if (sha1) {
 -                              git_SHA1_Update(&ctx, one.buf ? one.buf : "",
 +                      has_conflicts = 1;
 +                      rerere_strbuf_putconflict(out, '<', marker_size);
 +                      strbuf_addbuf(out, &one);
 +                      rerere_strbuf_putconflict(out, '=', marker_size);
 +                      strbuf_addbuf(out, &two);
 +                      rerere_strbuf_putconflict(out, '>', marker_size);
 +                      if (ctx) {
 +                              git_SHA1_Update(ctx, one.buf ? one.buf : "",
                                            one.len + 1);
 -                              git_SHA1_Update(&ctx, two.buf ? two.buf : "",
 +                              git_SHA1_Update(ctx, two.buf ? two.buf : "",
                                            two.len + 1);
                        }
 -                      strbuf_reset(&one);
 -                      strbuf_reset(&two);
 +                      break;
                } else if (hunk == RR_SIDE_1)
                        strbuf_addbuf(&one, &buf);
                else if (hunk == RR_ORIGINAL)
                        ; /* discard */
                else if (hunk == RR_SIDE_2)
                        strbuf_addbuf(&two, &buf);
 -              else
 -                      rerere_io_putstr(buf.buf, io);
 -              continue;
 -      bad:
 -              hunk = 99; /* force error exit */
 -              break;
        }
        strbuf_release(&one);
        strbuf_release(&two);
        strbuf_release(&buf);
  
 +      return has_conflicts;
 +}
 +
 +/*
 + * Read contents a file with conflicts, normalize the conflicts
 + * by (1) discarding the common ancestor version in diff3-style,
 + * (2) reordering our side and their side so that whichever sorts
 + * alphabetically earlier comes before the other one, while
 + * computing the "conflict ID", which is just an SHA-1 hash of
 + * one side of the conflict, NUL, the other side of the conflict,
 + * and NUL concatenated together.
 + *
 + * Return 1 if conflict hunks are found, 0 if there are no conflict
 + * hunks and -1 if an error occured.
 + */
 +static int handle_path(unsigned char *sha1, struct rerere_io *io, int marker_size)
 +{
 +      git_SHA_CTX ctx;
 +      struct strbuf buf = STRBUF_INIT, out = STRBUF_INIT;
 +      int has_conflicts = 0;
 +      if (sha1)
 +              git_SHA1_Init(&ctx);
 +
 +      while (!io->getline(&buf, io)) {
 +              if (is_cmarker(buf.buf, '<', marker_size)) {
 +                      has_conflicts = handle_conflict(&out, io, marker_size,
 +                                                      sha1 ? &ctx : NULL);
 +                      if (has_conflicts < 0)
 +                              break;
 +                      rerere_io_putmem(out.buf, out.len, io);
 +                      strbuf_reset(&out);
 +              } else
 +                      rerere_io_putstr(buf.buf, io);
 +      }
 +      strbuf_release(&buf);
 +      strbuf_release(&out);
 +
        if (sha1)
                git_SHA1_Final(sha1, &ctx);
 -      if (hunk != RR_CONTEXT)
 -              return -1;
 -      return hunk_no;
 +
 +      return has_conflicts;
  }
  
  /*
   * Scan the path for conflicts, do the "handle_path()" thing above, and
   * return the number of conflict hunks found.
   */
- static int handle_file(const char *path, unsigned char *sha1, const char *output)
+ static int handle_file(struct index_state *istate, const char *path,
+                      unsigned char *sha1, const char *output)
  {
 -      int hunk_no = 0;
 +      int has_conflicts = 0;
        struct rerere_io_file io;
-       int marker_size = ll_merge_marker_size(path);
+       int marker_size = ll_merge_marker_size(istate, path);
  
        memset(&io, 0, sizeof(io));
        io.io.getline = rerere_file_getline;
        io.input = fopen(path, "r");
        io.io.wrerror = 0;
        if (!io.input)
 -              return error_errno("Could not open %s", path);
 +              return error_errno(_("could not open '%s'"), path);
  
        if (output) {
                io.io.output = fopen(output, "w");
                if (!io.io.output) {
 -                      error_errno("Could not write %s", output);
 +                      error_errno(_("could not write '%s'"), output);
                        fclose(io.input);
                        return -1;
                }
        }
  
 -      hunk_no = handle_path(sha1, (struct rerere_io *)&io, marker_size);
 +      has_conflicts = handle_path(sha1, (struct rerere_io *)&io, marker_size);
  
        fclose(io.input);
        if (io.io.wrerror)
 -              error("There were errors while writing %s (%s)",
 +              error(_("there were errors while writing '%s' (%s)"),
                      path, strerror(io.io.wrerror));
        if (io.io.output && fclose(io.io.output))
 -              io.io.wrerror = error_errno("Failed to flush %s", path);
 +              io.io.wrerror = error_errno(_("failed to flush '%s'"), path);
  
 -      if (hunk_no < 0) {
 +      if (has_conflicts < 0) {
                if (output)
                        unlink_or_warn(output);
 -              return error("Could not parse conflict hunks in %s", path);
 +              return error(_("could not parse conflict hunks in '%s'"), path);
        }
        if (io.io.wrerror)
                return -1;
 -      return hunk_no;
 +      return has_conflicts;
  }
  
  /*
   * stages we have already looked at in this invocation of this
   * function.
   */
- static int check_one_conflict(int i, int *type)
+ static int check_one_conflict(struct index_state *istate, int i, int *type)
  {
-       const struct cache_entry *e = active_cache[i];
+       const struct cache_entry *e = istate->cache[i];
  
        if (!ce_stage(e)) {
                *type = RESOLVED;
        }
  
        *type = PUNTED;
-       while (i < active_nr && ce_stage(active_cache[i]) == 1)
 -      while (ce_stage(istate->cache[i]) == 1)
++      while (i < istate->cache_nr && ce_stage(istate->cache[i]) == 1)
                i++;
  
        /* Only handle regular files with both stages #2 and #3 */
-       if (i + 1 < active_nr) {
-               const struct cache_entry *e2 = active_cache[i];
-               const struct cache_entry *e3 = active_cache[i + 1];
+       if (i + 1 < istate->cache_nr) {
+               const struct cache_entry *e2 = istate->cache[i];
+               const struct cache_entry *e3 = istate->cache[i + 1];
                if (ce_stage(e2) == 2 &&
                    ce_stage(e3) == 3 &&
                    ce_same_name(e, e3) &&
        }
  
        /* Skip the entries with the same name */
-       while (i < active_nr && ce_same_name(e, active_cache[i]))
+       while (i < istate->cache_nr && ce_same_name(e, istate->cache[i]))
                i++;
        return i;
  }
   * are identical to the previous round, might want to be handled,
   * though.
   */
- static int find_conflict(struct string_list *conflict)
+ static int find_conflict(struct repository *r, struct string_list *conflict)
  {
        int i;
-       if (read_cache() < 0)
+       if (read_index(r->index) < 0)
 -              return error("Could not read index");
 +              return error(_("index file corrupt"));
  
-       for (i = 0; i < active_nr;) {
+       for (i = 0; i < r->index->cache_nr;) {
                int conflict_type;
-               const struct cache_entry *e = active_cache[i];
-               i = check_one_conflict(i, &conflict_type);
+               const struct cache_entry *e = r->index->cache[i];
+               i = check_one_conflict(r->index, i, &conflict_type);
                if (conflict_type == THREE_STAGED)
                        string_list_insert(conflict, (const char *)e->name);
        }
   * NEEDSWORK: we may want to fix the caller that implements "rerere
   * remaining" to do this without abusing merge_rr.
   */
- int rerere_remaining(struct string_list *merge_rr)
+ int rerere_remaining(struct repository *r, struct string_list *merge_rr)
  {
        int i;
        if (setup_rerere(merge_rr, RERERE_READONLY))
                return 0;
-       if (read_cache() < 0)
+       if (read_index(r->index) < 0)
 -              return error("Could not read index");
 +              return error(_("index file corrupt"));
  
-       for (i = 0; i < active_nr;) {
+       for (i = 0; i < r->index->cache_nr;) {
                int conflict_type;
-               const struct cache_entry *e = active_cache[i];
-               i = check_one_conflict(i, &conflict_type);
+               const struct cache_entry *e = r->index->cache[i];
+               i = check_one_conflict(r->index, i, &conflict_type);
                if (conflict_type == PUNTED)
                        string_list_insert(merge_rr, (const char *)e->name);
                else if (conflict_type == RESOLVED) {
   * if that recorded conflict resolves cleanly what we
   * got in the "cur".
   */
- static int try_merge(const struct rerere_id *id, const char *path,
+ static int try_merge(struct index_state *istate,
+                    const struct rerere_id *id, const char *path,
                     mmfile_t *cur, mmbuffer_t *result)
  {
        int ret;
                 * A three-way merge. Note that this honors user-customizable
                 * low-level merge driver settings.
                 */
-               ret = ll_merge(result, path, &base, NULL, cur, "", &other, "", NULL);
+               ret = ll_merge(result, path, &base, NULL, cur, "", &other, "",
+                              istate, NULL);
  
        free(base.ptr);
        free(other.ptr);
   * Returns 0 for successful replay of recorded resolution, or non-zero
   * for failure.
   */
- static int merge(const struct rerere_id *id, const char *path)
+ static int merge(struct index_state *istate, const struct rerere_id *id, const char *path)
  {
        FILE *f;
        int ret;
         * Normalize the conflicts in path and write it out to
         * "thisimage" temporary file.
         */
-       if ((handle_file(path, NULL, rerere_path(id, "thisimage")) < 0) ||
+       if ((handle_file(istate, path, NULL, rerere_path(id, "thisimage")) < 0) ||
            read_mmfile(&cur, rerere_path(id, "thisimage"))) {
                ret = 1;
                goto out;
        }
  
-       ret = try_merge(id, path, &cur, &result);
+       ret = try_merge(istate, id, path, &cur, &result);
        if (ret)
                goto out;
  
         * Mark that "postimage" was used to help gc.
         */
        if (utime(rerere_path(id, "postimage"), NULL) < 0)
 -              warning_errno("failed utime() on %s",
 +              warning_errno(_("failed utime() on '%s'"),
                              rerere_path(id, "postimage"));
  
        /* Update "path" with the resolution */
        f = fopen(path, "w");
        if (!f)
 -              return error_errno("Could not open %s", path);
 +              return error_errno(_("could not open '%s'"), path);
        if (fwrite(result.ptr, result.size, 1, f) != 1)
 -              error_errno("Could not write %s", path);
 +              error_errno(_("could not write '%s'"), path);
        if (fclose(f))
 -              return error_errno("Writing %s failed", path);
 +              return error_errno(_("writing '%s' failed"), path);
  
  out:
        free(cur.ptr);
        return ret;
  }
  
- static void update_paths(struct string_list *update)
+ static void update_paths(struct repository *r, struct string_list *update)
  {
        struct lock_file index_lock = LOCK_INIT;
        int i;
  
        for (i = 0; i < update->nr; i++) {
                struct string_list_item *item = &update->items[i];
-               if (add_file_to_cache(item->string, 0))
+               if (add_file_to_index(r->index, item->string, 0))
                        exit(128);
 -              fprintf(stderr, "Staged '%s' using previous resolution.\n",
 +              fprintf_ln(stderr, _("Staged '%s' using previous resolution."),
                        item->string);
        }
  
-       if (write_locked_index(&the_index, &index_lock,
+       if (write_locked_index(r->index, &index_lock,
                               COMMIT_LOCK | SKIP_IF_UNCHANGED))
 -              die("Unable to write new index file");
 +              die(_("unable to write new index file"));
  }
  
  static void remove_variant(struct rerere_id *id)
   * only have the preimage for that conflict, in which case the result
   * needs to be recorded as a resolution in a postimage file.
   */
- static void do_rerere_one_path(struct string_list_item *rr_item,
+ static void do_rerere_one_path(struct index_state *istate,
+                              struct string_list_item *rr_item,
                               struct string_list *update)
  {
        const char *path = rr_item->string;
  
        /* Has the user resolved it already? */
        if (variant >= 0) {
-               if (!handle_file(path, NULL, NULL)) {
+               if (!handle_file(istate, path, NULL, NULL)) {
                        copy_file(rerere_path(id, "postimage"), path, 0666);
                        id->collection->status[variant] |= RR_HAS_POSTIMAGE;
 -                      fprintf(stderr, "Recorded resolution for '%s'.\n", path);
 +                      fprintf_ln(stderr, _("Recorded resolution for '%s'."), path);
                        free_rerere_id(rr_item);
                        rr_item->util = NULL;
                        return;
                        continue;
  
                vid.variant = variant;
-               if (merge(&vid, path))
+               if (merge(istate, &vid, path))
                        continue; /* failed to replay */
  
                /*
                if (rerere_autoupdate)
                        string_list_insert(update, path);
                else
 -                      fprintf(stderr,
 -                              "Resolved '%s' using previous resolution.\n",
 -                              path);
 +                      fprintf_ln(stderr,
 +                                 _("Resolved '%s' using previous resolution."),
 +                                 path);
                free_rerere_id(rr_item);
                rr_item->util = NULL;
                return;
        assign_variant(id);
  
        variant = id->variant;
-       handle_file(path, NULL, rerere_path(id, "preimage"));
+       handle_file(istate, path, NULL, rerere_path(id, "preimage"));
        if (id->collection->status[variant] & RR_HAS_POSTIMAGE) {
                const char *path = rerere_path(id, "postimage");
                if (unlink(path))
 -                      die_errno("cannot unlink stray '%s'", path);
 +                      die_errno(_("cannot unlink stray '%s'"), path);
                id->collection->status[variant] &= ~RR_HAS_POSTIMAGE;
        }
        id->collection->status[variant] |= RR_HAS_PREIMAGE;
 -      fprintf(stderr, "Recorded preimage for '%s'\n", path);
 +      fprintf_ln(stderr, _("Recorded preimage for '%s'"), path);
  }
  
- static int do_plain_rerere(struct string_list *rr, int fd)
+ static int do_plain_rerere(struct repository *r,
+                          struct string_list *rr, int fd)
  {
        struct string_list conflict = STRING_LIST_INIT_DUP;
        struct string_list update = STRING_LIST_INIT_DUP;
        int i;
  
-       find_conflict(&conflict);
+       find_conflict(r, &conflict);
  
        /*
         * MERGE_RR records paths with conflicts immediately after
                const char *path = conflict.items[i].string;
                int ret;
  
 -              if (string_list_has_string(rr, path))
 -                      continue;
 -
                /*
                 * Ask handle_file() to scan and assign a
                 * conflict ID.  No need to write anything out
                 * yet.
                 */
-               ret = handle_file(path, sha1, NULL);
+               ret = handle_file(r->index, path, sha1, NULL);
 +              if (ret != 0 && string_list_has_string(rr, path)) {
 +                      remove_variant(string_list_lookup(rr, path)->util);
 +                      string_list_remove(rr, path, 1);
 +              }
                if (ret < 1)
                        continue;
  
        }
  
        for (i = 0; i < rr->nr; i++)
-               do_rerere_one_path(&rr->items[i], &update);
+               do_rerere_one_path(r->index, &rr->items[i], &update);
  
        if (update.nr)
-               update_paths(&update);
+               update_paths(r, &update);
  
        return write_rr(rr, fd);
  }
@@@ -868,7 -886,7 +875,7 @@@ static int is_rerere_enabled(void
                return rr_cache_exists;
  
        if (!rr_cache_exists && mkdir_in_gitdir(git_path_rr_cache()))
 -              die("Could not create directory %s", git_path_rr_cache());
 +              die(_("could not create directory '%s'"), git_path_rr_cache());
        return 1;
  }
  
@@@ -897,7 -915,7 +904,7 @@@ int setup_rerere(struct string_list *me
   * perform mergy operations, possibly leaving conflicted index entries
   * and working tree files.
   */
- int rerere(int flags)
+ int repo_rerere(struct repository *r, int flags)
  {
        struct string_list merge_rr = STRING_LIST_INIT_DUP;
        int fd, status;
        fd = setup_rerere(&merge_rr, flags);
        if (fd < 0)
                return 0;
-       status = do_plain_rerere(&merge_rr, fd);
+       status = do_plain_rerere(r, &merge_rr, fd);
        free_rerere_dirs();
        return status;
  }
@@@ -942,29 -960,30 +949,30 @@@ static int rerere_mem_getline(struct st
        return 0;
  }
  
- static int handle_cache(const char *path, unsigned char *sha1, const char *output)
+ static int handle_cache(struct index_state *istate, const char *path,
+                       unsigned char *sha1, const char *output)
  {
        mmfile_t mmfile[3] = {{NULL}};
        mmbuffer_t result = {NULL, 0};
        const struct cache_entry *ce;
 -      int pos, len, i, hunk_no;
 +      int pos, len, i, has_conflicts;
        struct rerere_io_mem io;
-       int marker_size = ll_merge_marker_size(path);
+       int marker_size = ll_merge_marker_size(istate, path);
  
        /*
         * Reproduce the conflicted merge in-core
         */
        len = strlen(path);
-       pos = cache_name_pos(path, len);
+       pos = index_name_pos(istate, path, len);
        if (0 <= pos)
                return -1;
        pos = -pos - 1;
  
-       while (pos < active_nr) {
+       while (pos < istate->cache_nr) {
                enum object_type type;
                unsigned long size;
  
-               ce = active_cache[pos++];
+               ce = istate->cache[pos++];
                if (ce_namelen(ce) != len || memcmp(ce->name, path, len))
                        break;
                i = ce_stage(ce) - 1;
         */
        ll_merge(&result, path, &mmfile[0], NULL,
                 &mmfile[1], "ours",
-                &mmfile[2], "theirs", NULL);
+                &mmfile[2], "theirs",
+                istate, NULL);
        for (i = 0; i < 3; i++)
                free(mmfile[i].ptr);
  
         * Grab the conflict ID and optionally write the original
         * contents with conflict markers out.
         */
 -      hunk_no = handle_path(sha1, (struct rerere_io *)&io, marker_size);
 +      has_conflicts = handle_path(sha1, (struct rerere_io *)&io, marker_size);
        strbuf_release(&io.input);
        if (io.io.output)
                fclose(io.io.output);
 -      return hunk_no;
 +      return has_conflicts;
  }
  
- static int rerere_forget_one_path(const char *path, struct string_list *rr)
+ static int rerere_forget_one_path(struct index_state *istate,
+                                 const char *path,
+                                 struct string_list *rr)
  {
        const char *filename;
        struct rerere_id *id;
         * Recreate the original conflict from the stages in the
         * index and compute the conflict ID
         */
-       ret = handle_cache(path, sha1, NULL);
+       ret = handle_cache(istate, path, sha1, NULL);
        if (ret < 1)
 -              return error("Could not parse conflict hunks in '%s'", path);
 +              return error(_("could not parse conflict hunks in '%s'"), path);
  
        /* Nuke the recorded resolution for the conflict */
        id = new_rerere_id(sha1);
                if (!has_rerere_resolution(id))
                        continue;
  
-               handle_cache(path, sha1, rerere_path(id, "thisimage"));
+               handle_cache(istate, path, sha1, rerere_path(id, "thisimage"));
                if (read_mmfile(&cur, rerere_path(id, "thisimage"))) {
                        free(cur.ptr);
 -                      error("Failed to update conflicted state in '%s'", path);
 +                      error(_("failed to update conflicted state in '%s'"), path);
                        goto fail_exit;
                }
-               cleanly_resolved = !try_merge(id, path, &cur, &result);
+               cleanly_resolved = !try_merge(istate, id, path, &cur, &result);
                free(result.ptr);
                free(cur.ptr);
                if (cleanly_resolved)
        }
  
        if (id->collection->status_nr <= id->variant) {
 -              error("no remembered resolution for '%s'", path);
 +              error(_("no remembered resolution for '%s'"), path);
                goto fail_exit;
        }
  
        filename = rerere_path(id, "postimage");
        if (unlink(filename)) {
                if (errno == ENOENT)
 -                      error("no remembered resolution for %s", path);
 +                      error(_("no remembered resolution for '%s'"), path);
                else
 -                      error_errno("cannot unlink %s", filename);
 +                      error_errno(_("cannot unlink '%s'"), filename);
                goto fail_exit;
        }
  
         * conflict in the working tree, run us again to record
         * the postimage.
         */
-       handle_cache(path, sha1, rerere_path(id, "preimage"));
+       handle_cache(istate, path, sha1, rerere_path(id, "preimage"));
 -      fprintf(stderr, "Updated preimage for '%s'\n", path);
 +      fprintf_ln(stderr, _("Updated preimage for '%s'"), path);
  
        /*
         * And remember that we can record resolution for this
        item = string_list_insert(rr, path);
        free_rerere_id(item);
        item->util = id;
 -      fprintf(stderr, "Forgot resolution for %s\n", path);
 +      fprintf(stderr, _("Forgot resolution for '%s'\n"), path);
        return 0;
  
  fail_exit:
        return -1;
  }
  
- int rerere_forget(struct pathspec *pathspec)
+ int rerere_forget(struct repository *r, struct pathspec *pathspec)
  {
        int i, fd;
        struct string_list conflict = STRING_LIST_INIT_DUP;
        struct string_list merge_rr = STRING_LIST_INIT_DUP;
  
-       if (read_cache() < 0)
+       if (read_index(r->index) < 0)
 -              return error("Could not read index");
 +              return error(_("index file corrupt"));
  
        fd = setup_rerere(&merge_rr, RERERE_NOAUTOUPDATE);
        if (fd < 0)
         * recover the original conflicted state and then
         * find the conflicted paths.
         */
-       unmerge_cache(pathspec);
-       find_conflict(&conflict);
+       unmerge_index(r->index, pathspec);
+       find_conflict(r, &conflict);
        for (i = 0; i < conflict.nr; i++) {
                struct string_list_item *it = &conflict.items[i];
-               if (!match_pathspec(&the_index, pathspec, it->string,
+               if (!match_pathspec(r->index, pathspec, it->string,
                                    strlen(it->string), 0, NULL, 0))
                        continue;
-               rerere_forget_one_path(it->string, &merge_rr);
+               rerere_forget_one_path(r->index, it->string, &merge_rr);
        }
        return write_rr(&merge_rr, fd);
  }
@@@ -1182,7 -1204,7 +1193,7 @@@ void rerere_gc(struct string_list *rr
        git_config(git_default_config, NULL);
        dir = opendir(git_path("rr-cache"));
        if (!dir)
 -              die_errno("unable to open rr-cache directory");
 +              die_errno(_("unable to open rr-cache directory"));
        /* Collect stale conflict IDs ... */
        while ((e = readdir(dir))) {
                struct rerere_dir *rr_dir;
diff --combined revision.c
index e18bd530e4c50d0f5a1887714b074a6c2c63875b,28366eaccf691b56a6ebe081c471638e4b13daa5..b5108b75abc9ff0ef0438f4cba2e932e935ff94f
@@@ -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;
  
@@@ -52,7 -51,8 +52,8 @@@ static void mark_blob_uninteresting(str
        blob->object.flags |= UNINTERESTING;
  }
  
- static void mark_tree_contents_uninteresting(struct tree *tree)
+ static void mark_tree_contents_uninteresting(struct repository *r,
+                                            struct tree *tree)
  {
        struct tree_desc desc;
        struct name_entry entry;
        while (tree_entry(&desc, &entry)) {
                switch (object_type(entry.mode)) {
                case OBJ_TREE:
-                       mark_tree_uninteresting(lookup_tree(the_repository, entry.oid));
+                       mark_tree_uninteresting(r, lookup_tree(r, entry.oid));
                        break;
                case OBJ_BLOB:
-                       mark_blob_uninteresting(lookup_blob(the_repository, entry.oid));
+                       mark_blob_uninteresting(lookup_blob(r, entry.oid));
                        break;
                default:
                        /* Subproject commit - not in this repository */
@@@ -82,7 -82,7 +83,7 @@@
        free_tree_buffer(tree);
  }
  
- void mark_tree_uninteresting(struct tree *tree)
+ void mark_tree_uninteresting(struct repository *r, struct tree *tree)
  {
        struct object *obj;
  
@@@ -93,7 -93,7 +94,7 @@@
        if (obj->flags & UNINTERESTING)
                return;
        obj->flags |= UNINTERESTING;
-       mark_tree_contents_uninteresting(tree);
+       mark_tree_contents_uninteresting(r, tree);
  }
  
  struct commit_stack {
@@@ -199,7 -199,7 +200,7 @@@ void add_head_to_pending(struct rev_inf
        struct object *obj;
        if (get_oid("HEAD", &oid))
                return;
-       obj = parse_object(the_repository, &oid);
+       obj = parse_object(revs->repo, &oid);
        if (!obj)
                return;
        add_pending_object(revs, obj, "HEAD");
@@@ -211,7 -211,7 +212,7 @@@ static struct object *get_reference(str
  {
        struct object *object;
  
-       object = parse_object(the_repository, oid);
+       object = parse_object(revs->repo, oid);
        if (!object) {
                if (revs->ignore_missing)
                        return object;
@@@ -248,7 -248,7 +249,7 @@@ static struct commit *handle_commit(str
                        add_pending_object(revs, object, tag->tag);
                if (!tag->tagged)
                        die("bad tag");
-               object = parse_object(the_repository, &tag->tagged->oid);
+               object = parse_object(revs->repo, &tag->tagged->oid);
                if (!object) {
                        if (revs->ignore_missing_links || (flags & UNINTERESTING))
                                return NULL;
                if (!revs->tree_objects)
                        return NULL;
                if (flags & UNINTERESTING) {
-                       mark_tree_contents_uninteresting(tree);
+                       mark_tree_contents_uninteresting(revs->repo, tree);
                        return NULL;
                }
                add_pending_object_with_path(revs, object, name, mode, path);
@@@ -878,7 -878,7 +879,7 @@@ static void cherry_pick_list(struct com
                return;
  
        left_first = left_count < right_count;
-       init_patch_ids(&ids);
+       init_patch_ids(revs->repo, &ids);
        ids.diffopts.pathspec = revs->diffopt.pathspec;
  
        /* Compute patch-ids for one side */
@@@ -1254,7 -1254,7 +1255,7 @@@ static void handle_one_reflog_commit(st
  {
        struct all_refs_cb *cb = cb_data;
        if (!is_null_oid(oid)) {
-               struct object *o = parse_object(the_repository, oid);
+               struct object *o = parse_object(cb->all_revs->repo, oid);
                if (o) {
                        o->flags |= cb->all_flags;
                        /* ??? CMDLINEFLAGS ??? */
@@@ -1313,7 -1313,7 +1314,7 @@@ void add_reflogs_to_pending(struct rev_
  
        cb.all_revs = revs;
        cb.all_flags = flags;
-       cb.refs = get_main_ref_store(the_repository);
+       cb.refs = get_main_ref_store(revs->repo);
        for_each_reflog(handle_one_reflog, &cb);
  
        if (!revs->single_worktree)
@@@ -1327,7 -1327,7 +1328,7 @@@ static void add_cache_tree(struct cache
        int i;
  
        if (it->entry_count >= 0) {
-               struct tree *tree = lookup_tree(the_repository, &it->oid);
+               struct tree *tree = lookup_tree(revs->repo, &it->oid);
                add_pending_object_with_path(revs, &tree->object, "",
                                             040000, path->buf);
        }
@@@ -1353,7 -1353,7 +1354,7 @@@ static void do_add_index_objects_to_pen
                if (S_ISGITLINK(ce->ce_mode))
                        continue;
  
-               blob = lookup_blob(the_repository, &ce->oid);
+               blob = lookup_blob(revs->repo, &ce->oid);
                if (!blob)
                        die("unable to add index blob to traversal");
                add_pending_object_with_path(revs, &blob->object, "",
@@@ -1371,8 -1371,8 +1372,8 @@@ void add_index_objects_to_pending(struc
  {
        struct worktree **worktrees, **p;
  
-       read_cache();
-       do_add_index_objects_to_pending(revs, &the_index);
+       read_index(revs->repo->index);
+       do_add_index_objects_to_pending(revs, revs->repo->index);
  
        if (revs->single_worktree)
                return;
@@@ -1440,10 -1440,13 +1441,13 @@@ static int add_parents_only(struct rev_
        return 1;
  }
  
- void init_revisions(struct rev_info *revs, const char *prefix)
+ void repo_init_revisions(struct repository *r,
+                        struct rev_info *revs,
+                        const char *prefix)
  {
        memset(revs, 0, sizeof(*revs));
  
+       revs->repo = r;
        revs->abbrev = DEFAULT_ABBREV;
        revs->ignore_merges = 1;
        revs->simplify_history = 1;
        revs->commit_format = CMIT_FMT_DEFAULT;
        revs->expand_tabs_in_log_default = 8;
  
-       init_grep_defaults();
-       grep_init(&revs->grep_filter, prefix);
+       init_grep_defaults(revs->repo);
+       grep_init(&revs->grep_filter, revs->repo, prefix);
        revs->grep_filter.status_only = 1;
  
-       diff_setup(&revs->diffopt);
+       repo_diff_setup(revs->repo, &revs->diffopt);
        if (prefix && !revs->diffopt.prefix) {
                revs->diffopt.prefix = prefix;
                revs->diffopt.prefix_length = strlen(prefix);
@@@ -1497,6 -1500,7 +1501,7 @@@ static void prepare_show_merge(struct r
        struct object_id oid;
        const char **prune = NULL;
        int i, prune_num = 1; /* counting terminating NULL */
+       struct index_state *istate = revs->repo->index;
  
        if (get_oid("HEAD", &oid))
                die("--merge without HEAD?");
        free_commit_list(bases);
        head->object.flags |= SYMMETRIC_LEFT;
  
-       if (!active_nr)
-               read_cache();
-       for (i = 0; i < active_nr; i++) {
-               const struct cache_entry *ce = active_cache[i];
+       if (!istate->cache_nr)
+               read_index(istate);
+       for (i = 0; i < istate->cache_nr; i++) {
+               const struct cache_entry *ce = istate->cache[i];
                if (!ce_stage(ce))
                        continue;
-               if (ce_path_match(&the_index, ce, &revs->prune_data, NULL)) {
+               if (ce_path_match(istate, ce, &revs->prune_data, NULL)) {
                        prune_num++;
                        REALLOC_ARRAY(prune, prune_num);
                        prune[prune_num-2] = ce->name;
                        prune[prune_num-1] = NULL;
                }
-               while ((i+1 < active_nr) &&
-                      ce_same_name(ce, active_cache[i+1]))
+               while ((i+1 < istate->cache_nr) &&
+                      ce_same_name(ce, istate->cache[i+1]))
                        i++;
        }
        clear_pathspec(&revs->prune_data);
@@@ -1582,8 -1586,8 +1587,8 @@@ static int handle_dotdot_1(const char *
                *dotdot = '\0';
        }
  
-       a_obj = parse_object(the_repository, &a_oid);
-       b_obj = parse_object(the_repository, &b_oid);
+       a_obj = parse_object(revs->repo, &a_oid);
+       b_obj = parse_object(revs->repo, &b_oid);
        if (!a_obj || !b_obj)
                return dotdot_missing(arg, dotdot, revs, symmetric);
  
                struct commit *a, *b;
                struct commit_list *exclude;
  
-               a = lookup_commit_reference(the_repository, &a_obj->oid);
-               b = lookup_commit_reference(the_repository, &b_obj->oid);
+               a = lookup_commit_reference(revs->repo, &a_obj->oid);
+               b = lookup_commit_reference(revs->repo, &b_obj->oid);
                if (!a || !b)
                        return dotdot_missing(arg, dotdot, revs, symmetric);
  
@@@ -2205,7 -2209,7 +2210,7 @@@ static int handle_revision_pseudo_opt(c
                        BUG("--single-worktree cannot be used together with submodule");
                refs = get_submodule_ref_store(submodule);
        } else
-               refs = get_main_ref_store(the_repository);
+               refs = get_main_ref_store(revs->repo);
  
        /*
         * NOTE!
@@@ -2319,7 -2323,7 +2324,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;
@@@ -2885,9 -2890,10 +2890,10 @@@ void reset_revision_walk(void
  static int mark_uninteresting(const struct object_id *oid,
                              struct packed_git *pack,
                              uint32_t pos,
-                             void *unused)
+                             void *cb)
  {
-       struct object *o = parse_object(the_repository, oid);
+       struct rev_info *revs = cb;
+       struct object *o = parse_object(revs->repo, oid);
        o->flags |= UNINTERESTING | SEEN;
        return 0;
  }
@@@ -2920,7 -2926,7 +2926,7 @@@ int prepare_revision_walk(struct rev_in
                revs->treesame.name = "treesame";
  
        if (revs->exclude_promisor_objects) {
-               for_each_packed_object(mark_uninteresting, NULL,
+               for_each_packed_object(mark_uninteresting, revs,
                                       FOR_EACH_OBJECT_PROMISOR_ONLY);
        }
  
@@@ -3238,7 -3244,7 +3244,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 revision.h
index 2b30ac270d9295e00641b08483fe07cd44dc51f6,7e62a65bad55f43c150ce12b2fd0be0478b13422..bc30a3023e20542480b7d771dd1e4001c518f30b
@@@ -28,8 -28,9 +28,9 @@@
  #define DECORATE_SHORT_REFS   1
  #define DECORATE_FULL_REFS    2
  
- struct rev_info;
  struct log_info;
+ struct repository;
+ struct rev_info;
  struct string_list;
  struct saved_parents;
  define_shared_commit_slab(revision_sources, char *);
@@@ -60,6 -61,7 +61,7 @@@ struct rev_info 
        /* Starting list */
        struct commit_list *commits;
        struct object_array pending;
+       struct repository *repo;
  
        /* Parents of shown commits */
        struct object_array boundary_commits;
         */
        int rev_input_given;
  
 +      /*
 +       * Whether we read from stdin due to the --stdin option.
 +       */
 +      int read_from_stdin;
 +
        /* topo-sort */
        enum rev_sort_order sort_order;
  
        /* notes-specific options: which refs to show */
        struct display_notes_opt notes_opt;
  
 +      /* interdiff */
 +      const struct object_id *idiff_oid1;
 +      const struct object_id *idiff_oid2;
 +      const char *idiff_title;
 +
 +      /* range-diff */
 +      const char *rdiff1;
 +      const char *rdiff2;
 +      int creation_factor;
 +      const char *rdiff_title;
 +
        /* commit counts */
        int count_left;
        int count_right;
@@@ -264,12 -250,17 +266,17 @@@ extern volatile show_early_output_fn_t 
  struct setup_revision_opt {
        const char *def;
        void (*tweak)(struct rev_info *, struct setup_revision_opt *);
-       const char *submodule;
+       const char *submodule;  /* TODO: drop this and use rev_info->repo */
        int assume_dashdash;
        unsigned revarg_opt;
  };
  
- void init_revisions(struct rev_info *revs, const char *prefix);
+ #ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
+ #define init_revisions(revs, prefix) repo_init_revisions(the_repository, revs, prefix)
+ #endif
+ void repo_init_revisions(struct repository *r,
+                        struct rev_info *revs,
+                        const char *prefix);
  int setup_revisions(int argc, const char **argv, struct rev_info *revs,
                    struct setup_revision_opt *);
  void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,
@@@ -289,7 -280,7 +296,7 @@@ void put_revision_mark(const struct rev
                       const struct commit *commit);
  
  void mark_parents_uninteresting(struct commit *commit);
- void mark_tree_uninteresting(struct tree *tree);
+ void mark_tree_uninteresting(struct repository *r, struct tree *tree);
  
  void show_object_with_name(FILE *, struct object *, const char *);
  
diff --combined sequencer.c
index 6387c9ee6e8ba20aa276cf3fb9620d2caed70079,da4e727cc3f3ee71010aaff20e9840ced7aaa266..83f17721d4fc44cd5da211878c335f4e0e07cde9
@@@ -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;
@@@ -474,8 -470,8 +474,8 @@@ static int fast_forward_to(const struc
        struct strbuf sb = STRBUF_INIT;
        struct strbuf err = STRBUF_INIT;
  
-       read_cache();
-       if (checkout_fast_forward(from, to, 1))
+       read_index(&the_index);
+       if (checkout_fast_forward(the_repository, from, to, 1))
                return -1; /* the callee should have complained already */
  
        strbuf_addf(&sb, _("%s: fast-forward"), _(action_name(opts)));
@@@ -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)
@@@ -903,7 -899,7 +903,7 @@@ static int run_git_commit(const char *d
        if ((flags & ALLOW_EMPTY))
                argv_array_push(&cmd.args, "--allow-empty");
  
 -      if (opts->allow_empty_message)
 +      if (!(flags & EDIT_MSG))
                argv_array_push(&cmd.args, "--allow-empty-message");
  
        if (cmd.err == -1) {
@@@ -1176,7 -1172,7 +1176,7 @@@ void print_commit_summary(const char *p
        strbuf_release(&author_ident);
        strbuf_release(&committer_ident);
  
-       init_revisions(&rev, prefix);
+       repo_init_revisions(the_repository, &rev, prefix);
        setup_revisions(0, NULL, &rev, NULL);
  
        rev.diff = 1;
@@@ -1221,7 -1217,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 -1287,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;
        }
  
        if (cleanup != COMMIT_MSG_CLEANUP_NONE)
                strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);
 -      if (!opts->allow_empty_message && message_is_empty(msg, cleanup)) {
 +      if ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {
                res = 1; /* run 'git commit' to display error message */
                goto out;
        }
@@@ -1398,7 -1394,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 -1674,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);
  
                commit_list_insert(base, &common);
                commit_list_insert(next, &remotes);
-               res |= try_merge_command(opts->strategy,
+               res |= try_merge_command(the_repository, opts->strategy,
                                         opts->xopts_nr, (const char **)opts->xopts,
                                        common, oid_to_hex(&head), remotes);
                free_commit_list(common);
                      : _("could not apply %s... %s"),
                      short_commit_name(commit), msg.subject);
                print_advice(res == 1, opts);
-               rerere(opts->allow_rerere_auto);
+               repo_rerere(the_repository, opts->allow_rerere_auto);
                goto leave;
        }
  
@@@ -2426,7 -2422,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)
@@@ -2599,7 -2595,7 +2599,7 @@@ static int make_patch(struct commit *co
  
        strbuf_addf(&buf, "%s/patch", get_dir(opts));
        memset(&log_tree_opt, 0, sizeof(log_tree_opt));
-       init_revisions(&log_tree_opt, NULL);
+       repo_init_revisions(the_repository, &log_tree_opt, NULL);
        log_tree_opt.abbrev = 0;
        log_tree_opt.diff = 1;
        log_tree_opt.diffopt.output_format = DIFF_FORMAT_PATCH;
@@@ -2987,7 -2983,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;
  
        rollback_lock_file(&lock);
        if (ret)
-               rerere(opts->allow_rerere_auto);
+               repo_rerere(the_repository, opts->allow_rerere_auto);
        else
                /*
                 * In case of problems, we now want to return a positive
@@@ -3382,9 -3378,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,
@@@ -3510,7 -3506,7 +3510,7 @@@ cleanup_head_ref
                        struct object_id orig, head;
  
                        memset(&log_tree_opt, 0, sizeof(log_tree_opt));
-                       init_revisions(&log_tree_opt, NULL);
+                       repo_init_revisions(the_repository, &log_tree_opt, NULL);
                        log_tree_opt.diff = 1;
                        log_tree_opt.diffopt.output_format =
                                DIFF_FORMAT_DIFFSTAT;
@@@ -3599,7 -3595,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) &&
 -                  opts->current_fixup_count > 0 &&
 -                  file_exists(rebase_path_stopped_sha())) {
 +              if (!is_clean || !opts->current_fixup_count)
 +                      ; /* this is not the final fixup */
 +              else if (!oideq(&head, &to_amend) ||
 +                       !file_exists(rebase_path_stopped_sha())) {
 +                      /* was a final fixup or squash done manually? */
 +                      if (!is_fixup(peek_command(todo_list, 0))) {
 +                              unlink(rebase_path_fixup_msg());
 +                              unlink(rebase_path_squash_msg());
 +                              unlink(rebase_path_current_fixups());
 +                              strbuf_reset(&opts->current_fixups);
 +                              opts->current_fixup_count = 0;
 +                      }
 +              } else {
 +                      /* we are in a fixup/squash chain */
                        const char *p = opts->current_fixups.buf;
                        int len = opts->current_fixups.len;
  
@@@ -3843,7 -3828,7 +3843,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;
@@@ -4146,7 -4131,9 +4146,7 @@@ static int make_script_with_merges(stru
                        struct object_id *oid = &parent->item->object.oid;
                        if (!oidset_contains(&interesting, oid))
                                continue;
 -                      if (!oidset_contains(&child_seen, oid))
 -                              oidset_insert(&child_seen, oid);
 -                      else
 +                      if (oidset_insert(&child_seen, oid))
                                label_oid(oid, "branch-point", &state);
                }
  
@@@ -4254,7 -4241,7 +4254,7 @@@ int sequencer_make_script(FILE *out, in
        const char *insn = flags & TODO_LIST_ABBREVIATE_CMDS ? "p" : "pick";
        int rebase_merges = flags & TODO_LIST_REBASE_MERGES;
  
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
        revs.verbose_header = 1;
        if (!rebase_merges)
                revs.max_parents = 1;
@@@ -4587,7 -4574,7 +4587,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-file.c
index a4367b8f044c6e9254d2a253149187bdb2be6dd2,308d5e20e2c6483fde64641a00f7c0b5b2f721ea..dd0b6aa873a95433906b52abf605a43acc924d4a
@@@ -149,10 -149,10 +149,10 @@@ static struct cached_object *find_cache
        struct cached_object *co = cached_objects;
  
        for (i = 0; i < cached_object_nr; i++, co++) {
 -              if (!oidcmp(&co->oid, oid))
 +              if (oideq(&co->oid, oid))
                        return co;
        }
 -      if (!oidcmp(oid, the_hash_algo->empty_tree))
 +      if (oideq(oid, the_hash_algo->empty_tree))
                return &empty_tree;
        return NULL;
  }
@@@ -825,7 -825,7 +825,7 @@@ int check_object_signature(const struc
  
        if (map) {
                hash_object_file(map, size, type, &real_oid);
 -              return oidcmp(oid, &real_oid) ? -1 : 0;
 +              return !oideq(oid, &real_oid) ? -1 : 0;
        }
  
        st = open_istream(oid, &obj_type, &size, NULL);
        }
        the_hash_algo->final_fn(real_oid.hash, &c);
        close_istream(st);
 -      return oidcmp(oid, &real_oid) ? -1 : 0;
 +      return !oideq(oid, &real_oid) ? -1 : 0;
  }
  
  int git_open_cloexec(const char *name, int flags)
@@@ -1317,7 -1317,7 +1317,7 @@@ int oid_object_info_extended(struct rep
                         * TODO Pass a repository struct through fetch_object,
                         * such that arbitrary repositories work.
                         */
 -                      fetch_object(repository_format_partial_clone, real->hash);
 +                      fetch_objects(repository_format_partial_clone, real, 1);
                        already_retried = 1;
                        continue;
                }
@@@ -1671,7 -1671,7 +1671,7 @@@ static int write_loose_object(const str
                die(_("deflateEnd on object %s failed (%d)"), oid_to_hex(oid),
                    ret);
        the_hash_algo->final_fn(parano_oid.hash, &c);
 -      if (oidcmp(oid, &parano_oid) != 0)
 +      if (!oideq(oid, &parano_oid))
                die(_("confused by unstable object source data for %s"),
                    oid_to_hex(oid));
  
@@@ -1813,7 -1813,8 +1813,8 @@@ static void check_tag(const void *buf, 
                die(_("corrupt tag"));
  }
  
- static int index_mem(struct object_id *oid, void *buf, size_t size,
+ static int index_mem(struct index_state *istate,
+                    struct object_id *oid, void *buf, size_t size,
                     enum object_type type,
                     const char *path, unsigned flags)
  {
         */
        if ((type == OBJ_BLOB) && path) {
                struct strbuf nbuf = STRBUF_INIT;
-               if (convert_to_git(&the_index, path, buf, size, &nbuf,
+               if (convert_to_git(istate, path, buf, size, &nbuf,
                                   get_conv_flags(flags))) {
                        buf = strbuf_detach(&nbuf, &size);
                        re_allocated = 1;
        return ret;
  }
  
- static int index_stream_convert_blob(struct object_id *oid, int fd,
-                                    const char *path, unsigned flags)
+ static int index_stream_convert_blob(struct index_state *istate,
+                                    struct object_id *oid,
+                                    int fd,
+                                    const char *path,
+                                    unsigned flags)
  {
        int ret;
        const int write_object = flags & HASH_WRITE_OBJECT;
        struct strbuf sbuf = STRBUF_INIT;
  
        assert(path);
-       assert(would_convert_to_git_filter_fd(&the_index, path));
+       assert(would_convert_to_git_filter_fd(istate, path));
  
-       convert_to_git_filter_fd(&the_index, path, fd, &sbuf,
+       convert_to_git_filter_fd(istate, path, fd, &sbuf,
                                 get_conv_flags(flags));
  
        if (write_object)
        return ret;
  }
  
- static int index_pipe(struct object_id *oid, int fd, enum object_type type,
+ static int index_pipe(struct index_state *istate, struct object_id *oid,
+                     int fd, enum object_type type,
                      const char *path, unsigned flags)
  {
        struct strbuf sbuf = STRBUF_INIT;
        int ret;
  
        if (strbuf_read(&sbuf, fd, 4096) >= 0)
-               ret = index_mem(oid, sbuf.buf, sbuf.len, type, path, flags);
+               ret = index_mem(istate, oid, sbuf.buf, sbuf.len, type, path, flags);
        else
                ret = -1;
        strbuf_release(&sbuf);
  
  #define SMALL_FILE_SIZE (32*1024)
  
- static int index_core(struct object_id *oid, int fd, size_t size,
+ static int index_core(struct index_state *istate,
+                     struct object_id *oid, int fd, size_t size,
                      enum object_type type, const char *path,
                      unsigned flags)
  {
        int ret;
  
        if (!size) {
-               ret = index_mem(oid, "", size, type, path, flags);
+               ret = index_mem(istate, oid, "", size, type, path, flags);
        } else if (size <= SMALL_FILE_SIZE) {
                char *buf = xmalloc(size);
                ssize_t read_result = read_in_full(fd, buf, size);
                        ret = error(_("short read while indexing %s"),
                                    path ? path : "<unknown>");
                else
-                       ret = index_mem(oid, buf, size, type, path, flags);
+                       ret = index_mem(istate, oid, buf, size, type, path, flags);
                free(buf);
        } else {
                void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
-               ret = index_mem(oid, buf, size, type, path, flags);
+               ret = index_mem(istate, oid, buf, size, type, path, flags);
                munmap(buf, size);
        }
        return ret;
@@@ -1941,7 -1947,8 +1947,8 @@@ static int index_stream(struct object_i
        return index_bulk_checkin(oid, fd, size, type, path, flags);
  }
  
- int index_fd(struct object_id *oid, int fd, struct stat *st,
+ int index_fd(struct index_state *istate, struct object_id *oid,
+            int fd, struct stat *st,
             enum object_type type, const char *path, unsigned flags)
  {
        int ret;
         * Call xsize_t() only when needed to avoid potentially unnecessary
         * die() for large files.
         */
-       if (type == OBJ_BLOB && path && would_convert_to_git_filter_fd(&the_index, path))
-               ret = index_stream_convert_blob(oid, fd, path, flags);
+       if (type == OBJ_BLOB && path && would_convert_to_git_filter_fd(istate, path))
+               ret = index_stream_convert_blob(istate, oid, fd, path, flags);
        else if (!S_ISREG(st->st_mode))
-               ret = index_pipe(oid, fd, type, path, flags);
+               ret = index_pipe(istate, oid, fd, type, path, flags);
        else if (st->st_size <= big_file_threshold || type != OBJ_BLOB ||
-                (path && would_convert_to_git(&the_index, path)))
-               ret = index_core(oid, fd, xsize_t(st->st_size), type, path,
-                                flags);
+                (path && would_convert_to_git(istate, path)))
+               ret = index_core(istate, oid, fd, xsize_t(st->st_size),
+                                type, path, flags);
        else
                ret = index_stream(oid, fd, xsize_t(st->st_size), type, path,
                                   flags);
        return ret;
  }
  
- int index_path(struct object_id *oid, const char *path, struct stat *st, unsigned flags)
+ int index_path(struct index_state *istate, struct object_id *oid,
+              const char *path, struct stat *st, unsigned flags)
  {
        int fd;
        struct strbuf sb = STRBUF_INIT;
                fd = open(path, O_RDONLY);
                if (fd < 0)
                        return error_errno("open(\"%s\")", path);
-               if (index_fd(oid, fd, st, OBJ_BLOB, path, flags) < 0)
+               if (index_fd(istate, oid, fd, st, OBJ_BLOB, path, flags) < 0)
                        return error(_("%s: failed to insert into database"),
                                     path);
                break;
@@@ -2213,7 -2221,7 +2221,7 @@@ static int check_stream_sha1(git_zstrea
        }
  
        the_hash_algo->final_fn(real_sha1, &c);
 -      if (hashcmp(expected_sha1, real_sha1)) {
 +      if (!hasheq(expected_sha1, real_sha1)) {
                error(_("sha1 mismatch for %s (expected %s)"), path,
                      sha1_to_hex(expected_sha1));
                return -1;
diff --combined shallow.c
index 99fd2d1ba0f70aaf238f55aae006a12e38090342,e656ce8b9cc7d916987e9b4f05897eccc0c53542..732e18d54f3b88d8a081786eabd030d84eb7e0a3
+++ b/shallow.c
@@@ -16,7 -16,6 +16,7 @@@
  #include "list-objects.h"
  #include "commit-slab.h"
  #include "repository.h"
 +#include "commit-reach.h"
  
  void set_alternate_shallow_file(struct repository *r, const char *path, int override)
  {
@@@ -185,7 -184,7 +185,7 @@@ struct commit_list *get_shallow_commits
  
        is_repository_shallow(the_repository); /* make sure shallows are read */
  
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
        save_commit_buffer = 0;
        setup_revisions(ac, av, &revs, NULL);
  
diff --combined submodule.c
index b53cb6e9c4714c3582aab35fea5bfb3739658348,442229bb493761c180fd2e32e185cd58503d1366..25c6e5d5b92e8501a2ad6ae93c5ca10b86d330a3
@@@ -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;
@@@ -66,7 -65,8 +66,7 @@@ int is_staging_gitmodules_ok(struct ind
        if ((pos >= 0) && (pos < istate->cache_nr)) {
                struct stat st;
                if (lstat(GITMODULES_FILE, &st) == 0 &&
 -                  ie_match_stat(istate, istate->cache[pos], &st,
 -                                CE_MATCH_IGNORE_FSMONITOR) & DATA_CHANGED)
 +                  ie_match_stat(istate, istate->cache[pos], &st, 0) & DATA_CHANGED)
                        return 0;
        }
  
@@@ -428,7 -428,7 +428,7 @@@ static int prepare_submodule_summary(st
  {
        struct commit_list *list;
  
-       init_revisions(rev, NULL);
+       repo_init_revisions(the_repository, rev, NULL);
        setup_revisions(0, NULL, rev, NULL);
        rev->left_right = 1;
        rev->first_parent_only = 1;
@@@ -536,7 -536,7 +536,7 @@@ static void show_submodule_header(struc
                        fast_backward = 1;
        }
  
 -      if (!oidcmp(one, two)) {
 +      if (oideq(one, two)) {
                strbuf_release(&sb);
                return;
        }
@@@ -766,13 -766,14 +766,14 @@@ static void collect_changed_submodules_
   * have a corresponding 'struct oid_array' (in the 'util' field) which lists
   * what the submodule pointers were updated to during the change.
   */
- static void collect_changed_submodules(struct string_list *changed,
+ static void collect_changed_submodules(struct index_state *istate,
+                                      struct string_list *changed,
                                       struct argv_array *argv)
  {
        struct rev_info rev;
        const struct commit *commit;
  
-       init_revisions(&rev, NULL);
+       repo_init_revisions(the_repository, &rev, NULL);
        setup_revisions(argv->argc, argv->argv, &rev, NULL);
        if (prepare_revision_walk(&rev))
                die("revision walk setup failed");
                data.changed = changed;
                data.commit_oid = &commit->object.oid;
  
-               init_revisions(&diff_rev, NULL);
+               repo_init_revisions(the_repository, &diff_rev, NULL);
                diff_rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
                diff_rev.diffopt.format_callback = collect_changed_submodules_cb;
                diff_rev.diffopt.format_callback_data = &data;
@@@ -930,8 -931,10 +931,10 @@@ static int submodule_needs_pushing(cons
        return 0;
  }
  
- int find_unpushed_submodules(struct oid_array *commits,
-               const char *remotes_name, struct string_list *needs_pushing)
+ int find_unpushed_submodules(struct index_state *istate,
+                            struct oid_array *commits,
+                            const char *remotes_name,
+                            struct string_list *needs_pushing)
  {
        struct string_list submodules = STRING_LIST_INIT_DUP;
        struct string_list_item *name;
        argv_array_push(&argv, "--not");
        argv_array_pushf(&argv, "--remotes=%s", remotes_name);
  
-       collect_changed_submodules(&submodules, &argv);
+       collect_changed_submodules(istate, &submodules, &argv);
  
        for_each_string_list_item(name, &submodules) {
                struct oid_array *commits = name->util;
@@@ -1044,7 -1047,8 +1047,8 @@@ static void submodule_push_check(const 
                die("process for submodule '%s' failed", path);
  }
  
- int push_unpushed_submodules(struct oid_array *commits,
+ int push_unpushed_submodules(struct index_state *istate,
+                            struct oid_array *commits,
                             const struct remote *remote,
                             const struct refspec *rs,
                             const struct string_list *push_options,
        int i, ret = 1;
        struct string_list needs_pushing = STRING_LIST_INIT_DUP;
  
-       if (!find_unpushed_submodules(commits, remote->name, &needs_pushing))
+       if (!find_unpushed_submodules(istate, commits,
+                                     remote->name, &needs_pushing))
                return 1;
  
        /*
@@@ -1110,7 -1115,7 +1115,7 @@@ void check_for_new_submodule_commits(st
        oid_array_append(&ref_tips_after_fetch, oid);
  }
  
- static void calculate_changed_submodule_paths(void)
+ static void calculate_changed_submodule_paths(struct index_state *istate)
  {
        struct argv_array argv = ARGV_ARRAY_INIT;
        struct string_list changed_submodules = STRING_LIST_INIT_DUP;
         * Collect all submodules (whether checked out or not) for which new
         * commits have been recorded upstream in "changed_submodule_names".
         */
-       collect_changed_submodules(&changed_submodules, &argv);
+       collect_changed_submodules(istate, &changed_submodules, &argv);
  
        for_each_string_list_item(name, &changed_submodules) {
                struct oid_array *commits = name->util;
        initialized_fetch_ref_tips = 0;
  }
  
- int submodule_touches_in_range(struct object_id *excl_oid,
+ int submodule_touches_in_range(struct index_state *istate,
+                              struct object_id *excl_oid,
                               struct object_id *incl_oid)
  {
        struct string_list subs = STRING_LIST_INIT_DUP;
                argv_array_push(&args, oid_to_hex(excl_oid));
        }
  
-       collect_changed_submodules(&subs, &args);
+       collect_changed_submodules(istate, &subs, &args);
        ret = subs.nr;
  
        argv_array_clear(&args);
@@@ -1346,7 -1352,7 +1352,7 @@@ int fetch_populated_submodules(struct r
        argv_array_push(&spf.args, "--recurse-submodules-default");
        /* default value, "--submodule-prefix" and its value are added later */
  
-       calculate_changed_submodule_paths();
+       calculate_changed_submodule_paths(r->index);
        run_processes_parallel(max_parallel_jobs,
                               get_next_submodule,
                               fetch_start_failure,
diff --combined transport.c
index 1c76d64aba9fac7d62dfc8e95ab2b32f45dd95a5,cb40a23d4558af9087473bd5fb5721b25a5e042b..dd7bd3436c5e5387097ff423adcf5db44bcbf43e
@@@ -1139,7 -1139,8 +1139,8 @@@ int transport_push(struct transport *tr
                                        oid_array_append(&commits,
                                                          &ref->new_oid);
  
-                       if (!push_unpushed_submodules(&commits,
+                       if (!push_unpushed_submodules(&the_index,
+                                                     &commits,
                                                      transport->remote,
                                                      rs,
                                                      transport->push_options,
                                        oid_array_append(&commits,
                                                          &ref->new_oid);
  
-                       if (find_unpushed_submodules(&commits, transport->remote->name,
-                                               &needs_pushing)) {
+                       if (find_unpushed_submodules(&the_index,
+                                                    &commits,
+                                                    transport->remote->name,
+                                                    &needs_pushing)) {
                                oid_array_clear(&commits);
                                die_with_unpushed_submodules(&needs_pushing);
                        }
@@@ -1228,7 -1231,7 +1231,7 @@@ int transport_fetch_refs(struct transpo
                nr_refs++;
                if (rm->peer_ref &&
                    !is_null_oid(&rm->old_oid) &&
 -                  !oidcmp(&rm->peer_ref->old_oid, &rm->old_oid))
 +                  oideq(&rm->peer_ref->old_oid, &rm->old_oid))
                        continue;
                ALLOC_GROW(heads, nr_heads + 1, nr_alloc);
                heads[nr_heads++] = rm;
diff --combined tree-diff.c
index 425668e1e0b468d55e87dba69169acd53bba2c31,16b28ff6d6d4b678c6e4659d4e81b1bcf7f00ad9..0e5432461026eff15fe101cf017cd839702e5870
@@@ -491,7 -491,7 +491,7 @@@ static struct combine_diff_path *ll_dif
                                                continue;
  
                                        /* diff(t,pi) != ΓΈ */
 -                                      if (oidcmp(t.entry.oid, tp[i].entry.oid) ||
 +                                      if (!oideq(t.entry.oid, tp[i].entry.oid) ||
                                            (t.entry.mode != tp[i].entry.mode))
                                                continue;
  
@@@ -605,7 -605,7 +605,7 @@@ static void try_to_follow_renames(cons
        choice = q->queue[0];
        q->nr = 0;
  
-       diff_setup(&diff_opts);
+       repo_diff_setup(opt->repo, &diff_opts);
        diff_opts.flags.recursive = 1;
        diff_opts.flags.find_copies_harder = 1;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
diff --combined userdiff.c
index f565f6731d1336c761b527a8ce8a62a21b453dcc,c913232396d92c62e5cd8b6a8cb632d4e7b7ce80..46d34cc2a436c6084531d39628d013785700e2ba
@@@ -270,7 -270,8 +270,8 @@@ struct userdiff_driver *userdiff_find_b
        return userdiff_find_by_namelen(name, len);
  }
  
- struct userdiff_driver *userdiff_find_by_path(const char *path)
+ struct userdiff_driver *userdiff_find_by_path(struct index_state *istate,
+                                             const char *path)
  {
        static struct attr_check *check;
  
                check = attr_check_initl("diff", NULL);
        if (!path)
                return NULL;
-       git_check_attr(&the_index, path, check);
 -      if (git_check_attr(istate, path, check))
 -              return NULL;
++      git_check_attr(istate, path, check);
  
        if (ATTR_TRUE(check->items[0].value))
                return &driver_true;
diff --combined ws.c
index a64ab51e09a99e190e5f1912de19b1e093feb360,55349b4c5d08597e38ab76d10cd0d11b944f4f37..6e69877f25791632d98bf7b109a2eaebd04c96af
--- 1/ws.c
--- 2/ws.c
+++ b/ws.c
@@@ -3,7 -3,6 +3,6 @@@
   *
   * Copyright (c) 2007 Junio C Hamano
   */
  #include "cache.h"
  #include "attr.h"
  
@@@ -71,34 -70,38 +70,34 @@@ unsigned parse_whitespace_rule(const ch
        return rule;
  }
  
- unsigned whitespace_rule(const char *pathname)
+ unsigned whitespace_rule(struct index_state *istate, const char *pathname)
  {
        static struct attr_check *attr_whitespace_rule;
 +      const char *value;
  
        if (!attr_whitespace_rule)
                attr_whitespace_rule = attr_check_initl("whitespace", NULL);
  
-       git_check_attr(&the_index, pathname, attr_whitespace_rule);
 -      if (!git_check_attr(istate, pathname, attr_whitespace_rule)) {
 -              const char *value;
 -
 -              value = attr_whitespace_rule->items[0].value;
 -              if (ATTR_TRUE(value)) {
 -                      /* true (whitespace) */
 -                      unsigned all_rule = ws_tab_width(whitespace_rule_cfg);
 -                      int i;
 -                      for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++)
 -                              if (!whitespace_rule_names[i].loosens_error &&
 -                                  !whitespace_rule_names[i].exclude_default)
 -                                      all_rule |= whitespace_rule_names[i].rule_bits;
 -                      return all_rule;
 -              } else if (ATTR_FALSE(value)) {
 -                      /* false (-whitespace) */
 -                      return ws_tab_width(whitespace_rule_cfg);
 -              } else if (ATTR_UNSET(value)) {
 -                      /* reset to default (!whitespace) */
 -                      return whitespace_rule_cfg;
 -              } else {
 -                      /* string */
 -                      return parse_whitespace_rule(value);
 -              }
 -      } else {
++      git_check_attr(istate, pathname, attr_whitespace_rule);
 +      value = attr_whitespace_rule->items[0].value;
 +      if (ATTR_TRUE(value)) {
 +              /* true (whitespace) */
 +              unsigned all_rule = ws_tab_width(whitespace_rule_cfg);
 +              int i;
 +              for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++)
 +                      if (!whitespace_rule_names[i].loosens_error &&
 +                          !whitespace_rule_names[i].exclude_default)
 +                              all_rule |= whitespace_rule_names[i].rule_bits;
 +              return all_rule;
 +      } else if (ATTR_FALSE(value)) {
 +              /* false (-whitespace) */
 +              return ws_tab_width(whitespace_rule_cfg);
 +      } else if (ATTR_UNSET(value)) {
 +              /* reset to default (!whitespace) */
                return whitespace_rule_cfg;
 +      } else {
 +              /* string */
 +              return parse_whitespace_rule(value);
        }
  }
  
diff --combined wt-status.c
index 1c8746d0ea7d02f6f7899fa5418597b584d8cfb8,2f743941d513503763b4f05ffb1bfdfaad79621a..87042d4568338aa946f6bc44f9980e91a3eff416
@@@ -453,8 -453,8 +453,8 @@@ static void wt_status_collect_changed_c
                        d->worktree_status = p->status;
                if (S_ISGITLINK(p->two->mode)) {
                        d->dirty_submodule = p->two->dirty_submodule;
 -                      d->new_submodule_commits = !!oidcmp(&p->one->oid,
 -                                                          &p->two->oid);
 +                      d->new_submodule_commits = !oideq(&p->one->oid,
 +                                                        &p->two->oid);
                        if (s->status_format == STATUS_FORMAT_SHORT)
                                d->worktree_status = short_submodule_status(d);
                }
@@@ -582,7 -582,7 +582,7 @@@ static void wt_status_collect_changes_w
  {
        struct rev_info rev;
  
-       init_revisions(&rev, NULL);
+       repo_init_revisions(the_repository, &rev, NULL);
        setup_revisions(0, NULL, &rev, NULL);
        rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
        rev.diffopt.flags.dirty_submodules = 1;
@@@ -607,7 -607,7 +607,7 @@@ static void wt_status_collect_changes_i
        struct rev_info rev;
        struct setup_revision_opt opt;
  
-       init_revisions(&rev, NULL);
+       repo_init_revisions(the_repository, &rev, NULL);
        memset(&opt, 0, sizeof(opt));
        opt.def = s->is_initial ? empty_tree_oid_hex() : s->reference;
        setup_revisions(0, NULL, &rev, &opt);
@@@ -982,7 -982,7 +982,7 @@@ static void wt_longstatus_print_verbose
        int dirty_submodules;
        const char *c = color(WT_STATUS_HEADER, s);
  
-       init_revisions(&rev, NULL);
+       repo_init_revisions(the_repository, &rev, NULL);
        rev.diffopt.flags.allow_textconv = 1;
        rev.diffopt.ita_invisible_in_index = 1;
  
@@@ -1487,10 -1487,10 +1487,10 @@@ static void wt_status_get_detached_from
  
        if (dwim_ref(cb.buf.buf, cb.buf.len, &oid, &ref) == 1 &&
            /* sha1 is a commit? match without further lookup */
 -          (!oidcmp(&cb.noid, &oid) ||
 +          (oideq(&cb.noid, &oid) ||
             /* perhaps sha1 is a tag, try to dereference to a commit */
             ((commit = lookup_commit_reference_gently(the_repository, &oid, 1)) != NULL &&
 -            !oidcmp(&cb.noid, &commit->object.oid)))) {
 +            oideq(&cb.noid, &commit->object.oid)))) {
                const char *from = ref;
                if (!skip_prefix(from, "refs/tags/", &from))
                        skip_prefix(from, "refs/remotes/", &from);
                        xstrdup(find_unique_abbrev(&cb.noid, DEFAULT_ABBREV));
        oidcpy(&state->detached_oid, &cb.noid);
        state->detached_at = !get_oid("HEAD", &oid) &&
 -                           !oidcmp(&oid, &state->detached_oid);
 +                           oideq(&oid, &state->detached_oid);
  
        free(ref);
        strbuf_release(&cb.buf);
@@@ -2314,7 -2314,7 +2314,7 @@@ int has_unstaged_changes(int ignore_sub
        struct rev_info rev_info;
        int result;
  
-       init_revisions(&rev_info, NULL);
+       repo_init_revisions(the_repository, &rev_info, NULL);
        if (ignore_submodules) {
                rev_info.diffopt.flags.ignore_submodules = 1;
                rev_info.diffopt.flags.override_submodule_config = 1;
@@@ -2336,7 -2336,7 +2336,7 @@@ int has_uncommitted_changes(int ignore_
        if (is_cache_unborn())
                return 0;
  
-       init_revisions(&rev_info, NULL);
+       repo_init_revisions(the_repository, &rev_info, NULL);
        if (ignore_submodules)
                rev_info.diffopt.flags.ignore_submodules = 1;
        rev_info.diffopt.flags.quick = 1;