Merge branch 'jc/clean' into next
authorJunio C Hamano <junkio@cox.net>
Mon, 8 May 2006 23:43:23 +0000 (16:43 -0700)
committerJunio C Hamano <junkio@cox.net>
Mon, 8 May 2006 23:43:23 +0000 (16:43 -0700)
* jc/clean:
Teach git-clean optional <paths>... parameters.
Separate object name errors from usage errors
Documentation: {caret} fixes (git-rev-list.txt)
Fix "git diff --stat" with long filenames
Fix repo-config set-multivar error return path.

1  2 
diff.c
read-tree.c
diff --combined diff.c
index bfe54c3e093439d8e9df55fa319715ca20090f99,5315270601eeb6ab54a12d97f69c5f29679c4cf7..7a7b839e56ac1ba2ed0b770a047aaf07bce23722
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -8,7 -8,6 +8,7 @@@
  #include "quote.h"
  #include "diff.h"
  #include "diffcore.h"
 +#include "delta.h"
  #include "xdiff-interface.h"
  
  static int use_size_cache;
@@@ -297,7 -296,6 +297,6 @@@ static const char minuses[]= "---------
  
  static void show_stats(struct diffstat_t* data)
  {
-       char *prefix = "";
        int i, len, add, del, total, adds = 0, dels = 0;
        int max, max_change = 0, max_len = 0;
        int total_files = data->nr;
        }
  
        for (i = 0; i < data->nr; i++) {
+               char *prefix = "";
                char *name = data->files[i]->name;
                int added = data->files[i]->added;
                int deleted = data->files[i]->deleted;
                        total_files, adds, dels);
  }
  
 +static unsigned char *deflate_it(char *data,
 +                               unsigned long size,
 +                               unsigned long *result_size)
 +{
 +      int bound;
 +      unsigned char *deflated;
 +      z_stream stream;
 +
 +      memset(&stream, 0, sizeof(stream));
 +      deflateInit(&stream, Z_BEST_COMPRESSION);
 +      bound = deflateBound(&stream, size);
 +      deflated = xmalloc(bound);
 +      stream.next_out = deflated;
 +      stream.avail_out = bound;
 +
 +      stream.next_in = (unsigned char *)data;
 +      stream.avail_in = size;
 +      while (deflate(&stream, Z_FINISH) == Z_OK)
 +              ; /* nothing */
 +      deflateEnd(&stream);
 +      *result_size = stream.total_out;
 +      return deflated;
 +}
 +
 +static void emit_binary_diff(mmfile_t *one, mmfile_t *two)
 +{
 +      void *cp;
 +      void *delta;
 +      void *deflated;
 +      void *data;
 +      unsigned long orig_size;
 +      unsigned long delta_size;
 +      unsigned long deflate_size;
 +      unsigned long data_size;
 +
 +      printf("GIT binary patch\n");
 +      /* We could do deflated delta, or we could do just deflated two,
 +       * whichever is smaller.
 +       */
 +      delta = NULL;
 +      deflated = deflate_it(two->ptr, two->size, &deflate_size);
 +      if (one->size && two->size) {
 +              delta = diff_delta(one->ptr, one->size,
 +                                 two->ptr, two->size,
 +                                 &delta_size, deflate_size);
 +              if (delta) {
 +                      void *to_free = delta;
 +                      orig_size = delta_size;
 +                      delta = deflate_it(delta, delta_size, &delta_size);
 +                      free(to_free);
 +              }
 +      }
 +
 +      if (delta && delta_size < deflate_size) {
 +              printf("delta %lu\n", orig_size);
 +              free(deflated);
 +              data = delta;
 +              data_size = delta_size;
 +      }
 +      else {
 +              printf("literal %lu\n", two->size);
 +              free(delta);
 +              data = deflated;
 +              data_size = deflate_size;
 +      }
 +
 +      /* emit data encoded in base85 */
 +      cp = data;
 +      while (data_size) {
 +              int bytes = (52 < data_size) ? 52 : data_size;
 +              char line[70];
 +              data_size -= bytes;
 +              if (bytes <= 26)
 +                      line[0] = bytes + 'A' - 1;
 +              else
 +                      line[0] = bytes - 26 + 'a' - 1;
 +              encode_85(line + 1, cp, bytes);
 +              cp += bytes;
 +              puts(line);
 +      }
 +      printf("\n");
 +      free(data);
 +}
 +
  #define FIRST_FEW_BYTES 8000
  static int mmfile_is_binary(mmfile_t *mf)
  {
@@@ -492,7 -407,6 +492,7 @@@ static void builtin_diff(const char *na
                         struct diff_filespec *one,
                         struct diff_filespec *two,
                         const char *xfrm_msg,
 +                       struct diff_options *o,
                         int complete_rewrite)
  {
        mmfile_t mf1, mf2;
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
  
 -      if (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2))
 -              printf("Binary files %s and %s differ\n", lbl[0], lbl[1]);
 +      if (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2)) {
 +              /* Quite common confusing case */
 +              if (mf1.size == mf2.size &&
 +                  !memcmp(mf1.ptr, mf2.ptr, mf1.size))
 +                      goto free_ab_and_return;
 +              if (o->binary)
 +                      emit_binary_diff(&mf1, &mf2);
 +              else
 +                      printf("Binary files %s and %s differ\n",
 +                             lbl[0], lbl[1]);
 +      }
        else {
                /* Crazy xdl interfaces.. */
                const char *diffopts = getenv("GIT_DIFF_OPTS");
@@@ -1023,7 -928,6 +1023,7 @@@ static void run_diff_cmd(const char *pg
                         struct diff_filespec *one,
                         struct diff_filespec *two,
                         const char *xfrm_msg,
 +                       struct diff_options *o,
                         int complete_rewrite)
  {
        if (pgm) {
        }
        if (one && two)
                builtin_diff(name, other ? other : name,
 -                           one, two, xfrm_msg, complete_rewrite);
 +                           one, two, xfrm_msg, o, complete_rewrite);
        else
                printf("* Unmerged path %s\n", name);
  }
@@@ -1067,7 -971,7 +1067,7 @@@ static void run_diff(struct diff_filepa
  
        if (DIFF_PAIR_UNMERGED(p)) {
                /* unmerged */
 -              run_diff_cmd(pgm, p->one->path, NULL, NULL, NULL, NULL, 0);
 +              run_diff_cmd(pgm, p->one->path, NULL, NULL, NULL, NULL, o, 0);
                return;
        }
  
                 * needs to be split into deletion and creation.
                 */
                struct diff_filespec *null = alloc_filespec(two->path);
 -              run_diff_cmd(NULL, name, other, one, null, xfrm_msg, 0);
 +              run_diff_cmd(NULL, name, other, one, null, xfrm_msg, o, 0);
                free(null);
                null = alloc_filespec(one->path);
 -              run_diff_cmd(NULL, name, other, null, two, xfrm_msg, 0);
 +              run_diff_cmd(NULL, name, other, null, two, xfrm_msg, o, 0);
                free(null);
        }
        else
 -              run_diff_cmd(pgm, name, other, one, two, xfrm_msg,
 +              run_diff_cmd(pgm, name, other, one, two, xfrm_msg, o,
                             complete_rewrite);
  
        free(name_munged);
@@@ -1243,10 -1147,6 +1243,10 @@@ int diff_opt_parse(struct diff_options 
                options->rename_limit = strtoul(arg+2, NULL, 10);
        else if (!strcmp(arg, "--full-index"))
                options->full_index = 1;
 +      else if (!strcmp(arg, "--binary")) {
 +              options->output_format = DIFF_FORMAT_PATCH;
 +              options->full_index = options->binary = 1;
 +      }
        else if (!strcmp(arg, "--name-only"))
                options->output_format = DIFF_FORMAT_NAME;
        else if (!strcmp(arg, "--name-status"))
diff --combined read-tree.c
index 5d304641067779b2c630a616279937378fe60c2c,e926e4c880363469c5abf766127acc466fb5e438..c25385d79f605c74ae9e9cde06225f0a4c834f00
@@@ -9,7 -9,6 +9,7 @@@
  
  #include "object.h"
  #include "tree.h"
 +#include "cache-tree.h"
  #include <sys/time.h>
  #include <signal.h>
  
@@@ -21,7 -20,6 +21,7 @@@ static int trivial_merges_only = 0
  static int aggressive = 0;
  static int verbose_update = 0;
  static volatile int progress_update = 0;
 +static const char *prefix = NULL;
  
  static int head_idx = -1;
  static int merge_size = 0;
@@@ -370,8 -368,7 +370,8 @@@ static int unpack_trees(merge_fn_t fn
                        posns[i] = ((struct tree *) posn->item)->entries;
                        posn = posn->next;
                }
 -              if (unpack_trees_rec(posns, len, "", fn, &indpos))
 +              if (unpack_trees_rec(posns, len, prefix ? prefix : "",
 +                                   fn, &indpos))
                        return -1;
        }
  
@@@ -424,12 -421,6 +424,12 @@@ static void verify_uptodate(struct cach
        die("Entry '%s' not uptodate. Cannot merge.", ce->name);
  }
  
 +static void invalidate_ce_path(struct cache_entry *ce)
 +{
 +      if (ce)
 +              cache_tree_invalidate_path(active_cache_tree, ce->name);
 +}
 +
  static int merged_entry(struct cache_entry *merge, struct cache_entry *old)
  {
        merge->ce_flags |= htons(CE_UPDATE);
                        *merge = *old;
                } else {
                        verify_uptodate(old);
 +                      invalidate_ce_path(old);
                }
        }
 +      else
 +              invalidate_ce_path(merge);
        merge->ce_flags &= ~htons(CE_STAGEMASK);
        add_cache_entry(merge, ADD_CACHE_OK_TO_ADD);
        return 1;
@@@ -461,7 -449,6 +461,7 @@@ static int deleted_entry(struct cache_e
                verify_uptodate(old);
        ce->ce_mode = 0;
        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD);
 +      invalidate_ce_path(ce);
        return 1;
  }
  
@@@ -681,28 -668,6 +681,28 @@@ static int twoway_merge(struct cache_en
                return deleted_entry(oldtree, current);
  }
  
 +/*
 + * Bind merge.
 + *
 + * Keep the index entries at stage0, collapse stage1 but make sure
 + * stage0 does not have anything in prefix.
 + */
 +static int bind_merge(struct cache_entry **src)
 +{
 +      struct cache_entry *old = src[0];
 +      struct cache_entry *a = src[1];
 +
 +      if (merge_size != 1)
 +              return error("Cannot do a bind merge of %d trees\n",
 +                           merge_size);
 +      if (!a)
 +              return merged_entry(old, NULL);
 +      if (old)
 +              die("Entry '%s' overlaps.  Cannot bind.", a->name);
 +
 +      return merged_entry(a, NULL);
 +}
 +
  /*
   * One-way merge.
   *
@@@ -718,10 -683,8 +718,10 @@@ static int oneway_merge(struct cache_en
                return error("Cannot do a oneway merge of %d trees",
                             merge_size);
  
 -      if (!a)
 +      if (!a) {
 +              invalidate_ce_path(old);
                return 0;
 +      }
        if (old && same(old, a)) {
                return keep_entry(old);
        }
@@@ -740,7 -703,6 +740,7 @@@ static int read_cache_unmerged(void
                struct cache_entry *ce = active_cache[i];
                if (ce_stage(ce)) {
                        deleted++;
 +                      invalidate_ce_path(ce);
                        continue;
                }
                if (deleted)
        return deleted;
  }
  
 -static const char read_tree_usage[] = "git-read-tree (<sha> | -m [--aggressive] [-u | -i] <sha1> [<sha2> [<sha3>]])";
 +static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
 +{
 +      struct tree_entry_list *ent;
 +      int cnt;
 +      
 +      memcpy(it->sha1, tree->object.sha1, 20);
 +      for (cnt = 0, ent = tree->entries; ent; ent = ent->next) {
 +              if (!ent->directory)
 +                      cnt++;
 +              else {
 +                      struct cache_tree_sub *sub;
 +                      struct tree *subtree = (struct tree *)ent->item.tree;
 +                      if (!subtree->object.parsed)
 +                              parse_tree(subtree);
 +                      sub = cache_tree_sub(it, ent->name);
 +                      sub->cache_tree = cache_tree();
 +                      prime_cache_tree_rec(sub->cache_tree, subtree);
 +                      cnt += sub->cache_tree->entry_count;
 +              }
 +      }
 +      it->entry_count = cnt;
 +}
 +
 +static void prime_cache_tree(void)
 +{
 +      struct tree *tree = (struct tree *)trees->item;
 +      if (!tree)
 +              return;
 +      active_cache_tree = cache_tree();
 +      prime_cache_tree_rec(active_cache_tree, tree);
 +
 +}
 +
 +static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] <sha1> [<sha2> [<sha3>]])";
  
  static struct cache_file cache_file;
  
@@@ -829,24 -758,9 +829,24 @@@ int main(int argc, char **argv
                        continue;
                }
  
 +              /* "--prefix=<subdirectory>/" means keep the current index
 +               *  entries and put the entries from the tree under the
 +               * given subdirectory.
 +               */
 +              if (!strncmp(arg, "--prefix=", 9)) {
 +                      if (stage || merge || prefix)
 +                              usage(read_tree_usage);
 +                      prefix = arg + 9;
 +                      merge = 1;
 +                      stage = 1;
 +                      if (read_cache_unmerged())
 +                              die("you need to resolve your current index first");
 +                      continue;
 +              }
 +
                /* This differs from "-m" in that we'll silently ignore unmerged entries */
                if (!strcmp(arg, "--reset")) {
 -                      if (stage || merge)
 +                      if (stage || merge || prefix)
                                usage(read_tree_usage);
                        reset = 1;
                        merge = 1;
  
                /* "-m" stands for "merge", meaning we start in stage 1 */
                if (!strcmp(arg, "-m")) {
 -                      if (stage || merge)
 +                      if (stage || merge || prefix)
                                usage(read_tree_usage);
                        if (read_cache_unmerged())
                                die("you need to resolve your current index first");
                if (1 < index_only + update)
                        usage(read_tree_usage);
  
-               if (get_sha1(arg, sha1) < 0)
-                       usage(read_tree_usage);
+               if (get_sha1(arg, sha1))
+                       die("Not a valid object name %s", arg);
                if (list_tree(sha1) < 0)
                        die("failed to unpack tree object %s", arg);
                stage++;
        if ((update||index_only) && !merge)
                usage(read_tree_usage);
  
 +      if (prefix) {
 +              int pfxlen = strlen(prefix);
 +              int pos;
 +              if (prefix[pfxlen-1] != '/')
 +                      die("prefix must end with /");
 +              if (stage != 2)
 +                      die("binding merge takes only one tree");
 +              pos = cache_name_pos(prefix, pfxlen);
 +              if (0 <= pos)
 +                      die("corrupt index file");
 +              pos = -pos-1;
 +              if (pos < active_nr &&
 +                  !strncmp(active_cache[pos]->name, prefix, pfxlen))
 +                      die("subdirectory '%s' already exists.", prefix);
 +              pos = cache_name_pos(prefix, pfxlen-1);
 +              if (0 <= pos)
 +                      die("file '%.*s' already exists.", pfxlen-1, prefix);
 +      }
 +
        if (merge) {
                if (stage < 2)
                        die("just how do you expect me to merge %d trees?", stage-1);
                switch (stage - 1) {
                case 1:
 -                      fn = oneway_merge;
 +                      fn = prefix ? bind_merge : oneway_merge;
                        break;
                case 2:
                        fn = twoway_merge;
                        break;
                case 3:
 -                      fn = threeway_merge;
 -                      break;
                default:
                        fn = threeway_merge;
 +                      cache_tree_free(&active_cache_tree);
                        break;
                }
  
        }
  
        unpack_trees(fn);
 +
 +      /*
 +       * When reading only one tree (either the most basic form,
 +       * "-m ent" or "--reset ent" form), we can obtain a fully
 +       * valid cache-tree because the index must match exactly
 +       * what came from the tree.
 +       */
 +      if (trees && trees->item && (!merge || (stage == 2))) {
 +              cache_tree_free(&active_cache_tree);
 +              prime_cache_tree();
 +      }
 +
        if (write_cache(newfd, active_cache, active_nr) ||
            commit_index_file(&cache_file))
                die("unable to write new index file");