git-clone.shon commit ls-files --others --directory: give trailing slash (0907fed)
   1#!/bin/sh
   2#
   3# Copyright (c) 2005, Linus Torvalds
   4# Copyright (c) 2005, Junio C Hamano
   5# 
   6# Clone a repository into a different directory that does not yet exist.
   7
   8# See git-sh-setup why.
   9unset CDPATH
  10
  11usage() {
  12        echo >&2 "Usage: $0 [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]"
  13        exit 1
  14}
  15
  16get_repo_base() {
  17        (cd "$1" && (cd .git ; pwd)) 2> /dev/null
  18}
  19
  20if [ -n "$GIT_SSL_NO_VERIFY" ]; then
  21    curl_extra_args="-k"
  22fi
  23
  24http_fetch () {
  25        # $1 = Remote, $2 = Local
  26        curl -nsfL $curl_extra_args "$1" >"$2"
  27}
  28
  29clone_dumb_http () {
  30        # $1 - remote, $2 - local
  31        cd "$2" &&
  32        clone_tmp='.git/clone-tmp' &&
  33        mkdir -p "$clone_tmp" || exit 1
  34        http_fetch "$1/info/refs" "$clone_tmp/refs" || {
  35                echo >&2 "Cannot get remote repository information.
  36Perhaps git-update-server-info needs to be run there?"
  37                exit 1;
  38        }
  39        while read sha1 refname
  40        do
  41                name=`expr "$refname" : 'refs/\(.*\)'` &&
  42                case "$name" in
  43                *^*)    ;;
  44                *)
  45                        git-http-fetch -v -a -w "$name" "$name" "$1/" || exit 1
  46                esac
  47        done <"$clone_tmp/refs"
  48        rm -fr "$clone_tmp"
  49}
  50
  51quiet=
  52use_local=no
  53local_shared=no
  54no_checkout=
  55upload_pack=
  56origin=origin
  57while
  58        case "$#,$1" in
  59        0,*) break ;;
  60        *,-n) no_checkout=yes ;;
  61        *,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local) use_local=yes ;;
  62        *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared) 
  63          local_shared=yes; use_local=yes ;;
  64        *,-q|*,--quiet) quiet=-q ;;
  65        1,-o) usage;;
  66        *,-o)
  67                git-check-ref-format "$2" || {
  68                    echo >&2 "'$2' is not suitable for a branch name"
  69                    exit 1
  70                }
  71                origin="$2"; shift
  72                ;;
  73        1,-u|1,--upload-pack) usage ;;
  74        *,-u|*,--upload-pack)
  75                shift
  76                upload_pack="--exec=$1" ;;
  77        *,-*) usage ;;
  78        *) break ;;
  79        esac
  80do
  81        shift
  82done
  83
  84# Turn the source into an absolute path if
  85# it is local
  86repo="$1"
  87local=no
  88if base=$(get_repo_base "$repo"); then
  89        repo="$base"
  90        local=yes
  91fi
  92
  93dir="$2"
  94# Try using "humanish" part of source repo if user didn't specify one
  95[ -z "$dir" ] && dir=$(echo "$repo" | sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*/||g')
  96[ -e "$dir" ] && echo "$dir already exists." && usage
  97mkdir -p "$dir" &&
  98D=$(
  99        (cd "$dir" && git-init-db && pwd)
 100) &&
 101test -d "$D" || usage
 102
 103# We do local magic only when the user tells us to.
 104case "$local,$use_local" in
 105yes,yes)
 106        ( cd "$repo/objects" ) || {
 107                echo >&2 "-l flag seen but $repo is not local."
 108                exit 1
 109        }
 110
 111        case "$local_shared" in
 112        no)
 113            # See if we can hardlink and drop "l" if not.
 114            sample_file=$(cd "$repo" && \
 115                          find objects -type f -print | sed -e 1q)
 116
 117            # objects directory should not be empty since we are cloning!
 118            test -f "$repo/$sample_file" || exit
 119
 120            l=
 121            if ln "$repo/$sample_file" "$D/.git/objects/sample" 2>/dev/null
 122            then
 123                    l=l
 124            fi &&
 125            rm -f "$D/.git/objects/sample" &&
 126            cd "$repo" &&
 127            find objects -depth -print | cpio -puamd$l "$D/.git/" || exit 1
 128            ;;
 129        yes)
 130            mkdir -p "$D/.git/objects/info"
 131            {
 132                test -f "$repo/objects/info/alternates" &&
 133                cat "$repo/objects/info/alternates";
 134                echo "$repo/objects"
 135            } >"$D/.git/objects/info/alternates"
 136            ;;
 137        esac
 138
 139        # Make a duplicate of refs and HEAD pointer
 140        HEAD=
 141        if test -f "$repo/HEAD"
 142        then
 143                HEAD=HEAD
 144        fi
 145        (cd "$repo" && tar cf - refs $HEAD) |
 146        (cd "$D/.git" && tar xf -) || exit 1
 147        ;;
 148*)
 149        case "$repo" in
 150        rsync://*)
 151                rsync $quiet -av --ignore-existing  \
 152                        --exclude info "$repo/objects/" "$D/.git/objects/" &&
 153                rsync $quiet -av --ignore-existing  \
 154                        --exclude info "$repo/refs/" "$D/.git/refs/" || exit
 155
 156                # Look at objects/info/alternates for rsync -- http will
 157                # support it natively and git native ones will do it on the
 158                # remote end.  Not having that file is not a crime.
 159                rsync -q "$repo/objects/info/alternates" \
 160                        "$D/.git/TMP_ALT" 2>/dev/null ||
 161                        rm -f "$D/.git/TMP_ALT"
 162                if test -f "$D/.git/TMP_ALT"
 163                then
 164                    ( cd "$D" &&
 165                      . git-parse-remote &&
 166                      resolve_alternates "$repo" <"./.git/TMP_ALT" ) |
 167                    while read alt
 168                    do
 169                        case "$alt" in 'bad alternate: '*) die "$alt";; esac
 170                        case "$quiet" in
 171                        '')     echo >&2 "Getting alternate: $alt" ;;
 172                        esac
 173                        rsync $quiet -av --ignore-existing  \
 174                            --exclude info "$alt" "$D/.git/objects" || exit
 175                    done
 176                    rm -f "$D/.git/TMP_ALT"
 177                fi
 178                ;;
 179        http://*)
 180                clone_dumb_http "$repo" "$D"
 181                ;;
 182        *)
 183                cd "$D" && case "$upload_pack" in
 184                '') git-clone-pack $quiet "$repo" ;;
 185                *) git-clone-pack $quiet "$upload_pack" "$repo" ;;
 186                esac || {
 187                        echo >&2 "clone-pack from '$repo' failed."
 188                        exit 1
 189                }
 190                ;;
 191        esac
 192        ;;
 193esac
 194
 195cd "$D" || exit
 196
 197if test -f ".git/HEAD"
 198then
 199        head_points_at=`git-symbolic-ref HEAD`
 200        case "$head_points_at" in
 201        refs/heads/*)
 202                head_points_at=`expr "$head_points_at" : 'refs/heads/\(.*\)'`
 203                mkdir -p .git/remotes &&
 204                echo >.git/remotes/origin \
 205                "URL: $repo
 206Pull: $head_points_at:$origin" &&
 207                git-update-ref "refs/heads/$origin" $(git-rev-parse HEAD) &&
 208                find .git/refs/heads -type f -print |
 209                while read ref
 210                do
 211                        head=`expr "$ref" : '.git/refs/heads/\(.*\)'` &&
 212                        test "$head_points_at" = "$head" ||
 213                        test "$origin" = "$head" ||
 214                        echo "Pull: ${head}:${head}"
 215                done >>.git/remotes/origin
 216        esac
 217
 218        case "$no_checkout" in
 219        '')
 220                git checkout
 221        esac
 222fi