git-parse-remote.shon commit git-svn: add support for --stat in the log command (488a63e)
   1#!/bin/sh
   2
   3# git-ls-remote could be called from outside a git managed repository;
   4# this would fail in that case and would issue an error message.
   5GIT_DIR=$(git-rev-parse --git-dir 2>/dev/null) || :;
   6
   7get_data_source () {
   8        case "$1" in
   9        */*)
  10                echo ''
  11                ;;
  12        *)
  13                if test "$(git-config --get "remote.$1.url")"
  14                then
  15                        echo config
  16                elif test -f "$GIT_DIR/remotes/$1"
  17                then
  18                        echo remotes
  19                elif test -f "$GIT_DIR/branches/$1"
  20                then
  21                        echo branches
  22                else
  23                        echo ''
  24                fi ;;
  25        esac
  26}
  27
  28get_remote_url () {
  29        data_source=$(get_data_source "$1")
  30        case "$data_source" in
  31        '')
  32                echo "$1"
  33                ;;
  34        config)
  35                git-config --get "remote.$1.url"
  36                ;;
  37        remotes)
  38                sed -ne '/^URL: */{
  39                        s///p
  40                        q
  41                }' "$GIT_DIR/remotes/$1"
  42                ;;
  43        branches)
  44                sed -e 's/#.*//' "$GIT_DIR/branches/$1"
  45                ;;
  46        *)
  47                die "internal error: get-remote-url $1" ;;
  48        esac
  49}
  50
  51get_default_remote () {
  52        curr_branch=$(git-symbolic-ref -q HEAD | sed -e 's|^refs/heads/||')
  53        origin=$(git-config --get "branch.$curr_branch.remote")
  54        echo ${origin:-origin}
  55}
  56
  57get_remote_default_refs_for_push () {
  58        data_source=$(get_data_source "$1")
  59        case "$data_source" in
  60        '' | branches)
  61                ;; # no default push mapping, just send matching refs.
  62        config)
  63                git-config --get-all "remote.$1.push" ;;
  64        remotes)
  65                sed -ne '/^Push: */{
  66                        s///p
  67                }' "$GIT_DIR/remotes/$1" ;;
  68        *)
  69                die "internal error: get-remote-default-ref-for-push $1" ;;
  70        esac
  71}
  72
  73# Called from canon_refs_list_for_fetch -d "$remote", which
  74# is called from get_remote_default_refs_for_fetch to grok
  75# refspecs that are retrieved from the configuration, but not
  76# from get_remote_refs_for_fetch when it deals with refspecs
  77# supplied on the command line.  $ls_remote_result has the list
  78# of refs available at remote.
  79#
  80# The first token returned is either "explicit" or "glob"; this
  81# is to help prevent randomly "globbed" ref from being chosen as
  82# a merge candidate
  83expand_refs_wildcard () {
  84        remote="$1"
  85        shift
  86        first_one=yes
  87        if test "$#" = 0
  88        then
  89                echo empty
  90                echo >&2 "Nothing specified for fetching with remote.$remote.fetch"
  91        fi
  92        for ref
  93        do
  94                lref=${ref#'+'}
  95                # a non glob pattern is given back as-is.
  96                expr "z$lref" : 'zrefs/.*/\*:refs/.*/\*$' >/dev/null || {
  97                        if test -n "$first_one"
  98                        then
  99                                echo "explicit"
 100                                first_one=
 101                        fi
 102                        echo "$ref"
 103                        continue
 104                }
 105
 106                # glob
 107                if test -n "$first_one"
 108                then
 109                        echo "glob"
 110                        first_one=
 111                fi
 112                from=`expr "z$lref" : 'z\(refs/.*/\)\*:refs/.*/\*$'`
 113                to=`expr "z$lref" : 'zrefs/.*/\*:\(refs/.*/\)\*$'`
 114                local_force=
 115                test "z$lref" = "z$ref" || local_force='+'
 116                echo "$ls_remote_result" |
 117                sed -e '/\^{}$/d' |
 118                (
 119                        IFS='   '
 120                        while read sha1 name
 121                        do
 122                                # ignore the ones that do not start with $from
 123                                mapped=${name#"$from"}
 124                                test "z$name" = "z$mapped" && continue
 125                                echo "${local_force}${name}:${to}${mapped}"
 126                        done
 127                )
 128        done
 129}
 130
 131# Subroutine to canonicalize remote:local notation.
 132canon_refs_list_for_fetch () {
 133        # If called from get_remote_default_refs_for_fetch
 134        # leave the branches in branch.${curr_branch}.merge alone,
 135        # or the first one otherwise; add prefix . to the rest
 136        # to prevent the secondary branches to be merged by default.
 137        merge_branches=
 138        curr_branch=
 139        if test "$1" = "-d"
 140        then
 141                shift ; remote="$1" ; shift
 142                set $(expand_refs_wildcard "$remote" "$@")
 143                is_explicit="$1"
 144                shift
 145                if test "$remote" = "$(get_default_remote)"
 146                then
 147                        curr_branch=$(git-symbolic-ref -q HEAD | \
 148                            sed -e 's|^refs/heads/||')
 149                        merge_branches=$(git-config \
 150                            --get-all "branch.${curr_branch}.merge")
 151                fi
 152                if test -z "$merge_branches" && test $is_explicit != explicit
 153                then
 154                        merge_branches=..this.will.never.match.any.ref..
 155                fi
 156        fi
 157        for ref
 158        do
 159                force=
 160                case "$ref" in
 161                +*)
 162                        ref=$(expr "z$ref" : 'z+\(.*\)')
 163                        force=+
 164                        ;;
 165                esac
 166                expr "z$ref" : 'z.*:' >/dev/null || ref="${ref}:"
 167                remote=$(expr "z$ref" : 'z\([^:]*\):')
 168                local=$(expr "z$ref" : 'z[^:]*:\(.*\)')
 169                dot_prefix=.
 170                if test -z "$merge_branches"
 171                then
 172                        merge_branches=$remote
 173                        dot_prefix=
 174                else
 175                        for merge_branch in $merge_branches
 176                        do
 177                            [ "$remote" = "$merge_branch" ] &&
 178                            dot_prefix= && break
 179                        done
 180                fi
 181                case "$remote" in
 182                '' | HEAD ) remote=HEAD ;;
 183                refs/heads/* | refs/tags/* | refs/remotes/*) ;;
 184                heads/* | tags/* | remotes/* ) remote="refs/$remote" ;;
 185                *) remote="refs/heads/$remote" ;;
 186                esac
 187                case "$local" in
 188                '') local= ;;
 189                refs/heads/* | refs/tags/* | refs/remotes/*) ;;
 190                heads/* | tags/* | remotes/* ) local="refs/$local" ;;
 191                *) local="refs/heads/$local" ;;
 192                esac
 193
 194                if local_ref_name=$(expr "z$local" : 'zrefs/\(.*\)')
 195                then
 196                   git-check-ref-format "$local_ref_name" ||
 197                   die "* refusing to create funny ref '$local_ref_name' locally"
 198                fi
 199                echo "${dot_prefix}${force}${remote}:${local}"
 200        done
 201}
 202
 203# Returns list of src: (no store), or src:dst (store)
 204get_remote_default_refs_for_fetch () {
 205        data_source=$(get_data_source "$1")
 206        case "$data_source" in
 207        '')
 208                echo "HEAD:" ;;
 209        config)
 210                canon_refs_list_for_fetch -d "$1" \
 211                        $(git-config --get-all "remote.$1.fetch") ;;
 212        branches)
 213                remote_branch=$(sed -ne '/#/s/.*#//p' "$GIT_DIR/branches/$1")
 214                case "$remote_branch" in '') remote_branch=master ;; esac
 215                echo "refs/heads/${remote_branch}:refs/heads/$1"
 216                ;;
 217        remotes)
 218                canon_refs_list_for_fetch -d "$1" $(sed -ne '/^Pull: */{
 219                                                s///p
 220                                        }' "$GIT_DIR/remotes/$1")
 221                ;;
 222        *)
 223                die "internal error: get-remote-default-ref-for-push $1" ;;
 224        esac
 225}
 226
 227get_remote_refs_for_push () {
 228        case "$#" in
 229        0) die "internal error: get-remote-refs-for-push." ;;
 230        1) get_remote_default_refs_for_push "$@" ;;
 231        *) shift; echo "$@" ;;
 232        esac
 233}
 234
 235get_remote_refs_for_fetch () {
 236        case "$#" in
 237        0)
 238            die "internal error: get-remote-refs-for-fetch." ;;
 239        1)
 240            get_remote_default_refs_for_fetch "$@" ;;
 241        *)
 242            shift
 243            tag_just_seen=
 244            for ref
 245            do
 246                if test "$tag_just_seen"
 247                then
 248                    echo "refs/tags/${ref}:refs/tags/${ref}"
 249                    tag_just_seen=
 250                    continue
 251                else
 252                    case "$ref" in
 253                    tag)
 254                        tag_just_seen=yes
 255                        continue
 256                        ;;
 257                    esac
 258                fi
 259                canon_refs_list_for_fetch "$ref"
 260            done
 261            ;;
 262        esac
 263}
 264
 265resolve_alternates () {
 266        # original URL (xxx.git)
 267        top_=`expr "z$1" : 'z\([^:]*:/*[^/]*\)/'`
 268        while read path
 269        do
 270                case "$path" in
 271                \#* | '')
 272                        continue ;;
 273                /*)
 274                        echo "$top_$path/" ;;
 275                ../*)
 276                        # relative -- ugly but seems to work.
 277                        echo "$1/objects/$path/" ;;
 278                *)
 279                        # exit code may not be caught by the reader.
 280                        echo "bad alternate: $path"
 281                        exit 1 ;;
 282                esac
 283        done
 284}
 285
 286get_uploadpack () {
 287        data_source=$(get_data_source "$1")
 288        case "$data_source" in
 289        config)
 290                uplp=$(git-config --get "remote.$1.uploadpack")
 291                echo ${uplp:-git-upload-pack}
 292                ;;
 293        *)
 294                echo "git-upload-pack"
 295                ;;
 296        esac
 297}