X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=git-clone.sh;h=6fa0daaacf4c677890768037c128d1d5e967a254;hb=1a82e79315ed633f6b0b1fc4076054950c5380d3;hp=4ed861d576bfaefa768f811a59d2ec53d233b5df;hpb=c40610422e1157e71dbc3c1a2f9e19bbe117962f;p=git.git diff --git a/git-clone.sh b/git-clone.sh index 4ed861d5..6fa0daaa 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -9,7 +9,7 @@ unset CDPATH usage() { - echo >&2 "Usage: $0 [--bare] [-l [-s]] [-q] [-u ] [-o ] [-n] []" + echo >&2 "Usage: $0 [--template=] [--use-separate-remote] [--reference ] [--bare] [-l [-s]] [-q] [-u ] [--origin ] [-n] []" exit 1 } @@ -29,7 +29,7 @@ http_fetch () { clone_dumb_http () { # $1 - remote, $2 - local cd "$2" && - clone_tmp='.git/clone-tmp' && + clone_tmp="$GIT_DIR/clone-tmp" && mkdir -p "$clone_tmp" || exit 1 http_fetch "$1/info/refs" "$clone_tmp/refs" || { echo >&2 "Cannot get remote repository information. @@ -38,24 +38,78 @@ Perhaps git-update-server-info needs to be run there?" } while read sha1 refname do - name=`expr "$refname" : 'refs/\(.*\)'` && + name=`expr "z$refname" : 'zrefs/\(.*\)'` && case "$name" in - *^*) ;; - *) - git-http-fetch -v -a -w "$name" "$name" "$1/" || exit 1 + *^*) continue;; esac + if test -n "$use_separate_remote" && + branch_name=`expr "z$name" : 'zheads/\(.*\)'` + then + tname="remotes/$origin/$branch_name" + else + tname=$name + fi + git-http-fetch -v -a -w "$tname" "$name" "$1/" || exit 1 done <"$clone_tmp/refs" rm -fr "$clone_tmp" + http_fetch "$1/HEAD" "$GIT_DIR/REMOTE_HEAD" || + rm -f "$GIT_DIR/REMOTE_HEAD" +} + +# Read git-fetch-pack -k output and store the remote branches. +copy_refs=' +use File::Path qw(mkpath); +use File::Basename qw(dirname); +my $git_dir = $ARGV[0]; +my $use_separate_remote = $ARGV[1]; +my $origin = $ARGV[2]; + +my $branch_top = ($use_separate_remote ? "remotes/$origin" : "heads"); +my $tag_top = "tags"; + +sub store { + my ($sha1, $name, $top) = @_; + $name = "$git_dir/refs/$top/$name"; + mkpath(dirname($name)); + open O, ">", "$name"; + print O "$sha1\n"; + close O; } +open FH, "<", "$git_dir/CLONE_HEAD"; +while () { + my ($sha1, $name) = /^([0-9a-f]{40})\s(.*)$/; + next if ($name =~ /\^\173/); + if ($name eq "HEAD") { + open O, ">", "$git_dir/REMOTE_HEAD"; + print O "$sha1\n"; + close O; + next; + } + if ($name =~ s/^refs\/heads\///) { + store($sha1, $name, $branch_top); + next; + } + if ($name =~ s/^refs\/tags\///) { + store($sha1, $name, $tag_top); + next; + } +} +close FH; +' + quiet= +local=no use_local=no local_shared=no +unset template no_checkout= upload_pack= bare= -origin=origin +reference= +origin= origin_override= +use_separate_remote= while case "$#,$1" in 0,*) break ;; @@ -67,15 +121,33 @@ while *,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local) use_local=yes ;; *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared) local_shared=yes; use_local=yes ;; + 1,--template) usage ;; + *,--template) + shift; template="--template=$1" ;; + *,--template=*) + template="$1" ;; *,-q|*,--quiet) quiet=-q ;; - 1,-o) usage;; - *,-o) - git-check-ref-format "$2" || { + *,--use-separate-remote) + use_separate_remote=t ;; + 1,--reference) usage ;; + *,--reference) + shift; reference="$1" ;; + *,--reference=*) + reference=`expr "$1" : '--reference=\(.*\)'` ;; + *,-o|*,--or|*,--ori|*,--orig|*,--origi|*,--origin) + case "$2" in + '') + usage ;; + */*) + echo >&2 "'$2' is not suitable for an origin name" + exit 1 + esac + git-check-ref-format "heads/$2" || { echo >&2 "'$2' is not suitable for a branch name" exit 1 } test -z "$origin_override" || { - echo >&2 "Do not give more than one -o options." + echo >&2 "Do not give more than one --origin options." exit 1 } origin_override=yes @@ -92,21 +164,36 @@ do shift done +repo="$1" +if test -z "$repo" +then + echo >&2 'you must specify a repository to clone.' + exit 1 +fi + # --bare implies --no-checkout if test yes = "$bare" then if test yes = "$origin_override" then - echo >&2 '--bare and -o $origin options are incompatible.' + echo >&2 '--bare and --origin $origin options are incompatible.' + exit 1 + fi + if test t = "$use_separate_remote" + then + echo >&2 '--bare and --use-separate-remote options are incompatible.' exit 1 fi no_checkout=yes fi +if test -z "$origin" +then + origin=origin +fi + # Turn the source into an absolute path if # it is local -repo="$1" -local=no if base=$(get_repo_base "$repo"); then repo="$base" local=yes @@ -118,17 +205,35 @@ dir="$2" [ -e "$dir" ] && echo "$dir already exists." && usage mkdir -p "$dir" && D=$(cd "$dir" && pwd) && -trap 'err=$?; cd ..; rm -r "$D"; exit $err' exit -case "$bare" in -yes) GIT_DIR="$D" ;; -*) GIT_DIR="$D/.git" ;; -esac && export GIT_DIR && git-init-db || usage +trap 'err=$?; cd ..; rm -r "$D"; exit $err' 0 case "$bare" in yes) GIT_DIR="$D" ;; *) GIT_DIR="$D/.git" ;; -esac +esac && export GIT_DIR && git-init-db ${template+"$template"} || usage + +if test -n "$reference" +then + if test -d "$reference" + then + if test -d "$reference/.git/objects" + then + reference="$reference/.git" + fi + reference=$(cd "$reference" && pwd) + echo "$reference/objects" >"$GIT_DIR/objects/info/alternates" + (cd "$reference" && tar cf - refs) | + (cd "$GIT_DIR/refs" && + mkdir reference-tmp && + cd reference-tmp && + tar xf -) + else + echo >&2 "$reference: not a local directory." && usage + fi +fi + +rm -f "$GIT_DIR/CLONE_HEAD" # We do local magic only when the user tells us to. case "$local,$use_local" in @@ -158,31 +263,17 @@ yes,yes) ;; yes) mkdir -p "$GIT_DIR/objects/info" - { - test -f "$repo/objects/info/alternates" && - cat "$repo/objects/info/alternates"; - echo "$repo/objects" - } >"$GIT_DIR/objects/info/alternates" + echo "$repo/objects" >> "$GIT_DIR/objects/info/alternates" ;; esac - - # Make a duplicate of refs and HEAD pointer - HEAD= - if test -f "$repo/HEAD" - then - HEAD=HEAD - fi - (cd "$repo" && tar cf - refs $HEAD) | - (cd "$GIT_DIR" && tar xf -) || exit 1 + git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" ;; *) case "$repo" in rsync://*) rsync $quiet -av --ignore-existing \ - --exclude info "$repo/objects/" "$GIT_DIR/objects/" && - rsync $quiet -av --ignore-existing \ - --exclude info "$repo/refs/" "$GIT_DIR/refs/" || exit - + --exclude info "$repo/objects/" "$GIT_DIR/objects/" || + exit # Look at objects/info/alternates for rsync -- http will # support it natively and git native ones will do it on the # remote end. Not having that file is not a crime. @@ -205,6 +296,7 @@ yes,yes) done rm -f "$GIT_DIR/TMP_ALT" fi + git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" ;; http://*) if test -z "@@NO_CURL@@" @@ -217,38 +309,102 @@ yes,yes) ;; *) cd "$D" && case "$upload_pack" in - '') git-clone-pack $quiet "$repo" ;; - *) git-clone-pack $quiet "$upload_pack" "$repo" ;; - esac || { - echo >&2 "clone-pack from '$repo' failed." + '') git-fetch-pack --all -k $quiet "$repo" ;; + *) git-fetch-pack --all -k $quiet "$upload_pack" "$repo" ;; + esac >"$GIT_DIR/CLONE_HEAD" || { + echo >&2 "fetch-pack from '$repo' failed." exit 1 } ;; esac ;; esac +test -d "$GIT_DIR/refs/reference-tmp" && rm -fr "$GIT_DIR/refs/reference-tmp" + +if test -f "$GIT_DIR/CLONE_HEAD" +then + # Read git-fetch-pack -k output and store the remote branches. + perl -e "$copy_refs" "$GIT_DIR" "$use_separate_remote" "$origin" +fi cd "$D" || exit -if test -f "$GIT_DIR/HEAD" && test -z "$bare" +if test -z "$bare" && test -f "$GIT_DIR/REMOTE_HEAD" then - head_points_at=`git-symbolic-ref HEAD` + # Figure out which remote branch HEAD points at. + case "$use_separate_remote" in + '') remote_top=refs/heads ;; + *) remote_top="refs/remotes/$origin" ;; + esac + + head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"` + case "$head_sha1" in + 'ref: refs/'*) + # Uh-oh, the remote told us (http transport done against + # new style repository with a symref HEAD). + # Ideally we should skip the guesswork but for now + # opt for minimum change. + head_sha1=`expr "z$head_sha1" : 'zref: refs/heads/\(.*\)'` + head_sha1=`cat "$GIT_DIR/$remote_top/$head_sha1"` + ;; + esac + + # The name under $remote_top the remote HEAD seems to point at. + head_points_at=$( + ( + echo "master" + cd "$GIT_DIR/$remote_top" && + find . -type f -print | sed -e 's/^\.\///' + ) | ( + done=f + while read name + do + test t = $done && continue + branch_tip=`cat "$GIT_DIR/$remote_top/$name"` + if test "$head_sha1" = "$branch_tip" + then + echo "$name" + done=t + fi + done + ) + ) + + # Write out remotes/$origin file, and update our "$head_points_at". case "$head_points_at" in - refs/heads/*) - head_points_at=`expr "$head_points_at" : 'refs/heads/\(.*\)'` + ?*) mkdir -p "$GIT_DIR/remotes" && - echo >"$GIT_DIR/remotes/origin" \ + git-symbolic-ref HEAD "refs/heads/$head_points_at" && + case "$use_separate_remote" in + t) origin_track="$remote_top/$head_points_at" + git-update-ref HEAD "$head_sha1" ;; + *) origin_track="$remote_top/$origin" + git-update-ref "refs/heads/$origin" "$head_sha1" ;; + esac && + echo >"$GIT_DIR/remotes/$origin" \ "URL: $repo -Pull: $head_points_at:$origin" && - git-update-ref "refs/heads/$origin" $(git-rev-parse HEAD) && - (cd "$GIT_DIR" && find "refs/heads" -type f -print) | - while read ref +Pull: refs/heads/$head_points_at:$origin_track" && + (cd "$GIT_DIR/$remote_top" && find . -type f -print) | + while read dotslref do - head=`expr "$ref" : 'refs/heads/\(.*\)'` && - test "$head_points_at" = "$head" || - test "$origin" = "$head" || - echo "Pull: ${head}:${head}" - done >>"$GIT_DIR/remotes/origin" + name=`expr "$dotslref" : './\(.*\)'` + if test "z$head_points_at" = "z$name" + then + continue + fi + if test "$use_separate_remote" = '' && + test "z$origin" = "z$name" + then + continue + fi + echo "Pull: refs/heads/${name}:$remote_top/${name}" + done >>"$GIT_DIR/remotes/$origin" && + case "$use_separate_remote" in + t) + rm -f "refs/remotes/$origin/HEAD" + git-symbolic-ref "refs/remotes/$origin/HEAD" \ + "refs/remotes/$origin/$head_points_at" + esac esac case "$no_checkout" in @@ -256,6 +412,7 @@ Pull: $head_points_at:$origin" && git-read-tree -m -u -v HEAD HEAD esac fi +rm -f "$GIT_DIR/CLONE_HEAD" "$GIT_DIR/REMOTE_HEAD" -trap - exit +trap - 0