{"thread":{"id":"3678","subject":"efficient cloning","startedAt":"2006-03-19T21:16:16Z","lastAt":"2006-03-21T11:29:52Z","messageCount":22,"participants":["James Cloos","Shawn Pearce","Junio C Hamano","Petr Baudis","Josef Weidendorfer","Andreas Ericsson","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"17677","messageId":"m3r74ykue7.fsf@lugabout.cloos.reno.nv.us","threadId":"3678","inReplyTo":null,"subject":"efficient cloning","fromName":"James Cloos","fromEmail":"cloos@jhcloos.com","sentAt":"2006-03-19T21:16:16Z","receivedAt":"2006-03-19T21:16:16Z","isPatch":false,"sender":{"key":"cloos@jhcloos.com","avatar":"https://gravatar.com/avatar/ec9a05787d29afe41e243e4b60bd0e2f69d757688e8f0bfe5e78bc185a3e317f?d=mp&s=160"},"body":"Is there a way to accomplish the effect of this script w/o having to\ndownload any unnecessary objects?\n\n==================================================\n#!/bin/bash\n\nlt=\"/gits/linux-2.6/.git\"\n\nif [ $# -ne 2 ]; then\n    echo >&2 \"Usage: $0 <repo> <target-dir>\"\n    exit 1\nfi\n\ngit-clone $1 $2\nmkdir -p $2/objects/info\n{\n test -f \"$lt/objects/info/alternates\" &&\n cat \"$lt/objects/info/alternates\";\n echo \"$lt/objects\"\n} >\"$2/objects/info/alternates\"\n\ncd $2\ngit-repack -a -d -s\ngit-prune-packed\n==================================================\n\nI tried to modify git-clone to add an alternates file before calling\nfetch, but that file just gets deleted.\n\nI presume I need to clone -s -l the local alternate, re-parent it to\nthe new URL and grab anything missing, but how can I assure that it\nresults in exactly the same repo as this script?\n\nI'm often behind tiny straws, so efficiency is important.\n\n-JimC\n-- \nJames H. Cloos, Jr. <cloos@jhcloos.com>\n"},{"id":"17685","messageId":"20060319223111.GA20464@spearce.org","threadId":"3678","inReplyTo":"m3r74ykue7.fsf@lugabout.cloos.reno.nv.us","subject":"Re: efficient cloning","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-03-19T22:31:12Z","receivedAt":"2006-03-19T22:31:12Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"James Cloos <cloos@jhcloos.com> wrote:\n> Is there a way to accomplish the effect of this script w/o having to\n> download any unnecessary objects?\n> \n> ==================================================\n> #!/bin/bash\n> \n> lt=\"/gits/linux-2.6/.git\"\n> \n> if [ $# -ne 2 ]; then\n>     echo >&2 \"Usage: $0 <repo> <target-dir>\"\n>     exit 1\n> fi\n> \n> git-clone $1 $2\n> mkdir -p $2/objects/info\n> {\n>  test -f \"$lt/objects/info/alternates\" &&\n>  cat \"$lt/objects/info/alternates\";\n>  echo \"$lt/objects\"\n> } >\"$2/objects/info/alternates\"\n> \n> cd $2\n> git-repack -a -d -s\n> git-prune-packed\n> ==================================================\n> \n> I tried to modify git-clone to add an alternates file before calling\n> fetch, but that file just gets deleted.\n> \n> I presume I need to clone -s -l the local alternate, re-parent it to\n> the new URL and grab anything missing, but how can I assure that it\n> results in exactly the same repo as this script?\n\nExactly right.  There was some discussion about this perhaps just\ntwo weeks back and it become clear that the easiest way to clone\nthrough a thin straw is to use `git clone -s -l' from a locally\navailable repository which is ``close''[*1*] to the remote you are going\nto actually trying to clone from, edit .git/remotes/origin to have\nthe correct URL: and Pull: lines, then `git-pull origin' to bring\ndown whatever you don't have yet.  This won't miss any objects so\nit will result in the same repository as a clone would have[*2*].\n\nFootnotes:\n\n  [*1*] Here ``close'' means probably related to the same project.\n  Meaning if you are cloning the Linux kernel at least start with\n  another kernel repository and not say the GIT repository.  :-)\n  The more your original repository has in common with the remote you\n  are trying to pull from the less that will need to be downloaded.\n\n  [*2*] This isn't entirely true.  During a normal clone everything\n  is pulled down into a single pack. Using this strategy the missing\n  objects that are downloaded will be loose; a git-repack after\n  the pull might be a good idea to pull them into a pack.\n\n-- \nShawn.\n"},{"id":"17687","messageId":"7vu09um3ae.fsf@assigned-by-dhcp.cox.net","threadId":"3678","inReplyTo":"m3r74ykue7.fsf@lugabout.cloos.reno.nv.us","subject":"Re: efficient cloning","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-19T23:18:49Z","receivedAt":"2006-03-19T23:18:49Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"James Cloos <cloos@jhcloos.com> writes:\n\n> I presume I need to clone -s -l the local alternate, re-parent it to\n> the new URL and grab anything missing, but how can I assure that it\n> results in exactly the same repo as this script?\n\n\"The same repo as this script\" is a very poor way to define what\nyou really want.  What is \"git-repack -a -d -s\"?\n\nGuessing what you perhaps are trying to do:\n\n - You have /gits/linux-2.6/.git on your local disk that is a\n   reasonably recent copy of the upstream Linux 2.6 repository.\n\n - You want to clone from whatever $1 is (maybe a subsystem\n   tree, but we cannot tell from your question) to a new\n   directory $2.\n\n - Presumably you know whatever $1 is is related to Linus\n   repository and would want to take advantage of the fact that\n   it shares many objects with /gits/linux-2.6/.git\n\nIt might be worth adding a --reference flag to git-clone like\nthis patch does.\n\nHowever, this patch alone does not reduce the transferred data\nduring cloning any smaller if you are using the \"$1\" repository\nover git native transport (including a local repository),\nbecause the current clone-pack does not look at existing refs\n(it was written assuming that there is _nothing_ in the cloned\nrepository at the beginning).  That needs a separate\nenhancements.  Maybe it would be a good idea to deprecate\nclone-pack altogether, use fetch-pack -k, and implement the\n\"copy upstream refs to our refs\" logic in git-clone.sh.  We need\nto do something like that if/when we are switching to use\n$GIT_DIR/refs/remotes/ to store tracking branches outside\nrefs/heads anyway.\n\nThe rsync transport has been deprecated for some time, and it\ndoes not handle alternates correctly anyway, so this patch does\nnot have any impact on that.\n\nBut if you are going to \"$1\" over http transport, this patch\nwould help because we stash away the existing refs obtained from\nthe reference repository under $GIT_DIR/refs/reference-tmp while\nwe run the fetch.\n\n---\ndiff --git a/git-clone.sh b/git-clone.sh\nindex 4ed861d..73fb03c 100755\n--- a/git-clone.sh\n+++ b/git-clone.sh\n@@ -9,7 +9,7 @@\n unset CDPATH\n \n usage() {\n-\techo >&2 \"Usage: $0 [--bare] [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]\"\n+\techo >&2 \"Usage: $0 [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]\"\n \texit 1\n }\n \n@@ -56,6 +56,7 @@ upload_pack=\n bare=\n origin=origin\n origin_override=\n+reference=\n while\n \tcase \"$#,$1\" in\n \t0,*) break ;;\n@@ -68,6 +69,11 @@ while\n         *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared) \n           local_shared=yes; use_local=yes ;;\n \t*,-q|*,--quiet) quiet=-q ;;\n+\t*,--reference=*)\n+\t  reference=`expr \"$1\" : '-[^=]*=\\(.*\\)'` ;;\n+\t*,--reference)\n+\t  case \"$#\" in 1) usage ;; esac\n+\t  reference=\"$1\" ;;\n \t1,-o) usage;;\n \t*,-o)\n \t\tgit-check-ref-format \"$2\" || {\n@@ -130,6 +136,23 @@ yes)\n \tGIT_DIR=\"$D/.git\" ;;\n esac\n \n+# If given a reference we would first add that one; it has to name a\n+# local repository that resembles the one being cloned.\n+if test -d \"$reference\"\n+then\n+\treference=$(cd \"$reference\" && pwd)\n+\tif test -d \"$reference/.git/objects\"\n+\tthen\n+\t\treference=\"$reference/.git\"\n+\tfi\n+\techo \"$reference/objects\" >\"$GIT_DIR/objects/info/alternates\"\n+\t# Pretend we know about these heads - clone-pack does not\n+\t# honor them currently, but that can be rectified later.\n+\tmkdir \"$GIT_DIR/refs/reference-tmp\" \n+\t(cd \"$reference\" && tar cf - refs) |\n+\t(cd \"$GIT_DIR/refs/reference-tmp\" && tar xf -)\n+fi\n+\n # We do local magic only when the user tells us to.\n case \"$local,$use_local\" in\n yes,yes)\n@@ -229,6 +252,7 @@ yes,yes)\n esac\n \n cd \"$D\" || exit\n+test -d \"$GIT_DIR/refs/reference-tmp\" && rm -fr \"$GIT_DIR/refs/reference-tmp\"\n \n if test -f \"$GIT_DIR/HEAD\" && test -z \"$bare\"\n then\n"},{"id":"17691","messageId":"m3wteqj6qx.fsf@lugabout.cloos.reno.nv.us","threadId":"3678","inReplyTo":"7vu09um3ae.fsf@assigned-by-dhcp.cox.net","subject":"Re: efficient cloning","fromName":"James Cloos","fromEmail":"cloos@jhcloos.com","sentAt":"2006-03-20T00:32:22Z","receivedAt":"2006-03-20T00:32:22Z","isPatch":false,"sender":{"key":"cloos@jhcloos.com","avatar":"https://gravatar.com/avatar/ec9a05787d29afe41e243e4b60bd0e2f69d757688e8f0bfe5e78bc185a3e317f?d=mp&s=160"},"body":">>>>> \"Junio\" == Junio C Hamano <junkio@cox.net> writes:\n\nJunio> \"The same repo as this script\" is a very poor way to define what\nJunio> you really want. \n\nI don't think so.  Getting the same values in files like FETCH_HEAD,\nORIG_HEAD, branches/*, remotes/*,  info/* et al is not obvious.\nEspecially, eg, all of the same Push/Pull lines.\n\nJunio> What is \"git-repack -a -d -s\"?\n\nA typo.  I of course meant -a -d -l.\n\nJunio> It might be worth adding a --reference flag to git-clone like\nJunio> this patch does.\n\nThat is essentially what I tried (except only the name of the flag; I\nprefer your choice).  I didn't include the reference-tmp logic, but\notherwise it looks about the same.\n\nJunio> However, this patch alone does not reduce the transferred data\nJunio> during cloning any smaller if you are using the \"$1\" repository\nJunio> over git native transport (including a local repository),\nJunio> because the current clone-pack does not look at existing refs\n\nExactly the wall I ran into.  And I really only need it for git://.\n\nJunio> Maybe it would be a good idea to deprecate\nJunio> clone-pack altogether, use fetch-pack -k, and implement the\nJunio> \"copy upstream refs to our refs\" logic in git-clone.sh.  We need\nJunio> to do something like that if/when we are switching to use\nJunio> $GIT_DIR/refs/remotes/ to store tracking branches outside\nJunio> refs/heads anyway.\n\nAnd it looks like you've shown me the door in that wall.\n\nI'll have to read up on fetch-pack as opposed to clone-pack.\n\n-JimC\n-- \nJames H. Cloos, Jr. <cloos@jhcloos.com>\n"},{"id":"17692","messageId":"7vbqw1nakz.fsf@assigned-by-dhcp.cox.net","threadId":"3678","inReplyTo":"m3wteqj6qx.fsf@lugabout.cloos.reno.nv.us","subject":"Re: efficient cloning","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-20T01:55:56Z","receivedAt":"2006-03-20T01:55:56Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"James Cloos <cloos@jhcloos.com> writes:\n\n> Junio> Maybe it would be a good idea to deprecate\n> Junio> clone-pack altogether, use fetch-pack -k, and implement the\n> Junio> \"copy upstream refs to our refs\" logic in git-clone.sh.  We need\n> Junio> to do something like that if/when we are switching to use\n> Junio> $GIT_DIR/refs/remotes/ to store tracking branches outside\n> Junio> refs/heads anyway.\n>\n> And it looks like you've shown me the door in that wall.\n\nI was going to write that myself, but unfortunately will be\noffline for the rest of the evening -- interrupted by a surprise\nvisitor from India who is only visiting for a few days.\n\nSo in case you are really in a rush, and in a mood to build on\ntop of my WIP, here is one.\n\n* fetch-pack.c is modified so that you can say:\n\n\tgit fetch-pack --all -k $1\n\n  to get the list of \"git ls-remote $1\" equivalent while\n  fetching everything from the remote.\n\n* Change git-clone.sh to use git-fetch-pack --all -k instead of\n  git-clone-pack; the output from fetch-pack is munged further\n  by a script that implements \"copy the refs to the same\n  location while figuring out where the HEAD is\".  The latter\n  part in my WIP is incomplete so --use-separate-remote option\n  probably would not work right now.\n\n---\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 535de10..2d0a626 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -7,8 +7,9 @@\n static int keep_pack;\n static int quiet;\n static int verbose;\n+static int fetch_all;\n static const char fetch_pack_usage[] =\n-\"git-fetch-pack [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory <refs>...\";\n+\"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory <refs>...\";\n static const char *exec = \"git-upload-pack\";\n \n #define COMPLETE\t(1U << 0)\n@@ -266,8 +267,9 @@ static void filter_refs(struct ref **ref\n \tfor (prev = NULL, current = *refs; current; current = next) {\n \t\tnext = current->next;\n \t\tif ((!memcmp(current->name, \"refs/\", 5) &&\n-\t\t\t\t\tcheck_ref_format(current->name + 5)) ||\n-\t\t\t\t!path_match(current->name, nr_match, match)) {\n+\t\t     check_ref_format(current->name + 5)) ||\n+\t\t    (!fetch_all &&\n+\t\t     !path_match(current->name, nr_match, match))) {\n \t\t\tif (prev == NULL)\n \t\t\t\t*refs = next;\n \t\t\telse\n@@ -426,6 +428,10 @@ int main(int argc, char **argv)\n \t\t\t\tuse_thin_pack = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(\"--all\", arg)) {\n+\t\t\t\tfetch_all = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(\"-v\", arg)) {\n \t\t\t\tverbose = 1;\n \t\t\t\tcontinue;\ndiff --git a/git-clone.sh b/git-clone.sh\nindex 4ed861d..718029b 100755\n--- a/git-clone.sh\n+++ b/git-clone.sh\n@@ -9,7 +9,7 @@\n unset CDPATH\n \n usage() {\n-\techo >&2 \"Usage: $0 [--bare] [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]\"\n+\techo >&2 \"Usage: $0 [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]\"\n \texit 1\n }\n \n@@ -40,22 +40,74 @@ Perhaps git-update-server-info needs to \n \tdo\n \t\tname=`expr \"$refname\" : 'refs/\\(.*\\)'` &&\n \t\tcase \"$name\" in\n-\t\t*^*)\t;;\n-\t\t*)\n-\t\t\tgit-http-fetch -v -a -w \"$name\" \"$name\" \"$1/\" || exit 1\n+\t\t*^*)\tcontinue;;\n \t\tesac\n+\t\tif test -n \"$use_separate_remote\" &&\n+\t\t   branch_name=`expr \"$name\" : 'heads/\\(.*\\)'`\n+\t\tthen\n+\t\t\ttname=\"remotes/$branch_name\"\n+\t\telse\n+\t\t\ttname=$name\n+\t\tfi\n+\t\tgit-http-fetch -v -a -w \"$tname\" \"$name\" \"$1/\" || exit 1\n \tdone <\"$clone_tmp/refs\"\n \trm -fr \"$clone_tmp\"\n }\n \n+# A Perl script to read git-fetch -k output and store the\n+# remote branches.\n+copy_refs='\n+use File::Path qw(mkpath);\n+my $refs_file = $ARGV[0];\n+my $use_separate_remote = $ARGV[1];\n+my $git_dir = $ARGV[2];\n+\n+my $branch_top = ($use_separate_remote ? \"heads\" : \"remotes\");\n+my $tag_top = \"tags\";\n+my $head = undef;\n+\n+sub store {\n+\tmy ($sha1, $name, $top) = @_;\n+\t$name = \"$git_dir/refs/$top/$name\";\n+\tmkpath(dirname($name));\n+\topen O, \">\", \"$name\";\n+\tprint O \"$sha1\\n\";\n+\tclose O;\n+}\n+\n+open FH, \"<\", $refs_file;\n+while (<FH>) {\n+\tmy ($sha1, $name) = /^([0-9a-f]{40}) (.*)$/;\n+\tif ($name eq \"HEAD\") {\n+\t\t$head = $sha1;\n+\t\tnext;\n+\t}\n+\tif ($name =~ s/^refs\\/heads\\//) {\n+\t\tif (!defined $head && $name eq \"master\") {\n+\t\t\t$head = $sha1;\n+\t\t}\n+\t\tstore_branch($sha1, $name, $branch_top);\n+\t\tnext;\n+\t}\n+\tif ($name =~ s/^refs\\/tags\\//) {\n+\t\tstore_tag($sha1, $name, $tag_top);\n+\t\tnext;\n+\t}\n+}\n+close FH;\n+'\n+\n+\n quiet=\n use_local=no\n local_shared=no\n no_checkout=\n upload_pack=\n bare=\n+reference=\n origin=origin\n origin_override=\n+use_separate_remote=\n while\n \tcase \"$#,$1\" in\n \t0,*) break ;;\n@@ -68,7 +120,14 @@ while\n         *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared) \n           local_shared=yes; use_local=yes ;;\n \t*,-q|*,--quiet) quiet=-q ;;\n+\t*,--use-separate-remote)\n+\t\tuse_separate_remote=t ;;\n \t1,-o) usage;;\n+\t1,--reference) usage ;;\n+\t*,--reference)\n+\t\tshift; reference=\"$2\" ;;\n+\t*,--reference=*)\n+\t\treference=`expr \"$1\" : '--reference=\\(.*\\)'` ;;\n \t*,-o)\n \t\tgit-check-ref-format \"$2\" || {\n \t\t    echo >&2 \"'$2' is not suitable for a branch name\"\n@@ -130,6 +189,26 @@ yes)\n \tGIT_DIR=\"$D/.git\" ;;\n esac\n \n+if -n \"$reference\"\n+then\n+\tif test -d \"$reference\n+\tthen\n+\t\tif test -d \"$reference/.git/objects\"\n+\t\tthen\n+\t\t\treference=\"$reference/.git\"\n+\t\tfi\n+\t\treference=(cd \"$reference\" && pwd)\n+\t\techo \"$reference/objects\" >\"$GIT_DIR/objects/info/alternates\"\n+\t\t(cd \"$reference\" && tar cf - refs) |\n+\t\t(cd \"$GIT_DIR/refs &&\n+\t\t mkdir reference-tmp &&\n+\t\t cd reference-tmp &&\n+\t\t tar xf -)\n+\telse\n+\t\techo >&2 \"$reference: not a local directory.\" && usage\n+\tfi\n+fi\n+\n # We do local magic only when the user tells us to.\n case \"$local,$use_local\" in\n yes,yes)\n@@ -217,17 +296,22 @@ yes,yes)\n \t\t;;\n \t*)\n \t\tcd \"$D\" && case \"$upload_pack\" in\n-\t\t'') git-clone-pack $quiet \"$repo\" ;;\n-\t\t*) git-clone-pack $quiet \"$upload_pack\" \"$repo\" ;;\n-\t\tesac || {\n+\t\t'') git-fetch-pack -k $quiet \"$repo\" ;;\n+\t\t*) git-fetch-pack -k $quiet \"$upload_pack\" \"$repo\" ;;\n+\t\tesac >\"$GIT_DIR/FETCH_HEAD\" || {\n \t\t\techo >&2 \"clone-pack from '$repo' failed.\"\n \t\t\texit 1\n \t\t}\n+\t\t# Now figure out where the remote HEAD points at.\n+\t\tperl -e \"$copy_refs\" \"$GIT_DIR/FETCH_HEAD\" \\\n+\t\t\t\"$use_separate_remote\" \"$GIT_DIR\"\n \t\t;;\n \tesac\n \t;;\n esac\n \n+test -d \"$GIT_DIR/refs/reference-tmp\" && rm -fr \"$GIT_DIR/refs/reference-tmp\"\n+\n cd \"$D\" || exit\n \n if test -f \"$GIT_DIR/HEAD\" && test -z \"$bare\"\n"},{"id":"17697","messageId":"7vu09tjy38.fsf@assigned-by-dhcp.cox.net","threadId":"3678","inReplyTo":"7vbqw1nakz.fsf@assigned-by-dhcp.cox.net","subject":"Re: efficient cloning","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-20T08:54:03Z","receivedAt":"2006-03-20T08:54:03Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> So in case you are really in a rush, and in a mood to build on\n> top of my WIP, here is one.\n\nAnd this is an replacement, which actually has seen some\ntesting.  I'll place this in the \"next\" branch tonight.  Further\ntesting is appreciated.\n\n-- >8 --\n[PATCH] revamp git-clone.\n\nThis does two things.\n\n * A new flag --reference can be used to name a local repository\n   that is to be used as an alternate.  This is in response to\n   an inquiry by James Cloos in the message on the list\n   <m3r74ykue7.fsf@lugabout.cloos.reno.nv.us>.\n\n * A new flag --use-separate-remote stops contaminating local\n   branch namespace by upstream branch names.  The upstream\n   branch heads are copied in .git/refs/remotes/ instead of\n   .git/refs/heads/ and .git/remotes/origin file is set up to\n   reflect this as well.  It requires to have fetch/pull update\n   to understand .git/refs/remotes by Eric Wong to further\n   update the repository cloned this way.\n\nFor the former change, git-fetch-pack is taught a new flag --all\nto fetch from all the remote heads.  Nobody uses the git-clone-pack\nwith this change, so we could deprecate the command, but removal\nof the command will be left to a separate round.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n fetch-pack.c |   18 ++++--\n git-clone.sh |  184 ++++++++++++++++++++++++++++++++++++++++++++++++----------\n 2 files changed, 166 insertions(+), 36 deletions(-)\n\ndfeff66ed9a3931d60f3cd600ad8c14b5cc3d9e5\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 535de10..a3bcad0 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -7,8 +7,9 @@\n static int keep_pack;\n static int quiet;\n static int verbose;\n+static int fetch_all;\n static const char fetch_pack_usage[] =\n-\"git-fetch-pack [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory <refs>...\";\n+\"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory <refs>...\";\n static const char *exec = \"git-upload-pack\";\n \n #define COMPLETE\t(1U << 0)\n@@ -266,8 +267,9 @@ static void filter_refs(struct ref **ref\n \tfor (prev = NULL, current = *refs; current; current = next) {\n \t\tnext = current->next;\n \t\tif ((!memcmp(current->name, \"refs/\", 5) &&\n-\t\t\t\t\tcheck_ref_format(current->name + 5)) ||\n-\t\t\t\t!path_match(current->name, nr_match, match)) {\n+\t\t     check_ref_format(current->name + 5)) ||\n+\t\t    (!fetch_all &&\n+\t\t     !path_match(current->name, nr_match, match))) {\n \t\t\tif (prev == NULL)\n \t\t\t\t*refs = next;\n \t\t\telse\n@@ -376,7 +378,11 @@ static int fetch_pack(int fd[2], int nr_\n \t\tgoto all_done;\n \t}\n \tif (find_common(fd, sha1, ref) < 0)\n-\t\tfprintf(stderr, \"warning: no common commits\\n\");\n+\t\tif (!keep_pack)\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\tfprintf(stderr, \"warning: no common commits\\n\");\n \n \tif (keep_pack)\n \t\tstatus = receive_keep_pack(fd, \"git-fetch-pack\", quiet);\n@@ -426,6 +432,10 @@ int main(int argc, char **argv)\n \t\t\t\tuse_thin_pack = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(\"--all\", arg)) {\n+\t\t\t\tfetch_all = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(\"-v\", arg)) {\n \t\t\t\tverbose = 1;\n \t\t\t\tcontinue;\ndiff --git a/git-clone.sh b/git-clone.sh\nindex 4ed861d..9db678b 100755\n--- a/git-clone.sh\n+++ b/git-clone.sh\n@@ -9,7 +9,7 @@\n unset CDPATH\n \n usage() {\n-\techo >&2 \"Usage: $0 [--bare] [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]\"\n+\techo >&2 \"Usage: $0 [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]\"\n \texit 1\n }\n \n@@ -40,13 +40,61 @@ Perhaps git-update-server-info needs to \n \tdo\n \t\tname=`expr \"$refname\" : 'refs/\\(.*\\)'` &&\n \t\tcase \"$name\" in\n-\t\t*^*)\t;;\n-\t\t*)\n-\t\t\tgit-http-fetch -v -a -w \"$name\" \"$name\" \"$1/\" || exit 1\n+\t\t*^*)\tcontinue;;\n \t\tesac\n+\t\tif test -n \"$use_separate_remote\" &&\n+\t\t   branch_name=`expr \"$name\" : 'heads/\\(.*\\)'`\n+\t\tthen\n+\t\t\ttname=\"remotes/$branch_name\"\n+\t\telse\n+\t\t\ttname=$name\n+\t\tfi\n+\t\tgit-http-fetch -v -a -w \"$tname\" \"$name\" \"$1/\" || exit 1\n \tdone <\"$clone_tmp/refs\"\n \trm -fr \"$clone_tmp\"\n+\thttp_fetch \"$1/HEAD\" \"$GIT_DIR/REMOTE_HEAD\"\n+}\n+\n+# Read git-fetch-pack -k output and store the remote branches.\n+copy_refs='\n+use File::Path qw(mkpath);\n+use File::Basename qw(dirname);\n+my $git_dir = $ARGV[0];\n+my $use_separate_remote = $ARGV[1];\n+\n+my $branch_top = ($use_separate_remote ? \"remotes\" : \"heads\");\n+my $tag_top = \"tags\";\n+\n+sub store {\n+\tmy ($sha1, $name, $top) = @_;\n+\t$name = \"$git_dir/refs/$top/$name\";\n+\tmkpath(dirname($name));\n+\topen O, \">\", \"$name\";\n+\tprint O \"$sha1\\n\";\n+\tclose O;\n+}\n+\n+open FH, \"<\", \"$git_dir/CLONE_HEAD\";\n+while (<FH>) {\n+\tmy ($sha1, $name) = /^([0-9a-f]{40})\\s(.*)$/;\n+\tnext if ($name =~ /\\^\\173/);\n+\tif ($name eq \"HEAD\") {\n+\t\topen O, \">\", \"$git_dir/REMOTE_HEAD\";\n+\t\tprint O \"$sha1\\n\";\n+\t\tclose O;\n+\t\tnext;\n+\t}\n+\tif ($name =~ s/^refs\\/heads\\///) {\n+\t\tstore($sha1, $name, $branch_top);\n+\t\tnext;\n+\t}\n+\tif ($name =~ s/^refs\\/tags\\///) {\n+\t\tstore($sha1, $name, $tag_top);\n+\t\tnext;\n+\t}\n }\n+close FH;\n+'\n \n quiet=\n use_local=no\n@@ -54,8 +102,10 @@ local_shared=no\n no_checkout=\n upload_pack=\n bare=\n-origin=origin\n+reference=\n+origin=\n origin_override=\n+use_separate_remote=\n while\n \tcase \"$#,$1\" in\n \t0,*) break ;;\n@@ -68,7 +118,14 @@ while\n         *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared) \n           local_shared=yes; use_local=yes ;;\n \t*,-q|*,--quiet) quiet=-q ;;\n+\t*,--use-separate-remote)\n+\t\tuse_separate_remote=t ;;\n \t1,-o) usage;;\n+\t1,--reference) usage ;;\n+\t*,--reference)\n+\t\tshift; reference=\"$1\" ;;\n+\t*,--reference=*)\n+\t\treference=`expr \"$1\" : '--reference=\\(.*\\)'` ;;\n \t*,-o)\n \t\tgit-check-ref-format \"$2\" || {\n \t\t    echo >&2 \"'$2' is not suitable for a branch name\"\n@@ -100,9 +157,24 @@ then\n \t\techo >&2 '--bare and -o $origin options are incompatible.'\n \t\texit 1\n \tfi\n+\tif test t = \"$use_separate_remote\"\n+\tthen\n+\t\techo >&2 '--bare and --use-separate-remote options are incompatible.'\n+\t\texit 1\n+\tfi\n \tno_checkout=yes\n fi\n \n+if test -z \"$origin_override$origin\"\n+then\n+\tif test -n \"$use_separate_remote\"\n+\tthen\n+\t\torigin=remotes/master\n+\telse\n+\t\torigin=heads/origin\n+\tfi\n+fi\n+\n # Turn the source into an absolute path if\n # it is local\n repo=\"$1\"\n@@ -130,6 +202,28 @@ yes)\n \tGIT_DIR=\"$D/.git\" ;;\n esac\n \n+if test -n \"$reference\"\n+then\n+\tif test -d \"$reference\"\n+\tthen\n+\t\tif test -d \"$reference/.git/objects\"\n+\t\tthen\n+\t\t\treference=\"$reference/.git\"\n+\t\tfi\n+\t\treference=$(cd \"$reference\" && pwd)\n+\t\techo \"$reference/objects\" >\"$GIT_DIR/objects/info/alternates\"\n+\t\t(cd \"$reference\" && tar cf - refs) |\n+\t\t(cd \"$GIT_DIR/refs\" &&\n+\t\t mkdir reference-tmp &&\n+\t\t cd reference-tmp &&\n+\t\t tar xf -)\n+\telse\n+\t\techo >&2 \"$reference: not a local directory.\" && usage\n+\tfi\n+fi\n+\n+rm -f \"$GIT_DIR/CLONE_HEAD\"\n+\n # We do local magic only when the user tells us to.\n case \"$local,$use_local\" in\n yes,yes)\n@@ -165,24 +259,14 @@ yes,yes)\n \t    } >\"$GIT_DIR/objects/info/alternates\"\n \t    ;;\n \tesac\n-\n-\t# Make a duplicate of refs and HEAD pointer\n-\tHEAD=\n-\tif test -f \"$repo/HEAD\"\n-\tthen\n-\t\tHEAD=HEAD\n-\tfi\n-\t(cd \"$repo\" && tar cf - refs $HEAD) |\n-\t(cd \"$GIT_DIR\" && tar xf -) || exit 1\n+\tgit-ls-remote \"$repo\" >\"$GIT_DIR/CLONE_HEAD\"\n \t;;\n *)\n \tcase \"$repo\" in\n \trsync://*)\n \t\trsync $quiet -av --ignore-existing  \\\n-\t\t\t--exclude info \"$repo/objects/\" \"$GIT_DIR/objects/\" &&\n-\t\trsync $quiet -av --ignore-existing  \\\n-\t\t\t--exclude info \"$repo/refs/\" \"$GIT_DIR/refs/\" || exit\n-\n+\t\t\t--exclude info \"$repo/objects/\" \"$GIT_DIR/objects/\" ||\n+\t\texit\n \t\t# Look at objects/info/alternates for rsync -- http will\n \t\t# support it natively and git native ones will do it on the\n \t\t# remote end.  Not having that file is not a crime.\n@@ -205,6 +289,7 @@ yes,yes)\n \t\t    done\n \t\t    rm -f \"$GIT_DIR/TMP_ALT\"\n \t\tfi\n+\t\tgit-ls-remote \"$repo\" >\"$GIT_DIR/CLONE_HEAD\"\n \t\t;;\n \thttp://*)\n \t\tif test -z \"@@NO_CURL@@\"\n@@ -217,37 +302,71 @@ yes,yes)\n \t\t;;\n \t*)\n \t\tcd \"$D\" && case \"$upload_pack\" in\n-\t\t'') git-clone-pack $quiet \"$repo\" ;;\n-\t\t*) git-clone-pack $quiet \"$upload_pack\" \"$repo\" ;;\n-\t\tesac || {\n-\t\t\techo >&2 \"clone-pack from '$repo' failed.\"\n+\t\t'') git-fetch-pack --all -k $quiet \"$repo\" ;;\n+\t\t*) git-fetch-pack --all -k $quiet \"$upload_pack\" \"$repo\" ;;\n+\t\tesac >\"$GIT_DIR/CLONE_HEAD\" || {\n+\t\t\techo >&2 \"fetch-pack from '$repo' failed.\"\n \t\t\texit 1\n \t\t}\n \t\t;;\n \tesac\n \t;;\n esac\n+test -d \"$GIT_DIR/refs/reference-tmp\" && rm -fr \"$GIT_DIR/refs/reference-tmp\"\n+\n+if test -f \"$GIT_DIR/CLONE_HEAD\"\n+then\n+\t# Figure out where the remote HEAD points at.\n+\tperl -e \"$copy_refs\" \"$GIT_DIR\" \"$use_separate_remote\"\n+fi\n \n cd \"$D\" || exit\n \n-if test -f \"$GIT_DIR/HEAD\" && test -z \"$bare\"\n+if test -z \"$bare\" && test -f \"$GIT_DIR/REMOTE_HEAD\"\n then\n-\thead_points_at=`git-symbolic-ref HEAD`\n+\thead_sha1=`cat \"$GIT_DIR/REMOTE_HEAD\"`\n+\t# Figure out which remote branch HEAD points at.\n+\tcase \"$use_separate_remote\" in\n+\t'')\tremote_top=refs/heads ;;\n+\t*)\tremote_top=refs/remotes ;;\n+\tesac\n+\thead_points_at=$(\n+\t\t(\n+\t\t\techo \"master\"\n+\t\t\tcd \"$GIT_DIR/$remote_top\" &&\n+\t\t\tfind . -type f -print | sed -e 's/^\\.\\///'\n+\t\t) | (\n+\t\tdone=f\n+\t\twhile read name\n+\t\tdo\n+\t\t\ttest t = $done && continue\n+\t\t\tbranch_tip=`cat \"$GIT_DIR/$remote_top/$name\"`\n+\t\t\tif test \"$head_sha1\" = \"$branch_tip\"\n+\t\t\tthen\n+\t\t\t\techo \"$name\"\n+\t\t\t\tdone=t\n+\t\t\tfi\n+\t\tdone\n+\t\t)\n+\t)\n \tcase \"$head_points_at\" in\n-\trefs/heads/*)\n-\t\thead_points_at=`expr \"$head_points_at\" : 'refs/heads/\\(.*\\)'`\n+\t?*)\n \t\tmkdir -p \"$GIT_DIR/remotes\" &&\n \t\techo >\"$GIT_DIR/remotes/origin\" \\\n \t\t\"URL: $repo\n-Pull: $head_points_at:$origin\" &&\n-\t\tgit-update-ref \"refs/heads/$origin\" $(git-rev-parse HEAD) &&\n-\t\t(cd \"$GIT_DIR\" && find \"refs/heads\" -type f -print) |\n+Pull: refs/heads/$head_points_at:refs/$origin\" &&\n+\t\tcase \"$use_separate_remote\" in\n+\t\tt) git-update-ref HEAD \"$head_sha1\" ;;\n+\t\t*) git-update-ref \"refs/$origin\" $(git-rev-parse HEAD)\n+\t\tesac &&\n+\t\t(cd \"$GIT_DIR\" && find \"$remote_top\" -type f -print) |\n \t\twhile read ref\n \t\tdo\n-\t\t\thead=`expr \"$ref\" : 'refs/heads/\\(.*\\)'` &&\n-\t\t\ttest \"$head_points_at\" = \"$head\" ||\n+\t\t\thead=`expr \"$ref\" : 'refs/\\(.*\\)'` &&\n+\t\t\tname=`expr \"$ref\" : 'refs/[^\\/]*/\\(.*\\)'` &&\n+\t\t\ttest \"$head_points_at\" = \"$name\" ||\n \t\t\ttest \"$origin\" = \"$head\" ||\n-\t\t\techo \"Pull: ${head}:${head}\"\n+\t\t\techo \"Pull: refs/heads/${name}:$remote_top/${name}\"\n \t\tdone >>\"$GIT_DIR/remotes/origin\"\n \tesac\n \n@@ -256,6 +375,7 @@ Pull: $head_points_at:$origin\" &&\n \t\tgit-read-tree -m -u -v HEAD HEAD\n \tesac\n fi\n+rm -f \"$GIT_DIR/CLONE_HEAD\" \"$GIT_DIR/REMOTE_HEAD\"\n \n trap - exit\n \n-- \n1.2.4.gb7986\n"},{"id":"17708","messageId":"20060320151833.GN18185@pasky.or.cz","threadId":"3678","inReplyTo":"7vu09tjy38.fsf@assigned-by-dhcp.cox.net","subject":"Re: efficient cloning","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-03-20T15:18:33Z","receivedAt":"2006-03-20T15:18:33Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Mon, Mar 20, 2006 at 09:54:03AM CET, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n>  * A new flag --use-separate-remote stops contaminating local\n>    branch namespace by upstream branch names.  The upstream\n>    branch heads are copied in .git/refs/remotes/ instead of\n>    .git/refs/heads/ and .git/remotes/origin file is set up to\n>    reflect this as well.  It requires to have fetch/pull update\n>    to understand .git/refs/remotes by Eric Wong to further\n>    update the repository cloned this way.\n\nI think this sucks the way it is, because you still have only a single\nnamespace for remotes (still quite a huge improvement to the current git\nsituation), but you can have many upstreams. So it would be a quite more\nreasonable to have:\n\n\t.git/refs/remotes/<remotename>/<headname>\n\nThis is also how I would like to do it for cg-clone -a (which I planned\nto implement the last weekend... well... ;). Actually, I think I will\nstay in .git/refs/heads/ at least for now until git versions with\n.git/refs/remotes/ in the refs search path will be released.\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nRight now I am having amnesia and deja-vu at the same time.  I think\nI have forgotten this before.\n"},{"id":"17710","messageId":"200603201730.19373.Josef.Weidendorfer@gmx.de","threadId":"3678","inReplyTo":"7vu09tjy38.fsf@assigned-by-dhcp.cox.net","subject":"Re: efficient cloning","fromName":"Josef Weidendorfer","fromEmail":"josef.weidendorfer@gmx.de","sentAt":"2006-03-20T16:30:19Z","receivedAt":"2006-03-20T16:30:19Z","isPatch":false,"sender":{"key":"josef.weidendorfer@gmx.de","avatar":null},"body":"On Monday 20 March 2006 09:54, you wrote:\n>  * A new flag --use-separate-remote stops contaminating local\n>    branch namespace by upstream branch names.  The upstream\n>    branch heads are copied in .git/refs/remotes/ instead of\n\nShouldn't this be .git/refs/remotes/origin/?\nIe. different namespaces for different remotes?\n\nLinus wanted to still be able to say \"origin\" which automatically\nwould map to \"remotes/origin/master\", where the name of the remote\nbranch (here \"master\") is the first mentioned in the Pull line of\nthe .git/remotes file in eg.\n\n\tgit diff origin..master\n\nI am not sure whether we really want \"take first refspec mentioned on Pull\nline\", as there can be multiple tracked remote branches with their own local\ndevelopments...\nIe. I want to be able to specify: \"The local development branch X is based on\nthe following remote branch Y , which is tracked locally as Z.\".\nThis way, you also could warn/prohobit accidential nonsense merges because of wrong use\nof \"git-pull\". \n\nJosef\n"},{"id":"17720","messageId":"7vk6aokd7m.fsf@assigned-by-dhcp.cox.net","threadId":"3678","inReplyTo":"20060320151833.GN18185@pasky.or.cz","subject":"Re: efficient cloning","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-20T21:39:41Z","receivedAt":"2006-03-20T21:39:41Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n> I think this sucks the way it is, because you still have only a single\n> namespace for remotes (still quite a huge improvement to the current git\n> situation), but you can have many upstreams.\n\nCome on, give me a break.\n\nYou are commenting on the initial 'git-clone' and specifically\non one of its optional feature.  What multiple upstreams?\n\nThe whole point of what git-clone does on top of making a\nstraight clone of the remote is to give you a reasonable\nstarting point.  The traditional \"master\" -> \"origin\" mapping is\ngood for cloning a typical single-head repository.  If your\nupsteram has more branches, --use-separate-remote would help you\nto start your branch namespace uncluttered.\n\nIf you want to go fancier after the initial clone to\n\"cg-add-branch\" more upstreams, you can implement a customized\neditor, even a graphical one if you want, that inspects\n$GIT_DIR/[branches,remotes} _and_ $GIT_DIR/{heads,remotes},\nshows the current status, and lets you edit the contents of a\n$GIT_DIR/remotes/foobar _while_ making matching changes to what\nare under $GIT_DIR/{heads,remotes}.\n"},{"id":"17721","messageId":"20060320224123.GP18185@pasky.or.cz","threadId":"3678","inReplyTo":"7vk6aokd7m.fsf@assigned-by-dhcp.cox.net","subject":"Re: efficient cloning","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-03-20T22:41:23Z","receivedAt":"2006-03-20T22:41:23Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Mon, Mar 20, 2006 at 10:39:41PM CET, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n> You are commenting on the initial 'git-clone' and specifically\n> on one of its optional feature.  What multiple upstreams?\n> \n> The whole point of what git-clone does on top of making a\n> straight clone of the remote is to give you a reasonable\n> starting point.  The traditional \"master\" -> \"origin\" mapping is\n> good for cloning a typical single-head repository.  If your\n> upsteram has more branches, --use-separate-remote would help you\n> to start your branch namespace uncluttered.\n\nYes, but I just see no connecting with a \"starting point\" whatsoever -\nwhy should this be inherent to initial clone? I can see no greater\nchance that I will want all the branches than when I want to fetch from\nanother repository later (especially in a truly distributed\nenvironment).\n\nSo, it doesn't make sense to me to limit this feature only to the\ninitial clone case - I want to be able to reasonably \"fetch all\nbranches\" of any repository I wish. Without massive namespace clashes,\nthe reasonable way is to just have a separate directory in\n.git/refs/remotes/ for each repository (and it's my understanding that\nthis was the original proposal as well).\n\nThen you can make a simple change that if a refname matches a directory\nin refs/remotes/, you rewrite it as refs/remotes/<refname>/master. This\nmakes 'origin' work seamlessly in a natural way and a lot more elegantly\nthan if you make up an artifical rule like \"if the remote's branch is\nmaster, save it as origin, but save all the other branches verbatim\".\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nRight now I am having amnesia and deja-vu at the same time.  I think\nI have forgotten this before.\n"},{"id":"17722","messageId":"7voe00iupp.fsf@assigned-by-dhcp.cox.net","threadId":"3678","inReplyTo":"200603201730.19373.Josef.Weidendorfer@gmx.de","subject":"Re: efficient cloning","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-20T23:04:34Z","receivedAt":"2006-03-20T23:04:34Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Josef Weidendorfer <Josef.Weidendorfer@gmx.de> writes:\n\n> On Monday 20 March 2006 09:54, you wrote:\n>>  * A new flag --use-separate-remote stops contaminating local\n>>    branch namespace by upstream branch names.  The upstream\n>>    branch heads are copied in .git/refs/remotes/ instead of\n>\n> Shouldn't this be .git/refs/remotes/origin/?\n> Ie. different namespaces for different remotes?\n>\n> Linus wanted to still be able to say \"origin\" which automatically\n> would map to \"remotes/origin/master\", where the name of the remote\n\nI do not remember that, but even if he said something similar to\nthat, I suspect it would not be \"map remotes/origin/master to\norigin\", but \"origin could mean remotes/origin when origin is\nthe unique tail-name anywhere under refs/\".\n\nI think what is reasonable is something like this:\n\n - If you start from a repository cloned in the traditional\n   way, the upstream \"master\" is kept track of with your\n   \"origin\", so \"diff origin master\" would be \"my changes on top\n   of the upstream\".\n\n - If your repository was cloned with --use-separate-remote, the\n   upstream \"master\" is refs/remotes/master, so the same diff\n   can be had with \"diff remotes/master master\".\n\n - Regardless of how you started your cloned repository, with an\n   $GIT_DIR/{remotes,refs/heads,refs/remotes} editor I hinted in\n   a separate message, you can rearrange things to organize the\n   refs/ hierarchy any way you want.\n\n   - You could for example arrange to track my \"master\" as\n     refs/heads/origin and all the other branch heads under\n     refs/remotes/junkio/ (or not even track my other branches\n     if you are not interested).  Then the same diff can be had\n     with \"diff origin master\".\n\n   - You could for example arrange to track all my branches in\n     refs/remotes/junkio/, and if git-pasky were still alive,\n     Pasky's branches in refs/remotes/pasky.  If we had a \"take\n     the unique tail-name anywhere under refs/\" logic, the same\n     diff can be had with \"diff junkio/master master\".\n\nSo I think two things that would be nice to have on top of what\nwe have are (1) the said \"remotes-and-refs editor\" [*1*], and\n(2) a change to sha1_name.c to look for places other than\nbuilt-in tags/ and heads/ under refs/ to find a unique\ntail-match.\n\nSince I do not do Porcelain, (2) would obviously be the next\nthing for me to work on on this topic.  I should also address\n\"Ouch I did not realize I have given the same name to a tag and\na branch\" warning issue while doing so.\n\n\n[Footnote]\n\n*1* ... which currently I do not plan to do myself unless I have\nabsolutely nothing else to do and really bored.  A sound of huge\nhint dropping ;-).\n"},{"id":"17723","messageId":"7vk6aoiulj.fsf@assigned-by-dhcp.cox.net","threadId":"3678","inReplyTo":"20060320224123.GP18185@pasky.or.cz","subject":"Re: efficient cloning","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-20T23:07:04Z","receivedAt":"2006-03-20T23:07:04Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n> Then you can make a simple change that if a refname matches a directory\n> in refs/remotes/, you rewrite it as refs/remotes/<refname>/master. This\n> makes 'origin' work seamlessly in a natural way and a lot more elegantly\n> than if you make up an artifical rule like \"if the remote's branch is\n> master, save it as origin, but save all the other branches verbatim\".\n\nThe \"origin\" rename applies only to the traditional one.\nSeparate remote stuff stores master in remotes/master.\n\nAt least that is the way I remember I designed it to work.\n"},{"id":"17724","messageId":"20060320232101.GQ18185@pasky.or.cz","threadId":"3678","inReplyTo":"7voe00iupp.fsf@assigned-by-dhcp.cox.net","subject":"Re: efficient cloning","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-03-20T23:21:01Z","receivedAt":"2006-03-20T23:21:01Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Tue, Mar 21, 2006 at 12:04:34AM CET, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n> I think what is reasonable is something like this:\n\n<insert all of the arguments in my other mail here ;>\n\n>  - If your repository was cloned with --use-separate-remote, the\n>    upstream \"master\" is refs/remotes/master, so the same diff\n>    can be had with \"diff remotes/master master\".\n\nWhich is ugly. There is no reason why you couldn't go on using 'origin'\nwhich is shorter and we can usually still unambiguously decide what did\nyou mean (unless you have a local head/tag 'origin' _and_ a remote named\n'origin' at the same time).\n\n>  - Regardless of how you started your cloned repository, with an\n>    $GIT_DIR/{remotes,refs/heads,refs/remotes} editor I hinted in\n>    a separate message, you can rearrange things to organize the\n>    refs/ hierarchy any way you want.\n\nYes, but that makes no sense to do when you usually need this only in\nsome very special cases (and then you ought to be able to set up the\nweird thing yourself), while we can do the doubtlessly right thing in\nthe general case, WITHOUT confusing the user, WHILE keeping things tidy\nand easy to use (and without excessive typing). In fact, you described\nit yourself:\n\n>    - You could for example arrange to track all my branches in\n>      refs/remotes/junkio/, and if git-pasky were still alive,\n>      Pasky's branches in refs/remotes/pasky.  If we had a \"take\n>      the unique tail-name anywhere under refs/\" logic, the same\n>      diff can be had with \"diff junkio/master master\".\n\nExcept that you can just name the refs/remotes/directory the same way\nyou name the remote repository identifier (be it a Git-style remote or\nCogito's remote branch).\n\nI still don't get what's wrong on what I'm proposing. I'm not seeing the\ndisadvantages, if there are any.\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nRight now I am having amnesia and deja-vu at the same time.  I think\nI have forgotten this before.\n"},{"id":"17725","messageId":"7vfylcismx.fsf@assigned-by-dhcp.cox.net","threadId":"3678","inReplyTo":"20060320232101.GQ18185@pasky.or.cz","subject":"Re: efficient cloning","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-20T23:49:26Z","receivedAt":"2006-03-20T23:49:26Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n> I still don't get what's wrong on what I'm proposing. I'm not seeing the\n> disadvantages, if there are any.\n\nThe only thing I think there is is that I do not get what you\nare proposing ;-), since I am not paying full attention while at\nday-job.\n\nIf you are proposing to root --use-separate-remote not at\nrefs/remotes but refs/remotes/origin/, I think it makes kind of\nsense.  It would make tons of sense _if_ dealing more than one\nremote repository is the norm, but otherwise you would have an\nextra level of directory refs/remotes which almost always have\nonly one subdirectory 'origin' and nothing else, which is\npointless.\n\nI am not sure if you are also advocating to map (somehow) origin\nto remotes/origin/master (or whatever branch remote's HEAD\npoints at), but if so I am not quite sure what its semantics\nwould be.  Which remote branch would you pick (that would not\nnecessarily be \"master\") and where are you going to record that\nand when.  It all sounds to me complicating things\nunnecessarily.\n"},{"id":"17726","messageId":"200603210126.59870.Josef.Weidendorfer@gmx.de","threadId":"3678","inReplyTo":"7voe00iupp.fsf@assigned-by-dhcp.cox.net","subject":"Re: efficient cloning","fromName":"Josef Weidendorfer","fromEmail":"josef.weidendorfer@gmx.de","sentAt":"2006-03-21T00:26:59Z","receivedAt":"2006-03-21T00:26:59Z","isPatch":false,"sender":{"key":"josef.weidendorfer@gmx.de","avatar":null},"body":"On Tuesday 21 March 2006 00:04, you wrote:\n> > Linus wanted to still be able to say \"origin\" which automatically\n> > would map to \"remotes/origin/master\", where the name of the remote\n> \n> I do not remember that,\n\nSee\nhttp://www.gelato.unsw.edu.au/archives/git/0603/17405.html\n\nI found it strange at first. But I think it is the right thing.\n\n> I think what is reasonable is something like this:\n> \n>  - If you start from a repository cloned in the traditional\n>    way, the upstream \"master\" is kept track of with your\n>    \"origin\", so \"diff origin master\" would be \"my changes on top\n>    of the upstream\".\n\nYes. And it would be nice if the same would work with the new layout,\nassuming that there is no local \"origin\" branch, but a .git/remotes/origin\nfile and .git/refs/remotes/origin directory.\n\n>  - Regardless of how you started your cloned repository, with an\n>    $GIT_DIR/{remotes,refs/heads,refs/remotes} editor I hinted in\n>    a separate message, you can rearrange things to organize the\n>    refs/ hierarchy any way you want.\n\nYes.\nStill it would be nice to have a fixed convention here.\nEg. gitk could decorate the namespace in a special way.\nEven if it is most of the time \"origin\" only.\n\n> [Footnote]\n> \n> *1* ... which currently I do not plan to do myself unless I have\n> absolutely nothing else to do and really bored.  A sound of huge\n> hint dropping ;-).\n\nIt should be as simple as (probably with quite some errors)\n\n~/> cat git-rename-remote.sh\nmv .git/refs/remotes/$1 .git/refs/remotes/$2\nsed -e \"s|remotes/$1|remotes/$2\" .git/remotes/$1 > .git/remotes/$2\nrm .git/remotes/$1\n\nIf you allow more freedom regarding the use of refs/remotes, it gets more\ncomplicated both for the script and for the user to understand.\n\nJosef\n"},{"id":"17727","messageId":"7v8xr4iph8.fsf@assigned-by-dhcp.cox.net","threadId":"3678","inReplyTo":"200603210126.59870.Josef.Weidendorfer@gmx.de","subject":"Re: efficient cloning","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-21T00:57:39Z","receivedAt":"2006-03-21T00:57:39Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Josef Weidendorfer <Josef.Weidendorfer@gmx.de> writes:\n\n>> I think what is reasonable is something like this:\n>> \n>>  - If you start from a repository cloned in the traditional\n>>    way, the upstream \"master\" is kept track of with your\n>>    \"origin\", so \"diff origin master\" would be \"my changes on top\n>>    of the upstream\".\n>\n> Yes. And it would be nice if the same would work with the new layout,\n> assuming that there is no local \"origin\" branch, but a .git/remotes/origin\n> file and .git/refs/remotes/origin directory.\n\nMy primary aversion comes from that I'd rather avoid teaching\nthe really core stuff about .git/remotes file, and the part that\ninterprets refname is fairly a low-level part.\n\nWe _could_ record refs/remotes/origin/HEAD that points at\nrefs/remotes/origin/master (or some other branch) upon cloning,\nand if Pasky wants to do something similar upon fetching, that\nfetch command could do the same thing.\n"},{"id":"17729","messageId":"441FB715.1000500@op5.se","threadId":"3678","inReplyTo":"7vfylcismx.fsf@assigned-by-dhcp.cox.net","subject":"Re: efficient cloning","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2006-03-21T08:19:33Z","receivedAt":"2006-03-21T08:19:33Z","isPatch":false,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> Petr Baudis <pasky@suse.cz> writes:\n> \n> \n>>I still don't get what's wrong on what I'm proposing. I'm not seeing the\n>>disadvantages, if there are any.\n> \n> \n> The only thing I think there is is that I do not get what you\n> are proposing ;-), since I am not paying full attention while at\n> day-job.\n> \n> If you are proposing to root --use-separate-remote not at\n> refs/remotes but refs/remotes/origin/, I think it makes kind of\n> sense.  It would make tons of sense _if_ dealing more than one\n> remote repository is the norm, but otherwise you would have an\n> extra level of directory refs/remotes which almost always have\n> only one subdirectory 'origin' and nothing else, which is\n> pointless.\n> \n\nafaiu, this is exactly what Pasky's proposing, and I agree. We could \nthen teach 'git diff origin master' to mean 'origin/master' *if* no \nother tag/branch is found in the lookup order. I think it makes sense to \ndo searching like this, for a ref named foo\n\n(current order, with .git/, .git/refs/, etc...)\n.git/refs/remotes/foo\n.git/refs/remotes/foo/master\n\nThat way the only extra dwimery would be to add \"remotes\" after \"heads\" \nunder .git/refs and accept directory in .git/remotes/ as ref and tack on \n'/master' at the end of it as the last option to search. For a specific \nbranch on an imported remote, one would have to say \"jc/next\". This \nmeans we still only handle 'master' specially so we don't introduce any \nnew protected or special names.\n\n\n> I am not sure if you are also advocating to map (somehow) origin\n> to remotes/origin/master (or whatever branch remote's HEAD\n> points at), but if so I am not quite sure what its semantics\n> would be.  Which remote branch would you pick (that would not\n> necessarily be \"master\") and where are you going to record that\n> and when.  It all sounds to me complicating things\n> unnecessarily.\n> \n\nNot too much so, I think. I'll look into it tonight, although I'm not \nvery familiar with the core stuff so possibly (/ hopefully) someone else \nwill beat me to it.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"17730","messageId":"7virq8gq12.fsf@assigned-by-dhcp.cox.net","threadId":"3678","inReplyTo":"200603201730.19373.Josef.Weidendorfer@gmx.de","subject":"Re: efficient cloning","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-21T08:28:41Z","receivedAt":"2006-03-21T08:28:41Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Josef Weidendorfer <Josef.Weidendorfer@gmx.de> writes:\n\n> Shouldn't this be .git/refs/remotes/origin/?\n> Ie. different namespaces for different remotes?\n\nOK, here is a second try, that comes on top of the one from the\nlast night.\n\nTogether with another topic in the \"next\" branch, you can now do\nthis:\n\n $ git clone --use-separate-remote --reference git.git \\\n   git://git.kernel.org/pub/scm/git/git.git new.git\n $ cd new.git\n $ git branch\n * master\n $ git log --pretty=oneline master..origin/next | wc -l\n 72\n\nWhat the last one shows is that sha1_basic() lets you omit\nrefs/remotes; it does not let you say \"origin\" to mean\n\"refs/remotes/origin/master\", although I agree that abbreviation\nwould be useful.  As I am still not yet convinced that using\nwhat is in .git/remotes/origin is a good way to implement that\nshorthand, and would rather avoid reading .git/remotes/origin\nfrom the C level (even though sha1_basic() is not _that_ core\nbut a lot closer to the UI, compared to other C level routines),\nI am leaving that part for later rounds.\n\n-- >8 --\n[PATCH] revamp git-clone (take #2).\n\nThis builds on top of the previous one.\n\n * --use-separate-remote uses .git/refs/remotes/$origin/\n   directory to keep track of the upstream branches.\n\n * The $origin above defaults to \"origin\" as usual, but the\n   existing \"-o $origin\" option can be used to override it.\n\nI am not yet convinced if we should make \"$origin\" the synonym to\n\"refs/remotes/$origin/$name\" where $name is the primary branch\nname of $origin upstream, nor if so how we should decide which\nupstream branch is the primary one, but that is more or less\northogonal to what the clone does here.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n git-clone.sh |   50 +++++++++++++++++++++++++++++++-------------------\n 1 files changed, 31 insertions(+), 19 deletions(-)\n\n47874d6d9a7f49ade6388df049597f03365961ca\ndiff --git a/git-clone.sh b/git-clone.sh\nindex 9db678b..3b54753 100755\n--- a/git-clone.sh\n+++ b/git-clone.sh\n@@ -9,7 +9,7 @@\n unset CDPATH\n \n usage() {\n-\techo >&2 \"Usage: $0 [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]\"\n+\techo >&2 \"Usage: $0 [--use-separate-remote] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]\"\n \texit 1\n }\n \n@@ -61,8 +61,9 @@ use File::Path qw(mkpath);\n use File::Basename qw(dirname);\n my $git_dir = $ARGV[0];\n my $use_separate_remote = $ARGV[1];\n+my $origin = $ARGV[2];\n \n-my $branch_top = ($use_separate_remote ? \"remotes\" : \"heads\");\n+my $branch_top = ($use_separate_remote ? \"remotes/$origin\" : \"heads\");\n my $tag_top = \"tags\";\n \n sub store {\n@@ -127,7 +128,12 @@ while\n \t*,--reference=*)\n \t\treference=`expr \"$1\" : '--reference=\\(.*\\)'` ;;\n \t*,-o)\n-\t\tgit-check-ref-format \"$2\" || {\n+\t\tcase \"$2\" in\n+\t\t*/*)\n+\t\t    echo >&2 \"'$2' is not suitable for an origin name\"\n+\t\t    exit 1\n+\t\tesac\n+\t\tgit-check-ref-format \"heads/$2\" || {\n \t\t    echo >&2 \"'$2' is not suitable for a branch name\"\n \t\t    exit 1\n \t\t}\n@@ -165,14 +171,9 @@ then\n \tno_checkout=yes\n fi\n \n-if test -z \"$origin_override$origin\"\n+if test -z \"$origin\"\n then\n-\tif test -n \"$use_separate_remote\"\n-\tthen\n-\t\torigin=remotes/master\n-\telse\n-\t\torigin=heads/origin\n-\tfi\n+\torigin=origin\n fi\n \n # Turn the source into an absolute path if\n@@ -317,7 +318,7 @@ test -d \"$GIT_DIR/refs/reference-tmp\" &&\n if test -f \"$GIT_DIR/CLONE_HEAD\"\n then\n \t# Figure out where the remote HEAD points at.\n-\tperl -e \"$copy_refs\" \"$GIT_DIR\" \"$use_separate_remote\"\n+\tperl -e \"$copy_refs\" \"$GIT_DIR\" \"$use_separate_remote\" \"$origin\"\n fi\n \n cd \"$D\" || exit\n@@ -328,8 +329,18 @@ then\n \t# Figure out which remote branch HEAD points at.\n \tcase \"$use_separate_remote\" in\n \t'')\tremote_top=refs/heads ;;\n-\t*)\tremote_top=refs/remotes ;;\n+\t*)\tremote_top=\"refs/remotes/$origin\" ;;\n \tesac\n+\n+\t# What to use to track the remote primary branch\n+\tif test -n \"$use_separate_remote\"\n+\tthen\n+\t\torigin_tracking=\"remotes/$origin/master\"\n+\telse\n+\t\torigin_tracking=\"heads/$origin\"\n+\tfi\n+\n+\t# The name under $remote_top the remote HEAD seems to point at\n \thead_points_at=$(\n \t\t(\n \t\t\techo \"master\"\n@@ -349,25 +360,26 @@ then\n \t\tdone\n \t\t)\n \t)\n+\n+\t# Write out remotes/$origin file.\n \tcase \"$head_points_at\" in\n \t?*)\n \t\tmkdir -p \"$GIT_DIR/remotes\" &&\n-\t\techo >\"$GIT_DIR/remotes/origin\" \\\n+\t\techo >\"$GIT_DIR/remotes/$origin\" \\\n \t\t\"URL: $repo\n-Pull: refs/heads/$head_points_at:refs/$origin\" &&\n+Pull: refs/heads/$head_points_at:refs/$origin_tracking\" &&\n \t\tcase \"$use_separate_remote\" in\n \t\tt) git-update-ref HEAD \"$head_sha1\" ;;\n \t\t*) git-update-ref \"refs/$origin\" $(git-rev-parse HEAD)\n \t\tesac &&\n-\t\t(cd \"$GIT_DIR\" && find \"$remote_top\" -type f -print) |\n-\t\twhile read ref\n+\t\t(cd \"$GIT_DIR/$remote_top\" && find . -type f -print) |\n+\t\twhile read dotslref\n \t\tdo\n-\t\t\thead=`expr \"$ref\" : 'refs/\\(.*\\)'` &&\n-\t\t\tname=`expr \"$ref\" : 'refs/[^\\/]*/\\(.*\\)'` &&\n+\t\t\tname=`expr \"$dotslref\" : './\\(.*\\)'` &&\n \t\t\ttest \"$head_points_at\" = \"$name\" ||\n \t\t\ttest \"$origin\" = \"$head\" ||\n \t\t\techo \"Pull: refs/heads/${name}:$remote_top/${name}\"\n-\t\tdone >>\"$GIT_DIR/remotes/origin\"\n+\t\tdone >>\"$GIT_DIR/remotes/$origin\"\n \tesac\n \n \tcase \"$no_checkout\" in\n-- \n1.2.4.ge2fc\n"},{"id":"17731","messageId":"7v4q1sgpet.fsf@assigned-by-dhcp.cox.net","threadId":"3678","inReplyTo":"441FB715.1000500@op5.se","subject":"Re: efficient cloning","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-21T08:42:02Z","receivedAt":"2006-03-21T08:42:02Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andreas Ericsson <ae@op5.se> writes:\n\n> That way the only extra dwimery would be to add \"remotes\" after\n> \"heads\" under .git/refs and accept directory in .git/remotes/ as ref\n> and tack on '/master' at the end of it as the last option to\n> search. For a specific branch on an imported remote, one would have to\n> say \"jc/next\". This means we still only handle 'master' specially so\n> we don't introduce any new protected or special names.\n\nTwo things that holding me back from doing what you suggested\nare (1) \"master\" is just a convention and indeed non-negligible\nnumber of kernel.org trees have \"test\" and \"release\" instead\nwithout \"master\"; (2) I'd really really really want to avoid\nteaching get_sha1_basic() C-level about .git/remotes/$origin\nfile, even though that function is more of a UI level than the\nrest of the really core C-level routines.\n\nBut if I were forced to choose between the above 2, I would\nprobably pick defaulting to \"master\".\n\nThe reason I would like to avoid .git/remotes/$origin is because\nit is designed to be Porcelainish thing.  The underlying C-level\ngit-fetch-pack never sees it; instead the information fed to\nC-level is prepared by the upper layer using that file.  As far\nas I understand, Cogito does not understand it either, except\nthat it ships with bash completion code that reads from\nfilenames there.\n"},{"id":"17732","messageId":"20060321091916.GA17125@coredump.intra.peff.net","threadId":"3678","inReplyTo":"7v4q1sgpet.fsf@assigned-by-dhcp.cox.net","subject":"Re: efficient cloning","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2006-03-21T09:19:16Z","receivedAt":"2006-03-21T09:19:16Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Mar 21, 2006 at 12:42:02AM -0800, Junio C Hamano wrote:\n\n> The reason I would like to avoid .git/remotes/$origin is because\n> it is designed to be Porcelainish thing.  The underlying C-level\n> git-fetch-pack never sees it; instead the information fed to\n> C-level is prepared by the upper layer using that file.  As far\n> as I understand, Cogito does not understand it either, except\n> that it ships with bash completion code that reads from\n> filenames there.\n\nThen why not create .git/refs/remotes/$origin/HEAD at the time of clone\n(or later)? Then the core looks for:\n  (current order, .git/refs, etc)\n  .git/refs/remotes/foo\n  .git/refs/remotes/foo/HEAD\nThe porcelain can take care of managing the contents of HEAD. If there\nis no HEAD in the directory, then it cannot be looked up by 'foo'\n('foo/remote-branch' must be used instead).\n\n-Peff\n"},{"id":"17733","messageId":"7vy7z4f7x3.fsf@assigned-by-dhcp.cox.net","threadId":"3678","inReplyTo":"20060321091916.GA17125@coredump.intra.peff.net","subject":"Re: efficient cloning","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-21T09:45:12Z","receivedAt":"2006-03-21T09:45:12Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Then why not create .git/refs/remotes/$origin/HEAD at the time of clone\n> (or later)? Then the core looks for:\n>   (current order, .git/refs, etc)\n>   .git/refs/remotes/foo\n>   .git/refs/remotes/foo/HEAD\n> The porcelain can take care of managing the contents of HEAD. If there\n> is no HEAD in the directory, then it cannot be looked up by 'foo'\n> ('foo/remote-branch' must be used instead).\n\nYup, earlier I mentioned that possibility, and it does not seem\ntoo painful.  On top of the \"next\", here is what is needed.\n\n-- >8 --\n[PATCH] get_sha1_basic(): try refs/... and finally refs/remotes/$foo/HEAD\n\nThis implements the suggestion by Jeff King to use\nrefs/remotes/$foo/HEAD to interpret a shorthand \"$foo\" to mean\nthe primary branch head of a tracked remote.  clone needs to be\ntold about this convention as well.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n sha1_name.c |   23 ++++++++++++-----------\n 1 files changed, 12 insertions(+), 11 deletions(-)\n\nc51d13692d4e451c755dd7da3521c5db395df192\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 74c479c..3adaec3 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -235,18 +235,21 @@ static int ambiguous_path(const char *pa\n \n static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n {\n-\tstatic const char *prefix[] = {\n-\t\t\"\",\n-\t\t\"refs\",\n-\t\t\"refs/tags\",\n-\t\t\"refs/heads\",\n-\t\t\"refs/remotes\",\n+\tstatic const char *fmt[] = {\n+\t\t\"/%.*s\",\n+\t\t\"refs/%.*s\",\n+\t\t\"refs/tags/%.*s\",\n+\t\t\"refs/heads/%.*s\",\n+\t\t\"refs/remotes/%.*s\",\n+\t\t\"refs/remotes/%.*s/HEAD\",\n \t\tNULL\n \t};\n \tconst char **p;\n \tconst char *warning = \"warning: refname '%.*s' is ambiguous.\\n\";\n \tchar *pathname;\n \tint already_found = 0;\n+\tunsigned char *this_result;\n+\tunsigned char sha1_from_ref[20];\n \n \tif (len == 40 && !get_sha1_hex(str, sha1))\n \t\treturn 0;\n@@ -255,11 +258,9 @@ static int get_sha1_basic(const char *st\n \tif (ambiguous_path(str, len))\n \t\treturn -1;\n \n-\tfor (p = prefix; *p; p++) {\n-\t\tunsigned char sha1_from_ref[20];\n-\t\tunsigned char *this_result =\n-\t\t\talready_found ? sha1_from_ref : sha1;\n-\t\tpathname = git_path(\"%s/%.*s\", *p, len, str);\n+\tfor (p = fmt; *p; p++) {\n+\t\tthis_result = already_found ? sha1_from_ref : sha1;\n+\t\tpathname = git_path(*p, len, str);\n \t\tif (!read_ref(pathname, this_result)) {\n \t\t\tif (warn_ambiguous_refs) {\n \t\t\t\tif (already_found &&\n-- \n1.2.4.gf1250\n"},{"id":"17734","messageId":"20060321112952.GR18185@pasky.or.cz","threadId":"3678","inReplyTo":"7vy7z4f7x3.fsf@assigned-by-dhcp.cox.net","subject":"Re: efficient cloning","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-03-21T11:29:52Z","receivedAt":"2006-03-21T11:29:52Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Tue, Mar 21, 2006 at 10:45:12AM CET, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n> Jeff King <peff@peff.net> writes:\n> \n> > Then why not create .git/refs/remotes/$origin/HEAD at the time of clone\n> > (or later)? Then the core looks for:\n> >   (current order, .git/refs, etc)\n> >   .git/refs/remotes/foo\n> >   .git/refs/remotes/foo/HEAD\n> > The porcelain can take care of managing the contents of HEAD. If there\n> > is no HEAD in the directory, then it cannot be looked up by 'foo'\n> > ('foo/remote-branch' must be used instead).\n> \n> Yup, earlier I mentioned that possibility, and it does not seem\n> too painful.  On top of the \"next\", here is what is needed.\n> \n> -- >8 --\n> [PATCH] get_sha1_basic(): try refs/... and finally refs/remotes/$foo/HEAD\n> \n> This implements the suggestion by Jeff King to use\n> refs/remotes/$foo/HEAD to interpret a shorthand \"$foo\" to mean\n> the primary branch head of a tracked remote.  clone needs to be\n> told about this convention as well.\n> \n> Signed-off-by: Junio C Hamano <junkio@cox.net>\n\nExcellent, yes, that's what I've meant. I'm happy now. :)\n\nThanks,\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nRight now I am having amnesia and deja-vu at the same time.  I think\nI have forgotten this before.\n"}]}