This patch adds a new capability "subtree", which supports two new requests "subtree" and "commit-subtree". "subtree" asks upload-pack to create a pack that contains only blobs from the given tree prefix (and necessary commits/trees to reach those blobs). "commit-tree" asks upload-pack to create a pack that contains trees of the given prefix (and necessary commits/trees to reach those trees) With "subtree" request, Git client may then rewrite commits to create a valid commit tree again, so that users can work on it independently. When users want to push from such a tree, "commit-tree" may then be used to re-match what users have and what is in upstream, recreate proper push commits. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- upload-pack.c | 31 ++++++++++++++++++++++++++++++- 1 files changed, 30 insertions(+), 1 deletions(-) diff --git a/upload-pack.c b/upload-pack.c index dc464d7..f97296a 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -41,6 +41,8 @@ static int use_sideband; static int debug_fd; static int advertise_refs; static int stateless_rpc; +static char *subtree; +static int commit_subtree; static void reset_timeout(void) { @@ -89,6 +91,17 @@ static void show_object(struct object *obj, const struct name_path *path, const */ const char *name = path_name(path, component); const char *ep = strchr(name, '\n'); + if (subtree) { + int len = strlen(name); + /* parent trees should always be kept */ + if (obj->type == OBJ_TREE && !prefixcmp(subtree, name) && subtree[len] == '/') + ; /* in */ + else if (commit_subtree) + goto out; + else if (prefixcmp(name, subtree)) + goto out; + } + if (ep) { fprintf(pack_pipe, "%s %.*s\n", sha1_to_hex(obj->sha1), (int) (ep - name), @@ -97,6 +110,7 @@ static void show_object(struct object *obj, const struct name_path *path, const else fprintf(pack_pipe, "%s %s\n", sha1_to_hex(obj->sha1), name); +out: free((char *)name); } @@ -504,6 +518,21 @@ static void receive_needs(void) if (debug_fd) write_in_full(debug_fd, line, len); + if (!prefixcmp(line, "subtree ")) { + int len = strlen(line+8); + subtree = malloc(len+1); + memcpy(subtree, line+8, len-1); + subtree[len-1] = '\0'; /* \n */ + continue; + } + if (!prefixcmp(line, "commit-subtree ")) { + int len = strlen(line+15); + subtree = malloc(len+1); + memcpy(subtree, line+15, len-1); + subtree[len-1] = '\0'; /* \n */ + commit_subtree = 1; + continue; + } if (!prefixcmp(line, "shallow ")) { unsigned char sha1[20]; struct object *object; @@ -623,7 +652,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo { static const char *capabilities = "multi_ack thin-pack side-band" " side-band-64k ofs-delta shallow no-progress" - " include-tag multi_ack_detailed"; + " include-tag multi_ack_detailed subtree"; struct object *o = parse_object(sha1); if (!o) -- 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