Merge branch 'nd/ita-cleanup'
authorJunio C Hamano <gitster@pobox.com>
Wed, 20 Jan 2016 19:43:25 +0000 (11:43 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 20 Jan 2016 19:43:25 +0000 (11:43 -0800)
Paths that have been told the index about with "add -N" are not
quite yet in the index, but a few commands behaved as if they
already are in a harmful way.

* nd/ita-cleanup:
grep: make it clear i-t-a entries are ignored
add and use a convenience macro ce_intent_to_add()
blame: remove obsolete comment

1  2 
builtin/blame.c
builtin/grep.c
builtin/rm.c
cache-tree.c
cache.h
read-cache.c
diff --combined builtin/blame.c
index d3fc82c852a7dfe26b7ca0556eb49fe2c2db37be,9a0df9215458604db4cb5ab500cb6e0f07d7664f..55bf5fae9d5d6ea6c4e058e50d9353e77e09b34b
@@@ -6,7 -6,6 +6,7 @@@
   */
  
  #include "cache.h"
 +#include "refs.h"
  #include "builtin.h"
  #include "blob.h"
  #include "commit.h"
  #include "userdiff.h"
  #include "line-range.h"
  #include "line-log.h"
 +#include "dir.h"
 +#include "progress.h"
  
 -static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] file");
 +static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
  
  static const char *blame_opt_usage[] = {
        blame_usage,
@@@ -51,9 -48,8 +51,9 @@@ static int incremental
  static int xdl_opts;
  static int abbrev = -1;
  static int no_whole_file_rename;
 +static int show_progress;
  
 -static enum date_mode blame_date_mode = DATE_ISO8601;
 +static struct date_mode blame_date_mode = { DATE_ISO8601 };
  static size_t blame_date_width;
  
  static struct string_list mailmap;
@@@ -129,11 -125,6 +129,11 @@@ struct origin 
        char path[FLEX_ARRAY];
  };
  
 +struct progress_info {
 +      struct progress *progress;
 +      int blamed_lines;
 +};
 +
  static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b, long ctxlen,
                      xdl_emit_hunk_consume_func_t hunk_func, void *cb_data)
  {
@@@ -466,13 -457,12 +466,13 @@@ static void queue_blames(struct scorebo
  static struct origin *make_origin(struct commit *commit, const char *path)
  {
        struct origin *o;
 -      o = xcalloc(1, sizeof(*o) + strlen(path) + 1);
 +      size_t pathlen = strlen(path) + 1;
 +      o = xcalloc(1, sizeof(*o) + pathlen);
        o->commit = commit;
        o->refcnt = 1;
        o->next = commit->util;
        commit->util = o;
 -      strcpy(o->path, path);
 +      memcpy(o->path, path, pathlen); /* includes NUL */
        return o;
  }
  
@@@ -513,7 -503,7 +513,7 @@@ static int fill_blob_sha1_and_mode(stru
  {
        if (!is_null_sha1(origin->blob_sha1))
                return 0;
 -      if (get_tree_entry(origin->commit->object.sha1,
 +      if (get_tree_entry(origin->commit->object.oid.hash,
                           origin->path,
                           origin->blob_sha1, &origin->mode))
                goto error_out;
@@@ -564,11 -554,11 +564,11 @@@ static struct origin *find_origin(struc
                       PATHSPEC_LITERAL_PATH, "", paths);
        diff_setup_done(&diff_opts);
  
 -      if (is_null_sha1(origin->commit->object.sha1))
 -              do_diff_cache(parent->tree->object.sha1, &diff_opts);
 +      if (is_null_oid(&origin->commit->object.oid))
 +              do_diff_cache(parent->tree->object.oid.hash, &diff_opts);
        else
 -              diff_tree_sha1(parent->tree->object.sha1,
 -                             origin->commit->tree->object.sha1,
 +              diff_tree_sha1(parent->tree->object.oid.hash,
 +                             origin->commit->tree->object.oid.hash,
                               "", &diff_opts);
        diffcore_std(&diff_opts);
  
@@@ -634,11 -624,11 +634,11 @@@ static struct origin *find_rename(struc
        diff_opts.single_follow = origin->path;
        diff_setup_done(&diff_opts);
  
 -      if (is_null_sha1(origin->commit->object.sha1))
 -              do_diff_cache(parent->tree->object.sha1, &diff_opts);
 +      if (is_null_oid(&origin->commit->object.oid))
 +              do_diff_cache(parent->tree->object.oid.hash, &diff_opts);
        else
 -              diff_tree_sha1(parent->tree->object.sha1,
 -                             origin->commit->tree->object.sha1,
 +              diff_tree_sha1(parent->tree->object.oid.hash,
 +                             origin->commit->tree->object.oid.hash,
                               "", &diff_opts);
        diffcore_std(&diff_opts);
  
@@@ -982,10 -972,7 +982,10 @@@ static void pass_blame_to_parent(struc
        fill_origin_blob(&sb->revs->diffopt, target, &file_o);
        num_get_patch++;
  
 -      diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d);
 +      if (diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d))
 +              die("unable to generate diff (%s -> %s)",
 +                  oid_to_hex(&parent->commit->object.oid),
 +                  oid_to_hex(&target->commit->object.oid));
        /* The rest are the same as the parent */
        blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, parent);
        *d.dstq = NULL;
@@@ -1131,9 -1118,7 +1131,9 @@@ static void find_copy_in_blob(struct sc
         * file_p partially may match that image.
         */
        memset(split, 0, sizeof(struct blame_entry [3]));
 -      diff_hunks(file_p, &file_o, 1, handle_split_cb, &d);
 +      if (diff_hunks(file_p, &file_o, 1, handle_split_cb, &d))
 +              die("unable to generate diff (%s)",
 +                  oid_to_hex(&parent->commit->object.oid));
        /* remainder, if any, all match the preimage */
        handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);
  }
@@@ -1282,11 -1267,11 +1282,11 @@@ static void find_copy_in_parent(struct 
                && (!porigin || strcmp(target->path, porigin->path))))
                DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
  
 -      if (is_null_sha1(target->commit->object.sha1))
 -              do_diff_cache(parent->tree->object.sha1, &diff_opts);
 +      if (is_null_oid(&target->commit->object.oid))
 +              do_diff_cache(parent->tree->object.oid.hash, &diff_opts);
        else
 -              diff_tree_sha1(parent->tree->object.sha1,
 -                             target->commit->tree->object.sha1,
 +              diff_tree_sha1(parent->tree->object.oid.hash,
 +                             target->commit->tree->object.oid.hash,
                               "", &diff_opts);
  
        if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER))
@@@ -1379,15 -1364,8 +1379,15 @@@ static void pass_whole_blame(struct sco
   */
  static struct commit_list *first_scapegoat(struct rev_info *revs, struct commit *commit)
  {
 -      if (!reverse)
 +      if (!reverse) {
 +              if (revs->first_parent_only &&
 +                  commit->parents &&
 +                  commit->parents->next) {
 +                      free_commit_list(commit->parents->next);
 +                      commit->parents->next = NULL;
 +              }
                return commit->parents;
 +      }
        return lookup_decoration(&revs->children, &commit->object);
  }
  
@@@ -1697,7 -1675,7 +1697,7 @@@ static void get_commit_info(struct comm
        if (len)
                strbuf_add(&ret->summary, subject, len);
        else
 -              strbuf_addf(&ret->summary, "(%s)", sha1_to_hex(commit->object.sha1));
 +              strbuf_addf(&ret->summary, "(%s)", oid_to_hex(&commit->object.oid));
  
        unuse_commit_buffer(commit, message);
  }
@@@ -1740,7 -1718,7 +1740,7 @@@ static int emit_one_suspect_detail(stru
                printf("boundary\n");
        if (suspect->previous) {
                struct origin *prev = suspect->previous;
 -              printf("previous %s ", sha1_to_hex(prev->commit->object.sha1));
 +              printf("previous %s ", oid_to_hex(&prev->commit->object.oid));
                write_name_quoted(prev->path, stdout, '\n');
        }
  
   * The blame_entry is found to be guilty for the range.
   * Show it in incremental output.
   */
 -static void found_guilty_entry(struct blame_entry *ent)
 +static void found_guilty_entry(struct blame_entry *ent,
 +                         struct progress_info *pi)
  {
        if (incremental) {
                struct origin *suspect = ent->suspect;
  
                printf("%s %d %d %d\n",
 -                     sha1_to_hex(suspect->commit->object.sha1),
 +                     oid_to_hex(&suspect->commit->object.oid),
                       ent->s_lno + 1, ent->lno + 1, ent->num_lines);
                emit_one_suspect_detail(suspect, 0);
                write_filename_info(suspect->path);
                maybe_flush_or_die(stdout, "stdout");
        }
 +      pi->blamed_lines += ent->num_lines;
 +      display_progress(pi->progress, pi->blamed_lines);
  }
  
  /*
@@@ -1778,11 -1753,6 +1778,11 @@@ static void assign_blame(struct scorebo
  {
        struct rev_info *revs = sb->revs;
        struct commit *commit = prio_queue_get(&sb->commits);
 +      struct progress_info pi = { NULL, 0 };
 +
 +      if (show_progress)
 +              pi.progress = start_progress_delay(_("Blaming lines"),
 +                                                 sb->num_lines, 50, 1);
  
        while (commit) {
                struct blame_entry *ent;
                        suspect->guilty = 1;
                        for (;;) {
                                struct blame_entry *next = ent->next;
 -                              found_guilty_entry(ent);
 +                              found_guilty_entry(ent, &pi);
                                if (next) {
                                        ent = next;
                                        continue;
                if (DEBUG) /* sanity */
                        sanity_check_refcnt(sb);
        }
 +
 +      stop_progress(&pi.progress);
  }
  
  static const char *format_time(unsigned long time, const char *tz_str,
                size_t time_width;
                int tz;
                tz = atoi(tz_str);
 -              time_str = show_date(time, tz, blame_date_mode);
 +              time_str = show_date(time, tz, &blame_date_mode);
                strbuf_addstr(&time_buf, time_str);
                /*
                 * Add space paddings to time_buf to display a fixed width
@@@ -1897,9 -1865,9 +1897,9 @@@ static void emit_porcelain(struct score
        int cnt;
        const char *cp;
        struct origin *suspect = ent->suspect;
 -      char hex[41];
 +      char hex[GIT_SHA1_HEXSZ + 1];
  
 -      strcpy(hex, sha1_to_hex(suspect->commit->object.sha1));
 +      sha1_to_hex_r(hex, suspect->commit->object.oid.hash);
        printf("%s %d %d %d\n",
               hex,
               ent->s_lno + 1,
@@@ -1935,11 -1903,11 +1935,11 @@@ static void emit_other(struct scoreboar
        const char *cp;
        struct origin *suspect = ent->suspect;
        struct commit_info ci;
 -      char hex[41];
 +      char hex[GIT_SHA1_HEXSZ + 1];
        int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);
  
        get_commit_info(suspect->commit, &ci, 1);
 -      strcpy(hex, sha1_to_hex(suspect->commit->object.sha1));
 +      sha1_to_hex_r(hex, suspect->commit->object.oid.hash);
  
        cp = nth_line(sb, ent->lno);
        for (cnt = 0; cnt < ent->num_lines; cnt++) {
@@@ -2094,7 -2062,7 +2094,7 @@@ static int read_ancestry(const char *gr
  
  static int update_auto_abbrev(int auto_abbrev, struct origin *suspect)
  {
 -      const char *uniq = find_unique_abbrev(suspect->commit->object.sha1,
 +      const char *uniq = find_unique_abbrev(suspect->commit->object.oid.hash,
                                              auto_abbrev);
        int len = strlen(uniq);
        if (auto_abbrev < len)
@@@ -2170,7 -2138,7 +2170,7 @@@ static void sanity_check_refcnt(struct 
                if (ent->suspect->refcnt <= 0) {
                        fprintf(stderr, "%s in %s has negative refcnt %d\n",
                                ent->suspect->path,
 -                              sha1_to_hex(ent->suspect->commit->object.sha1),
 +                              oid_to_hex(&ent->suspect->commit->object.oid),
                                ent->suspect->refcnt);
                        baa = 1;
                }
        }
  }
  
 -/*
 - * Used for the command line parsing; check if the path exists
 - * in the working tree.
 - */
 -static int has_string_in_work_tree(const char *path)
 -{
 -      struct stat st;
 -      return !lstat(path, &st);
 -}
 -
  static unsigned parse_score(const char *arg)
  {
        char *end;
@@@ -2207,18 -2185,10 +2207,18 @@@ static int git_blame_config(const char 
                blank_boundary = git_config_bool(var, value);
                return 0;
        }
 +      if (!strcmp(var, "blame.showemail")) {
 +              int *output_option = cb;
 +              if (git_config_bool(var, value))
 +                      *output_option |= OUTPUT_SHOW_EMAIL;
 +              else
 +                      *output_option &= ~OUTPUT_SHOW_EMAIL;
 +              return 0;
 +      }
        if (!strcmp(var, "blame.date")) {
                if (!value)
                        return config_error_nonbool(var);
 -              blame_date_mode = parse_date_format(value);
 +              parse_date_format(value, &blame_date_mode);
                return 0;
        }
  
@@@ -2233,7 -2203,7 +2233,7 @@@ static void verify_working_tree_path(st
        struct commit_list *parents;
  
        for (parents = work_tree->parents; parents; parents = parents->next) {
 -              const unsigned char *commit_sha1 = parents->item->object.sha1;
 +              const unsigned char *commit_sha1 = parents->item->object.oid.hash;
                unsigned char blob_sha1[20];
                unsigned mode;
  
@@@ -2257,19 -2227,20 +2257,19 @@@ static struct commit_list **append_pare
  static void append_merge_parents(struct commit_list **tail)
  {
        int merge_head;
 -      const char *merge_head_file = git_path("MERGE_HEAD");
        struct strbuf line = STRBUF_INIT;
  
 -      merge_head = open(merge_head_file, O_RDONLY);
 +      merge_head = open(git_path_merge_head(), O_RDONLY);
        if (merge_head < 0) {
                if (errno == ENOENT)
                        return;
 -              die("cannot open '%s' for reading", merge_head_file);
 +              die("cannot open '%s' for reading", git_path_merge_head());
        }
  
        while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
                unsigned char sha1[20];
                if (line.len < 40 || get_sha1_hex(line.buf, sha1))
 -                      die("unknown line in '%s': %s", merge_head_file, line.buf);
 +                      die("unknown line in '%s': %s", git_path_merge_head(), line.buf);
                tail = append_parent(tail, sha1);
        }
        close(merge_head);
@@@ -2327,7 -2298,7 +2327,7 @@@ static struct commit *fake_working_tree
        strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n");
        for (parent = commit->parents; parent; parent = parent->next)
                strbuf_addf(&msg, "parent %s\n",
 -                          sha1_to_hex(parent->item->object.sha1));
 +                          oid_to_hex(&parent->item->object.oid));
        strbuf_addf(&msg,
                    "author %s\n"
                    "committer %s\n\n"
                if (strbuf_read(&buf, 0, 0) < 0)
                        die_errno("failed to read from stdin");
        }
 +      convert_to_git(path, buf.buf, buf.len, &buf, 0);
        origin->file.ptr = buf.buf;
        origin->file.size = buf.len;
        pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1);
        ce->ce_mode = create_ce_mode(mode);
        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
  
-       /*
-        * We are not going to write this out, so this does not matter
-        * right now, but someday we might optimize diff-index --cached
-        * with cache-tree information.
-        */
        cache_tree_invalidate_path(&the_index, path);
  
        return commit;
  }
  
 -static char *prepare_final(struct scoreboard *sb)
 +static struct commit *find_single_final(struct rev_info *revs,
 +                                      const char **name_p)
  {
        int i;
 -      const char *final_commit_name = NULL;
 -      struct rev_info *revs = sb->revs;
 +      struct commit *found = NULL;
 +      const char *name = NULL;
  
 -      /*
 -       * There must be one and only one positive commit in the
 -       * revs->pending array.
 -       */
        for (i = 0; i < revs->pending.nr; i++) {
                struct object *obj = revs->pending.objects[i].item;
                if (obj->flags & UNINTERESTING)
                        obj = deref_tag(obj, NULL, 0);
                if (obj->type != OBJ_COMMIT)
                        die("Non commit %s?", revs->pending.objects[i].name);
 -              if (sb->final)
 +              if (found)
                        die("More than one commit to dig from %s and %s?",
 -                          revs->pending.objects[i].name,
 -                          final_commit_name);
 -              sb->final = (struct commit *) obj;
 -              final_commit_name = revs->pending.objects[i].name;
 +                          revs->pending.objects[i].name, name);
 +              found = (struct commit *)obj;
 +              name = revs->pending.objects[i].name;
        }
 -      return xstrdup_or_null(final_commit_name);
 +      if (name_p)
 +              *name_p = name;
 +      return found;
 +}
 +
 +static char *prepare_final(struct scoreboard *sb)
 +{
 +      const char *name;
 +      sb->final = find_single_final(sb->revs, &name);
 +      return xstrdup_or_null(name);
  }
  
  static char *prepare_initial(struct scoreboard *sb)
@@@ -2525,7 -2485,6 +2520,7 @@@ int cmd_blame(int argc, const char **ar
        long dashdash_pos, lno;
        char *final_commit_name = NULL;
        enum object_type type;
 +      struct commit *final_commit = NULL;
  
        static struct string_list range_list;
        static int output_option = 0, opt = 0;
                OPT_BOOL('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")),
                OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")),
                OPT_BOOL(0, "show-stats", &show_stats, N_("Show work cost statistics")),
 +              OPT_BOOL(0, "progress", &show_progress, N_("Force progress reporting")),
                OPT_BIT(0, "score-debug", &output_option, N_("Show output score for blame entries"), OUTPUT_SHOW_SCORE),
                OPT_BIT('f', "show-name", &output_option, N_("Show original filename (Default: auto)"), OUTPUT_SHOW_NAME),
                OPT_BIT('n', "show-number", &output_option, N_("Show original linenumber (Default: off)"), OUTPUT_SHOW_NUMBER),
        unsigned int range_i;
        long anchor;
  
 -      git_config(git_blame_config, NULL);
 +      git_config(git_blame_config, &output_option);
        init_revisions(&revs, NULL);
        revs.date_mode = blame_date_mode;
        DIFF_OPT_SET(&revs.diffopt, ALLOW_TEXTCONV);
  
        save_commit_buffer = 0;
        dashdash_pos = 0;
 +      show_progress = -1;
  
        parse_options_start(&ctx, argc, argv, prefix, options,
                            PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0);
@@@ -2598,13 -2555,6 +2593,13 @@@ parse_done
        DIFF_OPT_CLR(&revs.diffopt, FOLLOW_RENAMES);
        argc = parse_options_end(&ctx);
  
 +      if (incremental || (output_option & OUTPUT_PORCELAIN)) {
 +              if (show_progress > 0)
 +                      die("--progress can't be used with --incremental or porcelain formats");
 +              show_progress = 0;
 +      } else if (show_progress < 0)
 +              show_progress = isatty(2);
 +
        if (0 < abbrev)
                /* one more abbrev length is needed for the boundary commit */
                abbrev++;
  
        if (cmd_is_annotate) {
                output_option |= OUTPUT_ANNOTATE_COMPAT;
 -              blame_date_mode = DATE_ISO8601;
 +              blame_date_mode.type = DATE_ISO8601;
        } else {
                blame_date_mode = revs.date_mode;
        }
  
        /* The maximum width used to show the dates */
 -      switch (blame_date_mode) {
 +      switch (blame_date_mode.type) {
        case DATE_RFC2822:
                blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700");
                break;
                   fewer display columns. */
                blame_date_width = utf8_strwidth(_("4 years, 11 months ago")) + 1; /* add the null */
                break;
 -      case DATE_LOCAL:
        case DATE_NORMAL:
                blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
                break;
 +      case DATE_STRFTIME:
 +              blame_date_width = strlen(show_date(0, 0, &blame_date_mode)) + 1; /* add the null */
 +              break;
        }
        blame_date_width -= 1; /* strip the null */
  
                if (argc < 2)
                        usage_with_options(blame_opt_usage, options);
                path = add_prefix(prefix, argv[argc - 1]);
 -              if (argc == 3 && !has_string_in_work_tree(path)) { /* (2b) */
 +              if (argc == 3 && !file_exists(path)) { /* (2b) */
                        path = add_prefix(prefix, argv[1]);
                        argv[1] = argv[2];
                }
                argv[argc - 1] = "--";
  
                setup_work_tree();
 -              if (!has_string_in_work_tree(path))
 +              if (!file_exists(path))
                        die_errno("cannot stat path '%s'", path);
        }
  
                sb.commits.compare = compare_commits_by_commit_date;
        }
        else if (contents_from)
 -              die("--contents and --children do not blend well.");
 +              die("--contents and --reverse do not blend well.");
        else {
                final_commit_name = prepare_initial(&sb);
                sb.commits.compare = compare_commits_by_reverse_commit_date;
 +              if (revs.first_parent_only)
 +                      revs.children.name = NULL;
        }
  
        if (!sb.final) {
        else if (contents_from)
                die("Cannot use --contents with final commit object name");
  
 +      if (reverse && revs.first_parent_only) {
 +              final_commit = find_single_final(sb.revs, NULL);
 +              if (!final_commit)
 +                      die("--reverse and --first-parent together require specified latest commit");
 +      }
 +
        /*
         * If we have bottom, this will mark the ancestors of the
         * bottom commits we would reach while traversing as
        if (prepare_revision_walk(&revs))
                die(_("revision walk setup failed"));
  
 -      if (is_null_sha1(sb.final->object.sha1)) {
 +      if (reverse && revs.first_parent_only) {
 +              struct commit *c = final_commit;
 +
 +              sb.revs->children.name = "children";
 +              while (c->parents &&
 +                     oidcmp(&c->object.oid, &sb.final->object.oid)) {
 +                      struct commit_list *l = xcalloc(1, sizeof(*l));
 +
 +                      l->item = c;
 +                      if (add_decoration(&sb.revs->children,
 +                                         &c->parents->item->object, l))
 +                              die("BUG: not unique item in first-parent chain");
 +                      c = c->parents->item;
 +              }
 +
 +              if (oidcmp(&c->object.oid, &sb.final->object.oid))
 +                      die("--reverse --first-parent together require range along first-parent chain");
 +      }
 +
 +      if (is_null_oid(&sb.final->object.oid)) {
                o = sb.final->util;
                sb.final_buf = xmemdupz(o->file.ptr, o->file.size);
                sb.final_buf_size = o->file.size;
  
        read_mailmap(&mailmap, NULL);
  
 +      assign_blame(&sb, opt);
 +
        if (!incremental)
                setup_pager();
  
 -      assign_blame(&sb, opt);
 -
        free(final_commit_name);
  
        if (incremental)
diff --combined builtin/grep.c
index 760dc8eae90f0c28cc8b4c664472fdec20fe688d,f50817974070c414cc7c368df5bd78361a8f522d..06ab68223a13b35612e2cb283d778a9c904b5528
@@@ -24,11 -24,11 +24,11 @@@ static char const * const grep_usage[] 
        NULL
  };
  
 -static int use_threads = 1;
 +#define GREP_NUM_THREADS_DEFAULT 8
 +static int num_threads;
  
  #ifndef NO_PTHREADS
 -#define THREADS 8
 -static pthread_t threads[THREADS];
 +static pthread_t *threads;
  
  /* We use one producer thread and THREADS consumer
   * threads. The producer adds struct work_items to 'todo' and the
@@@ -63,13 -63,13 +63,13 @@@ static pthread_mutex_t grep_mutex
  
  static inline void grep_lock(void)
  {
 -      if (use_threads)
 +      if (num_threads)
                pthread_mutex_lock(&grep_mutex);
  }
  
  static inline void grep_unlock(void)
  {
 -      if (use_threads)
 +      if (num_threads)
                pthread_mutex_unlock(&grep_mutex);
  }
  
@@@ -206,8 -206,7 +206,8 @@@ static void start_threads(struct grep_o
                strbuf_init(&todo[i].out, 0);
        }
  
 -      for (i = 0; i < ARRAY_SIZE(threads); i++) {
 +      threads = xcalloc(num_threads, sizeof(*threads));
 +      for (i = 0; i < num_threads; i++) {
                int err;
                struct grep_opt *o = grep_opt_dup(opt);
                o->output = strbuf_out;
@@@ -239,14 -238,12 +239,14 @@@ static int wait_all(void
        pthread_cond_broadcast(&cond_add);
        grep_unlock();
  
 -      for (i = 0; i < ARRAY_SIZE(threads); i++) {
 +      for (i = 0; i < num_threads; i++) {
                void *h;
                pthread_join(threads[i], &h);
                hit |= (int) (intptr_t) h;
        }
  
 +      free(threads);
 +
        pthread_mutex_destroy(&grep_mutex);
        pthread_mutex_destroy(&grep_read_mutex);
        pthread_mutex_destroy(&grep_attr_mutex);
@@@ -270,14 -267,6 +270,14 @@@ static int grep_cmd_config(const char *
        int st = grep_config(var, value, cb);
        if (git_color_default_config(var, value, cb) < 0)
                st = -1;
 +
 +      if (!strcmp(var, "grep.threads")) {
 +              num_threads = git_config_int(var, value);
 +              if (num_threads < 0)
 +                      die(_("invalid number of threads specified (%d) for %s"),
 +                          num_threads, var);
 +      }
 +
        return st;
  }
  
@@@ -305,7 -294,7 +305,7 @@@ static int grep_sha1(struct grep_opt *o
        }
  
  #ifndef NO_PTHREADS
 -      if (use_threads) {
 +      if (num_threads) {
                add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1);
                strbuf_release(&pathbuf);
                return 0;
@@@ -334,7 -323,7 +334,7 @@@ static int grep_file(struct grep_opt *o
                strbuf_addstr(&buf, filename);
  
  #ifndef NO_PTHREADS
 -      if (use_threads) {
 +      if (num_threads) {
                add_work(opt, GREP_SOURCE_FILE, buf.buf, filename, filename);
                strbuf_release(&buf);
                return 0;
@@@ -386,7 -375,7 +386,7 @@@ static int grep_cache(struct grep_opt *
  
        for (nr = 0; nr < active_nr; nr++) {
                const struct cache_entry *ce = active_cache[nr];
-               if (!S_ISREG(ce->ce_mode))
+               if (!S_ISREG(ce->ce_mode) || ce_intent_to_add(ce))
                        continue;
                if (!ce_path_match(ce, pathspec, NULL))
                        continue;
@@@ -470,7 -459,7 +470,7 @@@ static int grep_object(struct grep_opt 
                       struct object *obj, const char *name, const char *path)
  {
        if (obj->type == OBJ_BLOB)
 -              return grep_sha1(opt, obj->sha1, name, 0, path);
 +              return grep_sha1(opt, obj->oid.hash, name, 0, path);
        if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
                struct tree_desc tree;
                void *data;
                int hit, len;
  
                grep_read_lock();
 -              data = read_object_with_reference(obj->sha1, tree_type,
 +              data = read_object_with_reference(obj->oid.hash, tree_type,
                                                  &size, NULL);
                grep_read_unlock();
  
                if (!data)
 -                      die(_("unable to read tree (%s)"), sha1_to_hex(obj->sha1));
 +                      die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid));
  
                len = name ? strlen(name) : 0;
                strbuf_init(&base, PATH_MAX + len + 1);
@@@ -623,6 -612,11 +623,6 @@@ static int pattern_callback(const struc
        return 0;
  }
  
 -static int help_callback(const struct option *opt, const char *arg, int unset)
 -{
 -      return -1;
 -}
 -
  int cmd_grep(int argc, const char **argv, const char *prefix)
  {
        int hit = 0;
                        N_("show <n> context lines before matches")),
                OPT_INTEGER('A', "after-context", &opt.post_context,
                        N_("show <n> context lines after matches")),
 +              OPT_INTEGER(0, "threads", &num_threads,
 +                      N_("use <n> worker threads")),
                OPT_NUMBER_CALLBACK(&opt, N_("shortcut for -C NUM"),
                        context_callback),
                OPT_BOOL('p', "show-function", &opt.funcname,
                        PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager },
                OPT_BOOL(0, "ext-grep", &external_grep_allowed__ignored,
                         N_("allow calling of grep(1) (ignored by this build)")),
 -              { OPTION_CALLBACK, 0, "help-all", NULL, NULL, N_("show usage"),
 -                PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
                OPT_END()
        };
  
 -      /*
 -       * 'git grep -h', unlike 'git grep -h <pattern>', is a request
 -       * to show usage information and exit.
 -       */
 -      if (argc == 2 && !strcmp(argv[1], "-h"))
 -              usage_with_options(grep_usage, options);
 -
        init_grep_defaults();
        git_config(grep_cmd_config, NULL);
        grep_init(&opt, prefix);
         */
        argc = parse_options(argc, argv, prefix, options, grep_usage,
                             PARSE_OPT_KEEP_DASHDASH |
 -                           PARSE_OPT_STOP_AT_NON_OPTION |
 -                           PARSE_OPT_NO_INTERNAL_HELP);
 +                           PARSE_OPT_STOP_AT_NON_OPTION);
        grep_commit_pattern_type(pattern_type_arg, &opt);
  
        if (use_index && !startup_info->have_repository)
                opt.output_priv = &path_list;
                opt.output = append_path;
                string_list_append(&path_list, show_in_pager);
 -              use_threads = 0;
        }
  
        if (!opt.pattern_list)
        }
  
  #ifndef NO_PTHREADS
 -      if (list.nr || cached || online_cpus() == 1)
 -              use_threads = 0;
 +      if (list.nr || cached || show_in_pager)
 +              num_threads = 0;
 +      else if (num_threads == 0)
 +              num_threads = GREP_NUM_THREADS_DEFAULT;
 +      else if (num_threads < 0)
 +              die(_("invalid number of threads specified (%d)"), num_threads);
  #else
 -      use_threads = 0;
 +      num_threads = 0;
  #endif
  
  #ifndef NO_PTHREADS
 -      if (use_threads) {
 +      if (num_threads) {
                if (!(opt.name_only || opt.unmatch_name_only || opt.count)
                    && (opt.pre_context || opt.post_context ||
                        opt.file_break || opt.funcbody))
                hit = grep_objects(&opt, &pathspec, &list);
        }
  
 -      if (use_threads)
 +      if (num_threads)
                hit |= wait_all();
        if (hit && show_in_pager)
                run_pager(&opt, prefix);
diff --combined builtin/rm.c
index 80b972f92fde3201bdf1cb8bd74c2b4ff53fa5ae,74a7a43efb9a119b342dde25db12902fdaf0e461..8829b09d0ba5d49edbad5f37f8246123dad3fd5f
@@@ -84,6 -84,7 +84,6 @@@ static int check_submodules_use_gitfile
                const char *name = list.entry[i].name;
                int pos;
                const struct cache_entry *ce;
 -              struct stat st;
  
                pos = cache_name_pos(name, strlen(name));
                if (pos < 0) {
@@@ -94,7 -95,7 +94,7 @@@
                ce = active_cache[pos];
  
                if (!S_ISGITLINK(ce->ce_mode) ||
 -                  (lstat(ce->name, &st) < 0) ||
 +                  !file_exists(ce->name) ||
                    is_empty_dir(name))
                        continue;
  
@@@ -211,7 -212,7 +211,7 @@@ static int check_local_mod(unsigned cha
                 * "intent to add" entry.
                 */
                if (local_changes && staged_changes) {
-                       if (!index_only || !(ce->ce_flags & CE_INTENT_TO_ADD))
+                       if (!index_only || !ce_intent_to_add(ce))
                                string_list_append(&files_staged, name);
                }
                else if (!index_only) {
diff --combined cache-tree.c
index a59e6f1e1fcfb65bd2fe9cdba0db60d6d87e7d96,e590346a08b4f71a1162ee5608c4c53467b9d0ea..20ee7b52df0c33d4473a198270705dffead01cdc
@@@ -377,7 -377,7 +377,7 @@@ static int update_one(struct cache_tre
                 * they are not part of generated trees. Invalidate up
                 * to root to force cache-tree users to read elsewhere.
                 */
-               if (ce->ce_flags & CE_INTENT_TO_ADD) {
+               if (ce_intent_to_add(ce)) {
                        to_invalidate = 1;
                        continue;
                }
@@@ -592,7 -592,7 +592,7 @@@ static struct cache_tree *cache_tree_fi
        return it;
  }
  
 -int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
 +int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, const char *index_path, int flags, const char *prefix)
  {
        int entries, was_valid, newfd;
        struct lock_file *lock_file;
         */
        lock_file = xcalloc(1, sizeof(struct lock_file));
  
 -      newfd = hold_locked_index(lock_file, 1);
 +      newfd = hold_lock_file_for_update(lock_file, index_path, LOCK_DIE_ON_ERROR);
  
 -      entries = read_cache();
 +      entries = read_index_from(index_state, index_path);
        if (entries < 0)
                return WRITE_TREE_UNREADABLE_INDEX;
        if (flags & WRITE_TREE_IGNORE_CACHE_TREE)
 -              cache_tree_free(&(active_cache_tree));
 +              cache_tree_free(&index_state->cache_tree);
  
 -      if (!active_cache_tree)
 -              active_cache_tree = cache_tree();
 +      if (!index_state->cache_tree)
 +              index_state->cache_tree = cache_tree();
  
 -      was_valid = cache_tree_fully_valid(active_cache_tree);
 +      was_valid = cache_tree_fully_valid(index_state->cache_tree);
        if (!was_valid) {
 -              if (cache_tree_update(&the_index, flags) < 0)
 +              if (cache_tree_update(index_state, flags) < 0)
                        return WRITE_TREE_UNMERGED_INDEX;
                if (0 <= newfd) {
 -                      if (!write_locked_index(&the_index, lock_file, COMMIT_LOCK))
 +                      if (!write_locked_index(index_state, lock_file, COMMIT_LOCK))
                                newfd = -1;
                }
                /* Not being able to write is fine -- we are only interested
        }
  
        if (prefix) {
 -              struct cache_tree *subtree =
 -                      cache_tree_find(active_cache_tree, prefix);
 +              struct cache_tree *subtree;
 +              subtree = cache_tree_find(index_state->cache_tree, prefix);
                if (!subtree)
                        return WRITE_TREE_PREFIX_ERROR;
                hashcpy(sha1, subtree->sha1);
        }
        else
 -              hashcpy(sha1, active_cache_tree->sha1);
 +              hashcpy(sha1, index_state->cache_tree->sha1);
  
        if (0 <= newfd)
                rollback_lock_file(lock_file);
        return 0;
  }
  
 +int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)
 +{
 +      return write_index_as_tree(sha1, &the_index, get_index_file(), flags, prefix);
 +}
 +
  static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
  {
        struct tree_desc desc;
        struct name_entry entry;
        int cnt;
  
 -      hashcpy(it->sha1, tree->object.sha1);
 +      hashcpy(it->sha1, tree->object.oid.hash);
        init_tree_desc(&desc, tree->buffer, tree->size);
        cnt = 0;
        while (tree_entry(&desc, &entry)) {
diff --combined cache.h
index bf00ce55f8094e36d414722035a1201789fe79ac,b1f05319667901f29a9642c4e6cd8aec7892a372..dcd654ffde28a869231ca032268d68499a84724f
+++ b/cache.h
@@@ -9,32 -9,13 +9,32 @@@
  #include "convert.h"
  #include "trace.h"
  #include "string-list.h"
 +#include "pack-revindex.h"
  
  #include SHA1_HEADER
 -#ifndef git_SHA_CTX
 -#define git_SHA_CTX   SHA_CTX
 -#define git_SHA1_Init SHA1_Init
 -#define git_SHA1_Update       SHA1_Update
 -#define git_SHA1_Final        SHA1_Final
 +#ifndef platform_SHA_CTX
 +/*
 + * platform's underlying implementation of SHA-1; could be OpenSSL,
 + * blk_SHA, Apple CommonCrypto, etc...  Note that including
 + * SHA1_HEADER may have already defined platform_SHA_CTX for our
 + * own implementations like block-sha1 and ppc-sha1, so we list
 + * the default for OpenSSL compatible SHA-1 implementations here.
 + */
 +#define platform_SHA_CTX      SHA_CTX
 +#define platform_SHA1_Init    SHA1_Init
 +#define platform_SHA1_Update  SHA1_Update
 +#define platform_SHA1_Final           SHA1_Final
 +#endif
 +
 +#define git_SHA_CTX           platform_SHA_CTX
 +#define git_SHA1_Init         platform_SHA1_Init
 +#define git_SHA1_Update               platform_SHA1_Update
 +#define git_SHA1_Final                platform_SHA1_Final
 +
 +#ifdef SHA1_MAX_BLOCK_SIZE
 +#include "compat/sha1-chunked.h"
 +#undef git_SHA1_Update
 +#define git_SHA1_Update               git_SHA1_Update_Chunked
  #endif
  
  #include <zlib.h>
@@@ -62,14 -43,6 +62,14 @@@ int git_deflate_end_gently(git_zstream 
  int git_deflate(git_zstream *, int flush);
  unsigned long git_deflate_bound(git_zstream *, unsigned long);
  
 +/* 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)
 +
 +struct object_id {
 +      unsigned char hash[GIT_SHA1_RAWSZ];
 +};
 +
  #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
  #define DTYPE(de)     ((de)->d_type)
  #else
@@@ -260,6 -233,7 +260,7 @@@ static inline unsigned create_ce_flags(
  #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
  #define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
  #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
+ #define ce_intent_to_add(ce) ((ce)->ce_flags & CE_INTENT_TO_ADD)
  
  #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
  static inline unsigned int create_ce_mode(unsigned int mode)
@@@ -316,11 -290,8 +317,11 @@@ static inline unsigned int canon_mode(u
  #define RESOLVE_UNDO_CHANGED  (1 << 4)
  #define CACHE_TREE_CHANGED    (1 << 5)
  #define SPLIT_INDEX_ORDERED   (1 << 6)
 +#define UNTRACKED_CHANGED     (1 << 7)
  
  struct split_index;
 +struct untracked_cache;
 +
  struct index_state {
        struct cache_entry **cache;
        unsigned int version;
        struct hashmap name_hash;
        struct hashmap dir_hash;
        unsigned char sha1[20];
 +      struct untracked_cache *untracked;
  };
  
  extern struct index_state the_index;
@@@ -401,7 -371,6 +402,7 @@@ static inline enum object_type object_t
  
  /* Double-check local_repo_env below if you add to this list. */
  #define GIT_DIR_ENVIRONMENT "GIT_DIR"
 +#define GIT_COMMON_DIR_ENVIRONMENT "GIT_COMMON_DIR"
  #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
  #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
  #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
  #define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
  #define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES"
  #define NO_REPLACE_OBJECTS_ENVIRONMENT "GIT_NO_REPLACE_OBJECTS"
 +#define GIT_REPLACE_REF_BASE_ENVIRONMENT "GIT_REPLACE_REF_BASE"
  #define GITATTRIBUTES_FILE ".gitattributes"
  #define INFOATTRIBUTES_FILE "info/attributes"
  #define ATTRIBUTE_MACRO_PREFIX "[attr]"
@@@ -456,28 -424,15 +457,28 @@@ extern int is_inside_git_dir(void)
  extern char *git_work_tree_cfg;
  extern int is_inside_work_tree(void);
  extern const char *get_git_dir(void);
 +extern const char *get_git_common_dir(void);
  extern int is_git_directory(const char *path);
  extern char *get_object_directory(void);
  extern char *get_index_file(void);
  extern char *get_graft_file(void);
  extern int set_git_dir(const char *path);
 +extern int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
 +extern int get_common_dir(struct strbuf *sb, const char *gitdir);
  extern const char *get_git_namespace(void);
  extern const char *strip_namespace(const char *namespaced_ref);
  extern const char *get_git_work_tree(void);
 -extern const char *read_gitfile(const char *path);
 +
 +#define READ_GITFILE_ERR_STAT_FAILED 1
 +#define READ_GITFILE_ERR_NOT_A_FILE 2
 +#define READ_GITFILE_ERR_OPEN_FAILED 3
 +#define READ_GITFILE_ERR_READ_FAILED 4
 +#define READ_GITFILE_ERR_INVALID_FORMAT 5
 +#define READ_GITFILE_ERR_NO_PATH 6
 +#define READ_GITFILE_ERR_NOT_A_REPO 7
 +#define READ_GITFILE_ERR_TOO_LARGE 8
 +extern const char *read_gitfile_gently(const char *path, int *return_error_code);
 +#define read_gitfile(path) read_gitfile_gently((path), NULL)
  extern const char *resolve_gitdir(const char *suspect);
  extern void set_git_work_tree(const char *tree);
  
@@@ -540,8 -495,7 +541,8 @@@ extern int write_locked_index(struct in
  extern int discard_index(struct index_state *);
  extern int unmerged_index(const struct index_state *);
  extern int verify_path(const char *path);
 -extern struct cache_entry *index_dir_exists(struct index_state *istate, const char *name, int namelen);
 +extern int index_dir_exists(struct index_state *istate, const char *name, int namelen);
 +extern void adjust_dirname_case(struct index_state *istate, char *name);
  extern struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);
  extern int index_name_pos(const struct index_state *, const char *name, int namelen);
  #define ADD_CACHE_OK_TO_ADD 1         /* Ok to add */
@@@ -599,8 -553,6 +600,8 @@@ extern void fill_stat_data(struct stat_
   * INODE_CHANGED, and DATA_CHANGED.
   */
  extern int match_stat_data(const struct stat_data *sd, struct stat *st);
 +extern int match_stat_data_racy(const struct index_state *istate,
 +                              const struct stat_data *sd, struct stat *st);
  
  extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
  
@@@ -617,6 -569,8 +618,6 @@@ extern void update_index_if_able(struc
  extern int hold_locked_index(struct lock_file *, int);
  extern void set_alternate_index_output(const char *);
  
 -extern int delete_ref(const char *, const unsigned char *sha1, unsigned int flags);
 -
  /* Environment bits from configuration mechanism */
  extern int trust_executable_bit;
  extern int trust_ctime;
@@@ -652,7 -606,6 +653,7 @@@ extern unsigned long pack_size_limit_cf
   * been sought but there were none.
   */
  extern int check_replace_refs;
 +extern char *git_replace_ref_base;
  
  extern int fsync_object_files;
  extern int core_preload_index;
@@@ -660,7 -613,6 +661,7 @@@ extern int core_apply_sparse_checkout
  extern int precomposed_unicode;
  extern int protect_hfs;
  extern int protect_ntfs;
 +extern int git_db_env, git_index_env, git_graft_env, git_common_dir_env;
  
  /*
   * Include broken refs in all ref iterations, which will
@@@ -717,15 -669,8 +718,15 @@@ extern char *notes_ref_name
  
  extern int grafts_replace_parents;
  
 +/*
 + * GIT_REPO_VERSION is the version we write by default. The
 + * _READ variant is the highest number we know how to
 + * handle.
 + */
  #define GIT_REPO_VERSION 0
 +#define GIT_REPO_VERSION_READ 1
  extern int repository_format_version;
 +extern int repository_format_precious_objects;
  extern int check_repository_format(void);
  
  #define MTIME_CHANGED 0x0001
  #define DATA_CHANGED    0x0020
  #define TYPE_CHANGED    0x0040
  
 +/*
 + * Return a statically allocated filename, either generically (mkpath), in
 + * the repository directory (git_path), or in a submodule's repository
 + * directory (git_path_submodule). In all cases, note that the result
 + * may be overwritten by another call to _any_ of the functions. Consider
 + * using the safer "dup" or "strbuf" formats below (in some cases, the
 + * unsafe versions have already been removed).
 + */
 +extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 +extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 +
  extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
        __attribute__((format (printf, 3, 4)));
 -extern char *git_snpath(char *buf, size_t n, const char *fmt, ...)
 +extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
 +      __attribute__((format (printf, 2, 3)));
 +extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
 +      __attribute__((format (printf, 2, 3)));
 +extern void strbuf_git_path_submodule(struct strbuf *sb, const char *path,
 +                                    const char *fmt, ...)
        __attribute__((format (printf, 3, 4)));
  extern char *git_pathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
  extern char *mkpathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
 -
 -/* 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, ...)
 +extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)
        __attribute__((format (printf, 2, 3)));
  
 +extern void report_linked_checkout_garbage(void);
 +
 +/*
 + * You can define a static memoized git path like:
 + *
 + *    static GIT_PATH_FUNC(git_path_foo, "FOO");
 + *
 + * or use one of the global ones below.
 + */
 +#define GIT_PATH_FUNC(func, filename) \
 +      const char *func(void) \
 +      { \
 +              static char *ret; \
 +              if (!ret) \
 +                      ret = git_pathdup(filename); \
 +              return ret; \
 +      }
 +
 +const char *git_path_cherry_pick_head(void);
 +const char *git_path_revert_head(void);
 +const char *git_path_squash_msg(void);
 +const char *git_path_merge_msg(void);
 +const char *git_path_merge_rr(void);
 +const char *git_path_merge_mode(void);
 +const char *git_path_merge_head(void);
 +const char *git_path_fetch_head(void);
 +const char *git_path_shallow(void);
 +
  /*
   * Return the name of the file in the local object database that would
   * be used to store a loose object with the specified sha1.  The
@@@ -813,32 -718,14 +814,32 @@@ extern char *sha1_pack_name(const unsig
   */
  extern char *sha1_pack_index_name(const unsigned char *sha1);
  
 -extern const char *find_unique_abbrev(const unsigned char *sha1, int);
 -extern const unsigned char null_sha1[20];
 +/*
 + * Return an abbreviated sha1 unique within this repository's object database.
 + * The result will be at least `len` characters long, and will be NUL
 + * terminated.
 + *
 + * The non-`_r` version returns a static buffer which will be overwritten by
 + * subsequent calls.
 + *
 + * The `_r` variant writes to a buffer supplied by the caller, which must be at
 + * least `GIT_SHA1_HEXSZ + 1` bytes. The return value is the number of bytes
 + * written (excluding the NUL terminator).
 + *
 + * Note that while this version avoids the static buffer, it is not fully
 + * reentrant, as it calls into other non-reentrant git code.
 + */
 +extern const char *find_unique_abbrev(const unsigned char *sha1, int len);
 +extern int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len);
 +
 +extern const unsigned char null_sha1[GIT_SHA1_RAWSZ];
 +extern const struct object_id null_oid;
  
  static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
  {
        int i;
  
 -      for (i = 0; i < 20; i++, sha1++, sha2++) {
 +      for (i = 0; i < GIT_SHA1_RAWSZ; i++, sha1++, sha2++) {
                if (*sha1 != *sha2)
                        return *sha1 - *sha2;
        }
        return 0;
  }
  
 +static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)
 +{
 +      return hashcmp(oid1->hash, oid2->hash);
 +}
 +
  static inline int is_null_sha1(const unsigned char *sha1)
  {
        return !hashcmp(sha1, null_sha1);
  }
  
 +static inline int is_null_oid(const struct object_id *oid)
 +{
 +      return !hashcmp(oid->hash, null_sha1);
 +}
 +
  static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
  {
 -      memcpy(sha_dst, sha_src, 20);
 +      memcpy(sha_dst, sha_src, GIT_SHA1_RAWSZ);
  }
 +
 +static inline void oidcpy(struct object_id *dst, const struct object_id *src)
 +{
 +      hashcpy(dst->hash, src->hash);
 +}
 +
  static inline void hashclr(unsigned char *hash)
  {
 -      memset(hash, 0, 20);
 +      memset(hash, 0, GIT_SHA1_RAWSZ);
 +}
 +
 +static inline void oidclr(struct object_id *oid)
 +{
 +      hashclr(oid->hash);
  }
  
 +
  #define EMPTY_TREE_SHA1_HEX \
        "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
  #define EMPTY_TREE_SHA1_BIN_LITERAL \
@@@ -952,6 -817,7 +953,6 @@@ enum scld_error safe_create_leading_dir
  enum scld_error safe_create_leading_directories_const(const char *path);
  
  int mkdir_in_gitdir(const char *path);
 -extern void home_config_paths(char **global, char **xdg, char *file);
  extern char *expand_user_path(const char *path);
  const char *enter_repo(const char *path, int strict);
  static inline int is_absolute_path(const char *path)
@@@ -971,16 -837,8 +972,16 @@@ char *strip_path_suffix(const char *pat
  int daemon_avoid_alias(const char *path);
  extern int is_ntfs_dotgit(const char *name);
  
 +/**
 + * Return a newly allocated string with the evaluation of
 + * "$XDG_CONFIG_HOME/git/$filename" if $XDG_CONFIG_HOME is non-empty, otherwise
 + * "$HOME/.config/git/$filename". Return NULL upon error.
 + */
 +extern char *xdg_config_home(const char *filename);
 +
  /* object replacement */
  #define LOOKUP_REPLACE_OBJECT 1
 +#define LOOKUP_UNKNOWN_OBJECT 2
  extern void *read_sha1_file_extended(const unsigned char *sha1, enum object_type *type, unsigned long *size, unsigned flag);
  static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
  {
@@@ -1017,7 -875,6 +1018,7 @@@ static inline const unsigned char *look
  extern int sha1_object_info(const unsigned char *, unsigned long *);
  extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
  extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 +extern int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type, unsigned char *sha1, unsigned flags);
  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);
  extern int git_open_noatime(const char *name);
@@@ -1030,7 -887,7 +1031,7 @@@ extern int do_check_packed_object_crc
  
  extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
  
 -extern int move_temp_to_file(const char *tmpfile, const char *filename);
 +extern int finalize_object_file(const char *tmpfile, const char *filename);
  
  extern int has_sha1_pack(const unsigned char *sha1);
  
   * Return true iff we have an object named sha1, whether local or in
   * an alternate object database, and whether packed or loose.  This
   * function does not respect replace references.
 + *
 + * If the QUICK flag is set, do not re-check the pack directory
 + * when we cannot find the object (this means we may give a false
 + * negative answer if another process is simultaneously repacking).
   */
 -extern int has_sha1_file(const unsigned char *sha1);
 +#define HAS_SHA1_QUICK 0x1
 +extern int has_sha1_file_with_flags(const unsigned char *sha1, int flags);
 +static inline int has_sha1_file(const unsigned char *sha1)
 +{
 +      return has_sha1_file_with_flags(sha1, 0);
 +}
 +
 +/* Same as the above, except for struct object_id. */
 +extern int has_object_file(const struct object_id *oid);
  
  /*
   * Return true iff an alternate object database has a loose object
@@@ -1078,21 -923,15 +1079,21 @@@ struct object_context 
        unsigned char tree[20];
        char path[PATH_MAX];
        unsigned mode;
 +      /*
 +       * symlink_path is only used by get_tree_entry_follow_symlinks,
 +       * and only for symlinks that point outside the repository.
 +       */
 +      struct strbuf symlink_path;
  };
  
 -#define GET_SHA1_QUIETLY        01
 -#define GET_SHA1_COMMIT         02
 -#define GET_SHA1_COMMITTISH     04
 -#define GET_SHA1_TREE          010
 -#define GET_SHA1_TREEISH       020
 -#define GET_SHA1_BLOB        040
 -#define GET_SHA1_ONLY_TO_DIE 04000
 +#define GET_SHA1_QUIETLY           01
 +#define GET_SHA1_COMMIT            02
 +#define GET_SHA1_COMMITTISH        04
 +#define GET_SHA1_TREE             010
 +#define GET_SHA1_TREEISH          020
 +#define GET_SHA1_BLOB             040
 +#define GET_SHA1_FOLLOW_SYMLINKS 0100
 +#define GET_SHA1_ONLY_TO_DIE    04000
  
  extern int get_sha1(const char *str, unsigned char *sha1);
  extern int get_sha1_commit(const char *str, unsigned char *sha1);
@@@ -1114,26 -953,78 +1115,26 @@@ extern int for_each_abbrev(const char *
   * null-terminated string.
   */
  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_full(const char *refname, int resolve_flags,
 -                       unsigned char *sha1, int *flags);
 -extern int read_ref(const char *refname, unsigned char *sha1);
 +extern int get_oid_hex(const char *hex, struct object_id *sha1);
  
  /*
 - * Resolve a reference, recursively following symbolic refererences.
 - *
 - * Store the referred-to object's name in sha1 and return the name of
 - * the non-symbolic reference that ultimately pointed at it.  The
 - * return value, if not NULL, is a pointer into either a static buffer
 - * or the input ref.
 - *
 - * If the reference cannot be resolved to an object, the behavior
 - * depends on the RESOLVE_REF_READING flag:
 - *
 - * - If RESOLVE_REF_READING is set, return NULL.
 + * Convert a binary sha1 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
 + * convenience.
   *
 - * - If RESOLVE_REF_READING is not set, clear sha1 and return the name of
 - *   the last reference name in the chain, which will either be a non-symbolic
 - *   reference or an undefined reference.  If this is a prelude to
 - *   "writing" to the ref, the return value is the name of the ref
 - *   that will actually be created or changed.
 + * The non-`_r` variant returns a static buffer, but uses a ring of 4
 + * buffers, making it safe to make multiple calls for a single statement, like:
   *
 - * If the RESOLVE_REF_NO_RECURSE flag is passed, only resolves one
 - * level of symbolic reference.  The value stored in sha1 for a symbolic
 - * reference will always be null_sha1 in this case, and the return
 - * value is the reference that the symref refers to directly.
 - *
 - * If flags is non-NULL, set the value that it points to the
 - * combination of REF_ISPACKED (if the reference was found among the
 - * packed references), REF_ISSYMREF (if the initial reference was a
 - * symbolic reference), REF_BAD_NAME (if the reference name is ill
 - * formed --- see RESOLVE_REF_ALLOW_BAD_NAME below), and REF_ISBROKEN
 - * (if the ref is malformed or has a bad name). See refs.h for more detail
 - * on each flag.
 - *
 - * If ref is not a properly-formatted, normalized reference, return
 - * NULL.  If more than MAXDEPTH recursive symbolic lookups are needed,
 - * give up and return NULL.
 - *
 - * RESOLVE_REF_ALLOW_BAD_NAME allows resolving refs even when their
 - * name is invalid according to git-check-ref-format(1).  If the name
 - * is bad then the value stored in sha1 will be null_sha1 and the two
 - * flags REF_ISBROKEN and REF_BAD_NAME will be set.
 - *
 - * Even with RESOLVE_REF_ALLOW_BAD_NAME, names that escape the refs/
 - * directory and do not consist of all caps and underscores cannot be
 - * resolved. The function returns NULL for such ref names.
 - * Caps and underscores refers to the special refs, such as HEAD,
 - * FETCH_HEAD and friends, that all live outside of the refs/ directory.
 + *   printf("%s -> %s", sha1_to_hex(one), sha1_to_hex(two));
   */
 -#define RESOLVE_REF_READING 0x01
 -#define RESOLVE_REF_NO_RECURSE 0x02
 -#define RESOLVE_REF_ALLOW_BAD_NAME 0x04
 -extern const char *resolve_ref_unsafe(const char *ref, int resolve_flags, unsigned char *sha1, int *flags);
 -extern char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags);
 -
 -extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
 -extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
 +extern char *sha1_to_hex_r(char *out, const unsigned char *sha1);
 +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 */
 +
  extern int interpret_branch_name(const char *str, int len, struct strbuf *);
  extern int get_sha1_mb(const char *str, unsigned char *sha1);
  
 -/*
 - * Return true iff abbrev_name is a possible abbreviation for
 - * full_name according to the rules defined by ref_rev_parse_rules in
 - * refs.c.
 - */
 -extern int refname_match(const char *abbrev_name, const char *full_name);
 -
 -extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
  extern int validate_headref(const char *ref);
  
  extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
@@@ -1149,30 -1040,18 +1150,30 @@@ extern void *read_object_with_reference
  extern struct object *peel_to_type(const char *name, int namelen,
                                   struct object *o, enum object_type);
  
 -enum date_mode {
 -      DATE_NORMAL = 0,
 -      DATE_RELATIVE,
 -      DATE_SHORT,
 -      DATE_LOCAL,
 -      DATE_ISO8601,
 -      DATE_ISO8601_STRICT,
 -      DATE_RFC2822,
 -      DATE_RAW
 +struct date_mode {
 +      enum date_mode_type {
 +              DATE_NORMAL = 0,
 +              DATE_RELATIVE,
 +              DATE_SHORT,
 +              DATE_ISO8601,
 +              DATE_ISO8601_STRICT,
 +              DATE_RFC2822,
 +              DATE_STRFTIME,
 +              DATE_RAW
 +      } type;
 +      const char *strftime_fmt;
 +      int local;
  };
  
 -const char *show_date(unsigned long time, int timezone, enum date_mode mode);
 +/*
 + * Convenience helper for passing a constant type, like:
 + *
 + *   show_date(t, tz, DATE_MODE(NORMAL));
 + */
 +#define DATE_MODE(t) date_mode_from_type(DATE_##t)
 +struct date_mode *date_mode_from_type(enum date_mode_type type);
 +
 +const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);
  void show_date_relative(unsigned long time, int tz, const struct timeval *now,
                        struct strbuf *timebuf);
  int parse_date(const char *date, struct strbuf *out);
@@@ -1182,7 -1061,7 +1183,7 @@@ void datestamp(struct strbuf *out)
  #define approxidate(s) approxidate_careful((s), NULL)
  unsigned long approxidate_careful(const char *, int *);
  unsigned long approxidate_relative(const char *date, const struct timeval *now);
 -enum date_mode parse_date_format(const char *format);
 +void parse_date_format(const char *format, struct date_mode *mode);
  int date_overflows(unsigned long date);
  
  #define IDENT_STRICT         1
@@@ -1219,8 -1098,7 +1220,8 @@@ extern int split_ident_line(struct iden
   * the ident_split. It will also sanity-check the values and produce
   * a well-known sentinel date if they appear bogus.
   */
 -const char *show_ident_date(const struct ident_split *id, enum date_mode mode);
 +const char *show_ident_date(const struct ident_split *id,
 +                          const struct date_mode *mode);
  
  /*
   * Compare split idents for equality or strict ordering. Note that we
@@@ -1297,10 -1175,8 +1298,10 @@@ extern struct packed_git 
        int pack_fd;
        unsigned pack_local:1,
                 pack_keep:1,
 +               freshened:1,
                 do_not_close:1;
        unsigned char sha1[20];
 +      struct revindex_entry *revindex;
        /* something like ".git/objects/pack/xxxxx.pack" */
        char pack_name[FLEX_ARRAY]; /* more */
  } *packed_git;
@@@ -1313,11 -1189,8 +1314,11 @@@ struct pack_entry 
  
  extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
  
 -/* A hook for count-objects to report invalid files in pack directory */
 -extern void (*report_garbage)(const char *desc, const char *path);
 +/* A hook to report invalid files in pack directory */
 +#define PACKDIR_FILE_PACK 1
 +#define PACKDIR_FILE_IDX 2
 +#define PACKDIR_FILE_GARBAGE 4
 +extern void (*report_garbage)(unsigned seen_bits, const char *path);
  
  extern void prepare_packed_git(void);
  extern void reprepare_packed_git(void);
@@@ -1342,11 -1215,10 +1343,11 @@@ extern void close_pack_index(struct pac
  
  extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *);
  extern void close_pack_windows(struct packed_git *);
 +extern void close_all_packs(void);
  extern void unuse_pack(struct pack_window **);
  extern void free_pack_by_name(const char *);
  extern void clear_delta_base_cache(void);
 -extern struct packed_git *add_packed_git(const char *, int, int);
 +extern struct packed_git *add_packed_git(const char *path, size_t path_len, int local);
  
  /*
   * Return the SHA-1 of the nth object within the specified packfile.
@@@ -1418,16 -1290,14 +1419,16 @@@ int for_each_loose_file_in_objdir_buf(s
  
  /*
   * Iterate over loose and packed objects in both the local
 - * repository and any alternates repositories.
 + * repository and any alternates repositories (unless the
 + * LOCAL_ONLY flag is set).
   */
 +#define FOR_EACH_OBJECT_LOCAL_ONLY 0x1
  typedef int each_packed_object_fn(const unsigned char *sha1,
                                  struct packed_git *pack,
                                  uint32_t pos,
                                  void *data);
 -extern int for_each_loose_object(each_loose_object_fn, void *);
 -extern int for_each_packed_object(each_packed_object_fn, void *);
 +extern int for_each_loose_object(each_loose_object_fn, void *, unsigned flags);
 +extern int for_each_packed_object(each_packed_object_fn, void *, unsigned flags);
  
  struct object_info {
        /* Request */
        unsigned long *sizep;
        unsigned long *disk_sizep;
        unsigned char *delta_base_sha1;
 +      struct strbuf *typename;
  
        /* Response */
        enum {
@@@ -1497,7 -1366,6 +1498,7 @@@ extern int git_config_with_options(conf
                                   int respect_includes);
  extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
  extern int git_parse_ulong(const char *, unsigned long *);
 +extern int git_parse_maybe_bool(const char *);
  extern int git_config_int(const char *, const char *);
  extern int64_t git_config_int64(const char *, const char *);
  extern unsigned long git_config_ulong(const char *, const char *);
@@@ -1509,7 -1377,6 +1510,7 @@@ extern int git_config_pathname(const ch
  extern int git_config_set_in_file(const char *, const char *, const char *);
  extern int git_config_set(const char *, const char *);
  extern int git_config_parse_key(const char *, char **, int *);
 +extern int git_config_key_is_valid(const char *key);
  extern int git_config_set_multivar(const char *, const char *, const char *, int);
  extern int git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
  extern int git_config_rename_section(const char *, const char *);
@@@ -1626,13 -1493,9 +1627,13 @@@ extern const char *git_mailmap_blob
  extern void maybe_flush_or_die(FILE *, const char *);
  __attribute__((format (printf, 2, 3)))
  extern void fprintf_or_die(FILE *, const char *fmt, ...);
 +
 +#define COPY_READ_ERROR (-2)
 +#define COPY_WRITE_ERROR (-3)
  extern int copy_fd(int ifd, int ofd);
  extern int copy_file(const char *dst, const char *src, int mode);
  extern int copy_file_with_time(const char *dst, const char *src, int mode);
 +
  extern void write_or_die(int fd, const void *buf, size_t count);
  extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
  extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
@@@ -1647,9 -1510,6 +1648,9 @@@ static inline ssize_t write_str_in_full
        return write_in_full(fd, str, strlen(str));
  }
  
 +extern int write_file(const char *path, const char *fmt, ...);
 +extern int write_file_gently(const char *path, const char *fmt, ...);
 +
  /* pager.c */
  extern void setup_pager(void);
  extern const char *pager_program;
@@@ -1772,14 -1632,5 +1773,14 @@@ int stat_validity_check(struct stat_val
  void stat_validity_update(struct stat_validity *sv, int fd);
  
  int versioncmp(const char *s1, const char *s2);
 +void sleep_millisec(int millisec);
 +
 +/*
 + * Create a directory and (if share is nonzero) adjust its permissions
 + * according to the shared_repository setting. Only use this for
 + * directories under $GIT_DIR.  Don't use it for working tree
 + * directories.
 + */
 +void safe_create_dir(const char *dir, int share);
  
  #endif /* CACHE_H */
diff --combined read-cache.c
index 84616c8e219bf3cf902643a8da62a2060d335c36,fb80c47e3820009a0c40797cf33892177afdf153..5be7cd1dbf50c850ee5e02dcfde69d7611c181b5
@@@ -5,7 -5,6 +5,7 @@@
   */
  #define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
 +#include "tempfile.h"
  #include "lockfile.h"
  #include "cache-tree.h"
  #include "refs.h"
@@@ -17,6 -16,7 +17,6 @@@
  #include "strbuf.h"
  #include "varint.h"
  #include "split-index.h"
 -#include "sigchain.h"
  #include "utf8.h"
  
  static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
  #define CACHE_EXT_TREE 0x54524545     /* "TREE" */
  #define CACHE_EXT_RESOLVE_UNDO 0x52455543 /* "REUC" */
  #define CACHE_EXT_LINK 0x6c696e6b       /* "link" */
 +#define CACHE_EXT_UNTRACKED 0x554E5452          /* "UNTR" */
  
  /* changes that can be kept in $GIT_DIR/index (basically all extensions) */
  #define EXTMASK (RESOLVE_UNDO_CHANGED | CACHE_TREE_CHANGED | \
                 CE_ENTRY_ADDED | CE_ENTRY_REMOVED | CE_ENTRY_CHANGED | \
 -               SPLIT_INDEX_ORDERED)
 +               SPLIT_INDEX_ORDERED | UNTRACKED_CHANGED)
  
  struct index_state the_index;
  static const char *alternate_index_output;
@@@ -80,7 -79,6 +80,7 @@@ void rename_index_entry_at(struct index
        memcpy(new->name, new_name, namelen + 1);
  
        cache_tree_invalidate_path(istate, old->name);
 +      untracked_cache_remove_from_index(istate, old->name);
        remove_index_entry_at(istate, nr);
        add_index_entry(istate, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
  }
@@@ -272,34 -270,20 +272,34 @@@ static int ce_match_stat_basic(const st
        return changed;
  }
  
 -static int is_racy_timestamp(const struct index_state *istate,
 -                           const struct cache_entry *ce)
 +static int is_racy_stat(const struct index_state *istate,
 +                      const struct stat_data *sd)
  {
 -      return (!S_ISGITLINK(ce->ce_mode) &&
 -              istate->timestamp.sec &&
 +      return (istate->timestamp.sec &&
  #ifdef USE_NSEC
                 /* nanosecond timestamped files can also be racy! */
 -              (istate->timestamp.sec < ce->ce_stat_data.sd_mtime.sec ||
 -               (istate->timestamp.sec == ce->ce_stat_data.sd_mtime.sec &&
 -                istate->timestamp.nsec <= ce->ce_stat_data.sd_mtime.nsec))
 +              (istate->timestamp.sec < sd->sd_mtime.sec ||
 +               (istate->timestamp.sec == sd->sd_mtime.sec &&
 +                istate->timestamp.nsec <= sd->sd_mtime.nsec))
  #else
 -              istate->timestamp.sec <= ce->ce_stat_data.sd_mtime.sec
 +              istate->timestamp.sec <= sd->sd_mtime.sec
  #endif
 -               );
 +              );
 +}
 +
 +static int is_racy_timestamp(const struct index_state *istate,
 +                           const struct cache_entry *ce)
 +{
 +      return (!S_ISGITLINK(ce->ce_mode) &&
 +              is_racy_stat(istate, &ce->ce_stat_data));
 +}
 +
 +int match_stat_data_racy(const struct index_state *istate,
 +                       const struct stat_data *sd, struct stat *st)
 +{
 +      if (is_racy_stat(istate, sd))
 +              return MTIME_CHANGED;
 +      return match_stat_data(sd, st);
  }
  
  int ie_match_stat(const struct index_state *istate,
         * by definition never matches what is in the work tree until it
         * actually gets added.
         */
-       if (ce->ce_flags & CE_INTENT_TO_ADD)
+       if (ce_intent_to_add(ce))
                return DATA_CHANGED | TYPE_CHANGED | MODE_CHANGED;
  
        changed = ce_match_stat_basic(ce, st);
@@@ -554,7 -538,6 +554,7 @@@ int remove_file_from_index(struct index
        if (pos < 0)
                pos = -pos-1;
        cache_tree_invalidate_path(istate, path);
 +      untracked_cache_remove_from_index(istate, path);
        while (pos < istate->cache_nr && !strcmp(istate->cache[pos]->name, path))
                remove_index_entry_at(istate, pos);
        return 0;
@@@ -678,7 -661,21 +678,7 @@@ int add_to_index(struct index_state *is
         * entry's directory case.
         */
        if (ignore_case) {
 -              const char *startPtr = ce->name;
 -              const char *ptr = startPtr;
 -              while (*ptr) {
 -                      while (*ptr && *ptr != '/')
 -                              ++ptr;
 -                      if (*ptr == '/') {
 -                              struct cache_entry *foundce;
 -                              ++ptr;
 -                              foundce = index_dir_exists(istate, ce->name, ptr - ce->name - 1);
 -                              if (foundce) {
 -                                      memcpy((void *)startPtr, foundce->name + (startPtr - ce->name), ptr - startPtr);
 -                                      startPtr = ptr;
 -                              }
 -                      }
 -              }
 +              adjust_dirname_case(istate, ce->name);
        }
  
        alias = index_file_exists(istate, ce->name, ce_namelen(ce), ignore_case);
@@@ -985,9 -982,6 +985,9 @@@ static int add_index_entry_with_check(s
        }
        pos = -pos-1;
  
 +      if (!(option & ADD_CACHE_KEEP_CACHE_TREE))
 +              untracked_cache_add_to_index(istate, ce->name);
 +
        /*
         * Inserting a merged entry ("stage 0") into the index
         * will always replace all non-merged entries..
@@@ -1237,7 -1231,7 +1237,7 @@@ int refresh_index(struct index_state *i
  
                        if (cache_errno == ENOENT)
                                fmt = deleted_fmt;
-                       else if (ce->ce_flags & CE_INTENT_TO_ADD)
+                       else if (ce_intent_to_add(ce))
                                fmt = added_fmt; /* must be before other checks */
                        else if (changed & TYPE_CHANGED)
                                fmt = typechange_fmt;
@@@ -1378,9 -1372,6 +1378,9 @@@ static int read_index_extension(struct 
                if (read_link_extension(istate, data, sz))
                        return -1;
                break;
 +      case CACHE_EXT_UNTRACKED:
 +              istate->untracked = read_untracked_extension(data, sz);
 +              break;
        default:
                if (*ext < 'A' || 'Z' < *ext)
                        return error("index uses %.4s extension, which we do not understand",
@@@ -1549,7 -1540,7 +1549,7 @@@ int do_read_index(struct index_state *i
        if (mmap_size < sizeof(struct cache_header) + 20)
                die("index file smaller than expected");
  
 -      mmap = xmmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
 +      mmap = xmmap(NULL, mmap_size, PROT_READ, MAP_PRIVATE, fd, 0);
        if (mmap == MAP_FAILED)
                die_errno("unable to map index file");
        close(fd);
@@@ -1639,7 -1630,7 +1639,7 @@@ int read_index_from(struct index_state 
                die("broken index, expect %s in %s, got %s",
                    sha1_to_hex(split_index->base_sha1),
                    git_path("sharedindex.%s",
 -                                   sha1_to_hex(split_index->base_sha1)),
 +                           sha1_to_hex(split_index->base_sha1)),
                    sha1_to_hex(split_index->base->sha1));
        merge_base_index(istate);
        check_ce_order(istate);
@@@ -1676,8 -1667,6 +1676,8 @@@ int discard_index(struct index_state *i
        istate->cache = NULL;
        istate->cache_alloc = 0;
        discard_split_index(istate);
 +      free_untracked_cache(istate->untracked);
 +      istate->untracked = NULL;
        return 0;
  }
  
@@@ -2064,17 -2053,6 +2064,17 @@@ static int do_write_index(struct index_
                if (err)
                        return -1;
        }
 +      if (!strip_extensions && istate->untracked) {
 +              struct strbuf sb = STRBUF_INIT;
 +
 +              write_untracked_extension(&sb, istate->untracked);
 +              err = write_index_ext_header(&c, newfd, CACHE_EXT_UNTRACKED,
 +                                           sb.len) < 0 ||
 +                      ce_write(&c, newfd, sb.buf, sb.len) < 0;
 +              strbuf_release(&sb);
 +              if (err)
 +                      return -1;
 +      }
  
        if (ce_flush(&c, newfd, istate->sha1) || fstat(newfd, &st))
                return -1;
@@@ -2099,7 -2077,7 +2099,7 @@@ static int commit_locked_index(struct l
  static int do_write_locked_index(struct index_state *istate, struct lock_file *lock,
                                 unsigned flags)
  {
 -      int ret = do_write_index(istate, lock->fd, 0);
 +      int ret = do_write_index(istate, get_lock_file_fd(lock), 0);
        if (ret)
                return ret;
        assert((flags & (COMMIT_LOCK | CLOSE_LOCK)) !=
@@@ -2123,27 -2101,54 +2123,27 @@@ static int write_split_index(struct ind
        return ret;
  }
  
 -static char *temporary_sharedindex;
 -
 -static void remove_temporary_sharedindex(void)
 -{
 -      if (temporary_sharedindex) {
 -              unlink_or_warn(temporary_sharedindex);
 -              free(temporary_sharedindex);
 -              temporary_sharedindex = NULL;
 -      }
 -}
 -
 -static void remove_temporary_sharedindex_on_signal(int signo)
 -{
 -      remove_temporary_sharedindex();
 -      sigchain_pop(signo);
 -      raise(signo);
 -}
 +static struct tempfile temporary_sharedindex;
  
  static int write_shared_index(struct index_state *istate,
                              struct lock_file *lock, unsigned flags)
  {
        struct split_index *si = istate->split_index;
 -      static int installed_handler;
        int fd, ret;
  
 -      temporary_sharedindex = git_pathdup("sharedindex_XXXXXX");
 -      fd = mkstemp(temporary_sharedindex);
 +      fd = mks_tempfile(&temporary_sharedindex, git_path("sharedindex_XXXXXX"));
        if (fd < 0) {
 -              free(temporary_sharedindex);
 -              temporary_sharedindex = NULL;
                hashclr(si->base_sha1);
                return do_write_locked_index(istate, lock, flags);
        }
 -      if (!installed_handler) {
 -              atexit(remove_temporary_sharedindex);
 -              sigchain_push_common(remove_temporary_sharedindex_on_signal);
 -      }
        move_cache_to_base_index(istate);
        ret = do_write_index(si->base, fd, 1);
 -      close(fd);
        if (ret) {
 -              remove_temporary_sharedindex();
 +              delete_tempfile(&temporary_sharedindex);
                return ret;
        }
 -      ret = rename(temporary_sharedindex,
 -                   git_path("sharedindex.%s", sha1_to_hex(si->base->sha1)));
 -      free(temporary_sharedindex);
 -      temporary_sharedindex = NULL;
 +      ret = rename_tempfile(&temporary_sharedindex,
 +                            git_path("sharedindex.%s", sha1_to_hex(si->base->sha1)));
        if (!ret)
                hashcpy(si->base_sha1, si->base->sha1);
        return ret;