Merge branch 'tg/checkout-no-overlay'
authorJunio C Hamano <gitster@pobox.com>
Thu, 7 Mar 2019 00:59:51 +0000 (09:59 +0900)
committerJunio C Hamano <gitster@pobox.com>
Thu, 7 Mar 2019 00:59:51 +0000 (09:59 +0900)
"git checkout --no-overlay" can be used to trigger a new mode of
checking out paths out of the tree-ish, that allows paths that
match the pathspec that are in the current index and working tree
and are not in the tree-ish.

* tg/checkout-no-overlay:
revert "checkout: introduce checkout.overlayMode config"
checkout: introduce checkout.overlayMode config
checkout: introduce --{,no-}overlay option
checkout: factor out mark_cache_entry_for_checkout function
checkout: clarify comment
read-cache: add invalidate parameter to remove_marked_cache_entries
entry: support CE_WT_REMOVE flag in checkout_entry
entry: factor out unlink_entry function
move worktree tests to t24*

1  2 
Documentation/git-checkout.txt
builtin/checkout.c
cache.h
entry.c
read-cache.c
t/t2403-worktree-move.sh
t/t9902-completion.sh
unpack-trees.c
index 8c3d4128c2871274967cd30029e2390e48d0dcc1,24e52b01e1897528780efed7ccb4490b897ec670..f179b43732aa2a7e211a95889847294890c90d38
@@@ -260,6 -260,9 +260,9 @@@ the conflicted merge in the specified p
  This means that you can use `git checkout -p` to selectively discard
  edits from your current working tree. See the ``Interactive Mode''
  section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
+ +
+ Note that this option uses the no overlay mode by default (see also
+ `--[no-]overlay`), and currently doesn't support overlay mode.
  
  --ignore-other-worktrees::
        `git checkout` refuses when the wanted ref is already checked
        Just like linkgit:git-submodule[1], this will detach the
        submodules HEAD.
  
 +--no-guess::
 +      Do not attempt to create a branch if a remote tracking branch
 +      of the same name exists.
 +
+ --[no-]overlay::
+       In the default overlay mode, `git checkout` never
+       removes files from the index or the working tree.  When
+       specifying `--no-overlay`, files that appear in the index and
+       working tree, but not in <tree-ish> are removed, to make them
+       match <tree-ish> exactly.
  <branch>::
        Branch to checkout; if it refers to a branch (i.e., a name that,
        when prepended with "refs/heads/", is a valid ref), then that
  +
  You can use the `"@{-N}"` syntax to refer to the N-th last
  branch/commit checked out using "git checkout" operation. You may
 -also specify `-` which is synonymous to `"@{-1}`.
 +also specify `-` which is synonymous to `"@{-1}"`.
  +
  As a special case, you may use `"A...B"` as a shortcut for the
  merge base of `A` and `B` if there is exactly one merge base. You can
@@@ -424,14 -430,14 +434,14 @@@ $ git tag foo           <3
  ------------
  
  <1> creates a new branch 'foo', which refers to commit 'f', and then
 -updates HEAD to refer to branch 'foo'. In other words, we'll no longer
 -be in detached HEAD state after this command.
 +    updates HEAD to refer to branch 'foo'. In other words, we'll no longer
 +    be in detached HEAD state after this command.
  
  <2> similarly creates a new branch 'foo', which refers to commit 'f',
 -but leaves HEAD detached.
 +    but leaves HEAD detached.
  
  <3> creates a new tag 'foo', which refers to commit 'f',
 -leaving HEAD detached.
 +    leaving HEAD detached.
  
  If we have moved away from commit 'f', then we must first recover its object
  name (typically by using git reflog), and then we can create a reference to
@@@ -459,8 -465,8 +469,8 @@@ EXAMPLE
  --------
  
  . The following sequence checks out the `master` branch, reverts
 -the `Makefile` to two revisions back, deletes hello.c by
 -mistake, and gets it back from the index.
 +  the `Makefile` to two revisions back, deletes hello.c by
 +  mistake, and gets it back from the index.
  +
  ------------
  $ git checkout master             <1>
@@@ -494,7 -500,7 +504,7 @@@ $ git checkout -- hello.
  ------------
  
  . After working in the wrong branch, switching to the correct
 -branch would be done using:
 +  branch would be done using:
  +
  ------------
  $ git checkout mytopic
@@@ -522,7 -528,7 +532,7 @@@ registered in your index file, so `git 
  changes you made since the tip of the new branch.
  
  . When a merge conflict happens during switching branches with
 -the `-m` option, you would see something like this:
 +  the `-m` option, you would see something like this:
  +
  ------------
  $ git checkout -m mytopic
diff --combined builtin/checkout.c
index 24b8593b938b67baf4a662f2463efdd35562873a,0c5fe948ef58901870949532b1a4bfc2b1870452..bea08ef959189cff99e34170a2999a52953a3020
@@@ -1,4 -1,3 +1,4 @@@
 +#define USE_THE_INDEX_COMPATIBILITY_MACROS
  #include "builtin.h"
  #include "config.h"
  #include "checkout.h"
@@@ -45,7 -44,7 +45,8 @@@ struct checkout_opts 
        int ignore_skipworktree;
        int ignore_other_worktrees;
        int show_progress;
 +      int count_checkout_paths;
+       int overlay_mode;
        /*
         * If new checkout options are added, skip_merge_working_tree
         * should be updated accordingly.
@@@ -117,8 -116,7 +118,8 @@@ static int update_some(const struct obj
  
  static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
  {
 -      read_tree_recursive(tree, "", 0, 0, pathspec, update_some, NULL);
 +      read_tree_recursive(the_repository, tree, "", 0, 0,
 +                          pathspec, update_some, NULL);
  
        /* update the index with the given tree's info
         * for all args, expanding wildcards, and exit
@@@ -135,7 -133,8 +136,8 @@@ static int skip_same_name(const struct 
        return pos;
  }
  
- static int check_stage(int stage, const struct cache_entry *ce, int pos)
+ static int check_stage(int stage, const struct cache_entry *ce, int pos,
+                      int overlay_mode)
  {
        while (pos < active_nr &&
               !strcmp(active_cache[pos]->name, ce->name)) {
                        return 0;
                pos++;
        }
+       if (!overlay_mode)
+               return 0;
        if (stage == 2)
                return error(_("path '%s' does not have our version"), ce->name);
        else
@@@ -168,22 -169,25 +172,27 @@@ static int check_stages(unsigned stages
  }
  
  static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
-                         const struct checkout *state, int *nr_checkouts)
 -                        const struct checkout *state, int overlay_mode)
++                        const struct checkout *state, int *nr_checkouts,
++                        int overlay_mode)
  {
        while (pos < active_nr &&
               !strcmp(active_cache[pos]->name, ce->name)) {
                if (ce_stage(active_cache[pos]) == stage)
 -                      return checkout_entry(active_cache[pos], state, NULL);
 +                      return checkout_entry(active_cache[pos], state,
 +                                            NULL, nr_checkouts);
                pos++;
        }
+       if (!overlay_mode) {
+               unlink_entry(ce);
+               return 0;
+       }
        if (stage == 2)
                return error(_("path '%s' does not have our version"), ce->name);
        else
                return error(_("path '%s' does not have their version"), ce->name);
  }
  
 -static int checkout_merged(int pos, const struct checkout *state)
 +static int checkout_merged(int pos, const struct checkout *state, int *nr_checkouts)
  {
        struct cache_entry *ce = active_cache[pos];
        const char *path = ce->name;
        ce = make_transient_cache_entry(mode, &oid, path, 2);
        if (!ce)
                die(_("make_cache_entry failed for path '%s'"), path);
 -      status = checkout_entry(ce, state, NULL);
 +      status = checkout_entry(ce, state, NULL, nr_checkouts);
        discard_cache_entry(ce);
        return status;
  }
  
+ static void mark_ce_for_checkout_overlay(struct cache_entry *ce,
+                                        char *ps_matched,
+                                        const struct checkout_opts *opts)
+ {
+       ce->ce_flags &= ~CE_MATCHED;
+       if (!opts->ignore_skipworktree && ce_skip_worktree(ce))
+               return;
+       if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
+               /*
+                * "git checkout tree-ish -- path", but this entry
+                * is in the original index but is not in tree-ish
+                * or does not match the pathspec; it will not be
+                * checked out to the working tree.  We will not do
+                * anything to this entry at all.
+                */
+               return;
+       /*
+        * Either this entry came from the tree-ish we are
+        * checking the paths out of, or we are checking out
+        * of the index.
+        *
+        * If it comes from the tree-ish, we already know it
+        * matches the pathspec and could just stamp
+        * CE_MATCHED to it from update_some(). But we still
+        * need ps_matched and read_tree_recursive (and
+        * eventually tree_entry_interesting) cannot fill
+        * ps_matched yet. Once it can, we can avoid calling
+        * match_pathspec() for _all_ entries when
+        * opts->source_tree != NULL.
+        */
+       if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched))
+               ce->ce_flags |= CE_MATCHED;
+ }
+ static void mark_ce_for_checkout_no_overlay(struct cache_entry *ce,
+                                           char *ps_matched,
+                                           const struct checkout_opts *opts)
+ {
+       ce->ce_flags &= ~CE_MATCHED;
+       if (!opts->ignore_skipworktree && ce_skip_worktree(ce))
+               return;
+       if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) {
+               ce->ce_flags |= CE_MATCHED;
+               if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
+                       /*
+                        * In overlay mode, but the path is not in
+                        * tree-ish, which means we should remove it
+                        * from the index and the working tree.
+                        */
+                       ce->ce_flags |= CE_REMOVE | CE_WT_REMOVE;
+       }
+ }
  static int checkout_paths(const struct checkout_opts *opts,
                          const char *revision)
  {
        struct commit *head;
        int errs = 0;
        struct lock_file lock_file = LOCK_INIT;
 +      int nr_checkouts = 0, nr_unmerged = 0;
  
        if (opts->track != BRANCH_TRACK_UNSPECIFIED)
                die(_("'%s' cannot be used with updating paths"), "--track");
                return run_add_interactive(revision, "--patch=checkout",
                                           &opts->pathspec);
  
 -      hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
 +      repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
        if (read_cache_preload(&opts->pathspec) < 0)
                return error(_("index file corrupt"));
  
         * Make sure all pathspecs participated in locating the paths
         * to be checked out.
         */
-       for (pos = 0; pos < active_nr; pos++) {
-               struct cache_entry *ce = active_cache[pos];
-               ce->ce_flags &= ~CE_MATCHED;
-               if (!opts->ignore_skipworktree && ce_skip_worktree(ce))
-                       continue;
-               if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
-                       /*
-                        * "git checkout tree-ish -- path", but this entry
-                        * is in the original index; it will not be checked
-                        * out to the working tree and it does not matter
-                        * if pathspec matched this entry.  We will not do
-                        * anything to this entry at all.
-                        */
-                       continue;
-               /*
-                * Either this entry came from the tree-ish we are
-                * checking the paths out of, or we are checking out
-                * of the index.
-                *
-                * If it comes from the tree-ish, we already know it
-                * matches the pathspec and could just stamp
-                * CE_MATCHED to it from update_some(). But we still
-                * need ps_matched and read_tree_recursive (and
-                * eventually tree_entry_interesting) cannot fill
-                * ps_matched yet. Once it can, we can avoid calling
-                * match_pathspec() for _all_ entries when
-                * opts->source_tree != NULL.
-                */
-               if (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched))
-                       ce->ce_flags |= CE_MATCHED;
-       }
+       for (pos = 0; pos < active_nr; pos++)
+               if (opts->overlay_mode)
+                       mark_ce_for_checkout_overlay(active_cache[pos],
+                                                    ps_matched,
+                                                    opts);
+               else
+                       mark_ce_for_checkout_no_overlay(active_cache[pos],
+                                                       ps_matched,
+                                                       opts);
  
        if (report_path_error(ps_matched, &opts->pathspec, opts->prefix)) {
                free(ps_matched);
                        if (opts->force) {
                                warning(_("path '%s' is unmerged"), ce->name);
                        } else if (opts->writeout_stage) {
-                               errs |= check_stage(opts->writeout_stage, ce, pos);
+                               errs |= check_stage(opts->writeout_stage, ce, pos, opts->overlay_mode);
                        } else if (opts->merge) {
                                errs |= check_stages((1<<2) | (1<<3), ce, pos);
                        } else {
                struct cache_entry *ce = active_cache[pos];
                if (ce->ce_flags & CE_MATCHED) {
                        if (!ce_stage(ce)) {
 -                              errs |= checkout_entry(ce, &state, NULL);
 +                              errs |= checkout_entry(ce, &state,
 +                                                     NULL, &nr_checkouts);
                                continue;
                        }
                        if (opts->writeout_stage)
 -                              errs |= checkout_stage(opts->writeout_stage, ce, pos, &state, opts->overlay_mode);
 +                              errs |= checkout_stage(opts->writeout_stage,
 +                                                     ce, pos,
-                                                      &state, &nr_checkouts);
++                                                     &state,
++                                                     &nr_checkouts, opts->overlay_mode);
                        else if (opts->merge)
 -                              errs |= checkout_merged(pos, &state);
 +                              errs |= checkout_merged(pos, &state,
 +                                                      &nr_unmerged);
                        pos = skip_same_name(ce, pos) - 1;
                }
        }
 -      errs |= finish_delayed_checkout(&state);
+       remove_marked_cache_entries(&the_index, 1);
+       remove_scheduled_dirs();
 +      errs |= finish_delayed_checkout(&state, &nr_checkouts);
 +
 +      if (opts->count_checkout_paths) {
 +              if (nr_unmerged)
 +                      fprintf_ln(stderr, Q_("Recreated %d merge conflict",
 +                                            "Recreated %d merge conflicts",
 +                                            nr_unmerged),
 +                                 nr_unmerged);
 +              if (opts->source_tree)
 +                      fprintf_ln(stderr, Q_("Updated %d path from %s",
 +                                            "Updated %d paths from %s",
 +                                            nr_checkouts),
 +                                 nr_checkouts,
 +                                 find_unique_abbrev(&opts->source_tree->object.oid,
 +                                                    DEFAULT_ABBREV));
 +              else if (!nr_unmerged || nr_checkouts)
 +                      fprintf_ln(stderr, Q_("Updated %d path from the index",
 +                                            "Updated %d paths from the index",
 +                                            nr_checkouts),
 +                                 nr_checkouts);
 +      }
  
        if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
@@@ -571,6 -583,11 +614,11 @@@ static int skip_merge_working_tree(cons
         * opts->show_progress only impacts output so doesn't require a merge
         */
  
+       /*
+        * opts->overlay_mode cannot be used with switching branches so is
+        * not tested here
+        */
        /*
         * If we aren't creating a new branch any changes or updates will
         * happen in the existing branch.  Since that could only be updating
         * Remaining variables are not checkout options but used to track state
         */
  
 +       /*
 +        * Do the merge if this is the initial checkout. We cannot use
 +        * is_cache_unborn() here because the index hasn't been loaded yet
 +        * so cache_nr and timestamp.sec are always zero.
 +        */
 +      if (!file_exists(get_index_file()))
 +              return 0;
 +
        return 1;
  }
  
@@@ -707,7 -716,7 +755,7 @@@ static int merge_working_tree(const str
                         * a pain; plumb in an option to set
                         * o.renormalize?
                         */
 -                      init_merge_options(&o);
 +                      init_merge_options(&o, the_repository);
                        o.verbosity = 0;
                        work = write_tree_from_memory(&o);
  
@@@ -790,8 -799,7 +838,8 @@@ static void update_refs_for_switch(cons
                        free(refname);
                }
                else
 -                      create_branch(opts->new_branch, new_branch_info->name,
 +                      create_branch(the_repository,
 +                                    opts->new_branch, new_branch_info->name,
                                      opts->new_branch_force ? 1 : 0,
                                      opts->new_branch_force ? 1 : 0,
                                      opts->new_branch_log,
                                delete_reflog(old_branch_info->path);
                }
        }
 -      remove_branch_state();
 +      remove_branch_state(the_repository);
        strbuf_release(&msg);
        if (!opts->quiet &&
            (new_branch_info->path || (!opts->force_detach && !strcmp(new_branch_info->name, "HEAD"))))
@@@ -1102,7 -1110,6 +1150,7 @@@ static int parse_branchname_arg(int arg
                has_dash_dash = 1; /* case (3) or (1) */
        else if (dash_dash_pos >= 2)
                die(_("only one reference expected, %d given."), dash_dash_pos);
 +      opts->count_checkout_paths = !opts->quiet && !has_dash_dash;
  
        if (!strcmp(arg, "-"))
                arg = "@{-1}";
                 */
                int recover_with_dwim = dwim_new_local_branch_ok;
  
 -              if (!has_dash_dash &&
 -                  (check_filename(opts->prefix, arg) || !no_wildcard(arg)))
 +              int could_be_checkout_paths = !has_dash_dash &&
 +                      check_filename(opts->prefix, arg);
 +
 +              if (!has_dash_dash && !no_wildcard(arg))
                        recover_with_dwim = 0;
 +
                /*
                 * Accept "git checkout foo" and "git checkout foo --"
                 * as candidates for dwim.
                        const char *remote = unique_tracking_name(arg, rev,
                                                                  dwim_remotes_matched);
                        if (remote) {
 +                              if (could_be_checkout_paths)
 +                                      die(_("'%s' could be both a local file and a tracking branch.\n"
 +                                            "Please use -- (and optionally --no-guess) to disambiguate"),
 +                                          arg);
                                *new_branch = arg;
                                arg = remote;
                                /* DWIMmed to create local branch, case (3).(b) */
@@@ -1224,6 -1224,10 +1272,10 @@@ static int checkout_branch(struct check
                die(_("'%s' cannot be used with switching branches"),
                    "--patch");
  
+       if (!opts->overlay_mode)
+               die(_("'%s' cannot be used with switching branches"),
+                   "--no-overlay");
        if (opts->writeout_stage)
                die(_("'%s' cannot be used with switching branches"),
                    "--ours/--theirs");
@@@ -1274,7 -1278,7 +1326,7 @@@ int cmd_checkout(int argc, const char *
        struct checkout_opts opts;
        struct branch_info new_branch_info;
        char *conflict_style = NULL;
 -      int dwim_new_local_branch = 1;
 +      int dwim_new_local_branch, no_dwim_new_local_branch = 0;
        int dwim_remotes_matched = 0;
        struct option options[] = {
                OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
                OPT_BOOL('p', "patch", &opts.patch_mode, N_("select hunks interactively")),
                OPT_BOOL(0, "ignore-skip-worktree-bits", &opts.ignore_skipworktree,
                         N_("do not limit pathspecs to sparse entries only")),
 -              OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
 -                              N_("second guess 'git checkout <no-such-branch>'")),
 +              OPT_BOOL(0, "no-guess", &no_dwim_new_local_branch,
 +                       N_("do not second guess 'git checkout <no-such-branch>'")),
                OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
                         N_("do not check if another worktree is holding the given ref")),
                { OPTION_CALLBACK, 0, "recurse-submodules", NULL,
                            "checkout", "control recursive updating of submodules",
                            PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },
                OPT_BOOL(0, "progress", &opts.show_progress, N_("force progress reporting")),
+               OPT_BOOL(0, "overlay", &opts.overlay_mode, N_("use overlay mode (default)")),
                OPT_END(),
        };
  
        opts.overwrite_ignore = 1;
        opts.prefix = prefix;
        opts.show_progress = -1;
+       opts.overlay_mode = -1;
  
        git_config(git_checkout_config, &opts);
  
        argc = parse_options(argc, argv, prefix, options, checkout_usage,
                             PARSE_OPT_KEEP_DASHDASH);
  
 +      dwim_new_local_branch = !no_dwim_new_local_branch;
        if (opts.show_progress < 0) {
                if (opts.quiet)
                        opts.show_progress = 0;
        if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)
                die(_("-b, -B and --orphan are mutually exclusive"));
  
+       if (opts.overlay_mode == 1 && opts.patch_mode)
+               die(_("-p and --overlay are mutually exclusive"));
        /*
         * From here on, new_branch will contain the branch to be checked out,
         * and new_branch_force and new_orphan_branch will tell us which one of
diff --combined cache.h
index 27fe635f622c49e2a21ffcb91d3113d3b3fbad8c,1deee48f5bff74226eb4f1ed21bc607a98d85b9e..473fa1eff10acf6f6e8357c6dabff6289883cdd0
+++ b/cache.h
@@@ -45,20 -45,10 +45,20 @@@ unsigned long git_deflate_bound(git_zst
  /* The length in bytes and in hex digits of an object name (SHA-1 value). */
  #define GIT_SHA1_RAWSZ 20
  #define GIT_SHA1_HEXSZ (2 * GIT_SHA1_RAWSZ)
 +/* The block size of SHA-1. */
 +#define GIT_SHA1_BLKSZ 64
 +
 +/* The length in bytes and in hex digits of an object name (SHA-256 value). */
 +#define GIT_SHA256_RAWSZ 32
 +#define GIT_SHA256_HEXSZ (2 * GIT_SHA256_RAWSZ)
 +/* The block size of SHA-256. */
 +#define GIT_SHA256_BLKSZ 64
  
  /* The length in byte and in hex digits of the largest possible hash value. */
 -#define GIT_MAX_RAWSZ GIT_SHA1_RAWSZ
 -#define GIT_MAX_HEXSZ GIT_SHA1_HEXSZ
 +#define GIT_MAX_RAWSZ GIT_SHA256_RAWSZ
 +#define GIT_MAX_HEXSZ GIT_SHA256_HEXSZ
 +/* The largest possible block size for any supported hash. */
 +#define GIT_MAX_BLKSZ GIT_SHA256_BLKSZ
  
  struct object_id {
        unsigned char hash[GIT_MAX_RAWSZ];
@@@ -348,6 -338,8 +348,6 @@@ struct index_state 
        struct mem_pool *ce_mem_pool;
  };
  
 -extern struct index_state the_index;
 -
  /* Name hashing */
  extern int test_lazy_init_name_hash(struct index_state *istate, int try_threaded);
  extern void add_name_hash(struct index_state *istate, struct cache_entry *ce);
@@@ -409,20 -401,18 +409,20 @@@ struct cache_entry *dup_cache_entry(con
   */
  void validate_cache_entries(const struct index_state *istate);
  
 -#ifndef NO_THE_INDEX_COMPATIBILITY_MACROS
 +#ifdef USE_THE_INDEX_COMPATIBILITY_MACROS
 +extern struct index_state the_index;
 +
  #define active_cache (the_index.cache)
  #define active_nr (the_index.cache_nr)
  #define active_alloc (the_index.cache_alloc)
  #define active_cache_changed (the_index.cache_changed)
  #define active_cache_tree (the_index.cache_tree)
  
 -#define read_cache() read_index(&the_index)
 +#define read_cache() repo_read_index(the_repository)
  #define read_cache_from(path) read_index_from(&the_index, (path), (get_git_dir()))
 -#define read_cache_preload(pathspec) read_index_preload(&the_index, (pathspec), 0)
 +#define read_cache_preload(pathspec) repo_read_index_preload(the_repository, (pathspec), 0)
  #define is_cache_unborn() is_index_unborn(&the_index)
 -#define read_cache_unmerged() read_index_unmerged(&the_index)
 +#define read_cache_unmerged() repo_read_index_unmerged(the_repository)
  #define discard_cache() discard_index(&the_index)
  #define unmerged_cache() unmerged_index(&the_index)
  #define cache_name_pos(name, namelen) index_name_pos(&the_index,(name),(namelen))
  #define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)
  #define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)
  #define read_blob_data_from_cache(path, sz) read_blob_data_from_index(&the_index, (path), (sz))
 +#define hold_locked_index(lock_file, flags) repo_hold_locked_index(the_repository, (lock_file), (flags))
  #endif
  
  #define TYPE_BITS 3
@@@ -671,14 -660,19 +671,14 @@@ extern int daemonize(void)
  
  /* Initialize and use the cache information */
  struct lock_file;
 -extern int read_index(struct index_state *);
  extern void preload_index(struct index_state *index,
                          const struct pathspec *pathspec,
                          unsigned int refresh_flags);
 -extern int read_index_preload(struct index_state *,
 -                            const struct pathspec *pathspec,
 -                            unsigned int refresh_flags);
  extern int do_read_index(struct index_state *istate, const char *path,
                         int must_exist); /* for testting only! */
  extern int read_index_from(struct index_state *, const char *path,
                           const char *gitdir);
  extern int is_index_unborn(struct index_state *);
 -extern int read_index_unmerged(struct index_state *);
  
  /* For use with `write_locked_index()`. */
  #define COMMIT_LOCK           (1 << 0)
@@@ -716,9 -710,9 +716,9 @@@ 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(struct index_state *istate,
 -                           struct tree *tree,
 -                           struct strbuf *sb);
 +extern int repo_index_has_changes(struct repository *repo,
 +                                struct tree *tree,
 +                                struct strbuf *sb);
  
  extern int verify_path(const char *path, unsigned mode);
  extern int strcmp_offset(const char *s1, const char *s2, size_t *first_change);
@@@ -751,14 -745,13 +751,14 @@@ extern int index_name_pos(const struct 
  #define ADD_CACHE_JUST_APPEND 8               /* Append only; tree.c::read_tree() */
  #define ADD_CACHE_NEW_ONLY 16         /* Do not replace existing ones */
  #define ADD_CACHE_KEEP_CACHE_TREE 32  /* Do not invalidate cache-tree */
 +#define ADD_CACHE_RENORMALIZE 64        /* Pass along HASH_RENORMALIZE */
  extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
  extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
  
  /* Remove entry, return true if there are more entries to go. */
  extern int remove_index_entry_at(struct index_state *, int pos);
  
- extern void remove_marked_cache_entries(struct index_state *istate);
+ extern void remove_marked_cache_entries(struct index_state *istate, int invalidate);
  extern int remove_file_from_index(struct index_state *, const char *path);
  #define ADD_CACHE_VERBOSE 1
  #define ADD_CACHE_PRETEND 2
@@@ -834,6 -827,13 +834,6 @@@ extern void fill_stat_cache_info(struc
  extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
  extern struct cache_entry *refresh_cache_entry(struct index_state *, struct cache_entry *, unsigned int);
  
 -/*
 - * Opportunistically update the index but do not complain if we can't.
 - * The lockfile is always committed or rolled back.
 - */
 -extern void update_index_if_able(struct index_state *, struct lock_file *);
 -
 -extern int hold_locked_index(struct lock_file *, int);
  extern void set_alternate_index_output(const char *);
  
  extern int verify_index_checksum;
@@@ -1028,12 -1028,16 +1028,12 @@@ extern const struct object_id null_oid
  static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
  {
        /*
 -       * This is a temporary optimization hack. By asserting the size here,
 -       * we let the compiler know that it's always going to be 20, which lets
 -       * it turn this fixed-size memcmp into a few inline instructions.
 -       *
 -       * This will need to be extended or ripped out when we learn about
 -       * hashes of different sizes.
 +       * Teach the compiler that there are only two possibilities of hash size
 +       * here, so that it can optimize for this case as much as possible.
         */
 -      if (the_hash_algo->rawsz != 20)
 -              BUG("hash size not yet supported by hashcmp");
 -      return memcmp(sha1, sha2, the_hash_algo->rawsz);
 +      if (the_hash_algo->rawsz == GIT_MAX_RAWSZ)
 +              return memcmp(sha1, sha2, GIT_MAX_RAWSZ);
 +      return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
  }
  
  static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)
  
  static inline int hasheq(const unsigned char *sha1, const unsigned char *sha2)
  {
 -      return !hashcmp(sha1, sha2);
 +      /*
 +       * We write this here instead of deferring to hashcmp so that the
 +       * compiler can properly inline it and avoid calling memcmp.
 +       */
 +      if (the_hash_algo->rawsz == GIT_MAX_RAWSZ)
 +              return !memcmp(sha1, sha2, GIT_MAX_RAWSZ);
 +      return !memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
  }
  
  static inline int oideq(const struct object_id *oid1, const struct object_id *oid2)
@@@ -1074,7 -1072,7 +1074,7 @@@ static inline void hashcpy(unsigned cha
  
  static inline void oidcpy(struct object_id *dst, const struct object_id *src)
  {
 -      hashcpy(dst->hash, src->hash);
 +      memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);
  }
  
  static inline struct object_id *oiddup(const struct object_id *src)
@@@ -1271,8 -1269,8 +1271,8 @@@ extern char *xdg_cache_home(const char 
  
  extern int git_open_cloexec(const char *name, int flags);
  #define git_open(name) git_open_cloexec(name, O_RDONLY)
 -extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
 -extern int parse_sha1_header(const char *hdr, unsigned long *sizep);
 +extern int unpack_loose_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
 +extern int parse_loose_header(const char *hdr, unsigned long *sizep);
  
  extern int check_object_signature(const struct object_id *oid, void *buf, unsigned long size, const char *type);
  
@@@ -1334,24 -1332,6 +1334,24 @@@ struct object_context 
        GET_OID_TREE | GET_OID_TREEISH | \
        GET_OID_BLOB)
  
 +enum get_oid_result {
 +      FOUND = 0,
 +      MISSING_OBJECT = -1, /* The requested object is missing */
 +      SHORT_NAME_AMBIGUOUS = -2,
 +      /* The following only apply when symlinks are followed */
 +      DANGLING_SYMLINK = -4, /*
 +                              * The initial symlink is there, but
 +                              * (transitively) points to a missing
 +                              * in-tree file
 +                              */
 +      SYMLINK_LOOP = -5,
 +      NOT_DIR = -6, /*
 +                     * Somewhere along the symlink chain, a path is
 +                     * requested which contains a file as a
 +                     * non-final element.
 +                     */
 +};
 +
  extern int get_oid(const char *str, struct object_id *oid);
  extern int get_oid_commit(const char *str, struct object_id *oid);
  extern int get_oid_committish(const char *str, struct object_id *oid);
@@@ -1359,9 -1339,8 +1359,9 @@@ extern int get_oid_tree(const char *str
  extern int get_oid_treeish(const char *str, struct object_id *oid);
  extern int get_oid_blob(const char *str, struct object_id *oid);
  extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
 -extern int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc);
 -
 +extern enum get_oid_result get_oid_with_context(struct repository *repo, const char *str,
 +                              unsigned flags, struct object_id *oid,
 +                              struct object_context *oc);
  
  typedef int each_abbrev_fn(const struct object_id *oid, void *);
  extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
@@@ -1386,9 -1365,9 +1386,9 @@@ extern int get_oid_hex(const char *hex
  extern int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
  
  /*
 - * Convert a binary sha1 to its hex equivalent. The `_r` variant is reentrant,
 + * Convert a binary hash to its hex equivalent. The `_r` variant is reentrant,
   * and writes the NUL-terminated output to the buffer `out`, which must be at
 - * least `GIT_SHA1_HEXSZ + 1` bytes, and returns a pointer to out for
 + * least `GIT_MAX_HEXSZ + 1` bytes, and returns a pointer to out for
   * convenience.
   *
   * The non-`_r` variant returns a static buffer, but uses a ring of 4
   *
   *   printf("%s -> %s", sha1_to_hex(one), sha1_to_hex(two));
   */
 -extern char *sha1_to_hex_r(char *out, const unsigned char *sha1);
 -extern char *oid_to_hex_r(char *out, const struct object_id *oid);
 -extern char *sha1_to_hex(const unsigned char *sha1);  /* static buffer result! */
 -extern char *oid_to_hex(const struct object_id *oid); /* same static buffer as sha1_to_hex */
 +char *hash_to_hex_algop_r(char *buffer, const unsigned char *hash, const struct git_hash_algo *);
 +char *sha1_to_hex_r(char *out, const unsigned char *sha1);
 +char *oid_to_hex_r(char *out, const struct object_id *oid);
 +char *hash_to_hex_algop(const unsigned char *hash, const struct git_hash_algo *);     /* static buffer result! */
 +char *sha1_to_hex(const unsigned char *sha1);                                         /* same static buffer */
 +char *hash_to_hex(const unsigned char *hash);                                         /* same static buffer */
 +char *oid_to_hex(const struct object_id *oid);                                                /* same static buffer */
  
  /*
   * Parse a 40-character hexadecimal object ID starting from hex, updating the
@@@ -1463,7 -1439,6 +1463,7 @@@ extern struct object *peel_to_type(cons
  
  enum date_mode_type {
        DATE_NORMAL = 0,
 +      DATE_HUMAN,
        DATE_RELATIVE,
        DATE_SHORT,
        DATE_ISO8601,
@@@ -1489,9 -1464,7 +1489,9 @@@ struct date_mode 
  struct date_mode *date_mode_from_type(enum date_mode_type type);
  
  const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);
 -void show_date_relative(timestamp_t time, int tz, const struct timeval *now,
 +void show_date_relative(timestamp_t time, const struct timeval *now,
 +                      struct strbuf *timebuf);
 +void show_date_human(timestamp_t time, int tz, const struct timeval *now,
                        struct strbuf *timebuf);
  int parse_date(const char *date, struct strbuf *out);
  int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);
@@@ -1566,9 -1539,14 +1566,14 @@@ struct checkout 
  #define CHECKOUT_INIT { NULL, "" }
  
  #define TEMPORARY_FILENAME_LENGTH 25
 -extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
 +extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath, int *nr_checkouts);
  extern void enable_delayed_checkout(struct checkout *state);
 -extern int finish_delayed_checkout(struct checkout *state);
 +extern int finish_delayed_checkout(struct checkout *state, int *nr_checkouts);
+ /*
+  * Unlink the last component and schedule the leading directories for
+  * removal, such that empty directories get removed.
+  */
+ extern void unlink_entry(const struct cache_entry *ce);
  
  struct cache_def {
        struct strbuf path;
@@@ -1619,7 -1597,7 +1624,7 @@@ extern int odb_mkstemp(struct strbuf *t
  extern int odb_pack_keep(const char *name);
  
  /*
 - * Set this to 0 to prevent sha1_object_info_extended() from fetching missing
 + * Set this to 0 to prevent oid_object_info_extended() from fetching missing
   * blobs. This has a difference only if extensions.partialClone is set.
   *
   * Its default value is 1.
@@@ -1815,7 -1793,4 +1820,7 @@@ void safe_create_dir(const char *dir, i
   */
  extern int print_sha1_ellipsis(void);
  
 +/* Return 1 if the file is empty or does not exists, 0 otherwise. */
 +extern int is_empty_or_missing_file(const char *filename);
 +
  #endif /* CACHE_H */
diff --combined entry.c
index 6fd72b30c8768677f044923ef5e715949d32fdae,3d3701e7ae148b623e353ad2874e9dce28cca32b..0e4f2f29101f913d0db2c401851f279eac496f02
+++ b/entry.c
@@@ -161,7 -161,7 +161,7 @@@ static int remove_available_paths(struc
        return !available;
  }
  
 -int finish_delayed_checkout(struct checkout *state)
 +int finish_delayed_checkout(struct checkout *state, int *nr_checkouts)
  {
        int errs = 0;
        unsigned delayed_object_count;
                                ce = index_file_exists(state->istate, path->string,
                                                       strlen(path->string), 0);
                                if (ce) {
 -                                      errs |= checkout_entry(ce, state, NULL);
 +                                      errs |= checkout_entry(ce, state, NULL, nr_checkouts);
                                        filtered_bytes += ce->ce_stat_data.sd_size;
                                        display_throughput(progress, filtered_bytes);
                                } else
@@@ -435,12 -435,23 +435,23 @@@ static void mark_colliding_entries(cons
   * its name is returned in topath[], which must be able to hold at
   * least TEMPORARY_FILENAME_LENGTH bytes long.
   */
 -int checkout_entry(struct cache_entry *ce,
 -                 const struct checkout *state, char *topath)
 +int checkout_entry(struct cache_entry *ce, const struct checkout *state,
 +                 char *topath, int *nr_checkouts)
  {
        static struct strbuf path = STRBUF_INIT;
        struct stat st;
  
+       if (ce->ce_flags & CE_WT_REMOVE) {
+               if (topath)
+                       /*
+                        * No content and thus no path to create, so we have
+                        * no pathname to return.
+                        */
+                       BUG("Can't remove entry to a path");
+               unlink_entry(ce);
+               return 0;
+       }
        if (topath)
                return write_entry(ce, topath, state, 1);
  
                return 0;
  
        create_directories(path.buf, path.len, state);
 +      if (nr_checkouts)
 +              (*nr_checkouts)++;
        return write_entry(ce, path.buf, state, 0);
  }
+ void unlink_entry(const struct cache_entry *ce)
+ {
+       const struct submodule *sub = submodule_from_ce(ce);
+       if (sub) {
+               /* state.force is set at the caller. */
+               submodule_move_head(ce->name, "HEAD", NULL,
+                                   SUBMODULE_MOVE_HEAD_FORCE);
+       }
+       if (!check_leading_path(ce->name, ce_namelen(ce)))
+               return;
+       if (remove_or_warn(ce->ce_mode, ce->name))
+               return;
+       schedule_dir_for_removal(ce->name, ce_namelen(ce));
+ }
diff --combined read-cache.c
index 0e0c93edc9be5a7af5de1097eafe9d860e7d183e,978d43f6763999c90845eefb5912135ee1a76d47..75ff234fc8674c749ee10175a5557c4c23bfe39f
@@@ -3,6 -3,7 +3,6 @@@
   *
   * Copyright (C) Linus Torvalds, 2005
   */
 -#define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
  #include "config.h"
  #include "diff.h"
@@@ -94,6 -95,7 +94,6 @@@ static struct mem_pool *find_mem_pool(s
        return *pool_ptr;
  }
  
 -struct index_state the_index;
  static const char *alternate_index_output;
  
  static void set_index_entry(struct index_state *istate, int nr, struct cache_entry *ce)
@@@ -314,7 -316,7 +314,7 @@@ static int ce_match_stat_basic(const st
                        changed |= DATA_CHANGED;
                return changed;
        default:
 -              die("internal error: ce_mode is %o", ce->ce_mode);
 +              BUG("unsupported ce_mode: %o", ce->ce_mode);
        }
  
        changed |= match_stat_data(&ce->ce_stat_data, st);
@@@ -588,13 -590,19 +588,19 @@@ int remove_index_entry_at(struct index_
   * CE_REMOVE is set in ce_flags.  This is much more effective than
   * calling remove_index_entry_at() for each entry to be removed.
   */
- void remove_marked_cache_entries(struct index_state *istate)
+ void remove_marked_cache_entries(struct index_state *istate, int invalidate)
  {
        struct cache_entry **ce_array = istate->cache;
        unsigned int i, j;
  
        for (i = j = 0; i < istate->cache_nr; i++) {
                if (ce_array[i]->ce_flags & CE_REMOVE) {
+                       if (invalidate) {
+                               cache_tree_invalidate_path(istate,
+                                                          ce_array[i]->name);
+                               untracked_cache_remove_from_index(istate,
+                                                                 ce_array[i]->name);
+                       }
                        remove_name_hash(istate, ce_array[i]);
                        save_or_free_index_entry(istate, ce_array[i]);
                }
@@@ -670,8 -678,7 +676,8 @@@ static struct cache_entry *create_alias
        struct cache_entry *new_entry;
  
        if (alias->ce_flags & CE_ADDED)
 -              die("Will not add file alias '%s' ('%s' already exists in index)", ce->name, alias->name);
 +              die(_("will not add file alias '%s' ('%s' already exists in index)"),
 +                  ce->name, alias->name);
  
        /* Ok, create the new entry using the name of the existing alias */
        len = ce_namelen(alias);
@@@ -686,7 -693,7 +692,7 @@@ void set_object_name_for_intent_to_add_
  {
        struct object_id oid;
        if (write_object_file("", 0, blob_type, &oid))
 -              die("cannot create an empty blob in the object database");
 +              die(_("cannot create an empty blob in the object database"));
        oidcpy(&ce->oid, &oid);
  }
  
@@@ -701,13 -708,13 +707,13 @@@ int add_to_index(struct index_state *is
        int intent_only = flags & ADD_CACHE_INTENT;
        int add_option = (ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|
                          (intent_only ? ADD_CACHE_NEW_ONLY : 0));
 -      int newflags = HASH_WRITE_OBJECT;
 +      int hash_flags = HASH_WRITE_OBJECT;
  
 -      if (flags & HASH_RENORMALIZE)
 -              newflags |= HASH_RENORMALIZE;
 +      if (flags & ADD_CACHE_RENORMALIZE)
 +              hash_flags |= HASH_RENORMALIZE;
  
        if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode))
 -              return error("%s: can only add regular files, symbolic links or git-directories", path);
 +              return error(_("%s: can only add regular files, symbolic links or git-directories"), path);
  
        namelen = strlen(path);
        if (S_ISDIR(st_mode)) {
        if (ignore_case) {
                adjust_dirname_case(istate, ce->name);
        }
 -      if (!(flags & HASH_RENORMALIZE)) {
 +      if (!(flags & ADD_CACHE_RENORMALIZE)) {
                alias = index_file_exists(istate, ce->name,
                                          ce_namelen(ce), ignore_case);
                if (alias &&
                }
        }
        if (!intent_only) {
 -              if (index_path(istate, &ce->oid, path, st, newflags)) {
 +              if (index_path(istate, &ce->oid, path, st, hash_flags)) {
                        discard_cache_entry(ce);
 -                      return error("unable to index file %s", path);
 +                      return error(_("unable to index file '%s'"), path);
                }
        } else
                set_object_name_for_intent_to_add_entry(ce);
                discard_cache_entry(ce);
        else if (add_index_entry(istate, ce, add_option)) {
                discard_cache_entry(ce);
 -              return error("unable to add %s to index", path);
 +              return error(_("unable to add '%s' to index"), path);
        }
        if (verbose && !was_same)
                printf("add '%s'\n", path);
@@@ -792,7 -799,7 +798,7 @@@ int add_file_to_index(struct index_stat
  {
        struct stat st;
        if (lstat(path, &st))
 -              die_errno("unable to stat '%s'", path);
 +              die_errno(_("unable to stat '%s'"), path);
        return add_to_index(istate, path, &st, flags);
  }
  
@@@ -817,7 -824,7 +823,7 @@@ struct cache_entry *make_cache_entry(st
        int len;
  
        if (!verify_path(path, mode)) {
 -              error("Invalid path '%s'", path);
 +              error(_("invalid path '%s'"), path);
                return NULL;
        }
  
@@@ -843,7 -850,7 +849,7 @@@ struct cache_entry *make_transient_cach
        int len;
  
        if (!verify_path(path, mode)) {
 -              error("Invalid path '%s'", path);
 +              error(_("invalid path '%s'"), path);
                return NULL;
        }
  
@@@ -1296,12 -1303,12 +1302,12 @@@ static int add_index_entry_with_check(s
        if (!ok_to_add)
                return -1;
        if (!verify_path(ce->name, ce->ce_mode))
 -              return error("Invalid path '%s'", ce->name);
 +              return error(_("invalid path '%s'"), ce->name);
  
        if (!skip_df_check &&
            check_file_directory_conflict(istate, ce, pos, ok_to_replace)) {
                if (!ok_to_replace)
 -                      return error("'%s' appears as both a file and as a directory",
 +                      return error(_("'%s' appears as both a file and as a directory"),
                                     ce->name);
                pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
                pos = -pos-1;
@@@ -1490,11 -1497,11 +1496,11 @@@ int refresh_index(struct index_state *i
                                                  istate->cache_nr);
  
        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");
 -      added_fmt = (in_porcelain ? "A\t%s\n" : "%s needs update\n");
 -      unmerged_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n");
 +      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";
 +      added_fmt      = in_porcelain ? "A\t%s\n" : "%s: needs update\n";
 +      unmerged_fmt   = in_porcelain ? "U\t%s\n" : "%s: needs merge\n";
        /*
         * Use the multi-threaded preload_index() to refresh most of the
         * cache entries quickly then in the single threaded loop below,
@@@ -1681,10 -1688,10 +1687,10 @@@ static int verify_hdr(const struct cach
        int hdr_version;
  
        if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
 -              return error("bad signature");
 +              return error(_("bad signature 0x%08x"), hdr->hdr_signature);
        hdr_version = ntohl(hdr->hdr_version);
        if (hdr_version < INDEX_FORMAT_LB || INDEX_FORMAT_UB < hdr_version)
 -              return error("bad index version %d", hdr_version);
 +              return error(_("bad index version %d"), hdr_version);
  
        if (!verify_index_checksum)
                return 0;
        the_hash_algo->update_fn(&c, hdr, size - the_hash_algo->rawsz);
        the_hash_algo->final_fn(hash, &c);
        if (!hasheq(hash, (unsigned char *)hdr + size - the_hash_algo->rawsz))
 -              return error("bad index file sha1 signature");
 +              return error(_("bad index file sha1 signature"));
        return 0;
  }
  
@@@ -1723,14 -1730,24 +1729,14 @@@ static int read_index_extension(struct 
                break;
        default:
                if (*ext < 'A' || 'Z' < *ext)
 -                      return error("index uses %.4s extension, which we do not understand",
 +                      return error(_("index uses %.4s extension, which we do not understand"),
                                     ext);
 -              fprintf(stderr, "ignoring %.4s extension\n", ext);
 +              fprintf_ln(stderr, _("ignoring %.4s extension"), ext);
                break;
        }
        return 0;
  }
  
 -int hold_locked_index(struct lock_file *lk, int lock_flags)
 -{
 -      return hold_lock_file_for_update(lk, get_index_file(), lock_flags);
 -}
 -
 -int read_index(struct index_state *istate)
 -{
 -      return read_index_from(istate, get_index_file(), get_git_dir());
 -}
 -
  static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
                                            unsigned int version,
                                            struct ondisk_cache_entry *ondisk,
                extended_flags = get_be16(&ondisk2->flags2) << 16;
                /* We do not yet understand any bit out of CE_EXTENDED_FLAGS */
                if (extended_flags & ~CE_EXTENDED_FLAGS)
 -                      die("Unknown index entry format %08x", extended_flags);
 +                      die(_("unknown index entry format 0x%08x"), extended_flags);
                flags |= extended_flags;
                name = ondisk2->name;
        }
@@@ -1833,13 -1850,13 +1839,13 @@@ static void check_ce_order(struct index
                int name_compare = strcmp(ce->name, next_ce->name);
  
                if (0 < name_compare)
 -                      die("unordered stage entries in index");
 +                      die(_("unordered stage entries in index"));
                if (!name_compare) {
                        if (!ce_stage(ce))
 -                              die("multiple stage entries for merged file '%s'",
 +                              die(_("multiple stage entries for merged file '%s'"),
                                    ce->name);
                        if (ce_stage(ce) > ce_stage(next_ce))
 -                              die("unordered stage entries for '%s'",
 +                              die(_("unordered stage entries for '%s'"),
                                    ce->name);
                }
        }
@@@ -2133,19 -2150,19 +2139,19 @@@ int do_read_index(struct index_state *i
        if (fd < 0) {
                if (!must_exist && errno == ENOENT)
                        return 0;
 -              die_errno("%s: index file open failed", path);
 +              die_errno(_("%s: index file open failed"), path);
        }
  
        if (fstat(fd, &st))
 -              die_errno("cannot stat the open index");
 +              die_errno(_("%s: cannot stat the open index"), path);
  
        mmap_size = xsize_t(st.st_size);
        if (mmap_size < sizeof(struct cache_header) + the_hash_algo->rawsz)
 -              die("index file smaller than expected");
 +              die(_("%s: index file smaller than expected"), path);
  
        mmap = xmmap(NULL, mmap_size, PROT_READ, MAP_PRIVATE, fd, 0);
        if (mmap == MAP_FAILED)
 -              die_errno("unable to map index file");
 +              die_errno(_("%s: unable to map index file"), path);
        close(fd);
  
        hdr = (const struct cache_header *)mmap;
  
  unmap:
        munmap((void *)mmap, mmap_size);
 -      die("index file corrupt");
 +      die(_("index file corrupt"));
  }
  
  /*
  static void freshen_shared_index(const char *shared_index, int warn)
  {
        if (!check_and_freshen_file(shared_index, 1) && warn)
 -              warning("could not freshen shared index '%s'", shared_index);
 +              warning(_("could not freshen shared index '%s'"), shared_index);
  }
  
  int read_index_from(struct index_state *istate, const char *path,
        base_path = xstrfmt("%s/sharedindex.%s", gitdir, base_oid_hex);
        ret = do_read_index(split_index->base, base_path, 1);
        if (!oideq(&split_index->base_oid, &split_index->base->oid))
 -              die("broken index, expect %s in %s, got %s",
 +              die(_("broken index, expect %s in %s, got %s"),
                    base_oid_hex, base_path,
                    oid_to_hex(&split_index->base->oid));
  
@@@ -2337,14 -2354,14 +2343,14 @@@ void validate_cache_entries(const struc
  
        for (i = 0; i < istate->cache_nr; i++) {
                if (!istate) {
 -                      die("internal error: cache entry is not allocated from expected memory pool");
 +                      BUG("cache entry is not allocated from expected memory pool");
                } else if (!istate->ce_mem_pool ||
                        !mem_pool_contains(istate->ce_mem_pool, istate->cache[i])) {
                        if (!istate->split_index ||
                                !istate->split_index->base ||
                                !istate->split_index->base->ce_mem_pool ||
                                !mem_pool_contains(istate->split_index->base->ce_mem_pool, istate->cache[i])) {
 -                              die("internal error: cache entry is not allocated from expected memory pool");
 +                              BUG("cache entry is not allocated from expected memory pool");
                        }
                }
        }
@@@ -2363,20 -2380,22 +2369,20 @@@ int unmerged_index(const struct index_s
        return 0;
  }
  
 -int index_has_changes(struct index_state *istate,
 -                    struct tree *tree,
 -                    struct strbuf *sb)
 +int repo_index_has_changes(struct repository *repo,
 +                         struct tree *tree,
 +                         struct strbuf *sb)
  {
 +      struct index_state *istate = repo->index;
        struct object_id cmp;
        int i;
  
 -      if (istate != &the_index) {
 -              BUG("index_has_changes cannot yet accept istate != &the_index; do_diff_cache needs updating first.");
 -      }
        if (tree)
                cmp = tree->object.oid;
        if (tree || !get_oid_tree("HEAD", &cmp)) {
                struct diff_options opt;
  
 -              repo_diff_setup(the_repository, &opt);
 +              repo_diff_setup(repo, &opt);
                opt.flags.exit_with_status = 1;
                if (!sb)
                        opt.flags.quick = 1;
@@@ -2650,9 -2669,9 +2656,9 @@@ out
        return 0;
  }
  
 -static int verify_index(const struct index_state *istate)
 +static int repo_verify_index(struct repository *repo)
  {
 -      return verify_index_from(istate, get_index_file());
 +      return verify_index_from(repo->index, repo->index_file);
  }
  
  static int has_racy_timestamp(struct index_state *istate)
        return 0;
  }
  
 -void update_index_if_able(struct index_state *istate, struct lock_file *lockfile)
 +void repo_update_index_if_able(struct repository *repo,
 +                             struct lock_file *lockfile)
  {
 -      if ((istate->cache_changed || has_racy_timestamp(istate)) &&
 -          verify_index(istate))
 -              write_locked_index(istate, lockfile, COMMIT_LOCK);
 +      if ((repo->index->cache_changed ||
 +           has_racy_timestamp(repo->index)) &&
 +          repo_verify_index(repo))
 +              write_locked_index(repo->index, lockfile, COMMIT_LOCK);
        else
                rollback_lock_file(lockfile);
  }
@@@ -3085,7 -3102,7 +3091,7 @@@ static int write_shared_index(struct in
                return ret;
        ret = adjust_shared_perm(get_tempfile_path(*temp));
        if (ret) {
 -              error("cannot fix permission bits on %s", get_tempfile_path(*temp));
 +              error(_("cannot fix permission bits on '%s'"), get_tempfile_path(*temp));
                return ret;
        }
        ret = rename_tempfile(temp,
@@@ -3135,7 -3152,7 +3141,7 @@@ int write_locked_index(struct index_sta
        struct split_index *si = istate->split_index;
  
        if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
 -              cache_tree_verify(istate);
 +              cache_tree_verify(the_repository, istate);
  
        if ((flags & SKIP_IF_UNCHANGED) && !istate->cache_changed) {
                if (flags & COMMIT_LOCK)
   * state can call this and check its return value, instead of calling
   * read_cache().
   */
 -int read_index_unmerged(struct index_state *istate)
 +int repo_read_index_unmerged(struct repository *repo)
  {
 +      struct index_state *istate;
        int i;
        int unmerged = 0;
  
 -      read_index(istate);
 +      repo_read_index(repo);
 +      istate = repo->index;
        for (i = 0; i < istate->cache_nr; i++) {
                struct cache_entry *ce = istate->cache[i];
                struct cache_entry *new_ce;
                new_ce->ce_namelen = len;
                new_ce->ce_mode = ce->ce_mode;
                if (add_index_entry(istate, new_ce, ADD_CACHE_SKIP_DFCHECK))
 -                      return error("%s: cannot drop to stage #0",
 +                      return error(_("%s: cannot drop to stage #0"),
                                     new_ce->name);
        }
        return unmerged;
@@@ -3485,71 -3500,71 +3491,71 @@@ static void write_eoie_extension(struc
  
  static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset)
  {
 -       const char *index = NULL;
 -       uint32_t extsize, ext_version;
 -       struct index_entry_offset_table *ieot;
 -       int i, nr;
 -
 -       /* find the IEOT extension */
 -       if (!offset)
 -             return NULL;
 -       while (offset <= mmap_size - the_hash_algo->rawsz - 8) {
 -             extsize = get_be32(mmap + offset + 4);
 -             if (CACHE_EXT((mmap + offset)) == CACHE_EXT_INDEXENTRYOFFSETTABLE) {
 -                     index = mmap + offset + 4 + 4;
 -                     break;
 -             }
 -             offset += 8;
 -             offset += extsize;
 -       }
 -       if (!index)
 -             return NULL;
 -
 -       /* validate the version is IEOT_VERSION */
 -       ext_version = get_be32(index);
 -       if (ext_version != IEOT_VERSION) {
 -             error("invalid IEOT version %d", ext_version);
 -             return NULL;
 -       }
 -       index += sizeof(uint32_t);
 -
 -       /* extension size - version bytes / bytes per entry */
 -       nr = (extsize - sizeof(uint32_t)) / (sizeof(uint32_t) + sizeof(uint32_t));
 -       if (!nr) {
 -             error("invalid number of IEOT entries %d", nr);
 -             return NULL;
 -       }
 -       ieot = xmalloc(sizeof(struct index_entry_offset_table)
 -             + (nr * sizeof(struct index_entry_offset)));
 -       ieot->nr = nr;
 -       for (i = 0; i < nr; i++) {
 -             ieot->entries[i].offset = get_be32(index);
 -             index += sizeof(uint32_t);
 -             ieot->entries[i].nr = get_be32(index);
 -             index += sizeof(uint32_t);
 -       }
 -
 -       return ieot;
 +      const char *index = NULL;
 +      uint32_t extsize, ext_version;
 +      struct index_entry_offset_table *ieot;
 +      int i, nr;
 +
 +      /* find the IEOT extension */
 +      if (!offset)
 +              return NULL;
 +      while (offset <= mmap_size - the_hash_algo->rawsz - 8) {
 +              extsize = get_be32(mmap + offset + 4);
 +              if (CACHE_EXT((mmap + offset)) == CACHE_EXT_INDEXENTRYOFFSETTABLE) {
 +                      index = mmap + offset + 4 + 4;
 +                      break;
 +              }
 +              offset += 8;
 +              offset += extsize;
 +      }
 +      if (!index)
 +              return NULL;
 +
 +      /* validate the version is IEOT_VERSION */
 +      ext_version = get_be32(index);
 +      if (ext_version != IEOT_VERSION) {
 +              error("invalid IEOT version %d", ext_version);
 +              return NULL;
 +      }
 +      index += sizeof(uint32_t);
 +
 +      /* extension size - version bytes / bytes per entry */
 +      nr = (extsize - sizeof(uint32_t)) / (sizeof(uint32_t) + sizeof(uint32_t));
 +      if (!nr) {
 +              error("invalid number of IEOT entries %d", nr);
 +              return NULL;
 +      }
 +      ieot = xmalloc(sizeof(struct index_entry_offset_table)
 +                     + (nr * sizeof(struct index_entry_offset)));
 +      ieot->nr = nr;
 +      for (i = 0; i < nr; i++) {
 +              ieot->entries[i].offset = get_be32(index);
 +              index += sizeof(uint32_t);
 +              ieot->entries[i].nr = get_be32(index);
 +              index += sizeof(uint32_t);
 +      }
 +
 +      return ieot;
  }
  
  static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_table *ieot)
  {
 -       uint32_t buffer;
 -       int i;
 +      uint32_t buffer;
 +      int i;
  
 -       /* version */
 -       put_be32(&buffer, IEOT_VERSION);
 -       strbuf_add(sb, &buffer, sizeof(uint32_t));
 +      /* version */
 +      put_be32(&buffer, IEOT_VERSION);
 +      strbuf_add(sb, &buffer, sizeof(uint32_t));
  
 -       /* ieot */
 -       for (i = 0; i < ieot->nr; i++) {
 +      /* ieot */
 +      for (i = 0; i < ieot->nr; i++) {
  
 -             /* offset */
 -             put_be32(&buffer, ieot->entries[i].offset);
 -             strbuf_add(sb, &buffer, sizeof(uint32_t));
 +              /* offset */
 +              put_be32(&buffer, ieot->entries[i].offset);
 +              strbuf_add(sb, &buffer, sizeof(uint32_t));
  
 -             /* count */
 -             put_be32(&buffer, ieot->entries[i].nr);
 -             strbuf_add(sb, &buffer, sizeof(uint32_t));
 -       }
 +              /* count */
 +              put_be32(&buffer, ieot->entries[i].nr);
 +              strbuf_add(sb, &buffer, sizeof(uint32_t));
 +      }
  }
diff --combined t/t2403-worktree-move.sh
index 0000000000000000000000000000000000000000,33c033773367a135d4cb7eb23f9e9d3131197174..939d18d7286c1be1e58a698e9164fda8e24c654a
mode 000000,100755..100755
--- /dev/null
@@@ -1,0 -1,188 +1,225 @@@
+ #!/bin/sh
+ test_description='test git worktree move, remove, lock and unlock'
+ . ./test-lib.sh
+ test_expect_success 'setup' '
+       test_commit init &&
+       git worktree add source &&
+       git worktree list --porcelain >out &&
+       grep "^worktree" out >actual &&
+       cat <<-EOF >expected &&
+       worktree $(pwd)
+       worktree $(pwd)/source
+       EOF
+       test_cmp expected actual
+ '
+ test_expect_success 'lock main worktree' '
+       test_must_fail git worktree lock .
+ '
+ test_expect_success 'lock linked worktree' '
+       git worktree lock --reason hahaha source &&
+       echo hahaha >expected &&
+       test_cmp expected .git/worktrees/source/locked
+ '
+ test_expect_success 'lock linked worktree from another worktree' '
+       rm .git/worktrees/source/locked &&
+       git worktree add elsewhere &&
+       git -C elsewhere worktree lock --reason hahaha ../source &&
+       echo hahaha >expected &&
+       test_cmp expected .git/worktrees/source/locked
+ '
+ test_expect_success 'lock worktree twice' '
+       test_must_fail git worktree lock source &&
+       echo hahaha >expected &&
+       test_cmp expected .git/worktrees/source/locked
+ '
+ test_expect_success 'lock worktree twice (from the locked worktree)' '
+       test_must_fail git -C source worktree lock . &&
+       echo hahaha >expected &&
+       test_cmp expected .git/worktrees/source/locked
+ '
+ test_expect_success 'unlock main worktree' '
+       test_must_fail git worktree unlock .
+ '
+ test_expect_success 'unlock linked worktree' '
+       git worktree unlock source &&
+       test_path_is_missing .git/worktrees/source/locked
+ '
+ test_expect_success 'unlock worktree twice' '
+       test_must_fail git worktree unlock source &&
+       test_path_is_missing .git/worktrees/source/locked
+ '
+ test_expect_success 'move non-worktree' '
+       mkdir abc &&
+       test_must_fail git worktree move abc def
+ '
+ test_expect_success 'move locked worktree' '
+       git worktree lock source &&
+       test_when_finished "git worktree unlock source" &&
+       test_must_fail git worktree move source destination
+ '
+ test_expect_success 'move worktree' '
+       git worktree move source destination &&
+       test_path_is_missing source &&
+       git worktree list --porcelain >out &&
+       grep "^worktree.*/destination$" out &&
+       ! grep "^worktree.*/source$" out &&
+       git -C destination log --format=%s >actual2 &&
+       echo init >expected2 &&
+       test_cmp expected2 actual2
+ '
+ test_expect_success 'move main worktree' '
+       test_must_fail git worktree move . def
+ '
+ test_expect_success 'move worktree to another dir' '
+       mkdir some-dir &&
+       git worktree move destination some-dir &&
+       test_when_finished "git worktree move some-dir/destination destination" &&
+       test_path_is_missing destination &&
+       git worktree list --porcelain >out &&
+       grep "^worktree.*/some-dir/destination$" out &&
+       git -C some-dir/destination log --format=%s >actual2 &&
+       echo init >expected2 &&
+       test_cmp expected2 actual2
+ '
+ test_expect_success 'move locked worktree (force)' '
+       test_when_finished "
+               git worktree unlock flump || :
+               git worktree remove flump || :
+               git worktree unlock ploof || :
+               git worktree remove ploof || :
+               " &&
+       git worktree add --detach flump &&
+       git worktree lock flump &&
+       test_must_fail git worktree move flump ploof" &&
+       test_must_fail git worktree move --force flump ploof" &&
+       git worktree move --force --force flump ploof
+ '
++test_expect_success 'move a repo with uninitialized submodule' '
++      git init withsub &&
++      (
++              cd withsub &&
++              test_commit initial &&
++              git submodule add "$PWD"/.git sub &&
++              git commit -m withsub &&
++              git worktree add second HEAD &&
++              git worktree move second third
++      )
++'
++
++test_expect_success 'not move a repo with initialized submodule' '
++      (
++              cd withsub &&
++              git -C third submodule update &&
++              test_must_fail git worktree move third forth
++      )
++'
++
+ test_expect_success 'remove main worktree' '
+       test_must_fail git worktree remove .
+ '
+ test_expect_success 'remove locked worktree' '
+       git worktree lock destination &&
+       test_when_finished "git worktree unlock destination" &&
+       test_must_fail git worktree remove destination
+ '
+ test_expect_success 'remove worktree with dirty tracked file' '
+       echo dirty >>destination/init.t &&
+       test_when_finished "git -C destination checkout init.t" &&
+       test_must_fail git worktree remove destination
+ '
+ test_expect_success 'remove worktree with untracked file' '
+       : >destination/untracked &&
+       test_must_fail git worktree remove destination
+ '
+ test_expect_success 'force remove worktree with untracked file' '
+       git worktree remove --force destination &&
+       test_path_is_missing destination
+ '
+ test_expect_success 'remove missing worktree' '
+       git worktree add to-be-gone &&
+       test -d .git/worktrees/to-be-gone &&
+       mv to-be-gone gone &&
+       git worktree remove to-be-gone &&
+       test_path_is_missing .git/worktrees/to-be-gone
+ '
+ test_expect_success 'NOT remove missing-but-locked worktree' '
+       git worktree add gone-but-locked &&
+       git worktree lock gone-but-locked &&
+       test -d .git/worktrees/gone-but-locked &&
+       mv gone-but-locked really-gone-now &&
+       test_must_fail git worktree remove gone-but-locked &&
+       test_path_is_dir .git/worktrees/gone-but-locked
+ '
+ test_expect_success 'proper error when worktree not found' '
+       for i in noodle noodle/bork
+       do
+               test_must_fail git worktree lock $i 2>err &&
+               test_i18ngrep "not a working tree" err || return 1
+       done
+ '
+ test_expect_success 'remove locked worktree (force)' '
+       git worktree add --detach gumby &&
+       test_when_finished "git worktree remove gumby || :" &&
+       git worktree lock gumby &&
+       test_when_finished "git worktree unlock gumby || :" &&
+       test_must_fail git worktree remove gumby &&
+       test_must_fail git worktree remove --force gumby &&
+       git worktree remove --force --force gumby
+ '
+ test_expect_success 'remove cleans up .git/worktrees when empty' '
+       git init moog &&
+       (
+               cd moog &&
+               test_commit bim &&
+               git worktree add --detach goom &&
+               test_path_exists .git/worktrees &&
+               git worktree remove goom &&
+               test_path_is_missing .git/worktrees
+       )
+ '
++test_expect_success 'remove a repo with uninitialized submodule' '
++      (
++              cd withsub &&
++              git worktree add to-remove HEAD &&
++              git worktree remove to-remove
++      )
++'
++
++test_expect_success 'not remove a repo with initialized submodule' '
++      (
++              cd withsub &&
++              git worktree add to-remove HEAD &&
++              git -C to-remove submodule update &&
++              test_must_fail git worktree remove to-remove
++      )
++'
++
+ test_done
diff --combined t/t9902-completion.sh
index 3a2c6326d83b760194c600e2ccde619438200508,5758fffa0dd19cf1a8095060d3dacb5b80b34216..f5e21bf970f4dc44c7fa30d54134a15cf343ffc1
@@@ -1434,9 -1434,9 +1434,10 @@@ test_expect_success 'double dash "git c
        --ignore-other-worktrees Z
        --recurse-submodules Z
        --progress Z
 -      --no-quiet Z
 +      --guess Z
 +      --no-guess Z
        --no-... Z
+       --overlay Z
        EOF
  '
  
@@@ -1516,8 -1516,8 +1517,8 @@@ test_expect_success 'show completes al
  
  test_expect_success '<ref>: completes paths' '
        test_completion "git show mytag:f" <<-\EOF
 -      file1 Z
 -      file2 Z
 +      file1Z
 +      file2Z
        EOF
  '
  
@@@ -1526,7 -1526,7 +1527,7 @@@ test_expect_success 'complete tree file
        git add "name with spaces" &&
        git commit -m spaces &&
        test_completion "git show HEAD:nam" <<-\EOF
 -      name with spaces Z
 +      name with spacesZ
        EOF
  '
  
@@@ -1535,12 -1535,12 +1536,12 @@@ test_expect_success 'complete tree file
        git add "name with \${meta}" &&
        git commit -m meta &&
        test_completion "git show HEAD:nam" <<-\EOF
 -      name with ${meta} Z
 -      name with spaces Z
 +      name with ${meta}Z
 +      name with spacesZ
        EOF
  '
  
 -test_expect_success 'send-email' '
 +test_expect_success PERL 'send-email' '
        test_completion "git send-email --cov" "--cover-letter " &&
        test_completion "git send-email ma" "master "
  '
diff --combined unpack-trees.c
index 3563daae1aa6bceb4f7a4715ee574e1359622239,8e6afa924d184c526be753c9a6344b4d53a48d57..22c41a3ba80971e5edc6bbf02eb6ea59d3c41277
@@@ -1,3 -1,4 +1,3 @@@
 -#define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
  #include "argv-array.h"
  #include "repository.h"
@@@ -293,31 -294,12 +293,12 @@@ static void load_gitmodules_file(struc
                        repo_read_gitmodules(the_repository);
                } else if (state && (ce->ce_flags & CE_UPDATE)) {
                        submodule_free(the_repository);
 -                      checkout_entry(ce, state, NULL);
 +                      checkout_entry(ce, state, NULL, NULL);
                        repo_read_gitmodules(the_repository);
                }
        }
  }
  
- /*
-  * Unlink the last component and schedule the leading directories for
-  * removal, such that empty directories get removed.
-  */
- static void unlink_entry(const struct cache_entry *ce)
- {
-       const struct submodule *sub = submodule_from_ce(ce);
-       if (sub) {
-               /* state.force is set at the caller. */
-               submodule_move_head(ce->name, "HEAD", NULL,
-                                   SUBMODULE_MOVE_HEAD_FORCE);
-       }
-       if (!check_leading_path(ce->name, ce_namelen(ce)))
-               return;
-       if (remove_or_warn(ce->ce_mode, ce->name))
-               return;
-       schedule_dir_for_removal(ce->name, ce_namelen(ce));
- }
  static struct progress *get_progress(struct unpack_trees_options *o)
  {
        unsigned cnt = 0, total = 0;
@@@ -410,7 -392,7 +391,7 @@@ static int check_updates(struct unpack_
                                unlink_entry(ce);
                }
        }
-       remove_marked_cache_entries(index);
+       remove_marked_cache_entries(index, 0);
        remove_scheduled_dirs();
  
        if (should_update_submodules() && o->update && !o->dry_run)
                        display_progress(progress, ++cnt);
                        ce->ce_flags &= ~CE_UPDATE;
                        if (o->update && !o->dry_run) {
 -                              errs |= checkout_entry(ce, &state, NULL);
 +                              errs |= checkout_entry(ce, &state, NULL, NULL);
                        }
                }
        }
        stop_progress(&progress);
 -      errs |= finish_delayed_checkout(&state);
 +      errs |= finish_delayed_checkout(&state, NULL);
        if (o->update)
                git_attr_set_direction(GIT_ATTR_CHECKIN);
  
@@@ -678,7 -660,7 +659,7 @@@ static int switch_cache_bottom(struct t
  
  static inline int are_same_oid(struct name_entry *name_j, struct name_entry *name_k)
  {
 -      return name_j->oid && name_k->oid && oideq(name_j->oid, name_k->oid);
 +      return !is_null_oid(&name_j->oid) && !is_null_oid(&name_k->oid) && oideq(&name_j->oid, &name_k->oid);
  }
  
  static int all_trees_same_as_cache_tree(int n, unsigned long dirmask,
@@@ -793,7 -775,6 +774,7 @@@ static int traverse_trees_recursive(in
                                    struct name_entry *names,
                                    struct traverse_info *info)
  {
 +      struct unpack_trees_options *o = info->data;
        int i, ret, bottom;
        int nr_buf = 0;
        struct tree_desc t[MAX_UNPACK_TREES];
  
        nr_entries = all_trees_same_as_cache_tree(n, dirmask, names, info);
        if (nr_entries > 0) {
 -              struct unpack_trees_options *o = info->data;
                int pos = index_pos_by_traverse_info(names, info);
  
                if (!o->merge || df_conflicts)
                else {
                        const struct object_id *oid = NULL;
                        if (dirmask & 1)
 -                              oid = names[i].oid;
 +                              oid = &names[i].oid;
                        buf[nr_buf++] = fill_tree_descriptor(t + i, oid);
                }
        }
  
        bottom = switch_cache_bottom(&newinfo);
 -      ret = traverse_trees(n, t, &newinfo);
 +      ret = traverse_trees(o->src_index, n, t, &newinfo);
        restore_cache_bottom(&newinfo, bottom);
  
        for (i = 0; i < nr_buf; i++)
@@@ -980,7 -962,7 +961,7 @@@ static struct cache_entry *create_ce_en
        ce->ce_mode = create_ce_mode(n->mode);
        ce->ce_flags = create_ce_flags(stage);
        ce->ce_namelen = len;
 -      oidcpy(&ce->oid, n->oid);
 +      oidcpy(&ce->oid, &n->oid);
        make_traverse_path(ce->name, info, n);
  
        return ce;
@@@ -1549,7 -1531,7 +1530,7 @@@ int unpack_trees(unsigned len, struct t
                }
  
                trace_performance_enter();
 -              ret = traverse_trees(len, t, &info);
 +              ret = traverse_trees(o->src_index, len, t, &info);
                trace_performance_leave("traverse_trees");
                if (ret < 0)
                        goto return_failed;
                move_index_extensions(&o->result, o->src_index);
                if (!ret) {
                        if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
 -                              cache_tree_verify(&o->result);
 +                              cache_tree_verify(the_repository, &o->result);
                        if (!o->result.cache_tree)
                                o->result.cache_tree = cache_tree();
                        if (!cache_tree_fully_valid(o->result.cache_tree))