Merge branch 'nd/fix-sparse-checkout'
authorJunio C Hamano <gitster@pobox.com>
Sun, 22 Aug 2010 06:28:05 +0000 (23:28 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 22 Aug 2010 06:28:05 +0000 (23:28 -0700)
* nd/fix-sparse-checkout:
unpack-trees: mark new entries skip-worktree appropriately
unpack-trees: do not check for conflict entries too early
unpack-trees: let read-tree -u remove index entries outside sparse area
unpack-trees: only clear CE_UPDATE|CE_REMOVE when skip-worktree is always set
t1011 (sparse checkout): style nitpicks

1  2 
cache.h
unpack-trees.c
diff --combined cache.h
index 94dde5312f368523447d6bd6fb61f5f0b51af25a,ec6b75a26ab2d47147ddaaf6b71bc687cbfbe2e9..61a563150f1a6e59d8246e0f613cf5bd8d39a8d4
+++ b/cache.h
@@@ -179,8 -179,7 +179,7 @@@ struct cache_entry 
  #define CE_UNHASHED  (0x200000)
  #define CE_CONFLICTED (0x800000)
  
- /* Only remove in work directory, not index */
- #define CE_WT_REMOVE (0x400000)
+ #define CE_WT_REMOVE (0x400000) /* remove in work directory */
  
  #define CE_UNPACKED  (0x1000000)
  
@@@ -361,7 -360,7 +360,7 @@@ enum object_type 
        OBJ_OFS_DELTA = 6,
        OBJ_REF_DELTA = 7,
        OBJ_ANY,
 -      OBJ_MAX,
 +      OBJ_MAX
  };
  
  static inline enum object_type object_type(unsigned int mode)
  #define ATTRIBUTE_MACRO_PREFIX "[attr]"
  #define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
  #define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
 +#define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF"
 +#define GIT_NOTES_REWRITE_REF_ENVIRONMENT "GIT_NOTES_REWRITE_REF"
 +#define GIT_NOTES_REWRITE_MODE_ENVIRONMENT "GIT_NOTES_REWRITE_MODE"
 +
 +/*
 + * Repository-local GIT_* environment variables
 + * The array is NULL-terminated to simplify its usage in contexts such
 + * environment creation or simple walk of the list.
 + * The number of non-NULL entries is available as a macro.
 + */
 +#define LOCAL_REPO_ENV_SIZE 8
 +extern const char *const local_repo_env[LOCAL_REPO_ENV_SIZE + 1];
  
  extern int is_bare_repository_cfg;
  extern int is_bare_repository(void);
@@@ -449,7 -436,7 +448,7 @@@ extern int init_db(const char *template
                                alloc = alloc_nr(alloc); \
                        x = xrealloc((x), alloc * sizeof(*(x))); \
                } \
 -      } while(0)
 +      } while (0)
  
  /* Initialize and use the cache information */
  extern int read_index(struct index_state *);
@@@ -547,6 -534,7 +546,6 @@@ extern int core_compression_seen
  extern size_t packed_git_window_size;
  extern size_t packed_git_limit;
  extern size_t delta_base_cache_limit;
 -extern int auto_crlf;
  extern int read_replace_refs;
  extern int fsync_object_files;
  extern int core_preload_index;
@@@ -555,53 -543,32 +554,53 @@@ extern int core_apply_sparse_checkout
  enum safe_crlf {
        SAFE_CRLF_FALSE = 0,
        SAFE_CRLF_FAIL = 1,
 -      SAFE_CRLF_WARN = 2,
 +      SAFE_CRLF_WARN = 2
  };
  
  extern enum safe_crlf safe_crlf;
  
 +enum auto_crlf {
 +      AUTO_CRLF_FALSE = 0,
 +      AUTO_CRLF_TRUE = 1,
 +      AUTO_CRLF_INPUT = -1,
 +};
 +
 +extern enum auto_crlf auto_crlf;
 +
 +enum eol {
 +      EOL_UNSET,
 +      EOL_CRLF,
 +      EOL_LF,
 +#ifdef NATIVE_CRLF
 +      EOL_NATIVE = EOL_CRLF
 +#else
 +      EOL_NATIVE = EOL_LF
 +#endif
 +};
 +
 +extern enum eol eol;
 +
  enum branch_track {
        BRANCH_TRACK_UNSPECIFIED = -1,
        BRANCH_TRACK_NEVER = 0,
        BRANCH_TRACK_REMOTE,
        BRANCH_TRACK_ALWAYS,
        BRANCH_TRACK_EXPLICIT,
 -      BRANCH_TRACK_OVERRIDE,
 +      BRANCH_TRACK_OVERRIDE
  };
  
  enum rebase_setup_type {
        AUTOREBASE_NEVER = 0,
        AUTOREBASE_LOCAL,
        AUTOREBASE_REMOTE,
 -      AUTOREBASE_ALWAYS,
 +      AUTOREBASE_ALWAYS
  };
  
  enum push_default_type {
        PUSH_DEFAULT_NOTHING = 0,
        PUSH_DEFAULT_MATCHING,
        PUSH_DEFAULT_TRACKING,
 -      PUSH_DEFAULT_CURRENT,
 +      PUSH_DEFAULT_CURRENT
  };
  
  extern enum branch_track git_branch_track;
@@@ -610,7 -577,7 +609,7 @@@ extern enum push_default_type push_defa
  
  enum object_creation_mode {
        OBJECT_CREATION_USES_HARDLINKS = 0,
 -      OBJECT_CREATION_USES_RENAMES = 1,
 +      OBJECT_CREATION_USES_RENAMES = 1
  };
  
  extern enum object_creation_mode object_creation_mode;
@@@ -641,9 -608,6 +640,9 @@@ extern char *git_pathdup(const char *fm
  /* Return a statically allocated filename matching the sha1 signature */
  extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
  extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 +extern char *git_path_submodule(const char *path, const char *fmt, ...)
 +      __attribute__((format (printf, 2, 3)));
 +
  extern char *sha1_file_name(const unsigned char *sha1);
  extern char *sha1_pack_name(const unsigned char *sha1);
  extern char *sha1_pack_index_name(const unsigned char *sha1);
@@@ -676,10 -640,6 +675,10 @@@ int git_mkstemp(char *path, size_t n, c
  
  int git_mkstemps(char *path, size_t n, const char *template, int suffix_len);
  
 +/* set default permissions by passing mode arguments to open(2) */
 +int git_mkstemps_mode(char *pattern, int suffix_len, int mode);
 +int git_mkstemp_mode(char *pattern, int mode);
 +
  /*
   * NOTE NOTE NOTE!!
   *
@@@ -693,7 -653,7 +692,7 @@@ enum sharedrepo 
        OLD_PERM_GROUP      = 1,
        OLD_PERM_EVERYBODY  = 2,
        PERM_GROUP          = 0660,
 -      PERM_EVERYBODY      = 0664,
 +      PERM_EVERYBODY      = 0664
  };
  int git_config_perm(const char *var, const char *value);
  int set_shared_perm(const char *path, int mode);
@@@ -714,7 -674,6 +713,7 @@@ int normalize_path_copy(char *dst, cons
  int longest_ancestor_length(const char *path, const char *prefix_list);
  char *strip_path_suffix(const char *path, const char *suffix);
  int daemon_avoid_alias(const char *path);
 +int offset_1st_component(const char *path);
  
  /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
  extern int sha1_object_info(const unsigned char *, unsigned long *);
@@@ -724,7 -683,7 +723,7 @@@ static inline void *read_sha1_file(cons
        return read_sha1_file_repl(sha1, type, size, NULL);
  }
  extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
 -extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 +extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
  extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
  extern int force_object_loose(const unsigned char *sha1, time_t mtime);
  
@@@ -741,8 -700,6 +740,8 @@@ extern int has_loose_object_nonlocal(co
  
  extern int has_pack_index(const unsigned char *sha1);
  
 +extern void assert_sha1_type(const unsigned char *sha1, enum object_type expect);
 +
  extern const signed char hexval_table[256];
  static inline unsigned int hexval(unsigned char c)
  {
  #define MINIMUM_ABBREV 4
  #define DEFAULT_ABBREV 7
  
 +struct object_context {
 +      unsigned char tree[20];
 +      char path[PATH_MAX];
 +      unsigned mode;
 +};
 +
  extern int get_sha1(const char *str, unsigned char *sha1);
  extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int gently, const char *prefix);
  static inline int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)
  {
        return get_sha1_with_mode_1(str, sha1, mode, 1, NULL);
  }
 +extern int get_sha1_with_context_1(const char *name, unsigned char *sha1, struct object_context *orc, int gently, const char *prefix);
 +static inline int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc)
 +{
 +      return get_sha1_with_context_1(str, sha1, orc, 1, NULL);
 +}
  extern int get_sha1_hex(const char *hex, unsigned char *sha1);
  extern char *sha1_to_hex(const unsigned char *sha1);  /* static buffer result! */
  extern int read_ref(const char *filename, unsigned char *sha1);
@@@ -814,7 -760,6 +813,7 @@@ const char *show_date_relative(unsigne
                               char *timebuf,
                               size_t timebuf_size);
  int parse_date(const char *date, char *buf, int bufsize);
 +int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);
  void datestamp(char *buf, int bufsize);
  #define approxidate(s) approxidate_careful((s), NULL)
  unsigned long approxidate_careful(const char *, int *);
@@@ -829,7 -774,7 +828,7 @@@ extern const char *git_committer_info(i
  extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
  extern const char *fmt_name(const char *name, const char *email);
  extern const char *git_editor(void);
 -extern const char *git_pager(void);
 +extern const char *git_pager(int stdout_is_tty);
  
  struct checkout {
        const char *base_dir;
@@@ -917,7 -862,7 +916,7 @@@ struct ref 
                REF_STATUS_REJECT_NODELETE,
                REF_STATUS_UPTODATE,
                REF_STATUS_REMOTE_REJECT,
 -              REF_STATUS_EXPECTING_REPORT,
 +              REF_STATUS_EXPECTING_REPORT
        } status;
        char *remote_status;
        struct ref *peer_ref; /* when renaming */
  extern struct ref *find_ref_by_name(const struct ref *list, const char *name);
  
  #define CONNECT_VERBOSE       (1u << 0)
 +extern char *git_getpass(const char *prompt);
  extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
  extern int finish_connect(struct child_process *conn);
  extern int path_match(const char *path, int nr, char **match);
@@@ -942,7 -886,7 +941,7 @@@ struct extra_have_objects 
  extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags, struct extra_have_objects *);
  extern int server_supports(const char *feature);
  
 -extern struct packed_git *parse_pack_index(unsigned char *sha1);
 +extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
  
  extern void prepare_packed_git(void);
  extern void reprepare_packed_git(void);
@@@ -953,7 -897,6 +952,7 @@@ extern struct packed_git *find_sha1_pac
  
  extern void pack_report(void);
  extern int open_pack_index(struct packed_git *);
 +extern void close_pack_index(struct packed_git *);
  extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *);
  extern void close_pack_windows(struct packed_git *);
  extern void unuse_pack(struct pack_window **);
@@@ -974,15 -917,12 +973,15 @@@ extern int update_server_info(int)
  typedef int (*config_fn_t)(const char *, const char *, void *);
  extern int git_default_config(const char *, const char *, void *);
  extern int git_config_from_file(config_fn_t fn, const char *, void *);
 +extern int git_config_parse_parameter(const char *text);
 +extern int git_config_from_parameters(config_fn_t fn, void *data);
  extern int git_config(config_fn_t fn, void *);
  extern int git_parse_ulong(const char *, unsigned long *);
  extern int git_config_int(const char *, const char *);
  extern unsigned long git_config_ulong(const char *, const char *);
  extern int git_config_bool_or_int(const char *, const char *, int *);
  extern int git_config_bool(const char *, const char *);
 +extern int git_config_maybe_bool(const char *, const char *);
  extern int git_config_string(const char **, const char *, const char *);
  extern int git_config_pathname(const char **, const char *, const char *);
  extern int git_config_set(const char *, const char *);
@@@ -990,7 -930,6 +989,7 @@@ extern int git_config_set_multivar(cons
  extern int git_config_rename_section(const char *, const char *);
  extern const char *git_etc_gitconfig(void);
  extern int check_repository_format_version(const char *var, const char *value, void *cb);
 +extern int git_env_bool(const char *, int);
  extern int git_config_system(void);
  extern int git_config_global(void);
  extern int config_error_nonbool(const char *);
@@@ -1082,7 -1021,6 +1081,7 @@@ void shift_tree_by(const unsigned char 
  #define WS_INDENT_WITH_NON_TAB        04
  #define WS_CR_AT_EOL           010
  #define WS_BLANK_AT_EOF        020
 +#define WS_TAB_IN_INDENT       040
  #define WS_TRAILING_SPACE      (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
  #define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB)
  extern unsigned whitespace_rule_cfg;
@@@ -1091,7 -1029,7 +1090,7 @@@ extern unsigned parse_whitespace_rule(c
  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);
  extern char *whitespace_error_string(unsigned ws);
 -extern int ws_fix_copy(char *, const char *, int, unsigned, int *);
 +extern void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *);
  extern int ws_blank_line(const char *line, int len, unsigned ws_rule);
  
  /* ls-files */
@@@ -1101,7 -1039,4 +1100,7 @@@ void overlay_tree_on_cache(const char *
  char *alias_lookup(const char *alias);
  int split_cmdline(char *cmdline, const char ***argv);
  
 +/* builtin/merge.c */
 +int checkout_fast_forward(const unsigned char *from, const unsigned char *to);
 +
  #endif /* CACHE_H */
diff --combined unpack-trees.c
index 62852aa7fb3fbd5e2d3ae1173d05deddba763d52,8b162153229db5d5dadbdbcacca3754f77618bdf..3c7a7c9cde745c1b438f60aceea7e556dded81d7
   * Error messages expected by scripts out of plumbing commands such as
   * read-tree.  Non-scripted Porcelain is not required to use these messages
   * and in fact are encouraged to reword them to better suit their particular
 - * situation better.  See how "git checkout" replaces not_uptodate_file to
 - * explain why it does not allow switching between branches when you have
 - * local changes, for example.
 + * situation better.  See how "git checkout" and "git merge" replaces
 + * them using set_porcelain_error_msgs(), for example.
   */
 -static struct unpack_trees_error_msgs unpack_plumbing_errors = {
 -      /* would_overwrite */
 +const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
 +      /* ERROR_WOULD_OVERWRITE */
        "Entry '%s' would be overwritten by merge. Cannot merge.",
  
 -      /* not_uptodate_file */
 +      /* ERROR_NOT_UPTODATE_FILE */
        "Entry '%s' not uptodate. Cannot merge.",
  
 -      /* not_uptodate_dir */
 +      /* ERROR_NOT_UPTODATE_DIR */
        "Updating '%s' would lose untracked files in it",
  
 -      /* would_lose_untracked */
 -      "Untracked working tree file '%s' would be %s by merge.",
 +      /* ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN */
 +      "Untracked working tree file '%s' would be overwritten by merge.",
  
 -      /* bind_overlap */
 +      /* ERROR_WOULD_LOSE_UNTRACKED_REMOVED */
 +      "Untracked working tree file '%s' would be removed by merge.",
 +
 +      /* ERROR_BIND_OVERLAP */
        "Entry '%s' overlaps with '%s'.  Cannot bind.",
  
 -      /* sparse_not_uptodate_file */
 +      /* ERROR_SPARSE_NOT_UPTODATE_FILE */
        "Entry '%s' not uptodate. Cannot update sparse checkout.",
  
 -      /* would_lose_orphaned */
 -      "Working tree file '%s' would be %s by sparse checkout update.",
 +      /* ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN */
 +      "Working tree file '%s' would be overwritten by sparse checkout update.",
 +
 +      /* ERROR_WOULD_LOSE_ORPHANED_REMOVED */
 +      "Working tree file '%s' would be removed by sparse checkout update.",
  };
  
 -#define ERRORMSG(o,fld) \
 -      ( ((o) && (o)->msgs.fld) \
 -      ? ((o)->msgs.fld) \
 -      : (unpack_plumbing_errors.fld) )
 +#define ERRORMSG(o,type) \
 +      ( ((o) && (o)->msgs[(type)]) \
 +        ? ((o)->msgs[(type)])      \
 +        : (unpack_plumbing_errors[(type)]) )
  
  static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
        unsigned int set, unsigned int clear)
  
        clear |= CE_HASHED | CE_UNHASHED;
  
+       if (set & CE_REMOVE)
+               set |= CE_WT_REMOVE;
        memcpy(new, ce, size);
        new->next = NULL;
        new->ce_flags = (new->ce_flags & ~clear) | set;
        add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
  }
  
 +/*
 + * add error messages on path <path>
 + * corresponding to the type <e> with the message <msg>
 + * indicating if it should be display in porcelain or not
 + */
 +static int add_rejected_path(struct unpack_trees_options *o,
 +                           enum unpack_trees_error_types e,
 +                           const char *path)
 +{
 +      struct rejected_paths_list *newentry;
 +      int porcelain = o && (o)->msgs[e];
 +      /*
 +       * simply display the given error message if in plumbing mode
 +       */
 +      if (!porcelain)
 +              o->show_all_errors = 0;
 +      if (!o->show_all_errors)
 +              return error(ERRORMSG(o, e), path);
 +
 +      /*
 +       * Otherwise, insert in a list for future display by
 +       * display_error_msgs()
 +       */
 +      newentry = xmalloc(sizeof(struct rejected_paths_list));
 +      newentry->path = (char *)path;
 +      newentry->next = o->unpack_rejects[e];
 +      o->unpack_rejects[e] = newentry;
 +      return -1;
 +}
 +
 +/*
 + * free all the structures allocated for the error <e>
 + */
 +static void free_rejected_paths(struct unpack_trees_options *o,
 +                              enum unpack_trees_error_types e)
 +{
 +      while (o->unpack_rejects[e]) {
 +              struct rejected_paths_list *del = o->unpack_rejects[e];
 +              o->unpack_rejects[e] = o->unpack_rejects[e]->next;
 +              free(del);
 +      }
 +      free(o->unpack_rejects[e]);
 +}
 +
 +/*
 + * display all the error messages stored in a nice way
 + */
 +static void display_error_msgs(struct unpack_trees_options *o)
 +{
 +      int e;
 +      int something_displayed = 0;
 +      for (e = 0; e < NB_UNPACK_TREES_ERROR_TYPES; e++) {
 +              if (o->unpack_rejects[e]) {
 +                      struct rejected_paths_list *rp;
 +                      struct strbuf path = STRBUF_INIT;
 +                      something_displayed = 1;
 +                      for (rp = o->unpack_rejects[e]; rp; rp = rp->next)
 +                              strbuf_addf(&path, "\t%s\n", rp->path);
 +                      error(ERRORMSG(o, e), path.buf);
 +                      strbuf_release(&path);
 +                      free_rejected_paths(o, e);
 +              }
 +      }
 +      if (something_displayed)
 +              printf("Aborting\n");
 +}
 +
  /*
   * Unlink the last component and schedule the leading directories for
   * removal, such that empty directories get removed.
@@@ -139,8 -70,16 +142,8 @@@ static void unlink_entry(struct cache_e
  {
        if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
                return;
 -      if (S_ISGITLINK(ce->ce_mode)) {
 -              if (rmdir(ce->name)) {
 -                      warning("unable to rmdir %s: %s",
 -                              ce->name, strerror(errno));
 -                      return;
 -              }
 -      }
 -      else
 -              if (unlink_or_warn(ce->name))
 -                      return;
 +      if (remove_or_warn(ce->ce_mode, ce->name))
 +              return;
        schedule_dir_for_removal(ce->name, ce_namelen(ce));
  }
  
@@@ -156,7 -95,7 +159,7 @@@ static int check_updates(struct unpack_
        if (o->update && o->verbose_update) {
                for (total = cnt = 0; cnt < index->cache_nr; cnt++) {
                        struct cache_entry *ce = index->cache[cnt];
-                       if (ce->ce_flags & (CE_UPDATE | CE_REMOVE | CE_WT_REMOVE))
+                       if (ce->ce_flags & (CE_UPDATE | CE_WT_REMOVE))
                                total++;
                }
  
                                unlink_entry(ce);
                        continue;
                }
-               if (ce->ce_flags & CE_REMOVE) {
-                       display_progress(progress, ++cnt);
-                       if (o->update)
-                               unlink_entry(ce);
-               }
        }
        remove_marked_cache_entries(&o->result);
        remove_scheduled_dirs();
  }
  
  static int verify_uptodate_sparse(struct cache_entry *ce, struct unpack_trees_options *o);
 -static int verify_absent_sparse(struct cache_entry *ce, const char *action, struct unpack_trees_options *o);
 +static int verify_absent_sparse(struct cache_entry *ce, enum unpack_trees_error_types, struct unpack_trees_options *o);
  
  static int will_have_skip_worktree(const struct cache_entry *ce, struct unpack_trees_options *o)
  {
        const char *basename;
  
-       if (ce_stage(ce))
-               return 0;
        basename = strrchr(ce->name, '/');
        basename = basename ? basename+1 : ce->name;
        return excluded_from_list(ce->name, ce_namelen(ce), basename, NULL, o->el) <= 0;
@@@ -222,19 -152,36 +216,36 @@@ static int apply_sparse_checkout(struc
  {
        int was_skip_worktree = ce_skip_worktree(ce);
  
-       if (will_have_skip_worktree(ce, o))
+       if (!ce_stage(ce) && will_have_skip_worktree(ce, o))
                ce->ce_flags |= CE_SKIP_WORKTREE;
        else
                ce->ce_flags &= ~CE_SKIP_WORKTREE;
  
        /*
-        * We only care about files getting into the checkout area
-        * If merge strategies want to remove some, go ahead, this
-        * flag will be removed eventually in unpack_trees() if it's
-        * outside checkout area.
+        * if (!was_skip_worktree && !ce_skip_worktree()) {
+        *      This is perfectly normal. Move on;
+        * }
         */
-       if (ce->ce_flags & CE_REMOVE)
-               return 0;
+       /*
+        * Merge strategies may set CE_UPDATE|CE_REMOVE outside checkout
+        * area as a result of ce_skip_worktree() shortcuts in
+        * verify_absent() and verify_uptodate().
+        * Make sure they don't modify worktree if they are already
+        * outside checkout area
+        */
+       if (was_skip_worktree && ce_skip_worktree(ce)) {
+               ce->ce_flags &= ~CE_UPDATE;
+               /*
+                * By default, when CE_REMOVE is on, CE_WT_REMOVE is also
+                * on to get that file removed from both index and worktree.
+                * If that file is already outside worktree area, don't
+                * bother remove it.
+                */
+               if (ce->ce_flags & CE_REMOVE)
+                       ce->ce_flags &= ~CE_WT_REMOVE;
+       }
  
        if (!was_skip_worktree && ce_skip_worktree(ce)) {
                /*
                ce->ce_flags |= CE_WT_REMOVE;
        }
        if (was_skip_worktree && !ce_skip_worktree(ce)) {
 -              if (verify_absent_sparse(ce, "overwritten", o))
 +              if (verify_absent_sparse(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
                        return -1;
                ce->ce_flags |= CE_UPDATE;
        }
@@@ -351,11 -298,9 +362,11 @@@ static void add_same_unmerged(struct ca
  static int unpack_index_entry(struct cache_entry *ce,
                              struct unpack_trees_options *o)
  {
 -      struct cache_entry *src[5] = { ce, NULL, };
 +      struct cache_entry *src[5] = { NULL };
        int ret;
  
 +      src[0] = ce;
 +
        mark_ce_used(ce, o);
        if (ce_stage(ce)) {
                if (o->skip_unmerged) {
@@@ -401,7 -346,6 +412,7 @@@ static int traverse_trees_recursive(in
  {
        int i, ret, bottom;
        struct tree_desc t[MAX_UNPACK_TREES];
 +      void *buf[MAX_UNPACK_TREES];
        struct traverse_info newinfo;
        struct name_entry *p;
  
                const unsigned char *sha1 = NULL;
                if (dirmask & 1)
                        sha1 = names[i].sha1;
 -              fill_tree_descriptor(t+i, sha1);
 +              buf[i] = fill_tree_descriptor(t+i, sha1);
        }
  
        bottom = switch_cache_bottom(&newinfo);
        ret = traverse_trees(n, t, &newinfo);
        restore_cache_bottom(&newinfo, bottom);
 +
 +      for (i = 0; i < n; i++)
 +              free(buf[i]);
 +
        return ret;
  }
  
@@@ -599,17 -539,9 +610,17 @@@ static int find_cache_pos(struct traver
                const char *ce_name, *ce_slash;
                int cmp, ce_len;
  
 -              if (!ce_in_traverse_path(ce, info))
 +              if (ce->ce_flags & CE_UNPACKED) {
 +                      /*
 +                       * cache_bottom entry is already unpacked, so
 +                       * we can never match it; don't check it
 +                       * again.
 +                       */
 +                      if (pos == o->cache_bottom)
 +                              ++o->cache_bottom;
                        continue;
 -              if (ce->ce_flags & CE_UNPACKED)
 +              }
 +              if (!ce_in_traverse_path(ce, info))
                        continue;
                ce_name = ce->name + pfxlen;
                ce_slash = strchr(ce_name, '/');
@@@ -827,7 -759,6 +838,7 @@@ int unpack_trees(unsigned len, struct t
                setup_traverse_info(&info, prefix);
                info.fn = unpack_callback;
                info.data = o;
 +              info.show_all_errors = o->show_all_errors;
  
                if (o->prefix) {
                        /*
                                ret = -1;
                                goto done;
                        }
-                       /*
-                        * Merge strategies may set CE_UPDATE|CE_REMOVE outside checkout
-                        * area as a result of ce_skip_worktree() shortcuts in
-                        * verify_absent() and verify_uptodate(). Clear them.
-                        */
-                       if (ce_skip_worktree(ce))
-                               ce->ce_flags &= ~(CE_UPDATE | CE_REMOVE);
-                       else
+                       if (!ce_skip_worktree(ce))
                                empty_worktree = 0;
  
                }
@@@ -907,8 -831,6 +911,8 @@@ done
        return ret;
  
  return_failed:
 +      if (o->show_all_errors)
 +              display_error_msgs(o);
        mark_all_ce_unused(o->src_index);
        ret = unpack_failed(o, NULL);
        goto done;
  
  static int reject_merge(struct cache_entry *ce, struct unpack_trees_options *o)
  {
 -      return error(ERRORMSG(o, would_overwrite), ce->name);
 +      return add_rejected_path(o, ERROR_WOULD_OVERWRITE, ce->name);
  }
  
  static int same(struct cache_entry *a, struct cache_entry *b)
   */
  static int verify_uptodate_1(struct cache_entry *ce,
                                   struct unpack_trees_options *o,
 -                                 const char *error_msg)
 +                                 enum unpack_trees_error_types error_type)
  {
        struct stat st;
  
 -      if (o->index_only || (!ce_skip_worktree(ce) && (o->reset || ce_uptodate(ce))))
 +      if (o->index_only || (!((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) && (o->reset || ce_uptodate(ce))))
                return 0;
  
        if (!lstat(ce->name, &st)) {
        if (errno == ENOENT)
                return 0;
        return o->gently ? -1 :
 -              error(error_msg, ce->name);
 +              add_rejected_path(o, error_type, ce->name);
  }
  
  static int verify_uptodate(struct cache_entry *ce,
  {
        if (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))
                return 0;
 -      return verify_uptodate_1(ce, o, ERRORMSG(o, not_uptodate_file));
 +      return verify_uptodate_1(ce, o, ERROR_NOT_UPTODATE_FILE);
  }
  
  static int verify_uptodate_sparse(struct cache_entry *ce,
                                  struct unpack_trees_options *o)
  {
 -      return verify_uptodate_1(ce, o, ERRORMSG(o, sparse_not_uptodate_file));
 +      return verify_uptodate_1(ce, o, ERROR_SPARSE_NOT_UPTODATE_FILE);
  }
  
  static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o)
   * Currently, git does not checkout subprojects during a superproject
   * checkout, so it is not going to overwrite anything.
   */
 -static int verify_clean_submodule(struct cache_entry *ce, const char *action,
 +static int verify_clean_submodule(struct cache_entry *ce,
 +                                    enum unpack_trees_error_types error_type,
                                      struct unpack_trees_options *o)
  {
        return 0;
  }
  
 -static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
 +static int verify_clean_subdirectory(struct cache_entry *ce,
 +                                    enum unpack_trees_error_types error_type,
                                      struct unpack_trees_options *o)
  {
        /*
                 */
                if (!hashcmp(sha1, ce->sha1))
                        return 0;
 -              return verify_clean_submodule(ce, action, o);
 +              return verify_clean_submodule(ce, error_type, o);
        }
  
        /*
        i = read_directory(&d, pathbuf, namelen+1, NULL);
        if (i)
                return o->gently ? -1 :
 -                      error(ERRORMSG(o, not_uptodate_dir), ce->name);
 +                      add_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name);
        free(pathbuf);
        return cnt;
  }
@@@ -1093,9 -1013,9 +1097,9 @@@ static int icase_exists(struct unpack_t
   * We do not want to remove or overwrite a working tree file that
   * is not tracked, unless it is ignored.
   */
 -static int verify_absent_1(struct cache_entry *ce, const char *action,
 -                               struct unpack_trees_options *o,
 -                               const char *error_msg)
 +static int verify_absent_1(struct cache_entry *ce,
 +                               enum unpack_trees_error_types error_type,
 +                               struct unpack_trees_options *o)
  {
        struct stat st;
  
                         * files that are in "foo/" we would lose
                         * them.
                         */
 -                      if (verify_clean_subdirectory(ce, action, o) < 0)
 +                      if (verify_clean_subdirectory(ce, error_type, o) < 0)
                                return -1;
                        return 0;
                }
                }
  
                return o->gently ? -1 :
 -                      error(ERRORMSG(o, would_lose_untracked), ce->name, action);
 +                      add_rejected_path(o, error_type, ce->name);
        }
        return 0;
  }
 -static int verify_absent(struct cache_entry *ce, const char *action,
 +static int verify_absent(struct cache_entry *ce,
 +                       enum unpack_trees_error_types error_type,
                         struct unpack_trees_options *o)
  {
        if (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))
                return 0;
 -      return verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_untracked));
 +      return verify_absent_1(ce, error_type, o);
  }
  
 -static int verify_absent_sparse(struct cache_entry *ce, const char *action,
 +static int verify_absent_sparse(struct cache_entry *ce,
 +                       enum unpack_trees_error_types error_type,
                         struct unpack_trees_options *o)
  {
 -      return verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_orphaned));
 +      enum unpack_trees_error_types orphaned_error = error_type;
 +      if (orphaned_error == ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN)
 +              orphaned_error = ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN;
 +
 +      return verify_absent_1(ce, orphaned_error, o);
  }
  
  static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
        int update = CE_UPDATE;
  
        if (!old) {
 -              if (verify_absent(merge, "overwritten", o))
 +              if (verify_absent(merge, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
                        return -1;
+               if (!o->skip_sparse_checkout && will_have_skip_worktree(merge, o))
+                       update |= CE_SKIP_WORKTREE;
                invalidate_ce_path(merge, o);
        } else if (!(old->ce_flags & CE_CONFLICTED)) {
                /*
@@@ -1218,7 -1134,7 +1224,7 @@@ static int deleted_entry(struct cache_e
  {
        /* Did it exist in the index? */
        if (!old) {
 -              if (verify_absent(ce, "removed", o))
 +              if (verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED, o))
                        return -1;
                return 0;
        }
@@@ -1367,7 -1283,7 +1373,7 @@@ int threeway_merge(struct cache_entry *
                        if (index)
                                return deleted_entry(index, index, o);
                        if (ce && !head_deleted) {
 -                              if (verify_absent(ce, "removed", o))
 +                              if (verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED, o))
                                        return -1;
                        }
                        return 0;
@@@ -1500,7 -1416,7 +1506,7 @@@ int bind_merge(struct cache_entry **src
                             o->merge_size);
        if (a && old)
                return o->gently ? -1 :
 -                      error(ERRORMSG(o, bind_overlap), a->name, old->name);
 +                      error(ERRORMSG(o, ERROR_BIND_OVERLAP), a->name, old->name);
        if (!a)
                return keep_entry(old, o);
        else