Merge branch 'master' into ph/strbuf
authorJunio C Hamano <gitster@pobox.com>
Wed, 19 Sep 2007 00:42:15 +0000 (17:42 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 19 Sep 2007 00:42:15 +0000 (17:42 -0700)
* master: (94 commits)
Fixed update-hook example allow-users format.
Documentation/git-svn: updated design philosophy notes
t/t4014: test "am -3" with mode-only change.
git-commit.sh: Shell script cleanup
preserve executable bits in zip archives
Fix lapsus in builtin-apply.c
git-push: documentation and tests for pushing only branches
git-svnimport: Use separate arguments in the pipe for git-rev-parse
contrib/fast-import: add perl version of simple example
contrib/fast-import: add simple shell example
rev-list --bisect: Bisection "distance" clean up.
rev-list --bisect: Move some bisection code into best_bisection.
rev-list --bisect: Move finding bisection into do_find_bisection.
Document ls-files --with-tree=<tree-ish>
git-commit: partial commit of paths only removed from the index
git-commit: Allow partial commit of file removal.
send-email: make message-id generation a bit more robust
git-apply: fix whitespace stripping
git-gui: Disable native platform text selection in "lists"
apply --index-info: fall back to current index for mode changes
...

1  2 
builtin-apply.c
builtin-log.c
builtin-rev-list.c
builtin-update-index.c
cache.h
diff.c
diff --combined builtin-apply.c
index 61b51315edb040b19e7e17314c66780bab1be346,86d89a4a7e9240a75e1500bba524acdcec7f14d2..f953c5b768480e87aeb98d90d73c81167a937505
@@@ -181,21 -181,34 +181,21 @@@ static void say_patch_name(FILE *output
  
  static void *read_patch_file(int fd, unsigned long *sizep)
  {
 -      unsigned long size = 0, alloc = CHUNKSIZE;
 -      void *buffer = xmalloc(alloc);
 +      struct strbuf buf;
  
 -      for (;;) {
 -              ssize_t nr = alloc - size;
 -              if (nr < 1024) {
 -                      alloc += CHUNKSIZE;
 -                      buffer = xrealloc(buffer, alloc);
 -                      nr = alloc - size;
 -              }
 -              nr = xread(fd, (char *) buffer + size, nr);
 -              if (!nr)
 -                      break;
 -              if (nr < 0)
 -                      die("git-apply: read returned %s", strerror(errno));
 -              size += nr;
 -      }
 -      *sizep = size;
 +      strbuf_init(&buf, 0);
 +      if (strbuf_read(&buf, fd, 0) < 0)
 +              die("git-apply: read returned %s", strerror(errno));
 +      *sizep = buf.len;
  
        /*
         * Make sure that we have some slop in the buffer
         * so that we can do speculative "memcmp" etc, and
         * see to it that it is NUL-filled.
         */
 -      if (alloc < size + SLOP)
 -              buffer = xrealloc(buffer, size + SLOP);
 -      memset((char *) buffer + size, 0, SLOP);
 -      return buffer;
 +      strbuf_grow(&buf, SLOP);
 +      memset(buf.buf + buf.len, 0, SLOP);
 +      return strbuf_detach(&buf);
  }
  
  static unsigned long linelen(const char *buffer, unsigned long size)
@@@ -241,7 -254,7 +241,7 @@@ static char *find_name(const char *line
                if (name) {
                        char *cp = name;
                        while (p_value) {
-                               cp = strchr(name, '/');
+                               cp = strchr(cp, '/');
                                if (!cp)
                                        break;
                                cp++;
@@@ -1441,28 -1454,39 +1441,28 @@@ static void show_stats(struct patch *pa
        free(qname);
  }
  
 -static int read_old_data(struct stat *st, const char *path, char **buf_p, unsigned long *alloc_p, unsigned long *size_p)
 +static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
  {
        int fd;
 -      unsigned long got;
 -      unsigned long nsize;
 -      char *nbuf;
 -      unsigned long size = *size_p;
 -      char *buf = *buf_p;
  
        switch (st->st_mode & S_IFMT) {
        case S_IFLNK:
 -              return readlink(path, buf, size) != size;
 +              strbuf_grow(buf, st->st_size);
 +              if (readlink(path, buf->buf, st->st_size) != st->st_size)
 +                      return -1;
 +              strbuf_setlen(buf, st->st_size);
 +              return 0;
        case S_IFREG:
                fd = open(path, O_RDONLY);
                if (fd < 0)
                        return error("unable to open %s", path);
 -              got = 0;
 -              for (;;) {
 -                      ssize_t ret = xread(fd, buf + got, size - got);
 -                      if (ret <= 0)
 -                              break;
 -                      got += ret;
 +              if (strbuf_read(buf, fd, st->st_size) < 0) {
 +                      close(fd);
 +                      return -1;
                }
                close(fd);
 -              nsize = got;
 -              nbuf = convert_to_git(path, buf, &nsize);
 -              if (nbuf) {
 -                      free(buf);
 -                      *buf_p = nbuf;
 -                      *alloc_p = nsize;
 -                      *size_p = nsize;
 -              }
 -              return got != size;
 +              convert_to_git(path, buf->buf, buf->len, buf);
 +              return 0;
        default:
                return -1;
        }
@@@ -1567,6 -1591,12 +1567,6 @@@ static void remove_last_line(const cha
        *rsize = offset + 1;
  }
  
 -struct buffer_desc {
 -      char *buffer;
 -      unsigned long size;
 -      unsigned long alloc;
 -};
 -
  static int apply_line(char *output, const char *patch, int plen)
  {
        /* plen is number of bytes to be copied from patch,
  
        buf = output;
        if (need_fix_leading_space) {
+               int consecutive_spaces = 0;
                /* between patch[1..last_tab_in_indent] strip the
                 * funny spaces, updating them to tab as needed.
                 */
                for (i = 1; i < last_tab_in_indent; i++, plen--) {
                        char ch = patch[i];
-                       if (ch != ' ')
+                       if (ch != ' ') {
+                               consecutive_spaces = 0;
                                *output++ = ch;
-                       else if ((i % 8) == 0)
-                               *output++ = '\t';
+                       } else {
+                               consecutive_spaces++;
+                               if (consecutive_spaces == 8) {
+                                       *output++ = '\t';
+                                       consecutive_spaces = 0;
+                               }
+                       }
                }
                fixed = 1;
                i = last_tab_in_indent;
        return output + plen - buf;
  }
  
 -static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, int inaccurate_eof)
 +static int apply_one_fragment(struct strbuf *buf, struct fragment *frag, int inaccurate_eof)
  {
        int match_beginning, match_end;
 -      char *buf = desc->buffer;
        const char *patch = frag->patch;
        int offset, size = frag->size;
        char *old = xmalloc(size);
        lines = 0;
        pos = frag->newpos;
        for (;;) {
 -              offset = find_offset(buf, desc->size,
 +              offset = find_offset(buf->buf, buf->len,
                                     oldlines, oldsize, pos, &lines);
 -              if (match_end && offset + oldsize != desc->size)
 +              if (match_end && offset + oldsize != buf->len)
                        offset = -1;
                if (match_beginning && offset)
                        offset = -1;
                if (offset >= 0) {
 -                      int diff;
 -                      unsigned long size, alloc;
 -
                        if (new_whitespace == strip_whitespace &&
 -                          (desc->size - oldsize - offset == 0)) /* end of file? */
 +                          (buf->len - oldsize - offset == 0)) /* end of file? */
                                newsize -= new_blank_lines_at_end;
  
 -                      diff = newsize - oldsize;
 -                      size = desc->size + diff;
 -                      alloc = desc->alloc;
 -
                        /* Warn if it was necessary to reduce the number
                         * of context lines.
                         */
                                        " to apply fragment at %d\n",
                                        leading, trailing, pos + lines);
  
 -                      if (size > alloc) {
 -                              alloc = size + 8192;
 -                              desc->alloc = alloc;
 -                              buf = xrealloc(buf, alloc);
 -                              desc->buffer = buf;
 -                      }
 -                      desc->size = size;
 -                      memmove(buf + offset + newsize,
 -                              buf + offset + oldsize,
 -                              size - offset - newsize);
 -                      memcpy(buf + offset, newlines, newsize);
 +                      strbuf_splice(buf, offset, oldsize, newlines, newsize);
                        offset = 0;
 -
                        break;
                }
  
        return offset;
  }
  
 -static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch)
 +static int apply_binary_fragment(struct strbuf *buf, struct patch *patch)
  {
 -      unsigned long dst_size;
        struct fragment *fragment = patch->fragments;
 -      void *data;
 -      void *result;
 +      unsigned long len;
 +      void *dst;
  
        /* Binary patch is irreversible without the optional second hunk */
        if (apply_in_reverse) {
                                     ? patch->new_name : patch->old_name);
                fragment = fragment->next;
        }
 -      data = (void*) fragment->patch;
        switch (fragment->binary_patch_method) {
        case BINARY_DELTA_DEFLATED:
 -              result = patch_delta(desc->buffer, desc->size,
 -                                   data,
 -                                   fragment->size,
 -                                   &dst_size);
 -              free(desc->buffer);
 -              desc->buffer = result;
 -              break;
 +              dst = patch_delta(buf->buf, buf->len, fragment->patch,
 +                                fragment->size, &len);
 +              if (!dst)
 +                      return -1;
 +              /* XXX patch_delta NUL-terminates */
 +              strbuf_attach(buf, dst, len, len + 1);
 +              return 0;
        case BINARY_LITERAL_DEFLATED:
 -              free(desc->buffer);
 -              desc->buffer = data;
 -              dst_size = fragment->size;
 -              break;
 +              strbuf_reset(buf);
 +              strbuf_add(buf, fragment->patch, fragment->size);
 +              return 0;
        }
 -      if (!desc->buffer)
 -              return -1;
 -      desc->size = desc->alloc = dst_size;
 -      return 0;
 +      return -1;
  }
  
 -static int apply_binary(struct buffer_desc *desc, struct patch *patch)
 +static int apply_binary(struct strbuf *buf, struct patch *patch)
  {
        const char *name = patch->old_name ? patch->old_name : patch->new_name;
        unsigned char sha1[20];
                /* See if the old one matches what the patch
                 * applies to.
                 */
 -              hash_sha1_file(desc->buffer, desc->size, blob_type, sha1);
 +              hash_sha1_file(buf->buf, buf->len, blob_type, sha1);
                if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
                        return error("the patch applies to '%s' (%s), "
                                     "which does not match the "
        }
        else {
                /* Otherwise, the old one must be empty. */
 -              if (desc->size)
 +              if (buf->len)
                        return error("the patch applies to an empty "
                                     "'%s' but it is not empty", name);
        }
  
        get_sha1_hex(patch->new_sha1_prefix, sha1);
        if (is_null_sha1(sha1)) {
 -              free(desc->buffer);
 -              desc->alloc = desc->size = 0;
 -              desc->buffer = NULL;
 +              strbuf_release(buf);
                return 0; /* deletion patch */
        }
  
                /* We already have the postimage */
                enum object_type type;
                unsigned long size;
 +              char *result;
  
 -              free(desc->buffer);
 -              desc->buffer = read_sha1_file(sha1, &type, &size);
 -              if (!desc->buffer)
 +              result = read_sha1_file(sha1, &type, &size);
 +              if (!result)
                        return error("the necessary postimage %s for "
                                     "'%s' cannot be read",
                                     patch->new_sha1_prefix, name);
 -              desc->alloc = desc->size = size;
 -      }
 -      else {
 -              /* We have verified desc matches the preimage;
 +              /* XXX read_sha1_file NUL-terminates */
 +              strbuf_attach(buf, result, size, size + 1);
 +      else {
 +              /* We have verified buf matches the preimage;
                 * apply the patch data to it, which is stored
                 * in the patch->fragments->{patch,size}.
                 */
 -              if (apply_binary_fragment(desc, patch))
 +              if (apply_binary_fragment(buf, patch))
                        return error("binary patch does not apply to '%s'",
                                     name);
  
                /* verify that the result matches */
 -              hash_sha1_file(desc->buffer, desc->size, blob_type, sha1);
 +              hash_sha1_file(buf->buf, buf->len, blob_type, sha1);
                if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix))
 -                      return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)", name, patch->new_sha1_prefix, sha1_to_hex(sha1));
 +                      return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)",
 +                              name, patch->new_sha1_prefix, sha1_to_hex(sha1));
        }
  
        return 0;
  }
  
 -static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
 +static int apply_fragments(struct strbuf *buf, struct patch *patch)
  {
        struct fragment *frag = patch->fragments;
        const char *name = patch->old_name ? patch->old_name : patch->new_name;
  
        if (patch->is_binary)
 -              return apply_binary(desc, patch);
 +              return apply_binary(buf, patch);
  
        while (frag) {
 -              if (apply_one_fragment(desc, frag, patch->inaccurate_eof)) {
 +              if (apply_one_fragment(buf, frag, patch->inaccurate_eof)) {
                        error("patch failed: %s:%ld", name, frag->oldpos);
                        if (!apply_with_reject)
                                return -1;
        return 0;
  }
  
 -static int read_file_or_gitlink(struct cache_entry *ce, char **buf_p,
 -                              unsigned long *size_p)
 +static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
  {
        if (!ce)
                return 0;
  
        if (S_ISGITLINK(ntohl(ce->ce_mode))) {
 -              *buf_p = xmalloc(100);
 -              *size_p = snprintf(*buf_p, 100,
 -                      "Subproject commit %s\n", sha1_to_hex(ce->sha1));
 +              strbuf_grow(buf, 100);
 +              strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1));
        } else {
                enum object_type type;
 -              *buf_p = read_sha1_file(ce->sha1, &type, size_p);
 -              if (!*buf_p)
 +              unsigned long sz;
 +              char *result;
 +
 +              result = read_sha1_file(ce->sha1, &type, &sz);
 +              if (!result)
                        return -1;
 +              /* XXX read_sha1_file NUL-terminates */
 +              strbuf_attach(buf, result, sz, sz + 1);
        }
        return 0;
  }
  
  static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
  {
 -      char *buf;
 -      unsigned long size, alloc;
 -      struct buffer_desc desc;
 +      struct strbuf buf;
  
 -      size = 0;
 -      alloc = 0;
 -      buf = NULL;
 +      strbuf_init(&buf, 0);
        if (cached) {
 -              if (read_file_or_gitlink(ce, &buf, &size))
 +              if (read_file_or_gitlink(ce, &buf))
                        return error("read of %s failed", patch->old_name);
 -              alloc = size;
        } else if (patch->old_name) {
                if (S_ISGITLINK(patch->old_mode)) {
 -                      if (ce)
 -                              read_file_or_gitlink(ce, &buf, &size);
 -                      else {
 +                      if (ce) {
 +                              read_file_or_gitlink(ce, &buf);
 +                      else {
                                /*
                                 * There is no way to apply subproject
                                 * patch without looking at the index.
                                 */
                                patch->fragments = NULL;
 -                              size = 0;
                        }
 -              }
 -              else {
 -                      size = xsize_t(st->st_size);
 -                      alloc = size + 8192;
 -                      buf = xmalloc(alloc);
 -                      if (read_old_data(st, patch->old_name,
 -                                        &buf, &alloc, &size))
 -                              return error("read of %s failed",
 -                                           patch->old_name);
 +              } else {
 +                      if (read_old_data(st, patch->old_name, &buf))
 +                              return error("read of %s failed", patch->old_name);
                }
        }
  
 -      desc.size = size;
 -      desc.alloc = alloc;
 -      desc.buffer = buf;
 -
 -      if (apply_fragments(&desc, patch) < 0)
 +      if (apply_fragments(&buf, patch) < 0)
                return -1; /* note with --reject this succeeds. */
 -
 -      /* NUL terminate the result */
 -      if (desc.alloc <= desc.size)
 -              desc.buffer = xrealloc(desc.buffer, desc.size + 1);
 -      desc.buffer[desc.size] = 0;
 -
 -      patch->result = desc.buffer;
 -      patch->resultsize = desc.size;
 +      patch->result = buf.buf;
 +      patch->resultsize = buf.len;
  
        if (0 < patch->is_delete && patch->resultsize)
                return error("removal patch leaves file contents");
@@@ -2152,6 -2234,20 +2159,20 @@@ static int check_patch_list(struct patc
        return err;
  }
  
+ /* This function tries to read the sha1 from the current index */
+ static int get_current_sha1(const char *path, unsigned char *sha1)
+ {
+       int pos;
+       if (read_cache() < 0)
+               return -1;
+       pos = cache_name_pos(path, strlen(path));
+       if (pos < 0)
+               return -1;
+       hashcpy(sha1, active_cache[pos]->sha1);
+       return 0;
+ }
  static void show_index_list(struct patch *list)
  {
        struct patch *patch;
                if (0 < patch->is_new)
                        sha1_ptr = null_sha1;
                else if (get_sha1(patch->old_sha1_prefix, sha1))
-                       die("sha1 information is lacking or useless (%s).",
-                           name);
+                       /* git diff has no index line for mode/type changes */
+                       if (!patch->lines_added && !patch->lines_deleted) {
+                               if (get_current_sha1(patch->new_name, sha1) ||
+                                   get_current_sha1(patch->old_name, sha1))
+                                       die("mode change for %s, which is not "
+                                               "in current HEAD", name);
+                               sha1_ptr = sha1;
+                       } else
+                               die("sha1 information is lacking or useless "
+                                       "(%s).", name);
                else
                        sha1_ptr = sha1;
  
@@@ -2319,7 -2423,6 +2348,6 @@@ static void remove_file(struct patch *p
        if (update_index) {
                if (remove_file_from_cache(patch->old_name) < 0)
                        die("unable to remove %s from index", patch->old_name);
-               cache_tree_invalidate_path(active_cache_tree, patch->old_name);
        }
        if (!cached) {
                if (S_ISGITLINK(patch->old_mode)) {
@@@ -2376,7 -2479,7 +2404,7 @@@ static void add_index_file(const char *
  static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
  {
        int fd;
 -      char *nbuf;
 +      struct strbuf nbuf;
  
        if (S_ISGITLINK(mode)) {
                struct stat st;
        if (fd < 0)
                return -1;
  
 -      nbuf = convert_to_working_tree(path, buf, &size);
 -      if (nbuf)
 -              buf = nbuf;
 -
 -      while (size) {
 -              int written = xwrite(fd, buf, size);
 -              if (written < 0)
 -                      die("writing file %s: %s", path, strerror(errno));
 -              if (!written)
 -                      die("out of space writing file %s", path);
 -              buf += written;
 -              size -= written;
 +      strbuf_init(&nbuf, 0);
 +      if (convert_to_working_tree(path, buf, size, &nbuf)) {
 +              size = nbuf.len;
 +              buf  = nbuf.buf;
        }
 +      write_or_die(fd, buf, size);
 +      strbuf_release(&nbuf);
 +
        if (close(fd) < 0)
                die("closing file %s: %s", path, strerror(errno));
 -      if (nbuf)
 -              free(nbuf);
        return 0;
  }
  
@@@ -2467,7 -2577,6 +2495,6 @@@ static void create_file(struct patch *p
                mode = S_IFREG | 0644;
        create_one_file(path, mode, buf, size);
        add_index_file(path, mode, buf, size);
-       cache_tree_invalidate_path(active_cache_tree, path);
  }
  
  /* phase zero is to remove, phase one is to create */
diff --combined builtin-log.c
index e1d3e7d74bcac3c684d63090265c956b1d579288,c6cc3aef5270fe64821146376354239d54de5a26..60819d15c52dc8cb13ac08ba23986e4be56279a4
@@@ -437,6 -437,34 +437,34 @@@ static void gen_message_id(char *dest, 
                 (int)(email_end - email_start - 1), email_start + 1);
  }
  
+ static const char *clean_message_id(const char *msg_id)
+ {
+       char ch;
+       const char *a, *z, *m;
+       char *n;
+       size_t len;
+       m = msg_id;
+       while ((ch = *m) && (isspace(ch) || (ch == '<')))
+               m++;
+       a = m;
+       z = NULL;
+       while ((ch = *m)) {
+               if (!isspace(ch) && (ch != '>'))
+                       z = m;
+               m++;
+       }
+       if (!z)
+               die("insane in-reply-to: %s", msg_id);
+       if (++z == m)
+               return a;
+       len = z - a;
+       n = xmalloc(len + 1);
+       memcpy(n, a, len);
+       n[len] = 0;
+       return n;
+ }
  int cmd_format_patch(int argc, const char **argv, const char *prefix)
  {
        struct commit *commit;
        if (numbered)
                rev.total = total + start_number - 1;
        rev.add_signoff = add_signoff;
-       rev.ref_message_id = in_reply_to;
+       if (in_reply_to)
+               rev.ref_message_id = clean_message_id(in_reply_to);
        while (0 <= --nr) {
                int shown;
                commit = list[nr];
@@@ -763,13 -792,13 +792,13 @@@ int cmd_cherry(int argc, const char **a
                        sign = '-';
  
                if (verbose) {
 -                      char *buf = NULL;
 -                      unsigned long buflen = 0;
 -                      pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
 -                                          &buf, &buflen, 0, NULL, NULL, 0);
 +                      struct strbuf buf;
 +                      strbuf_init(&buf, 0);
 +                      pretty_print_commit(CMIT_FMT_ONELINE, commit,
 +                                          &buf, 0, NULL, NULL, 0);
                        printf("%c %s %s\n", sign,
 -                             sha1_to_hex(commit->object.sha1), buf);
 -                      free(buf);
 +                             sha1_to_hex(commit->object.sha1), buf.buf);
 +                      strbuf_release(&buf);
                }
                else {
                        printf("%c %s\n", sign,
diff --combined builtin-rev-list.c
index 4fd4b6bec1a91761f2cb5b52ce69d211fa97f78e,899a31d09ac31aaf1336b5ab3959345ac83a9579..43b88fae298bc21a55d3dd83d2b31019fd431d02
@@@ -80,12 -80,13 +80,12 @@@ static void show_commit(struct commit *
                putchar('\n');
  
        if (revs.verbose_header) {
 -              char *buf = NULL;
 -              unsigned long buflen = 0;
 -              pretty_print_commit(revs.commit_format, commit, ~0,
 -                                  &buf, &buflen,
 -                                  revs.abbrev, NULL, NULL, revs.date_mode);
 -              printf("%s%c", buf, hdr_termination);
 -              free(buf);
 +              struct strbuf buf;
 +              strbuf_init(&buf, 0);
 +              pretty_print_commit(revs.commit_format, commit,
 +                                      &buf, revs.abbrev, NULL, NULL, revs.date_mode);
 +              printf("%s%c", buf.buf, hdr_termination);
 +              strbuf_release(&buf);
        }
        maybe_flush_or_die(stdout, "stdout");
        if (commit->parents) {
@@@ -188,7 -189,7 +188,7 @@@ static int count_interesting_parents(st
        return count;
  }
  
- static inline int halfway(struct commit_list *p, int distance, int nr)
+ static inline int halfway(struct commit_list *p, int nr)
  {
        /*
         * Don't short-cut something we are not going to return!
         * 2 and 3 are halfway of 5.
         * 3 is halfway of 6 but 2 and 4 are not.
         */
-       distance *= 2;
-       switch (distance - nr) {
+       switch (2 * weight(p) - nr) {
        case -1: case 0: case 1:
                return 1;
        default:
@@@ -254,6 -254,30 +253,30 @@@ static void show_list(const char *debug
  }
  #endif /* DEBUG_BISECT */
  
+ static struct commit_list *best_bisection(struct commit_list *list, int nr)
+ {
+       struct commit_list *p, *best;
+       int best_distance = -1;
+       best = list;
+       for (p = list; p; p = p->next) {
+               int distance;
+               unsigned flags = p->item->object.flags;
+               if (revs.prune_fn && !(flags & TREECHANGE))
+                       continue;
+               distance = weight(p);
+               if (nr - distance < distance)
+                       distance = nr - distance;
+               if (distance > best_distance) {
+                       best = p;
+                       best_distance = distance;
+               }
+       }
+       return best;
+ }
  /*
   * zero or positive weight is the number of interesting commits it can
   * reach, including itself.  Especially, weight = 0 means it does not
   * unknown.  After running count_distance() first, they will get zero
   * or positive distance.
   */
- static struct commit_list *find_bisection(struct commit_list *list,
-                                         int *reaches, int *all)
+ static struct commit_list *do_find_bisection(struct commit_list *list,
+                                            int nr, int *weights)
  {
-       int n, nr, on_list, counted, distance;
-       struct commit_list *p, *best, *next, *last;
-       int *weights;
-       show_list("bisection 2 entry", 0, 0, list);
-       /*
-        * Count the number of total and tree-changing items on the
-        * list, while reversing the list.
-        */
-       for (nr = on_list = 0, last = NULL, p = list;
-            p;
-            p = next) {
-               unsigned flags = p->item->object.flags;
-               next = p->next;
-               if (flags & UNINTERESTING)
-                       continue;
-               p->next = last;
-               last = p;
-               if (!revs.prune_fn || (flags & TREECHANGE))
-                       nr++;
-               on_list++;
-       }
-       list = last;
-       show_list("bisection 2 sorted", 0, nr, list);
+       int n, counted;
+       struct commit_list *p;
  
-       *all = nr;
-       weights = xcalloc(on_list, sizeof(*weights));
        counted = 0;
  
        for (n = 0, p = list; p; p = p->next) {
        for (p = list; p; p = p->next) {
                if (p->item->object.flags & UNINTERESTING)
                        continue;
-               n = weight(p);
-               if (n != -2)
+               if (weight(p) != -2)
                        continue;
-               distance = count_distance(p);
+               weight_set(p, count_distance(p));
                clear_distance(list);
-               weight_set(p, distance);
  
                /* Does it happen to be at exactly half-way? */
-               if (halfway(p, distance, nr)) {
-                       p->next = NULL;
-                       *reaches = distance;
-                       free(weights);
+               if (halfway(p, nr))
                        return p;
-               }
                counted++;
        }
  
                                weight_set(p, weight(q));
  
                        /* Does it happen to be at exactly half-way? */
-                       distance = weight(p);
-                       if (halfway(p, distance, nr)) {
-                               p->next = NULL;
-                               *reaches = distance;
-                               free(weights);
+                       if (halfway(p, nr))
                                return p;
-                       }
                }
        }
  
        show_list("bisection 2 counted all", counted, nr, list);
  
        /* Then find the best one */
-       counted = -1;
-       best = list;
-       for (p = list; p; p = p->next) {
+       return best_bisection(list, nr);
+ }
+ static struct commit_list *find_bisection(struct commit_list *list,
+                                         int *reaches, int *all)
+ {
+       int nr, on_list;
+       struct commit_list *p, *best, *next, *last;
+       int *weights;
+       show_list("bisection 2 entry", 0, 0, list);
+       /*
+        * Count the number of total and tree-changing items on the
+        * list, while reversing the list.
+        */
+       for (nr = on_list = 0, last = NULL, p = list;
+            p;
+            p = next) {
                unsigned flags = p->item->object.flags;
  
-               if (revs.prune_fn && !(flags & TREECHANGE))
+               next = p->next;
+               if (flags & UNINTERESTING)
                        continue;
-               distance = weight(p);
-               if (nr - distance < distance)
-                       distance = nr - distance;
-               if (distance > counted) {
-                       best = p;
-                       counted = distance;
-                       *reaches = weight(p);
-               }
+               p->next = last;
+               last = p;
+               if (!revs.prune_fn || (flags & TREECHANGE))
+                       nr++;
+               on_list++;
        }
+       list = last;
+       show_list("bisection 2 sorted", 0, nr, list);
+       *all = nr;
+       weights = xcalloc(on_list, sizeof(*weights));
+       /* Do the real work of finding bisection commit. */
+       best = do_find_bisection(list, nr, weights);
        if (best)
                best->next = NULL;
+       *reaches = weight(best);
        free(weights);
        return best;
  }
  
diff --combined builtin-update-index.c
index 45e33f5584b6c61cb64d7b408c89917320487f43,55fb679d68f141253f5d0ba5c73033d267e2a271..acd5ab592641064c4dab1f24b3e1cdb15b1326bb
@@@ -4,6 -4,7 +4,6 @@@
   * Copyright (C) Linus Torvalds, 2005
   */
  #include "cache.h"
 -#include "strbuf.h"
  #include "quote.h"
  #include "cache-tree.h"
  #include "tree-walk.h"
@@@ -194,11 -195,6 +194,6 @@@ static int process_path(const char *pat
        int len;
        struct stat st;
  
-       /* We probably want to do this in remove_file_from_cache() and
-        * add_cache_entry() instead...
-        */
-       cache_tree_invalidate_path(active_cache_tree, path);
        /*
         * First things first: get the stat information, to decide
         * what to do about the pathname!
@@@ -238,7 -234,6 +233,6 @@@ static int add_cacheinfo(unsigned int m
                return error("%s: cannot add to the index - missing --add option?",
                             path);
        report("add '%s'", path);
-       cache_tree_invalidate_path(active_cache_tree, path);
        return 0;
  }
  
@@@ -283,7 -278,6 +277,6 @@@ static void update_one(const char *path
                        die("Unable to mark file %s", path);
                goto free_return;
        }
-       cache_tree_invalidate_path(active_cache_tree, path);
  
        if (force_remove) {
                if (remove_file_from_cache(p))
  static void read_index_info(int line_termination)
  {
        struct strbuf buf;
 -      strbuf_init(&buf);
 +      strbuf_init(&buf, 0);
        while (1) {
                char *ptr, *tab;
                char *path_name;
                 * This format is to put higher order stages into the
                 * index file and matches git-ls-files --stage output.
                 */
 -              read_line(&buf, stdin, line_termination);
 -              if (buf.eof)
 +              if (strbuf_getline(&buf, stdin, line_termination) == EOF)
                        break;
  
                errno = 0;
                                free(path_name);
                        continue;
                }
-               cache_tree_invalidate_path(active_cache_tree, path_name);
  
                if (!mode) {
                        /* mode == 0 means there is no such path -- remove */
        bad_line:
                die("malformed index info %s", buf.buf);
        }
 +      strbuf_release(&buf);
  }
  
  static const char update_index_usage[] =
@@@ -473,7 -466,6 +465,6 @@@ static int unresolve_one(const char *pa
                goto free_return;
        }
  
-       cache_tree_invalidate_path(active_cache_tree, path);
        remove_file_from_cache(path);
        if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) {
                error("%s: cannot add our version to the index.", path);
@@@ -715,11 -707,12 +706,11 @@@ int cmd_update_index(int argc, const ch
        }
        if (read_from_stdin) {
                struct strbuf buf;
 -              strbuf_init(&buf);
 +              strbuf_init(&buf, 0);
                while (1) {
                        char *path_name;
                        const char *p;
 -                      read_line(&buf, stdin, line_termination);
 -                      if (buf.eof)
 +                      if (strbuf_getline(&buf, stdin, line_termination) == EOF)
                                break;
                        if (line_termination && buf.buf[0] == '"')
                                path_name = unquote_c_style(buf.buf, NULL);
                        if (path_name != buf.buf)
                                free(path_name);
                }
 +              strbuf_release(&buf);
        }
  
   finish:
diff --combined cache.h
index 37eb57eabad09e39b3252ad6406c333b1b74ec9b,824650016677353cfa8c8a140eb3d904f56d60ee..8650d62334323898f5173dcfa5af463c18e40624
+++ b/cache.h
@@@ -2,7 -2,6 +2,7 @@@
  #define CACHE_H
  
  #include "git-compat-util.h"
 +#include "strbuf.h"
  
  #include SHA1_HEADER
  #include <zlib.h>
@@@ -265,11 -264,13 +265,12 @@@ extern struct cache_entry *refresh_cach
  extern int remove_index_entry_at(struct index_state *, int pos);
  extern int remove_file_from_index(struct index_state *, const char *path);
  extern int add_file_to_index(struct index_state *, const char *path, int verbose);
+ extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
  extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
  extern int ie_match_stat(struct index_state *, struct cache_entry *, struct stat *, int);
  extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, int);
  extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
  extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
 -extern int read_fd(int fd, char **return_buf, unsigned long *return_size);
  extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
  extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
  extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
@@@ -590,9 -591,8 +591,9 @@@ extern void trace_printf(const char *fo
  extern void trace_argv_printf(const char **argv, int count, const char *format, ...);
  
  /* convert.c */
 -extern char *convert_to_git(const char *path, const char *src, unsigned long *sizep);
 -extern char *convert_to_working_tree(const char *path, const char *src, unsigned long *sizep);
 +/* returns 1 if *dst was used */
 +extern int convert_to_git(const char *path, const char *src, size_t len, struct strbuf *dst);
 +extern int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst);
  
  /* diff.c */
  extern int diff_auto_refresh_index;
diff --combined diff.c
index 56b672c4f0cb6287f03230e11b18ebf8fd81b744,0ee9ea1c1b47b82710a3850e7e9f679e4486f7bd..a5b69ed2d236309bb9e960251515e69cec528935
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -17,7 -17,7 +17,7 @@@
  #endif
  
  static int diff_detect_rename_default;
- static int diff_rename_limit_default = -1;
+ static int diff_rename_limit_default = 100;
  static int diff_use_color_default;
  int diff_auto_refresh_index = 1;
  
@@@ -1545,16 -1545,26 +1545,16 @@@ static int reuse_worktree_file(const ch
  
  static int populate_from_stdin(struct diff_filespec *s)
  {
 -#define INCREMENT 1024
 -      char *buf;
 -      unsigned long size;
 -      ssize_t got;
 -
 -      size = 0;
 -      buf = NULL;
 -      while (1) {
 -              buf = xrealloc(buf, size + INCREMENT);
 -              got = xread(0, buf + size, INCREMENT);
 -              if (!got)
 -                      break; /* EOF */
 -              if (got < 0)
 -                      return error("error while reading from stdin %s",
 +      struct strbuf buf;
 +
 +      strbuf_init(&buf, 0);
 +      if (strbuf_read(&buf, 0, 0) < 0)
 +              return error("error while reading from stdin %s",
                                     strerror(errno));
 -              size += got;
 -      }
 +
        s->should_munmap = 0;
 -      s->data = buf;
 -      s->size = size;
 +      s->size = buf.len;
 +      s->data = strbuf_detach(&buf);
        s->should_free = 1;
        return 0;
  }
@@@ -1599,9 -1609,10 +1599,9 @@@ int diff_populate_filespec(struct diff_
  
        if (!s->sha1_valid ||
            reuse_worktree_file(s->path, s->sha1, 0)) {
 +              struct strbuf buf;
                struct stat st;
                int fd;
 -              char *buf;
 -              unsigned long size;
  
                if (!strcmp(s->path, "-"))
                        return populate_from_stdin(s);
                /*
                 * Convert from working tree format to canonical git format
                 */
 -              size = s->size;
 -              buf = convert_to_git(s->path, s->data, &size);
 -              if (buf) {
 +              strbuf_init(&buf, 0);
 +              if (convert_to_git(s->path, s->data, s->size, &buf)) {
                        munmap(s->data, s->size);
                        s->should_munmap = 0;
 -                      s->data = buf;
 -                      s->size = size;
 +                      s->data = buf.buf;
 +                      s->size = buf.len;
                        s->should_free = 1;
                }
        }