{"thread":{"id":"9428","subject":"resumable git-clone?","startedAt":"2007-08-07T13:23:51Z","lastAt":"2007-08-09T12:32:50Z","messageCount":11,"participants":["Nguyen Thai Ngoc Duy","Shawn O. Pearce","Johannes Schindelin","Junio C Hamano","Mark Levedahl"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"50125","messageId":"fcaeb9bf0708070623p24f1cae2q2af959a89738c4e8@mail.gmail.com","threadId":"9428","inReplyTo":null,"subject":"resumable git-clone?","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2007-08-07T13:23:51Z","receivedAt":"2007-08-07T13:23:51Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"I was on a crappy connection and it was frustrated seeing git-clone\nreached 80% then failed, then started over again. Can we support\nresumable git-clone at some level? I think we could split into several\nsmall packs, keep fetched ones, just get missing packs until we have\nall.\nI didn't clone via http so I don't know if http supports resumable.\n-- \nDuy\n"},{"id":"50169","messageId":"20070808035946.GP9527@spearce.org","threadId":"9428","inReplyTo":"fcaeb9bf0708070623p24f1cae2q2af959a89738c4e8@mail.gmail.com","subject":"Re: resumable git-clone?","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2007-08-08T03:59:46Z","receivedAt":"2007-08-08T03:59:46Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:\n> I was on a crappy connection and it was frustrated seeing git-clone\n> reached 80% then failed, then started over again. Can we support\n> resumable git-clone at some level? I think we could split into several\n> small packs, keep fetched ones, just get missing packs until we have\n> all.\n\nThis is uh, difficult over the native git protocol.  The problem\nis the native protocol negotiates what the client already has and\nwhat it needs by comparing sets of commits.  If the client says\n\"I have commit X\" then the server assumes it has not only commit\nX _but also every object reachable from it_.\n\nNow packfiles are organized to place commits at the front of the\npackfile.  So a truncated download will give the client a whole\nhost of commits, like maybe all of them, but none of the trees\nor blobs associated with them as those come behind the commits.\nWorse, the commits are sorted most recent to least recent.  So if\nthe client claims he has the very first commit he received, that\nis currently an assertion that he has the entire repository.\n\nI have been thinking about this resumable fetch idea for the native\nprotocol for a few days now, like since the last time it came up\non #git.\n\nOne possiblity is to have the client store locally in a temporary\nfile the list of wants and the list of haves it sent to the server\nduring the last fetch.\n\nDuring a resume of a packfile download we actually just replay this\nlist of wants/haves, even if the server has newer data.  We also tell\nthe server which object we last successfully downloaded (its SHA-1).\n\nThe server would only accept the resumed want list if all of the\nwants are reachable from its current refs.  If one or more aren't\nthen they are just culled from the want list; this way you can still\nsuccessfully resume a download of say git.git where pu rebases often.\nYou just might not get pu without going back for it.\n\nIf the server always performs a very stable (meaning we don't ever\nchange the sorting order!) and deterministic sorting of the objects\nin the packfile then given the same list of wants/haves and a\n\"prior\" point it can pickup from where it left off.\n\nAt worst we are retransmitting one whole object again, e.g. the\nclient had all but the last byte of the object, so it was no good.\nI'm willing to say we do the full object retransmission in case the\nobject was recompressed on the server between the first fetch and\nthe second.  It just simplifies the restart.\n\nProbably not that difficult.  The hardest part is committing to the\nobject sorting order so that when we ask for a restart we *know*\nwe didn't miss an object.\n\n> I didn't clone via http so I don't know if http supports resumable.\n\nThis would have a better chance at doing a resume.  Looking at the\ncode it looks like we do in fact resume a packfile download if it\nwas truncated.\n\n-- \nShawn.\n"},{"id":"50182","messageId":"Pine.LNX.4.64.0708081012110.14781@racer.site","threadId":"9428","inReplyTo":"20070808035946.GP9527@spearce.org","subject":"Re: resumable git-clone?","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-08-08T09:14:28Z","receivedAt":"2007-08-08T09:14:28Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 7 Aug 2007, Shawn O. Pearce wrote:\n\n> Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:\n> > I was on a crappy connection and it was frustrated seeing git-clone\n> > reached 80% then failed, then started over again. Can we support\n> > resumable git-clone at some level? I think we could split into several\n> > small packs, keep fetched ones, just get missing packs until we have\n> > all.\n> \n> This is uh, difficult over the native git protocol.  The problem\n> is the native protocol negotiates what the client already has and\n> what it needs by comparing sets of commits.  If the client says\n> \"I have commit X\" then the server assumes it has not only commit\n> X _but also every object reachable from it_.\n\nNow here is a thought: after an interrupted fetch, you could do a \n(possibly expensive) analysis what commits are dangling, but do not \ncontain broken links in their _complete_ history.  Then mark them as \n(temporary) refs.\n\nAnother possibility should be to start with a shallow clone, and to deepen \nit.  However, IIRC there have been complaints that that does not work, and \nit was not my itch, so I did not come around to scratch it.\n\nCiao,\nDscho\n"},{"id":"50188","messageId":"fcaeb9bf0708080420t192596f0kfabbaa5b058d49e5@mail.gmail.com","threadId":"9428","inReplyTo":"20070808035946.GP9527@spearce.org","subject":"Re: resumable git-clone?","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2007-08-08T11:20:59Z","receivedAt":"2007-08-08T11:20:59Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On 8/7/07, Shawn O. Pearce <spearce@spearce.org> wrote:\n> Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:\n> > I was on a crappy connection and it was frustrated seeing git-clone\n> > reached 80% then failed, then started over again. Can we support\n> > resumable git-clone at some level? I think we could split into several\n> > small packs, keep fetched ones, just get missing packs until we have\n> > all.\n>\n> This is uh, difficult over the native git protocol.  The problem\n> is the native protocol negotiates what the client already has and\n> what it needs by comparing sets of commits.  If the client says\n> \"I have commit X\" then the server assumes it has not only commit\n> X _but also every object reachable from it_.\n>\n> Now packfiles are organized to place commits at the front of the\n> packfile.  So a truncated download will give the client a whole\n> host of commits, like maybe all of them, but none of the trees\n> or blobs associated with them as those come behind the commits.\n> Worse, the commits are sorted most recent to least recent.  So if\n> the client claims he has the very first commit he received, that\n> is currently an assertion that he has the entire repository.\n\nI'm thinking about things like bisect and use it to cut the history\ninto parts. Clients only use completed parts. Uncompleted parts are\nthrown away. So if users think they cannot suffer too big packs, they\ntell server to send smaller (and less efficient) packs. Anyway I don't\nhave deep knowledge of Git internals, my opion could be completely\nwrong.\n-- \nDuy\n"},{"id":"50209","messageId":"7vlkcl4zcw.fsf@assigned-by-dhcp.cox.net","threadId":"9428","inReplyTo":"Pine.LNX.4.64.0708081012110.14781@racer.site","subject":"Re: resumable git-clone?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-08-08T19:09:51Z","receivedAt":"2007-08-08T19:09:51Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Now here is a thought: after an interrupted fetch, you could do a \n> (possibly expensive) analysis what commits are dangling, but do not \n> contain broken links in their _complete_ history.  Then mark them as \n> (temporary) refs.\n\nThat's all too elaborate and sounds fairly expensive.\n\nI think another practical solution is to reduce the need to\nresume git-clone, and I foresee a nice side effect.\n\nLet's talk a bit about the side effect first.  Often I see\npeople wondering...\n\n - I am forking off of somebody's big project;\n\n - I want to publish the result of _my_ part of the work;\n\n - I cannot afford the diskspace nor the bandwidth at the\n   hosting service to offer the whole project, but my own work\n   on top of the upstream is small enough;\n\nSo I've been thinking about teaching the server side, when\nresponding to a fetch request, to be able to say something like\n\"Sorry but this repository is for fetching by people who have at\nleast these commits from that other project I am a fork of.\"\nWe make that \"at least these from that other project\" part\nmachine readable, and git-fetch request git-clone makes can\nredirect itself to fill the prerequisites before attempting to\ngo there again.\n\nAnd one way of doing that \"at least these commits\" part could be\na pre-built, well known bundle.  The bulk of the older history\nof a repository insanely large for your bandwidth requirements\ncould be made to a single bundle [*1*], and distributed from\nother places like mirrored HTTP servers, or even from torrent\nnetwork.  The pre-built bundle does not have to be built too\noften.  Probably after every other big release would do.\n\nOnce we have such a support, cloning from a regular full\nrepository ove an unreliable connection could fall back on\ngetting a bundle (a regular repository does not have to refuse\nto serve downloaders that do not have the prerequisites, but\nit could still suggest that as an alternate method to fall back\non.\n\n\n[Footnote]\n\n*1* Sheesh.  While I was writing this I noticed that the current\n    'git bundle' is suitable only for incremental sneakernet but\n    not for this particular use case.\n\n    $ git bundle create 2612.bndl v2.6.12\n\n    does not work, although\n\n    $ git bundle create 2612-2613.bndl v2.6.12..v2.6.13\n\n    does.  We need to fix this.\n"},{"id":"50214","messageId":"Pine.LNX.4.64.0708082134130.21916@wbgn129.biozentrum.uni-wuerzburg.de","threadId":"9428","inReplyTo":"7vlkcl4zcw.fsf@assigned-by-dhcp.cox.net","subject":"Re: resumable git-clone?","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-08-08T19:35:45Z","receivedAt":"2007-08-08T19:35:45Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 8 Aug 2007, Junio C Hamano wrote:\n\n> So I've been thinking about teaching the server side, when responding to \n> a fetch request, to be able to say something like \"Sorry but this \n> repository is for fetching by people who have at least these commits \n> from that other project I am a fork of.\" We make that \"at least these \n> from that other project\" part machine readable, and git-fetch request \n> git-clone makes can redirect itself to fill the prerequisites before \n> attempting to go there again.\n\nSomething like the alternates that http transport can use?\n\n> *1* Sheesh.  While I was writing this I noticed that the current\n>     'git bundle' is suitable only for incremental sneakernet but\n>     not for this particular use case.\n> \n>     $ git bundle create 2612.bndl v2.6.12\n> \n>     does not work, although\n> \n>     $ git bundle create 2612-2613.bndl v2.6.12..v2.6.13\n> \n>     does.  We need to fix this.\n\nYes, I noticed this a long time ago.  Time is lacking...\n\nCiao,\nDscho\n"},{"id":"50271","messageId":"7vps1xzic2.fsf_-_@assigned-by-dhcp.cox.net","threadId":"9428","inReplyTo":"7vlkcl4zcw.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] allow git-bundle to create bottomless bundle","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-08-09T00:01:49Z","receivedAt":"2007-08-09T00:01:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"While \"git bundle\" was a useful way to sneakernet incremental\nchanges, we did not allow:\n\n\t$ git bundle create v2.6.20.bndl v2.6.20\n\nto create a bundle that contains the whole history to a\nwell-known good revision.  Such a bundle can be mirrored\neverywhere, and people can prime their repository with it to\nreduce the load on the repository that serves near the tip of\nthe development.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n Junio C Hamano <gitster@pobox.com> writes:\n\n > *1* Sheesh.  While I was writing this I noticed that the current\n >     'git bundle' is suitable only for incremental sneakernet but\n >     not for this particular use case.\n >\n >     $ git bundle create 2612.bndl v2.6.12\n >\n >     does not work, although\n >\n >     $ git bundle create 2612-2613.bndl v2.6.12..v2.6.13\n >\n >     does.  We need to fix this.\n\n Only very lightly tested, but the fix looks obvious enough.\n\n builtin-bundle.c |   10 +++++++++-\n t/t5510-fetch.sh |    8 ++++++++\n 2 files changed, 17 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-bundle.c b/builtin-bundle.c\nindex 6ae5ab0..cb439ca 100644\n--- a/builtin-bundle.c\n+++ b/builtin-bundle.c\n@@ -208,6 +208,10 @@ static int create_bundle(struct bundle_header *header, const char *path,\n \tstruct rev_info revs;\n \tstruct child_process rls;\n \n+\t/*\n+\t * NEEDSWORK: this should use something like lock-file\n+\t * to create temporary that is cleaned up upon error.\n+\t */\n \tbundle_fd = (!strcmp(path, \"-\") ? 1 :\n \t\t\topen(path, O_CREAT | O_EXCL | O_WRONLY, 0666));\n \tif (bundle_fd < 0)\n@@ -267,8 +271,12 @@ static int create_bundle(struct bundle_header *header, const char *path,\n \t\t * Make sure the refs we wrote out is correct; --max-count and\n \t\t * other limiting options could have prevented all the tips\n \t\t * from getting output.\n+\t\t *\n+\t\t * Non commit objects such as tags and blobs do not have\n+\t\t * this issue as they are not affected by those extra\n+\t\t * constraints.\n \t\t */\n-\t\tif (!(e->item->flags & SHOWN)) {\n+\t\tif (!(e->item->flags & SHOWN) && e->item->type == OBJ_COMMIT) {\n \t\t\twarning(\"ref '%s' is excluded by the rev-list options\",\n \t\t\t\te->name);\n \t\t\tcontinue;\ndiff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh\nindex 426017e..439430f 100755\n--- a/t/t5510-fetch.sh\n+++ b/t/t5510-fetch.sh\n@@ -145,4 +145,12 @@ test_expect_success 'bundle does not prerequisite objects' '\n \ttest 4 = $(git verify-pack -v bundle.pack | wc -l)\n '\n \n+test_expect_success 'bundle should be able to create a full history' '\n+\n+\tcd \"$D\" &&\n+\tgit tag -a -m '1.0' v1.0 master &&\n+\tgit bundle create bundle4 v1.0\n+\n+'\n+\n test_done\n"},{"id":"50273","messageId":"Pine.LNX.4.64.0708090127440.21857@racer.site","threadId":"9428","inReplyTo":"7vps1xzic2.fsf_-_@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] allow git-bundle to create bottomless bundle","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-08-09T00:28:25Z","receivedAt":"2007-08-09T00:28:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 8 Aug 2007, Junio C Hamano wrote:\n\n> +\t\t *\n> +\t\t * Non commit objects such as tags and blobs do not have\n> +\t\t * this issue as they are not affected by those extra\n> +\t\t * constraints.\n>  \t\t */\n> -\t\tif (!(e->item->flags & SHOWN)) {\n> +\t\tif (!(e->item->flags & SHOWN) && e->item->type == OBJ_COMMIT) {\n\nThat is all?  Heh.\n\nThanks for fixing this bug,\nDscho\n"},{"id":"50274","messageId":"46BA8065.6010005@gmail.com","threadId":"9428","inReplyTo":"7vps1xzic2.fsf_-_@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] allow git-bundle to create bottomless bundle","fromName":"Mark Levedahl","fromEmail":"mlevedahl@gmail.com","sentAt":"2007-08-09T02:48:05Z","receivedAt":"2007-08-09T02:48:05Z","isPatch":true,"sender":{"key":"mdl123@verizon.net","avatar":"https://avatars.githubusercontent.com/u/5302462?v=4"},"body":"Junio C Hamano wrote:\n> While \"git bundle\" was a useful way to sneakernet incremental\n> changes, we did not allow:\n>   \nThanks - I've been thinking for months I could fix this bug, never \nfigured it out and didn't want to nag Dscho one more time. I confirm \nthat this allows creation of bundles with arbitrary refs, not just those \nunder refs/heads. Yahoo!\n\nMark\n"},{"id":"50278","messageId":"7v643pz4c9.fsf@assigned-by-dhcp.cox.net","threadId":"9428","inReplyTo":"46BA8065.6010005@gmail.com","subject":"Re: [PATCH] allow git-bundle to create bottomless bundle","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-08-09T05:04:06Z","receivedAt":"2007-08-09T05:04:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Mark Levedahl <mlevedahl@gmail.com> writes:\n\n> Junio C Hamano wrote:\n>> While \"git bundle\" was a useful way to sneakernet incremental\n>> changes, we did not allow:\n>>\n> Thanks - I've been thinking for months I could fix this bug, never\n> figured it out and didn't want to nag Dscho one more time. I confirm\n> that this allows creation of bundles with arbitrary refs, not just\n> those under refs/heads. Yahoo!\n\nActually, there is another bug nearby.\n\nIf you do:\n\n\tgit bundle create v2.6-20-v2.6.22.bndl v2.6.20..v2.6.22\n\nthe bundle records that it requires v2.6.20^0 commit (correct)\nand gives you tag v2.6.22 (incorrect); the bug is that the\nobject it lists in fact is the commit v2.6.22^0, not the tag.\n\nThis is because the revision range operation .. is always about\nset of commits, but the code near where my patch touches does\nnot validate that the sha1 value obtained from dwim_ref()\nagainst the commit object name e->item->sha1 before placing the\nhead information in the commit.\n\nThe attached patch attempts to fix this problem.\n\n---\n\n builtin-bundle.c |   43 ++++++++++++++++++++++++++++++++++++++++++-\n t/t5510-fetch.sh |    8 ++++++++\n 2 files changed, 50 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-bundle.c b/builtin-bundle.c\nindex 6ae5ab0..2d0e106 100644\n--- a/builtin-bundle.c\n+++ b/builtin-bundle.c\n@@ -208,6 +208,10 @@ static int create_bundle(struct bundle_header *header, const char *path,\n \tstruct rev_info revs;\n \tstruct child_process rls;\n \n+\t/*\n+\t * NEEDSWORK: this should use something like lock-file\n+\t * to create temporary that is cleaned up upon error.\n+\t */\n \tbundle_fd = (!strcmp(path, \"-\") ? 1 :\n \t\t\topen(path, O_CREAT | O_EXCL | O_WRONLY, 0666));\n \tif (bundle_fd < 0)\n@@ -267,12 +271,49 @@ static int create_bundle(struct bundle_header *header, const char *path,\n \t\t * Make sure the refs we wrote out is correct; --max-count and\n \t\t * other limiting options could have prevented all the tips\n \t\t * from getting output.\n+\t\t *\n+\t\t * Non commit objects such as tags and blobs do not have\n+\t\t * this issue as they are not affected by those extra\n+\t\t * constraints.\n \t\t */\n-\t\tif (!(e->item->flags & SHOWN)) {\n+\t\tif (!(e->item->flags & SHOWN) && e->item->type == OBJ_COMMIT) {\n \t\t\twarning(\"ref '%s' is excluded by the rev-list options\",\n \t\t\t\te->name);\n+\t\t\tfree(ref);\n+\t\t\tcontinue;\n+\t\t}\n+\t\t/*\n+\t\t * If you run \"git bundle create bndl v1.0..v2.0\", the\n+\t\t * name of the positive ref is \"v2.0\" but that is the\n+\t\t * commit that is referenced by the tag, and not the tag\n+\t\t * itself.\n+\t\t */\n+\t\tif (hashcmp(sha1, e->item->sha1)) {\n+\t\t\t/*\n+\t\t\t * Is this the positive end of a range expressed\n+\t\t\t * in terms of a tag (e.g. v2.0 from the range\n+\t\t\t * \"v1.0..v2.0\")?\n+\t\t\t */\n+\t\t\tstruct commit *one = lookup_commit_reference(sha1);\n+\t\t\tstruct object *obj;\n+\n+\t\t\tif (e->item == &(one->object)) {\n+\t\t\t\t/*\n+\t\t\t\t * Need to include e->name as an\n+\t\t\t\t * independent ref to the pack-objects\n+\t\t\t\t * input, so that the tag is included\n+\t\t\t\t * in the output; otherwise we would\n+\t\t\t\t * end up triggering \"empty bundle\"\n+\t\t\t\t * error.\n+\t\t\t\t */\n+\t\t\t\tobj = parse_object(sha1);\n+\t\t\t\tobj->flags |= SHOWN;\n+\t\t\t\tadd_pending_object(&revs, obj, e->name);\n+\t\t\t}\n+\t\t\tfree(ref);\n \t\t\tcontinue;\n \t\t}\n+\n \t\tref_count++;\n \t\twrite_or_die(bundle_fd, sha1_to_hex(e->item->sha1), 40);\n \t\twrite_or_die(bundle_fd, \" \", 1);\ndiff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh\nindex 426017e..439430f 100755\n--- a/t/t5510-fetch.sh\n+++ b/t/t5510-fetch.sh\n@@ -145,4 +145,12 @@ test_expect_success 'bundle does not prerequisite objects' '\n \ttest 4 = $(git verify-pack -v bundle.pack | wc -l)\n '\n \n+test_expect_success 'bundle should be able to create a full history' '\n+\n+\tcd \"$D\" &&\n+\tgit tag -a -m '1.0' v1.0 master &&\n+\tgit bundle create bundle4 v1.0\n+\n+'\n+\n test_done\n"},{"id":"50317","messageId":"30e4a070708090532y4d5f8528q8458fb5d28c980eb@mail.gmail.com","threadId":"9428","inReplyTo":"7v643pz4c9.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] allow git-bundle to create bottomless bundle","fromName":"Mark Levedahl","fromEmail":"mlevedahl@gmail.com","sentAt":"2007-08-09T12:32:50Z","receivedAt":"2007-08-09T12:32:50Z","isPatch":true,"sender":{"key":"mdl123@verizon.net","avatar":"https://avatars.githubusercontent.com/u/5302462?v=4"},"body":"On 8/9/07, Junio C Hamano <gitster@pobox.com> wrote:\n> Mark Levedahl <mlevedahl@gmail.com> writes:\n>\n> > Junio C Hamano wrote:\n>\n> Actually, there is another bug nearby.\n>\nCurious... I did a long time ago get git-bundle.sh to write out the\nformat Dscho finally implemented working in Linux and Cygwin. With\nyour latest patch, both produce identical bundles for a number of\ncases, but the timing is very curious:\n\n*builtin*\ngit>time git-bundle create foo refs/tags/v1.0.3\nGenerating pack...\nDone counting 12288 objects.\nDeltifying 12288 objects...\n 100% (12288/12288) done\nWriting 12288 objects...\n 100% (12288/12288) done\nTotal 12288 (delta 8435), reused 11542 (delta 7961)\n\nreal    0m41.953s\nuser    0m5.060s\nsys     0m39.685s\n\n*shell script*\ngit>time git-bundle2 create foo2 refs/tags/v1.0.3\nGenerating pack...\nDone counting 12288 objects.\nDeltifying 12288 objects...\n 100% (12288/12288) done\nTotal 12288 (delta 8435), reused 11542 (delta 7961)\nCreated foo2\n\nreal    0m2.453s\nuser    0m1.842s\nsys     0m1.190s\ngit>diff foo foo2\ngit>\n\nSince when is shell 20 times faster than a builtin? Ok, those results\nare on Cygwin. On Linux, I get  1.21 sec for the builtin vs 0.933 for\nthe shell script. Not as dramatic, but the script is still faster. So,\nI think this qualifies as a bug. I'm attaching the script (for info\nonly, I'm not suggesting to replace the builtin), as I can't usefully\nput it inline from gmail.\n\nThe timing difference seem to be in the rev walking (by eyeball,\npackfile generation time is the same), so something the shell script\nis doing to get the rev list is obviously more efficient than how the\nbuiltin works for this case.\n\nMark\n"}]}