[PATCH 1/2] upload-pack: support subtree packing
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@gmail.com>
---
upload-pack.c | 31 ++++++++++++++++++++++++++++++-
1 files changed, 30 insertions(+), 1 deletions(-)
Show changes to upload-pack.c +30 −1
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