As stated somewhere, the index in narrow repo is also narrowed. When a users are done with his changes and about to commit, the new narrow tree created from index will be grafted back to a base toplevel tree (usually from parent commit). The result is a new toplevel tree with user's changes and suitable for commits. The narrow version uses join_narrow_tree() to recreate a full tree from a base toplevel tree (typically commit parent's tree) and a tree created from index. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- Equivalence to Elijah's 07/15 and 08/15. My way generates some throw away trees at write_cache_as_tree(), not good. commit.c | 16 +++++++++ commit.h | 5 +++ narrow-tree.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ narrow-tree.h | 4 ++ 4 files changed, 126 insertions(+), 0 deletions(-) diff --git a/commit.c b/commit.c index 0094ec1..c7fe7fc 100644 --- a/commit.c +++ b/commit.c @@ -6,6 +6,7 @@ #include "diff.h" #include "revision.h" #include "notes.h" +#include "narrow-tree.h" int save_commit_buffer = 1; @@ -864,3 +865,18 @@ int commit_tree(const char *msg, unsigned char *tree, strbuf_release(&buffer); return result; } + +int commit_narrow_tree(const char *msg, unsigned char *tree, + const unsigned char *narrow_base, + struct commit_list *parents, unsigned char *ret, + const char *author) +{ + unsigned char sha1[20]; + + if (get_narrow_prefix()) { + if (join_narrow_tree(sha1, narrow_base, tree, get_narrow_prefix())) + die("Failed to join tree"); + tree = sha1; + } + return commit_tree(msg, tree, parents, ret, author); +} diff --git a/commit.h b/commit.h index 9113bbe..c718439 100644 --- a/commit.h +++ b/commit.h @@ -170,5 +170,10 @@ struct commit_list *reduce_heads(struct commit_list *heads); extern int commit_tree(const char *msg, unsigned char *tree, struct commit_list *parents, unsigned char *ret, const char *author); +extern int commit_narrow_tree(const char *msg, unsigned char *tree, + const unsigned char *narrow_base, + struct commit_list *parents, + unsigned char *ret, + const char *author); #endif /* COMMIT_H */ diff --git a/narrow-tree.c b/narrow-tree.c index 85dbab4..110fac2 100644 --- a/narrow-tree.c +++ b/narrow-tree.c @@ -1,4 +1,14 @@ #include "cache.h" +#include "commit.h" +#include "tree.h" +#include "diff.h" +#include "revision.h" +#include "refs.h" +#include "tag.h" +#include "progress.h" +#include "pack.h" +#include "sha1-lookup.h" +#include "csum-file.h" #include "narrow-tree.h" static const char **narrow_prefix; @@ -104,3 +114,94 @@ char *get_narrow_string() } return strbuf_detach(&sb, NULL); } + +/* + * The opposite of narrow_tree(). Put the subtree back to the original tree. + */ +static int join_narrow_tree_rec(unsigned char *result, + const unsigned char *basetree, + const unsigned char *newtree, + const char **prefix, + char *base, + int baselen) +{ + struct tree_desc desc; + struct name_entry entry; + struct strbuf buffer; + enum object_type type; + unsigned long size; + const char **p; + int len, found; + char *buf; + + buf = read_sha1_file(basetree, &type, &size); + if (!buf || type != OBJ_TREE) + die("Bad tree %s", sha1_to_hex(basetree)); + + if (baselen) + base[baselen++] = '/'; + + init_tree_desc(&desc, buf, size); + strbuf_init(&buffer, 8192); + while (tree_entry(&desc, &entry)) { + strbuf_addf(&buffer, "%o %.*s%c", entry.mode, strlen(entry.path), entry.path, '\0'); + + if (!S_ISDIR(entry.mode)) { + strbuf_add(&buffer, entry.sha1, 20); + continue; + } + + p = prefix; + len = strlen(entry.path); + found = 0; + + while (*p) { + if (!strcmp(entry.path, *p)) { + found = 2; + break; + } + if (!prefixcmp(*p, entry.path)) { + found = 1; + break; + } + p++; + } + switch (found) { + case 1: + memcpy(base+baselen, entry.path, len+1); + join_narrow_tree_rec(result, entry.sha1, newtree, + prefix, base, baselen+len+1); + break; + case 2: + if (!path_to_tree_sha1(result, newtree, *p)) + die("Could not find tree %s in the new tree", *p); + break; + case 0: + hashcpy(result, entry.sha1); + break; + } + + /* FIXME, what if placeholder tree does not exist? */ + + strbuf_add(&buffer, result, 20); + } + + free(buf); + if (write_sha1_file(buffer.buf, buffer.len, tree_type, result)) { + base[baselen] = '\0'; + error("Could not write tree %s", base); + strbuf_release(&buffer); + return 1; + } + strbuf_release(&buffer); + return 0; +} + +int join_narrow_tree(unsigned char *result, + const unsigned char *basetree, + const unsigned char *newtree, + const char **prefix) +{ + char path[PATH_MAX]; + return join_narrow_tree_rec(result, basetree, newtree, prefix, path, 0); +} diff --git a/narrow-tree.h b/narrow-tree.h index 2097436..e7d84c4 100644 --- a/narrow-tree.h +++ b/narrow-tree.h @@ -1,3 +1,7 @@ extern int valid_narrow_prefix(const char *prefix, const char *prev_prefix, int quiet); extern int check_narrow_prefix(); extern char *get_narrow_string(); +extern int join_narrow_tree(unsigned char *result, + const unsigned char *base, + const unsigned char *newtree, + const char **prefix); -- 1.7.1.rc1.69.g24c2f7 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html