|  | #!/bin/sh | 
|  | # | 
|  | # Copyright (c) 2005, Linus Torvalds | 
|  | # Copyright (c) 2005, Junio C Hamano | 
|  | # | 
|  | # Clone a repository into a different directory that does not yet exist. | 
|  |  | 
|  | # See git-sh-setup why. | 
|  | unset CDPATH | 
|  |  | 
|  | OPTIONS_SPEC="\ | 
|  | git-clone [options] [--] <repo> [<dir>] | 
|  | -- | 
|  | n,no-checkout        don't create a checkout | 
|  | bare                 create a bare repository | 
|  | naked                create a bare repository | 
|  | l,local              to clone from a local repository | 
|  | no-hardlinks         don't use local hardlinks, always copy | 
|  | s,shared             setup as a shared repository | 
|  | template=            path to the template directory | 
|  | q,quiet              be quiet | 
|  | reference=           reference repository | 
|  | o,origin=            use <name> instead of 'origin' to track upstream | 
|  | u,upload-pack=       path to git-upload-pack on the remote | 
|  | depth=               create a shallow clone of that depth | 
|  |  | 
|  | use-separate-remote  compatibility, do not use | 
|  | no-separate-remote   compatibility, do not use" | 
|  |  | 
|  | die() { | 
|  | echo >&2 "$@" | 
|  | exit 1 | 
|  | } | 
|  |  | 
|  | usage() { | 
|  | exec "$0" -h | 
|  | } | 
|  |  | 
|  | eval "$(echo "$OPTIONS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)" | 
|  |  | 
|  | get_repo_base() { | 
|  | ( | 
|  | cd "`/bin/pwd`" && | 
|  | cd "$1" || cd "$1.git" && | 
|  | { | 
|  | cd .git | 
|  | pwd | 
|  | } | 
|  | ) 2>/dev/null | 
|  | } | 
|  |  | 
|  | if [ -n "$GIT_SSL_NO_VERIFY" -o \ | 
|  | "`git config --bool http.sslVerify`" = false ]; then | 
|  | curl_extra_args="-k" | 
|  | fi | 
|  |  | 
|  | http_fetch () { | 
|  | # $1 = Remote, $2 = Local | 
|  | curl -nsfL $curl_extra_args "$1" >"$2" | 
|  | curl_exit_status=$? | 
|  | case $curl_exit_status in | 
|  | 126|127) exit ;; | 
|  | *)	 return $curl_exit_status ;; | 
|  | esac | 
|  | } | 
|  |  | 
|  | clone_dumb_http () { | 
|  | # $1 - remote, $2 - local | 
|  | cd "$2" && | 
|  | clone_tmp="$GIT_DIR/clone-tmp" && | 
|  | mkdir -p "$clone_tmp" || exit 1 | 
|  | if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \ | 
|  | "`git config --bool http.noEPSV`" = true ]; then | 
|  | curl_extra_args="${curl_extra_args} --disable-epsv" | 
|  | fi | 
|  | http_fetch "$1/info/refs" "$clone_tmp/refs" || | 
|  | die "Cannot get remote repository information. | 
|  | Perhaps git-update-server-info needs to be run there?" | 
|  | test "z$quiet" = z && v=-v || v= | 
|  | while read sha1 refname | 
|  | do | 
|  | name=`expr "z$refname" : 'zrefs/\(.*\)'` && | 
|  | case "$name" in | 
|  | *^*)	continue;; | 
|  | esac | 
|  | case "$bare,$name" in | 
|  | yes,* | ,heads/* | ,tags/*) ;; | 
|  | *)	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" "$sha1" "$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" | 
|  | if test -f "$GIT_DIR/REMOTE_HEAD"; then | 
|  | head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"` | 
|  | case "$head_sha1" in | 
|  | 'ref: refs/'*) | 
|  | ;; | 
|  | *) | 
|  | git-http-fetch $v -a "$head_sha1" "$1" || | 
|  | rm -f "$GIT_DIR/REMOTE_HEAD" | 
|  | ;; | 
|  | esac | 
|  | fi | 
|  | } | 
|  |  | 
|  | quiet= | 
|  | local=no | 
|  | use_local_hardlink=yes | 
|  | local_shared=no | 
|  | unset template | 
|  | no_checkout= | 
|  | upload_pack= | 
|  | bare= | 
|  | reference= | 
|  | origin= | 
|  | origin_override= | 
|  | use_separate_remote=t | 
|  | depth= | 
|  | no_progress= | 
|  | local_explicitly_asked_for= | 
|  | test -t 1 || no_progress=--no-progress | 
|  |  | 
|  | while test $# != 0 | 
|  | do | 
|  | case "$1" in | 
|  | -n|--no-checkout) | 
|  | no_checkout=yes ;; | 
|  | --naked|--bare) | 
|  | bare=yes ;; | 
|  | -l|--local) | 
|  | local_explicitly_asked_for=yes | 
|  | use_local_hardlink=yes | 
|  | ;; | 
|  | --no-hardlinks) | 
|  | use_local_hardlink=no ;; | 
|  | -s|--shared) | 
|  | local_shared=yes ;; | 
|  | --template) | 
|  | shift; template="--template=$1" ;; | 
|  | -q|--quiet) | 
|  | quiet=-q ;; | 
|  | --use-separate-remote|--no-separate-remote) | 
|  | die "clones are always made with separate-remote layout" ;; | 
|  | --reference) | 
|  | shift; reference="$1" ;; | 
|  | -o|--origin) | 
|  | shift; | 
|  | case "$1" in | 
|  | '') | 
|  | usage ;; | 
|  | */*) | 
|  | die "'$1' is not suitable for an origin name" | 
|  | esac | 
|  | git check-ref-format "heads/$1" || | 
|  | die "'$1' is not suitable for a branch name" | 
|  | test -z "$origin_override" || | 
|  | die "Do not give more than one --origin options." | 
|  | origin_override=yes | 
|  | origin="$1" | 
|  | ;; | 
|  | -u|--upload-pack) | 
|  | shift | 
|  | upload_pack="--upload-pack=$1" ;; | 
|  | --depth) | 
|  | shift | 
|  | depth="--depth=$1" ;; | 
|  | --) | 
|  | shift | 
|  | break ;; | 
|  | *) | 
|  | usage ;; | 
|  | esac | 
|  | shift | 
|  | done | 
|  |  | 
|  | repo="$1" | 
|  | test -n "$repo" || | 
|  | die 'you must specify a repository to clone.' | 
|  |  | 
|  | # --bare implies --no-checkout and --no-separate-remote | 
|  | if test yes = "$bare" | 
|  | then | 
|  | if test yes = "$origin_override" | 
|  | then | 
|  | die '--bare and --origin $origin options are incompatible.' | 
|  | fi | 
|  | no_checkout=yes | 
|  | use_separate_remote= | 
|  | fi | 
|  |  | 
|  | if test -z "$origin" | 
|  | then | 
|  | origin=origin | 
|  | fi | 
|  |  | 
|  | # Turn the source into an absolute path if | 
|  | # it is local | 
|  | if base=$(get_repo_base "$repo"); then | 
|  | repo="$base" | 
|  | if test -z "$depth" | 
|  | then | 
|  | local=yes | 
|  | fi | 
|  | elif test -f "$repo" | 
|  | then | 
|  | case "$repo" in /*) ;; *) repo="$PWD/$repo" ;; esac | 
|  | fi | 
|  |  | 
|  | # Decide the directory name of the new repository | 
|  | if test -n "$2" | 
|  | then | 
|  | dir="$2" | 
|  | test $# = 2 || die "excess parameter to git-clone" | 
|  | else | 
|  | # Derive one from the repository name | 
|  | # Try using "humanish" part of source repo if user didn't specify one | 
|  | if test -f "$repo" | 
|  | then | 
|  | # Cloning from a bundle | 
|  | dir=$(echo "$repo" | sed -e 's|/*\.bundle$||' -e 's|.*/||g') | 
|  | else | 
|  | dir=$(echo "$repo" | | 
|  | sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g') | 
|  | fi | 
|  | fi | 
|  |  | 
|  | [ -e "$dir" ] && die "destination directory '$dir' already exists." | 
|  | [ yes = "$bare" ] && unset GIT_WORK_TREE | 
|  | [ -n "$GIT_WORK_TREE" ] && [ -e "$GIT_WORK_TREE" ] && | 
|  | die "working tree '$GIT_WORK_TREE' already exists." | 
|  | D= | 
|  | W= | 
|  | cleanup() { | 
|  | test -z "$D" && rm -rf "$dir" | 
|  | test -z "$W" && test -n "$GIT_WORK_TREE" && rm -rf "$GIT_WORK_TREE" | 
|  | cd .. | 
|  | test -n "$D" && rm -rf "$D" | 
|  | test -n "$W" && rm -rf "$W" | 
|  | exit $err | 
|  | } | 
|  | trap 'err=$?; cleanup' 0 | 
|  | mkdir -p "$dir" && D=$(cd "$dir" && pwd) || usage | 
|  | test -n "$GIT_WORK_TREE" && mkdir -p "$GIT_WORK_TREE" && | 
|  | W=$(cd "$GIT_WORK_TREE" && pwd) && GIT_WORK_TREE="$W" && export GIT_WORK_TREE | 
|  | if test yes = "$bare" || test -n "$GIT_WORK_TREE"; then | 
|  | GIT_DIR="$D" | 
|  | else | 
|  | GIT_DIR="$D/.git" | 
|  | fi && | 
|  | export GIT_DIR && | 
|  | GIT_CONFIG="$GIT_DIR/config" git-init $quiet ${template+"$template"} || usage | 
|  |  | 
|  | if test -n "$bare" | 
|  | then | 
|  | GIT_CONFIG="$GIT_DIR/config" git config core.bare true | 
|  | fi | 
|  |  | 
|  | if test -n "$reference" | 
|  | then | 
|  | ref_git= | 
|  | if test -d "$reference" | 
|  | then | 
|  | if test -d "$reference/.git/objects" | 
|  | then | 
|  | ref_git="$reference/.git" | 
|  | elif test -d "$reference/objects" | 
|  | then | 
|  | ref_git="$reference" | 
|  | fi | 
|  | fi | 
|  | if test -n "$ref_git" | 
|  | then | 
|  | ref_git=$(cd "$ref_git" && pwd) | 
|  | echo "$ref_git/objects" >"$GIT_DIR/objects/info/alternates" | 
|  | ( | 
|  | GIT_DIR="$ref_git" git for-each-ref \ | 
|  | --format='%(objectname) %(*objectname)' | 
|  | ) | | 
|  | while read a b | 
|  | do | 
|  | test -z "$a" || | 
|  | git update-ref "refs/reference-tmp/$a" "$a" | 
|  | test -z "$b" || | 
|  | git update-ref "refs/reference-tmp/$b" "$b" | 
|  | done | 
|  | else | 
|  | die "reference repository '$reference' is not a local directory." | 
|  | fi | 
|  | fi | 
|  |  | 
|  | rm -f "$GIT_DIR/CLONE_HEAD" | 
|  |  | 
|  | # We do local magic only when the user tells us to. | 
|  | case "$local" in | 
|  | yes) | 
|  | ( cd "$repo/objects" ) || | 
|  | die "cannot chdir to local '$repo/objects'." | 
|  |  | 
|  | if test "$local_shared" = yes | 
|  | then | 
|  | mkdir -p "$GIT_DIR/objects/info" | 
|  | echo "$repo/objects" >>"$GIT_DIR/objects/info/alternates" | 
|  | else | 
|  | cpio_quiet_flag="" | 
|  | cpio --help 2>&1 | grep -- --quiet >/dev/null && \ | 
|  | cpio_quiet_flag=--quiet | 
|  | l= && | 
|  | if test "$use_local_hardlink" = yes | 
|  | then | 
|  | # See if we can hardlink and drop "l" if not. | 
|  | sample_file=$(cd "$repo" && \ | 
|  | find objects -type f -print | sed -e 1q) | 
|  | # objects directory should not be empty because | 
|  | # we are cloning! | 
|  | test -f "$repo/$sample_file" || | 
|  | die "fatal: cannot clone empty repository" | 
|  | if ln "$repo/$sample_file" "$GIT_DIR/objects/sample" 2>/dev/null | 
|  | then | 
|  | rm -f "$GIT_DIR/objects/sample" | 
|  | l=l | 
|  | elif test -n "$local_explicitly_asked_for" | 
|  | then | 
|  | echo >&2 "Warning: -l asked but cannot hardlink to $repo" | 
|  | fi | 
|  | fi && | 
|  | cd "$repo" && | 
|  | # Create dirs using umask and permissions and destination | 
|  | find objects -type d -print | (cd "$GIT_DIR" && xargs mkdir -p) && | 
|  | # Copy existing 0444 permissions on content | 
|  | find objects ! -type d -print | cpio $cpio_quiet_flag -pumd$l "$GIT_DIR/" || \ | 
|  | exit 1 | 
|  | fi | 
|  | git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1 | 
|  | ;; | 
|  | *) | 
|  | case "$repo" in | 
|  | rsync://*) | 
|  | case "$depth" in | 
|  | "") ;; | 
|  | *) die "shallow over rsync not supported" ;; | 
|  | esac | 
|  | rsync $quiet -av --ignore-existing  \ | 
|  | --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. | 
|  | rsync -q "$repo/objects/info/alternates" \ | 
|  | "$GIT_DIR/TMP_ALT" 2>/dev/null || | 
|  | rm -f "$GIT_DIR/TMP_ALT" | 
|  | if test -f "$GIT_DIR/TMP_ALT" | 
|  | then | 
|  | ( cd "$D" && | 
|  | . git-parse-remote && | 
|  | resolve_alternates "$repo" <"$GIT_DIR/TMP_ALT" ) | | 
|  | while read alt | 
|  | do | 
|  | case "$alt" in 'bad alternate: '*) die "$alt";; esac | 
|  | case "$quiet" in | 
|  | '')	echo >&2 "Getting alternate: $alt" ;; | 
|  | esac | 
|  | rsync $quiet -av --ignore-existing  \ | 
|  | --exclude info "$alt" "$GIT_DIR/objects" || exit | 
|  | done | 
|  | rm -f "$GIT_DIR/TMP_ALT" | 
|  | fi | 
|  | git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1 | 
|  | ;; | 
|  | https://*|http://*|ftp://*) | 
|  | case "$depth" in | 
|  | "") ;; | 
|  | *) die "shallow over http or ftp not supported" ;; | 
|  | esac | 
|  | if test -z "@@NO_CURL@@" | 
|  | then | 
|  | clone_dumb_http "$repo" "$D" | 
|  | else | 
|  | die "http transport not supported, rebuild Git with curl support" | 
|  | fi | 
|  | ;; | 
|  | *) | 
|  | if [ -f "$repo" ] ; then | 
|  | git bundle unbundle "$repo" > "$GIT_DIR/CLONE_HEAD" || | 
|  | die "unbundle from '$repo' failed." | 
|  | else | 
|  | case "$upload_pack" in | 
|  | '') git-fetch-pack --all -k $quiet $depth $no_progress "$repo";; | 
|  | *) git-fetch-pack --all -k \ | 
|  | $quiet "$upload_pack" $depth $no_progress "$repo" ;; | 
|  | esac >"$GIT_DIR/CLONE_HEAD" || | 
|  | die "fetch-pack from '$repo' failed." | 
|  | fi | 
|  | ;; | 
|  | 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. | 
|  | if [ -n "$use_separate_remote" ] | 
|  | then | 
|  | branch_top="remotes/$origin" | 
|  | else | 
|  | branch_top="heads" | 
|  | fi | 
|  | tag_top="tags" | 
|  | while read sha1 name | 
|  | do | 
|  | case "$name" in | 
|  | *'^{}') | 
|  | continue ;; | 
|  | HEAD) | 
|  | destname="REMOTE_HEAD" ;; | 
|  | refs/heads/*) | 
|  | destname="refs/$branch_top/${name#refs/heads/}" ;; | 
|  | refs/tags/*) | 
|  | destname="refs/$tag_top/${name#refs/tags/}" ;; | 
|  | *) | 
|  | continue ;; | 
|  | esac | 
|  | git update-ref -m "clone: from $repo" "$destname" "$sha1" "" | 
|  | done < "$GIT_DIR/CLONE_HEAD" | 
|  | fi | 
|  |  | 
|  | if test -n "$W"; then | 
|  | cd "$W" || exit | 
|  | else | 
|  | cd "$D" || exit | 
|  | fi | 
|  |  | 
|  | if test -z "$bare" | 
|  | then | 
|  | # a non-bare repository is always in separate-remote layout | 
|  | remote_top="refs/remotes/$origin" | 
|  | head_sha1= | 
|  | test ! -r "$GIT_DIR/REMOTE_HEAD" || 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=$( | 
|  | ( | 
|  | test -f "$GIT_DIR/$remote_top/master" && 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 | 
|  | ) | 
|  | ) | 
|  |  | 
|  | # Upstream URL | 
|  | git config remote."$origin".url "$repo" && | 
|  |  | 
|  | # Set up the mappings to track the remote branches. | 
|  | git config remote."$origin".fetch \ | 
|  | "+refs/heads/*:$remote_top/*" '^$' && | 
|  |  | 
|  | # Write out remote.$origin config, and update our "$head_points_at". | 
|  | case "$head_points_at" in | 
|  | ?*) | 
|  | # Local default branch | 
|  | git symbolic-ref HEAD "refs/heads/$head_points_at" && | 
|  |  | 
|  | # Tracking branch for the primary branch at the remote. | 
|  | git update-ref HEAD "$head_sha1" && | 
|  |  | 
|  | rm -f "refs/remotes/$origin/HEAD" | 
|  | git symbolic-ref "refs/remotes/$origin/HEAD" \ | 
|  | "refs/remotes/$origin/$head_points_at" && | 
|  |  | 
|  | git config branch."$head_points_at".remote "$origin" && | 
|  | git config branch."$head_points_at".merge "refs/heads/$head_points_at" | 
|  | ;; | 
|  | '') | 
|  | if test -z "$head_sha1" | 
|  | then | 
|  | # Source had nonexistent ref in HEAD | 
|  | echo >&2 "Warning: Remote HEAD refers to nonexistent ref, unable to checkout." | 
|  | no_checkout=t | 
|  | else | 
|  | # Source had detached HEAD pointing nowhere | 
|  | git update-ref --no-deref HEAD "$head_sha1" && | 
|  | rm -f "refs/remotes/$origin/HEAD" | 
|  | fi | 
|  | ;; | 
|  | esac | 
|  |  | 
|  | case "$no_checkout" in | 
|  | '') | 
|  | test "z$quiet" = z -a "z$no_progress" = z && v=-v || v= | 
|  | git read-tree -m -u $v HEAD HEAD | 
|  | esac | 
|  | fi | 
|  | rm -f "$GIT_DIR/CLONE_HEAD" "$GIT_DIR/REMOTE_HEAD" | 
|  |  | 
|  | trap - 0 |