{"thread":{"id":"6845","subject":"Re: Re: [PATCH] Add git-unbundle - unpack objects and references for disconnected transfer","startedAt":"2007-02-16T12:53:13Z","lastAt":"2007-02-18T22:47:18Z","messageCount":12,"participants":["Mark Levedahl","Junio C Hamano","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"34792","messageId":"28763990.2658921171630394111.JavaMail.root@vms064.mailsrvcs.net","threadId":"6845","inReplyTo":null,"subject":"Re: Re: [PATCH] Add git-unbundle - unpack objects and references for disconnected transfer","fromName":"Mark Levedahl","fromEmail":"mdl123@verizon.net","sentAt":"2007-02-16T12:53:13Z","receivedAt":"2007-02-16T12:53:13Z","isPatch":true,"sender":{"key":"mdl123@verizon.net","avatar":"https://avatars.githubusercontent.com/u/5302462?v=4"},"body":">>\n>Also as Shawn pointed out, the script too heavily depends on GNU\n>tar.  Can we do something about it?\n\nLet me ponder, I'm sure I can do something. As I noted in another response, Cygwin won't let me reliably pipe the pack file through bash, so I'm forced to use some archiver.\n\nMark\n"},{"id":"34826","messageId":"7vhctl50zc.fsf@assigned-by-dhcp.cox.net","threadId":"6845","inReplyTo":"28763990.2658921171630394111.JavaMail.root@vms064.mailsrvcs.net","subject":"Re: [PATCH] Add git-unbundle - unpack objects and references for disconnected transfer","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-02-16T19:57:59Z","receivedAt":"2007-02-16T19:57:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Mark Levedahl <mdl123@verizon.net> writes:\n\n>>>\n>>Also as Shawn pointed out, the script too heavily depends on GNU\n>>tar.  Can we do something about it?\n>\n> Let me ponder, I'm sure I can do something. As I noted in\n> another response, Cygwin won't let me reliably pipe the pack\n> file through bash, so I'm forced to use some archiver.\n\nMark, how urgent do you want to have \"bundle\" in my tree?  As I\nunderstand it, this came out of your working zip based\nimplementation your group already use, so I am suspecting that\nyou do not have urgent need to have a different one in git.git\nin a half-baked shape.\n\nThe reason I say this is because I very much in favor of the\ngeneral idea of an archive file that can be used to sneakernet\nrepository updates, but I find the current bundle-unbundle\ninterface a bit awkward to integrate into the rest of the\nsystem.\n\nWouldn't it be nice if you can treat a bundle as just a\ndifferent kind of git URL that you can \"git fetch\"?\n\n\t$ git fetch file.bdl 'refs/heads/*:refs/heads/*'\n\nAs the way I read the current implementation of git-unbundle is\nthat it is designed to only overwrite (with fast-forward check\nnot to lose changes from the target) all the refs in place.  It\ndoes not, for example, allow extracting only one branch, nor\nstoring the branch in a tracking branch by renaming.  I think it\nwould be nicer to change the external interface from the bundle\nsubsystem to the calling scripts, so that it behaves closer to\ngit-fetch-pack.\n\nI haven't thought things through, but I think something like this\nwould be sufficient:\n\n\t# create a bundle.\n\t$ git bundle --create v1.5.0..maint master next >file.bdl\n\n\t# you can view the tips of refs it contains.  This is\n        # similar to \"ls-remote\" output.\n\t$ git bundle --list-heads file.bdl\n        efa13f7b7ea1605deab3a6478fa0d0706c828170 refs/heads/maint\n        af99711cd84c30a16450f73dbc21ba9f9f9803e6 refs/heads/master\n        664e83a22b604fc5af1a84ddd48549b005cf4bc9 refs/heads/next\n\n        # optionally allow checking if the pre-requisites of the\n        # bundle are available.\n\t$ git bundle --verify file.bdl\n\terror: file.bdl depends on the following commits you lack\n\tin the repository:\n        82bf92f9846326a743102e27fa9827422dddfada v1.5.0-564-g82bf92f\n\t4d462883de41190afd23672c8236361c61a9e6bd v1.5.0-34-g4d46288\n\n\t# extract the packfile part, run index-pack and report\n        # the result the same way as git-fetch-pack\n        $ git bundle --unbundle file.bdl\n\tpack\t340e3faa26616ca8c38b369a6d323ecf7a34f4fb\n        efa13f7b7ea1605deab3a6478fa0d0706c828170 refs/heads/maint\n        af99711cd84c30a16450f73dbc21ba9f9f9803e6 refs/heads/master\n        664e83a22b604fc5af1a84ddd48549b005cf4bc9 refs/heads/next\n\nThen git-ls-remote can be taught about a bundle file and use the\n'git bundle --list-heads'.  Also, with something like this in\nyour config:\n\n\t[remote \"bundle\"]\n        \turl = /home/me/tmp/file.bdl\n                fetch = refs/heads/*:refs/remotes/origin/*\n\nYou can first sneakernet the bundle file to ~/tmp/file.bdl and\nthen these commands:\n\n\t$ git ls-remote bundle\n        $ git fetch bundle\n\t$ git pull bundle\n\nwould treat it as if it is talking with a remote side over the\nnetwork.\n\nHmm?\n"},{"id":"34834","messageId":"45D628E9.20605@verizon.net","threadId":"6845","inReplyTo":"28763990.2658921171630394111.JavaMail.root@vms064.mailsrvcs.net","subject":"Re: [PATCH] Add git-unbundle - unpack objects and references for disconnected transfer","fromName":"Mark Levedahl","fromEmail":"mdl123@verizon.net","sentAt":"2007-02-16T21:58:01Z","receivedAt":"2007-02-16T21:58:01Z","isPatch":true,"sender":{"key":"mdl123@verizon.net","avatar":"https://avatars.githubusercontent.com/u/5302462?v=4"},"body":"Mark Levedahl wrote:\n>> Also as Shawn pointed out, the script too heavily depends on GNU\n>> tar.  Can we do something about it\n>>     \nThis one is easy, make tmp a directory, then build the tar file in that \ndirectory so the archive members don't include the tmp name, then just \nmove the tar file to where it is needed...\n\ntmp=\"$GIT_DIR/bundle_tmp$$\"\nreferences=\"$tmp/references\"\npack=\"$tmp/pack\"\ntrap 'rm -rf \"$tmp\"' 0 1 2 3 15\n\nmkdir \"$tmp\" &&\necho \"v1 git-bundle\" > \"$version\" &&\n------\n\n# create the tar file, clean up\ncd \"$tmp\" &&\ntar cf bundle prerequisites references version pack &&\ncd - &&\nmv \"$tmp/bundle\" \"$bfile\" &&\nrm -rf \"$tmp\"\n\nI believe that as this works, tar needs only to understand c, f, and -O. \nIt is easy enough to search for gtar and use that, or allow user to \ndefine TAR. So, I think this is a non-issue.\n\nMark\n"},{"id":"34837","messageId":"Pine.LNX.4.63.0702162348380.22628@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"6845","inReplyTo":"45D628E9.20605@verizon.net","subject":"Re: [PATCH] Add git-unbundle - unpack objects and references for disconnected transfer","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-02-16T22:51:00Z","receivedAt":"2007-02-16T22:51:00Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 16 Feb 2007, Mark Levedahl wrote:\n\n> Mark Levedahl wrote:\n> > > Also as Shawn pointed out, the script too heavily depends on GNU \n> > > tar.  Can we do something about it\n> > >     \n> This one is easy, make tmp a directory, then build the tar file in that\n> directory so the archive members don't include the tmp name, then just move\n> the tar file to where it is needed...\n\nWhy not just get rid of this unneeded dependency? It is _unneeded_. Maybe \nyou never suffered dependency hell (this is the only way I can explain \nyour resistance). It is _good_ to get rid of dependencies.\n\nAh whatever, if you don't just get rid of that tar dependency, I'll just \ndo it.\n\nCiao,\nDscho\n"},{"id":"34840","messageId":"45D63C7A.4050300@verizon.net","threadId":"6845","inReplyTo":"7vhctl50zc.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Add git-unbundle - unpack objects and references for disconnected transfer","fromName":"Mark Levedahl","fromEmail":"mdl123@verizon.net","sentAt":"2007-02-16T23:21:30Z","receivedAt":"2007-02-16T23:21:30Z","isPatch":true,"sender":{"key":"mdl123@verizon.net","avatar":"https://avatars.githubusercontent.com/u/5302462?v=4"},"body":"Junio C Hamano wrote:\n> Mark, how urgent do you want to have \"bundle\" in my tree?  As I\n> understand it, this came out of your working zip based\n> implementation your group already use, so I am suspecting that\n> you do not have urgent need to have a different one in git.git\n> in a half-baked shape.\n>   \nI can get my work done today with what I have. However, I really believe \nbundle is a good addition to git, and I don't want to maintain an \nout-of-tree patch to git to add this capability.\n> Wouldn't it be nice if you can treat a bundle as just a\n> different kind of git URL that you can \"git fetch\"?\n>\n> \t$ git fetch file.bdl 'refs/heads/*:refs/heads/*'\n>   \nyes\n>\n> Then git-ls-remote can be taught about a bundle file and use the\n> 'git bundle --list-heads'.  Also, with something like this in\n> your config:\n>\n> \t[remote \"bundle\"]\n>         \turl = /home/me/tmp/file.bdl\n>                 fetch = refs/heads/*:refs/remotes/origin/*\n>\n> You can first sneakernet the bundle file to ~/tmp/file.bdl and\n> then these commands:\n>\n> \t$ git ls-remote bundle\n>         $ git fetch bundle\n> \t$ git pull bundle\n>\n> would treat it as if it is talking with a remote side over the\n> network.\n>\n> Hmm?\n>\n>   \nAs long as I can still do a \"git fetch file.bdl\" and without having to \ndo the config stuff. I'm happy. Integrating this bundle with basic git \napproaches to things is obviously good. The frontend you outlined seems \na trivial rearrangement of what I already have, but I'll let this \ndiscussion progress a bit further before I start doing that.\n\nMark\n"},{"id":"34851","messageId":"7vfy95w9sc.fsf@assigned-by-dhcp.cox.net","threadId":"6845","inReplyTo":"45D63C7A.4050300@verizon.net","subject":"Re: [PATCH] Add git-unbundle - unpack objects and references for disconnected transfer","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-02-17T06:57:55Z","receivedAt":"2007-02-17T06:57:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Mark Levedahl <mdl123@verizon.net> writes:\n\n>> Wouldn't it be nice if you can treat a bundle as just a\n>> different kind of git URL that you can \"git fetch\"?\n>>\n>> \t$ git fetch file.bdl 'refs/heads/*:refs/heads/*'\n>>\n> yes\n>...\n>\n> As long as I can still do a \"git fetch file.bdl\" and without having to\n> do the config stuff. I'm happy.\n\nI do not think your patch (original or respun) checks if it is\noverwriting the current branch.  Even if it is a fast forward,\nit should check this condition and prevent the end user from\ngetting confused.  The above sample command line you quoted from\nmy message can potentially have the same problem, but \"git\nfetch\" checks and refuses.\n\nEven when the \"remote\" is not a bundle file, it sometimes is\nuseful to store the refs as they are without mapping them to\nremotes hierarchy as the separate-remote layout does.  An\nobvious use case is to mirror another repository as is.  So it\nmay make sense to teach --mirror to \"git-fetch\" so that you can\nsay:\n\n\t$ git fetch --mirror file.bdl\n\nwhich would be a short-hand to say:\n\n\t$ git fetch file.bdl 'refs/*:refs/*'\n\nA final note.  A real 'mirror' mode should also remove stale\nrefs that do not exist on the remote side anymore, which is a\ndifferent use case as your bundle, which presumably is primarily\nmeant to carry not all but only selected set of refs, and most\nlikely not the 'master' branch head (and I am guessing that that\nis why you forgot to make sure you are not overwriting the\ncurrent branch in the unbundle script).  A real 'mirror' mode\nwould use a separate option to remove a ref that does not exist\non the remote end anymore, like:\n\n\t$ git fetch --mirror-all git://git.kernel.org/pub/scm/git/git.git/\n"},{"id":"34870","messageId":"45D713C0.1010401@verizon.net","threadId":"6845","inReplyTo":"7vfy95w9sc.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Add git-unbundle - unpack objects and references for disconnected transfer","fromName":"Mark Levedahl","fromEmail":"mdl123@verizon.net","sentAt":"2007-02-17T14:40:00Z","receivedAt":"2007-02-17T14:40:00Z","isPatch":true,"sender":{"key":"mdl123@verizon.net","avatar":"https://avatars.githubusercontent.com/u/5302462?v=4"},"body":"Junio C Hamano wrote:\n> I do not think your patch (original or respun) checks if it is\n> overwriting the current branch.  Even if it is a fast forward,\n> it should check this condition and prevent the end user from\n> getting confused.  The above sample command line you quoted from\n> my message can potentially have the same problem, but \"git\n> fetch\" checks and refuses.\n>   \nTrue. I've been using this to mirror remote/* and tags. Making this just \nan alternate transport behind fetch and pull is clearly the cleanest way \nto deal with non-remote branches.\n> A final note.  A real 'mirror' mode should also remove stale\n> refs that do not exist on the remote side anymore, which is a\n> different use case as your bundle, which presumably is primarily\n> meant to carry not all but only selected set of refs, and most\n> likely not the 'master' branch head (and I am guessing that that\n> is why you forgot to make sure you are not overwriting the\n> current branch in the unbundle script).  A real 'mirror' mode\n> would use a separate option to remove a ref that does not exist\n> on the remote end anymore, like:\n>\n> \t$ git fetch --mirror-all git://git.kernel.org/pub/scm/git/git.git\n>   \nPerhaps \"git fetch --mirror --delete\" would be more suggestive of the \ndifference to \"git fetch --mirror\"?\n\nMark\n"},{"id":"34872","messageId":"45D7161C.3050604@verizon.net","threadId":"6845","inReplyTo":"7vhctl50zc.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Add git-unbundle - unpack objects and references for disconnected transfer","fromName":"Mark Levedahl","fromEmail":"mdl123@verizon.net","sentAt":"2007-02-17T14:50:04Z","receivedAt":"2007-02-17T14:50:04Z","isPatch":true,"sender":{"key":"mdl123@verizon.net","avatar":"https://avatars.githubusercontent.com/u/5302462?v=4"},"body":"Junio C Hamano wrote:\n> I haven't thought things through, but I think something like this\n> would be sufficient:\n>\n> \t# create a bundle.\n> \t$ git bundle --create v1.5.0..maint master next >file.bdl\n>\n>   \nIn this vein, would it make sense to let git-push be the front end to \ncreate the bundle? I'm not sure git-push really contributes anything, \nbut the interface would then be consistent across all transports. Just a \nthought.\n\nMark\n"},{"id":"34879","messageId":"7v8xewvfez.fsf@assigned-by-dhcp.cox.net","threadId":"6845","inReplyTo":"45D713C0.1010401@verizon.net","subject":"Re: [PATCH] Add git-unbundle - unpack objects and references for disconnected transfer","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-02-17T17:53:56Z","receivedAt":"2007-02-17T17:53:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Mark Levedahl <mdl123@verizon.net> writes:\n\n> Junio C Hamano wrote:\n> ...\n>> A final note.  A real 'mirror' mode should also remove stale\n>> refs that do not exist on the remote side anymore, which is a\n>> different use case as your bundle,...\n>> ...  A real 'mirror' mode\n>> would use a separate option to remove a ref that does not exist\n>> on the remote end anymore, like:\n>>\n>> \t$ git fetch --mirror-all git://git.kernel.org/pub/scm/git/git.git\n>>\n> Perhaps \"git fetch --mirror --delete\" would be more suggestive of the\n> difference to \"git fetch --mirror\"?\n\nI think that is a good suggestion, as people familiar with rsync\nalready know what --delete means in such a context.\n"},{"id":"34887","messageId":"7vejootynq.fsf@assigned-by-dhcp.cox.net","threadId":"6845","inReplyTo":"45D7161C.3050604@verizon.net","subject":"Re: [PATCH] Add git-unbundle - unpack objects and references for disconnected transfer","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-02-17T18:41:13Z","receivedAt":"2007-02-17T18:41:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Mark Levedahl <mdl123@verizon.net> writes:\n\n> Junio C Hamano wrote:\n>> I haven't thought things through, but I think something like this\n>> would be sufficient:\n>>\n>> \t# create a bundle.\n>> \t$ git bundle --create v1.5.0..maint master next >file.bdl\n>>\n>>\n> In this vein, would it make sense to let git-push be the front end to\n> create the bundle? I'm not sure git-push really contributes anything,\n> but the interface would then be consistent across all transports. Just\n> a thought.\n\nI am not sure.  For the \"fetch\" case, the UI will be exactly the\nsame (URL and then refspecs), but we never say bottom commits\nfor git-push.  When you are creating a bundle, unless you are\nincluding everything, you want a way to say which bottom commits\nto be excluded from the resulting pack, so they are different.\nI had an impression bundle creation is similar to archive.\n"},{"id":"34960","messageId":"11718196342317-git-send-email-mdl123@verizon.net","threadId":"6845","inReplyTo":"7vejootynq.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] Add git-bundle: move objects and references by archive.","fromName":"Mark Levedahl","fromEmail":"mdl123@verizon.net","sentAt":"2007-02-18T17:27:14Z","receivedAt":"2007-02-18T17:27:14Z","isPatch":true,"sender":{"key":"mdl123@verizon.net","avatar":"https://avatars.githubusercontent.com/u/5302462?v=4"},"body":"Some workflows require use of repositories on machines that cannot be\nconnected, preventing use of git-fetch / git-push to transport objects\nand references between the repositories.\n\ngit-bundle provides an alternate transport mechanism, effectively allowing\ngit-fetch and git-pull to operate using sneakernet transport. git-bundle\n--create allows the user to create a bundle containing one or more branches\nor tags, but with specified basis assumed to exist on the target repository.\nAt the receiving end, git-bundle acts like git-fetch-pack, allowing the\nuser to invoke git-fetch or git-pull using the bundle file as the URL.\ngit-fetch and git-ls-remote determine they have a bundle URL by checking\nthat the URL points to a file, but are otherwise unchanged in operation\nwith bundles.\n\nSigned-off-by: Mark Levedahl <mdl123@verizon.net>\n---\n Documentation/cmd-list.perl  |    1 +\n Documentation/git-bundle.txt |  146 +++++++++++++++++++++++++++++++++++\n Makefile                     |    3 +-\n git-bundle.sh                |  174 ++++++++++++++++++++++++++++++++++++++++++\n git-fetch.sh                 |   11 ++-\n git-ls-remote.sh             |    7 ++-\n 6 files changed, 338 insertions(+), 4 deletions(-)\n mode change 100755 => 100644 Documentation/cmd-list.perl\n create mode 100644 Documentation/git-bundle.txt\n create mode 100755 git-bundle.sh\n\ndiff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl\nold mode 100755\nnew mode 100644\nindex a2d6268..f61c77a\n--- a/Documentation/cmd-list.perl\n+++ b/Documentation/cmd-list.perl\n@@ -70,6 +70,7 @@ git-archive                             mainporcelain\n git-bisect                              mainporcelain\n git-blame                               ancillaryinterrogators\n git-branch                              mainporcelain\n+git-bundle                              mainporcelain\n git-cat-file                            plumbinginterrogators\n git-checkout-index                      plumbingmanipulators\n git-checkout                            mainporcelain\ndiff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt\nnew file mode 100644\nindex 0000000..27db785\n--- /dev/null\n+++ b/Documentation/git-bundle.txt\n@@ -0,0 +1,146 @@\n+git-bundle(1)\n+=============\n+\n+NAME\n+----\n+git-bundle - Move objects and refs by archive\n+\n+\n+SYNOPSIS\n+--------\n+'git-bundle' --create file <git-rev-list args> <--tar tarspec>\n+'git-bundle' --verify file  <--tar tarspec>\n+'git-bundle' --list-heads file <reflist> <--tar tarspec>\n+'git-bundle' --unbundle file <reflist> <--tar tarspec>\n+\n+DESCRIPTION\n+-----------\n+\n+Some workflows require that one or more branches of development on one\n+machine be replicated on another machine, but the two machines cannot\n+be directly connected so the interactive git protocols (git, ssh,\n+rsync, http) cannot be used.  This command provides suport for\n+git-fetch and git-pull to operate by packaging objects and references\n+in an archive at the originating machine, then importing those into\n+another repository using gitlink:git-fetch[1] and gitlink:git-pull[1]\n+after moving the archive by some means (i.e., by sneakernet).  As no\n+direct connection between repositories exists, the user must specify a\n+basis for the bundle that is held by the destination repository: the\n+bundle assumes that all objects in the basis are already in the\n+destination repository.\n+\n+OPTIONS\n+-------\n+\n+--create file::\n+       Used to create a bundle named 'file'.  This requires the\n+       git-rev-list arguments to define the bundle contents.\n+\n+--verify file::\n+       Used to check that a bundle file is valid and will apply\n+       cleanly to the current repository.  This includes checks on the\n+       bundle format itself as well as checking that the prerequisite\n+       commits exist and are fully linked in the current repository.\n+       git-bundle prints a list of missing commits, if any, and exits\n+       with non-zero status.\n+\n+--list-heads file::\n+       Lists the references defined in the bundle.  If followed by a\n+       list of references, only references matching those given are\n+       printed out.\n+\n+--unbundle file::\n+       Passes the objects in the bundle to gitlink:git-index-pack[1]\n+       for storage in the repository, then prints the names of all\n+       defined references. If a reflist is given, only references\n+       matching those in the given list are printed. This command is\n+       really plumbing, intended to be called only by\n+       gitlink:git-fetch[1].\n+\n+git-rev-list args::\n+       A list of arguments, accepatble to git-rev-parse and\n+       git-rev-list, that specify the specific objects and references\n+       to transport.  For example, \"master~10..master\" causes the\n+       current master reference to be packaged along with all objects\n+       added since its 10th ancestor commit.  There is no explicit\n+       limit to the number of references and objects that may be\n+       packaged.\n+\n+\n+reflist::\n+       A list of references used to limit the references reported as\n+       available. This is principally of use to git-fetch, which\n+       expects to recieve only those references asked for and not\n+       necessarily everything in the pack (in this case, git-bundle is\n+       acting like gitlink:git-fetch-pack[1]).\n+\n+tar tarspec::\n+\n+       git-bundle uses tar, and requires a tar supporting c, f, and\n+       -O. By default, git-bundle looks for gtar on the path, then for\n+       tar if gtar is not found. This can be overridden by explicitly\n+       defining tarspec, or by defining TAR in the environment.\n+\n+SPECIFYING REFERENCES\n+---------------------\n+\n+git-bundle will only package references that are shown by\n+git-show-ref: this includes heads, tags, and remote heads.  References\n+such as master~1 cannot be packaged, but are perfectly suitable for\n+defining the basis.  More than one reference may be packaged, and more\n+than one basis can be specified.  The objects packaged are those not\n+contained in the union of the given bases.  Each basis can be\n+specified explicitly (e.g., ^master~10), or implicitly (e.g.,\n+master~10..master, master --since=10.days.ago).\n+\n+It is very important that the basis used be held by the destination.\n+It is ok to err on the side of conservatism, causing the bundle file\n+to contain objects already in the destination as these are ignored\n+when unpacking at the destination.\n+\n+EXAMPLE\n+-------\n+\n+Assume two repositories exist as R1 on machine A, and R2 on machine B.\n+For whatever reason, direct connection between A and B is not allowed,\n+but we can move data from A to B via some mechanism (CD, email, etc).\n+We want to update R2 with developments made on branch master in R1.\n+We set a tag in R1 (lastR2bundle) after the previous such transport,\n+and move it afterwards to help build the bundle.\n+\n+in R1 on A:\n+$ git-bundle --create mybundle master ^lastR2bundle\n+$ git tag -f lastR2bundle master\n+\n+(move mybundle from A to B by some mechanism)\n+\n+in R2 on B:\n+$ git-bundle --verify mybundle\n+$ git-fetch mybundle  refspec\n+\n+where refspec is refInBundle:localRef\n+\n+\n+Also, with something like this in your config:\n+\n+[remote \"bundle\"]\n+    url = /home/me/tmp/file.bdl\n+    fetch = refs/heads/*:refs/remotes/origin/*\n+\n+You can first sneakernet the bundle file to ~/tmp/file.bdl and\n+then these commands:\n+\n+$ git ls-remote bundle\n+$ git fetch bundle\n+$ git pull bundle\n+\n+would treat it as if it is talking with a remote side over the\n+network.\n+\n+Author\n+------\n+Written by Mark Levedahl <mdl123@verizon.net>\n+\n+GIT\n+---\n+Part of the gitlink:git[7] suite\ndiff --git a/Makefile b/Makefile\nindex ebecbbd..c6d540e 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -177,7 +177,8 @@ SCRIPT_SH = \\\n \tgit-applymbox.sh git-applypatch.sh git-am.sh \\\n \tgit-merge.sh git-merge-stupid.sh git-merge-octopus.sh \\\n \tgit-merge-resolve.sh git-merge-ours.sh \\\n-\tgit-lost-found.sh git-quiltimport.sh\n+\tgit-lost-found.sh git-quiltimport.sh \\\n+\tgit-bundle.sh\n \n SCRIPT_PERL = \\\n \tgit-add--interactive.perl \\\ndiff --git a/git-bundle.sh b/git-bundle.sh\nnew file mode 100755\nindex 0000000..2bb9232\n--- /dev/null\n+++ b/git-bundle.sh\n@@ -0,0 +1,174 @@\n+#!/bin/sh\n+# Basic handler for bundle files to connect repositories via sneakernet.\n+# Invocation must include action.\n+# This function can create a bundle or provide information on an existing bundle\n+# supporting git-fetch, git-pull, and git-ls-remote\n+\n+USAGE='[--create bundle <git-rev-list args>] |\n+[--verify|--list-heads|--unbundle bundle] <--tar tarspec>\n+     where bundle is the name of the bundle file.'\n+\n+verify() {\n+    # Check bundle version\n+    test -r \"$bfile\" || die \"cannot find $bfile\"\n+    test \"$($TAR -xf \"\"$bfile\"\" -O version)\" = \"v1 git-bundle\" ||\n+        die \"$bfile doesn't look like a v1 bundle file.\"\n+\n+\t# do fast check, then if any prereqs are missing then go line by line\n+\t# to be verbose about the errors\n+    prereqs=$($TAR xf \"$bfile\" -O prerequisites)\n+\ttest -z \"$prereqs\" && return 0\n+\tbad=$(echo \"$prereqs\" | cut -b-40 | git-rev-list --stdin --not --all 2>&1)\n+    if test -n \"$bad\" ; then\n+\t\ttest \"$1\" = \"--silent\" && return 1\n+        echo \"error: $bfile requires the following commits you lack:\"\n+\t\techo \"$prereqs\" |\n+\t\twhile read sha1 comment ; do\n+            missing=$(git-rev-list $sha1 --not --all 2>&1)\n+            test -n \"$missing\" && echo \"$sha1 $comment\"\n+\t\tdone\n+        exit 1\n+    fi\n+    return 0\n+}\n+\n+# list all or just a subset\n+list_heads() {\n+\tif test -z \"$*\" ; then\n+\t\t$TAR -xf \"$bfile\" -O references 2>/dev/null || exit 1\n+\telse\n+\t\t($TAR -xf \"$bfile\" -O references 2>/dev/null || exit 1) |\n+\t\twhile read sha1 ref ; do\n+\t\t\tfor arg in $* ; do\n+\t\t\t\tif test \"${ref%$arg}\" != \"$ref\" ; then\n+\t\t\t\t\techo \"$sha1 $ref\"\n+\t\t\t\t\tbreak\n+\t\t\t\tfi\n+\t\t\tdone\n+\t\tdone\n+\tfi\n+}\n+\n+SUBDIRECTORY_OK=1\n+. git-sh-setup\n+\n+args=\n+action=\n+while test -n \"$1\" ; do\n+    case $1 in\n+        --create|--list-heads|--unbundle|--verify)\n+            action=${1#--}\n+            shift\n+            bfile=$1\n+            test -z \"$bfile\" && die \"$action requires filename\";;\n+        --tar=*)\n+            TAR=${1##--tar=};;\n+        --tar)\n+\t\t\tshift\n+            TAR=$1;;\n+        *)\n+            args=\"$args $1\";;\n+    esac\n+    shift\n+done\n+test -z \"$action\" && die \"No action given, what should I do?\"\n+\n+# what tar to use, prefer gtar, then tar.\n+if test -z \"$TAR\" ; then\n+    GTAR=$(which gtar 2>/dev/null)\n+    TAR=${GTAR:-tar}\n+fi\n+\n+case $action in\n+create)\n+    unknown=$(git-rev-parse --no-revs $args)\n+    test -z \"$unknown\" || die \"unknown option: $unknown\"\n+    gitrevargs=$(git-rev-parse --symbolic --revs-only $args) || exit 1\n+\n+    # find the refs to carry along and get sha1s for each.\n+    refs=\n+    fullrevargs=\n+    for arg in $gitrevargs ; do\n+        #ignore options and basis refs, get full ref name for things\n+\t\t# we will transport rejecting anything ambiguous (e.g., user\n+\t\t# gives master, have heads/master and remotes/origin/master, we\n+\t\t# keep the former).\n+        case \"$arg\" in\n+            -* | ^*) fullrevargs=\"$fullrevargs $arg\";;\n+            *)  ref=$(git-show-ref \"$arg\")\n+                test \"$(echo $ref | wc -w)\" = \"2\" || die \"Ambigous reference: $arg\n+$ref\"\n+                fullrevargs=\"$fullrevargs ${ref#* }\"\n+                refs=\"$refs $ref\";;\n+        esac\n+    done\n+    test -z \"$refs\" && die \"No references specified, I don't know what to bundle.\"\n+\n+    # git-rev-list cannot determine edge objects if a date restriction is\n+    # given...  we do things a slow way if max-age or min-age are given\n+    case \"$fullrevargs\" in\n+        *--max-age* | *--min-age*)\n+            # get a list of all commits that will be packed along with\n+            # parents of each.  A fixed git-rev-list --boundary should\n+            # replace all of this.\n+            echo \"Finding prerequisites and commits to bundle...\"\n+            commits=$(git-rev-list $fullrevargs)\n+\n+            # get immediate parents of each commit to include\n+            parents=\n+            for c in $commits ; do\n+                parents=\"$parents $(git-rev-list --parents --max-count=1 $c | cut -b42-)\"\n+            done\n+            parents=$(printf \"%s\\n\" $parents | sort | uniq)\n+\n+            # factor out what will be in this bundle, the remainder are the\n+            # bundle's prerequisites.  double up commits in this as we only\n+            # want things that are only in parents to appear once\n+            prereqs=$(printf \"%s\\n\" $parents $commits $commits | \\\n+                sort | uniq -c | sed -ne 's/^ *1 //p');;\n+        *)\n+            prereqs=$(git-rev-list --objects-edge $fullrevargs | sed -ne 's/^-//p');;\n+    esac\n+\n+\t# replace prereqs with annotated version of same\n+\n+    # create refs and pack\n+    tmp=\"$GIT_DIR/bundle_tmp$$\"\n+    prerequisites=\"$tmp/prerequisites\"\n+    references=\"$tmp/references\"\n+    version=\"$tmp/version\"\n+    pack=\"$tmp/pack\"\n+    trap 'rm -rf \"$tmp\"' 0 1 2 3 15\n+\n+    mkdir \"$tmp\" &&\n+    echo \"v1 git-bundle\" > \"$version\" &&\n+\ttouch \"$prerequisites\" &&\n+\t(for p in $prereqs ; do\n+\t\tgit-rev-list --pretty=one --max-count=1 $p\n+\tdone) > \"$prerequisites\" &&\n+    git-show-ref $refs > \"$references\" &&\n+    git-rev-list --objects $fullrevargs | cut -b-40 |\n+        git pack-objects --all-progress --stdout > \"$pack\" &&\n+\n+    # create the tar file, clean up\n+    cd \"$tmp\" &&\n+    tar cf bundle prerequisites references version pack &&\n+    cd - &&\n+    mv \"$tmp/bundle\" \"$bfile\" &&\n+    rm -rf \"$tmp\"\n+\n+    # done\n+    echo \"Created $bfile\";;\n+\n+verify)\n+    verify && echo \"$bfile is ok\";;\n+\n+list-heads)\n+    list_heads $args;;\n+\n+unbundle)\n+    verify --silent || exit 1\n+    $TAR -xf \"$bfile\" -O pack | git-index-pack --stdin ||\n+        die \"error: $bfile has a corrupted pack file\"\n+    list_heads $args;;\n+esac\ndiff --git a/git-fetch.sh b/git-fetch.sh\nindex ca984e7..4cb4009 100755\n--- a/git-fetch.sh\n+++ b/git-fetch.sh\n@@ -377,8 +377,15 @@ fetch_main () {\n     ( : subshell because we muck with IFS\n       IFS=\" \t$LF\"\n       (\n-\t  git-fetch-pack --thin $exec $keep $shallow_depth \"$remote\" $rref ||\n-\t  echo failed \"$remote\"\n+\tif test -r \"$remote\" ; then\n+\t    test -n \"$shallow_depth\" &&\n+\t\tdie \"shallow clone with bundle is not supported\"\n+\t    git-bundle --unbundle \"$remote\" $rref ||\n+\t    echo failed \"$remote\"\n+\telse\n+\t    git-fetch-pack --thin $exec $keep $shallow_depth \"$remote\" $rref ||\n+\t    echo failed \"$remote\"\n+\tfi\n       ) |\n       (\n \ttrap '\ndiff --git a/git-ls-remote.sh b/git-ls-remote.sh\nindex 8ea5c5e..73b745d 100755\n--- a/git-ls-remote.sh\n+++ b/git-ls-remote.sh\n@@ -89,8 +89,13 @@ rsync://* )\n \t;;\n \n * )\n-\tgit-peek-remote $exec \"$peek_repo\" ||\n+\tif test -r \"$peek_repo\" ; then\n+\t\tgit bundle --list-heads \"$peek_repo\" ||\n \t\techo \"failed\tslurping\"\n+\telse\n+\t\tgit-peek-remote $exec \"$peek_repo\" ||\n+\t\techo \"failed\tslurping\"\n+\tfi\n \t;;\n esac |\n sort -t '\t' -k 2 |\n-- \n1.5.0.rc4.375.gd0938-dirty\n"},{"id":"34966","messageId":"45D8D776.9040604@verizon.net","threadId":"6845","inReplyTo":"11718196342317-git-send-email-mdl123@verizon.net","subject":"Re: [PATCH] Add git-bundle: move objects and references by archive.","fromName":"Mark Levedahl","fromEmail":"mdl123@verizon.net","sentAt":"2007-02-18T22:47:18Z","receivedAt":"2007-02-18T22:47:18Z","isPatch":true,"sender":{"key":"mdl123@verizon.net","avatar":"https://avatars.githubusercontent.com/u/5302462?v=4"},"body":"Mark Levedahl wrote:\n> -\tgit-peek-remote $exec \"$peek_repo\" ||\n> +\tif test -r \"$peek_repo\" ; then\n>   \noops:                   test    -f\nactually works. Corrected patch follows.\n\nMark\n"}]}