{"thread":{"id":"42576","subject":"[PATCH 08/27] upload-pack: tighten number parsing at \"deepen\" lines","startedAt":"2016-06-16T02:19:50Z","lastAt":"2016-06-16T06:55:52Z","messageCount":64,"participants":["Nguyễn Thái Ngọc Duy","Junio C Hamano","Eric Sunshine","Duy Nguyen"],"isPatch":true,"patchVersion":1,"patchTotal":27},"messages":[{"id":"288895","messageId":"20160610122714.3341-9-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 08/27] upload-pack: tighten number parsing at \"deepen\" lines","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:26:55Z","receivedAt":"2016-06-16T02:19:50Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n upload-pack.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 615bfb2..60f2e5e 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -641,9 +641,9 @@ static void receive_needs(void)\n \t\t\tcontinue;\n \t\t}\n \t\tif (skip_prefix(line, \"deepen \", &arg)) {\n-\t\t\tchar *end;\n+\t\t\tchar *end = NULL;\n \t\t\tdepth = strtol(arg, &end, 0);\n-\t\t\tif (end == arg || depth <= 0)\n+\t\t\tif (!end || *end || depth <= 0)\n \t\t\t\tdie(\"Invalid deepen: %s\", line);\n \t\t\tcontinue;\n \t\t}\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288896","messageId":"20160610122714.3341-10-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 09/27] upload-pack: make check_non_tip() clean things up error","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:26:56Z","receivedAt":"2016-06-16T02:19:50Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On error check_non_tip() will die and not closing file descriptors is no\nbig deal. The next patch will split the majority of this function out\nfor reuse in other cases, where die() may not be the only outcome. Same\nstory for popping SIGPIPE out of the signal chain. So let's make sure we\nclean things up properly first.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n upload-pack.c | 15 +++++++++++++--\n 1 file changed, 13 insertions(+), 2 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 60f2e5e..1e8b025 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -494,8 +494,10 @@ static void check_non_tip(void)\n \t\tif (!is_our_ref(o))\n \t\t\tcontinue;\n \t\tmemcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n-\t\tif (write_in_full(cmd.in, namebuf, 42) < 0)\n+\t\tif (write_in_full(cmd.in, namebuf, 42) < 0) {\n+\t\t\tsigchain_pop(SIGPIPE);\n \t\t\tgoto error;\n+\t\t}\n \t}\n \tnamebuf[40] = '\\n';\n \tfor (i = 0; i < want_obj.nr; i++) {\n@@ -503,10 +505,13 @@ static void check_non_tip(void)\n \t\tif (is_our_ref(o))\n \t\t\tcontinue;\n \t\tmemcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n-\t\tif (write_in_full(cmd.in, namebuf, 41) < 0)\n+\t\tif (write_in_full(cmd.in, namebuf, 41) < 0) {\n+\t\t\tsigchain_pop(SIGPIPE);\n \t\t\tgoto error;\n+\t\t}\n \t}\n \tclose(cmd.in);\n+\tcmd.in = -1;\n \n \tsigchain_pop(SIGPIPE);\n \n@@ -518,6 +523,7 @@ static void check_non_tip(void)\n \tif (i)\n \t\tgoto error;\n \tclose(cmd.out);\n+\tcmd.out = -1;\n \n \t/*\n \t * rev-list may have died by encountering a bad commit\n@@ -531,6 +537,11 @@ static void check_non_tip(void)\n \treturn;\n \n error:\n+\tif (cmd.in >= 0)\n+\t\tclose(cmd.in);\n+\tif (cmd.out >= 0)\n+\t\tclose(cmd.out);\n+\n \t/* Pick one of them (we know there at least is one) */\n \tfor (i = 0; i < want_obj.nr; i++) {\n \t\to = want_obj.objects[i].item;\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288897","messageId":"20160610122714.3341-6-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 05/27] upload-pack: remove unused variable \"backup\"","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:26:52Z","receivedAt":"2016-06-16T02:19:50Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"After the last patch, \"result\" and \"backup\" are the same. \"result\" used\nto move, but the movement is now contained in send_shallow(). Delete\nthis redundant variable.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n upload-pack.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 0eb9a0b..ee5d20b 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -554,7 +554,7 @@ static void send_shallow(struct commit_list *result)\n \n static void deepen(int depth, const struct object_array *shallows)\n {\n-\tstruct commit_list *result = NULL, *backup = NULL;\n+\tstruct commit_list *result = NULL;\n \tint i;\n \tif (depth == INFINITE_DEPTH && !is_repository_shallow())\n \t\tfor (i = 0; i < shallows->nr; i++) {\n@@ -562,11 +562,10 @@ static void deepen(int depth, const struct object_array *shallows)\n \t\t\tobject->flags |= NOT_SHALLOW;\n \t\t}\n \telse\n-\t\tbackup = result =\n-\t\t\tget_shallow_commits(&want_obj, depth,\n-\t\t\t\t\t    SHALLOW, NOT_SHALLOW);\n+\t\tresult = get_shallow_commits(&want_obj, depth,\n+\t\t\t\t\t     SHALLOW, NOT_SHALLOW);\n \tsend_shallow(result);\n-\tfree_commit_list(backup);\n+\tfree_commit_list(result);\n \tfor (i = 0; i < shallows->nr; i++) {\n \t\tstruct object *object = shallows->objects[i].item;\n \t\tif (object->flags & NOT_SHALLOW) {\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288898","messageId":"20160610122714.3341-13-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 12/27] fetch-pack: use a common function for verbose printing","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:26:59Z","receivedAt":"2016-06-16T02:19:50Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This reduces the number of \"if (verbose)\" which makes it a bit easier\nto read imo. It also makes it easier to redirect all these printouts,\nto a file for example.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n fetch-pack.c | 88 +++++++++++++++++++++++++++++-------------------------------\n 1 file changed, 42 insertions(+), 46 deletions(-)\n\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 01e34b6..4020744 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -50,6 +50,21 @@ static int non_common_revs, multi_ack, use_sideband;\n #define ALLOW_REACHABLE_SHA1\t02\n static unsigned int allow_unadvertised_object_request;\n \n+__attribute__((format (printf, 2, 3)))\n+static inline void print_verbose(const struct fetch_pack_args *args,\n+\t\t\t\t const char *fmt, ...)\n+{\n+\tva_list params;\n+\n+\tif (!args->verbose)\n+\t\treturn;\n+\n+\tva_start(params, fmt);\n+\tvfprintf(stderr, fmt, params);\n+\tva_end(params);\n+\tfputc('\\n', stderr);\n+}\n+\n static void rev_list_push(struct commit *commit, int mark)\n {\n \tif (!(commit->object.flags & mark)) {\n@@ -375,8 +390,7 @@ static int find_common(struct fetch_pack_args *args,\n \tretval = -1;\n \twhile ((sha1 = get_rev())) {\n \t\tpacket_buf_write(&req_buf, \"have %s\\n\", sha1_to_hex(sha1));\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"have %s\\n\", sha1_to_hex(sha1));\n+\t\tprint_verbose(args, \"have %s\", sha1_to_hex(sha1));\n \t\tin_vain++;\n \t\tif (flush_at <= ++count) {\n \t\t\tint ack;\n@@ -397,9 +411,9 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\tconsume_shallow_list(args, fd[0]);\n \t\t\tdo {\n \t\t\t\tack = get_ack(fd[0], result_sha1);\n-\t\t\t\tif (args->verbose && ack)\n-\t\t\t\t\tfprintf(stderr, \"got ack %d %s\\n\", ack,\n-\t\t\t\t\t\t\tsha1_to_hex(result_sha1));\n+\t\t\t\tif (ack)\n+\t\t\t\t\tprint_verbose(args, \"got ack %d %s\", ack,\n+\t\t\t\t\t\t      sha1_to_hex(result_sha1));\n \t\t\t\tswitch (ack) {\n \t\t\t\tcase ACK:\n \t\t\t\t\tflushes = 0;\n@@ -438,8 +452,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\t} while (ack);\n \t\t\tflushes--;\n \t\t\tif (got_continue && MAX_IN_VAIN < in_vain) {\n-\t\t\t\tif (args->verbose)\n-\t\t\t\t\tfprintf(stderr, \"giving up\\n\");\n+\t\t\t\tprint_verbose(args, \"giving up\");\n \t\t\t\tbreak; /* give up */\n \t\t\t}\n \t\t}\n@@ -449,8 +462,7 @@ done:\n \t\tpacket_buf_write(&req_buf, \"done\\n\");\n \t\tsend_request(args, fd[1], &req_buf);\n \t}\n-\tif (args->verbose)\n-\t\tfprintf(stderr, \"done\\n\");\n+\tprint_verbose(args, \"done\");\n \tif (retval != 0) {\n \t\tmulti_ack = 0;\n \t\tflushes++;\n@@ -462,9 +474,8 @@ done:\n \twhile (flushes || multi_ack) {\n \t\tint ack = get_ack(fd[0], result_sha1);\n \t\tif (ack) {\n-\t\t\tif (args->verbose)\n-\t\t\t\tfprintf(stderr, \"got ack (%d) %s\\n\", ack,\n-\t\t\t\t\tsha1_to_hex(result_sha1));\n+\t\t\tprint_verbose(args, \"got ack (%d) %s\", ack,\n+\t\t\t\t      sha1_to_hex(result_sha1));\n \t\t\tif (ack == ACK)\n \t\t\t\treturn 0;\n \t\t\tmulti_ack = 1;\n@@ -509,9 +520,8 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args,\n \t\t\t\t\t unsigned long cutoff)\n {\n \twhile (complete && cutoff <= complete->item->date) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Marking %s as complete\\n\",\n-\t\t\t\toid_to_hex(&complete->item->object.oid));\n+\t\tprint_verbose(args, \"Marking %s as complete\",\n+\t\t\t      oid_to_hex(&complete->item->object.oid));\n \t\tpop_most_recent_commit(&complete, COMPLETE);\n \t}\n }\n@@ -652,18 +662,12 @@ static int everything_local(struct fetch_pack_args *args,\n \t\to = lookup_object(remote);\n \t\tif (!o || !(o->flags & COMPLETE)) {\n \t\t\tretval = 0;\n-\t\t\tif (!args->verbose)\n-\t\t\t\tcontinue;\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"want %s (%s)\\n\", sha1_to_hex(remote),\n-\t\t\t\tref->name);\n+\t\t\tprint_verbose(args, \"want %s (%s)\", sha1_to_hex(remote),\n+\t\t\t\t      ref->name);\n \t\t\tcontinue;\n \t\t}\n-\t\tif (!args->verbose)\n-\t\t\tcontinue;\n-\t\tfprintf(stderr,\n-\t\t\t\"already have %s (%s)\\n\", sha1_to_hex(remote),\n-\t\t\tref->name);\n+\t\tprint_verbose(args, \"already have %s (%s)\", sha1_to_hex(remote),\n+\t\t\t      ref->name);\n \t}\n \treturn retval;\n }\n@@ -810,39 +814,32 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \tif ((args->depth > 0 || is_repository_shallow()) && !server_supports(\"shallow\"))\n \t\tdie(\"Server does not support shallow clients\");\n \tif (server_supports(\"multi_ack_detailed\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports multi_ack_detailed\\n\");\n+\t\tprint_verbose(args, \"Server supports multi_ack_detailed\");\n \t\tmulti_ack = 2;\n \t\tif (server_supports(\"no-done\")) {\n-\t\t\tif (args->verbose)\n-\t\t\t\tfprintf(stderr, \"Server supports no-done\\n\");\n+\t\t\tprint_verbose(args, \"Server supports no-done\");\n \t\t\tif (args->stateless_rpc)\n \t\t\t\tno_done = 1;\n \t\t}\n \t}\n \telse if (server_supports(\"multi_ack\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports multi_ack\\n\");\n+\t\tprint_verbose(args, \"Server supports multi_ack\");\n \t\tmulti_ack = 1;\n \t}\n \tif (server_supports(\"side-band-64k\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports side-band-64k\\n\");\n+\t\tprint_verbose(args, \"Server supports side-band-64k\");\n \t\tuse_sideband = 2;\n \t}\n \telse if (server_supports(\"side-band\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports side-band\\n\");\n+\t\tprint_verbose(args, \"Server supports side-band\");\n \t\tuse_sideband = 1;\n \t}\n \tif (server_supports(\"allow-tip-sha1-in-want\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports allow-tip-sha1-in-want\\n\");\n+\t\tprint_verbose(args, \"Server supports allow-tip-sha1-in-want\");\n \t\tallow_unadvertised_object_request |= ALLOW_TIP_SHA1;\n \t}\n \tif (server_supports(\"allow-reachable-sha1-in-want\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports allow-reachable-sha1-in-want\\n\");\n+\t\tprint_verbose(args, \"Server supports allow-reachable-sha1-in-want\");\n \t\tallow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1;\n \t}\n \tif (!server_supports(\"thin-pack\"))\n@@ -851,17 +848,16 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t\targs->no_progress = 0;\n \tif (!server_supports(\"include-tag\"))\n \t\targs->include_tag = 0;\n-\tif (server_supports(\"ofs-delta\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports ofs-delta\\n\");\n-\t} else\n+\tif (server_supports(\"ofs-delta\"))\n+\t\tprint_verbose(args, \"Server supports ofs-delta\");\n+\telse\n \t\tprefer_ofs_delta = 0;\n \n \tif ((agent_feature = server_feature_value(\"agent\", &agent_len))) {\n \t\tagent_supported = 1;\n-\t\tif (args->verbose && agent_len)\n-\t\t\tfprintf(stderr, \"Server version is %.*s\\n\",\n-\t\t\t\tagent_len, agent_feature);\n+\t\tif (agent_len)\n+\t\t\tprint_verbose(args, \"Server version is %.*s\",\n+\t\t\t\t      agent_len, agent_feature);\n \t}\n \n \tif (everything_local(args, &ref, sought, nr_sought)) {\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288899","messageId":"20160610122714.3341-5-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 04/27] upload-pack: move \"shallow\" sending code out of deepen()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:26:51Z","receivedAt":"2016-06-16T02:19:50Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n upload-pack.c | 25 +++++++++++++++----------\n 1 file changed, 15 insertions(+), 10 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 97ed620..0eb9a0b 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -538,6 +538,20 @@ error:\n \t}\n }\n \n+static void send_shallow(struct commit_list *result)\n+{\n+\twhile (result) {\n+\t\tstruct object *object = &result->item->object;\n+\t\tif (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {\n+\t\t\tpacket_write(1, \"shallow %s\",\n+\t\t\t\t     oid_to_hex(&object->oid));\n+\t\t\tregister_shallow(object->oid.hash);\n+\t\t\tshallow_nr++;\n+\t\t}\n+\t\tresult = result->next;\n+\t}\n+}\n+\n static void deepen(int depth, const struct object_array *shallows)\n {\n \tstruct commit_list *result = NULL, *backup = NULL;\n@@ -551,16 +565,7 @@ static void deepen(int depth, const struct object_array *shallows)\n \t\tbackup = result =\n \t\t\tget_shallow_commits(&want_obj, depth,\n \t\t\t\t\t    SHALLOW, NOT_SHALLOW);\n-\twhile (result) {\n-\t\tstruct object *object = &result->item->object;\n-\t\tif (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {\n-\t\t\tpacket_write(1, \"shallow %s\",\n-\t\t\t\t     oid_to_hex(&object->oid));\n-\t\t\tregister_shallow(object->oid.hash);\n-\t\t\tshallow_nr++;\n-\t\t}\n-\t\tresult = result->next;\n-\t}\n+\tsend_shallow(result);\n \tfree_commit_list(backup);\n \tfor (i = 0; i < shallows->nr; i++) {\n \t\tstruct object *object = shallows->objects[i].item;\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288900","messageId":"20160610122714.3341-12-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 11/27] fetch-pack: use skip_prefix() instead of starts_with()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:26:58Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/fetch-pack.c | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex 9b2a514..8332d3d 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -59,12 +59,12 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \tfor (i = 1; i < argc && *argv[i] == '-'; i++) {\n \t\tconst char *arg = argv[i];\n \n-\t\tif (starts_with(arg, \"--upload-pack=\")) {\n-\t\t\targs.uploadpack = arg + 14;\n+\t\tif (skip_prefix(arg, \"--upload-pack=\", &arg)) {\n+\t\t\targs.uploadpack = arg;\n \t\t\tcontinue;\n \t\t}\n-\t\tif (starts_with(arg, \"--exec=\")) {\n-\t\t\targs.uploadpack = arg + 7;\n+\t\tif (skip_prefix(arg, \"--exec=\", &arg)) {\n+\t\t\targs.uploadpack = arg;\n \t\t\tcontinue;\n \t\t}\n \t\tif (!strcmp(\"--quiet\", arg) || !strcmp(\"-q\", arg)) {\n@@ -100,8 +100,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \t\t\targs.verbose = 1;\n \t\t\tcontinue;\n \t\t}\n-\t\tif (starts_with(arg, \"--depth=\")) {\n-\t\t\targs.depth = strtol(arg + 8, NULL, 0);\n+\t\tif (skip_prefix(arg, \"--depth=\", &arg)) {\n+\t\t\targs.depth = strtol(arg, NULL, 0);\n \t\t\tcontinue;\n \t\t}\n \t\tif (!strcmp(\"--no-progress\", arg)) {\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288901","messageId":"20160610122714.3341-7-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 06/27] upload-pack: move \"unshallow\" sending code out of deepen()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:26:53Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Also add some more comments in this code because it takes too long to\nunderstand what it does (to me, who should be familiar enough to\nunderstand this code well!)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n upload-pack.c | 39 ++++++++++++++++++++++++++-------------\n 1 file changed, 26 insertions(+), 13 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex ee5d20b..bfb7985 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -552,20 +552,10 @@ static void send_shallow(struct commit_list *result)\n \t}\n }\n \n-static void deepen(int depth, const struct object_array *shallows)\n+static void send_unshallow(const struct object_array *shallows)\n {\n-\tstruct commit_list *result = NULL;\n \tint i;\n-\tif (depth == INFINITE_DEPTH && !is_repository_shallow())\n-\t\tfor (i = 0; i < shallows->nr; i++) {\n-\t\t\tstruct object *object = shallows->objects[i].item;\n-\t\t\tobject->flags |= NOT_SHALLOW;\n-\t\t}\n-\telse\n-\t\tresult = get_shallow_commits(&want_obj, depth,\n-\t\t\t\t\t     SHALLOW, NOT_SHALLOW);\n-\tsend_shallow(result);\n-\tfree_commit_list(result);\n+\n \tfor (i = 0; i < shallows->nr; i++) {\n \t\tstruct object *object = shallows->objects[i].item;\n \t\tif (object->flags & NOT_SHALLOW) {\n@@ -573,7 +563,13 @@ static void deepen(int depth, const struct object_array *shallows)\n \t\t\tpacket_write(1, \"unshallow %s\",\n \t\t\t\t     oid_to_hex(&object->oid));\n \t\t\tobject->flags &= ~CLIENT_SHALLOW;\n-\t\t\t/* make sure the real parents are parsed */\n+\t\t\t/*\n+\t\t\t * We want to _register_ \"object\" as shallow, but we\n+\t\t\t * also need to traverse object's parents to deepen a\n+\t\t\t * shallow clone. Unregister it for now so we can\n+\t\t\t * parse and add the parents to the want list, then\n+\t\t\t * re-register it.\n+\t\t\t */\n \t\t\tunregister_shallow(object->oid.hash);\n \t\t\tobject->parsed = 0;\n \t\t\tparse_commit_or_die((struct commit *)object);\n@@ -588,6 +584,23 @@ static void deepen(int depth, const struct object_array *shallows)\n \t\t/* make sure commit traversal conforms to client */\n \t\tregister_shallow(object->oid.hash);\n \t}\n+}\n+\n+static void deepen(int depth, const struct object_array *shallows)\n+{\n+\tstruct commit_list *result = NULL;\n+\tint i;\n+\tif (depth == INFINITE_DEPTH && !is_repository_shallow())\n+\t\tfor (i = 0; i < shallows->nr; i++) {\n+\t\t\tstruct object *object = shallows->objects[i].item;\n+\t\t\tobject->flags |= NOT_SHALLOW;\n+\t\t}\n+\telse\n+\t\tresult = get_shallow_commits(&want_obj, depth,\n+\t\t\t\t\t     SHALLOW, NOT_SHALLOW);\n+\tsend_shallow(result);\n+\tfree_commit_list(result);\n+\tsend_unshallow(shallows);\n \tpacket_flush(1);\n }\n \n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288902","messageId":"20160610122714.3341-4-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 03/27] upload-pack: move shallow deepen code out of receive_needs()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:26:50Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is a prep step for further refactoring. Besides reindentation and\ns/shallows\\./shallows->/g, no other changes are expected.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n upload-pack.c | 99 +++++++++++++++++++++++++++++++----------------------------\n 1 file changed, 52 insertions(+), 47 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex b3f6653..97ed620 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -538,6 +538,55 @@ error:\n \t}\n }\n \n+static void deepen(int depth, const struct object_array *shallows)\n+{\n+\tstruct commit_list *result = NULL, *backup = NULL;\n+\tint i;\n+\tif (depth == INFINITE_DEPTH && !is_repository_shallow())\n+\t\tfor (i = 0; i < shallows->nr; i++) {\n+\t\t\tstruct object *object = shallows->objects[i].item;\n+\t\t\tobject->flags |= NOT_SHALLOW;\n+\t\t}\n+\telse\n+\t\tbackup = result =\n+\t\t\tget_shallow_commits(&want_obj, depth,\n+\t\t\t\t\t    SHALLOW, NOT_SHALLOW);\n+\twhile (result) {\n+\t\tstruct object *object = &result->item->object;\n+\t\tif (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {\n+\t\t\tpacket_write(1, \"shallow %s\",\n+\t\t\t\t     oid_to_hex(&object->oid));\n+\t\t\tregister_shallow(object->oid.hash);\n+\t\t\tshallow_nr++;\n+\t\t}\n+\t\tresult = result->next;\n+\t}\n+\tfree_commit_list(backup);\n+\tfor (i = 0; i < shallows->nr; i++) {\n+\t\tstruct object *object = shallows->objects[i].item;\n+\t\tif (object->flags & NOT_SHALLOW) {\n+\t\t\tstruct commit_list *parents;\n+\t\t\tpacket_write(1, \"unshallow %s\",\n+\t\t\t\t     oid_to_hex(&object->oid));\n+\t\t\tobject->flags &= ~CLIENT_SHALLOW;\n+\t\t\t/* make sure the real parents are parsed */\n+\t\t\tunregister_shallow(object->oid.hash);\n+\t\t\tobject->parsed = 0;\n+\t\t\tparse_commit_or_die((struct commit *)object);\n+\t\t\tparents = ((struct commit *)object)->parents;\n+\t\t\twhile (parents) {\n+\t\t\t\tadd_object_array(&parents->item->object,\n+\t\t\t\t\t\t NULL, &want_obj);\n+\t\t\t\tparents = parents->next;\n+\t\t\t}\n+\t\t\tadd_object_array(object, NULL, &extra_edge_obj);\n+\t\t}\n+\t\t/* make sure commit traversal conforms to client */\n+\t\tregister_shallow(object->oid.hash);\n+\t}\n+\tpacket_flush(1);\n+}\n+\n static void receive_needs(void)\n {\n \tstruct object_array shallows = OBJECT_ARRAY_INIT;\n@@ -630,53 +679,9 @@ static void receive_needs(void)\n \n \tif (depth == 0 && shallows.nr == 0)\n \t\treturn;\n-\tif (depth > 0) {\n-\t\tstruct commit_list *result = NULL, *backup = NULL;\n-\t\tint i;\n-\t\tif (depth == INFINITE_DEPTH && !is_repository_shallow())\n-\t\t\tfor (i = 0; i < shallows.nr; i++) {\n-\t\t\t\tstruct object *object = shallows.objects[i].item;\n-\t\t\t\tobject->flags |= NOT_SHALLOW;\n-\t\t\t}\n-\t\telse\n-\t\t\tbackup = result =\n-\t\t\t\tget_shallow_commits(&want_obj, depth,\n-\t\t\t\t\t\t    SHALLOW, NOT_SHALLOW);\n-\t\twhile (result) {\n-\t\t\tstruct object *object = &result->item->object;\n-\t\t\tif (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {\n-\t\t\t\tpacket_write(1, \"shallow %s\",\n-\t\t\t\t\t\toid_to_hex(&object->oid));\n-\t\t\t\tregister_shallow(object->oid.hash);\n-\t\t\t\tshallow_nr++;\n-\t\t\t}\n-\t\t\tresult = result->next;\n-\t\t}\n-\t\tfree_commit_list(backup);\n-\t\tfor (i = 0; i < shallows.nr; i++) {\n-\t\t\tstruct object *object = shallows.objects[i].item;\n-\t\t\tif (object->flags & NOT_SHALLOW) {\n-\t\t\t\tstruct commit_list *parents;\n-\t\t\t\tpacket_write(1, \"unshallow %s\",\n-\t\t\t\t\toid_to_hex(&object->oid));\n-\t\t\t\tobject->flags &= ~CLIENT_SHALLOW;\n-\t\t\t\t/* make sure the real parents are parsed */\n-\t\t\t\tunregister_shallow(object->oid.hash);\n-\t\t\t\tobject->parsed = 0;\n-\t\t\t\tparse_commit_or_die((struct commit *)object);\n-\t\t\t\tparents = ((struct commit *)object)->parents;\n-\t\t\t\twhile (parents) {\n-\t\t\t\t\tadd_object_array(&parents->item->object,\n-\t\t\t\t\t\t\tNULL, &want_obj);\n-\t\t\t\t\tparents = parents->next;\n-\t\t\t\t}\n-\t\t\t\tadd_object_array(object, NULL, &extra_edge_obj);\n-\t\t\t}\n-\t\t\t/* make sure commit traversal conforms to client */\n-\t\t\tregister_shallow(object->oid.hash);\n-\t\t}\n-\t\tpacket_flush(1);\n-\t} else\n+\tif (depth > 0)\n+\t\tdeepen(depth, &shallows);\n+\telse\n \t\tif (shallows.nr > 0) {\n \t\t\tint i;\n \t\t\tfor (i = 0; i < shallows.nr; i++)\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288903","messageId":"20160610122714.3341-3-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 02/27] transport-helper.c: refactor set_helper_option()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:26:49Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"For now we can handle two types, string and boolean, in\nset_helper_option(). Later on we'll add string_list support, which does\nnot fit well. The new function strbuf_set_helper_option() can be reused\nfor a separate function that handles string-list.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n transport-helper.c | 37 +++++++++++++++++++++++--------------\n 1 file changed, 23 insertions(+), 14 deletions(-)\n\ndiff --git a/transport-helper.c b/transport-helper.c\nindex a6bff8b..27a34e9 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -260,6 +260,28 @@ static const char *boolean_options[] = {\n \tTRANS_OPT_FOLLOWTAGS,\n \t};\n \n+static int strbuf_set_helper_option(struct helper_data *data,\n+\t\t\t\t    struct strbuf *buf)\n+{\n+\tint ret;\n+\n+\tsendline(data, buf);\n+\tif (recvline(data, buf))\n+\t\texit(128);\n+\n+\tif (!strcmp(buf->buf, \"ok\"))\n+\t\tret = 0;\n+\telse if (starts_with(buf->buf, \"error\"))\n+\t\tret = -1;\n+\telse if (!strcmp(buf->buf, \"unsupported\"))\n+\t\tret = 1;\n+\telse {\n+\t\twarning(\"%s unexpectedly said: '%s'\", data->name, buf->buf);\n+\t\tret = 1;\n+\t}\n+\treturn ret;\n+}\n+\n static int set_helper_option(struct transport *transport,\n \t\t\t  const char *name, const char *value)\n {\n@@ -291,20 +313,7 @@ static int set_helper_option(struct transport *transport,\n \t\tquote_c_style(value, &buf, NULL, 0);\n \tstrbuf_addch(&buf, '\\n');\n \n-\tsendline(data, &buf);\n-\tif (recvline(data, &buf))\n-\t\texit(128);\n-\n-\tif (!strcmp(buf.buf, \"ok\"))\n-\t\tret = 0;\n-\telse if (starts_with(buf.buf, \"error\")) {\n-\t\tret = -1;\n-\t} else if (!strcmp(buf.buf, \"unsupported\"))\n-\t\tret = 1;\n-\telse {\n-\t\twarning(\"%s unexpectedly said: '%s'\", data->name, buf.buf);\n-\t\tret = 1;\n-\t}\n+\tret = strbuf_set_helper_option(data, &buf);\n \tstrbuf_release(&buf);\n \treturn ret;\n }\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288904","messageId":"20160610122714.3341-2-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 01/27] remote-curl.c: convert fetch_git() to use argv_array","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:26:48Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n remote-curl.c | 46 ++++++++++++++++++----------------------------\n 1 file changed, 18 insertions(+), 28 deletions(-)\n\ndiff --git a/remote-curl.c b/remote-curl.c\nindex c704857..fd030c1 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -725,38 +725,28 @@ static int fetch_git(struct discovery *heads,\n {\n \tstruct rpc_state rpc;\n \tstruct strbuf preamble = STRBUF_INIT;\n-\tchar *depth_arg = NULL;\n-\tint argc = 0, i, err;\n-\tconst char *argv[17];\n-\n-\targv[argc++] = \"fetch-pack\";\n-\targv[argc++] = \"--stateless-rpc\";\n-\targv[argc++] = \"--stdin\";\n-\targv[argc++] = \"--lock-pack\";\n+\tint i, err;\n+\tstruct argv_array args = ARGV_ARRAY_INIT;\n+\n+\targv_array_pushl(&args, \"fetch-pack\", \"--stateless-rpc\",\n+\t\t\t \"--stdin\", \"--lock-pack\", NULL);\n \tif (options.followtags)\n-\t\targv[argc++] = \"--include-tag\";\n+\t\targv_array_push(&args, \"--include-tag\");\n \tif (options.thin)\n-\t\targv[argc++] = \"--thin\";\n-\tif (options.verbosity >= 3) {\n-\t\targv[argc++] = \"-v\";\n-\t\targv[argc++] = \"-v\";\n-\t}\n+\t\targv_array_push(&args, \"--thin\");\n+\tif (options.verbosity >= 3)\n+\t\targv_array_pushl(&args, \"-v\", \"-v\", NULL);\n \tif (options.check_self_contained_and_connected)\n-\t\targv[argc++] = \"--check-self-contained-and-connected\";\n+\t\targv_array_push(&args, \"--check-self-contained-and-connected\");\n \tif (options.cloning)\n-\t\targv[argc++] = \"--cloning\";\n+\t\targv_array_push(&args, \"--cloning\");\n \tif (options.update_shallow)\n-\t\targv[argc++] = \"--update-shallow\";\n+\t\targv_array_push(&args, \"--update-shallow\");\n \tif (!options.progress)\n-\t\targv[argc++] = \"--no-progress\";\n-\tif (options.depth) {\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\t\tstrbuf_addf(&buf, \"--depth=%lu\", options.depth);\n-\t\tdepth_arg = strbuf_detach(&buf, NULL);\n-\t\targv[argc++] = depth_arg;\n-\t}\n-\targv[argc++] = url.buf;\n-\targv[argc++] = NULL;\n+\t\targv_array_push(&args, \"--no-progress\");\n+\tif (options.depth)\n+\t\targv_array_pushf(&args, \"--depth=%lu\", options.depth);\n+\targv_array_push(&args, url.buf);\n \n \tfor (i = 0; i < nr_heads; i++) {\n \t\tstruct ref *ref = to_fetch[i];\n@@ -769,7 +759,7 @@ static int fetch_git(struct discovery *heads,\n \n \tmemset(&rpc, 0, sizeof(rpc));\n \trpc.service_name = \"git-upload-pack\",\n-\trpc.argv = argv;\n+\trpc.argv = args.argv;\n \trpc.stdin_preamble = &preamble;\n \trpc.gzip_request = 1;\n \n@@ -778,7 +768,7 @@ static int fetch_git(struct discovery *heads,\n \t\twrite_or_die(1, rpc.result.buf, rpc.result.len);\n \tstrbuf_release(&rpc.result);\n \tstrbuf_release(&preamble);\n-\tfree(depth_arg);\n+\targv_array_clear(&args);\n \treturn err;\n }\n \n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288905","messageId":"20160610122714.3341-8-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 07/27] upload-pack: use skip_prefix() instead of starts_with()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:26:54Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n upload-pack.c | 32 ++++++++++++++++++--------------\n 1 file changed, 18 insertions(+), 14 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex bfb7985..615bfb2 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -276,7 +276,7 @@ static void create_pack_file(void)\n \tdie(\"git upload-pack: %s\", abort_msg);\n }\n \n-static int got_sha1(char *hex, unsigned char *sha1)\n+static int got_sha1(const char *hex, unsigned char *sha1)\n {\n \tstruct object *o;\n \tint we_knew_they_have = 0;\n@@ -382,6 +382,8 @@ static int get_common_commits(void)\n \n \tfor (;;) {\n \t\tchar *line = packet_read_line(0, NULL);\n+\t\tconst char *arg;\n+\n \t\treset_timeout();\n \n \t\tif (!line) {\n@@ -403,8 +405,8 @@ static int get_common_commits(void)\n \t\t\tgot_other = 0;\n \t\t\tcontinue;\n \t\t}\n-\t\tif (starts_with(line, \"have \")) {\n-\t\t\tswitch (got_sha1(line+5, sha1)) {\n+\t\tif (skip_prefix(line, \"have \", &arg)) {\n+\t\t\tswitch (got_sha1(arg, sha1)) {\n \t\t\tcase -1: /* they have what we do not */\n \t\t\t\tgot_other = 1;\n \t\t\t\tif (multi_ack && ok_to_give_up()) {\n@@ -616,14 +618,16 @@ static void receive_needs(void)\n \t\tconst char *features;\n \t\tunsigned char sha1_buf[20];\n \t\tchar *line = packet_read_line(0, NULL);\n+\t\tconst char *arg;\n+\n \t\treset_timeout();\n \t\tif (!line)\n \t\t\tbreak;\n \n-\t\tif (starts_with(line, \"shallow \")) {\n+\t\tif (skip_prefix(line, \"shallow \", &arg)) {\n \t\t\tunsigned char sha1[20];\n \t\t\tstruct object *object;\n-\t\t\tif (get_sha1_hex(line + 8, sha1))\n+\t\t\tif (get_sha1_hex(arg, sha1))\n \t\t\t\tdie(\"invalid shallow line: %s\", line);\n \t\t\tobject = parse_object(sha1);\n \t\t\tif (!object)\n@@ -636,19 +640,19 @@ static void receive_needs(void)\n \t\t\t}\n \t\t\tcontinue;\n \t\t}\n-\t\tif (starts_with(line, \"deepen \")) {\n+\t\tif (skip_prefix(line, \"deepen \", &arg)) {\n \t\t\tchar *end;\n-\t\t\tdepth = strtol(line + 7, &end, 0);\n-\t\t\tif (end == line + 7 || depth <= 0)\n+\t\t\tdepth = strtol(arg, &end, 0);\n+\t\t\tif (end == arg || depth <= 0)\n \t\t\t\tdie(\"Invalid deepen: %s\", line);\n \t\t\tcontinue;\n \t\t}\n-\t\tif (!starts_with(line, \"want \") ||\n-\t\t    get_sha1_hex(line+5, sha1_buf))\n+\t\tif (!skip_prefix(line, \"want \", &arg) ||\n+\t\t    get_sha1_hex(arg, sha1_buf))\n \t\t\tdie(\"git upload-pack: protocol error, \"\n \t\t\t    \"expected to get sha, not '%s'\", line);\n \n-\t\tfeatures = line + 45;\n+\t\tfeatures = arg + 40;\n \n \t\tif (parse_feature_request(features, \"multi_ack_detailed\"))\n \t\t\tmulti_ack = 2;\n@@ -855,7 +859,7 @@ int main(int argc, char **argv)\n \tcheck_replace_refs = 0;\n \n \tfor (i = 1; i < argc; i++) {\n-\t\tchar *arg = argv[i];\n+\t\tconst char *arg = argv[i];\n \n \t\tif (arg[0] != '-')\n \t\t\tbreak;\n@@ -871,8 +875,8 @@ int main(int argc, char **argv)\n \t\t\tstrict = 1;\n \t\t\tcontinue;\n \t\t}\n-\t\tif (starts_with(arg, \"--timeout=\")) {\n-\t\t\ttimeout = atoi(arg+10);\n+\t\tif (skip_prefix(arg, \"--timeout=\", &arg)) {\n+\t\t\ttimeout = atoi(arg);\n \t\t\tdaemon_mode = 1;\n \t\t\tcontinue;\n \t\t}\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288906","messageId":"20160610122714.3341-1-pclouds@gmail.com","threadId":"42576","inReplyTo":null,"subject":"[PATCH 00/27] nd/shallow-deepen updates","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:26:47Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This contains cleanups after Eric's comments (all good points,\nthanks!). Changed patches have Junio's s-o-b line removed, so it's\neasy to see which is changed and which is not. 09/27 is a new one,\nsplit out of 10/27.\n\nInterdiff\n\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex 5ccf6b7..3849231 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -53,13 +53,6 @@ static struct string_list option_config;\n static struct string_list option_reference;\n static int option_dissociate;\n \n-static int option_parse_deepen_not(const struct option *opt,\n-\t\t\t\t   const char *arg, int unset)\n-{\n-\tstring_list_append(&option_not, arg);\n-\treturn 0;\n-}\n-\n static struct option builtin_clone_options[] = {\n \tOPT__VERBOSITY(&option_verbosity),\n \tOPT_BOOL(0, \"progress\", &option_progress,\n@@ -97,9 +90,8 @@ static struct option builtin_clone_options[] = {\n \t\t    N_(\"create a shallow clone of that depth\")),\n \tOPT_STRING(0, \"shallow-since\", &option_since, N_(\"time\"),\n \t\t    N_(\"create a shallow clone since a specific time\")),\n-\t{ OPTION_CALLBACK, 0, \"shallow-exclude\", NULL, N_(\"revision\"),\n-\t\t    N_(\"deepen history of shallow clone by excluding rev\"),\n-\t\t    PARSE_OPT_NONEG, option_parse_deepen_not },\n+\tOPT_STRING_LIST(0, \"shallow-exclude\", &option_not, N_(\"revision\"),\n+\t\t\tN_(\"deepen history of shallow clone by excluding rev\")),\n \tOPT_BOOL(0, \"single-branch\", &option_single_branch,\n \t\t    N_(\"clone only one branch, HEAD or --branch\")),\n \tOPT_STRING(0, \"separate-git-dir\", &real_git_dir, N_(\"gitdir\"),\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 68b44ba..7b0ea1c 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -51,13 +51,6 @@ static int shown_url = 0;\n static int refmap_alloc, refmap_nr;\n static const char **refmap_array;\n \n-static int option_parse_deepen_not(const struct option *opt,\n-\t\t\t\t   const char *arg, int unset)\n-{\n-\tstring_list_append(&deepen_not, arg);\n-\treturn 0;\n-}\n-\n static int option_parse_recurse_submodules(const struct option *opt,\n \t\t\t\t   const char *arg, int unset)\n {\n@@ -126,9 +119,8 @@ static struct option builtin_fetch_options[] = {\n \t\t   N_(\"deepen history of shallow clone\")),\n \tOPT_STRING(0, \"shallow-since\", &deepen_since, N_(\"time\"),\n \t\t   N_(\"deepen history of shallow repository based on time\")),\n-\t{ OPTION_CALLBACK, 0, \"shallow-exclude\", NULL, N_(\"revision\"),\n-\t\t    N_(\"deepen history of shallow clone by excluding rev\"),\n-\t\t    PARSE_OPT_NONEG, option_parse_deepen_not },\n+\tOPT_STRING_LIST(0, \"shallow-exclude\", &deepen_not, N_(\"revision\"),\n+\t\t\tN_(\"deepen history of shallow clone by excluding rev\")),\n \tOPT_INTEGER(0, \"deepen\", &deepen_relative,\n \t\t    N_(\"deepen history of shallow clone\")),\n \t{ OPTION_SET_INT, 0, \"unshallow\", &unshallow, NULL,\ndiff --git a/remote-curl.c b/remote-curl.c\nindex 3f1a8f5..d56412d 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -745,7 +745,6 @@ static int fetch_git(struct discovery *heads,\n {\n \tstruct rpc_state rpc;\n \tstruct strbuf preamble = STRBUF_INIT;\n-\tchar *depth_arg = NULL;\n \tint i, err;\n \tstruct argv_array args = ARGV_ARRAY_INIT;\n \n@@ -755,10 +754,8 @@ static int fetch_git(struct discovery *heads,\n \t\targv_array_push(&args, \"--include-tag\");\n \tif (options.thin)\n \t\targv_array_push(&args, \"--thin\");\n-\tif (options.verbosity >= 3) {\n-\t\targv_array_push(&args, \"-v\");\n-\t\targv_array_push(&args, \"-v\");\n-\t}\n+\tif (options.verbosity >= 3)\n+\t\targv_array_pushl(&args, \"-v\", \"-v\", NULL);\n \tif (options.check_self_contained_and_connected)\n \t\targv_array_push(&args, \"--check-self-contained-and-connected\");\n \tif (options.cloning)\n@@ -798,7 +795,6 @@ static int fetch_git(struct discovery *heads,\n \t\twrite_or_die(1, rpc.result.buf, rpc.result.len);\n \tstrbuf_release(&rpc.result);\n \tstrbuf_release(&preamble);\n-\tfree(depth_arg);\n \targv_array_clear(&args);\n \treturn err;\n }\ndiff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh\nindex f512098..a908036 100755\n--- a/t/t5500-fetch-pack.sh\n+++ b/t/t5500-fetch-pack.sh\n@@ -678,8 +678,7 @@ test_expect_success 'shallow clone exclude tag two' '\n test_expect_success 'fetch exclude tag one' '\n \tgit -C shallow12 fetch --shallow-exclude one origin &&\n \tgit -C shallow12 log --pretty=tformat:%s origin/master >actual &&\n-\techo three >expected &&\n-\techo two  >>expected &&\n+\ttest_write_lines three two >expected &&\n \ttest_cmp expected actual\n '\n \ndiff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh\nindex 25f8968..5fbf67c 100755\n--- a/t/t5539-fetch-http-shallow.sh\n+++ b/t/t5539-fetch-http-shallow.sh\n@@ -116,8 +116,7 @@ test_expect_success 'shallow clone exclude tag two' '\n test_expect_success 'fetch exclude tag one' '\n \tgit -C shallow12 fetch --shallow-exclude one origin &&\n \tgit -C shallow12 log --pretty=tformat:%s origin/master >actual &&\n-\techo three >expected &&\n-\techo two  >>expected &&\n+\ttest_write_lines three two >expected &&\n \ttest_cmp expected actual\n '\n \ndiff --git a/transport-helper.c b/transport-helper.c\nindex b894b60..a5cdd77 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -272,9 +272,9 @@ static int strbuf_set_helper_option(struct helper_data *data,\n \n \tif (!strcmp(buf->buf, \"ok\"))\n \t\tret = 0;\n-\telse if (starts_with(buf->buf, \"error\")) {\n+\telse if (starts_with(buf->buf, \"error\"))\n \t\tret = -1;\n-\t} else if (!strcmp(buf->buf, \"unsupported\"))\n+\telse if (!strcmp(buf->buf, \"unsupported\"))\n \t\tret = 1;\n \telse {\n \t\twarning(\"%s unexpectedly said: '%s'\", data->name, buf->buf);\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 18b914a..ef693bd 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -471,7 +471,7 @@ static int do_reachable_revlist(struct child_process *cmd,\n \tcmd->out = -1;\n \n \tif (start_command(cmd))\n-\t\treturn -1;\n+\t\tgoto error;\n \n \t/*\n \t * If rev-list --stdin encounters an unknown commit, it\n@@ -491,8 +491,10 @@ static int do_reachable_revlist(struct child_process *cmd,\n \t\tif (!is_our_ref(o))\n \t\t\tcontinue;\n \t\tmemcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n-\t\tif (write_in_full(cmd->in, namebuf, 42) < 0)\n-\t\t\treturn -1;\n+\t\tif (write_in_full(cmd->in, namebuf, 42) < 0) {\n+\t\t\tsigchain_pop(SIGPIPE);\n+\t\t\tgoto error;\n+\t\t}\n \t}\n \tnamebuf[40] = '\\n';\n \tfor (i = 0; i < src->nr; i++) {\n@@ -505,13 +507,23 @@ static int do_reachable_revlist(struct child_process *cmd,\n \t\tif (reachable && o->type == OBJ_COMMIT)\n \t\t\to->flags |= TMP_MARK;\n \t\tmemcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n-\t\tif (write_in_full(cmd->in, namebuf, 41) < 0)\n-\t\t\treturn -1;\n+\t\tif (write_in_full(cmd->in, namebuf, 41) < 0) {\n+\t\t\tsigchain_pop(SIGPIPE);\n+\t\t\tgoto error;\n+\t\t}\n \t}\n \tclose(cmd->in);\n+\tcmd->in = -1;\n \n \tsigchain_pop(SIGPIPE);\n \treturn 0;\n+\n+error:\n+\tif (cmd->in >= 0)\n+\t\tclose(cmd->in);\n+\tif (cmd->out >= 0)\n+\t\tclose(cmd->out);\n+\treturn -1;\n }\n \n static int get_reachable_list(struct object_array *src,\n@@ -555,10 +567,10 @@ static int get_reachable_list(struct object_array *src,\n static int check_unreachable(struct object_array *src)\n {\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n-\tint i, ret = do_reachable_revlist(&cmd, src, NULL);\n \tchar buf[1];\n+\tint i;\n \n-\tif (ret < 0)\n+\tif (do_reachable_revlist(&cmd, src, NULL) < 0)\n \t\treturn 0;\n \n \t/*\n@@ -567,8 +579,9 @@ static int check_unreachable(struct object_array *src)\n \t */\n \ti = read_in_full(cmd.out, buf, 1);\n \tif (i)\n-\t\treturn 0;\n+\t\tgoto error;\n \tclose(cmd.out);\n+\tcmd.out = -1;\n \n \t/*\n \t * rev-list may have died by encountering a bad commit\n@@ -576,10 +589,17 @@ static int check_unreachable(struct object_array *src)\n \t * even when it showed no commit.\n \t */\n \tif (finish_command(&cmd))\n-\t\treturn 0;\n+\t\tgoto error;\n \n \t/* All the non-tip ones are ancestors of what we advertised */\n \treturn 1;\n+\n+error:\n+\tif (cmd.in >= 0)\n+\t\tclose(cmd.in);\n+\tif (cmd.out >= 0)\n+\t\tclose(cmd.out);\n+\treturn 0;\n }\n \n static void check_non_tip(void)\n@@ -592,10 +612,12 @@ static void check_non_tip(void)\n \t * non-tip requests can never happen.\n \t */\n \tif (!stateless_rpc && !(allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1))\n-\t\t;\t\t/* error */\n-\telse if (check_unreachable(&want_obj))\n+\t\tgoto error;\n+\tif (check_unreachable(&want_obj))\n+\t\t/* All the non-tip ones are ancestors of what we advertised */\n \t\treturn;\n \n+error:\n \t/* Pick one of them (we know there at least is one) */\n \tfor (i = 0; i < want_obj.nr; i++) {\n \t\tstruct object *o = want_obj.objects[i].item;\n@@ -993,7 +1015,7 @@ int main(int argc, char **argv)\n \tcheck_replace_refs = 0;\n \n \tfor (i = 1; i < argc; i++) {\n-\t\tchar *arg = argv[i];\n+\t\tconst char *arg = argv[i];\n \n \t\tif (arg[0] != '-')\n \t\t\tbreak;\n@@ -1009,8 +1031,8 @@ int main(int argc, char **argv)\n \t\t\tstrict = 1;\n \t\t\tcontinue;\n \t\t}\n-\t\tif (starts_with(arg, \"--timeout=\")) {\n-\t\t\ttimeout = atoi(arg+10);\n+\t\tif (skip_prefix(arg, \"--timeout=\", &arg)) {\n+\t\t\ttimeout = atoi(arg);\n \t\t\tdaemon_mode = 1;\n \t\t\tcontinue;\n \t\t}\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288907","messageId":"20160610122714.3341-11-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 10/27] upload-pack: move rev-list code out of check_non_tip()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:26:57Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n upload-pack.c | 36 +++++++++++++++++++++++-------------\n 1 file changed, 23 insertions(+), 13 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 1e8b025..b6f3756 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -451,7 +451,7 @@ static int is_our_ref(struct object *o)\n \treturn o->flags & ((allow_hidden_ref ? HIDDEN_REF : 0) | OUR_REF);\n }\n \n-static void check_non_tip(void)\n+static int check_unreachable(struct object_array *src)\n {\n \tstatic const char *argv[] = {\n \t\t\"rev-list\", \"--stdin\", NULL,\n@@ -461,14 +461,6 @@ static void check_non_tip(void)\n \tchar namebuf[42]; /* ^ + SHA-1 + LF */\n \tint i;\n \n-\t/*\n-\t * In the normal in-process case without\n-\t * uploadpack.allowReachableSHA1InWant,\n-\t * non-tip requests can never happen.\n-\t */\n-\tif (!stateless_rpc && !(allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1))\n-\t\tgoto error;\n-\n \tcmd.argv = argv;\n \tcmd.git_cmd = 1;\n \tcmd.no_stderr = 1;\n@@ -500,8 +492,8 @@ static void check_non_tip(void)\n \t\t}\n \t}\n \tnamebuf[40] = '\\n';\n-\tfor (i = 0; i < want_obj.nr; i++) {\n-\t\to = want_obj.objects[i].item;\n+\tfor (i = 0; i < src->nr; i++) {\n+\t\to = src->objects[i].item;\n \t\tif (is_our_ref(o))\n \t\t\tcontinue;\n \t\tmemcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n@@ -534,17 +526,35 @@ static void check_non_tip(void)\n \t\tgoto error;\n \n \t/* All the non-tip ones are ancestors of what we advertised */\n-\treturn;\n+\treturn 1;\n \n error:\n \tif (cmd.in >= 0)\n \t\tclose(cmd.in);\n \tif (cmd.out >= 0)\n \t\tclose(cmd.out);\n+\treturn 0;\n+}\n \n+static void check_non_tip(void)\n+{\n+\tint i;\n+\n+\t/*\n+\t * In the normal in-process case without\n+\t * uploadpack.allowReachableSHA1InWant,\n+\t * non-tip requests can never happen.\n+\t */\n+\tif (!stateless_rpc && !(allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1))\n+\t\tgoto error;\n+\tif (check_unreachable(&want_obj))\n+\t\t/* All the non-tip ones are ancestors of what we advertised */\n+\t\treturn;\n+\n+error:\n \t/* Pick one of them (we know there at least is one) */\n \tfor (i = 0; i < want_obj.nr; i++) {\n-\t\to = want_obj.objects[i].item;\n+\t\tstruct object *o = want_obj.objects[i].item;\n \t\tif (!is_our_ref(o))\n \t\t\tdie(\"git upload-pack: not our ref %s\",\n \t\t\t    oid_to_hex(&o->oid));\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288908","messageId":"20160610122714.3341-26-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 25/27] upload-pack: split check_unreachable() in two, prep for get_reachable_list()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:12Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n upload-pack.c | 44 +++++++++++++++++++++++++++++++-------------\n 1 file changed, 31 insertions(+), 13 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 3f40fcb..5942f99 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -452,23 +452,23 @@ static int is_our_ref(struct object *o)\n \treturn o->flags & ((allow_hidden_ref ? HIDDEN_REF : 0) | OUR_REF);\n }\n \n-static int check_unreachable(struct object_array *src)\n+static int do_reachable_revlist(struct child_process *cmd,\n+\t\t\t\tstruct object_array *src)\n {\n \tstatic const char *argv[] = {\n \t\t\"rev-list\", \"--stdin\", NULL,\n \t};\n-\tstatic struct child_process cmd = CHILD_PROCESS_INIT;\n \tstruct object *o;\n \tchar namebuf[42]; /* ^ + SHA-1 + LF */\n \tint i;\n \n-\tcmd.argv = argv;\n-\tcmd.git_cmd = 1;\n-\tcmd.no_stderr = 1;\n-\tcmd.in = -1;\n-\tcmd.out = -1;\n+\tcmd->argv = argv;\n+\tcmd->git_cmd = 1;\n+\tcmd->no_stderr = 1;\n+\tcmd->in = -1;\n+\tcmd->out = -1;\n \n-\tif (start_command(&cmd))\n+\tif (start_command(cmd))\n \t\tgoto error;\n \n \t/*\n@@ -487,7 +487,7 @@ static int check_unreachable(struct object_array *src)\n \t\tif (!is_our_ref(o))\n \t\t\tcontinue;\n \t\tmemcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n-\t\tif (write_in_full(cmd.in, namebuf, 42) < 0) {\n+\t\tif (write_in_full(cmd->in, namebuf, 42) < 0) {\n \t\t\tsigchain_pop(SIGPIPE);\n \t\t\tgoto error;\n \t\t}\n@@ -498,21 +498,39 @@ static int check_unreachable(struct object_array *src)\n \t\tif (is_our_ref(o))\n \t\t\tcontinue;\n \t\tmemcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n-\t\tif (write_in_full(cmd.in, namebuf, 41) < 0) {\n+\t\tif (write_in_full(cmd->in, namebuf, 41) < 0) {\n \t\t\tsigchain_pop(SIGPIPE);\n \t\t\tgoto error;\n \t\t}\n \t}\n-\tclose(cmd.in);\n-\tcmd.in = -1;\n+\tclose(cmd->in);\n+\tcmd->in = -1;\n \n \tsigchain_pop(SIGPIPE);\n+\treturn 0;\n+\n+error:\n+\tif (cmd->in >= 0)\n+\t\tclose(cmd->in);\n+\tif (cmd->out >= 0)\n+\t\tclose(cmd->out);\n+\treturn -1;\n+}\n+\n+static int check_unreachable(struct object_array *src)\n+{\n+\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\tchar buf[1];\n+\tint i;\n+\n+\tif (do_reachable_revlist(&cmd, src) < 0)\n+\t\treturn 0;\n \n \t/*\n \t * The commits out of the rev-list are not ancestors of\n \t * our ref.\n \t */\n-\ti = read_in_full(cmd.out, namebuf, 1);\n+\ti = read_in_full(cmd.out, buf, 1);\n \tif (i)\n \t\tgoto error;\n \tclose(cmd.out);\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288909","messageId":"20160610122714.3341-17-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 16/27] upload-pack: add deepen-since to cut shallow repos based on time","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:03Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This should allow the user to say \"create a shallow clone containing the\nwork from last year\" (once the client side is fixed up, of course).\n\nIn theory deepen-since and deepen (aka --depth) can be used together to\ndraw the shallow boundary (whether it's intersection or union is up to\ndiscussion, but if rev-list is used, it's likely intersection). However,\nbecause deepen goes with a custom commit walker, we can't mix the two\nyet.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/technical/pack-protocol.txt         |  3 +-\n Documentation/technical/protocol-capabilities.txt |  9 +++++\n upload-pack.c                                     | 45 ++++++++++++++++++++++-\n 3 files changed, 54 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt\nindex c6977bb..9251df1 100644\n--- a/Documentation/technical/pack-protocol.txt\n+++ b/Documentation/technical/pack-protocol.txt\n@@ -219,7 +219,8 @@ out of what the server said it could do with the first 'want' line.\n \n   shallow-line      =  PKT-LINE(\"shallow\" SP obj-id)\n \n-  depth-request     =  PKT-LINE(\"deepen\" SP depth)\n+  depth-request     =  PKT-LINE(\"deepen\" SP depth) /\n+\t\t       PKT-LINE(\"deepen-since\" SP timestamp)\n \n   first-want        =  PKT-LINE(\"want\" SP obj-id SP capability-list)\n   additional-want   =  PKT-LINE(\"want\" SP obj-id)\ndiff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt\nindex eaab6b4..f08cc4e 100644\n--- a/Documentation/technical/protocol-capabilities.txt\n+++ b/Documentation/technical/protocol-capabilities.txt\n@@ -179,6 +179,15 @@ This capability adds \"deepen\", \"shallow\" and \"unshallow\" commands to\n the  fetch-pack/upload-pack protocol so clients can request shallow\n clones.\n \n+deepen-since\n+------------\n+\n+This capability adds \"deepen-since\" command to fetch-pack/upload-pack\n+protocol so the client can request shallow clones that are cut at a\n+specific time, instead of depth. Internally it's equivalent of doing\n+\"rev-list --max-age=<timestamp>\" on the server side. \"deepen-since\"\n+cannot be used with \"deepen\".\n+\n no-progress\n -----------\n \ndiff --git a/upload-pack.c b/upload-pack.c\nindex b6f3756..b0ddfff 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -14,6 +14,7 @@\n #include \"sigchain.h\"\n #include \"version.h\"\n #include \"string-list.h\"\n+#include \"argv-array.h\"\n \n static const char upload_pack_usage[] = \"git upload-pack [--strict] [--timeout=<n>] <dir>\";\n \n@@ -627,11 +628,25 @@ static void deepen(int depth, const struct object_array *shallows)\n \tpacket_flush(1);\n }\n \n+static void deepen_by_rev_list(int ac, const char **av,\n+\t\t\t       struct object_array *shallows)\n+{\n+\tstruct commit_list *result;\n+\n+\tresult = get_shallow_commits_by_rev_list(ac, av, SHALLOW, NOT_SHALLOW);\n+\tsend_shallow(result);\n+\tfree_commit_list(result);\n+\tsend_unshallow(shallows);\n+\tpacket_flush(1);\n+}\n+\n static void receive_needs(void)\n {\n \tstruct object_array shallows = OBJECT_ARRAY_INIT;\n \tint depth = 0;\n \tint has_non_tip = 0;\n+\tunsigned long deepen_since = 0;\n+\tint deepen_rev_list = 0;\n \n \tshallow_nr = 0;\n \tfor (;;) {\n@@ -668,6 +683,16 @@ static void receive_needs(void)\n \t\t\t\tdie(\"Invalid deepen: %s\", line);\n \t\t\tcontinue;\n \t\t}\n+\t\tif (skip_prefix(line, \"deepen-since \", &arg)) {\n+\t\t\tchar *end = NULL;\n+\t\t\tdeepen_since = strtoul(arg, &end, 0);\n+\t\t\tif (!end || *end || !deepen_since ||\n+\t\t\t    /* revisions.c's max_age -1 is special */\n+\t\t\t    deepen_since == -1)\n+\t\t\t\tdie(\"Invalid deepen-since: %s\", line);\n+\t\t\tdeepen_rev_list = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!skip_prefix(line, \"want \", &arg) ||\n \t\t    get_sha1_hex(arg, sha1_buf))\n \t\t\tdie(\"git upload-pack: protocol error, \"\n@@ -719,10 +744,26 @@ static void receive_needs(void)\n \tif (!use_sideband && daemon_mode)\n \t\tno_progress = 1;\n \n-\tif (depth == 0 && shallows.nr == 0)\n+\tif (depth == 0 && !deepen_rev_list && shallows.nr == 0)\n \t\treturn;\n+\tif (depth > 0 && deepen_rev_list)\n+\t\tdie(\"git upload-pack: deepen and deepen-since cannot be used together\");\n \tif (depth > 0)\n \t\tdeepen(depth, &shallows);\n+\telse if (deepen_rev_list) {\n+\t\tstruct argv_array av = ARGV_ARRAY_INIT;\n+\t\tint i;\n+\n+\t\targv_array_push(&av, \"rev-list\");\n+\t\tif (deepen_since)\n+\t\t\targv_array_pushf(&av, \"--max-age=%lu\", deepen_since);\n+\t\tfor (i = 0; i < want_obj.nr; i++) {\n+\t\t\tstruct object *o = want_obj.objects[i].item;\n+\t\t\targv_array_push(&av, oid_to_hex(&o->oid));\n+\t\t}\n+\t\tdeepen_by_rev_list(av.argc, av.argv, &shallows);\n+\t\targv_array_clear(&av);\n+\t}\n \telse\n \t\tif (shallows.nr > 0) {\n \t\t\tint i;\n@@ -771,7 +812,7 @@ static int send_ref(const char *refname, const struct object_id *oid,\n \t\t    int flag, void *cb_data)\n {\n \tstatic const char *capabilities = \"multi_ack thin-pack side-band\"\n-\t\t\" side-band-64k ofs-delta shallow no-progress\"\n+\t\t\" side-band-64k ofs-delta shallow deepen-since no-progress\"\n \t\t\" include-tag multi_ack_detailed\";\n \tconst char *refname_nons = strip_namespace(refname);\n \tstruct object_id peeled;\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288910","messageId":"20160610122714.3341-18-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 17/27] fetch: define shallow boundary with --shallow-since","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:04Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/fetch-options.txt     |  4 ++++\n Documentation/git-fetch-pack.txt    |  4 ++++\n Documentation/gitremote-helpers.txt |  3 +++\n builtin/fetch-pack.c                |  4 ++++\n builtin/fetch.c                     | 29 +++++++++++++++++++++++------\n fetch-pack.c                        | 12 +++++++++++-\n fetch-pack.h                        |  1 +\n remote-curl.c                       | 11 +++++++++--\n transport.c                         |  4 ++++\n transport.h                         |  4 ++++\n 10 files changed, 67 insertions(+), 9 deletions(-)\n\ndiff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\nindex 952dfdf..8738d3d 100644\n--- a/Documentation/fetch-options.txt\n+++ b/Documentation/fetch-options.txt\n@@ -14,6 +14,10 @@\n \tlinkgit:git-clone[1]), deepen or shorten the history to the specified\n \tnumber of commits. Tags for the deepened commits are not fetched.\n \n+--shallow-since=<date>::\n+\tDeepen or shorten the history of a shallow repository to\n+\tinclude all reachable commits after <date>.\n+\n --unshallow::\n \tIf the source repository is complete, convert a shallow\n \trepository to a complete one, removing all the limitations\ndiff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt\nindex 8680f45..99e6257 100644\n--- a/Documentation/git-fetch-pack.txt\n+++ b/Documentation/git-fetch-pack.txt\n@@ -87,6 +87,10 @@ be in a separate packet, and the list must end with a flush packet.\n \t'git-upload-pack' treats the special depth 2147483647 as\n \tinfinite even if there is an ancestor-chain that long.\n \n+--shallow-since=<date>::\n+\tDeepen or shorten the history of a shallow'repository to\n+\tinclude all reachable commits after <date>.\n+\n --no-progress::\n \tDo not show the progress.\n \ndiff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt\nindex 78e0b27..9971d9a 100644\n--- a/Documentation/gitremote-helpers.txt\n+++ b/Documentation/gitremote-helpers.txt\n@@ -415,6 +415,9 @@ set by Git if the remote helper has the 'option' capability.\n 'option depth' <depth>::\n \tDeepens the history of a shallow repository.\n \n+'option deepen-since <timestamp>::\n+\tDeepens the history of a shallow repository based on time.\n+\n 'option followtags' {'true'|'false'}::\n \tIf enabled the helper should automatically fetch annotated\n \ttag objects if the object the tag points at was transferred\ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex 8332d3d..0402e27 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -104,6 +104,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \t\t\targs.depth = strtol(arg, NULL, 0);\n \t\t\tcontinue;\n \t\t}\n+\t\tif (skip_prefix(arg, \"--shallow-since=\", &arg)) {\n+\t\t\targs.deepen_since = xstrdup(arg);\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(\"--no-progress\", arg)) {\n \t\t\targs.no_progress = 1;\n \t\t\tcontinue;\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 8e74213..283aa95 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -36,9 +36,10 @@ static int prune = -1; /* unspecified */\n \n static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity;\n static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n-static int tags = TAGS_DEFAULT, unshallow, update_shallow;\n+static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;\n static int max_children = 1;\n static const char *depth;\n+static const char *deepen_since;\n static const char *upload_pack;\n static struct strbuf default_rla = STRBUF_INIT;\n static struct transport *gtransport;\n@@ -115,6 +116,8 @@ static struct option builtin_fetch_options[] = {\n \tOPT_BOOL(0, \"progress\", &progress, N_(\"force progress reporting\")),\n \tOPT_STRING(0, \"depth\", &depth, N_(\"depth\"),\n \t\t   N_(\"deepen history of shallow clone\")),\n+\tOPT_STRING(0, \"shallow-since\", &deepen_since, N_(\"time\"),\n+\t\t   N_(\"deepen history of shallow repository based on time\")),\n \t{ OPTION_SET_INT, 0, \"unshallow\", &unshallow, NULL,\n \t\t   N_(\"convert to a complete repository\"),\n \t\t   PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 },\n@@ -754,7 +757,7 @@ static int quickfetch(struct ref *ref_map)\n \t * really need to perform.  Claiming failure now will ensure\n \t * we perform the network exchange to deepen our history.\n \t */\n-\tif (depth)\n+\tif (deepen)\n \t\treturn -1;\n \treturn check_everything_connected(iterate_ref_map, 1, &rm);\n }\n@@ -859,7 +862,7 @@ static void set_option(struct transport *transport, const char *name, const char\n \t\t\tname, transport->url);\n }\n \n-static struct transport *prepare_transport(struct remote *remote)\n+static struct transport *prepare_transport(struct remote *remote, int deepen)\n {\n \tstruct transport *transport;\n \ttransport = transport_get(remote, NULL);\n@@ -870,6 +873,8 @@ static struct transport *prepare_transport(struct remote *remote)\n \t\tset_option(transport, TRANS_OPT_KEEP, \"yes\");\n \tif (depth)\n \t\tset_option(transport, TRANS_OPT_DEPTH, depth);\n+\tif (deepen && deepen_since)\n+\t\tset_option(transport, TRANS_OPT_DEEPEN_SINCE, deepen_since);\n \tif (update_shallow)\n \t\tset_option(transport, TRANS_OPT_UPDATE_SHALLOW, \"yes\");\n \treturn transport;\n@@ -877,8 +882,18 @@ static struct transport *prepare_transport(struct remote *remote)\n \n static void backfill_tags(struct transport *transport, struct ref *ref_map)\n {\n-\tif (transport->cannot_reuse) {\n-\t\tgsecondary = prepare_transport(transport->remote);\n+\tint cannot_reuse;\n+\n+\t/*\n+\t * Once we have set TRANS_OPT_DEEPEN_SINCE, we can't unset it\n+\t * when remote helper is used (setting it to an empty string\n+\t * is not unsetting). We could extend the remote helper\n+\t * protocol for that, but for now, just force a new connection\n+\t * without deepen-since.\n+\t */\n+\tcannot_reuse = transport->cannot_reuse || deepen_since;\n+\tif (cannot_reuse) {\n+\t\tgsecondary = prepare_transport(transport->remote, 0);\n \t\ttransport = gsecondary;\n \t}\n \n@@ -1095,7 +1110,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)\n \t\tdie(_(\"No remote repository specified.  Please, specify either a URL or a\\n\"\n \t\t    \"remote name from which new revisions should be fetched.\"));\n \n-\tgtransport = prepare_transport(remote);\n+\tgtransport = prepare_transport(remote, 1);\n \n \tif (prune < 0) {\n \t\t/* no command line request */\n@@ -1167,6 +1182,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n \t/* no need to be strict, transport_set_option() will validate it again */\n \tif (depth && atoi(depth) < 1)\n \t\tdie(_(\"depth %s is not a positive number\"), depth);\n+\tif (depth || deepen_since)\n+\t\tdeepen = 1;\n \n \tif (recurse_submodules != RECURSE_SUBMODULES_OFF) {\n \t\tif (recurse_submodules_default) {\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex a14d24a..a2f25c1 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -21,6 +21,7 @@ static int fetch_unpack_limit = -1;\n static int unpack_limit = 100;\n static int prefer_ofs_delta = 1;\n static int no_done;\n+static int deepen_since_ok;\n static int fetch_fsck_objects = -1;\n static int transfer_fsck_objects = -1;\n static int agent_supported;\n@@ -326,6 +327,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\tif (args->no_progress)   strbuf_addstr(&c, \" no-progress\");\n \t\t\tif (args->include_tag)   strbuf_addstr(&c, \" include-tag\");\n \t\t\tif (prefer_ofs_delta)   strbuf_addstr(&c, \" ofs-delta\");\n+\t\t\tif (deepen_since_ok)    strbuf_addstr(&c, \" deepen-since\");\n \t\t\tif (agent_supported)    strbuf_addf(&c, \" agent=%s\",\n \t\t\t\t\t\t\t    git_user_agent_sanitized());\n \t\t\tpacket_buf_write(&req_buf, \"want %s%s\\n\", remote_hex, c.buf);\n@@ -345,6 +347,10 @@ static int find_common(struct fetch_pack_args *args,\n \t\twrite_shallow_commits(&req_buf, 1, NULL);\n \tif (args->depth > 0)\n \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n+\tif (args->deepen_since) {\n+\t\tunsigned long max_age = approxidate(args->deepen_since);\n+\t\tpacket_buf_write(&req_buf, \"deepen-since %lu\", max_age);\n+\t}\n \tpacket_buf_flush(&req_buf);\n \tstate_len = req_buf.len;\n \n@@ -812,7 +818,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \n \tif ((args->depth > 0 || is_repository_shallow()) && !server_supports(\"shallow\"))\n \t\tdie(_(\"Server does not support shallow clients\"));\n-\tif (args->depth > 0)\n+\tif (args->depth > 0 || args->deepen_since)\n \t\targs->deepen = 1;\n \tif (server_supports(\"multi_ack_detailed\")) {\n \t\tprint_verbose(args, _(\"Server supports multi_ack_detailed\"));\n@@ -860,6 +866,10 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t\t\tprint_verbose(args, _(\"Server version is %.*s\"),\n \t\t\t\t      agent_len, agent_feature);\n \t}\n+\tif (server_supports(\"deepen-since\"))\n+\t\tdeepen_since_ok = 1;\n+\telse if (args->deepen_since)\n+\t\tdie(_(\"Server does not support --shallow-since\"));\n \n \tif (everything_local(args, &ref, sought, nr_sought)) {\n \t\tpacket_flush(fd[1]);\ndiff --git a/fetch-pack.h b/fetch-pack.h\nindex 4d0adb0..f7eadb2 100644\n--- a/fetch-pack.h\n+++ b/fetch-pack.h\n@@ -10,6 +10,7 @@ struct fetch_pack_args {\n \tconst char *uploadpack;\n \tint unpacklimit;\n \tint depth;\n+\tconst char *deepen_since;\n \tunsigned quiet:1;\n \tunsigned keep_pack:1;\n \tunsigned lock_pack:1;\ndiff --git a/remote-curl.c b/remote-curl.c\nindex fd030c1..5876f24 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -20,6 +20,7 @@ static struct strbuf url = STRBUF_INIT;\n struct options {\n \tint verbosity;\n \tunsigned long depth;\n+\tchar *deepen_since;\n \tunsigned progress : 1,\n \t\tcheck_self_contained_and_connected : 1,\n \t\tcloning : 1,\n@@ -60,6 +61,10 @@ static int set_option(const char *name, const char *value)\n \t\toptions.depth = v;\n \t\treturn 0;\n \t}\n+\telse if (!strcmp(name, \"deepen-since\")) {\n+\t\toptions.deepen_since = xstrdup(value);\n+\t\treturn 0;\n+\t}\n \telse if (!strcmp(name, \"followtags\")) {\n \t\tif (!strcmp(value, \"true\"))\n \t\t\toptions.followtags = 1;\n@@ -699,8 +704,8 @@ static int fetch_dumb(int nr_heads, struct ref **to_fetch)\n \tchar **targets = xmalloc(nr_heads * sizeof(char*));\n \tint ret, i;\n \n-\tif (options.depth)\n-\t\tdie(\"dumb http transport does not support --depth\");\n+\tif (options.depth || options.deepen_since)\n+\t\tdie(\"dumb http transport does not support shallow capabilities\");\n \tfor (i = 0; i < nr_heads; i++)\n \t\ttargets[i] = xstrdup(oid_to_hex(&to_fetch[i]->old_oid));\n \n@@ -746,6 +751,8 @@ static int fetch_git(struct discovery *heads,\n \t\targv_array_push(&args, \"--no-progress\");\n \tif (options.depth)\n \t\targv_array_pushf(&args, \"--depth=%lu\", options.depth);\n+\tif (options.deepen_since)\n+\t\targv_array_pushf(&args, \"--shallow-since=%s\", options.deepen_since);\n \targv_array_push(&args, url.buf);\n \n \tfor (i = 0; i < nr_heads; i++) {\ndiff --git a/transport.c b/transport.c\nindex c92f8ae..f04a302 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -151,6 +151,9 @@ static int set_git_option(struct git_transport_options *opts,\n \t\t\t\tdie(\"transport: invalid depth option '%s'\", value);\n \t\t}\n \t\treturn 0;\n+\t} else if (!strcmp(name, TRANS_OPT_DEEPEN_SINCE)) {\n+\t\topts->deepen_since = value;\n+\t\treturn 0;\n \t}\n \treturn 1;\n }\n@@ -205,6 +208,7 @@ static int fetch_refs_via_pack(struct transport *transport,\n \targs.quiet = (transport->verbose < 0);\n \targs.no_progress = !transport->progress;\n \targs.depth = data->options.depth;\n+\targs.deepen_since = data->options.deepen_since;\n \targs.check_self_contained_and_connected =\n \t\tdata->options.check_self_contained_and_connected;\n \targs.cloning = transport->cloning;\ndiff --git a/transport.h b/transport.h\nindex 8ebaaf2..9c10a44 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -13,6 +13,7 @@ struct git_transport_options {\n \tunsigned self_contained_and_connected : 1;\n \tunsigned update_shallow : 1;\n \tint depth;\n+\tconst char *deepen_since;\n \tconst char *uploadpack;\n \tconst char *receivepack;\n \tstruct push_cas_option *cas;\n@@ -171,6 +172,9 @@ int transport_restrict_protocols(void);\n /* Limit the depth of the fetch if not null */\n #define TRANS_OPT_DEPTH \"depth\"\n \n+/* Limit the depth of the fetch based on time if not null */\n+#define TRANS_OPT_DEEPEN_SINCE \"deepen-since\"\n+\n /* Aggressively fetch annotated tags if possible */\n #define TRANS_OPT_FOLLOWTAGS \"followtags\"\n \n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288911","messageId":"20160610122714.3341-19-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 18/27] clone: define shallow clone boundary based on time with --shallow-since","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:05Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-clone.txt |  3 +++\n builtin/clone.c             | 16 +++++++++++++---\n 2 files changed, 16 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt\nindex b7c467a..a410409 100644\n--- a/Documentation/git-clone.txt\n+++ b/Documentation/git-clone.txt\n@@ -193,6 +193,9 @@ objects from the source repository into a pack in the cloned repository.\n \t`--no-single-branch` is given to fetch the histories near the\n \ttips of all branches.\n \n+--shallow-since=<date>::\n+\tCreate a shallow clone with a history after the specified time.\n+\n --[no-]single-branch::\n \tClone only the history leading to the tip of a single branch,\n \teither specified by the `--branch` option or the primary\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex bcba080..dc2ef4f 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -40,7 +40,8 @@ static const char * const builtin_clone_usage[] = {\n \n static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;\n static int option_local = -1, option_no_hardlinks, option_shared, option_recursive;\n-static char *option_template, *option_depth;\n+static int deepen;\n+static char *option_template, *option_depth, *option_since;\n static char *option_origin = NULL;\n static char *option_branch = NULL;\n static const char *real_git_dir;\n@@ -86,6 +87,8 @@ static struct option builtin_clone_options[] = {\n \t\t   N_(\"path to git-upload-pack on the remote\")),\n \tOPT_STRING(0, \"depth\", &option_depth, N_(\"depth\"),\n \t\t    N_(\"create a shallow clone of that depth\")),\n+\tOPT_STRING(0, \"shallow-since\", &option_since, N_(\"time\"),\n+\t\t    N_(\"create a shallow clone since a specific time\")),\n \tOPT_BOOL(0, \"single-branch\", &option_single_branch,\n \t\t    N_(\"clone only one branch, HEAD or --branch\")),\n \tOPT_STRING(0, \"separate-git-dir\", &real_git_dir, N_(\"gitdir\"),\n@@ -849,8 +852,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\tusage_msg_opt(_(\"You must specify a repository to clone.\"),\n \t\t\tbuiltin_clone_usage, builtin_clone_options);\n \n+\tif (option_depth || option_since)\n+\t\tdeepen = 1;\n \tif (option_single_branch == -1)\n-\t\toption_single_branch = option_depth ? 1 : 0;\n+\t\toption_single_branch = deepen ? 1 : 0;\n \n \tif (option_mirror)\n \t\toption_bare = 1;\n@@ -976,6 +981,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \tif (is_local) {\n \t\tif (option_depth)\n \t\t\twarning(_(\"--depth is ignored in local clones; use file:// instead.\"));\n+\t\tif (option_since)\n+\t\t\twarning(_(\"--shallow-since is ignored in local clones; use file:// instead.\"));\n \t\tif (!access(mkpath(\"%s/shallow\", path), F_OK)) {\n \t\t\tif (option_local > 0)\n \t\t\t\twarning(_(\"source repository is shallow, ignoring --local\"));\n@@ -994,6 +1001,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \tif (option_depth)\n \t\ttransport_set_option(transport, TRANS_OPT_DEPTH,\n \t\t\t\t     option_depth);\n+\tif (option_since)\n+\t\ttransport_set_option(transport, TRANS_OPT_DEEPEN_SINCE,\n+\t\t\t\t     option_since);\n \tif (option_single_branch)\n \t\ttransport_set_option(transport, TRANS_OPT_FOLLOWTAGS, \"1\");\n \n@@ -1001,7 +1011,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\ttransport_set_option(transport, TRANS_OPT_UPLOADPACK,\n \t\t\t\t     option_upload_pack);\n \n-\tif (transport->smart_options && !option_depth)\n+\tif (transport->smart_options && !deepen)\n \t\ttransport->smart_options->check_self_contained_and_connected = 1;\n \n \trefs = transport_get_remote_refs(transport);\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288912","messageId":"20160610122714.3341-25-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 24/27] t5500, t5539: tests for shallow depth excluding a ref","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:11Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n t/t5500-fetch-pack.sh         | 21 +++++++++++++++++++++\n t/t5539-fetch-http-shallow.sh | 22 ++++++++++++++++++++++\n 2 files changed, 43 insertions(+)\n\ndiff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh\nindex 26f050d..145b370 100755\n--- a/t/t5500-fetch-pack.sh\n+++ b/t/t5500-fetch-pack.sh\n@@ -661,4 +661,25 @@ test_expect_success 'fetch shallow since ...' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'shallow clone exclude tag two' '\n+\ttest_create_repo shallow-exclude &&\n+\t(\n+\tcd shallow-exclude &&\n+\ttest_commit one &&\n+\ttest_commit two &&\n+\ttest_commit three &&\n+\tgit clone --shallow-exclude two \"file://$(pwd)/.\" ../shallow12 &&\n+\tgit -C ../shallow12 log --pretty=tformat:%s HEAD >actual &&\n+\techo three >expected &&\n+\ttest_cmp expected actual\n+\t)\n+'\n+\n+test_expect_success 'fetch exclude tag one' '\n+\tgit -C shallow12 fetch --shallow-exclude one origin &&\n+\tgit -C shallow12 log --pretty=tformat:%s origin/master >actual &&\n+\ttest_write_lines three two >expected &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\ndiff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh\nindex 704753c..8e38c1b 100755\n--- a/t/t5539-fetch-http-shallow.sh\n+++ b/t/t5539-fetch-http-shallow.sh\n@@ -98,5 +98,27 @@ test_expect_success 'fetch shallow since ...' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'shallow clone exclude tag two' '\n+\ttest_create_repo shallow-exclude &&\n+\t(\n+\tcd shallow-exclude &&\n+\ttest_commit one &&\n+\ttest_commit two &&\n+\ttest_commit three &&\n+\tmv .git \"$HTTPD_DOCUMENT_ROOT_PATH/shallow-exclude.git\" &&\n+\tgit clone --shallow-exclude two $HTTPD_URL/smart/shallow-exclude.git ../shallow12 &&\n+\tgit -C ../shallow12 log --pretty=tformat:%s HEAD >actual &&\n+\techo three >expected &&\n+\ttest_cmp expected actual\n+\t)\n+'\n+\n+test_expect_success 'fetch exclude tag one' '\n+\tgit -C shallow12 fetch --shallow-exclude one origin &&\n+\tgit -C shallow12 log --pretty=tformat:%s origin/master >actual &&\n+\ttest_write_lines three two >expected &&\n+\ttest_cmp expected actual\n+'\n+\n stop_httpd\n test_done\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288913","messageId":"20160610122714.3341-24-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 23/27] clone: define shallow clone boundary with --shallow-exclude","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:10Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-clone.txt |  5 +++++\n builtin/clone.c             | 10 +++++++++-\n 2 files changed, 14 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt\nindex a410409..5049663 100644\n--- a/Documentation/git-clone.txt\n+++ b/Documentation/git-clone.txt\n@@ -196,6 +196,11 @@ objects from the source repository into a pack in the cloned repository.\n --shallow-since=<date>::\n \tCreate a shallow clone with a history after the specified time.\n \n+--shallow-exclude=<revision>::\n+\tCreate a shallow clone with a history, excluding commits\n+\treachable from a specified remote branch or tag.  This option\n+\tcan be specified multiple times.\n+\n --[no-]single-branch::\n \tClone only the history leading to the tip of a single branch,\n \teither specified by the `--branch` option or the primary\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex dc2ef4f..3849231 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -44,6 +44,7 @@ static int deepen;\n static char *option_template, *option_depth, *option_since;\n static char *option_origin = NULL;\n static char *option_branch = NULL;\n+static struct string_list option_not = STRING_LIST_INIT_NODUP;\n static const char *real_git_dir;\n static char *option_upload_pack = \"git-upload-pack\";\n static int option_verbosity;\n@@ -89,6 +90,8 @@ static struct option builtin_clone_options[] = {\n \t\t    N_(\"create a shallow clone of that depth\")),\n \tOPT_STRING(0, \"shallow-since\", &option_since, N_(\"time\"),\n \t\t    N_(\"create a shallow clone since a specific time\")),\n+\tOPT_STRING_LIST(0, \"shallow-exclude\", &option_not, N_(\"revision\"),\n+\t\t\tN_(\"deepen history of shallow clone by excluding rev\")),\n \tOPT_BOOL(0, \"single-branch\", &option_single_branch,\n \t\t    N_(\"clone only one branch, HEAD or --branch\")),\n \tOPT_STRING(0, \"separate-git-dir\", &real_git_dir, N_(\"gitdir\"),\n@@ -852,7 +855,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\tusage_msg_opt(_(\"You must specify a repository to clone.\"),\n \t\t\tbuiltin_clone_usage, builtin_clone_options);\n \n-\tif (option_depth || option_since)\n+\tif (option_depth || option_since || option_not.nr)\n \t\tdeepen = 1;\n \tif (option_single_branch == -1)\n \t\toption_single_branch = deepen ? 1 : 0;\n@@ -983,6 +986,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\t\twarning(_(\"--depth is ignored in local clones; use file:// instead.\"));\n \t\tif (option_since)\n \t\t\twarning(_(\"--shallow-since is ignored in local clones; use file:// instead.\"));\n+\t\tif (option_not.nr)\n+\t\t\twarning(_(\"--shallow-exclude is ignored in local clones; use file:// instead.\"));\n \t\tif (!access(mkpath(\"%s/shallow\", path), F_OK)) {\n \t\t\tif (option_local > 0)\n \t\t\t\twarning(_(\"source repository is shallow, ignoring --local\"));\n@@ -1004,6 +1009,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \tif (option_since)\n \t\ttransport_set_option(transport, TRANS_OPT_DEEPEN_SINCE,\n \t\t\t\t     option_since);\n+\tif (option_not.nr)\n+\t\ttransport_set_option(transport, TRANS_OPT_DEEPEN_NOT,\n+\t\t\t\t     (const char *)&option_not);\n \tif (option_single_branch)\n \t\ttransport_set_option(transport, TRANS_OPT_FOLLOWTAGS, \"1\");\n \n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288914","messageId":"20160610122714.3341-22-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 21/27] upload-pack: support define shallow boundary by excluding revisions","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:08Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This should allow the user to say \"create a shallow clone of this branch\nafter version <some-tag>\".\n\nShort refs are accepted and expanded at the server side with expand_ref()\nbecause we cannot expand (unknown) refs from the client side.\n\nLike deepen-since, deepen-not cannot be used with deepen. But deepen-not\ncan be mixed with deepen-since. The result is exactly how you do the\ncommand \"git rev-list --since=... --not ref\".\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/technical/pack-protocol.txt         |  3 ++-\n Documentation/technical/protocol-capabilities.txt |  9 +++++++++\n upload-pack.c                                     | 23 +++++++++++++++++++++--\n 3 files changed, 32 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt\nindex 9251df1..dee33a6 100644\n--- a/Documentation/technical/pack-protocol.txt\n+++ b/Documentation/technical/pack-protocol.txt\n@@ -220,7 +220,8 @@ out of what the server said it could do with the first 'want' line.\n   shallow-line      =  PKT-LINE(\"shallow\" SP obj-id)\n \n   depth-request     =  PKT-LINE(\"deepen\" SP depth) /\n-\t\t       PKT-LINE(\"deepen-since\" SP timestamp)\n+\t\t       PKT-LINE(\"deepen-since\" SP timestamp) /\n+\t\t       PKT-LINE(\"deepen-not\" SP ref)\n \n   first-want        =  PKT-LINE(\"want\" SP obj-id SP capability-list)\n   additional-want   =  PKT-LINE(\"want\" SP obj-id)\ndiff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt\nindex f08cc4e..0e6b57d 100644\n--- a/Documentation/technical/protocol-capabilities.txt\n+++ b/Documentation/technical/protocol-capabilities.txt\n@@ -188,6 +188,15 @@ specific time, instead of depth. Internally it's equivalent of doing\n \"rev-list --max-age=<timestamp>\" on the server side. \"deepen-since\"\n cannot be used with \"deepen\".\n \n+deepen-not\n+----------\n+\n+This capability adds \"deepen-not\" command to fetch-pack/upload-pack\n+protocol so the client can request shallow clones that are cut at a\n+specific revision, instead of depth. Internally it's equivalent of\n+doing \"rev-list --not <rev>\" on the server side. \"deepen-not\"\n+cannot be used with \"deepen\", but can be used with \"deepen-since\".\n+\n no-progress\n -----------\n \ndiff --git a/upload-pack.c b/upload-pack.c\nindex b0ddfff..3f40fcb 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -643,6 +643,7 @@ static void deepen_by_rev_list(int ac, const char **av,\n static void receive_needs(void)\n {\n \tstruct object_array shallows = OBJECT_ARRAY_INIT;\n+\tstruct string_list deepen_not = STRING_LIST_INIT_DUP;\n \tint depth = 0;\n \tint has_non_tip = 0;\n \tunsigned long deepen_since = 0;\n@@ -693,6 +694,16 @@ static void receive_needs(void)\n \t\t\tdeepen_rev_list = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (skip_prefix(line, \"deepen-not \", &arg)) {\n+\t\t\tchar *ref = NULL;\n+\t\t\tunsigned char sha1[20];\n+\t\t\tif (expand_ref(arg, strlen(arg), sha1, &ref) != 1)\n+\t\t\t\tdie(\"git upload-pack: ambiguous deepen-not: %s\", line);\n+\t\t\tstring_list_append(&deepen_not, ref);\n+\t\t\tfree(ref);\n+\t\t\tdeepen_rev_list = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!skip_prefix(line, \"want \", &arg) ||\n \t\t    get_sha1_hex(arg, sha1_buf))\n \t\t\tdie(\"git upload-pack: protocol error, \"\n@@ -747,7 +758,7 @@ static void receive_needs(void)\n \tif (depth == 0 && !deepen_rev_list && shallows.nr == 0)\n \t\treturn;\n \tif (depth > 0 && deepen_rev_list)\n-\t\tdie(\"git upload-pack: deepen and deepen-since cannot be used together\");\n+\t\tdie(\"git upload-pack: deepen and deepen-since (or deepen-not) cannot be used together\");\n \tif (depth > 0)\n \t\tdeepen(depth, &shallows);\n \telse if (deepen_rev_list) {\n@@ -757,6 +768,14 @@ static void receive_needs(void)\n \t\targv_array_push(&av, \"rev-list\");\n \t\tif (deepen_since)\n \t\t\targv_array_pushf(&av, \"--max-age=%lu\", deepen_since);\n+\t\tif (deepen_not.nr) {\n+\t\t\targv_array_push(&av, \"--not\");\n+\t\t\tfor (i = 0; i < deepen_not.nr; i++) {\n+\t\t\t\tstruct string_list_item *s = deepen_not.items + i;\n+\t\t\t\targv_array_push(&av, s->string);\n+\t\t\t}\n+\t\t\targv_array_push(&av, \"--not\");\n+\t\t}\n \t\tfor (i = 0; i < want_obj.nr; i++) {\n \t\t\tstruct object *o = want_obj.objects[i].item;\n \t\t\targv_array_push(&av, oid_to_hex(&o->oid));\n@@ -812,7 +831,7 @@ static int send_ref(const char *refname, const struct object_id *oid,\n \t\t    int flag, void *cb_data)\n {\n \tstatic const char *capabilities = \"multi_ack thin-pack side-band\"\n-\t\t\" side-band-64k ofs-delta shallow deepen-since no-progress\"\n+\t\t\" side-band-64k ofs-delta shallow deepen-since deepen-not no-progress\"\n \t\t\" include-tag multi_ack_detailed\";\n \tconst char *refname_nons = strip_namespace(refname);\n \tstruct object_id peeled;\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288915","messageId":"20160610122714.3341-27-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 26/27] upload-pack: add get_reachable_list()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:13Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n object.h      |  2 +-\n upload-pack.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++---\n 2 files changed, 50 insertions(+), 4 deletions(-)\n\ndiff --git a/object.h b/object.h\nindex f8b6442..614a006 100644\n--- a/object.h\n+++ b/object.h\n@@ -31,7 +31,7 @@ struct object_array {\n  * revision.h:      0---------10                                26\n  * fetch-pack.c:    0---4\n  * walker.c:        0-2\n- * upload-pack.c:               11----------------19\n+ * upload-pack.c:       4       11----------------19\n  * builtin/blame.c:               12-13\n  * bisect.c:                               16\n  * bundle.c:                               16\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 5942f99..1d4f914 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -453,7 +453,8 @@ static int is_our_ref(struct object *o)\n }\n \n static int do_reachable_revlist(struct child_process *cmd,\n-\t\t\t\tstruct object_array *src)\n+\t\t\t\tstruct object_array *src,\n+\t\t\t\tstruct object_array *reachable)\n {\n \tstatic const char *argv[] = {\n \t\t\"rev-list\", \"--stdin\", NULL,\n@@ -484,6 +485,8 @@ static int do_reachable_revlist(struct child_process *cmd,\n \t\to = get_indexed_object(--i);\n \t\tif (!o)\n \t\t\tcontinue;\n+\t\tif (reachable && o->type == OBJ_COMMIT)\n+\t\t\to->flags &= ~TMP_MARK;\n \t\tif (!is_our_ref(o))\n \t\t\tcontinue;\n \t\tmemcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n@@ -495,8 +498,13 @@ static int do_reachable_revlist(struct child_process *cmd,\n \tnamebuf[40] = '\\n';\n \tfor (i = 0; i < src->nr; i++) {\n \t\to = src->objects[i].item;\n-\t\tif (is_our_ref(o))\n+\t\tif (is_our_ref(o)) {\n+\t\t\tif (reachable)\n+\t\t\t\tadd_object_array(o, NULL, reachable);\n \t\t\tcontinue;\n+\t\t}\n+\t\tif (reachable && o->type == OBJ_COMMIT)\n+\t\t\to->flags |= TMP_MARK;\n \t\tmemcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n \t\tif (write_in_full(cmd->in, namebuf, 41) < 0) {\n \t\t\tsigchain_pop(SIGPIPE);\n@@ -517,13 +525,51 @@ error:\n \treturn -1;\n }\n \n+static int get_reachable_list(struct object_array *src,\n+\t\t\t      struct object_array *reachable)\n+{\n+\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\tint i, ret = do_reachable_revlist(&cmd, src, reachable);\n+\tstruct object *o;\n+\tchar namebuf[42]; /* ^ + SHA-1 + LF */\n+\n+\tif (ret < 0)\n+\t\treturn -1;\n+\n+\twhile ((i = read_in_full(cmd.out, namebuf, 41)) == 41) {\n+\t\tstruct object_id sha1;\n+\n+\t\tif (namebuf[40] != '\\n' || get_oid_hex(namebuf, &sha1))\n+\t\t\tbreak;\n+\n+\t\to = lookup_object(sha1.hash);\n+\t\tif (o && o->type == OBJ_COMMIT) {\n+\t\t\to->flags &= ~TMP_MARK;\n+\t\t}\n+\t}\n+\tfor (i = get_max_object_index(); 0 < i; i--) {\n+\t\to = get_indexed_object(i - 1);\n+\t\tif (o && o->type == OBJ_COMMIT &&\n+\t\t    (o->flags & TMP_MARK)) {\n+\t\t\tadd_object_array(o, NULL, reachable);\n+\t\t\t\to->flags &= ~TMP_MARK;\n+\t\t}\n+\t}\n+\tclose(cmd.out);\n+\n+\tif (finish_command(&cmd))\n+\t\treturn -1;\n+\n+\treturn 0;\n+}\n+\n static int check_unreachable(struct object_array *src)\n {\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n \tchar buf[1];\n \tint i;\n \n-\tif (do_reachable_revlist(&cmd, src) < 0)\n+\tif (do_reachable_revlist(&cmd, src, NULL) < 0)\n \t\treturn 0;\n \n \t/*\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288916","messageId":"20160610122714.3341-28-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 27/27] fetch, upload-pack: --deepen=N extends shallow boundary by N commits","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:14Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"In git-fetch, --depth argument is always relative with the latest\nremote refs. This makes it a bit difficult to cover this use case,\nwhere the user wants to make the shallow history, say 3 levels\ndeeper. It would work if remote refs have not moved yet, but nobody\ncan guarantee that, especially when that use case is performed a\ncouple months after the last clone or \"git fetch --depth\". Also,\nmodifying shallow boundary using --depth does not work well with\nclones created by --since or --not.\n\nThis patch fixes that. A new argument --deepen=<N> will add <N> more (*)\nparent commits to the current history regardless of where remote refs\nare.\n\nHave/Want negotiation is still respected. So if remote refs move, the\nserver will send two chunks: one between \"have\" and \"want\" and another\nto extend shallow history. In theory, the client could send no \"want\"s\nin order to get the second chunk only. But the protocol does not allow\nthat. Either you send no want lines, which means ls-remote; or you\nhave to send at least one want line that carries deep-relative to the\nserver..\n\nThe main work was done by Dongcan Jiang. I fixed it up here and there.\nAnd of course all the bugs belong to me.\n\n(*) We could even support --deepen=<N> where <N> is negative. In that\ncase we can cut some history from the shallow clone. This operation\n(and --depth=<shorter depth>) does not require interaction with remote\nside (and more complicated to implement as a result).\n\nHelped-by: Duy Nguyen <pclouds@gmail.com>\nHelped-by: Eric Sunshine <sunshine@sunshineco.com>\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Dongcan Jiang <dongcan.jiang@gmail.com>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/fetch-options.txt                   |  5 +++++\n Documentation/git-fetch-pack.txt                  |  5 +++++\n Documentation/gitremote-helpers.txt               |  4 ++++\n Documentation/technical/protocol-capabilities.txt |  7 ++++++\n builtin/fetch-pack.c                              |  4 ++++\n builtin/fetch.c                                   | 14 +++++++++++-\n fetch-pack.c                                      |  3 +++\n fetch-pack.h                                      |  1 +\n remote-curl.c                                     | 14 +++++++++++-\n t/t5500-fetch-pack.sh                             | 23 ++++++++++++++++++++\n t/t5539-fetch-http-shallow.sh                     | 26 +++++++++++++++++++++++\n transport-helper.c                                |  1 +\n transport.c                                       |  4 ++++\n transport.h                                       |  4 ++++\n upload-pack.c                                     | 21 +++++++++++++-----\n 15 files changed, 129 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\nindex 7aa1285..3b91f15 100644\n--- a/Documentation/fetch-options.txt\n+++ b/Documentation/fetch-options.txt\n@@ -14,6 +14,11 @@\n \tlinkgit:git-clone[1]), deepen or shorten the history to the specified\n \tnumber of commits. Tags for the deepened commits are not fetched.\n \n+--deepen=<depth>::\n+\tSimilar to --depth, except it specifies the number of commits\n+\tfrom the current shallow boundary instead of from the tip of\n+\teach remote branch history.\n+\n --shallow-since=<date>::\n \tDeepen or shorten the history of a shallow repository to\n \tinclude all reachable commits after <date>.\ndiff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt\nindex 4d15b04..c20958f 100644\n--- a/Documentation/git-fetch-pack.txt\n+++ b/Documentation/git-fetch-pack.txt\n@@ -96,6 +96,11 @@ be in a separate packet, and the list must end with a flush packet.\n \texclude commits reachable from a specified remote branch or tag.\n \tThis option can be specified multiple times.\n \n+--deepen-relative::\n+\tArgument --depth specifies the number of commits from the\n+\tcurrent shallow boundary instead of from the tip of each\n+\tremote branch history.\n+\n --no-progress::\n \tDo not show the progress.\n \ndiff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt\nindex 75bb638..6fca268 100644\n--- a/Documentation/gitremote-helpers.txt\n+++ b/Documentation/gitremote-helpers.txt\n@@ -422,6 +422,10 @@ set by Git if the remote helper has the 'option' capability.\n \tDeepens the history of a shallow repository excluding ref.\n \tMultiple options add up.\n \n+'option deepen-relative {'true'|'false'}::\n+\tDeepens the history of a shallow repository relative to\n+\tcurrent boundary. Only valid when used with \"option depth\".\n+\n 'option followtags' {'true'|'false'}::\n \tIf enabled the helper should automatically fetch annotated\n \ttag objects if the object the tag points at was transferred\ndiff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt\nindex 0e6b57d..4fd6dcc 100644\n--- a/Documentation/technical/protocol-capabilities.txt\n+++ b/Documentation/technical/protocol-capabilities.txt\n@@ -197,6 +197,13 @@ specific revision, instead of depth. Internally it's equivalent of\n doing \"rev-list --not <rev>\" on the server side. \"deepen-not\"\n cannot be used with \"deepen\", but can be used with \"deepen-since\".\n \n+deepen-relative\n+---------------\n+\n+If this capability is requested by the client, the semantics of\n+\"deepen\" command is changed. The \"depth\" argument is the depth from\n+the current shallow boundary, instead of the depth from remote refs.\n+\n no-progress\n -----------\n \ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex 07570be..8265348 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -113,6 +113,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \t\t\tstring_list_append(&deepen_not, arg);\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--deepen-relative\")) {\n+\t\t\targs.deepen_relative = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(\"--no-progress\", arg)) {\n \t\t\targs.no_progress = 1;\n \t\t\tcontinue;\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 147504d..7b0ea1c 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -34,7 +34,7 @@ static int fetch_prune_config = -1; /* unspecified */\n static int prune = -1; /* unspecified */\n #define PRUNE_BY_DEFAULT 0 /* do we prune by default? */\n \n-static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity;\n+static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative;\n static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;\n static int max_children = 1;\n@@ -121,6 +121,8 @@ static struct option builtin_fetch_options[] = {\n \t\t   N_(\"deepen history of shallow repository based on time\")),\n \tOPT_STRING_LIST(0, \"shallow-exclude\", &deepen_not, N_(\"revision\"),\n \t\t\tN_(\"deepen history of shallow clone by excluding rev\")),\n+\tOPT_INTEGER(0, \"deepen\", &deepen_relative,\n+\t\t    N_(\"deepen history of shallow clone\")),\n \t{ OPTION_SET_INT, 0, \"unshallow\", &unshallow, NULL,\n \t\t   N_(\"convert to a complete repository\"),\n \t\t   PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 },\n@@ -881,6 +883,8 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)\n \tif (deepen && deepen_not.nr)\n \t\tset_option(transport, TRANS_OPT_DEEPEN_NOT,\n \t\t\t   (const char *)&deepen_not);\n+\tif (deepen_relative)\n+\t\tset_option(transport, TRANS_OPT_DEEPEN_RELATIVE, \"yes\");\n \tif (update_shallow)\n \t\tset_option(transport, TRANS_OPT_UPDATE_SHALLOW, \"yes\");\n \treturn transport;\n@@ -906,6 +910,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)\n \n \ttransport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);\n \ttransport_set_option(transport, TRANS_OPT_DEPTH, \"0\");\n+\ttransport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);\n \tfetch_refs(transport, ref_map);\n \n \tif (gsecondary) {\n@@ -1177,6 +1182,13 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix,\n \t\t\t     builtin_fetch_options, builtin_fetch_usage, 0);\n \n+\tif (deepen_relative) {\n+\t\tif (deepen_relative < 0)\n+\t\t\tdie(_(\"Negative depth in --deepen is not supported\"));\n+\t\tif (depth)\n+\t\t\tdie(_(\"--deepen and --depth are mutually exclusive\"));\n+\t\tdepth = xstrfmt(\"%d\", deepen_relative);\n+\t}\n \tif (unshallow) {\n \t\tif (depth)\n \t\t\tdie(_(\"--depth and --unshallow cannot be used together\"));\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex ad7d00f..e2a235f 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -324,6 +324,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\tif (no_done)            strbuf_addstr(&c, \" no-done\");\n \t\t\tif (use_sideband == 2)  strbuf_addstr(&c, \" side-band-64k\");\n \t\t\tif (use_sideband == 1)  strbuf_addstr(&c, \" side-band\");\n+\t\t\tif (args->deepen_relative) strbuf_addstr(&c, \" deepen-relative\");\n \t\t\tif (args->use_thin_pack) strbuf_addstr(&c, \" thin-pack\");\n \t\t\tif (args->no_progress)   strbuf_addstr(&c, \" no-progress\");\n \t\t\tif (args->include_tag)   strbuf_addstr(&c, \" include-tag\");\n@@ -883,6 +884,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t\tdeepen_not_ok = 1;\n \telse if (args->deepen_not)\n \t\tdie(_(\"Server does not support --shallow-exclude\"));\n+\tif (!server_supports(\"deepen-relative\") && args->deepen_relative)\n+\t\tdie(_(\"Server does not support --deepen\"));\n \n \tif (everything_local(args, &ref, sought, nr_sought)) {\n \t\tpacket_flush(fd[1]);\ndiff --git a/fetch-pack.h b/fetch-pack.h\nindex 144301f..c912e3d 100644\n--- a/fetch-pack.h\n+++ b/fetch-pack.h\n@@ -12,6 +12,7 @@ struct fetch_pack_args {\n \tint depth;\n \tconst char *deepen_since;\n \tconst struct string_list *deepen_not;\n+\tunsigned deepen_relative:1;\n \tunsigned quiet:1;\n \tunsigned keep_pack:1;\n \tunsigned lock_pack:1;\ndiff --git a/remote-curl.c b/remote-curl.c\nindex 1406e6a..d56412d 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -30,7 +30,8 @@ struct options {\n \t\tdry_run : 1,\n \t\tthin : 1,\n \t\t/* One of the SEND_PACK_PUSH_CERT_* constants. */\n-\t\tpush_cert : 2;\n+\t\tpush_cert : 2,\n+\t\tdeepen_relative : 1;\n };\n static struct options options;\n static struct string_list cas_options = STRING_LIST_INIT_DUP;\n@@ -70,6 +71,15 @@ static int set_option(const char *name, const char *value)\n \t\tstring_list_append(&options.deepen_not, value);\n \t\treturn 0;\n \t}\n+\telse if (!strcmp(name, \"deepen-relative\")) {\n+\t\tif (!strcmp(value, \"true\"))\n+\t\t\toptions.deepen_relative = 1;\n+\t\telse if (!strcmp(value, \"false\"))\n+\t\t\toptions.deepen_relative = 0;\n+\t\telse\n+\t\t\treturn -1;\n+\t\treturn 0;\n+\t}\n \telse if (!strcmp(name, \"followtags\")) {\n \t\tif (!strcmp(value, \"true\"))\n \t\t\toptions.followtags = 1;\n@@ -761,6 +771,8 @@ static int fetch_git(struct discovery *heads,\n \tfor (i = 0; i < options.deepen_not.nr; i++)\n \t\targv_array_pushf(&args, \"--shallow-exclude=%s\",\n \t\t\t\t options.deepen_not.items[i].string);\n+\tif (options.deepen_relative && options.depth)\n+\t\targv_array_push(&args, \"--deepen-relative\");\n \targv_array_push(&args, url.buf);\n \n \tfor (i = 0; i < nr_heads; i++) {\ndiff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh\nindex 145b370..a908036 100755\n--- a/t/t5500-fetch-pack.sh\n+++ b/t/t5500-fetch-pack.sh\n@@ -682,4 +682,27 @@ test_expect_success 'fetch exclude tag one' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'fetching deepen' '\n+\ttest_create_repo shallow-deepen &&\n+\t(\n+\tcd shallow-deepen &&\n+\ttest_commit one &&\n+\ttest_commit two &&\n+\ttest_commit three &&\n+\tgit clone --depth 1 \"file://$(pwd)/.\" deepen &&\n+\ttest_commit four &&\n+\tgit -C deepen log --pretty=tformat:%s master >actual &&\n+\techo three >expected &&\n+\ttest_cmp expected actual &&\n+\tgit -C deepen fetch --deepen=1 &&\n+\tgit -C deepen log --pretty=tformat:%s origin/master >actual &&\n+\tcat >expected <<-\\EOF &&\n+\tfour\n+\tthree\n+\ttwo\n+\tEOF\n+\ttest_cmp expected actual\n+\t)\n+'\n+\n test_done\ndiff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh\nindex 8e38c1b..5fbf67c 100755\n--- a/t/t5539-fetch-http-shallow.sh\n+++ b/t/t5539-fetch-http-shallow.sh\n@@ -120,5 +120,31 @@ test_expect_success 'fetch exclude tag one' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'fetching deepen' '\n+\ttest_create_repo shallow-deepen &&\n+\t(\n+\tcd shallow-deepen &&\n+\ttest_commit one &&\n+\ttest_commit two &&\n+\ttest_commit three &&\n+\tmv .git \"$HTTPD_DOCUMENT_ROOT_PATH/shallow-deepen.git\" &&\n+\tgit clone --depth 1 $HTTPD_URL/smart/shallow-deepen.git deepen &&\n+\tmv \"$HTTPD_DOCUMENT_ROOT_PATH/shallow-deepen.git\" .git &&\n+\ttest_commit four &&\n+\tgit -C deepen log --pretty=tformat:%s master >actual &&\n+\techo three >expected &&\n+\ttest_cmp expected actual &&\n+\tmv .git \"$HTTPD_DOCUMENT_ROOT_PATH/shallow-deepen.git\" &&\n+\tgit -C deepen fetch --deepen=1 &&\n+\tgit -C deepen log --pretty=tformat:%s origin/master >actual &&\n+\tcat >expected <<-\\EOF &&\n+\tfour\n+\tthree\n+\ttwo\n+\tEOF\n+\ttest_cmp expected actual\n+\t)\n+'\n+\n stop_httpd\n test_done\ndiff --git a/transport-helper.c b/transport-helper.c\nindex cc1a396..a5cdd77 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -258,6 +258,7 @@ static const char *boolean_options[] = {\n \tTRANS_OPT_THIN,\n \tTRANS_OPT_KEEP,\n \tTRANS_OPT_FOLLOWTAGS,\n+\tTRANS_OPT_DEEPEN_RELATIVE\n \t};\n \n static int strbuf_set_helper_option(struct helper_data *data,\ndiff --git a/transport.c b/transport.c\nindex 3e6f3aa..3e76a9a 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -157,6 +157,9 @@ static int set_git_option(struct git_transport_options *opts,\n \t} else if (!strcmp(name, TRANS_OPT_DEEPEN_NOT)) {\n \t\topts->deepen_not = (const struct string_list *)value;\n \t\treturn 0;\n+\t} else if (!strcmp(name, TRANS_OPT_DEEPEN_RELATIVE)) {\n+\t\topts->deepen_relative = !!value;\n+\t\treturn 0;\n \t}\n \treturn 1;\n }\n@@ -213,6 +216,7 @@ static int fetch_refs_via_pack(struct transport *transport,\n \targs.depth = data->options.depth;\n \targs.deepen_since = data->options.deepen_since;\n \targs.deepen_not = data->options.deepen_not;\n+\targs.deepen_relative = data->options.deepen_relative;\n \targs.check_self_contained_and_connected =\n \t\tdata->options.check_self_contained_and_connected;\n \targs.cloning = transport->cloning;\ndiff --git a/transport.h b/transport.h\nindex ab61932..bdc3518 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -14,6 +14,7 @@ struct git_transport_options {\n \tunsigned check_self_contained_and_connected : 1;\n \tunsigned self_contained_and_connected : 1;\n \tunsigned update_shallow : 1;\n+\tunsigned deepen_relative : 1;\n \tint depth;\n \tconst char *deepen_since;\n \tconst struct string_list *deepen_not;\n@@ -181,6 +182,9 @@ int transport_restrict_protocols(void);\n /* Limit the depth of the fetch based on revs if not null */\n #define TRANS_OPT_DEEPEN_NOT \"deepen-not\"\n \n+/* Limit the deepen of the fetch if not null */\n+#define TRANS_OPT_DEEPEN_RELATIVE \"deepen-relative\"\n+\n /* Aggressively fetch annotated tags if possible */\n #define TRANS_OPT_FOLLOWTAGS \"followtags\"\n \ndiff --git a/upload-pack.c b/upload-pack.c\nindex 1d4f914..ef693bd 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -32,6 +32,7 @@ static const char upload_pack_usage[] = \"git upload-pack [--strict] [--timeout=<\n \n static unsigned long oldest_have;\n \n+static int deepen_relative;\n static int multi_ack;\n static int no_done;\n static int use_thin_pack, use_ofs_delta, use_include_tag;\n@@ -674,7 +675,8 @@ static void send_unshallow(const struct object_array *shallows)\n \t}\n }\n \n-static void deepen(int depth, const struct object_array *shallows)\n+static void deepen(int depth, int deepen_relative,\n+\t\t   struct object_array *shallows)\n {\n \tstruct commit_list *result = NULL;\n \tint i;\n@@ -683,7 +685,14 @@ static void deepen(int depth, const struct object_array *shallows)\n \t\t\tstruct object *object = shallows->objects[i].item;\n \t\t\tobject->flags |= NOT_SHALLOW;\n \t\t}\n-\telse\n+\telse if (deepen_relative) {\n+\t\tstruct object_array reachable_shallows = OBJECT_ARRAY_INIT;\n+\t\tget_reachable_list(shallows, &reachable_shallows);\n+\t\tresult = get_shallow_commits(&reachable_shallows,\n+\t\t\t\t\t     depth + 1,\n+\t\t\t\t\t     SHALLOW, NOT_SHALLOW);\n+\t\tobject_array_clear(&reachable_shallows);\n+\t} else\n \t\tresult = get_shallow_commits(&want_obj, depth,\n \t\t\t\t\t     SHALLOW, NOT_SHALLOW);\n \tsend_shallow(result);\n@@ -775,6 +784,8 @@ static void receive_needs(void)\n \n \t\tfeatures = arg + 40;\n \n+\t\tif (parse_feature_request(features, \"deepen-relative\"))\n+\t\t\tdeepen_relative = 1;\n \t\tif (parse_feature_request(features, \"multi_ack_detailed\"))\n \t\t\tmulti_ack = 2;\n \t\telse if (parse_feature_request(features, \"multi_ack\"))\n@@ -824,7 +835,7 @@ static void receive_needs(void)\n \tif (depth > 0 && deepen_rev_list)\n \t\tdie(\"git upload-pack: deepen and deepen-since (or deepen-not) cannot be used together\");\n \tif (depth > 0)\n-\t\tdeepen(depth, &shallows);\n+\t\tdeepen(depth, deepen_relative, &shallows);\n \telse if (deepen_rev_list) {\n \t\tstruct argv_array av = ARGV_ARRAY_INIT;\n \t\tint i;\n@@ -895,8 +906,8 @@ static int send_ref(const char *refname, const struct object_id *oid,\n \t\t    int flag, void *cb_data)\n {\n \tstatic const char *capabilities = \"multi_ack thin-pack side-band\"\n-\t\t\" side-band-64k ofs-delta shallow deepen-since deepen-not no-progress\"\n-\t\t\" include-tag multi_ack_detailed\";\n+\t\t\" side-band-64k ofs-delta shallow deepen-since deepen-not\"\n+\t\t\" deepen-relative no-progress include-tag multi_ack_detailed\";\n \tconst char *refname_nons = strip_namespace(refname);\n \tstruct object_id peeled;\n \n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288917","messageId":"20160610122714.3341-23-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 22/27] fetch: define shallow boundary with --shallow-exclude","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:09Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/fetch-options.txt     |  5 +++++\n Documentation/git-fetch-pack.txt    |  5 +++++\n Documentation/gitremote-helpers.txt |  4 ++++\n builtin/fetch-pack.c                |  7 +++++++\n builtin/fetch.c                     | 13 ++++++++++---\n fetch-pack.c                        | 15 ++++++++++++++-\n fetch-pack.h                        |  1 +\n remote-curl.c                       |  9 +++++++++\n transport-helper.c                  | 24 ++++++++++++++++++++++++\n transport.c                         |  4 ++++\n transport.h                         |  6 ++++++\n 11 files changed, 89 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\nindex 8738d3d..7aa1285 100644\n--- a/Documentation/fetch-options.txt\n+++ b/Documentation/fetch-options.txt\n@@ -18,6 +18,11 @@\n \tDeepen or shorten the history of a shallow repository to\n \tinclude all reachable commits after <date>.\n \n+--shallow-exclude=<revision>::\n+\tDeepen or shorten the history of a shallow repository to\n+\texclude commits reachable from a specified remote branch or tag.\n+\tThis option can be specified multiple times.\n+\n --unshallow::\n \tIf the source repository is complete, convert a shallow\n \trepository to a complete one, removing all the limitations\ndiff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt\nindex 99e6257..4d15b04 100644\n--- a/Documentation/git-fetch-pack.txt\n+++ b/Documentation/git-fetch-pack.txt\n@@ -91,6 +91,11 @@ be in a separate packet, and the list must end with a flush packet.\n \tDeepen or shorten the history of a shallow'repository to\n \tinclude all reachable commits after <date>.\n \n+--shallow-exclude=<revision>::\n+\tDeepen or shorten the history of a shallow repository to\n+\texclude commits reachable from a specified remote branch or tag.\n+\tThis option can be specified multiple times.\n+\n --no-progress::\n \tDo not show the progress.\n \ndiff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt\nindex 9971d9a..75bb638 100644\n--- a/Documentation/gitremote-helpers.txt\n+++ b/Documentation/gitremote-helpers.txt\n@@ -418,6 +418,10 @@ set by Git if the remote helper has the 'option' capability.\n 'option deepen-since <timestamp>::\n \tDeepens the history of a shallow repository based on time.\n \n+'option deepen-not <ref>::\n+\tDeepens the history of a shallow repository excluding ref.\n+\tMultiple options add up.\n+\n 'option followtags' {'true'|'false'}::\n \tIf enabled the helper should automatically fetch annotated\n \ttag objects if the object the tag points at was transferred\ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex 0402e27..07570be 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -50,6 +50,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \tstruct child_process *conn;\n \tstruct fetch_pack_args args;\n \tstruct sha1_array shallow = SHA1_ARRAY_INIT;\n+\tstruct string_list deepen_not = STRING_LIST_INIT_DUP;\n \n \tpacket_trace_identity(\"fetch-pack\");\n \n@@ -108,6 +109,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \t\t\targs.deepen_since = xstrdup(arg);\n \t\t\tcontinue;\n \t\t}\n+\t\tif (skip_prefix(arg, \"--shallow-exclude=\", &arg)) {\n+\t\t\tstring_list_append(&deepen_not, arg);\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(\"--no-progress\", arg)) {\n \t\t\targs.no_progress = 1;\n \t\t\tcontinue;\n@@ -135,6 +140,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \t\t}\n \t\tusage(fetch_pack_usage);\n \t}\n+\tif (deepen_not.nr)\n+\t\targs.deepen_not = &deepen_not;\n \n \tif (i < argc)\n \t\tdest = argv[i++];\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 283aa95..147504d 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -41,6 +41,7 @@ static int max_children = 1;\n static const char *depth;\n static const char *deepen_since;\n static const char *upload_pack;\n+static struct string_list deepen_not = STRING_LIST_INIT_NODUP;\n static struct strbuf default_rla = STRBUF_INIT;\n static struct transport *gtransport;\n static struct transport *gsecondary;\n@@ -118,6 +119,8 @@ static struct option builtin_fetch_options[] = {\n \t\t   N_(\"deepen history of shallow clone\")),\n \tOPT_STRING(0, \"shallow-since\", &deepen_since, N_(\"time\"),\n \t\t   N_(\"deepen history of shallow repository based on time\")),\n+\tOPT_STRING_LIST(0, \"shallow-exclude\", &deepen_not, N_(\"revision\"),\n+\t\t\tN_(\"deepen history of shallow clone by excluding rev\")),\n \t{ OPTION_SET_INT, 0, \"unshallow\", &unshallow, NULL,\n \t\t   N_(\"convert to a complete repository\"),\n \t\t   PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 },\n@@ -875,6 +878,9 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)\n \t\tset_option(transport, TRANS_OPT_DEPTH, depth);\n \tif (deepen && deepen_since)\n \t\tset_option(transport, TRANS_OPT_DEEPEN_SINCE, deepen_since);\n+\tif (deepen && deepen_not.nr)\n+\t\tset_option(transport, TRANS_OPT_DEEPEN_NOT,\n+\t\t\t   (const char *)&deepen_not);\n \tif (update_shallow)\n \t\tset_option(transport, TRANS_OPT_UPDATE_SHALLOW, \"yes\");\n \treturn transport;\n@@ -889,9 +895,10 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)\n \t * when remote helper is used (setting it to an empty string\n \t * is not unsetting). We could extend the remote helper\n \t * protocol for that, but for now, just force a new connection\n-\t * without deepen-since.\n+\t * without deepen-since. Similar story for deepen-not.\n \t */\n-\tcannot_reuse = transport->cannot_reuse || deepen_since;\n+\tcannot_reuse = transport->cannot_reuse ||\n+\t\tdeepen_since || deepen_not.nr;\n \tif (cannot_reuse) {\n \t\tgsecondary = prepare_transport(transport->remote, 0);\n \t\ttransport = gsecondary;\n@@ -1182,7 +1189,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n \t/* no need to be strict, transport_set_option() will validate it again */\n \tif (depth && atoi(depth) < 1)\n \t\tdie(_(\"depth %s is not a positive number\"), depth);\n-\tif (depth || deepen_since)\n+\tif (depth || deepen_since || deepen_not.nr)\n \t\tdeepen = 1;\n \n \tif (recurse_submodules != RECURSE_SUBMODULES_OFF) {\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex a2f25c1..ad7d00f 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -22,6 +22,7 @@ static int unpack_limit = 100;\n static int prefer_ofs_delta = 1;\n static int no_done;\n static int deepen_since_ok;\n+static int deepen_not_ok;\n static int fetch_fsck_objects = -1;\n static int transfer_fsck_objects = -1;\n static int agent_supported;\n@@ -328,6 +329,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\tif (args->include_tag)   strbuf_addstr(&c, \" include-tag\");\n \t\t\tif (prefer_ofs_delta)   strbuf_addstr(&c, \" ofs-delta\");\n \t\t\tif (deepen_since_ok)    strbuf_addstr(&c, \" deepen-since\");\n+\t\t\tif (deepen_not_ok)      strbuf_addstr(&c, \" deepen-not\");\n \t\t\tif (agent_supported)    strbuf_addf(&c, \" agent=%s\",\n \t\t\t\t\t\t\t    git_user_agent_sanitized());\n \t\t\tpacket_buf_write(&req_buf, \"want %s%s\\n\", remote_hex, c.buf);\n@@ -351,6 +353,13 @@ static int find_common(struct fetch_pack_args *args,\n \t\tunsigned long max_age = approxidate(args->deepen_since);\n \t\tpacket_buf_write(&req_buf, \"deepen-since %lu\", max_age);\n \t}\n+\tif (args->deepen_not) {\n+\t\tint i;\n+\t\tfor (i = 0; i < args->deepen_not->nr; i++) {\n+\t\t\tstruct string_list_item *s = args->deepen_not->items + i;\n+\t\t\tpacket_buf_write(&req_buf, \"deepen-not %s\", s->string);\n+\t\t}\n+\t}\n \tpacket_buf_flush(&req_buf);\n \tstate_len = req_buf.len;\n \n@@ -818,7 +827,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \n \tif ((args->depth > 0 || is_repository_shallow()) && !server_supports(\"shallow\"))\n \t\tdie(_(\"Server does not support shallow clients\"));\n-\tif (args->depth > 0 || args->deepen_since)\n+\tif (args->depth > 0 || args->deepen_since || args->deepen_not)\n \t\targs->deepen = 1;\n \tif (server_supports(\"multi_ack_detailed\")) {\n \t\tprint_verbose(args, _(\"Server supports multi_ack_detailed\"));\n@@ -870,6 +879,10 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t\tdeepen_since_ok = 1;\n \telse if (args->deepen_since)\n \t\tdie(_(\"Server does not support --shallow-since\"));\n+\tif (server_supports(\"deepen-not\"))\n+\t\tdeepen_not_ok = 1;\n+\telse if (args->deepen_not)\n+\t\tdie(_(\"Server does not support --shallow-exclude\"));\n \n \tif (everything_local(args, &ref, sought, nr_sought)) {\n \t\tpacket_flush(fd[1]);\ndiff --git a/fetch-pack.h b/fetch-pack.h\nindex f7eadb2..144301f 100644\n--- a/fetch-pack.h\n+++ b/fetch-pack.h\n@@ -11,6 +11,7 @@ struct fetch_pack_args {\n \tint unpacklimit;\n \tint depth;\n \tconst char *deepen_since;\n+\tconst struct string_list *deepen_not;\n \tunsigned quiet:1;\n \tunsigned keep_pack:1;\n \tunsigned lock_pack:1;\ndiff --git a/remote-curl.c b/remote-curl.c\nindex 5876f24..1406e6a 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -21,6 +21,7 @@ struct options {\n \tint verbosity;\n \tunsigned long depth;\n \tchar *deepen_since;\n+\tstruct string_list deepen_not;\n \tunsigned progress : 1,\n \t\tcheck_self_contained_and_connected : 1,\n \t\tcloning : 1,\n@@ -65,6 +66,10 @@ static int set_option(const char *name, const char *value)\n \t\toptions.deepen_since = xstrdup(value);\n \t\treturn 0;\n \t}\n+\telse if (!strcmp(name, \"deepen-not\")) {\n+\t\tstring_list_append(&options.deepen_not, value);\n+\t\treturn 0;\n+\t}\n \telse if (!strcmp(name, \"followtags\")) {\n \t\tif (!strcmp(value, \"true\"))\n \t\t\toptions.followtags = 1;\n@@ -753,6 +758,9 @@ static int fetch_git(struct discovery *heads,\n \t\targv_array_pushf(&args, \"--depth=%lu\", options.depth);\n \tif (options.deepen_since)\n \t\targv_array_pushf(&args, \"--shallow-since=%s\", options.deepen_since);\n+\tfor (i = 0; i < options.deepen_not.nr; i++)\n+\t\targv_array_pushf(&args, \"--shallow-exclude=%s\",\n+\t\t\t\t options.deepen_not.items[i].string);\n \targv_array_push(&args, url.buf);\n \n \tfor (i = 0; i < nr_heads; i++) {\n@@ -973,6 +981,7 @@ int main(int argc, const char **argv)\n \toptions.verbosity = 1;\n \toptions.progress = !!isatty(2);\n \toptions.thin = 1;\n+\tstring_list_init(&options.deepen_not, 1);\n \n \tremote = remote_get(argv[1]);\n \ndiff --git a/transport-helper.c b/transport-helper.c\nindex 27a34e9..cc1a396 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -282,6 +282,26 @@ static int strbuf_set_helper_option(struct helper_data *data,\n \treturn ret;\n }\n \n+static int string_list_set_helper_option(struct helper_data *data,\n+\t\t\t\t\t const char *name,\n+\t\t\t\t\t struct string_list *list)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint i, ret = 0;\n+\n+\tfor (i = 0; i < list->nr; i++) {\n+\t\tstrbuf_addf(&buf, \"option %s \", name);\n+\t\tquote_c_style(list->items[i].string, &buf, NULL, 0);\n+\t\tstrbuf_addch(&buf, '\\n');\n+\n+\t\tif ((ret = strbuf_set_helper_option(data, &buf)))\n+\t\t\tbreak;\n+\t\tstrbuf_reset(&buf);\n+\t}\n+\tstrbuf_release(&buf);\n+\treturn ret;\n+}\n+\n static int set_helper_option(struct transport *transport,\n \t\t\t  const char *name, const char *value)\n {\n@@ -294,6 +314,10 @@ static int set_helper_option(struct transport *transport,\n \tif (!data->option)\n \t\treturn 1;\n \n+\tif (!strcmp(name, \"deepen-not\"))\n+\t\treturn string_list_set_helper_option(data, name,\n+\t\t\t\t\t\t     (struct string_list *)value);\n+\n \tfor (i = 0; i < ARRAY_SIZE(unsupported_options); i++) {\n \t\tif (!strcmp(name, unsupported_options[i]))\n \t\t\treturn 1;\ndiff --git a/transport.c b/transport.c\nindex f04a302..3e6f3aa 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -154,6 +154,9 @@ static int set_git_option(struct git_transport_options *opts,\n \t} else if (!strcmp(name, TRANS_OPT_DEEPEN_SINCE)) {\n \t\topts->deepen_since = value;\n \t\treturn 0;\n+\t} else if (!strcmp(name, TRANS_OPT_DEEPEN_NOT)) {\n+\t\topts->deepen_not = (const struct string_list *)value;\n+\t\treturn 0;\n \t}\n \treturn 1;\n }\n@@ -209,6 +212,7 @@ static int fetch_refs_via_pack(struct transport *transport,\n \targs.no_progress = !transport->progress;\n \targs.depth = data->options.depth;\n \targs.deepen_since = data->options.deepen_since;\n+\targs.deepen_not = data->options.deepen_not;\n \targs.check_self_contained_and_connected =\n \t\tdata->options.check_self_contained_and_connected;\n \targs.cloning = transport->cloning;\ndiff --git a/transport.h b/transport.h\nindex 9c10a44..ab61932 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -5,6 +5,8 @@\n #include \"run-command.h\"\n #include \"remote.h\"\n \n+struct string_list;\n+\n struct git_transport_options {\n \tunsigned thin : 1;\n \tunsigned keep : 1;\n@@ -14,6 +16,7 @@ struct git_transport_options {\n \tunsigned update_shallow : 1;\n \tint depth;\n \tconst char *deepen_since;\n+\tconst struct string_list *deepen_not;\n \tconst char *uploadpack;\n \tconst char *receivepack;\n \tstruct push_cas_option *cas;\n@@ -175,6 +178,9 @@ int transport_restrict_protocols(void);\n /* Limit the depth of the fetch based on time if not null */\n #define TRANS_OPT_DEEPEN_SINCE \"deepen-since\"\n \n+/* Limit the depth of the fetch based on revs if not null */\n+#define TRANS_OPT_DEEPEN_NOT \"deepen-not\"\n+\n /* Aggressively fetch annotated tags if possible */\n #define TRANS_OPT_FOLLOWTAGS \"followtags\"\n \n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288918","messageId":"20160610122714.3341-15-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 14/27] fetch-pack: use a separate flag for fetch in deepening mode","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:01Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The shallow repo could be deepened or shortened when then user gives\n--depth. But in future that won't be the only way to deepen/shorten a\nrepo. Stop relying on args->depth in this mode. Future deepening\nmethods can simply set this flag on instead of updating all these if\nexpressions.\n\nThe new name \"deepen\" was chosen after the command to define shallow\nboundary in pack protocol. New commands also follow this tradition.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n fetch-pack.c | 14 ++++++++------\n fetch-pack.h |  1 +\n 2 files changed, 9 insertions(+), 6 deletions(-)\n\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 08caf1d..a14d24a 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -197,7 +197,7 @@ enum ack_type {\n \n static void consume_shallow_list(struct fetch_pack_args *args, int fd)\n {\n-\tif (args->stateless_rpc && args->depth > 0) {\n+\tif (args->stateless_rpc && args->deepen) {\n \t\t/* If we sent a depth we will get back \"duplicate\"\n \t\t * shallow and unshallow commands every time there\n \t\t * is a block of have lines exchanged.\n@@ -348,7 +348,7 @@ static int find_common(struct fetch_pack_args *args,\n \tpacket_buf_flush(&req_buf);\n \tstate_len = req_buf.len;\n \n-\tif (args->depth > 0) {\n+\tif (args->deepen) {\n \t\tchar *line;\n \t\tconst char *arg;\n \t\tunsigned char sha1[20];\n@@ -557,7 +557,7 @@ static void filter_refs(struct fetch_pack_args *args,\n \t\t}\n \n \t\tif (!keep && args->fetch_all &&\n-\t\t    (!args->depth || !starts_with(ref->name, \"refs/tags/\")))\n+\t\t    (!args->deepen || !starts_with(ref->name, \"refs/tags/\")))\n \t\t\tkeep = 1;\n \n \t\tif (keep) {\n@@ -627,7 +627,7 @@ static int everything_local(struct fetch_pack_args *args,\n \t\t}\n \t}\n \n-\tif (!args->depth) {\n+\tif (!args->deepen) {\n \t\tfor_each_ref(mark_complete_oid, NULL);\n \t\tfor_each_alternate_ref(mark_alternate_complete, NULL);\n \t\tcommit_list_sort_by_date(&complete);\n@@ -812,6 +812,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \n \tif ((args->depth > 0 || is_repository_shallow()) && !server_supports(\"shallow\"))\n \t\tdie(_(\"Server does not support shallow clients\"));\n+\tif (args->depth > 0)\n+\t\targs->deepen = 1;\n \tif (server_supports(\"multi_ack_detailed\")) {\n \t\tprint_verbose(args, _(\"Server supports multi_ack_detailed\"));\n \t\tmulti_ack = 2;\n@@ -872,7 +874,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \n \tif (args->stateless_rpc)\n \t\tpacket_flush(fd[1]);\n-\tif (args->depth > 0)\n+\tif (args->deepen)\n \t\tsetup_alternate_shallow(&shallow_lock, &alternate_shallow_file,\n \t\t\t\t\tNULL);\n \telse if (si->nr_ours || si->nr_theirs)\n@@ -939,7 +941,7 @@ static void update_shallow(struct fetch_pack_args *args,\n \tint *status;\n \tint i;\n \n-\tif (args->depth > 0 && alternate_shallow_file) {\n+\tif (args->deepen && alternate_shallow_file) {\n \t\tif (*alternate_shallow_file == '\\0') { /* --unshallow */\n \t\t\tunlink_or_warn(git_path_shallow());\n \t\t\trollback_lock_file(&shallow_lock);\ndiff --git a/fetch-pack.h b/fetch-pack.h\nindex bb7fd76..4d0adb0 100644\n--- a/fetch-pack.h\n+++ b/fetch-pack.h\n@@ -25,6 +25,7 @@ struct fetch_pack_args {\n \tunsigned self_contained_and_connected:1;\n \tunsigned cloning:1;\n \tunsigned update_shallow:1;\n+\tunsigned deepen:1;\n };\n \n /*\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288919","messageId":"20160610122714.3341-21-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 20/27] refs: add expand_ref()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:07Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is basically dwim_ref() without @{} support. To be used on the\nserver side where we want to expand abbreviated to full ref names and\nnothing else. The first user is \"git clone/fetch --shallow-exclude\".\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c | 8 +++++++-\n refs.h | 1 +\n 2 files changed, 8 insertions(+), 1 deletion(-)\n\ndiff --git a/refs.c b/refs.c\nindex e2d34b2..842e4d8 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -392,6 +392,13 @@ static char *substitute_branch_name(const char **string, int *len)\n int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)\n {\n \tchar *last_branch = substitute_branch_name(&str, &len);\n+\tint   refs_found  = expand_ref(str, len, sha1, ref);\n+\tfree(last_branch);\n+\treturn refs_found;\n+}\n+\n+int expand_ref(const char *str, int len, unsigned char *sha1, char **ref)\n+{\n \tconst char **p, *r;\n \tint refs_found = 0;\n \n@@ -417,7 +424,6 @@ int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)\n \t\t\twarning(\"ignoring broken ref %s.\", fullref);\n \t\t}\n \t}\n-\tfree(last_branch);\n \treturn refs_found;\n }\n \ndiff --git a/refs.h b/refs.h\nindex 3c3da29..31a2fa6 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -90,6 +90,7 @@ extern int resolve_gitlink_ref(const char *path, const char *refname, unsigned c\n  */\n extern int refname_match(const char *abbrev_name, const char *full_name);\n \n+extern int expand_ref(const char *str, int len, unsigned char *sha1, char **ref);\n extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);\n extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);\n \n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288920","messageId":"20160610122714.3341-20-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 19/27] t5500, t5539: tests for shallow depth since a specific date","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:06Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n t/t5500-fetch-pack.sh         | 24 ++++++++++++++++++++++++\n t/t5539-fetch-http-shallow.sh | 25 +++++++++++++++++++++++++\n 2 files changed, 49 insertions(+)\n\ndiff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh\nindex e5f83bf..26f050d 100755\n--- a/t/t5500-fetch-pack.sh\n+++ b/t/t5500-fetch-pack.sh\n@@ -637,4 +637,28 @@ test_expect_success MINGW 'fetch-pack --diag-url c:repo' '\n \tcheck_prot_path c:repo file c:repo\n '\n \n+test_expect_success 'clone shallow since ...' '\n+\ttest_create_repo shallow-since &&\n+\t(\n+\tcd shallow-since &&\n+\tGIT_COMMITTER_DATE=\"100000000 +0700\" git commit --allow-empty -m one &&\n+\tGIT_COMMITTER_DATE=\"200000000 +0700\" git commit --allow-empty -m two &&\n+\tGIT_COMMITTER_DATE=\"300000000 +0700\" git commit --allow-empty -m three &&\n+\tgit clone --shallow-since \"300000000 +0700\" \"file://$(pwd)/.\" ../shallow11 &&\n+\tgit -C ../shallow11 log --pretty=tformat:%s HEAD >actual &&\n+\techo three >expected &&\n+\ttest_cmp expected actual\n+\t)\n+'\n+\n+test_expect_success 'fetch shallow since ...' '\n+\tgit -C shallow11 fetch --shallow-since \"200000000 +0700\" origin &&\n+\tgit -C shallow11 log --pretty=tformat:%s origin/master >actual &&\n+\tcat >expected <<-\\EOF &&\n+\tthree\n+\ttwo\n+\tEOF\n+\ttest_cmp expected actual\n+'\n+\n test_done\ndiff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh\nindex 37a4335..704753c 100755\n--- a/t/t5539-fetch-http-shallow.sh\n+++ b/t/t5539-fetch-http-shallow.sh\n@@ -73,5 +73,30 @@ test_expect_success 'no shallow lines after receiving ACK ready' '\n \t)\n '\n \n+test_expect_success 'clone shallow since ...' '\n+\ttest_create_repo shallow-since &&\n+\t(\n+\tcd shallow-since &&\n+\tGIT_COMMITTER_DATE=\"100000000 +0700\" git commit --allow-empty -m one &&\n+\tGIT_COMMITTER_DATE=\"200000000 +0700\" git commit --allow-empty -m two &&\n+\tGIT_COMMITTER_DATE=\"300000000 +0700\" git commit --allow-empty -m three &&\n+\tmv .git \"$HTTPD_DOCUMENT_ROOT_PATH/shallow-since.git\" &&\n+\tgit clone --shallow-since \"300000000 +0700\" $HTTPD_URL/smart/shallow-since.git ../shallow11 &&\n+\tgit -C ../shallow11 log --pretty=tformat:%s HEAD >actual &&\n+\techo three >expected &&\n+\ttest_cmp expected actual\n+\t)\n+'\n+\n+test_expect_success 'fetch shallow since ...' '\n+\tgit -C shallow11 fetch --shallow-since \"200000000 +0700\" origin &&\n+\tgit -C shallow11 log --pretty=tformat:%s origin/master >actual &&\n+\tcat >expected <<-\\EOF &&\n+\tthree\n+\ttwo\n+\tEOF\n+\ttest_cmp expected actual\n+'\n+\n stop_httpd\n test_done\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288921","messageId":"20160610122714.3341-16-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 15/27] shallow.c: implement a generic shallow boundary finder based on rev-list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:02Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Instead of a custom commit walker like get_shallow_commits(), this new\nfunction uses rev-list to mark NOT_SHALLOW to all reachable commits,\nexcept borders. The definition of reachable is to be defined by the\nprotocol later. This makes it more flexible to define shallow boundary.\n\nThe way we find border is paint all reachable commits NOT_SHALLOW.  Any\nof them that \"touches\" commits without NOT_SHALLOW flag are considered\nshallow (e.g. zero parents via grafting mechanism). Shallow commits and\ntheir true parents are all marked SHALLOW. Then NOT_SHALLOW is removed\nfrom shallow commits at the end.\n\nThere is an interesting observation. With a generic walker, we can\nproduce all kinds of shallow cutting. In the following graph, every\ncommit but \"x\" is reachable. \"b\" is a parent of \"a\".\n\n           x -- a -- o\n          /    /\n    x -- c -- b -- o\n\nAfter this function is run, \"a\" and \"c\" are both considered shallow\ncommits. After grafting occurs at the client side, what we see is\n\n                a -- o\n                    /\n         c -- b -- o\n\nNotice that because of grafting, \"a\" has zero parents, so \"b\" is no\nlonger a parent of \"a\".\n\nThis is unfortunate and may be solved in two ways. The first is change\nthe way shallow grafting works and keep \"a -- b\" connection if \"b\"\nexists and always ends at shallow commits (iow, no loose ends). This is\nhard to detect, or at least not cheap to do.\n\nThe second way is mark one \"x\" as shallow commit instead of \"a\" and\nproduce this graph at client side:\n\n           x -- a -- o\n               /    /\n         c -- b -- o\n\nMore commits, but simpler grafting rules.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n commit.h  |  2 ++\n shallow.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 80 insertions(+)\n\ndiff --git a/commit.h b/commit.h\nindex 5d58be0..b717be1 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -258,6 +258,8 @@ extern int for_each_commit_graft(each_commit_graft_fn, void *);\n extern int is_repository_shallow(void);\n extern struct commit_list *get_shallow_commits(struct object_array *heads,\n \t\tint depth, int shallow_flag, int not_shallow_flag);\n+extern struct commit_list *get_shallow_commits_by_rev_list(\n+\t\tint ac, const char **av, int shallow_flag, int not_shallow_flag);\n extern void set_alternate_shallow_file(const char *path, int override);\n extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol,\n \t\t\t\t const struct sha1_array *extra);\ndiff --git a/shallow.c b/shallow.c\nindex 60f1505..40c2485 100644\n--- a/shallow.c\n+++ b/shallow.c\n@@ -10,6 +10,8 @@\n #include \"diff.h\"\n #include \"revision.h\"\n #include \"commit-slab.h\"\n+#include \"revision.h\"\n+#include \"list-objects.h\"\n \n static int is_shallow = -1;\n static struct stat_validity shallow_stat;\n@@ -137,6 +139,82 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,\n \treturn result;\n }\n \n+static void show_commit(struct commit *commit, void *data)\n+{\n+\tcommit_list_insert(commit, data);\n+}\n+\n+/*\n+ * Given rev-list arguments, run rev-list. All reachable commits\n+ * except border ones are marked with not_shallow_flag. Border commits\n+ * are marked with shallow_flag. The list of border/shallow commits\n+ * are also returned.\n+ */\n+struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av,\n+\t\t\t\t\t\t    int shallow_flag,\n+\t\t\t\t\t\t    int not_shallow_flag)\n+{\n+\tstruct commit_list *result = NULL, *p;\n+\tstruct commit_list *not_shallow_list = NULL;\n+\tstruct rev_info revs;\n+\tint both_flags = shallow_flag | not_shallow_flag;\n+\n+\t/*\n+\t * SHALLOW (excluded) and NOT_SHALLOW (included) should not be\n+\t * set at this point. But better be safe than sorry.\n+\t */\n+\tclear_object_flags(both_flags);\n+\n+\tis_repository_shallow(); /* make sure shallows are read */\n+\n+\tinit_revisions(&revs, NULL);\n+\tsave_commit_buffer = 0;\n+\tsetup_revisions(ac, av, &revs, NULL);\n+\n+\tif (prepare_revision_walk(&revs))\n+\t\tdie(\"revision walk setup failed\");\n+\ttraverse_commit_list(&revs, show_commit, NULL, &not_shallow_list);\n+\n+\t/* Mark all reachable commits as NOT_SHALLOW */\n+\tfor (p = not_shallow_list; p; p = p->next)\n+\t\tp->item->object.flags |= not_shallow_flag;\n+\n+\t/*\n+\t * mark border commits SHALLOW + NOT_SHALLOW.\n+\t * We cannot clear NOT_SHALLOW right now. Imagine border\n+\t * commit A is processed first, then commit B, whose parent is\n+\t * A, later. If NOT_SHALLOW on A is cleared at step 1, B\n+\t * itself is considered border at step 2, which is incorrect.\n+\t */\n+\tfor (p = not_shallow_list; p; p = p->next) {\n+\t\tstruct commit *c = p->item;\n+\t\tstruct commit_list *parent;\n+\n+\t\tif (parse_commit(c))\n+\t\t\tdie(\"unable to parse commit %s\",\n+\t\t\t    oid_to_hex(&c->object.oid));\n+\n+\t\tfor (parent = c->parents; parent; parent = parent->next)\n+\t\t\tif (!(parent->item->object.flags & not_shallow_flag)) {\n+\t\t\t\tc->object.flags |= shallow_flag;\n+\t\t\t\tcommit_list_insert(c, &result);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t}\n+\tfree_commit_list(not_shallow_list);\n+\n+\t/*\n+\t * Now we can clean up NOT_SHALLOW on border commits. Having\n+\t * both flags set can confuse the caller.\n+\t */\n+\tfor (p = result; p; p = p->next) {\n+\t\tstruct object *o = &p->item->object;\n+\t\tif ((o->flags & both_flags) == both_flags)\n+\t\t\to->flags &= ~not_shallow_flag;\n+\t}\n+\treturn result;\n+}\n+\n static void check_shallow_file_for_update(void)\n {\n \tif (is_shallow == -1)\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288922","messageId":"20160610122714.3341-14-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH 13/27] fetch-pack.c: mark strings for translating","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-10T12:27:00Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n fetch-pack.c | 75 ++++++++++++++++++++++++++++++------------------------------\n 1 file changed, 37 insertions(+), 38 deletions(-)\n\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 4020744..08caf1d 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -208,7 +208,7 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd)\n \t\t\t\tcontinue;\n \t\t\tif (starts_with(line, \"unshallow \"))\n \t\t\t\tcontinue;\n-\t\t\tdie(\"git fetch-pack: expected shallow list\");\n+\t\t\tdie(_(\"git fetch-pack: expected shallow list\"));\n \t\t}\n \t}\n }\n@@ -220,7 +220,7 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1)\n \tconst char *arg;\n \n \tif (!len)\n-\t\tdie(\"git fetch-pack: expected ACK/NAK, got EOF\");\n+\t\tdie(_(\"git fetch-pack: expected ACK/NAK, got EOF\"));\n \tif (!strcmp(line, \"NAK\"))\n \t\treturn NAK;\n \tif (skip_prefix(line, \"ACK \", &arg)) {\n@@ -238,7 +238,7 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1)\n \t\t\treturn ACK;\n \t\t}\n \t}\n-\tdie(\"git fetch_pack: expected ACK/NAK, got '%s'\", line);\n+\tdie(_(\"git fetch_pack: expected ACK/NAK, got '%s'\"), line);\n }\n \n static void send_request(struct fetch_pack_args *args,\n@@ -285,7 +285,7 @@ static int find_common(struct fetch_pack_args *args,\n \tsize_t state_len = 0;\n \n \tif (args->stateless_rpc && multi_ack == 1)\n-\t\tdie(\"--stateless-rpc requires multi_ack_detailed\");\n+\t\tdie(_(\"--stateless-rpc requires multi_ack_detailed\"));\n \tif (marked)\n \t\tfor_each_ref(clear_marks, NULL);\n \tmarked = 1;\n@@ -357,23 +357,23 @@ static int find_common(struct fetch_pack_args *args,\n \t\twhile ((line = packet_read_line(fd[0], NULL))) {\n \t\t\tif (skip_prefix(line, \"shallow \", &arg)) {\n \t\t\t\tif (get_sha1_hex(arg, sha1))\n-\t\t\t\t\tdie(\"invalid shallow line: %s\", line);\n+\t\t\t\t\tdie(_(\"invalid shallow line: %s\"), line);\n \t\t\t\tregister_shallow(sha1);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (skip_prefix(line, \"unshallow \", &arg)) {\n \t\t\t\tif (get_sha1_hex(arg, sha1))\n-\t\t\t\t\tdie(\"invalid unshallow line: %s\", line);\n+\t\t\t\t\tdie(_(\"invalid unshallow line: %s\"), line);\n \t\t\t\tif (!lookup_object(sha1))\n-\t\t\t\t\tdie(\"object not found: %s\", line);\n+\t\t\t\t\tdie(_(\"object not found: %s\"), line);\n \t\t\t\t/* make sure that it is parsed as shallow */\n \t\t\t\tif (!parse_object(sha1))\n-\t\t\t\t\tdie(\"error in object: %s\", line);\n+\t\t\t\t\tdie(_(\"error in object: %s\"), line);\n \t\t\t\tif (unregister_shallow(sha1))\n-\t\t\t\t\tdie(\"no shallow found: %s\", line);\n+\t\t\t\t\tdie(_(\"no shallow found: %s\"), line);\n \t\t\t\tcontinue;\n \t\t\t}\n-\t\t\tdie(\"expected shallow/unshallow, got %s\", line);\n+\t\t\tdie(_(\"expected shallow/unshallow, got %s\"), line);\n \t\t}\n \t} else if (!args->stateless_rpc)\n \t\tsend_request(args, fd[1], &req_buf);\n@@ -412,8 +412,8 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\tdo {\n \t\t\t\tack = get_ack(fd[0], result_sha1);\n \t\t\t\tif (ack)\n-\t\t\t\t\tprint_verbose(args, \"got ack %d %s\", ack,\n-\t\t\t\t\t\t      sha1_to_hex(result_sha1));\n+\t\t\t\t\tprint_verbose(args, _(\"got %s %d %s\"), \"ack\",\n+\t\t\t\t\t\t      ack, sha1_to_hex(result_sha1));\n \t\t\t\tswitch (ack) {\n \t\t\t\tcase ACK:\n \t\t\t\t\tflushes = 0;\n@@ -426,7 +426,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\t\t\tstruct commit *commit =\n \t\t\t\t\t\tlookup_commit(result_sha1);\n \t\t\t\t\tif (!commit)\n-\t\t\t\t\t\tdie(\"invalid commit %s\", sha1_to_hex(result_sha1));\n+\t\t\t\t\t\tdie(_(\"invalid commit %s\"), sha1_to_hex(result_sha1));\n \t\t\t\t\tif (args->stateless_rpc\n \t\t\t\t\t && ack == ACK_common\n \t\t\t\t\t && !(commit->object.flags & COMMON)) {\n@@ -452,7 +452,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\t} while (ack);\n \t\t\tflushes--;\n \t\t\tif (got_continue && MAX_IN_VAIN < in_vain) {\n-\t\t\t\tprint_verbose(args, \"giving up\");\n+\t\t\t\tprint_verbose(args, _(\"giving up\"));\n \t\t\t\tbreak; /* give up */\n \t\t\t}\n \t\t}\n@@ -462,7 +462,7 @@ done:\n \t\tpacket_buf_write(&req_buf, \"done\\n\");\n \t\tsend_request(args, fd[1], &req_buf);\n \t}\n-\tprint_verbose(args, \"done\");\n+\tprint_verbose(args, _(\"done\"));\n \tif (retval != 0) {\n \t\tmulti_ack = 0;\n \t\tflushes++;\n@@ -474,8 +474,8 @@ done:\n \twhile (flushes || multi_ack) {\n \t\tint ack = get_ack(fd[0], result_sha1);\n \t\tif (ack) {\n-\t\t\tprint_verbose(args, \"got ack (%d) %s\", ack,\n-\t\t\t\t      sha1_to_hex(result_sha1));\n+\t\t\tprint_verbose(args, _(\"got %s (%d) %s\"), \"ack\",\n+\t\t\t\t      ack, sha1_to_hex(result_sha1));\n \t\t\tif (ack == ACK)\n \t\t\t\treturn 0;\n \t\t\tmulti_ack = 1;\n@@ -520,7 +520,7 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args,\n \t\t\t\t\t unsigned long cutoff)\n {\n \twhile (complete && cutoff <= complete->item->date) {\n-\t\tprint_verbose(args, \"Marking %s as complete\",\n+\t\tprint_verbose(args, _(\"Marking %s as complete\"),\n \t\t\t      oid_to_hex(&complete->item->object.oid));\n \t\tpop_most_recent_commit(&complete, COMPLETE);\n \t}\n@@ -666,7 +666,7 @@ static int everything_local(struct fetch_pack_args *args,\n \t\t\t\t      ref->name);\n \t\t\tcontinue;\n \t\t}\n-\t\tprint_verbose(args, \"already have %s (%s)\", sha1_to_hex(remote),\n+\t\tprint_verbose(args, _(\"already have %s (%s)\"), sha1_to_hex(remote),\n \t\t\t      ref->name);\n \t}\n \treturn retval;\n@@ -702,8 +702,7 @@ static int get_pack(struct fetch_pack_args *args,\n \t\tdemux.data = xd;\n \t\tdemux.out = -1;\n \t\tif (start_async(&demux))\n-\t\t\tdie(\"fetch-pack: unable to fork off sideband\"\n-\t\t\t    \" demultiplexer\");\n+\t\t\tdie(_(\"fetch-pack: unable to fork off sideband demultiplexer\"));\n \t}\n \telse\n \t\tdemux.out = xd[0];\n@@ -711,7 +710,7 @@ static int get_pack(struct fetch_pack_args *args,\n \tif (!args->keep_pack && unpack_limit) {\n \n \t\tif (read_pack_header(demux.out, &header))\n-\t\t\tdie(\"protocol error: bad pack header\");\n+\t\t\tdie(_(\"protocol error: bad pack header\"));\n \t\tpass_header = 1;\n \t\tif (ntohl(header.hdr_entries) < unpack_limit)\n \t\t\tdo_keep = 0;\n@@ -767,7 +766,7 @@ static int get_pack(struct fetch_pack_args *args,\n \tcmd.in = demux.out;\n \tcmd.git_cmd = 1;\n \tif (start_command(&cmd))\n-\t\tdie(\"fetch-pack: unable to fork off %s\", cmd_name);\n+\t\tdie(_(\"fetch-pack: unable to fork off %s\"), cmd_name);\n \tif (do_keep && pack_lockfile) {\n \t\t*pack_lockfile = index_pack_lockfile(cmd.out);\n \t\tclose(cmd.out);\n@@ -783,9 +782,9 @@ static int get_pack(struct fetch_pack_args *args,\n \t\t\targs->check_self_contained_and_connected &&\n \t\t\tret == 0;\n \telse\n-\t\tdie(\"%s failed\", cmd_name);\n+\t\tdie(_(\"%s failed\"), cmd_name);\n \tif (use_sideband && finish_async(&demux))\n-\t\tdie(\"error in sideband demultiplexer\");\n+\t\tdie(_(\"error in sideband demultiplexer\"));\n \treturn 0;\n }\n \n@@ -812,34 +811,34 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \tqsort(sought, nr_sought, sizeof(*sought), cmp_ref_by_name);\n \n \tif ((args->depth > 0 || is_repository_shallow()) && !server_supports(\"shallow\"))\n-\t\tdie(\"Server does not support shallow clients\");\n+\t\tdie(_(\"Server does not support shallow clients\"));\n \tif (server_supports(\"multi_ack_detailed\")) {\n-\t\tprint_verbose(args, \"Server supports multi_ack_detailed\");\n+\t\tprint_verbose(args, _(\"Server supports multi_ack_detailed\"));\n \t\tmulti_ack = 2;\n \t\tif (server_supports(\"no-done\")) {\n-\t\t\tprint_verbose(args, \"Server supports no-done\");\n+\t\t\tprint_verbose(args, _(\"Server supports no-done\"));\n \t\t\tif (args->stateless_rpc)\n \t\t\t\tno_done = 1;\n \t\t}\n \t}\n \telse if (server_supports(\"multi_ack\")) {\n-\t\tprint_verbose(args, \"Server supports multi_ack\");\n+\t\tprint_verbose(args, _(\"Server supports multi_ack\"));\n \t\tmulti_ack = 1;\n \t}\n \tif (server_supports(\"side-band-64k\")) {\n-\t\tprint_verbose(args, \"Server supports side-band-64k\");\n+\t\tprint_verbose(args, _(\"Server supports side-band-64k\"));\n \t\tuse_sideband = 2;\n \t}\n \telse if (server_supports(\"side-band\")) {\n-\t\tprint_verbose(args, \"Server supports side-band\");\n+\t\tprint_verbose(args, _(\"Server supports side-band\"));\n \t\tuse_sideband = 1;\n \t}\n \tif (server_supports(\"allow-tip-sha1-in-want\")) {\n-\t\tprint_verbose(args, \"Server supports allow-tip-sha1-in-want\");\n+\t\tprint_verbose(args, _(\"Server supports allow-tip-sha1-in-want\"));\n \t\tallow_unadvertised_object_request |= ALLOW_TIP_SHA1;\n \t}\n \tif (server_supports(\"allow-reachable-sha1-in-want\")) {\n-\t\tprint_verbose(args, \"Server supports allow-reachable-sha1-in-want\");\n+\t\tprint_verbose(args, _(\"Server supports allow-reachable-sha1-in-want\"));\n \t\tallow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1;\n \t}\n \tif (!server_supports(\"thin-pack\"))\n@@ -849,14 +848,14 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \tif (!server_supports(\"include-tag\"))\n \t\targs->include_tag = 0;\n \tif (server_supports(\"ofs-delta\"))\n-\t\tprint_verbose(args, \"Server supports ofs-delta\");\n+\t\tprint_verbose(args, _(\"Server supports ofs-delta\"));\n \telse\n \t\tprefer_ofs_delta = 0;\n \n \tif ((agent_feature = server_feature_value(\"agent\", &agent_len))) {\n \t\tagent_supported = 1;\n \t\tif (agent_len)\n-\t\t\tprint_verbose(args, \"Server version is %.*s\",\n+\t\t\tprint_verbose(args, _(\"Server version is %.*s\"),\n \t\t\t\t      agent_len, agent_feature);\n \t}\n \n@@ -869,7 +868,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t\t\t/* When cloning, it is not unusual to have\n \t\t\t * no common commit.\n \t\t\t */\n-\t\t\twarning(\"no common commits\");\n+\t\t\twarning(_(\"no common commits\"));\n \n \tif (args->stateless_rpc)\n \t\tpacket_flush(fd[1]);\n@@ -881,7 +880,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \telse\n \t\talternate_shallow_file = NULL;\n \tif (get_pack(args, fd, pack_lockfile))\n-\t\tdie(\"git fetch-pack: fetch failed.\");\n+\t\tdie(_(\"git fetch-pack: fetch failed.\"));\n \n  all_done:\n \treturn ref;\n@@ -1043,7 +1042,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args,\n \n \tif (!ref) {\n \t\tpacket_flush(fd[1]);\n-\t\tdie(\"no matching remote head\");\n+\t\tdie(_(\"no matching remote head\"));\n \t}\n \tprepare_shallow_info(&si, shallow);\n \tref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought,\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"288941","messageId":"xmqqa8isg67j.fsf@gitster.mtv.corp.google.com","threadId":"42576","inReplyTo":"20160610122714.3341-5-pclouds@gmail.com","subject":"Re: [PATCH 04/27] upload-pack: move \"shallow\" sending code out of deepen()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-06-10T20:05:36Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> @@ -551,16 +565,7 @@ static void deepen(int depth, const struct object_array *shallows)\n>  \t\tbackup = result =\n>  \t\t\tget_shallow_commits(&want_obj, depth,\n>  \t\t\t\t\t    SHALLOW, NOT_SHALLOW);\n> -\twhile (result) {\n> -\t\tstruct object *object = &result->item->object;\n> -\t\tif (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {\n> -\t\t\tpacket_write(1, \"shallow %s\",\n> -\t\t\t\t     oid_to_hex(&object->oid));\n> -\t\t\tregister_shallow(object->oid.hash);\n> -\t\t\tshallow_nr++;\n> -\t\t}\n> -\t\tresult = result->next;\n> -\t}\n> +\tsend_shallow(result);\n>  \tfree_commit_list(backup);\n\nAt this point in the series, \"backup\" becomes an unnecessary and\nredundant variable, as you can free_commit_list(result) here, right?\n\n>  \tfor (i = 0; i < shallows->nr; i++) {\n>  \t\tstruct object *object = shallows->objects[i].item;\n"},{"id":"288942","messageId":"xmqq60tgg663.fsf@gitster.mtv.corp.google.com","threadId":"42576","inReplyTo":"20160610122714.3341-6-pclouds@gmail.com","subject":"Re: [PATCH 05/27] upload-pack: remove unused variable \"backup\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-06-10T20:06:28Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> After the last patch, \"result\" and \"backup\" are the same. \"result\" used\n> to move, but the movement is now contained in send_shallow(). Delete\n> this redundant variable.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n\nAh, OK ;-)  Having this as a separate step is OK, too.\n"},{"id":"288943","messageId":"xmqq1t44g61j.fsf@gitster.mtv.corp.google.com","threadId":"42576","inReplyTo":"20160610122714.3341-7-pclouds@gmail.com","subject":"Re: [PATCH 06/27] upload-pack: move \"unshallow\" sending code out of deepen()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-06-10T20:09:12Z","receivedAt":"2016-06-16T02:19:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> +static void deepen(int depth, const struct object_array *shallows)\n> +{\n> +\tstruct commit_list *result = NULL;\n> +\tint i;\n> +\tif (depth == INFINITE_DEPTH && !is_repository_shallow())\n> +\t\tfor (i = 0; i < shallows->nr; i++) {\n> +\t\t\tstruct object *object = shallows->objects[i].item;\n> +\t\t\tobject->flags |= NOT_SHALLOW;\n> +\t\t}\n> +\telse\n> +\t\tresult = get_shallow_commits(&want_obj, depth,\n> +\t\t\t\t\t     SHALLOW, NOT_SHALLOW);\n> +\tsend_shallow(result);\n> +\tfree_commit_list(result);\n> +\tsend_unshallow(shallows);\n>  \tpacket_flush(1);\n>  }\n\nStarting from the original up to this point, the code structure of\nthis function have bothered me quite a bit because I would expect\n\n\tif (depth == INFINITE_DEPTH && !is_repository_shallow()) {\n\t\tfor (i = 0; i < shallows->nr; i++) {\n\t\t\tstruct object *object = shallows->objects[i].item;\n\t\t\tobject->flags |= NOT_SHALLOW;\n\t\t}\n\t} else {\n\t\tstruct commit_list *result;\n\t\tresult = get_shallow_commits(&want_obj, depth,\n\t\t\t\t\t     SHALLOW, NOT_SHALLOW);\n\t\tsend_shallow(result);\n\t\tfree_commit_list(result);\n\t}\n\tsend_unshallow(shallows);\n\tpacket_flush(1);\n\nwould be easier to understand.  The function seems to be reshaped\nfurther in the series, so let's keep reading...\n"},{"id":"288988","messageId":"xmqqwplweqpi.fsf@gitster.mtv.corp.google.com","threadId":"42576","inReplyTo":"20160610122714.3341-10-pclouds@gmail.com","subject":"Re: [PATCH 09/27] upload-pack: make check_non_tip() clean things up error","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-06-10T20:25:45Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> Subject: Re: [PATCH 09/27] upload-pack: make check_non_tip() clean things up error\n\n\"clean things up on error\"?\n\n> On error check_non_tip() will die and not closing file descriptors is no\n> big deal. The next patch will split the majority of this function out\n> for reuse in other cases, where die() may not be the only outcome. Same\n> story for popping SIGPIPE out of the signal chain. So let's make sure we\n> clean things up properly first.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n\nMakes me wonder if you can push into sigchain before the first\nappearance of \"goto error\" so that in the error handling codepath\nyou can do sigchain_pop(), without adding sigchain_pop() before all\nthe \"goto error\"?\n\n>  upload-pack.c | 15 +++++++++++++--\n>  1 file changed, 13 insertions(+), 2 deletions(-)\n>\n> diff --git a/upload-pack.c b/upload-pack.c\n> index 60f2e5e..1e8b025 100644\n> --- a/upload-pack.c\n> +++ b/upload-pack.c\n> @@ -494,8 +494,10 @@ static void check_non_tip(void)\n>  \t\tif (!is_our_ref(o))\n>  \t\t\tcontinue;\n>  \t\tmemcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n> -\t\tif (write_in_full(cmd.in, namebuf, 42) < 0)\n> +\t\tif (write_in_full(cmd.in, namebuf, 42) < 0) {\n> +\t\t\tsigchain_pop(SIGPIPE);\n>  \t\t\tgoto error;\n> +\t\t}\n>  \t}\n>  \tnamebuf[40] = '\\n';\n>  \tfor (i = 0; i < want_obj.nr; i++) {\n> @@ -503,10 +505,13 @@ static void check_non_tip(void)\n>  \t\tif (is_our_ref(o))\n>  \t\t\tcontinue;\n>  \t\tmemcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n> -\t\tif (write_in_full(cmd.in, namebuf, 41) < 0)\n> +\t\tif (write_in_full(cmd.in, namebuf, 41) < 0) {\n> +\t\t\tsigchain_pop(SIGPIPE);\n>  \t\t\tgoto error;\n> +\t\t}\n>  \t}\n>  \tclose(cmd.in);\n> +\tcmd.in = -1;\n>  \n>  \tsigchain_pop(SIGPIPE);\n>  \n> @@ -518,6 +523,7 @@ static void check_non_tip(void)\n>  \tif (i)\n>  \t\tgoto error;\n>  \tclose(cmd.out);\n> +\tcmd.out = -1;\n>  \n>  \t/*\n>  \t * rev-list may have died by encountering a bad commit\n> @@ -531,6 +537,11 @@ static void check_non_tip(void)\n>  \treturn;\n>  \n>  error:\n> +\tif (cmd.in >= 0)\n> +\t\tclose(cmd.in);\n> +\tif (cmd.out >= 0)\n> +\t\tclose(cmd.out);\n> +\n>  \t/* Pick one of them (we know there at least is one) */\n>  \tfor (i = 0; i < want_obj.nr; i++) {\n>  \t\to = want_obj.objects[i].item;\n"},{"id":"288991","messageId":"xmqqshwkeq7z.fsf@gitster.mtv.corp.google.com","threadId":"42576","inReplyTo":"20160610122714.3341-11-pclouds@gmail.com","subject":"Re: [PATCH 10/27] upload-pack: move rev-list code out of check_non_tip()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-06-10T20:36:16Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> -static void check_non_tip(void)\n> +static int check_unreachable(struct object_array *src)\n>  {\n>...\n>  \t/* All the non-tip ones are ancestors of what we advertised */\n> -\treturn;\n> +\treturn 1;\n>  \n>  error:\n>  \tif (cmd.in >= 0)\n>  \t\tclose(cmd.in);\n>  \tif (cmd.out >= 0)\n>  \t\tclose(cmd.out);\n> +\treturn 0;\n> +}\n\n\"zero is bad, one is good\" is OK as a helper function that is local.\nThe convention needs to be documented as a comment before the\nfunction.\n\nPerhaps if you avoid using \"check_\", which does not hint the return\nvalue, both the function and the caller would become easier to read.\n\nHow about calling it has_unreachable() and make the caller say\n\n\tif (!has_unreachable(&want_obj))\n        \t/* all requested tips are reachable from what we advertised */\n\t\treturn;\n\ninstead?\n\n> +static void check_non_tip(void)\n> +{\n> +\tint i;\n> +\n> +\t/*\n> +\t * In the normal in-process case without\n> +\t * uploadpack.allowReachableSHA1InWant,\n> +\t * non-tip requests can never happen.\n> +\t */\n> +\tif (!stateless_rpc && !(allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1))\n> +\t\tgoto error;\n> +\tif (check_unreachable(&want_obj))\n> +\t\t/* All the non-tip ones are ancestors of what we advertised */\n> +\t\treturn;\n> +\n> +error:\n>  \t/* Pick one of them (we know there at least is one) */\n>  \tfor (i = 0; i < want_obj.nr; i++) {\n> -\t\to = want_obj.objects[i].item;\n> +\t\tstruct object *o = want_obj.objects[i].item;\n>  \t\tif (!is_our_ref(o))\n>  \t\t\tdie(\"git upload-pack: not our ref %s\",\n>  \t\t\t    oid_to_hex(&o->oid));\n"},{"id":"289007","messageId":"CAPig+cRfUjpku1Abf=GxrbFeS4txwr=yZsJ7EKo-aWmxYog6Xw@mail.gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"Re: [PATCH 00/27] nd/shallow-deepen updates","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-06-10T23:42:12Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Jun 10, 2016 at 8:26 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> This contains cleanups after Eric's comments (all good points,\n> thanks!). Changed patches have Junio's s-o-b line removed, so it's\n> easy to see which is changed and which is not. 09/27 is a new one,\n> split out of 10/27.\n\nThanks, the interdiff looks sensible and I think it covers all the\npoints raised by my review of the previous round.\n\nI agree with Junio that moving the sigchain_pop() into the error\nhandling code-path, if possible, would be a nice improvement.\n"},{"id":"289028","messageId":"20160612105409.22156-1-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160610122714.3341-1-pclouds@gmail.com","subject":"[PATCH v2 00/27] nd/shallow-deepen updates","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:42Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Second update to address Junio comments. Interdiff\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex ef693bd..e40d15a 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -453,6 +453,9 @@ static int is_our_ref(struct object *o)\n \treturn o->flags & ((allow_hidden_ref ? HIDDEN_REF : 0) | OUR_REF);\n }\n \n+/*\n+ * on successful case, it's up to the caller to close cmd->out\n+ */\n static int do_reachable_revlist(struct child_process *cmd,\n \t\t\t\tstruct object_array *src,\n \t\t\t\tstruct object_array *reachable)\n@@ -470,16 +473,16 @@ static int do_reachable_revlist(struct child_process *cmd,\n \tcmd->in = -1;\n \tcmd->out = -1;\n \n-\tif (start_command(cmd))\n-\t\tgoto error;\n-\n \t/*\n-\t * If rev-list --stdin encounters an unknown commit, it\n-\t * terminates, which will cause SIGPIPE in the write loop\n+\t * If the next rev-list --stdin encounters an unknown commit,\n+\t * it terminates, which will cause SIGPIPE in the write loop\n \t * below.\n \t */\n \tsigchain_push(SIGPIPE, SIG_IGN);\n \n+\tif (start_command(cmd))\n+\t\tgoto error;\n+\n \tnamebuf[0] = '^';\n \tnamebuf[41] = '\\n';\n \tfor (i = get_max_object_index(); 0 < i; ) {\n@@ -491,10 +494,8 @@ static int do_reachable_revlist(struct child_process *cmd,\n \t\tif (!is_our_ref(o))\n \t\t\tcontinue;\n \t\tmemcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n-\t\tif (write_in_full(cmd->in, namebuf, 42) < 0) {\n-\t\t\tsigchain_pop(SIGPIPE);\n+\t\tif (write_in_full(cmd->in, namebuf, 42) < 0)\n \t\t\tgoto error;\n-\t\t}\n \t}\n \tnamebuf[40] = '\\n';\n \tfor (i = 0; i < src->nr; i++) {\n@@ -507,18 +508,18 @@ static int do_reachable_revlist(struct child_process *cmd,\n \t\tif (reachable && o->type == OBJ_COMMIT)\n \t\t\to->flags |= TMP_MARK;\n \t\tmemcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n-\t\tif (write_in_full(cmd->in, namebuf, 41) < 0) {\n-\t\t\tsigchain_pop(SIGPIPE);\n+\t\tif (write_in_full(cmd->in, namebuf, 41) < 0)\n \t\t\tgoto error;\n-\t\t}\n \t}\n \tclose(cmd->in);\n \tcmd->in = -1;\n-\n \tsigchain_pop(SIGPIPE);\n+\n \treturn 0;\n \n error:\n+\tsigchain_pop(SIGPIPE);\n+\n \tif (cmd->in >= 0)\n \t\tclose(cmd->in);\n \tif (cmd->out >= 0)\n@@ -530,11 +531,11 @@ static int get_reachable_list(struct object_array *src,\n \t\t\t      struct object_array *reachable)\n {\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n-\tint i, ret = do_reachable_revlist(&cmd, src, reachable);\n+\tint i;\n \tstruct object *o;\n \tchar namebuf[42]; /* ^ + SHA-1 + LF */\n \n-\tif (ret < 0)\n+\tif (do_reachable_revlist(&cmd, src, reachable) < 0)\n \t\treturn -1;\n \n \twhile ((i = read_in_full(cmd.out, namebuf, 41)) == 41) {\n@@ -564,14 +565,14 @@ static int get_reachable_list(struct object_array *src,\n \treturn 0;\n }\n \n-static int check_unreachable(struct object_array *src)\n+static int has_unreachable(struct object_array *src)\n {\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n \tchar buf[1];\n \tint i;\n \n \tif (do_reachable_revlist(&cmd, src, NULL) < 0)\n-\t\treturn 0;\n+\t\treturn 1;\n \n \t/*\n \t * The commits out of the rev-list are not ancestors of\n@@ -592,14 +593,13 @@ static int check_unreachable(struct object_array *src)\n \t\tgoto error;\n \n \t/* All the non-tip ones are ancestors of what we advertised */\n-\treturn 1;\n+\treturn 0;\n \n error:\n-\tif (cmd.in >= 0)\n-\t\tclose(cmd.in);\n+\tsigchain_pop(SIGPIPE);\n \tif (cmd.out >= 0)\n \t\tclose(cmd.out);\n-\treturn 0;\n+\treturn 1;\n }\n \n static void check_non_tip(void)\n@@ -613,7 +613,7 @@ static void check_non_tip(void)\n \t */\n \tif (!stateless_rpc && !(allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1))\n \t\tgoto error;\n-\tif (check_unreachable(&want_obj))\n+\tif (!has_unreachable(&want_obj))\n \t\t/* All the non-tip ones are ancestors of what we advertised */\n \t\treturn;\n \n@@ -678,25 +678,33 @@ static void send_unshallow(const struct object_array *shallows)\n static void deepen(int depth, int deepen_relative,\n \t\t   struct object_array *shallows)\n {\n-\tstruct commit_list *result = NULL;\n-\tint i;\n-\tif (depth == INFINITE_DEPTH && !is_repository_shallow())\n+\tif (depth == INFINITE_DEPTH && !is_repository_shallow()) {\n+\t\tint i;\n+\n \t\tfor (i = 0; i < shallows->nr; i++) {\n \t\t\tstruct object *object = shallows->objects[i].item;\n \t\t\tobject->flags |= NOT_SHALLOW;\n \t\t}\n-\telse if (deepen_relative) {\n+\t} else if (deepen_relative) {\n \t\tstruct object_array reachable_shallows = OBJECT_ARRAY_INIT;\n+\t\tstruct commit_list *result;\n+\n \t\tget_reachable_list(shallows, &reachable_shallows);\n \t\tresult = get_shallow_commits(&reachable_shallows,\n \t\t\t\t\t     depth + 1,\n \t\t\t\t\t     SHALLOW, NOT_SHALLOW);\n+\t\tsend_shallow(result);\n+\t\tfree_commit_list(result);\n \t\tobject_array_clear(&reachable_shallows);\n-\t} else\n+\t} else {\n+\t\tstruct commit_list *result;\n+\n \t\tresult = get_shallow_commits(&want_obj, depth,\n \t\t\t\t\t     SHALLOW, NOT_SHALLOW);\n-\tsend_shallow(result);\n-\tfree_commit_list(result);\n+\t\tsend_shallow(result);\n+\t\tfree_commit_list(result);\n+\t}\n+\n \tsend_unshallow(shallows);\n \tpacket_flush(1);\n }\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289029","messageId":"20160612105409.22156-2-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 01/27] remote-curl.c: convert fetch_git() to use argv_array","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:43Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n remote-curl.c | 46 ++++++++++++++++++----------------------------\n 1 file changed, 18 insertions(+), 28 deletions(-)\n\ndiff --git a/remote-curl.c b/remote-curl.c\nindex c704857..fd030c1 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -725,38 +725,28 @@ static int fetch_git(struct discovery *heads,\n {\n \tstruct rpc_state rpc;\n \tstruct strbuf preamble = STRBUF_INIT;\n-\tchar *depth_arg = NULL;\n-\tint argc = 0, i, err;\n-\tconst char *argv[17];\n-\n-\targv[argc++] = \"fetch-pack\";\n-\targv[argc++] = \"--stateless-rpc\";\n-\targv[argc++] = \"--stdin\";\n-\targv[argc++] = \"--lock-pack\";\n+\tint i, err;\n+\tstruct argv_array args = ARGV_ARRAY_INIT;\n+\n+\targv_array_pushl(&args, \"fetch-pack\", \"--stateless-rpc\",\n+\t\t\t \"--stdin\", \"--lock-pack\", NULL);\n \tif (options.followtags)\n-\t\targv[argc++] = \"--include-tag\";\n+\t\targv_array_push(&args, \"--include-tag\");\n \tif (options.thin)\n-\t\targv[argc++] = \"--thin\";\n-\tif (options.verbosity >= 3) {\n-\t\targv[argc++] = \"-v\";\n-\t\targv[argc++] = \"-v\";\n-\t}\n+\t\targv_array_push(&args, \"--thin\");\n+\tif (options.verbosity >= 3)\n+\t\targv_array_pushl(&args, \"-v\", \"-v\", NULL);\n \tif (options.check_self_contained_and_connected)\n-\t\targv[argc++] = \"--check-self-contained-and-connected\";\n+\t\targv_array_push(&args, \"--check-self-contained-and-connected\");\n \tif (options.cloning)\n-\t\targv[argc++] = \"--cloning\";\n+\t\targv_array_push(&args, \"--cloning\");\n \tif (options.update_shallow)\n-\t\targv[argc++] = \"--update-shallow\";\n+\t\targv_array_push(&args, \"--update-shallow\");\n \tif (!options.progress)\n-\t\targv[argc++] = \"--no-progress\";\n-\tif (options.depth) {\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\t\tstrbuf_addf(&buf, \"--depth=%lu\", options.depth);\n-\t\tdepth_arg = strbuf_detach(&buf, NULL);\n-\t\targv[argc++] = depth_arg;\n-\t}\n-\targv[argc++] = url.buf;\n-\targv[argc++] = NULL;\n+\t\targv_array_push(&args, \"--no-progress\");\n+\tif (options.depth)\n+\t\targv_array_pushf(&args, \"--depth=%lu\", options.depth);\n+\targv_array_push(&args, url.buf);\n \n \tfor (i = 0; i < nr_heads; i++) {\n \t\tstruct ref *ref = to_fetch[i];\n@@ -769,7 +759,7 @@ static int fetch_git(struct discovery *heads,\n \n \tmemset(&rpc, 0, sizeof(rpc));\n \trpc.service_name = \"git-upload-pack\",\n-\trpc.argv = argv;\n+\trpc.argv = args.argv;\n \trpc.stdin_preamble = &preamble;\n \trpc.gzip_request = 1;\n \n@@ -778,7 +768,7 @@ static int fetch_git(struct discovery *heads,\n \t\twrite_or_die(1, rpc.result.buf, rpc.result.len);\n \tstrbuf_release(&rpc.result);\n \tstrbuf_release(&preamble);\n-\tfree(depth_arg);\n+\targv_array_clear(&args);\n \treturn err;\n }\n \n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289030","messageId":"20160612105409.22156-3-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 02/27] transport-helper.c: refactor set_helper_option()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:44Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"For now we can handle two types, string and boolean, in\nset_helper_option(). Later on we'll add string_list support, which does\nnot fit well. The new function strbuf_set_helper_option() can be reused\nfor a separate function that handles string-list.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n transport-helper.c | 37 +++++++++++++++++++++++--------------\n 1 file changed, 23 insertions(+), 14 deletions(-)\n\ndiff --git a/transport-helper.c b/transport-helper.c\nindex a6bff8b..27a34e9 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -260,6 +260,28 @@ static const char *boolean_options[] = {\n \tTRANS_OPT_FOLLOWTAGS,\n \t};\n \n+static int strbuf_set_helper_option(struct helper_data *data,\n+\t\t\t\t    struct strbuf *buf)\n+{\n+\tint ret;\n+\n+\tsendline(data, buf);\n+\tif (recvline(data, buf))\n+\t\texit(128);\n+\n+\tif (!strcmp(buf->buf, \"ok\"))\n+\t\tret = 0;\n+\telse if (starts_with(buf->buf, \"error\"))\n+\t\tret = -1;\n+\telse if (!strcmp(buf->buf, \"unsupported\"))\n+\t\tret = 1;\n+\telse {\n+\t\twarning(\"%s unexpectedly said: '%s'\", data->name, buf->buf);\n+\t\tret = 1;\n+\t}\n+\treturn ret;\n+}\n+\n static int set_helper_option(struct transport *transport,\n \t\t\t  const char *name, const char *value)\n {\n@@ -291,20 +313,7 @@ static int set_helper_option(struct transport *transport,\n \t\tquote_c_style(value, &buf, NULL, 0);\n \tstrbuf_addch(&buf, '\\n');\n \n-\tsendline(data, &buf);\n-\tif (recvline(data, &buf))\n-\t\texit(128);\n-\n-\tif (!strcmp(buf.buf, \"ok\"))\n-\t\tret = 0;\n-\telse if (starts_with(buf.buf, \"error\")) {\n-\t\tret = -1;\n-\t} else if (!strcmp(buf.buf, \"unsupported\"))\n-\t\tret = 1;\n-\telse {\n-\t\twarning(\"%s unexpectedly said: '%s'\", data->name, buf.buf);\n-\t\tret = 1;\n-\t}\n+\tret = strbuf_set_helper_option(data, &buf);\n \tstrbuf_release(&buf);\n \treturn ret;\n }\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289031","messageId":"20160612105409.22156-4-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 03/27] upload-pack: move shallow deepen code out of receive_needs()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:45Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is a prep step for further refactoring. Besides reindentation and\ns/shallows\\./shallows->/g, no other changes are expected.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n upload-pack.c | 99 +++++++++++++++++++++++++++++++----------------------------\n 1 file changed, 52 insertions(+), 47 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex b3f6653..97ed620 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -538,6 +538,55 @@ error:\n \t}\n }\n \n+static void deepen(int depth, const struct object_array *shallows)\n+{\n+\tstruct commit_list *result = NULL, *backup = NULL;\n+\tint i;\n+\tif (depth == INFINITE_DEPTH && !is_repository_shallow())\n+\t\tfor (i = 0; i < shallows->nr; i++) {\n+\t\t\tstruct object *object = shallows->objects[i].item;\n+\t\t\tobject->flags |= NOT_SHALLOW;\n+\t\t}\n+\telse\n+\t\tbackup = result =\n+\t\t\tget_shallow_commits(&want_obj, depth,\n+\t\t\t\t\t    SHALLOW, NOT_SHALLOW);\n+\twhile (result) {\n+\t\tstruct object *object = &result->item->object;\n+\t\tif (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {\n+\t\t\tpacket_write(1, \"shallow %s\",\n+\t\t\t\t     oid_to_hex(&object->oid));\n+\t\t\tregister_shallow(object->oid.hash);\n+\t\t\tshallow_nr++;\n+\t\t}\n+\t\tresult = result->next;\n+\t}\n+\tfree_commit_list(backup);\n+\tfor (i = 0; i < shallows->nr; i++) {\n+\t\tstruct object *object = shallows->objects[i].item;\n+\t\tif (object->flags & NOT_SHALLOW) {\n+\t\t\tstruct commit_list *parents;\n+\t\t\tpacket_write(1, \"unshallow %s\",\n+\t\t\t\t     oid_to_hex(&object->oid));\n+\t\t\tobject->flags &= ~CLIENT_SHALLOW;\n+\t\t\t/* make sure the real parents are parsed */\n+\t\t\tunregister_shallow(object->oid.hash);\n+\t\t\tobject->parsed = 0;\n+\t\t\tparse_commit_or_die((struct commit *)object);\n+\t\t\tparents = ((struct commit *)object)->parents;\n+\t\t\twhile (parents) {\n+\t\t\t\tadd_object_array(&parents->item->object,\n+\t\t\t\t\t\t NULL, &want_obj);\n+\t\t\t\tparents = parents->next;\n+\t\t\t}\n+\t\t\tadd_object_array(object, NULL, &extra_edge_obj);\n+\t\t}\n+\t\t/* make sure commit traversal conforms to client */\n+\t\tregister_shallow(object->oid.hash);\n+\t}\n+\tpacket_flush(1);\n+}\n+\n static void receive_needs(void)\n {\n \tstruct object_array shallows = OBJECT_ARRAY_INIT;\n@@ -630,53 +679,9 @@ static void receive_needs(void)\n \n \tif (depth == 0 && shallows.nr == 0)\n \t\treturn;\n-\tif (depth > 0) {\n-\t\tstruct commit_list *result = NULL, *backup = NULL;\n-\t\tint i;\n-\t\tif (depth == INFINITE_DEPTH && !is_repository_shallow())\n-\t\t\tfor (i = 0; i < shallows.nr; i++) {\n-\t\t\t\tstruct object *object = shallows.objects[i].item;\n-\t\t\t\tobject->flags |= NOT_SHALLOW;\n-\t\t\t}\n-\t\telse\n-\t\t\tbackup = result =\n-\t\t\t\tget_shallow_commits(&want_obj, depth,\n-\t\t\t\t\t\t    SHALLOW, NOT_SHALLOW);\n-\t\twhile (result) {\n-\t\t\tstruct object *object = &result->item->object;\n-\t\t\tif (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {\n-\t\t\t\tpacket_write(1, \"shallow %s\",\n-\t\t\t\t\t\toid_to_hex(&object->oid));\n-\t\t\t\tregister_shallow(object->oid.hash);\n-\t\t\t\tshallow_nr++;\n-\t\t\t}\n-\t\t\tresult = result->next;\n-\t\t}\n-\t\tfree_commit_list(backup);\n-\t\tfor (i = 0; i < shallows.nr; i++) {\n-\t\t\tstruct object *object = shallows.objects[i].item;\n-\t\t\tif (object->flags & NOT_SHALLOW) {\n-\t\t\t\tstruct commit_list *parents;\n-\t\t\t\tpacket_write(1, \"unshallow %s\",\n-\t\t\t\t\toid_to_hex(&object->oid));\n-\t\t\t\tobject->flags &= ~CLIENT_SHALLOW;\n-\t\t\t\t/* make sure the real parents are parsed */\n-\t\t\t\tunregister_shallow(object->oid.hash);\n-\t\t\t\tobject->parsed = 0;\n-\t\t\t\tparse_commit_or_die((struct commit *)object);\n-\t\t\t\tparents = ((struct commit *)object)->parents;\n-\t\t\t\twhile (parents) {\n-\t\t\t\t\tadd_object_array(&parents->item->object,\n-\t\t\t\t\t\t\tNULL, &want_obj);\n-\t\t\t\t\tparents = parents->next;\n-\t\t\t\t}\n-\t\t\t\tadd_object_array(object, NULL, &extra_edge_obj);\n-\t\t\t}\n-\t\t\t/* make sure commit traversal conforms to client */\n-\t\t\tregister_shallow(object->oid.hash);\n-\t\t}\n-\t\tpacket_flush(1);\n-\t} else\n+\tif (depth > 0)\n+\t\tdeepen(depth, &shallows);\n+\telse\n \t\tif (shallows.nr > 0) {\n \t\t\tint i;\n \t\t\tfor (i = 0; i < shallows.nr; i++)\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289032","messageId":"20160612105409.22156-6-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 05/27] upload-pack: remove unused variable \"backup\"","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:47Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"After the last patch, \"result\" and \"backup\" are the same. \"result\" used\nto move, but the movement is now contained in send_shallow(). Delete\nthis redundant variable.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n upload-pack.c | 9 ++++-----\n 1 file changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 0eb9a0b..ee5d20b 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -554,7 +554,7 @@ static void send_shallow(struct commit_list *result)\n \n static void deepen(int depth, const struct object_array *shallows)\n {\n-\tstruct commit_list *result = NULL, *backup = NULL;\n+\tstruct commit_list *result = NULL;\n \tint i;\n \tif (depth == INFINITE_DEPTH && !is_repository_shallow())\n \t\tfor (i = 0; i < shallows->nr; i++) {\n@@ -562,11 +562,10 @@ static void deepen(int depth, const struct object_array *shallows)\n \t\t\tobject->flags |= NOT_SHALLOW;\n \t\t}\n \telse\n-\t\tbackup = result =\n-\t\t\tget_shallow_commits(&want_obj, depth,\n-\t\t\t\t\t    SHALLOW, NOT_SHALLOW);\n+\t\tresult = get_shallow_commits(&want_obj, depth,\n+\t\t\t\t\t     SHALLOW, NOT_SHALLOW);\n \tsend_shallow(result);\n-\tfree_commit_list(backup);\n+\tfree_commit_list(result);\n \tfor (i = 0; i < shallows->nr; i++) {\n \t\tstruct object *object = shallows->objects[i].item;\n \t\tif (object->flags & NOT_SHALLOW) {\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289033","messageId":"20160612105409.22156-5-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 04/27] upload-pack: move \"shallow\" sending code out of deepen()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:46Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n upload-pack.c | 25 +++++++++++++++----------\n 1 file changed, 15 insertions(+), 10 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 97ed620..0eb9a0b 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -538,6 +538,20 @@ error:\n \t}\n }\n \n+static void send_shallow(struct commit_list *result)\n+{\n+\twhile (result) {\n+\t\tstruct object *object = &result->item->object;\n+\t\tif (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {\n+\t\t\tpacket_write(1, \"shallow %s\",\n+\t\t\t\t     oid_to_hex(&object->oid));\n+\t\t\tregister_shallow(object->oid.hash);\n+\t\t\tshallow_nr++;\n+\t\t}\n+\t\tresult = result->next;\n+\t}\n+}\n+\n static void deepen(int depth, const struct object_array *shallows)\n {\n \tstruct commit_list *result = NULL, *backup = NULL;\n@@ -551,16 +565,7 @@ static void deepen(int depth, const struct object_array *shallows)\n \t\tbackup = result =\n \t\t\tget_shallow_commits(&want_obj, depth,\n \t\t\t\t\t    SHALLOW, NOT_SHALLOW);\n-\twhile (result) {\n-\t\tstruct object *object = &result->item->object;\n-\t\tif (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {\n-\t\t\tpacket_write(1, \"shallow %s\",\n-\t\t\t\t     oid_to_hex(&object->oid));\n-\t\t\tregister_shallow(object->oid.hash);\n-\t\t\tshallow_nr++;\n-\t\t}\n-\t\tresult = result->next;\n-\t}\n+\tsend_shallow(result);\n \tfree_commit_list(backup);\n \tfor (i = 0; i < shallows->nr; i++) {\n \t\tstruct object *object = shallows->objects[i].item;\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289034","messageId":"20160612105409.22156-7-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 06/27] upload-pack: move \"unshallow\" sending code out of deepen()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:48Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Also add some more comments in this code because it takes too long to\nunderstand what it does (to me, who should be familiar enough to\nunderstand this code well!)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n upload-pack.c | 43 ++++++++++++++++++++++++++++++-------------\n 1 file changed, 30 insertions(+), 13 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex ee5d20b..73a8b28 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -552,20 +552,10 @@ static void send_shallow(struct commit_list *result)\n \t}\n }\n \n-static void deepen(int depth, const struct object_array *shallows)\n+static void send_unshallow(const struct object_array *shallows)\n {\n-\tstruct commit_list *result = NULL;\n \tint i;\n-\tif (depth == INFINITE_DEPTH && !is_repository_shallow())\n-\t\tfor (i = 0; i < shallows->nr; i++) {\n-\t\t\tstruct object *object = shallows->objects[i].item;\n-\t\t\tobject->flags |= NOT_SHALLOW;\n-\t\t}\n-\telse\n-\t\tresult = get_shallow_commits(&want_obj, depth,\n-\t\t\t\t\t     SHALLOW, NOT_SHALLOW);\n-\tsend_shallow(result);\n-\tfree_commit_list(result);\n+\n \tfor (i = 0; i < shallows->nr; i++) {\n \t\tstruct object *object = shallows->objects[i].item;\n \t\tif (object->flags & NOT_SHALLOW) {\n@@ -573,7 +563,13 @@ static void deepen(int depth, const struct object_array *shallows)\n \t\t\tpacket_write(1, \"unshallow %s\",\n \t\t\t\t     oid_to_hex(&object->oid));\n \t\t\tobject->flags &= ~CLIENT_SHALLOW;\n-\t\t\t/* make sure the real parents are parsed */\n+\t\t\t/*\n+\t\t\t * We want to _register_ \"object\" as shallow, but we\n+\t\t\t * also need to traverse object's parents to deepen a\n+\t\t\t * shallow clone. Unregister it for now so we can\n+\t\t\t * parse and add the parents to the want list, then\n+\t\t\t * re-register it.\n+\t\t\t */\n \t\t\tunregister_shallow(object->oid.hash);\n \t\t\tobject->parsed = 0;\n \t\t\tparse_commit_or_die((struct commit *)object);\n@@ -588,6 +584,27 @@ static void deepen(int depth, const struct object_array *shallows)\n \t\t/* make sure commit traversal conforms to client */\n \t\tregister_shallow(object->oid.hash);\n \t}\n+}\n+\n+static void deepen(int depth, const struct object_array *shallows)\n+{\n+\tif (depth == INFINITE_DEPTH && !is_repository_shallow()) {\n+\t\tint i;\n+\n+\t\tfor (i = 0; i < shallows->nr; i++) {\n+\t\t\tstruct object *object = shallows->objects[i].item;\n+\t\t\tobject->flags |= NOT_SHALLOW;\n+\t\t}\n+\t} else {\n+\t\tstruct commit_list *result;\n+\n+\t\tresult = get_shallow_commits(&want_obj, depth,\n+\t\t\t\t\t     SHALLOW, NOT_SHALLOW);\n+\t\tsend_shallow(result);\n+\t\tfree_commit_list(result);\n+\t}\n+\n+\tsend_unshallow(shallows);\n \tpacket_flush(1);\n }\n \n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289035","messageId":"20160612105409.22156-8-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 07/27] upload-pack: use skip_prefix() instead of starts_with()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:49Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n upload-pack.c | 32 ++++++++++++++++++--------------\n 1 file changed, 18 insertions(+), 14 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 73a8b28..fa7ce09 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -276,7 +276,7 @@ static void create_pack_file(void)\n \tdie(\"git upload-pack: %s\", abort_msg);\n }\n \n-static int got_sha1(char *hex, unsigned char *sha1)\n+static int got_sha1(const char *hex, unsigned char *sha1)\n {\n \tstruct object *o;\n \tint we_knew_they_have = 0;\n@@ -382,6 +382,8 @@ static int get_common_commits(void)\n \n \tfor (;;) {\n \t\tchar *line = packet_read_line(0, NULL);\n+\t\tconst char *arg;\n+\n \t\treset_timeout();\n \n \t\tif (!line) {\n@@ -403,8 +405,8 @@ static int get_common_commits(void)\n \t\t\tgot_other = 0;\n \t\t\tcontinue;\n \t\t}\n-\t\tif (starts_with(line, \"have \")) {\n-\t\t\tswitch (got_sha1(line+5, sha1)) {\n+\t\tif (skip_prefix(line, \"have \", &arg)) {\n+\t\t\tswitch (got_sha1(arg, sha1)) {\n \t\t\tcase -1: /* they have what we do not */\n \t\t\t\tgot_other = 1;\n \t\t\t\tif (multi_ack && ok_to_give_up()) {\n@@ -620,14 +622,16 @@ static void receive_needs(void)\n \t\tconst char *features;\n \t\tunsigned char sha1_buf[20];\n \t\tchar *line = packet_read_line(0, NULL);\n+\t\tconst char *arg;\n+\n \t\treset_timeout();\n \t\tif (!line)\n \t\t\tbreak;\n \n-\t\tif (starts_with(line, \"shallow \")) {\n+\t\tif (skip_prefix(line, \"shallow \", &arg)) {\n \t\t\tunsigned char sha1[20];\n \t\t\tstruct object *object;\n-\t\t\tif (get_sha1_hex(line + 8, sha1))\n+\t\t\tif (get_sha1_hex(arg, sha1))\n \t\t\t\tdie(\"invalid shallow line: %s\", line);\n \t\t\tobject = parse_object(sha1);\n \t\t\tif (!object)\n@@ -640,19 +644,19 @@ static void receive_needs(void)\n \t\t\t}\n \t\t\tcontinue;\n \t\t}\n-\t\tif (starts_with(line, \"deepen \")) {\n+\t\tif (skip_prefix(line, \"deepen \", &arg)) {\n \t\t\tchar *end;\n-\t\t\tdepth = strtol(line + 7, &end, 0);\n-\t\t\tif (end == line + 7 || depth <= 0)\n+\t\t\tdepth = strtol(arg, &end, 0);\n+\t\t\tif (end == arg || depth <= 0)\n \t\t\t\tdie(\"Invalid deepen: %s\", line);\n \t\t\tcontinue;\n \t\t}\n-\t\tif (!starts_with(line, \"want \") ||\n-\t\t    get_sha1_hex(line+5, sha1_buf))\n+\t\tif (!skip_prefix(line, \"want \", &arg) ||\n+\t\t    get_sha1_hex(arg, sha1_buf))\n \t\t\tdie(\"git upload-pack: protocol error, \"\n \t\t\t    \"expected to get sha, not '%s'\", line);\n \n-\t\tfeatures = line + 45;\n+\t\tfeatures = arg + 40;\n \n \t\tif (parse_feature_request(features, \"multi_ack_detailed\"))\n \t\t\tmulti_ack = 2;\n@@ -859,7 +863,7 @@ int main(int argc, char **argv)\n \tcheck_replace_refs = 0;\n \n \tfor (i = 1; i < argc; i++) {\n-\t\tchar *arg = argv[i];\n+\t\tconst char *arg = argv[i];\n \n \t\tif (arg[0] != '-')\n \t\t\tbreak;\n@@ -875,8 +879,8 @@ int main(int argc, char **argv)\n \t\t\tstrict = 1;\n \t\t\tcontinue;\n \t\t}\n-\t\tif (starts_with(arg, \"--timeout=\")) {\n-\t\t\ttimeout = atoi(arg+10);\n+\t\tif (skip_prefix(arg, \"--timeout=\", &arg)) {\n+\t\t\ttimeout = atoi(arg);\n \t\t\tdaemon_mode = 1;\n \t\t\tcontinue;\n \t\t}\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289036","messageId":"20160612105409.22156-9-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 08/27] upload-pack: tighten number parsing at \"deepen\" lines","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:50Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n upload-pack.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex fa7ce09..8f4d7f4 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -645,9 +645,9 @@ static void receive_needs(void)\n \t\t\tcontinue;\n \t\t}\n \t\tif (skip_prefix(line, \"deepen \", &arg)) {\n-\t\t\tchar *end;\n+\t\t\tchar *end = NULL;\n \t\t\tdepth = strtol(arg, &end, 0);\n-\t\t\tif (end == arg || depth <= 0)\n+\t\t\tif (!end || *end || depth <= 0)\n \t\t\t\tdie(\"Invalid deepen: %s\", line);\n \t\t\tcontinue;\n \t\t}\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289037","messageId":"20160612105409.22156-10-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 09/27] upload-pack: make check_non_tip() clean things up on error","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:51Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On error check_non_tip() will die and not closing file descriptors is no\nbig deal. The next patch will split the majority of this function out\nfor reuse in other cases, where die() may not be the only outcome. Same\nstory for popping SIGPIPE out of the signal chain. So let's make sure we\nclean things up properly first.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n upload-pack.c | 23 ++++++++++++++++-------\n 1 file changed, 16 insertions(+), 7 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 8f4d7f4..7ce97ec 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -475,16 +475,16 @@ static void check_non_tip(void)\n \tcmd.in = -1;\n \tcmd.out = -1;\n \n-\tif (start_command(&cmd))\n-\t\tgoto error;\n-\n \t/*\n-\t * If rev-list --stdin encounters an unknown commit, it\n-\t * terminates, which will cause SIGPIPE in the write loop\n+\t * If the next rev-list --stdin encounters an unknown commit,\n+\t * it terminates, which will cause SIGPIPE in the write loop\n \t * below.\n \t */\n \tsigchain_push(SIGPIPE, SIG_IGN);\n \n+\tif (start_command(&cmd))\n+\t\tgoto error;\n+\n \tnamebuf[0] = '^';\n \tnamebuf[41] = '\\n';\n \tfor (i = get_max_object_index(); 0 < i; ) {\n@@ -507,8 +507,7 @@ static void check_non_tip(void)\n \t\t\tgoto error;\n \t}\n \tclose(cmd.in);\n-\n-\tsigchain_pop(SIGPIPE);\n+\tcmd.in = -1;\n \n \t/*\n \t * The commits out of the rev-list are not ancestors of\n@@ -518,6 +517,7 @@ static void check_non_tip(void)\n \tif (i)\n \t\tgoto error;\n \tclose(cmd.out);\n+\tcmd.out = -1;\n \n \t/*\n \t * rev-list may have died by encountering a bad commit\n@@ -527,10 +527,19 @@ static void check_non_tip(void)\n \tif (finish_command(&cmd))\n \t\tgoto error;\n \n+\tsigchain_pop(SIGPIPE);\n+\n \t/* All the non-tip ones are ancestors of what we advertised */\n \treturn;\n \n error:\n+\tsigchain_pop(SIGPIPE);\n+\n+\tif (cmd.in >= 0)\n+\t\tclose(cmd.in);\n+\tif (cmd.out >= 0)\n+\t\tclose(cmd.out);\n+\n \t/* Pick one of them (we know there at least is one) */\n \tfor (i = 0; i < want_obj.nr; i++) {\n \t\to = want_obj.objects[i].item;\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289038","messageId":"20160612105409.22156-12-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 11/27] fetch-pack: use skip_prefix() instead of starts_with()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:53Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/fetch-pack.c | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex 9b2a514..8332d3d 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -59,12 +59,12 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \tfor (i = 1; i < argc && *argv[i] == '-'; i++) {\n \t\tconst char *arg = argv[i];\n \n-\t\tif (starts_with(arg, \"--upload-pack=\")) {\n-\t\t\targs.uploadpack = arg + 14;\n+\t\tif (skip_prefix(arg, \"--upload-pack=\", &arg)) {\n+\t\t\targs.uploadpack = arg;\n \t\t\tcontinue;\n \t\t}\n-\t\tif (starts_with(arg, \"--exec=\")) {\n-\t\t\targs.uploadpack = arg + 7;\n+\t\tif (skip_prefix(arg, \"--exec=\", &arg)) {\n+\t\t\targs.uploadpack = arg;\n \t\t\tcontinue;\n \t\t}\n \t\tif (!strcmp(\"--quiet\", arg) || !strcmp(\"-q\", arg)) {\n@@ -100,8 +100,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \t\t\targs.verbose = 1;\n \t\t\tcontinue;\n \t\t}\n-\t\tif (starts_with(arg, \"--depth=\")) {\n-\t\t\targs.depth = strtol(arg + 8, NULL, 0);\n+\t\tif (skip_prefix(arg, \"--depth=\", &arg)) {\n+\t\t\targs.depth = strtol(arg, NULL, 0);\n \t\t\tcontinue;\n \t\t}\n \t\tif (!strcmp(\"--no-progress\", arg)) {\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289039","messageId":"20160612105409.22156-11-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 10/27] upload-pack: move rev-list code out of check_non_tip()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:52Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n upload-pack.c | 36 +++++++++++++++++++++++-------------\n 1 file changed, 23 insertions(+), 13 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 7ce97ec..93c0522 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -451,7 +451,7 @@ static int is_our_ref(struct object *o)\n \treturn o->flags & ((allow_hidden_ref ? HIDDEN_REF : 0) | OUR_REF);\n }\n \n-static void check_non_tip(void)\n+static int has_unreachable(struct object_array *src)\n {\n \tstatic const char *argv[] = {\n \t\t\"rev-list\", \"--stdin\", NULL,\n@@ -461,14 +461,6 @@ static void check_non_tip(void)\n \tchar namebuf[42]; /* ^ + SHA-1 + LF */\n \tint i;\n \n-\t/*\n-\t * In the normal in-process case without\n-\t * uploadpack.allowReachableSHA1InWant,\n-\t * non-tip requests can never happen.\n-\t */\n-\tif (!stateless_rpc && !(allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1))\n-\t\tgoto error;\n-\n \tcmd.argv = argv;\n \tcmd.git_cmd = 1;\n \tcmd.no_stderr = 1;\n@@ -498,8 +490,8 @@ static void check_non_tip(void)\n \t\t\tgoto error;\n \t}\n \tnamebuf[40] = '\\n';\n-\tfor (i = 0; i < want_obj.nr; i++) {\n-\t\to = want_obj.objects[i].item;\n+\tfor (i = 0; i < src->nr; i++) {\n+\t\to = src->objects[i].item;\n \t\tif (is_our_ref(o))\n \t\t\tcontinue;\n \t\tmemcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n@@ -530,7 +522,7 @@ static void check_non_tip(void)\n \tsigchain_pop(SIGPIPE);\n \n \t/* All the non-tip ones are ancestors of what we advertised */\n-\treturn;\n+\treturn 0;\n \n error:\n \tsigchain_pop(SIGPIPE);\n@@ -539,10 +531,28 @@ error:\n \t\tclose(cmd.in);\n \tif (cmd.out >= 0)\n \t\tclose(cmd.out);\n+\treturn 1;\n+}\n \n+static void check_non_tip(void)\n+{\n+\tint i;\n+\n+\t/*\n+\t * In the normal in-process case without\n+\t * uploadpack.allowReachableSHA1InWant,\n+\t * non-tip requests can never happen.\n+\t */\n+\tif (!stateless_rpc && !(allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1))\n+\t\tgoto error;\n+\tif (!has_unreachable(&want_obj))\n+\t\t/* All the non-tip ones are ancestors of what we advertised */\n+\t\treturn;\n+\n+error:\n \t/* Pick one of them (we know there at least is one) */\n \tfor (i = 0; i < want_obj.nr; i++) {\n-\t\to = want_obj.objects[i].item;\n+\t\tstruct object *o = want_obj.objects[i].item;\n \t\tif (!is_our_ref(o))\n \t\t\tdie(\"git upload-pack: not our ref %s\",\n \t\t\t    oid_to_hex(&o->oid));\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289040","messageId":"20160612105409.22156-13-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 12/27] fetch-pack: use a common function for verbose printing","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:54Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This reduces the number of \"if (verbose)\" which makes it a bit easier\nto read imo. It also makes it easier to redirect all these printouts,\nto a file for example.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n fetch-pack.c | 88 +++++++++++++++++++++++++++++-------------------------------\n 1 file changed, 42 insertions(+), 46 deletions(-)\n\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 01e34b6..4020744 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -50,6 +50,21 @@ static int non_common_revs, multi_ack, use_sideband;\n #define ALLOW_REACHABLE_SHA1\t02\n static unsigned int allow_unadvertised_object_request;\n \n+__attribute__((format (printf, 2, 3)))\n+static inline void print_verbose(const struct fetch_pack_args *args,\n+\t\t\t\t const char *fmt, ...)\n+{\n+\tva_list params;\n+\n+\tif (!args->verbose)\n+\t\treturn;\n+\n+\tva_start(params, fmt);\n+\tvfprintf(stderr, fmt, params);\n+\tva_end(params);\n+\tfputc('\\n', stderr);\n+}\n+\n static void rev_list_push(struct commit *commit, int mark)\n {\n \tif (!(commit->object.flags & mark)) {\n@@ -375,8 +390,7 @@ static int find_common(struct fetch_pack_args *args,\n \tretval = -1;\n \twhile ((sha1 = get_rev())) {\n \t\tpacket_buf_write(&req_buf, \"have %s\\n\", sha1_to_hex(sha1));\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"have %s\\n\", sha1_to_hex(sha1));\n+\t\tprint_verbose(args, \"have %s\", sha1_to_hex(sha1));\n \t\tin_vain++;\n \t\tif (flush_at <= ++count) {\n \t\t\tint ack;\n@@ -397,9 +411,9 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\tconsume_shallow_list(args, fd[0]);\n \t\t\tdo {\n \t\t\t\tack = get_ack(fd[0], result_sha1);\n-\t\t\t\tif (args->verbose && ack)\n-\t\t\t\t\tfprintf(stderr, \"got ack %d %s\\n\", ack,\n-\t\t\t\t\t\t\tsha1_to_hex(result_sha1));\n+\t\t\t\tif (ack)\n+\t\t\t\t\tprint_verbose(args, \"got ack %d %s\", ack,\n+\t\t\t\t\t\t      sha1_to_hex(result_sha1));\n \t\t\t\tswitch (ack) {\n \t\t\t\tcase ACK:\n \t\t\t\t\tflushes = 0;\n@@ -438,8 +452,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\t} while (ack);\n \t\t\tflushes--;\n \t\t\tif (got_continue && MAX_IN_VAIN < in_vain) {\n-\t\t\t\tif (args->verbose)\n-\t\t\t\t\tfprintf(stderr, \"giving up\\n\");\n+\t\t\t\tprint_verbose(args, \"giving up\");\n \t\t\t\tbreak; /* give up */\n \t\t\t}\n \t\t}\n@@ -449,8 +462,7 @@ done:\n \t\tpacket_buf_write(&req_buf, \"done\\n\");\n \t\tsend_request(args, fd[1], &req_buf);\n \t}\n-\tif (args->verbose)\n-\t\tfprintf(stderr, \"done\\n\");\n+\tprint_verbose(args, \"done\");\n \tif (retval != 0) {\n \t\tmulti_ack = 0;\n \t\tflushes++;\n@@ -462,9 +474,8 @@ done:\n \twhile (flushes || multi_ack) {\n \t\tint ack = get_ack(fd[0], result_sha1);\n \t\tif (ack) {\n-\t\t\tif (args->verbose)\n-\t\t\t\tfprintf(stderr, \"got ack (%d) %s\\n\", ack,\n-\t\t\t\t\tsha1_to_hex(result_sha1));\n+\t\t\tprint_verbose(args, \"got ack (%d) %s\", ack,\n+\t\t\t\t      sha1_to_hex(result_sha1));\n \t\t\tif (ack == ACK)\n \t\t\t\treturn 0;\n \t\t\tmulti_ack = 1;\n@@ -509,9 +520,8 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args,\n \t\t\t\t\t unsigned long cutoff)\n {\n \twhile (complete && cutoff <= complete->item->date) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Marking %s as complete\\n\",\n-\t\t\t\toid_to_hex(&complete->item->object.oid));\n+\t\tprint_verbose(args, \"Marking %s as complete\",\n+\t\t\t      oid_to_hex(&complete->item->object.oid));\n \t\tpop_most_recent_commit(&complete, COMPLETE);\n \t}\n }\n@@ -652,18 +662,12 @@ static int everything_local(struct fetch_pack_args *args,\n \t\to = lookup_object(remote);\n \t\tif (!o || !(o->flags & COMPLETE)) {\n \t\t\tretval = 0;\n-\t\t\tif (!args->verbose)\n-\t\t\t\tcontinue;\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"want %s (%s)\\n\", sha1_to_hex(remote),\n-\t\t\t\tref->name);\n+\t\t\tprint_verbose(args, \"want %s (%s)\", sha1_to_hex(remote),\n+\t\t\t\t      ref->name);\n \t\t\tcontinue;\n \t\t}\n-\t\tif (!args->verbose)\n-\t\t\tcontinue;\n-\t\tfprintf(stderr,\n-\t\t\t\"already have %s (%s)\\n\", sha1_to_hex(remote),\n-\t\t\tref->name);\n+\t\tprint_verbose(args, \"already have %s (%s)\", sha1_to_hex(remote),\n+\t\t\t      ref->name);\n \t}\n \treturn retval;\n }\n@@ -810,39 +814,32 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \tif ((args->depth > 0 || is_repository_shallow()) && !server_supports(\"shallow\"))\n \t\tdie(\"Server does not support shallow clients\");\n \tif (server_supports(\"multi_ack_detailed\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports multi_ack_detailed\\n\");\n+\t\tprint_verbose(args, \"Server supports multi_ack_detailed\");\n \t\tmulti_ack = 2;\n \t\tif (server_supports(\"no-done\")) {\n-\t\t\tif (args->verbose)\n-\t\t\t\tfprintf(stderr, \"Server supports no-done\\n\");\n+\t\t\tprint_verbose(args, \"Server supports no-done\");\n \t\t\tif (args->stateless_rpc)\n \t\t\t\tno_done = 1;\n \t\t}\n \t}\n \telse if (server_supports(\"multi_ack\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports multi_ack\\n\");\n+\t\tprint_verbose(args, \"Server supports multi_ack\");\n \t\tmulti_ack = 1;\n \t}\n \tif (server_supports(\"side-band-64k\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports side-band-64k\\n\");\n+\t\tprint_verbose(args, \"Server supports side-band-64k\");\n \t\tuse_sideband = 2;\n \t}\n \telse if (server_supports(\"side-band\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports side-band\\n\");\n+\t\tprint_verbose(args, \"Server supports side-band\");\n \t\tuse_sideband = 1;\n \t}\n \tif (server_supports(\"allow-tip-sha1-in-want\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports allow-tip-sha1-in-want\\n\");\n+\t\tprint_verbose(args, \"Server supports allow-tip-sha1-in-want\");\n \t\tallow_unadvertised_object_request |= ALLOW_TIP_SHA1;\n \t}\n \tif (server_supports(\"allow-reachable-sha1-in-want\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports allow-reachable-sha1-in-want\\n\");\n+\t\tprint_verbose(args, \"Server supports allow-reachable-sha1-in-want\");\n \t\tallow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1;\n \t}\n \tif (!server_supports(\"thin-pack\"))\n@@ -851,17 +848,16 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t\targs->no_progress = 0;\n \tif (!server_supports(\"include-tag\"))\n \t\targs->include_tag = 0;\n-\tif (server_supports(\"ofs-delta\")) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"Server supports ofs-delta\\n\");\n-\t} else\n+\tif (server_supports(\"ofs-delta\"))\n+\t\tprint_verbose(args, \"Server supports ofs-delta\");\n+\telse\n \t\tprefer_ofs_delta = 0;\n \n \tif ((agent_feature = server_feature_value(\"agent\", &agent_len))) {\n \t\tagent_supported = 1;\n-\t\tif (args->verbose && agent_len)\n-\t\t\tfprintf(stderr, \"Server version is %.*s\\n\",\n-\t\t\t\tagent_len, agent_feature);\n+\t\tif (agent_len)\n+\t\t\tprint_verbose(args, \"Server version is %.*s\",\n+\t\t\t\t      agent_len, agent_feature);\n \t}\n \n \tif (everything_local(args, &ref, sought, nr_sought)) {\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289041","messageId":"20160612105409.22156-14-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 13/27] fetch-pack.c: mark strings for translating","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:55Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n fetch-pack.c | 75 ++++++++++++++++++++++++++++++------------------------------\n 1 file changed, 37 insertions(+), 38 deletions(-)\n\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 4020744..08caf1d 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -208,7 +208,7 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd)\n \t\t\t\tcontinue;\n \t\t\tif (starts_with(line, \"unshallow \"))\n \t\t\t\tcontinue;\n-\t\t\tdie(\"git fetch-pack: expected shallow list\");\n+\t\t\tdie(_(\"git fetch-pack: expected shallow list\"));\n \t\t}\n \t}\n }\n@@ -220,7 +220,7 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1)\n \tconst char *arg;\n \n \tif (!len)\n-\t\tdie(\"git fetch-pack: expected ACK/NAK, got EOF\");\n+\t\tdie(_(\"git fetch-pack: expected ACK/NAK, got EOF\"));\n \tif (!strcmp(line, \"NAK\"))\n \t\treturn NAK;\n \tif (skip_prefix(line, \"ACK \", &arg)) {\n@@ -238,7 +238,7 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1)\n \t\t\treturn ACK;\n \t\t}\n \t}\n-\tdie(\"git fetch_pack: expected ACK/NAK, got '%s'\", line);\n+\tdie(_(\"git fetch_pack: expected ACK/NAK, got '%s'\"), line);\n }\n \n static void send_request(struct fetch_pack_args *args,\n@@ -285,7 +285,7 @@ static int find_common(struct fetch_pack_args *args,\n \tsize_t state_len = 0;\n \n \tif (args->stateless_rpc && multi_ack == 1)\n-\t\tdie(\"--stateless-rpc requires multi_ack_detailed\");\n+\t\tdie(_(\"--stateless-rpc requires multi_ack_detailed\"));\n \tif (marked)\n \t\tfor_each_ref(clear_marks, NULL);\n \tmarked = 1;\n@@ -357,23 +357,23 @@ static int find_common(struct fetch_pack_args *args,\n \t\twhile ((line = packet_read_line(fd[0], NULL))) {\n \t\t\tif (skip_prefix(line, \"shallow \", &arg)) {\n \t\t\t\tif (get_sha1_hex(arg, sha1))\n-\t\t\t\t\tdie(\"invalid shallow line: %s\", line);\n+\t\t\t\t\tdie(_(\"invalid shallow line: %s\"), line);\n \t\t\t\tregister_shallow(sha1);\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (skip_prefix(line, \"unshallow \", &arg)) {\n \t\t\t\tif (get_sha1_hex(arg, sha1))\n-\t\t\t\t\tdie(\"invalid unshallow line: %s\", line);\n+\t\t\t\t\tdie(_(\"invalid unshallow line: %s\"), line);\n \t\t\t\tif (!lookup_object(sha1))\n-\t\t\t\t\tdie(\"object not found: %s\", line);\n+\t\t\t\t\tdie(_(\"object not found: %s\"), line);\n \t\t\t\t/* make sure that it is parsed as shallow */\n \t\t\t\tif (!parse_object(sha1))\n-\t\t\t\t\tdie(\"error in object: %s\", line);\n+\t\t\t\t\tdie(_(\"error in object: %s\"), line);\n \t\t\t\tif (unregister_shallow(sha1))\n-\t\t\t\t\tdie(\"no shallow found: %s\", line);\n+\t\t\t\t\tdie(_(\"no shallow found: %s\"), line);\n \t\t\t\tcontinue;\n \t\t\t}\n-\t\t\tdie(\"expected shallow/unshallow, got %s\", line);\n+\t\t\tdie(_(\"expected shallow/unshallow, got %s\"), line);\n \t\t}\n \t} else if (!args->stateless_rpc)\n \t\tsend_request(args, fd[1], &req_buf);\n@@ -412,8 +412,8 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\tdo {\n \t\t\t\tack = get_ack(fd[0], result_sha1);\n \t\t\t\tif (ack)\n-\t\t\t\t\tprint_verbose(args, \"got ack %d %s\", ack,\n-\t\t\t\t\t\t      sha1_to_hex(result_sha1));\n+\t\t\t\t\tprint_verbose(args, _(\"got %s %d %s\"), \"ack\",\n+\t\t\t\t\t\t      ack, sha1_to_hex(result_sha1));\n \t\t\t\tswitch (ack) {\n \t\t\t\tcase ACK:\n \t\t\t\t\tflushes = 0;\n@@ -426,7 +426,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\t\t\tstruct commit *commit =\n \t\t\t\t\t\tlookup_commit(result_sha1);\n \t\t\t\t\tif (!commit)\n-\t\t\t\t\t\tdie(\"invalid commit %s\", sha1_to_hex(result_sha1));\n+\t\t\t\t\t\tdie(_(\"invalid commit %s\"), sha1_to_hex(result_sha1));\n \t\t\t\t\tif (args->stateless_rpc\n \t\t\t\t\t && ack == ACK_common\n \t\t\t\t\t && !(commit->object.flags & COMMON)) {\n@@ -452,7 +452,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\t} while (ack);\n \t\t\tflushes--;\n \t\t\tif (got_continue && MAX_IN_VAIN < in_vain) {\n-\t\t\t\tprint_verbose(args, \"giving up\");\n+\t\t\t\tprint_verbose(args, _(\"giving up\"));\n \t\t\t\tbreak; /* give up */\n \t\t\t}\n \t\t}\n@@ -462,7 +462,7 @@ done:\n \t\tpacket_buf_write(&req_buf, \"done\\n\");\n \t\tsend_request(args, fd[1], &req_buf);\n \t}\n-\tprint_verbose(args, \"done\");\n+\tprint_verbose(args, _(\"done\"));\n \tif (retval != 0) {\n \t\tmulti_ack = 0;\n \t\tflushes++;\n@@ -474,8 +474,8 @@ done:\n \twhile (flushes || multi_ack) {\n \t\tint ack = get_ack(fd[0], result_sha1);\n \t\tif (ack) {\n-\t\t\tprint_verbose(args, \"got ack (%d) %s\", ack,\n-\t\t\t\t      sha1_to_hex(result_sha1));\n+\t\t\tprint_verbose(args, _(\"got %s (%d) %s\"), \"ack\",\n+\t\t\t\t      ack, sha1_to_hex(result_sha1));\n \t\t\tif (ack == ACK)\n \t\t\t\treturn 0;\n \t\t\tmulti_ack = 1;\n@@ -520,7 +520,7 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args,\n \t\t\t\t\t unsigned long cutoff)\n {\n \twhile (complete && cutoff <= complete->item->date) {\n-\t\tprint_verbose(args, \"Marking %s as complete\",\n+\t\tprint_verbose(args, _(\"Marking %s as complete\"),\n \t\t\t      oid_to_hex(&complete->item->object.oid));\n \t\tpop_most_recent_commit(&complete, COMPLETE);\n \t}\n@@ -666,7 +666,7 @@ static int everything_local(struct fetch_pack_args *args,\n \t\t\t\t      ref->name);\n \t\t\tcontinue;\n \t\t}\n-\t\tprint_verbose(args, \"already have %s (%s)\", sha1_to_hex(remote),\n+\t\tprint_verbose(args, _(\"already have %s (%s)\"), sha1_to_hex(remote),\n \t\t\t      ref->name);\n \t}\n \treturn retval;\n@@ -702,8 +702,7 @@ static int get_pack(struct fetch_pack_args *args,\n \t\tdemux.data = xd;\n \t\tdemux.out = -1;\n \t\tif (start_async(&demux))\n-\t\t\tdie(\"fetch-pack: unable to fork off sideband\"\n-\t\t\t    \" demultiplexer\");\n+\t\t\tdie(_(\"fetch-pack: unable to fork off sideband demultiplexer\"));\n \t}\n \telse\n \t\tdemux.out = xd[0];\n@@ -711,7 +710,7 @@ static int get_pack(struct fetch_pack_args *args,\n \tif (!args->keep_pack && unpack_limit) {\n \n \t\tif (read_pack_header(demux.out, &header))\n-\t\t\tdie(\"protocol error: bad pack header\");\n+\t\t\tdie(_(\"protocol error: bad pack header\"));\n \t\tpass_header = 1;\n \t\tif (ntohl(header.hdr_entries) < unpack_limit)\n \t\t\tdo_keep = 0;\n@@ -767,7 +766,7 @@ static int get_pack(struct fetch_pack_args *args,\n \tcmd.in = demux.out;\n \tcmd.git_cmd = 1;\n \tif (start_command(&cmd))\n-\t\tdie(\"fetch-pack: unable to fork off %s\", cmd_name);\n+\t\tdie(_(\"fetch-pack: unable to fork off %s\"), cmd_name);\n \tif (do_keep && pack_lockfile) {\n \t\t*pack_lockfile = index_pack_lockfile(cmd.out);\n \t\tclose(cmd.out);\n@@ -783,9 +782,9 @@ static int get_pack(struct fetch_pack_args *args,\n \t\t\targs->check_self_contained_and_connected &&\n \t\t\tret == 0;\n \telse\n-\t\tdie(\"%s failed\", cmd_name);\n+\t\tdie(_(\"%s failed\"), cmd_name);\n \tif (use_sideband && finish_async(&demux))\n-\t\tdie(\"error in sideband demultiplexer\");\n+\t\tdie(_(\"error in sideband demultiplexer\"));\n \treturn 0;\n }\n \n@@ -812,34 +811,34 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \tqsort(sought, nr_sought, sizeof(*sought), cmp_ref_by_name);\n \n \tif ((args->depth > 0 || is_repository_shallow()) && !server_supports(\"shallow\"))\n-\t\tdie(\"Server does not support shallow clients\");\n+\t\tdie(_(\"Server does not support shallow clients\"));\n \tif (server_supports(\"multi_ack_detailed\")) {\n-\t\tprint_verbose(args, \"Server supports multi_ack_detailed\");\n+\t\tprint_verbose(args, _(\"Server supports multi_ack_detailed\"));\n \t\tmulti_ack = 2;\n \t\tif (server_supports(\"no-done\")) {\n-\t\t\tprint_verbose(args, \"Server supports no-done\");\n+\t\t\tprint_verbose(args, _(\"Server supports no-done\"));\n \t\t\tif (args->stateless_rpc)\n \t\t\t\tno_done = 1;\n \t\t}\n \t}\n \telse if (server_supports(\"multi_ack\")) {\n-\t\tprint_verbose(args, \"Server supports multi_ack\");\n+\t\tprint_verbose(args, _(\"Server supports multi_ack\"));\n \t\tmulti_ack = 1;\n \t}\n \tif (server_supports(\"side-band-64k\")) {\n-\t\tprint_verbose(args, \"Server supports side-band-64k\");\n+\t\tprint_verbose(args, _(\"Server supports side-band-64k\"));\n \t\tuse_sideband = 2;\n \t}\n \telse if (server_supports(\"side-band\")) {\n-\t\tprint_verbose(args, \"Server supports side-band\");\n+\t\tprint_verbose(args, _(\"Server supports side-band\"));\n \t\tuse_sideband = 1;\n \t}\n \tif (server_supports(\"allow-tip-sha1-in-want\")) {\n-\t\tprint_verbose(args, \"Server supports allow-tip-sha1-in-want\");\n+\t\tprint_verbose(args, _(\"Server supports allow-tip-sha1-in-want\"));\n \t\tallow_unadvertised_object_request |= ALLOW_TIP_SHA1;\n \t}\n \tif (server_supports(\"allow-reachable-sha1-in-want\")) {\n-\t\tprint_verbose(args, \"Server supports allow-reachable-sha1-in-want\");\n+\t\tprint_verbose(args, _(\"Server supports allow-reachable-sha1-in-want\"));\n \t\tallow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1;\n \t}\n \tif (!server_supports(\"thin-pack\"))\n@@ -849,14 +848,14 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \tif (!server_supports(\"include-tag\"))\n \t\targs->include_tag = 0;\n \tif (server_supports(\"ofs-delta\"))\n-\t\tprint_verbose(args, \"Server supports ofs-delta\");\n+\t\tprint_verbose(args, _(\"Server supports ofs-delta\"));\n \telse\n \t\tprefer_ofs_delta = 0;\n \n \tif ((agent_feature = server_feature_value(\"agent\", &agent_len))) {\n \t\tagent_supported = 1;\n \t\tif (agent_len)\n-\t\t\tprint_verbose(args, \"Server version is %.*s\",\n+\t\t\tprint_verbose(args, _(\"Server version is %.*s\"),\n \t\t\t\t      agent_len, agent_feature);\n \t}\n \n@@ -869,7 +868,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t\t\t/* When cloning, it is not unusual to have\n \t\t\t * no common commit.\n \t\t\t */\n-\t\t\twarning(\"no common commits\");\n+\t\t\twarning(_(\"no common commits\"));\n \n \tif (args->stateless_rpc)\n \t\tpacket_flush(fd[1]);\n@@ -881,7 +880,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \telse\n \t\talternate_shallow_file = NULL;\n \tif (get_pack(args, fd, pack_lockfile))\n-\t\tdie(\"git fetch-pack: fetch failed.\");\n+\t\tdie(_(\"git fetch-pack: fetch failed.\"));\n \n  all_done:\n \treturn ref;\n@@ -1043,7 +1042,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args,\n \n \tif (!ref) {\n \t\tpacket_flush(fd[1]);\n-\t\tdie(\"no matching remote head\");\n+\t\tdie(_(\"no matching remote head\"));\n \t}\n \tprepare_shallow_info(&si, shallow);\n \tref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought,\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289042","messageId":"20160612105409.22156-15-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 14/27] fetch-pack: use a separate flag for fetch in deepening mode","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:56Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The shallow repo could be deepened or shortened when then user gives\n--depth. But in future that won't be the only way to deepen/shorten a\nrepo. Stop relying on args->depth in this mode. Future deepening\nmethods can simply set this flag on instead of updating all these if\nexpressions.\n\nThe new name \"deepen\" was chosen after the command to define shallow\nboundary in pack protocol. New commands also follow this tradition.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n fetch-pack.c | 14 ++++++++------\n fetch-pack.h |  1 +\n 2 files changed, 9 insertions(+), 6 deletions(-)\n\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 08caf1d..a14d24a 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -197,7 +197,7 @@ enum ack_type {\n \n static void consume_shallow_list(struct fetch_pack_args *args, int fd)\n {\n-\tif (args->stateless_rpc && args->depth > 0) {\n+\tif (args->stateless_rpc && args->deepen) {\n \t\t/* If we sent a depth we will get back \"duplicate\"\n \t\t * shallow and unshallow commands every time there\n \t\t * is a block of have lines exchanged.\n@@ -348,7 +348,7 @@ static int find_common(struct fetch_pack_args *args,\n \tpacket_buf_flush(&req_buf);\n \tstate_len = req_buf.len;\n \n-\tif (args->depth > 0) {\n+\tif (args->deepen) {\n \t\tchar *line;\n \t\tconst char *arg;\n \t\tunsigned char sha1[20];\n@@ -557,7 +557,7 @@ static void filter_refs(struct fetch_pack_args *args,\n \t\t}\n \n \t\tif (!keep && args->fetch_all &&\n-\t\t    (!args->depth || !starts_with(ref->name, \"refs/tags/\")))\n+\t\t    (!args->deepen || !starts_with(ref->name, \"refs/tags/\")))\n \t\t\tkeep = 1;\n \n \t\tif (keep) {\n@@ -627,7 +627,7 @@ static int everything_local(struct fetch_pack_args *args,\n \t\t}\n \t}\n \n-\tif (!args->depth) {\n+\tif (!args->deepen) {\n \t\tfor_each_ref(mark_complete_oid, NULL);\n \t\tfor_each_alternate_ref(mark_alternate_complete, NULL);\n \t\tcommit_list_sort_by_date(&complete);\n@@ -812,6 +812,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \n \tif ((args->depth > 0 || is_repository_shallow()) && !server_supports(\"shallow\"))\n \t\tdie(_(\"Server does not support shallow clients\"));\n+\tif (args->depth > 0)\n+\t\targs->deepen = 1;\n \tif (server_supports(\"multi_ack_detailed\")) {\n \t\tprint_verbose(args, _(\"Server supports multi_ack_detailed\"));\n \t\tmulti_ack = 2;\n@@ -872,7 +874,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \n \tif (args->stateless_rpc)\n \t\tpacket_flush(fd[1]);\n-\tif (args->depth > 0)\n+\tif (args->deepen)\n \t\tsetup_alternate_shallow(&shallow_lock, &alternate_shallow_file,\n \t\t\t\t\tNULL);\n \telse if (si->nr_ours || si->nr_theirs)\n@@ -939,7 +941,7 @@ static void update_shallow(struct fetch_pack_args *args,\n \tint *status;\n \tint i;\n \n-\tif (args->depth > 0 && alternate_shallow_file) {\n+\tif (args->deepen && alternate_shallow_file) {\n \t\tif (*alternate_shallow_file == '\\0') { /* --unshallow */\n \t\t\tunlink_or_warn(git_path_shallow());\n \t\t\trollback_lock_file(&shallow_lock);\ndiff --git a/fetch-pack.h b/fetch-pack.h\nindex bb7fd76..4d0adb0 100644\n--- a/fetch-pack.h\n+++ b/fetch-pack.h\n@@ -25,6 +25,7 @@ struct fetch_pack_args {\n \tunsigned self_contained_and_connected:1;\n \tunsigned cloning:1;\n \tunsigned update_shallow:1;\n+\tunsigned deepen:1;\n };\n \n /*\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289043","messageId":"20160612105409.22156-16-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 15/27] shallow.c: implement a generic shallow boundary finder based on rev-list","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:57Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Instead of a custom commit walker like get_shallow_commits(), this new\nfunction uses rev-list to mark NOT_SHALLOW to all reachable commits,\nexcept borders. The definition of reachable is to be defined by the\nprotocol later. This makes it more flexible to define shallow boundary.\n\nThe way we find border is paint all reachable commits NOT_SHALLOW.  Any\nof them that \"touches\" commits without NOT_SHALLOW flag are considered\nshallow (e.g. zero parents via grafting mechanism). Shallow commits and\ntheir true parents are all marked SHALLOW. Then NOT_SHALLOW is removed\nfrom shallow commits at the end.\n\nThere is an interesting observation. With a generic walker, we can\nproduce all kinds of shallow cutting. In the following graph, every\ncommit but \"x\" is reachable. \"b\" is a parent of \"a\".\n\n           x -- a -- o\n          /    /\n    x -- c -- b -- o\n\nAfter this function is run, \"a\" and \"c\" are both considered shallow\ncommits. After grafting occurs at the client side, what we see is\n\n                a -- o\n                    /\n         c -- b -- o\n\nNotice that because of grafting, \"a\" has zero parents, so \"b\" is no\nlonger a parent of \"a\".\n\nThis is unfortunate and may be solved in two ways. The first is change\nthe way shallow grafting works and keep \"a -- b\" connection if \"b\"\nexists and always ends at shallow commits (iow, no loose ends). This is\nhard to detect, or at least not cheap to do.\n\nThe second way is mark one \"x\" as shallow commit instead of \"a\" and\nproduce this graph at client side:\n\n           x -- a -- o\n               /    /\n         c -- b -- o\n\nMore commits, but simpler grafting rules.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n commit.h  |  2 ++\n shallow.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 80 insertions(+)\n\ndiff --git a/commit.h b/commit.h\nindex 5d58be0..b717be1 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -258,6 +258,8 @@ extern int for_each_commit_graft(each_commit_graft_fn, void *);\n extern int is_repository_shallow(void);\n extern struct commit_list *get_shallow_commits(struct object_array *heads,\n \t\tint depth, int shallow_flag, int not_shallow_flag);\n+extern struct commit_list *get_shallow_commits_by_rev_list(\n+\t\tint ac, const char **av, int shallow_flag, int not_shallow_flag);\n extern void set_alternate_shallow_file(const char *path, int override);\n extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol,\n \t\t\t\t const struct sha1_array *extra);\ndiff --git a/shallow.c b/shallow.c\nindex 60f1505..40c2485 100644\n--- a/shallow.c\n+++ b/shallow.c\n@@ -10,6 +10,8 @@\n #include \"diff.h\"\n #include \"revision.h\"\n #include \"commit-slab.h\"\n+#include \"revision.h\"\n+#include \"list-objects.h\"\n \n static int is_shallow = -1;\n static struct stat_validity shallow_stat;\n@@ -137,6 +139,82 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,\n \treturn result;\n }\n \n+static void show_commit(struct commit *commit, void *data)\n+{\n+\tcommit_list_insert(commit, data);\n+}\n+\n+/*\n+ * Given rev-list arguments, run rev-list. All reachable commits\n+ * except border ones are marked with not_shallow_flag. Border commits\n+ * are marked with shallow_flag. The list of border/shallow commits\n+ * are also returned.\n+ */\n+struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av,\n+\t\t\t\t\t\t    int shallow_flag,\n+\t\t\t\t\t\t    int not_shallow_flag)\n+{\n+\tstruct commit_list *result = NULL, *p;\n+\tstruct commit_list *not_shallow_list = NULL;\n+\tstruct rev_info revs;\n+\tint both_flags = shallow_flag | not_shallow_flag;\n+\n+\t/*\n+\t * SHALLOW (excluded) and NOT_SHALLOW (included) should not be\n+\t * set at this point. But better be safe than sorry.\n+\t */\n+\tclear_object_flags(both_flags);\n+\n+\tis_repository_shallow(); /* make sure shallows are read */\n+\n+\tinit_revisions(&revs, NULL);\n+\tsave_commit_buffer = 0;\n+\tsetup_revisions(ac, av, &revs, NULL);\n+\n+\tif (prepare_revision_walk(&revs))\n+\t\tdie(\"revision walk setup failed\");\n+\ttraverse_commit_list(&revs, show_commit, NULL, &not_shallow_list);\n+\n+\t/* Mark all reachable commits as NOT_SHALLOW */\n+\tfor (p = not_shallow_list; p; p = p->next)\n+\t\tp->item->object.flags |= not_shallow_flag;\n+\n+\t/*\n+\t * mark border commits SHALLOW + NOT_SHALLOW.\n+\t * We cannot clear NOT_SHALLOW right now. Imagine border\n+\t * commit A is processed first, then commit B, whose parent is\n+\t * A, later. If NOT_SHALLOW on A is cleared at step 1, B\n+\t * itself is considered border at step 2, which is incorrect.\n+\t */\n+\tfor (p = not_shallow_list; p; p = p->next) {\n+\t\tstruct commit *c = p->item;\n+\t\tstruct commit_list *parent;\n+\n+\t\tif (parse_commit(c))\n+\t\t\tdie(\"unable to parse commit %s\",\n+\t\t\t    oid_to_hex(&c->object.oid));\n+\n+\t\tfor (parent = c->parents; parent; parent = parent->next)\n+\t\t\tif (!(parent->item->object.flags & not_shallow_flag)) {\n+\t\t\t\tc->object.flags |= shallow_flag;\n+\t\t\t\tcommit_list_insert(c, &result);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t}\n+\tfree_commit_list(not_shallow_list);\n+\n+\t/*\n+\t * Now we can clean up NOT_SHALLOW on border commits. Having\n+\t * both flags set can confuse the caller.\n+\t */\n+\tfor (p = result; p; p = p->next) {\n+\t\tstruct object *o = &p->item->object;\n+\t\tif ((o->flags & both_flags) == both_flags)\n+\t\t\to->flags &= ~not_shallow_flag;\n+\t}\n+\treturn result;\n+}\n+\n static void check_shallow_file_for_update(void)\n {\n \tif (is_shallow == -1)\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289044","messageId":"20160612105409.22156-17-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 16/27] upload-pack: add deepen-since to cut shallow repos based on time","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:58Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This should allow the user to say \"create a shallow clone containing the\nwork from last year\" (once the client side is fixed up, of course).\n\nIn theory deepen-since and deepen (aka --depth) can be used together to\ndraw the shallow boundary (whether it's intersection or union is up to\ndiscussion, but if rev-list is used, it's likely intersection). However,\nbecause deepen goes with a custom commit walker, we can't mix the two\nyet.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/technical/pack-protocol.txt         |  3 +-\n Documentation/technical/protocol-capabilities.txt |  9 +++++\n upload-pack.c                                     | 45 ++++++++++++++++++++++-\n 3 files changed, 54 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt\nindex c6977bb..9251df1 100644\n--- a/Documentation/technical/pack-protocol.txt\n+++ b/Documentation/technical/pack-protocol.txt\n@@ -219,7 +219,8 @@ out of what the server said it could do with the first 'want' line.\n \n   shallow-line      =  PKT-LINE(\"shallow\" SP obj-id)\n \n-  depth-request     =  PKT-LINE(\"deepen\" SP depth)\n+  depth-request     =  PKT-LINE(\"deepen\" SP depth) /\n+\t\t       PKT-LINE(\"deepen-since\" SP timestamp)\n \n   first-want        =  PKT-LINE(\"want\" SP obj-id SP capability-list)\n   additional-want   =  PKT-LINE(\"want\" SP obj-id)\ndiff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt\nindex eaab6b4..f08cc4e 100644\n--- a/Documentation/technical/protocol-capabilities.txt\n+++ b/Documentation/technical/protocol-capabilities.txt\n@@ -179,6 +179,15 @@ This capability adds \"deepen\", \"shallow\" and \"unshallow\" commands to\n the  fetch-pack/upload-pack protocol so clients can request shallow\n clones.\n \n+deepen-since\n+------------\n+\n+This capability adds \"deepen-since\" command to fetch-pack/upload-pack\n+protocol so the client can request shallow clones that are cut at a\n+specific time, instead of depth. Internally it's equivalent of doing\n+\"rev-list --max-age=<timestamp>\" on the server side. \"deepen-since\"\n+cannot be used with \"deepen\".\n+\n no-progress\n -----------\n \ndiff --git a/upload-pack.c b/upload-pack.c\nindex 93c0522..5269461 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -14,6 +14,7 @@\n #include \"sigchain.h\"\n #include \"version.h\"\n #include \"string-list.h\"\n+#include \"argv-array.h\"\n \n static const char upload_pack_usage[] = \"git upload-pack [--strict] [--timeout=<n>] <dir>\";\n \n@@ -629,11 +630,25 @@ static void deepen(int depth, const struct object_array *shallows)\n \tpacket_flush(1);\n }\n \n+static void deepen_by_rev_list(int ac, const char **av,\n+\t\t\t       struct object_array *shallows)\n+{\n+\tstruct commit_list *result;\n+\n+\tresult = get_shallow_commits_by_rev_list(ac, av, SHALLOW, NOT_SHALLOW);\n+\tsend_shallow(result);\n+\tfree_commit_list(result);\n+\tsend_unshallow(shallows);\n+\tpacket_flush(1);\n+}\n+\n static void receive_needs(void)\n {\n \tstruct object_array shallows = OBJECT_ARRAY_INIT;\n \tint depth = 0;\n \tint has_non_tip = 0;\n+\tunsigned long deepen_since = 0;\n+\tint deepen_rev_list = 0;\n \n \tshallow_nr = 0;\n \tfor (;;) {\n@@ -670,6 +685,16 @@ static void receive_needs(void)\n \t\t\t\tdie(\"Invalid deepen: %s\", line);\n \t\t\tcontinue;\n \t\t}\n+\t\tif (skip_prefix(line, \"deepen-since \", &arg)) {\n+\t\t\tchar *end = NULL;\n+\t\t\tdeepen_since = strtoul(arg, &end, 0);\n+\t\t\tif (!end || *end || !deepen_since ||\n+\t\t\t    /* revisions.c's max_age -1 is special */\n+\t\t\t    deepen_since == -1)\n+\t\t\t\tdie(\"Invalid deepen-since: %s\", line);\n+\t\t\tdeepen_rev_list = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!skip_prefix(line, \"want \", &arg) ||\n \t\t    get_sha1_hex(arg, sha1_buf))\n \t\t\tdie(\"git upload-pack: protocol error, \"\n@@ -721,10 +746,26 @@ static void receive_needs(void)\n \tif (!use_sideband && daemon_mode)\n \t\tno_progress = 1;\n \n-\tif (depth == 0 && shallows.nr == 0)\n+\tif (depth == 0 && !deepen_rev_list && shallows.nr == 0)\n \t\treturn;\n+\tif (depth > 0 && deepen_rev_list)\n+\t\tdie(\"git upload-pack: deepen and deepen-since cannot be used together\");\n \tif (depth > 0)\n \t\tdeepen(depth, &shallows);\n+\telse if (deepen_rev_list) {\n+\t\tstruct argv_array av = ARGV_ARRAY_INIT;\n+\t\tint i;\n+\n+\t\targv_array_push(&av, \"rev-list\");\n+\t\tif (deepen_since)\n+\t\t\targv_array_pushf(&av, \"--max-age=%lu\", deepen_since);\n+\t\tfor (i = 0; i < want_obj.nr; i++) {\n+\t\t\tstruct object *o = want_obj.objects[i].item;\n+\t\t\targv_array_push(&av, oid_to_hex(&o->oid));\n+\t\t}\n+\t\tdeepen_by_rev_list(av.argc, av.argv, &shallows);\n+\t\targv_array_clear(&av);\n+\t}\n \telse\n \t\tif (shallows.nr > 0) {\n \t\t\tint i;\n@@ -773,7 +814,7 @@ static int send_ref(const char *refname, const struct object_id *oid,\n \t\t    int flag, void *cb_data)\n {\n \tstatic const char *capabilities = \"multi_ack thin-pack side-band\"\n-\t\t\" side-band-64k ofs-delta shallow no-progress\"\n+\t\t\" side-band-64k ofs-delta shallow deepen-since no-progress\"\n \t\t\" include-tag multi_ack_detailed\";\n \tconst char *refname_nons = strip_namespace(refname);\n \tstruct object_id peeled;\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289045","messageId":"20160612105409.22156-18-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 17/27] fetch: define shallow boundary with --shallow-since","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:53:59Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/fetch-options.txt     |  4 ++++\n Documentation/git-fetch-pack.txt    |  4 ++++\n Documentation/gitremote-helpers.txt |  3 +++\n builtin/fetch-pack.c                |  4 ++++\n builtin/fetch.c                     | 29 +++++++++++++++++++++++------\n fetch-pack.c                        | 12 +++++++++++-\n fetch-pack.h                        |  1 +\n remote-curl.c                       | 11 +++++++++--\n transport.c                         |  4 ++++\n transport.h                         |  4 ++++\n 10 files changed, 67 insertions(+), 9 deletions(-)\n\ndiff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\nindex 952dfdf..8738d3d 100644\n--- a/Documentation/fetch-options.txt\n+++ b/Documentation/fetch-options.txt\n@@ -14,6 +14,10 @@\n \tlinkgit:git-clone[1]), deepen or shorten the history to the specified\n \tnumber of commits. Tags for the deepened commits are not fetched.\n \n+--shallow-since=<date>::\n+\tDeepen or shorten the history of a shallow repository to\n+\tinclude all reachable commits after <date>.\n+\n --unshallow::\n \tIf the source repository is complete, convert a shallow\n \trepository to a complete one, removing all the limitations\ndiff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt\nindex 8680f45..99e6257 100644\n--- a/Documentation/git-fetch-pack.txt\n+++ b/Documentation/git-fetch-pack.txt\n@@ -87,6 +87,10 @@ be in a separate packet, and the list must end with a flush packet.\n \t'git-upload-pack' treats the special depth 2147483647 as\n \tinfinite even if there is an ancestor-chain that long.\n \n+--shallow-since=<date>::\n+\tDeepen or shorten the history of a shallow'repository to\n+\tinclude all reachable commits after <date>.\n+\n --no-progress::\n \tDo not show the progress.\n \ndiff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt\nindex 78e0b27..9971d9a 100644\n--- a/Documentation/gitremote-helpers.txt\n+++ b/Documentation/gitremote-helpers.txt\n@@ -415,6 +415,9 @@ set by Git if the remote helper has the 'option' capability.\n 'option depth' <depth>::\n \tDeepens the history of a shallow repository.\n \n+'option deepen-since <timestamp>::\n+\tDeepens the history of a shallow repository based on time.\n+\n 'option followtags' {'true'|'false'}::\n \tIf enabled the helper should automatically fetch annotated\n \ttag objects if the object the tag points at was transferred\ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex 8332d3d..0402e27 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -104,6 +104,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \t\t\targs.depth = strtol(arg, NULL, 0);\n \t\t\tcontinue;\n \t\t}\n+\t\tif (skip_prefix(arg, \"--shallow-since=\", &arg)) {\n+\t\t\targs.deepen_since = xstrdup(arg);\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(\"--no-progress\", arg)) {\n \t\t\targs.no_progress = 1;\n \t\t\tcontinue;\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 8e74213..283aa95 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -36,9 +36,10 @@ static int prune = -1; /* unspecified */\n \n static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity;\n static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n-static int tags = TAGS_DEFAULT, unshallow, update_shallow;\n+static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;\n static int max_children = 1;\n static const char *depth;\n+static const char *deepen_since;\n static const char *upload_pack;\n static struct strbuf default_rla = STRBUF_INIT;\n static struct transport *gtransport;\n@@ -115,6 +116,8 @@ static struct option builtin_fetch_options[] = {\n \tOPT_BOOL(0, \"progress\", &progress, N_(\"force progress reporting\")),\n \tOPT_STRING(0, \"depth\", &depth, N_(\"depth\"),\n \t\t   N_(\"deepen history of shallow clone\")),\n+\tOPT_STRING(0, \"shallow-since\", &deepen_since, N_(\"time\"),\n+\t\t   N_(\"deepen history of shallow repository based on time\")),\n \t{ OPTION_SET_INT, 0, \"unshallow\", &unshallow, NULL,\n \t\t   N_(\"convert to a complete repository\"),\n \t\t   PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 },\n@@ -754,7 +757,7 @@ static int quickfetch(struct ref *ref_map)\n \t * really need to perform.  Claiming failure now will ensure\n \t * we perform the network exchange to deepen our history.\n \t */\n-\tif (depth)\n+\tif (deepen)\n \t\treturn -1;\n \treturn check_everything_connected(iterate_ref_map, 1, &rm);\n }\n@@ -859,7 +862,7 @@ static void set_option(struct transport *transport, const char *name, const char\n \t\t\tname, transport->url);\n }\n \n-static struct transport *prepare_transport(struct remote *remote)\n+static struct transport *prepare_transport(struct remote *remote, int deepen)\n {\n \tstruct transport *transport;\n \ttransport = transport_get(remote, NULL);\n@@ -870,6 +873,8 @@ static struct transport *prepare_transport(struct remote *remote)\n \t\tset_option(transport, TRANS_OPT_KEEP, \"yes\");\n \tif (depth)\n \t\tset_option(transport, TRANS_OPT_DEPTH, depth);\n+\tif (deepen && deepen_since)\n+\t\tset_option(transport, TRANS_OPT_DEEPEN_SINCE, deepen_since);\n \tif (update_shallow)\n \t\tset_option(transport, TRANS_OPT_UPDATE_SHALLOW, \"yes\");\n \treturn transport;\n@@ -877,8 +882,18 @@ static struct transport *prepare_transport(struct remote *remote)\n \n static void backfill_tags(struct transport *transport, struct ref *ref_map)\n {\n-\tif (transport->cannot_reuse) {\n-\t\tgsecondary = prepare_transport(transport->remote);\n+\tint cannot_reuse;\n+\n+\t/*\n+\t * Once we have set TRANS_OPT_DEEPEN_SINCE, we can't unset it\n+\t * when remote helper is used (setting it to an empty string\n+\t * is not unsetting). We could extend the remote helper\n+\t * protocol for that, but for now, just force a new connection\n+\t * without deepen-since.\n+\t */\n+\tcannot_reuse = transport->cannot_reuse || deepen_since;\n+\tif (cannot_reuse) {\n+\t\tgsecondary = prepare_transport(transport->remote, 0);\n \t\ttransport = gsecondary;\n \t}\n \n@@ -1095,7 +1110,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv)\n \t\tdie(_(\"No remote repository specified.  Please, specify either a URL or a\\n\"\n \t\t    \"remote name from which new revisions should be fetched.\"));\n \n-\tgtransport = prepare_transport(remote);\n+\tgtransport = prepare_transport(remote, 1);\n \n \tif (prune < 0) {\n \t\t/* no command line request */\n@@ -1167,6 +1182,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n \t/* no need to be strict, transport_set_option() will validate it again */\n \tif (depth && atoi(depth) < 1)\n \t\tdie(_(\"depth %s is not a positive number\"), depth);\n+\tif (depth || deepen_since)\n+\t\tdeepen = 1;\n \n \tif (recurse_submodules != RECURSE_SUBMODULES_OFF) {\n \t\tif (recurse_submodules_default) {\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex a14d24a..a2f25c1 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -21,6 +21,7 @@ static int fetch_unpack_limit = -1;\n static int unpack_limit = 100;\n static int prefer_ofs_delta = 1;\n static int no_done;\n+static int deepen_since_ok;\n static int fetch_fsck_objects = -1;\n static int transfer_fsck_objects = -1;\n static int agent_supported;\n@@ -326,6 +327,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\tif (args->no_progress)   strbuf_addstr(&c, \" no-progress\");\n \t\t\tif (args->include_tag)   strbuf_addstr(&c, \" include-tag\");\n \t\t\tif (prefer_ofs_delta)   strbuf_addstr(&c, \" ofs-delta\");\n+\t\t\tif (deepen_since_ok)    strbuf_addstr(&c, \" deepen-since\");\n \t\t\tif (agent_supported)    strbuf_addf(&c, \" agent=%s\",\n \t\t\t\t\t\t\t    git_user_agent_sanitized());\n \t\t\tpacket_buf_write(&req_buf, \"want %s%s\\n\", remote_hex, c.buf);\n@@ -345,6 +347,10 @@ static int find_common(struct fetch_pack_args *args,\n \t\twrite_shallow_commits(&req_buf, 1, NULL);\n \tif (args->depth > 0)\n \t\tpacket_buf_write(&req_buf, \"deepen %d\", args->depth);\n+\tif (args->deepen_since) {\n+\t\tunsigned long max_age = approxidate(args->deepen_since);\n+\t\tpacket_buf_write(&req_buf, \"deepen-since %lu\", max_age);\n+\t}\n \tpacket_buf_flush(&req_buf);\n \tstate_len = req_buf.len;\n \n@@ -812,7 +818,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \n \tif ((args->depth > 0 || is_repository_shallow()) && !server_supports(\"shallow\"))\n \t\tdie(_(\"Server does not support shallow clients\"));\n-\tif (args->depth > 0)\n+\tif (args->depth > 0 || args->deepen_since)\n \t\targs->deepen = 1;\n \tif (server_supports(\"multi_ack_detailed\")) {\n \t\tprint_verbose(args, _(\"Server supports multi_ack_detailed\"));\n@@ -860,6 +866,10 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t\t\tprint_verbose(args, _(\"Server version is %.*s\"),\n \t\t\t\t      agent_len, agent_feature);\n \t}\n+\tif (server_supports(\"deepen-since\"))\n+\t\tdeepen_since_ok = 1;\n+\telse if (args->deepen_since)\n+\t\tdie(_(\"Server does not support --shallow-since\"));\n \n \tif (everything_local(args, &ref, sought, nr_sought)) {\n \t\tpacket_flush(fd[1]);\ndiff --git a/fetch-pack.h b/fetch-pack.h\nindex 4d0adb0..f7eadb2 100644\n--- a/fetch-pack.h\n+++ b/fetch-pack.h\n@@ -10,6 +10,7 @@ struct fetch_pack_args {\n \tconst char *uploadpack;\n \tint unpacklimit;\n \tint depth;\n+\tconst char *deepen_since;\n \tunsigned quiet:1;\n \tunsigned keep_pack:1;\n \tunsigned lock_pack:1;\ndiff --git a/remote-curl.c b/remote-curl.c\nindex fd030c1..5876f24 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -20,6 +20,7 @@ static struct strbuf url = STRBUF_INIT;\n struct options {\n \tint verbosity;\n \tunsigned long depth;\n+\tchar *deepen_since;\n \tunsigned progress : 1,\n \t\tcheck_self_contained_and_connected : 1,\n \t\tcloning : 1,\n@@ -60,6 +61,10 @@ static int set_option(const char *name, const char *value)\n \t\toptions.depth = v;\n \t\treturn 0;\n \t}\n+\telse if (!strcmp(name, \"deepen-since\")) {\n+\t\toptions.deepen_since = xstrdup(value);\n+\t\treturn 0;\n+\t}\n \telse if (!strcmp(name, \"followtags\")) {\n \t\tif (!strcmp(value, \"true\"))\n \t\t\toptions.followtags = 1;\n@@ -699,8 +704,8 @@ static int fetch_dumb(int nr_heads, struct ref **to_fetch)\n \tchar **targets = xmalloc(nr_heads * sizeof(char*));\n \tint ret, i;\n \n-\tif (options.depth)\n-\t\tdie(\"dumb http transport does not support --depth\");\n+\tif (options.depth || options.deepen_since)\n+\t\tdie(\"dumb http transport does not support shallow capabilities\");\n \tfor (i = 0; i < nr_heads; i++)\n \t\ttargets[i] = xstrdup(oid_to_hex(&to_fetch[i]->old_oid));\n \n@@ -746,6 +751,8 @@ static int fetch_git(struct discovery *heads,\n \t\targv_array_push(&args, \"--no-progress\");\n \tif (options.depth)\n \t\targv_array_pushf(&args, \"--depth=%lu\", options.depth);\n+\tif (options.deepen_since)\n+\t\targv_array_pushf(&args, \"--shallow-since=%s\", options.deepen_since);\n \targv_array_push(&args, url.buf);\n \n \tfor (i = 0; i < nr_heads; i++) {\ndiff --git a/transport.c b/transport.c\nindex c92f8ae..f04a302 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -151,6 +151,9 @@ static int set_git_option(struct git_transport_options *opts,\n \t\t\t\tdie(\"transport: invalid depth option '%s'\", value);\n \t\t}\n \t\treturn 0;\n+\t} else if (!strcmp(name, TRANS_OPT_DEEPEN_SINCE)) {\n+\t\topts->deepen_since = value;\n+\t\treturn 0;\n \t}\n \treturn 1;\n }\n@@ -205,6 +208,7 @@ static int fetch_refs_via_pack(struct transport *transport,\n \targs.quiet = (transport->verbose < 0);\n \targs.no_progress = !transport->progress;\n \targs.depth = data->options.depth;\n+\targs.deepen_since = data->options.deepen_since;\n \targs.check_self_contained_and_connected =\n \t\tdata->options.check_self_contained_and_connected;\n \targs.cloning = transport->cloning;\ndiff --git a/transport.h b/transport.h\nindex 8ebaaf2..9c10a44 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -13,6 +13,7 @@ struct git_transport_options {\n \tunsigned self_contained_and_connected : 1;\n \tunsigned update_shallow : 1;\n \tint depth;\n+\tconst char *deepen_since;\n \tconst char *uploadpack;\n \tconst char *receivepack;\n \tstruct push_cas_option *cas;\n@@ -171,6 +172,9 @@ int transport_restrict_protocols(void);\n /* Limit the depth of the fetch if not null */\n #define TRANS_OPT_DEPTH \"depth\"\n \n+/* Limit the depth of the fetch based on time if not null */\n+#define TRANS_OPT_DEEPEN_SINCE \"deepen-since\"\n+\n /* Aggressively fetch annotated tags if possible */\n #define TRANS_OPT_FOLLOWTAGS \"followtags\"\n \n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289046","messageId":"20160612105409.22156-19-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 18/27] clone: define shallow clone boundary based on time with --shallow-since","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:54:00Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-clone.txt |  3 +++\n builtin/clone.c             | 16 +++++++++++++---\n 2 files changed, 16 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt\nindex b7c467a..a410409 100644\n--- a/Documentation/git-clone.txt\n+++ b/Documentation/git-clone.txt\n@@ -193,6 +193,9 @@ objects from the source repository into a pack in the cloned repository.\n \t`--no-single-branch` is given to fetch the histories near the\n \ttips of all branches.\n \n+--shallow-since=<date>::\n+\tCreate a shallow clone with a history after the specified time.\n+\n --[no-]single-branch::\n \tClone only the history leading to the tip of a single branch,\n \teither specified by the `--branch` option or the primary\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex bcba080..dc2ef4f 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -40,7 +40,8 @@ static const char * const builtin_clone_usage[] = {\n \n static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;\n static int option_local = -1, option_no_hardlinks, option_shared, option_recursive;\n-static char *option_template, *option_depth;\n+static int deepen;\n+static char *option_template, *option_depth, *option_since;\n static char *option_origin = NULL;\n static char *option_branch = NULL;\n static const char *real_git_dir;\n@@ -86,6 +87,8 @@ static struct option builtin_clone_options[] = {\n \t\t   N_(\"path to git-upload-pack on the remote\")),\n \tOPT_STRING(0, \"depth\", &option_depth, N_(\"depth\"),\n \t\t    N_(\"create a shallow clone of that depth\")),\n+\tOPT_STRING(0, \"shallow-since\", &option_since, N_(\"time\"),\n+\t\t    N_(\"create a shallow clone since a specific time\")),\n \tOPT_BOOL(0, \"single-branch\", &option_single_branch,\n \t\t    N_(\"clone only one branch, HEAD or --branch\")),\n \tOPT_STRING(0, \"separate-git-dir\", &real_git_dir, N_(\"gitdir\"),\n@@ -849,8 +852,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\tusage_msg_opt(_(\"You must specify a repository to clone.\"),\n \t\t\tbuiltin_clone_usage, builtin_clone_options);\n \n+\tif (option_depth || option_since)\n+\t\tdeepen = 1;\n \tif (option_single_branch == -1)\n-\t\toption_single_branch = option_depth ? 1 : 0;\n+\t\toption_single_branch = deepen ? 1 : 0;\n \n \tif (option_mirror)\n \t\toption_bare = 1;\n@@ -976,6 +981,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \tif (is_local) {\n \t\tif (option_depth)\n \t\t\twarning(_(\"--depth is ignored in local clones; use file:// instead.\"));\n+\t\tif (option_since)\n+\t\t\twarning(_(\"--shallow-since is ignored in local clones; use file:// instead.\"));\n \t\tif (!access(mkpath(\"%s/shallow\", path), F_OK)) {\n \t\t\tif (option_local > 0)\n \t\t\t\twarning(_(\"source repository is shallow, ignoring --local\"));\n@@ -994,6 +1001,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \tif (option_depth)\n \t\ttransport_set_option(transport, TRANS_OPT_DEPTH,\n \t\t\t\t     option_depth);\n+\tif (option_since)\n+\t\ttransport_set_option(transport, TRANS_OPT_DEEPEN_SINCE,\n+\t\t\t\t     option_since);\n \tif (option_single_branch)\n \t\ttransport_set_option(transport, TRANS_OPT_FOLLOWTAGS, \"1\");\n \n@@ -1001,7 +1011,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\ttransport_set_option(transport, TRANS_OPT_UPLOADPACK,\n \t\t\t\t     option_upload_pack);\n \n-\tif (transport->smart_options && !option_depth)\n+\tif (transport->smart_options && !deepen)\n \t\ttransport->smart_options->check_self_contained_and_connected = 1;\n \n \trefs = transport_get_remote_refs(transport);\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289047","messageId":"20160612105409.22156-21-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 20/27] refs: add expand_ref()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:54:02Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is basically dwim_ref() without @{} support. To be used on the\nserver side where we want to expand abbreviated to full ref names and\nnothing else. The first user is \"git clone/fetch --shallow-exclude\".\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n refs.c | 8 +++++++-\n refs.h | 1 +\n 2 files changed, 8 insertions(+), 1 deletion(-)\n\ndiff --git a/refs.c b/refs.c\nindex e2d34b2..842e4d8 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -392,6 +392,13 @@ static char *substitute_branch_name(const char **string, int *len)\n int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)\n {\n \tchar *last_branch = substitute_branch_name(&str, &len);\n+\tint   refs_found  = expand_ref(str, len, sha1, ref);\n+\tfree(last_branch);\n+\treturn refs_found;\n+}\n+\n+int expand_ref(const char *str, int len, unsigned char *sha1, char **ref)\n+{\n \tconst char **p, *r;\n \tint refs_found = 0;\n \n@@ -417,7 +424,6 @@ int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)\n \t\t\twarning(\"ignoring broken ref %s.\", fullref);\n \t\t}\n \t}\n-\tfree(last_branch);\n \treturn refs_found;\n }\n \ndiff --git a/refs.h b/refs.h\nindex 3c3da29..31a2fa6 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -90,6 +90,7 @@ extern int resolve_gitlink_ref(const char *path, const char *refname, unsigned c\n  */\n extern int refname_match(const char *abbrev_name, const char *full_name);\n \n+extern int expand_ref(const char *str, int len, unsigned char *sha1, char **ref);\n extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);\n extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);\n \n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289048","messageId":"20160612105409.22156-20-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 19/27] t5500, t5539: tests for shallow depth since a specific date","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:54:01Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t5500-fetch-pack.sh         | 24 ++++++++++++++++++++++++\n t/t5539-fetch-http-shallow.sh | 25 +++++++++++++++++++++++++\n 2 files changed, 49 insertions(+)\n\ndiff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh\nindex e5f83bf..26f050d 100755\n--- a/t/t5500-fetch-pack.sh\n+++ b/t/t5500-fetch-pack.sh\n@@ -637,4 +637,28 @@ test_expect_success MINGW 'fetch-pack --diag-url c:repo' '\n \tcheck_prot_path c:repo file c:repo\n '\n \n+test_expect_success 'clone shallow since ...' '\n+\ttest_create_repo shallow-since &&\n+\t(\n+\tcd shallow-since &&\n+\tGIT_COMMITTER_DATE=\"100000000 +0700\" git commit --allow-empty -m one &&\n+\tGIT_COMMITTER_DATE=\"200000000 +0700\" git commit --allow-empty -m two &&\n+\tGIT_COMMITTER_DATE=\"300000000 +0700\" git commit --allow-empty -m three &&\n+\tgit clone --shallow-since \"300000000 +0700\" \"file://$(pwd)/.\" ../shallow11 &&\n+\tgit -C ../shallow11 log --pretty=tformat:%s HEAD >actual &&\n+\techo three >expected &&\n+\ttest_cmp expected actual\n+\t)\n+'\n+\n+test_expect_success 'fetch shallow since ...' '\n+\tgit -C shallow11 fetch --shallow-since \"200000000 +0700\" origin &&\n+\tgit -C shallow11 log --pretty=tformat:%s origin/master >actual &&\n+\tcat >expected <<-\\EOF &&\n+\tthree\n+\ttwo\n+\tEOF\n+\ttest_cmp expected actual\n+'\n+\n test_done\ndiff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh\nindex 37a4335..704753c 100755\n--- a/t/t5539-fetch-http-shallow.sh\n+++ b/t/t5539-fetch-http-shallow.sh\n@@ -73,5 +73,30 @@ test_expect_success 'no shallow lines after receiving ACK ready' '\n \t)\n '\n \n+test_expect_success 'clone shallow since ...' '\n+\ttest_create_repo shallow-since &&\n+\t(\n+\tcd shallow-since &&\n+\tGIT_COMMITTER_DATE=\"100000000 +0700\" git commit --allow-empty -m one &&\n+\tGIT_COMMITTER_DATE=\"200000000 +0700\" git commit --allow-empty -m two &&\n+\tGIT_COMMITTER_DATE=\"300000000 +0700\" git commit --allow-empty -m three &&\n+\tmv .git \"$HTTPD_DOCUMENT_ROOT_PATH/shallow-since.git\" &&\n+\tgit clone --shallow-since \"300000000 +0700\" $HTTPD_URL/smart/shallow-since.git ../shallow11 &&\n+\tgit -C ../shallow11 log --pretty=tformat:%s HEAD >actual &&\n+\techo three >expected &&\n+\ttest_cmp expected actual\n+\t)\n+'\n+\n+test_expect_success 'fetch shallow since ...' '\n+\tgit -C shallow11 fetch --shallow-since \"200000000 +0700\" origin &&\n+\tgit -C shallow11 log --pretty=tformat:%s origin/master >actual &&\n+\tcat >expected <<-\\EOF &&\n+\tthree\n+\ttwo\n+\tEOF\n+\ttest_cmp expected actual\n+'\n+\n stop_httpd\n test_done\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289049","messageId":"20160612105409.22156-23-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 22/27] fetch: define shallow boundary with --shallow-exclude","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:54:04Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/fetch-options.txt     |  5 +++++\n Documentation/git-fetch-pack.txt    |  5 +++++\n Documentation/gitremote-helpers.txt |  4 ++++\n builtin/fetch-pack.c                |  7 +++++++\n builtin/fetch.c                     | 13 ++++++++++---\n fetch-pack.c                        | 15 ++++++++++++++-\n fetch-pack.h                        |  1 +\n remote-curl.c                       |  9 +++++++++\n transport-helper.c                  | 24 ++++++++++++++++++++++++\n transport.c                         |  4 ++++\n transport.h                         |  6 ++++++\n 11 files changed, 89 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\nindex 8738d3d..7aa1285 100644\n--- a/Documentation/fetch-options.txt\n+++ b/Documentation/fetch-options.txt\n@@ -18,6 +18,11 @@\n \tDeepen or shorten the history of a shallow repository to\n \tinclude all reachable commits after <date>.\n \n+--shallow-exclude=<revision>::\n+\tDeepen or shorten the history of a shallow repository to\n+\texclude commits reachable from a specified remote branch or tag.\n+\tThis option can be specified multiple times.\n+\n --unshallow::\n \tIf the source repository is complete, convert a shallow\n \trepository to a complete one, removing all the limitations\ndiff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt\nindex 99e6257..4d15b04 100644\n--- a/Documentation/git-fetch-pack.txt\n+++ b/Documentation/git-fetch-pack.txt\n@@ -91,6 +91,11 @@ be in a separate packet, and the list must end with a flush packet.\n \tDeepen or shorten the history of a shallow'repository to\n \tinclude all reachable commits after <date>.\n \n+--shallow-exclude=<revision>::\n+\tDeepen or shorten the history of a shallow repository to\n+\texclude commits reachable from a specified remote branch or tag.\n+\tThis option can be specified multiple times.\n+\n --no-progress::\n \tDo not show the progress.\n \ndiff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt\nindex 9971d9a..75bb638 100644\n--- a/Documentation/gitremote-helpers.txt\n+++ b/Documentation/gitremote-helpers.txt\n@@ -418,6 +418,10 @@ set by Git if the remote helper has the 'option' capability.\n 'option deepen-since <timestamp>::\n \tDeepens the history of a shallow repository based on time.\n \n+'option deepen-not <ref>::\n+\tDeepens the history of a shallow repository excluding ref.\n+\tMultiple options add up.\n+\n 'option followtags' {'true'|'false'}::\n \tIf enabled the helper should automatically fetch annotated\n \ttag objects if the object the tag points at was transferred\ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex 0402e27..07570be 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -50,6 +50,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \tstruct child_process *conn;\n \tstruct fetch_pack_args args;\n \tstruct sha1_array shallow = SHA1_ARRAY_INIT;\n+\tstruct string_list deepen_not = STRING_LIST_INIT_DUP;\n \n \tpacket_trace_identity(\"fetch-pack\");\n \n@@ -108,6 +109,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \t\t\targs.deepen_since = xstrdup(arg);\n \t\t\tcontinue;\n \t\t}\n+\t\tif (skip_prefix(arg, \"--shallow-exclude=\", &arg)) {\n+\t\t\tstring_list_append(&deepen_not, arg);\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(\"--no-progress\", arg)) {\n \t\t\targs.no_progress = 1;\n \t\t\tcontinue;\n@@ -135,6 +140,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \t\t}\n \t\tusage(fetch_pack_usage);\n \t}\n+\tif (deepen_not.nr)\n+\t\targs.deepen_not = &deepen_not;\n \n \tif (i < argc)\n \t\tdest = argv[i++];\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 283aa95..147504d 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -41,6 +41,7 @@ static int max_children = 1;\n static const char *depth;\n static const char *deepen_since;\n static const char *upload_pack;\n+static struct string_list deepen_not = STRING_LIST_INIT_NODUP;\n static struct strbuf default_rla = STRBUF_INIT;\n static struct transport *gtransport;\n static struct transport *gsecondary;\n@@ -118,6 +119,8 @@ static struct option builtin_fetch_options[] = {\n \t\t   N_(\"deepen history of shallow clone\")),\n \tOPT_STRING(0, \"shallow-since\", &deepen_since, N_(\"time\"),\n \t\t   N_(\"deepen history of shallow repository based on time\")),\n+\tOPT_STRING_LIST(0, \"shallow-exclude\", &deepen_not, N_(\"revision\"),\n+\t\t\tN_(\"deepen history of shallow clone by excluding rev\")),\n \t{ OPTION_SET_INT, 0, \"unshallow\", &unshallow, NULL,\n \t\t   N_(\"convert to a complete repository\"),\n \t\t   PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 },\n@@ -875,6 +878,9 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)\n \t\tset_option(transport, TRANS_OPT_DEPTH, depth);\n \tif (deepen && deepen_since)\n \t\tset_option(transport, TRANS_OPT_DEEPEN_SINCE, deepen_since);\n+\tif (deepen && deepen_not.nr)\n+\t\tset_option(transport, TRANS_OPT_DEEPEN_NOT,\n+\t\t\t   (const char *)&deepen_not);\n \tif (update_shallow)\n \t\tset_option(transport, TRANS_OPT_UPDATE_SHALLOW, \"yes\");\n \treturn transport;\n@@ -889,9 +895,10 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)\n \t * when remote helper is used (setting it to an empty string\n \t * is not unsetting). We could extend the remote helper\n \t * protocol for that, but for now, just force a new connection\n-\t * without deepen-since.\n+\t * without deepen-since. Similar story for deepen-not.\n \t */\n-\tcannot_reuse = transport->cannot_reuse || deepen_since;\n+\tcannot_reuse = transport->cannot_reuse ||\n+\t\tdeepen_since || deepen_not.nr;\n \tif (cannot_reuse) {\n \t\tgsecondary = prepare_transport(transport->remote, 0);\n \t\ttransport = gsecondary;\n@@ -1182,7 +1189,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n \t/* no need to be strict, transport_set_option() will validate it again */\n \tif (depth && atoi(depth) < 1)\n \t\tdie(_(\"depth %s is not a positive number\"), depth);\n-\tif (depth || deepen_since)\n+\tif (depth || deepen_since || deepen_not.nr)\n \t\tdeepen = 1;\n \n \tif (recurse_submodules != RECURSE_SUBMODULES_OFF) {\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex a2f25c1..ad7d00f 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -22,6 +22,7 @@ static int unpack_limit = 100;\n static int prefer_ofs_delta = 1;\n static int no_done;\n static int deepen_since_ok;\n+static int deepen_not_ok;\n static int fetch_fsck_objects = -1;\n static int transfer_fsck_objects = -1;\n static int agent_supported;\n@@ -328,6 +329,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\tif (args->include_tag)   strbuf_addstr(&c, \" include-tag\");\n \t\t\tif (prefer_ofs_delta)   strbuf_addstr(&c, \" ofs-delta\");\n \t\t\tif (deepen_since_ok)    strbuf_addstr(&c, \" deepen-since\");\n+\t\t\tif (deepen_not_ok)      strbuf_addstr(&c, \" deepen-not\");\n \t\t\tif (agent_supported)    strbuf_addf(&c, \" agent=%s\",\n \t\t\t\t\t\t\t    git_user_agent_sanitized());\n \t\t\tpacket_buf_write(&req_buf, \"want %s%s\\n\", remote_hex, c.buf);\n@@ -351,6 +353,13 @@ static int find_common(struct fetch_pack_args *args,\n \t\tunsigned long max_age = approxidate(args->deepen_since);\n \t\tpacket_buf_write(&req_buf, \"deepen-since %lu\", max_age);\n \t}\n+\tif (args->deepen_not) {\n+\t\tint i;\n+\t\tfor (i = 0; i < args->deepen_not->nr; i++) {\n+\t\t\tstruct string_list_item *s = args->deepen_not->items + i;\n+\t\t\tpacket_buf_write(&req_buf, \"deepen-not %s\", s->string);\n+\t\t}\n+\t}\n \tpacket_buf_flush(&req_buf);\n \tstate_len = req_buf.len;\n \n@@ -818,7 +827,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \n \tif ((args->depth > 0 || is_repository_shallow()) && !server_supports(\"shallow\"))\n \t\tdie(_(\"Server does not support shallow clients\"));\n-\tif (args->depth > 0 || args->deepen_since)\n+\tif (args->depth > 0 || args->deepen_since || args->deepen_not)\n \t\targs->deepen = 1;\n \tif (server_supports(\"multi_ack_detailed\")) {\n \t\tprint_verbose(args, _(\"Server supports multi_ack_detailed\"));\n@@ -870,6 +879,10 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t\tdeepen_since_ok = 1;\n \telse if (args->deepen_since)\n \t\tdie(_(\"Server does not support --shallow-since\"));\n+\tif (server_supports(\"deepen-not\"))\n+\t\tdeepen_not_ok = 1;\n+\telse if (args->deepen_not)\n+\t\tdie(_(\"Server does not support --shallow-exclude\"));\n \n \tif (everything_local(args, &ref, sought, nr_sought)) {\n \t\tpacket_flush(fd[1]);\ndiff --git a/fetch-pack.h b/fetch-pack.h\nindex f7eadb2..144301f 100644\n--- a/fetch-pack.h\n+++ b/fetch-pack.h\n@@ -11,6 +11,7 @@ struct fetch_pack_args {\n \tint unpacklimit;\n \tint depth;\n \tconst char *deepen_since;\n+\tconst struct string_list *deepen_not;\n \tunsigned quiet:1;\n \tunsigned keep_pack:1;\n \tunsigned lock_pack:1;\ndiff --git a/remote-curl.c b/remote-curl.c\nindex 5876f24..1406e6a 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -21,6 +21,7 @@ struct options {\n \tint verbosity;\n \tunsigned long depth;\n \tchar *deepen_since;\n+\tstruct string_list deepen_not;\n \tunsigned progress : 1,\n \t\tcheck_self_contained_and_connected : 1,\n \t\tcloning : 1,\n@@ -65,6 +66,10 @@ static int set_option(const char *name, const char *value)\n \t\toptions.deepen_since = xstrdup(value);\n \t\treturn 0;\n \t}\n+\telse if (!strcmp(name, \"deepen-not\")) {\n+\t\tstring_list_append(&options.deepen_not, value);\n+\t\treturn 0;\n+\t}\n \telse if (!strcmp(name, \"followtags\")) {\n \t\tif (!strcmp(value, \"true\"))\n \t\t\toptions.followtags = 1;\n@@ -753,6 +758,9 @@ static int fetch_git(struct discovery *heads,\n \t\targv_array_pushf(&args, \"--depth=%lu\", options.depth);\n \tif (options.deepen_since)\n \t\targv_array_pushf(&args, \"--shallow-since=%s\", options.deepen_since);\n+\tfor (i = 0; i < options.deepen_not.nr; i++)\n+\t\targv_array_pushf(&args, \"--shallow-exclude=%s\",\n+\t\t\t\t options.deepen_not.items[i].string);\n \targv_array_push(&args, url.buf);\n \n \tfor (i = 0; i < nr_heads; i++) {\n@@ -973,6 +981,7 @@ int main(int argc, const char **argv)\n \toptions.verbosity = 1;\n \toptions.progress = !!isatty(2);\n \toptions.thin = 1;\n+\tstring_list_init(&options.deepen_not, 1);\n \n \tremote = remote_get(argv[1]);\n \ndiff --git a/transport-helper.c b/transport-helper.c\nindex 27a34e9..cc1a396 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -282,6 +282,26 @@ static int strbuf_set_helper_option(struct helper_data *data,\n \treturn ret;\n }\n \n+static int string_list_set_helper_option(struct helper_data *data,\n+\t\t\t\t\t const char *name,\n+\t\t\t\t\t struct string_list *list)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint i, ret = 0;\n+\n+\tfor (i = 0; i < list->nr; i++) {\n+\t\tstrbuf_addf(&buf, \"option %s \", name);\n+\t\tquote_c_style(list->items[i].string, &buf, NULL, 0);\n+\t\tstrbuf_addch(&buf, '\\n');\n+\n+\t\tif ((ret = strbuf_set_helper_option(data, &buf)))\n+\t\t\tbreak;\n+\t\tstrbuf_reset(&buf);\n+\t}\n+\tstrbuf_release(&buf);\n+\treturn ret;\n+}\n+\n static int set_helper_option(struct transport *transport,\n \t\t\t  const char *name, const char *value)\n {\n@@ -294,6 +314,10 @@ static int set_helper_option(struct transport *transport,\n \tif (!data->option)\n \t\treturn 1;\n \n+\tif (!strcmp(name, \"deepen-not\"))\n+\t\treturn string_list_set_helper_option(data, name,\n+\t\t\t\t\t\t     (struct string_list *)value);\n+\n \tfor (i = 0; i < ARRAY_SIZE(unsupported_options); i++) {\n \t\tif (!strcmp(name, unsupported_options[i]))\n \t\t\treturn 1;\ndiff --git a/transport.c b/transport.c\nindex f04a302..3e6f3aa 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -154,6 +154,9 @@ static int set_git_option(struct git_transport_options *opts,\n \t} else if (!strcmp(name, TRANS_OPT_DEEPEN_SINCE)) {\n \t\topts->deepen_since = value;\n \t\treturn 0;\n+\t} else if (!strcmp(name, TRANS_OPT_DEEPEN_NOT)) {\n+\t\topts->deepen_not = (const struct string_list *)value;\n+\t\treturn 0;\n \t}\n \treturn 1;\n }\n@@ -209,6 +212,7 @@ static int fetch_refs_via_pack(struct transport *transport,\n \targs.no_progress = !transport->progress;\n \targs.depth = data->options.depth;\n \targs.deepen_since = data->options.deepen_since;\n+\targs.deepen_not = data->options.deepen_not;\n \targs.check_self_contained_and_connected =\n \t\tdata->options.check_self_contained_and_connected;\n \targs.cloning = transport->cloning;\ndiff --git a/transport.h b/transport.h\nindex 9c10a44..ab61932 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -5,6 +5,8 @@\n #include \"run-command.h\"\n #include \"remote.h\"\n \n+struct string_list;\n+\n struct git_transport_options {\n \tunsigned thin : 1;\n \tunsigned keep : 1;\n@@ -14,6 +16,7 @@ struct git_transport_options {\n \tunsigned update_shallow : 1;\n \tint depth;\n \tconst char *deepen_since;\n+\tconst struct string_list *deepen_not;\n \tconst char *uploadpack;\n \tconst char *receivepack;\n \tstruct push_cas_option *cas;\n@@ -175,6 +178,9 @@ int transport_restrict_protocols(void);\n /* Limit the depth of the fetch based on time if not null */\n #define TRANS_OPT_DEEPEN_SINCE \"deepen-since\"\n \n+/* Limit the depth of the fetch based on revs if not null */\n+#define TRANS_OPT_DEEPEN_NOT \"deepen-not\"\n+\n /* Aggressively fetch annotated tags if possible */\n #define TRANS_OPT_FOLLOWTAGS \"followtags\"\n \n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289050","messageId":"20160612105409.22156-22-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 21/27] upload-pack: support define shallow boundary by excluding revisions","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:54:03Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This should allow the user to say \"create a shallow clone of this branch\nafter version <some-tag>\".\n\nShort refs are accepted and expanded at the server side with expand_ref()\nbecause we cannot expand (unknown) refs from the client side.\n\nLike deepen-since, deepen-not cannot be used with deepen. But deepen-not\ncan be mixed with deepen-since. The result is exactly how you do the\ncommand \"git rev-list --since=... --not ref\".\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/technical/pack-protocol.txt         |  3 ++-\n Documentation/technical/protocol-capabilities.txt |  9 +++++++++\n upload-pack.c                                     | 23 +++++++++++++++++++++--\n 3 files changed, 32 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt\nindex 9251df1..dee33a6 100644\n--- a/Documentation/technical/pack-protocol.txt\n+++ b/Documentation/technical/pack-protocol.txt\n@@ -220,7 +220,8 @@ out of what the server said it could do with the first 'want' line.\n   shallow-line      =  PKT-LINE(\"shallow\" SP obj-id)\n \n   depth-request     =  PKT-LINE(\"deepen\" SP depth) /\n-\t\t       PKT-LINE(\"deepen-since\" SP timestamp)\n+\t\t       PKT-LINE(\"deepen-since\" SP timestamp) /\n+\t\t       PKT-LINE(\"deepen-not\" SP ref)\n \n   first-want        =  PKT-LINE(\"want\" SP obj-id SP capability-list)\n   additional-want   =  PKT-LINE(\"want\" SP obj-id)\ndiff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt\nindex f08cc4e..0e6b57d 100644\n--- a/Documentation/technical/protocol-capabilities.txt\n+++ b/Documentation/technical/protocol-capabilities.txt\n@@ -188,6 +188,15 @@ specific time, instead of depth. Internally it's equivalent of doing\n \"rev-list --max-age=<timestamp>\" on the server side. \"deepen-since\"\n cannot be used with \"deepen\".\n \n+deepen-not\n+----------\n+\n+This capability adds \"deepen-not\" command to fetch-pack/upload-pack\n+protocol so the client can request shallow clones that are cut at a\n+specific revision, instead of depth. Internally it's equivalent of\n+doing \"rev-list --not <rev>\" on the server side. \"deepen-not\"\n+cannot be used with \"deepen\", but can be used with \"deepen-since\".\n+\n no-progress\n -----------\n \ndiff --git a/upload-pack.c b/upload-pack.c\nindex 5269461..acc6d97 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -645,6 +645,7 @@ static void deepen_by_rev_list(int ac, const char **av,\n static void receive_needs(void)\n {\n \tstruct object_array shallows = OBJECT_ARRAY_INIT;\n+\tstruct string_list deepen_not = STRING_LIST_INIT_DUP;\n \tint depth = 0;\n \tint has_non_tip = 0;\n \tunsigned long deepen_since = 0;\n@@ -695,6 +696,16 @@ static void receive_needs(void)\n \t\t\tdeepen_rev_list = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (skip_prefix(line, \"deepen-not \", &arg)) {\n+\t\t\tchar *ref = NULL;\n+\t\t\tunsigned char sha1[20];\n+\t\t\tif (expand_ref(arg, strlen(arg), sha1, &ref) != 1)\n+\t\t\t\tdie(\"git upload-pack: ambiguous deepen-not: %s\", line);\n+\t\t\tstring_list_append(&deepen_not, ref);\n+\t\t\tfree(ref);\n+\t\t\tdeepen_rev_list = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!skip_prefix(line, \"want \", &arg) ||\n \t\t    get_sha1_hex(arg, sha1_buf))\n \t\t\tdie(\"git upload-pack: protocol error, \"\n@@ -749,7 +760,7 @@ static void receive_needs(void)\n \tif (depth == 0 && !deepen_rev_list && shallows.nr == 0)\n \t\treturn;\n \tif (depth > 0 && deepen_rev_list)\n-\t\tdie(\"git upload-pack: deepen and deepen-since cannot be used together\");\n+\t\tdie(\"git upload-pack: deepen and deepen-since (or deepen-not) cannot be used together\");\n \tif (depth > 0)\n \t\tdeepen(depth, &shallows);\n \telse if (deepen_rev_list) {\n@@ -759,6 +770,14 @@ static void receive_needs(void)\n \t\targv_array_push(&av, \"rev-list\");\n \t\tif (deepen_since)\n \t\t\targv_array_pushf(&av, \"--max-age=%lu\", deepen_since);\n+\t\tif (deepen_not.nr) {\n+\t\t\targv_array_push(&av, \"--not\");\n+\t\t\tfor (i = 0; i < deepen_not.nr; i++) {\n+\t\t\t\tstruct string_list_item *s = deepen_not.items + i;\n+\t\t\t\targv_array_push(&av, s->string);\n+\t\t\t}\n+\t\t\targv_array_push(&av, \"--not\");\n+\t\t}\n \t\tfor (i = 0; i < want_obj.nr; i++) {\n \t\t\tstruct object *o = want_obj.objects[i].item;\n \t\t\targv_array_push(&av, oid_to_hex(&o->oid));\n@@ -814,7 +833,7 @@ static int send_ref(const char *refname, const struct object_id *oid,\n \t\t    int flag, void *cb_data)\n {\n \tstatic const char *capabilities = \"multi_ack thin-pack side-band\"\n-\t\t\" side-band-64k ofs-delta shallow deepen-since no-progress\"\n+\t\t\" side-band-64k ofs-delta shallow deepen-since deepen-not no-progress\"\n \t\t\" include-tag multi_ack_detailed\";\n \tconst char *refname_nons = strip_namespace(refname);\n \tstruct object_id peeled;\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289051","messageId":"20160612105409.22156-25-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 24/27] t5500, t5539: tests for shallow depth excluding a ref","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:54:06Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t5500-fetch-pack.sh         | 21 +++++++++++++++++++++\n t/t5539-fetch-http-shallow.sh | 22 ++++++++++++++++++++++\n 2 files changed, 43 insertions(+)\n\ndiff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh\nindex 26f050d..145b370 100755\n--- a/t/t5500-fetch-pack.sh\n+++ b/t/t5500-fetch-pack.sh\n@@ -661,4 +661,25 @@ test_expect_success 'fetch shallow since ...' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'shallow clone exclude tag two' '\n+\ttest_create_repo shallow-exclude &&\n+\t(\n+\tcd shallow-exclude &&\n+\ttest_commit one &&\n+\ttest_commit two &&\n+\ttest_commit three &&\n+\tgit clone --shallow-exclude two \"file://$(pwd)/.\" ../shallow12 &&\n+\tgit -C ../shallow12 log --pretty=tformat:%s HEAD >actual &&\n+\techo three >expected &&\n+\ttest_cmp expected actual\n+\t)\n+'\n+\n+test_expect_success 'fetch exclude tag one' '\n+\tgit -C shallow12 fetch --shallow-exclude one origin &&\n+\tgit -C shallow12 log --pretty=tformat:%s origin/master >actual &&\n+\ttest_write_lines three two >expected &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\ndiff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh\nindex 704753c..8e38c1b 100755\n--- a/t/t5539-fetch-http-shallow.sh\n+++ b/t/t5539-fetch-http-shallow.sh\n@@ -98,5 +98,27 @@ test_expect_success 'fetch shallow since ...' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'shallow clone exclude tag two' '\n+\ttest_create_repo shallow-exclude &&\n+\t(\n+\tcd shallow-exclude &&\n+\ttest_commit one &&\n+\ttest_commit two &&\n+\ttest_commit three &&\n+\tmv .git \"$HTTPD_DOCUMENT_ROOT_PATH/shallow-exclude.git\" &&\n+\tgit clone --shallow-exclude two $HTTPD_URL/smart/shallow-exclude.git ../shallow12 &&\n+\tgit -C ../shallow12 log --pretty=tformat:%s HEAD >actual &&\n+\techo three >expected &&\n+\ttest_cmp expected actual\n+\t)\n+'\n+\n+test_expect_success 'fetch exclude tag one' '\n+\tgit -C shallow12 fetch --shallow-exclude one origin &&\n+\tgit -C shallow12 log --pretty=tformat:%s origin/master >actual &&\n+\ttest_write_lines three two >expected &&\n+\ttest_cmp expected actual\n+'\n+\n stop_httpd\n test_done\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289052","messageId":"20160612105409.22156-24-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 23/27] clone: define shallow clone boundary with --shallow-exclude","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:54:05Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-clone.txt |  5 +++++\n builtin/clone.c             | 10 +++++++++-\n 2 files changed, 14 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt\nindex a410409..5049663 100644\n--- a/Documentation/git-clone.txt\n+++ b/Documentation/git-clone.txt\n@@ -196,6 +196,11 @@ objects from the source repository into a pack in the cloned repository.\n --shallow-since=<date>::\n \tCreate a shallow clone with a history after the specified time.\n \n+--shallow-exclude=<revision>::\n+\tCreate a shallow clone with a history, excluding commits\n+\treachable from a specified remote branch or tag.  This option\n+\tcan be specified multiple times.\n+\n --[no-]single-branch::\n \tClone only the history leading to the tip of a single branch,\n \teither specified by the `--branch` option or the primary\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex dc2ef4f..3849231 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -44,6 +44,7 @@ static int deepen;\n static char *option_template, *option_depth, *option_since;\n static char *option_origin = NULL;\n static char *option_branch = NULL;\n+static struct string_list option_not = STRING_LIST_INIT_NODUP;\n static const char *real_git_dir;\n static char *option_upload_pack = \"git-upload-pack\";\n static int option_verbosity;\n@@ -89,6 +90,8 @@ static struct option builtin_clone_options[] = {\n \t\t    N_(\"create a shallow clone of that depth\")),\n \tOPT_STRING(0, \"shallow-since\", &option_since, N_(\"time\"),\n \t\t    N_(\"create a shallow clone since a specific time\")),\n+\tOPT_STRING_LIST(0, \"shallow-exclude\", &option_not, N_(\"revision\"),\n+\t\t\tN_(\"deepen history of shallow clone by excluding rev\")),\n \tOPT_BOOL(0, \"single-branch\", &option_single_branch,\n \t\t    N_(\"clone only one branch, HEAD or --branch\")),\n \tOPT_STRING(0, \"separate-git-dir\", &real_git_dir, N_(\"gitdir\"),\n@@ -852,7 +855,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\tusage_msg_opt(_(\"You must specify a repository to clone.\"),\n \t\t\tbuiltin_clone_usage, builtin_clone_options);\n \n-\tif (option_depth || option_since)\n+\tif (option_depth || option_since || option_not.nr)\n \t\tdeepen = 1;\n \tif (option_single_branch == -1)\n \t\toption_single_branch = deepen ? 1 : 0;\n@@ -983,6 +986,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\t\twarning(_(\"--depth is ignored in local clones; use file:// instead.\"));\n \t\tif (option_since)\n \t\t\twarning(_(\"--shallow-since is ignored in local clones; use file:// instead.\"));\n+\t\tif (option_not.nr)\n+\t\t\twarning(_(\"--shallow-exclude is ignored in local clones; use file:// instead.\"));\n \t\tif (!access(mkpath(\"%s/shallow\", path), F_OK)) {\n \t\t\tif (option_local > 0)\n \t\t\t\twarning(_(\"source repository is shallow, ignoring --local\"));\n@@ -1004,6 +1009,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \tif (option_since)\n \t\ttransport_set_option(transport, TRANS_OPT_DEEPEN_SINCE,\n \t\t\t\t     option_since);\n+\tif (option_not.nr)\n+\t\ttransport_set_option(transport, TRANS_OPT_DEEPEN_NOT,\n+\t\t\t\t     (const char *)&option_not);\n \tif (option_single_branch)\n \t\ttransport_set_option(transport, TRANS_OPT_FOLLOWTAGS, \"1\");\n \n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289053","messageId":"20160612105409.22156-26-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 25/27] upload-pack: split check_unreachable() in two, prep for get_reachable_list()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:54:07Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n upload-pack.c | 56 ++++++++++++++++++++++++++++++++++++++------------------\n 1 file changed, 38 insertions(+), 18 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex acc6d97..adb8e33 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -452,21 +452,24 @@ static int is_our_ref(struct object *o)\n \treturn o->flags & ((allow_hidden_ref ? HIDDEN_REF : 0) | OUR_REF);\n }\n \n-static int has_unreachable(struct object_array *src)\n+/*\n+ * on successful case, it's up to the caller to close cmd->out\n+ */\n+static int do_reachable_revlist(struct child_process *cmd,\n+\t\t\t\tstruct object_array *src)\n {\n \tstatic const char *argv[] = {\n \t\t\"rev-list\", \"--stdin\", NULL,\n \t};\n-\tstatic struct child_process cmd = CHILD_PROCESS_INIT;\n \tstruct object *o;\n \tchar namebuf[42]; /* ^ + SHA-1 + LF */\n \tint i;\n \n-\tcmd.argv = argv;\n-\tcmd.git_cmd = 1;\n-\tcmd.no_stderr = 1;\n-\tcmd.in = -1;\n-\tcmd.out = -1;\n+\tcmd->argv = argv;\n+\tcmd->git_cmd = 1;\n+\tcmd->no_stderr = 1;\n+\tcmd->in = -1;\n+\tcmd->out = -1;\n \n \t/*\n \t * If the next rev-list --stdin encounters an unknown commit,\n@@ -475,7 +478,7 @@ static int has_unreachable(struct object_array *src)\n \t */\n \tsigchain_push(SIGPIPE, SIG_IGN);\n \n-\tif (start_command(&cmd))\n+\tif (start_command(cmd))\n \t\tgoto error;\n \n \tnamebuf[0] = '^';\n@@ -487,7 +490,7 @@ static int has_unreachable(struct object_array *src)\n \t\tif (!is_our_ref(o))\n \t\t\tcontinue;\n \t\tmemcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n-\t\tif (write_in_full(cmd.in, namebuf, 42) < 0)\n+\t\tif (write_in_full(cmd->in, namebuf, 42) < 0)\n \t\t\tgoto error;\n \t}\n \tnamebuf[40] = '\\n';\n@@ -496,17 +499,39 @@ static int has_unreachable(struct object_array *src)\n \t\tif (is_our_ref(o))\n \t\t\tcontinue;\n \t\tmemcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n-\t\tif (write_in_full(cmd.in, namebuf, 41) < 0)\n+\t\tif (write_in_full(cmd->in, namebuf, 41) < 0)\n \t\t\tgoto error;\n \t}\n-\tclose(cmd.in);\n-\tcmd.in = -1;\n+\tclose(cmd->in);\n+\tcmd->in = -1;\n+\tsigchain_pop(SIGPIPE);\n+\n+\treturn 0;\n+\n+error:\n+\tsigchain_pop(SIGPIPE);\n+\n+\tif (cmd->in >= 0)\n+\t\tclose(cmd->in);\n+\tif (cmd->out >= 0)\n+\t\tclose(cmd->out);\n+\treturn -1;\n+}\n+\n+static int has_unreachable(struct object_array *src)\n+{\n+\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\tchar buf[1];\n+\tint i;\n+\n+\tif (do_reachable_revlist(&cmd, src) < 0)\n+\t\treturn 1;\n \n \t/*\n \t * The commits out of the rev-list are not ancestors of\n \t * our ref.\n \t */\n-\ti = read_in_full(cmd.out, namebuf, 1);\n+\ti = read_in_full(cmd.out, buf, 1);\n \tif (i)\n \t\tgoto error;\n \tclose(cmd.out);\n@@ -520,16 +545,11 @@ static int has_unreachable(struct object_array *src)\n \tif (finish_command(&cmd))\n \t\tgoto error;\n \n-\tsigchain_pop(SIGPIPE);\n-\n \t/* All the non-tip ones are ancestors of what we advertised */\n \treturn 0;\n \n error:\n \tsigchain_pop(SIGPIPE);\n-\n-\tif (cmd.in >= 0)\n-\t\tclose(cmd.in);\n \tif (cmd.out >= 0)\n \t\tclose(cmd.out);\n \treturn 1;\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289054","messageId":"20160612105409.22156-27-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 26/27] upload-pack: add get_reachable_list()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:54:08Z","receivedAt":"2016-06-16T02:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n object.h      |  2 +-\n upload-pack.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++---\n 2 files changed, 50 insertions(+), 4 deletions(-)\n\ndiff --git a/object.h b/object.h\nindex f8b6442..614a006 100644\n--- a/object.h\n+++ b/object.h\n@@ -31,7 +31,7 @@ struct object_array {\n  * revision.h:      0---------10                                26\n  * fetch-pack.c:    0---4\n  * walker.c:        0-2\n- * upload-pack.c:               11----------------19\n+ * upload-pack.c:       4       11----------------19\n  * builtin/blame.c:               12-13\n  * bisect.c:                               16\n  * bundle.c:                               16\ndiff --git a/upload-pack.c b/upload-pack.c\nindex adb8e33..3227df8 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -456,7 +456,8 @@ static int is_our_ref(struct object *o)\n  * on successful case, it's up to the caller to close cmd->out\n  */\n static int do_reachable_revlist(struct child_process *cmd,\n-\t\t\t\tstruct object_array *src)\n+\t\t\t\tstruct object_array *src,\n+\t\t\t\tstruct object_array *reachable)\n {\n \tstatic const char *argv[] = {\n \t\t\"rev-list\", \"--stdin\", NULL,\n@@ -487,6 +488,8 @@ static int do_reachable_revlist(struct child_process *cmd,\n \t\to = get_indexed_object(--i);\n \t\tif (!o)\n \t\t\tcontinue;\n+\t\tif (reachable && o->type == OBJ_COMMIT)\n+\t\t\to->flags &= ~TMP_MARK;\n \t\tif (!is_our_ref(o))\n \t\t\tcontinue;\n \t\tmemcpy(namebuf + 1, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n@@ -496,8 +499,13 @@ static int do_reachable_revlist(struct child_process *cmd,\n \tnamebuf[40] = '\\n';\n \tfor (i = 0; i < src->nr; i++) {\n \t\to = src->objects[i].item;\n-\t\tif (is_our_ref(o))\n+\t\tif (is_our_ref(o)) {\n+\t\t\tif (reachable)\n+\t\t\t\tadd_object_array(o, NULL, reachable);\n \t\t\tcontinue;\n+\t\t}\n+\t\tif (reachable && o->type == OBJ_COMMIT)\n+\t\t\to->flags |= TMP_MARK;\n \t\tmemcpy(namebuf, oid_to_hex(&o->oid), GIT_SHA1_HEXSZ);\n \t\tif (write_in_full(cmd->in, namebuf, 41) < 0)\n \t\t\tgoto error;\n@@ -518,13 +526,51 @@ error:\n \treturn -1;\n }\n \n+static int get_reachable_list(struct object_array *src,\n+\t\t\t      struct object_array *reachable)\n+{\n+\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\tint i;\n+\tstruct object *o;\n+\tchar namebuf[42]; /* ^ + SHA-1 + LF */\n+\n+\tif (do_reachable_revlist(&cmd, src, reachable) < 0)\n+\t\treturn -1;\n+\n+\twhile ((i = read_in_full(cmd.out, namebuf, 41)) == 41) {\n+\t\tstruct object_id sha1;\n+\n+\t\tif (namebuf[40] != '\\n' || get_oid_hex(namebuf, &sha1))\n+\t\t\tbreak;\n+\n+\t\to = lookup_object(sha1.hash);\n+\t\tif (o && o->type == OBJ_COMMIT) {\n+\t\t\to->flags &= ~TMP_MARK;\n+\t\t}\n+\t}\n+\tfor (i = get_max_object_index(); 0 < i; i--) {\n+\t\to = get_indexed_object(i - 1);\n+\t\tif (o && o->type == OBJ_COMMIT &&\n+\t\t    (o->flags & TMP_MARK)) {\n+\t\t\tadd_object_array(o, NULL, reachable);\n+\t\t\t\to->flags &= ~TMP_MARK;\n+\t\t}\n+\t}\n+\tclose(cmd.out);\n+\n+\tif (finish_command(&cmd))\n+\t\treturn -1;\n+\n+\treturn 0;\n+}\n+\n static int has_unreachable(struct object_array *src)\n {\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n \tchar buf[1];\n \tint i;\n \n-\tif (do_reachable_revlist(&cmd, src) < 0)\n+\tif (do_reachable_revlist(&cmd, src, NULL) < 0)\n \t\treturn 1;\n \n \t/*\n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289055","messageId":"20160612105409.22156-28-pclouds@gmail.com","threadId":"42576","inReplyTo":"20160612105409.22156-1-pclouds@gmail.com","subject":"[PATCH v2 27/27] fetch, upload-pack: --deepen=N extends shallow boundary by N commits","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-12T10:54:09Z","receivedAt":"2016-06-16T02:19:53Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"In git-fetch, --depth argument is always relative with the latest\nremote refs. This makes it a bit difficult to cover this use case,\nwhere the user wants to make the shallow history, say 3 levels\ndeeper. It would work if remote refs have not moved yet, but nobody\ncan guarantee that, especially when that use case is performed a\ncouple months after the last clone or \"git fetch --depth\". Also,\nmodifying shallow boundary using --depth does not work well with\nclones created by --since or --not.\n\nThis patch fixes that. A new argument --deepen=<N> will add <N> more (*)\nparent commits to the current history regardless of where remote refs\nare.\n\nHave/Want negotiation is still respected. So if remote refs move, the\nserver will send two chunks: one between \"have\" and \"want\" and another\nto extend shallow history. In theory, the client could send no \"want\"s\nin order to get the second chunk only. But the protocol does not allow\nthat. Either you send no want lines, which means ls-remote; or you\nhave to send at least one want line that carries deep-relative to the\nserver..\n\nThe main work was done by Dongcan Jiang. I fixed it up here and there.\nAnd of course all the bugs belong to me.\n\n(*) We could even support --deepen=<N> where <N> is negative. In that\ncase we can cut some history from the shallow clone. This operation\n(and --depth=<shorter depth>) does not require interaction with remote\nside (and more complicated to implement as a result).\n\nHelped-by: Duy Nguyen <pclouds@gmail.com>\nHelped-by: Eric Sunshine <sunshine@sunshineco.com>\nHelped-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Dongcan Jiang <dongcan.jiang@gmail.com>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/fetch-options.txt                   |  5 +++++\n Documentation/git-fetch-pack.txt                  |  5 +++++\n Documentation/gitremote-helpers.txt               |  4 ++++\n Documentation/technical/protocol-capabilities.txt |  7 ++++++\n builtin/fetch-pack.c                              |  4 ++++\n builtin/fetch.c                                   | 14 +++++++++++-\n fetch-pack.c                                      |  3 +++\n fetch-pack.h                                      |  1 +\n remote-curl.c                                     | 14 +++++++++++-\n t/t5500-fetch-pack.sh                             | 23 ++++++++++++++++++++\n t/t5539-fetch-http-shallow.sh                     | 26 +++++++++++++++++++++++\n transport-helper.c                                |  1 +\n transport.c                                       |  4 ++++\n transport.h                                       |  4 ++++\n upload-pack.c                                     | 23 ++++++++++++++++----\n 15 files changed, 132 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\nindex 7aa1285..3b91f15 100644\n--- a/Documentation/fetch-options.txt\n+++ b/Documentation/fetch-options.txt\n@@ -14,6 +14,11 @@\n \tlinkgit:git-clone[1]), deepen or shorten the history to the specified\n \tnumber of commits. Tags for the deepened commits are not fetched.\n \n+--deepen=<depth>::\n+\tSimilar to --depth, except it specifies the number of commits\n+\tfrom the current shallow boundary instead of from the tip of\n+\teach remote branch history.\n+\n --shallow-since=<date>::\n \tDeepen or shorten the history of a shallow repository to\n \tinclude all reachable commits after <date>.\ndiff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt\nindex 4d15b04..c20958f 100644\n--- a/Documentation/git-fetch-pack.txt\n+++ b/Documentation/git-fetch-pack.txt\n@@ -96,6 +96,11 @@ be in a separate packet, and the list must end with a flush packet.\n \texclude commits reachable from a specified remote branch or tag.\n \tThis option can be specified multiple times.\n \n+--deepen-relative::\n+\tArgument --depth specifies the number of commits from the\n+\tcurrent shallow boundary instead of from the tip of each\n+\tremote branch history.\n+\n --no-progress::\n \tDo not show the progress.\n \ndiff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt\nindex 75bb638..6fca268 100644\n--- a/Documentation/gitremote-helpers.txt\n+++ b/Documentation/gitremote-helpers.txt\n@@ -422,6 +422,10 @@ set by Git if the remote helper has the 'option' capability.\n \tDeepens the history of a shallow repository excluding ref.\n \tMultiple options add up.\n \n+'option deepen-relative {'true'|'false'}::\n+\tDeepens the history of a shallow repository relative to\n+\tcurrent boundary. Only valid when used with \"option depth\".\n+\n 'option followtags' {'true'|'false'}::\n \tIf enabled the helper should automatically fetch annotated\n \ttag objects if the object the tag points at was transferred\ndiff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt\nindex 0e6b57d..4fd6dcc 100644\n--- a/Documentation/technical/protocol-capabilities.txt\n+++ b/Documentation/technical/protocol-capabilities.txt\n@@ -197,6 +197,13 @@ specific revision, instead of depth. Internally it's equivalent of\n doing \"rev-list --not <rev>\" on the server side. \"deepen-not\"\n cannot be used with \"deepen\", but can be used with \"deepen-since\".\n \n+deepen-relative\n+---------------\n+\n+If this capability is requested by the client, the semantics of\n+\"deepen\" command is changed. The \"depth\" argument is the depth from\n+the current shallow boundary, instead of the depth from remote refs.\n+\n no-progress\n -----------\n \ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex 07570be..8265348 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -113,6 +113,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \t\t\tstring_list_append(&deepen_not, arg);\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--deepen-relative\")) {\n+\t\t\targs.deepen_relative = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(\"--no-progress\", arg)) {\n \t\t\targs.no_progress = 1;\n \t\t\tcontinue;\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 147504d..7b0ea1c 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -34,7 +34,7 @@ static int fetch_prune_config = -1; /* unspecified */\n static int prune = -1; /* unspecified */\n #define PRUNE_BY_DEFAULT 0 /* do we prune by default? */\n \n-static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity;\n+static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative;\n static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;\n static int max_children = 1;\n@@ -121,6 +121,8 @@ static struct option builtin_fetch_options[] = {\n \t\t   N_(\"deepen history of shallow repository based on time\")),\n \tOPT_STRING_LIST(0, \"shallow-exclude\", &deepen_not, N_(\"revision\"),\n \t\t\tN_(\"deepen history of shallow clone by excluding rev\")),\n+\tOPT_INTEGER(0, \"deepen\", &deepen_relative,\n+\t\t    N_(\"deepen history of shallow clone\")),\n \t{ OPTION_SET_INT, 0, \"unshallow\", &unshallow, NULL,\n \t\t   N_(\"convert to a complete repository\"),\n \t\t   PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 },\n@@ -881,6 +883,8 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)\n \tif (deepen && deepen_not.nr)\n \t\tset_option(transport, TRANS_OPT_DEEPEN_NOT,\n \t\t\t   (const char *)&deepen_not);\n+\tif (deepen_relative)\n+\t\tset_option(transport, TRANS_OPT_DEEPEN_RELATIVE, \"yes\");\n \tif (update_shallow)\n \t\tset_option(transport, TRANS_OPT_UPDATE_SHALLOW, \"yes\");\n \treturn transport;\n@@ -906,6 +910,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)\n \n \ttransport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);\n \ttransport_set_option(transport, TRANS_OPT_DEPTH, \"0\");\n+\ttransport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);\n \tfetch_refs(transport, ref_map);\n \n \tif (gsecondary) {\n@@ -1177,6 +1182,13 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix,\n \t\t\t     builtin_fetch_options, builtin_fetch_usage, 0);\n \n+\tif (deepen_relative) {\n+\t\tif (deepen_relative < 0)\n+\t\t\tdie(_(\"Negative depth in --deepen is not supported\"));\n+\t\tif (depth)\n+\t\t\tdie(_(\"--deepen and --depth are mutually exclusive\"));\n+\t\tdepth = xstrfmt(\"%d\", deepen_relative);\n+\t}\n \tif (unshallow) {\n \t\tif (depth)\n \t\t\tdie(_(\"--depth and --unshallow cannot be used together\"));\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex ad7d00f..e2a235f 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -324,6 +324,7 @@ static int find_common(struct fetch_pack_args *args,\n \t\t\tif (no_done)            strbuf_addstr(&c, \" no-done\");\n \t\t\tif (use_sideband == 2)  strbuf_addstr(&c, \" side-band-64k\");\n \t\t\tif (use_sideband == 1)  strbuf_addstr(&c, \" side-band\");\n+\t\t\tif (args->deepen_relative) strbuf_addstr(&c, \" deepen-relative\");\n \t\t\tif (args->use_thin_pack) strbuf_addstr(&c, \" thin-pack\");\n \t\t\tif (args->no_progress)   strbuf_addstr(&c, \" no-progress\");\n \t\t\tif (args->include_tag)   strbuf_addstr(&c, \" include-tag\");\n@@ -883,6 +884,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,\n \t\tdeepen_not_ok = 1;\n \telse if (args->deepen_not)\n \t\tdie(_(\"Server does not support --shallow-exclude\"));\n+\tif (!server_supports(\"deepen-relative\") && args->deepen_relative)\n+\t\tdie(_(\"Server does not support --deepen\"));\n \n \tif (everything_local(args, &ref, sought, nr_sought)) {\n \t\tpacket_flush(fd[1]);\ndiff --git a/fetch-pack.h b/fetch-pack.h\nindex 144301f..c912e3d 100644\n--- a/fetch-pack.h\n+++ b/fetch-pack.h\n@@ -12,6 +12,7 @@ struct fetch_pack_args {\n \tint depth;\n \tconst char *deepen_since;\n \tconst struct string_list *deepen_not;\n+\tunsigned deepen_relative:1;\n \tunsigned quiet:1;\n \tunsigned keep_pack:1;\n \tunsigned lock_pack:1;\ndiff --git a/remote-curl.c b/remote-curl.c\nindex 1406e6a..d56412d 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -30,7 +30,8 @@ struct options {\n \t\tdry_run : 1,\n \t\tthin : 1,\n \t\t/* One of the SEND_PACK_PUSH_CERT_* constants. */\n-\t\tpush_cert : 2;\n+\t\tpush_cert : 2,\n+\t\tdeepen_relative : 1;\n };\n static struct options options;\n static struct string_list cas_options = STRING_LIST_INIT_DUP;\n@@ -70,6 +71,15 @@ static int set_option(const char *name, const char *value)\n \t\tstring_list_append(&options.deepen_not, value);\n \t\treturn 0;\n \t}\n+\telse if (!strcmp(name, \"deepen-relative\")) {\n+\t\tif (!strcmp(value, \"true\"))\n+\t\t\toptions.deepen_relative = 1;\n+\t\telse if (!strcmp(value, \"false\"))\n+\t\t\toptions.deepen_relative = 0;\n+\t\telse\n+\t\t\treturn -1;\n+\t\treturn 0;\n+\t}\n \telse if (!strcmp(name, \"followtags\")) {\n \t\tif (!strcmp(value, \"true\"))\n \t\t\toptions.followtags = 1;\n@@ -761,6 +771,8 @@ static int fetch_git(struct discovery *heads,\n \tfor (i = 0; i < options.deepen_not.nr; i++)\n \t\targv_array_pushf(&args, \"--shallow-exclude=%s\",\n \t\t\t\t options.deepen_not.items[i].string);\n+\tif (options.deepen_relative && options.depth)\n+\t\targv_array_push(&args, \"--deepen-relative\");\n \targv_array_push(&args, url.buf);\n \n \tfor (i = 0; i < nr_heads; i++) {\ndiff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh\nindex 145b370..a908036 100755\n--- a/t/t5500-fetch-pack.sh\n+++ b/t/t5500-fetch-pack.sh\n@@ -682,4 +682,27 @@ test_expect_success 'fetch exclude tag one' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'fetching deepen' '\n+\ttest_create_repo shallow-deepen &&\n+\t(\n+\tcd shallow-deepen &&\n+\ttest_commit one &&\n+\ttest_commit two &&\n+\ttest_commit three &&\n+\tgit clone --depth 1 \"file://$(pwd)/.\" deepen &&\n+\ttest_commit four &&\n+\tgit -C deepen log --pretty=tformat:%s master >actual &&\n+\techo three >expected &&\n+\ttest_cmp expected actual &&\n+\tgit -C deepen fetch --deepen=1 &&\n+\tgit -C deepen log --pretty=tformat:%s origin/master >actual &&\n+\tcat >expected <<-\\EOF &&\n+\tfour\n+\tthree\n+\ttwo\n+\tEOF\n+\ttest_cmp expected actual\n+\t)\n+'\n+\n test_done\ndiff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh\nindex 8e38c1b..5fbf67c 100755\n--- a/t/t5539-fetch-http-shallow.sh\n+++ b/t/t5539-fetch-http-shallow.sh\n@@ -120,5 +120,31 @@ test_expect_success 'fetch exclude tag one' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'fetching deepen' '\n+\ttest_create_repo shallow-deepen &&\n+\t(\n+\tcd shallow-deepen &&\n+\ttest_commit one &&\n+\ttest_commit two &&\n+\ttest_commit three &&\n+\tmv .git \"$HTTPD_DOCUMENT_ROOT_PATH/shallow-deepen.git\" &&\n+\tgit clone --depth 1 $HTTPD_URL/smart/shallow-deepen.git deepen &&\n+\tmv \"$HTTPD_DOCUMENT_ROOT_PATH/shallow-deepen.git\" .git &&\n+\ttest_commit four &&\n+\tgit -C deepen log --pretty=tformat:%s master >actual &&\n+\techo three >expected &&\n+\ttest_cmp expected actual &&\n+\tmv .git \"$HTTPD_DOCUMENT_ROOT_PATH/shallow-deepen.git\" &&\n+\tgit -C deepen fetch --deepen=1 &&\n+\tgit -C deepen log --pretty=tformat:%s origin/master >actual &&\n+\tcat >expected <<-\\EOF &&\n+\tfour\n+\tthree\n+\ttwo\n+\tEOF\n+\ttest_cmp expected actual\n+\t)\n+'\n+\n stop_httpd\n test_done\ndiff --git a/transport-helper.c b/transport-helper.c\nindex cc1a396..a5cdd77 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -258,6 +258,7 @@ static const char *boolean_options[] = {\n \tTRANS_OPT_THIN,\n \tTRANS_OPT_KEEP,\n \tTRANS_OPT_FOLLOWTAGS,\n+\tTRANS_OPT_DEEPEN_RELATIVE\n \t};\n \n static int strbuf_set_helper_option(struct helper_data *data,\ndiff --git a/transport.c b/transport.c\nindex 3e6f3aa..3e76a9a 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -157,6 +157,9 @@ static int set_git_option(struct git_transport_options *opts,\n \t} else if (!strcmp(name, TRANS_OPT_DEEPEN_NOT)) {\n \t\topts->deepen_not = (const struct string_list *)value;\n \t\treturn 0;\n+\t} else if (!strcmp(name, TRANS_OPT_DEEPEN_RELATIVE)) {\n+\t\topts->deepen_relative = !!value;\n+\t\treturn 0;\n \t}\n \treturn 1;\n }\n@@ -213,6 +216,7 @@ static int fetch_refs_via_pack(struct transport *transport,\n \targs.depth = data->options.depth;\n \targs.deepen_since = data->options.deepen_since;\n \targs.deepen_not = data->options.deepen_not;\n+\targs.deepen_relative = data->options.deepen_relative;\n \targs.check_self_contained_and_connected =\n \t\tdata->options.check_self_contained_and_connected;\n \targs.cloning = transport->cloning;\ndiff --git a/transport.h b/transport.h\nindex ab61932..bdc3518 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -14,6 +14,7 @@ struct git_transport_options {\n \tunsigned check_self_contained_and_connected : 1;\n \tunsigned self_contained_and_connected : 1;\n \tunsigned update_shallow : 1;\n+\tunsigned deepen_relative : 1;\n \tint depth;\n \tconst char *deepen_since;\n \tconst struct string_list *deepen_not;\n@@ -181,6 +182,9 @@ int transport_restrict_protocols(void);\n /* Limit the depth of the fetch based on revs if not null */\n #define TRANS_OPT_DEEPEN_NOT \"deepen-not\"\n \n+/* Limit the deepen of the fetch if not null */\n+#define TRANS_OPT_DEEPEN_RELATIVE \"deepen-relative\"\n+\n /* Aggressively fetch annotated tags if possible */\n #define TRANS_OPT_FOLLOWTAGS \"followtags\"\n \ndiff --git a/upload-pack.c b/upload-pack.c\nindex 3227df8..e40d15a 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -32,6 +32,7 @@ static const char upload_pack_usage[] = \"git upload-pack [--strict] [--timeout=<\n \n static unsigned long oldest_have;\n \n+static int deepen_relative;\n static int multi_ack;\n static int no_done;\n static int use_thin_pack, use_ofs_delta, use_include_tag;\n@@ -674,7 +675,8 @@ static void send_unshallow(const struct object_array *shallows)\n \t}\n }\n \n-static void deepen(int depth, const struct object_array *shallows)\n+static void deepen(int depth, int deepen_relative,\n+\t\t   struct object_array *shallows)\n {\n \tif (depth == INFINITE_DEPTH && !is_repository_shallow()) {\n \t\tint i;\n@@ -683,6 +685,17 @@ static void deepen(int depth, const struct object_array *shallows)\n \t\t\tstruct object *object = shallows->objects[i].item;\n \t\t\tobject->flags |= NOT_SHALLOW;\n \t\t}\n+\t} else if (deepen_relative) {\n+\t\tstruct object_array reachable_shallows = OBJECT_ARRAY_INIT;\n+\t\tstruct commit_list *result;\n+\n+\t\tget_reachable_list(shallows, &reachable_shallows);\n+\t\tresult = get_shallow_commits(&reachable_shallows,\n+\t\t\t\t\t     depth + 1,\n+\t\t\t\t\t     SHALLOW, NOT_SHALLOW);\n+\t\tsend_shallow(result);\n+\t\tfree_commit_list(result);\n+\t\tobject_array_clear(&reachable_shallows);\n \t} else {\n \t\tstruct commit_list *result;\n \n@@ -779,6 +792,8 @@ static void receive_needs(void)\n \n \t\tfeatures = arg + 40;\n \n+\t\tif (parse_feature_request(features, \"deepen-relative\"))\n+\t\t\tdeepen_relative = 1;\n \t\tif (parse_feature_request(features, \"multi_ack_detailed\"))\n \t\t\tmulti_ack = 2;\n \t\telse if (parse_feature_request(features, \"multi_ack\"))\n@@ -828,7 +843,7 @@ static void receive_needs(void)\n \tif (depth > 0 && deepen_rev_list)\n \t\tdie(\"git upload-pack: deepen and deepen-since (or deepen-not) cannot be used together\");\n \tif (depth > 0)\n-\t\tdeepen(depth, &shallows);\n+\t\tdeepen(depth, deepen_relative, &shallows);\n \telse if (deepen_rev_list) {\n \t\tstruct argv_array av = ARGV_ARRAY_INIT;\n \t\tint i;\n@@ -899,8 +914,8 @@ static int send_ref(const char *refname, const struct object_id *oid,\n \t\t    int flag, void *cb_data)\n {\n \tstatic const char *capabilities = \"multi_ack thin-pack side-band\"\n-\t\t\" side-band-64k ofs-delta shallow deepen-since deepen-not no-progress\"\n-\t\t\" include-tag multi_ack_detailed\";\n+\t\t\" side-band-64k ofs-delta shallow deepen-since deepen-not\"\n+\t\t\" deepen-relative no-progress include-tag multi_ack_detailed\";\n \tconst char *refname_nons = strip_namespace(refname);\n \tstruct object_id peeled;\n \n-- \n2.8.2.524.g6ff3d78\n"},{"id":"289156","messageId":"xmqqr3c1c8we.fsf@gitster.mtv.corp.google.com","threadId":"42576","inReplyTo":"CAPig+cRfUjpku1Abf=GxrbFeS4txwr=yZsJ7EKo-aWmxYog6Xw@mail.gmail.com","subject":"Re: [PATCH 00/27] nd/shallow-deepen updates","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-06-13T17:10:09Z","receivedAt":"2016-06-16T06:55:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> I agree with Junio that moving the sigchain_pop() into the error\n> handling code-path, if possible, would be a nice improvement.\n\nYeah, \"if possible\" is really what I was not sure about---is it safe\nto do the _push() thing before start_command(), which presumably\nwould affect both the main and the forked processes?\n"},{"id":"289197","messageId":"CACsJy8BAawP+599R7iKYcEa+DJ=Gc_Zv11ma5SSqA0eCki1p=g@mail.gmail.com","threadId":"42576","inReplyTo":"xmqqr3c1c8we.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 00/27] nd/shallow-deepen updates","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-06-14T09:21:22Z","receivedAt":"2016-06-16T06:55:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Jun 14, 2016 at 12:10 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Eric Sunshine <sunshine@sunshineco.com> writes:\n>\n>> I agree with Junio that moving the sigchain_pop() into the error\n>> handling code-path, if possible, would be a nice improvement.\n>\n> Yeah, \"if possible\" is really what I was not sure about---is it safe\n> to do the _push() thing before start_command(), which presumably\n> would affect both the main and the forked processes?\n\nGood point. But we do exec() very shortly in the forked process, which\nshould reset signal table back to default. So probably not a bad\nthing.\n-- \nDuy\n"}]}