Merge branch 'jc/gitlink' into next
authorJunio C Hamano <junkio@cox.net>
Sun, 7 May 2006 23:17:43 +0000 (16:17 -0700)
committerJunio C Hamano <junkio@cox.net>
Sun, 7 May 2006 23:17:43 +0000 (16:17 -0700)
* jc/gitlink:
  write-tree: --prefix=<path>
  read-tree: --prefix=<path>/ option.

1  2 
cache-tree.c
read-tree.c

diff --combined cache-tree.c
@@@ -110,10 -110,6 +110,10 @@@ void cache_tree_invalidate_path(struct 
        int namelen;
        struct cache_tree_sub *down;
  
 +#if DEBUG
 +      fprintf(stderr, "cache-tree invalidate <%s>\n", path);
 +#endif
 +
        if (!it)
                return;
        slash = strchr(path, '/');
@@@ -339,7 -335,7 +339,7 @@@ static int update_one(struct cache_tre
                offset += 20;
  
  #if DEBUG
 -              fprintf(stderr, "cache-tree %o %.*s\n",
 +              fprintf(stderr, "cache-tree update-one %o %.*s\n",
                        mode, entlen, path + baselen);
  #endif
        }
        free(buffer);
        it->entry_count = i;
  #if DEBUG
 -      fprintf(stderr, "cache-tree (%d ent, %d subtree) %s\n",
 +      fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n",
                it->entry_count, it->subtree_nr,
                sha1_to_hex(it->sha1));
  #endif
@@@ -529,3 -525,29 +529,29 @@@ struct cache_tree *cache_tree_read(cons
                return NULL; /* not the whole tree */
        return read_one(&buffer, &size);
  }
+ struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path)
+ {
+       while (*path) {
+               const char *slash;
+               struct cache_tree_sub *sub;
+               slash = strchr(path, '/');
+               if (!slash)
+                       slash = path + strlen(path);
+               /* between path and slash is the name of the
+                * subtree to look for.
+                */
+               sub = find_subtree(it, path, slash - path, 0);
+               if (!sub)
+                       return NULL;
+               it = sub->cache_tree;
+               if (slash)
+                       while (*slash && *slash == '/')
+                               slash++;
+               if (!slash || !*slash)
+                       return it; /* prefix ended with slashes */
+               path = slash;
+       }
+       return it;
+ }
diff --combined read-tree.c
@@@ -21,6 -21,7 +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;
@@@ -369,7 -370,8 +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;
        }
  
@@@ -446,8 -448,6 +448,8 @@@ static int merged_entry(struct cache_en
                        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;
@@@ -680,6 -680,28 +682,28 @@@ static int twoway_merge(struct cache_en
  }
  
  /*
+  * 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.
   *
   * The rule is:
@@@ -760,7 -782,7 +784,7 @@@ static void prime_cache_tree(void
  
  }
  
- static const char read_tree_usage[] = "git-read-tree (<sha> | -m [--aggressive] [-u | -i] <sha1> [<sha2> [<sha3>]])";
+ 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;
  
@@@ -805,9 -827,24 +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 ((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;
         * valid cache-tree because the index must match exactly
         * what came from the tree.
         */
 -      if (trees->item && !prefix && (!merge || (stage == 2))) {
 +      if (trees && trees->item && (!merge || (stage == 2))) {
                cache_tree_free(&active_cache_tree);
                prime_cache_tree();
        }