git-parse-remote.shon commit Documentation: reorder development section, todo's (b684f83)
   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-repo-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-repo-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 HEAD | sed -e 's|^refs/heads/||')
  53        origin=$(git-repo-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-repo-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        first_one=yes
  85        for ref
  86        do
  87                lref=${ref#'+'}
  88                # a non glob pattern is given back as-is.
  89                expr "z$lref" : 'zrefs/.*/\*:refs/.*/\*$' >/dev/null || {
  90                        if test -n "$first_one"
  91                        then
  92                                echo "explicit"
  93                                first_one=
  94                        fi
  95                        echo "$ref"
  96                        continue
  97                }
  98
  99                # glob
 100                if test -n "$first_one"
 101                then
 102                        echo "glob"
 103                        first_one=
 104                fi
 105                from=`expr "z$lref" : 'z\(refs/.*/\)\*:refs/.*/\*$'`
 106                to=`expr "z$lref" : 'zrefs/.*/\*:\(refs/.*/\)\*$'`
 107                local_force=
 108                test "z$lref" = "z$ref" || local_force='+'
 109                echo "$ls_remote_result" |
 110                sed -e '/\^{}$/d' |
 111                (
 112                        IFS='   '
 113                        while read sha1 name
 114                        do
 115                                # ignore the ones that do not start with $from
 116                                mapped=${name#"$from"}
 117                                test "z$name" = "z$mapped" && continue
 118                                echo "${local_force}${name}:${to}${mapped}"
 119                        done
 120                )
 121        done
 122}
 123
 124# Subroutine to canonicalize remote:local notation.
 125canon_refs_list_for_fetch () {
 126        # If called from get_remote_default_refs_for_fetch
 127        # leave the branches in branch.${curr_branch}.merge alone,
 128        # or the first one otherwise; add prefix . to the rest
 129        # to prevent the secondary branches to be merged by default.
 130        merge_branches=
 131        curr_branch=
 132        if test "$1" = "-d"
 133        then
 134                shift ; remote="$1" ; shift
 135                set $(expand_refs_wildcard "$@")
 136                is_explicit="$1"
 137                shift
 138                if test "$remote" = "$(get_default_remote)"
 139                then
 140                        curr_branch=$(git-symbolic-ref HEAD | \
 141                            sed -e 's|^refs/heads/||')
 142                        merge_branches=$(git-repo-config \
 143                            --get-all "branch.${curr_branch}.merge")
 144                fi
 145                if test -z "$merge_branches" && test $is_explicit != explicit
 146                then
 147                        merge_branches=..this.will.never.match.any.ref..
 148                fi
 149        fi
 150        for ref
 151        do
 152                force=
 153                case "$ref" in
 154                +*)
 155                        ref=$(expr "z$ref" : 'z+\(.*\)')
 156                        force=+
 157                        ;;
 158                esac
 159                expr "z$ref" : 'z.*:' >/dev/null || ref="${ref}:"
 160                remote=$(expr "z$ref" : 'z\([^:]*\):')
 161                local=$(expr "z$ref" : 'z[^:]*:\(.*\)')
 162                dot_prefix=.
 163                if test -z "$merge_branches"
 164                then
 165                        merge_branches=$remote
 166                        dot_prefix=
 167                else
 168                        for merge_branch in $merge_branches
 169                        do
 170                            if  test "$remote" = "$merge_branch" ||
 171                                test "$local" = "$merge_branch"
 172                            then
 173                                    dot_prefix=
 174                                    break
 175                            fi
 176                        done
 177                fi
 178                case "$remote" in
 179                '') remote=HEAD ;;
 180                refs/heads/* | refs/tags/* | refs/remotes/*) ;;
 181                heads/* | tags/* | remotes/* ) remote="refs/$remote" ;;
 182                *) remote="refs/heads/$remote" ;;
 183                esac
 184                case "$local" in
 185                '') local= ;;
 186                refs/heads/* | refs/tags/* | refs/remotes/*) ;;
 187                heads/* | tags/* | remotes/* ) local="refs/$local" ;;
 188                *) local="refs/heads/$local" ;;
 189                esac
 190
 191                if local_ref_name=$(expr "z$local" : 'zrefs/\(.*\)')
 192                then
 193                   git-check-ref-format "$local_ref_name" ||
 194                   die "* refusing to create funny ref '$local_ref_name' locally"
 195                fi
 196                echo "${dot_prefix}${force}${remote}:${local}"
 197        done
 198}
 199
 200# Returns list of src: (no store), or src:dst (store)
 201get_remote_default_refs_for_fetch () {
 202        data_source=$(get_data_source "$1")
 203        case "$data_source" in
 204        '')
 205                echo "HEAD:" ;;
 206        config)
 207                canon_refs_list_for_fetch -d "$1" \
 208                        $(git-repo-config --get-all "remote.$1.fetch") ;;
 209        branches)
 210                remote_branch=$(sed -ne '/#/s/.*#//p' "$GIT_DIR/branches/$1")
 211                case "$remote_branch" in '') remote_branch=master ;; esac
 212                echo "refs/heads/${remote_branch}:refs/heads/$1"
 213                ;;
 214        remotes)
 215                canon_refs_list_for_fetch -d "$1" $(sed -ne '/^Pull: */{
 216                                                s///p
 217                                        }' "$GIT_DIR/remotes/$1")
 218                ;;
 219        *)
 220                die "internal error: get-remote-default-ref-for-push $1" ;;
 221        esac
 222}
 223
 224get_remote_refs_for_push () {
 225        case "$#" in
 226        0) die "internal error: get-remote-refs-for-push." ;;
 227        1) get_remote_default_refs_for_push "$@" ;;
 228        *) shift; echo "$@" ;;
 229        esac
 230}
 231
 232get_remote_refs_for_fetch () {
 233        case "$#" in
 234        0)
 235            die "internal error: get-remote-refs-for-fetch." ;;
 236        1)
 237            get_remote_default_refs_for_fetch "$@" ;;
 238        *)
 239            shift
 240            tag_just_seen=
 241            for ref
 242            do
 243                if test "$tag_just_seen"
 244                then
 245                    echo "refs/tags/${ref}:refs/tags/${ref}"
 246                    tag_just_seen=
 247                    continue
 248                else
 249                    case "$ref" in
 250                    tag)
 251                        tag_just_seen=yes
 252                        continue
 253                        ;;
 254                    esac
 255                fi
 256                canon_refs_list_for_fetch "$ref"
 257            done
 258            ;;
 259        esac
 260}
 261
 262resolve_alternates () {
 263        # original URL (xxx.git)
 264        top_=`expr "z$1" : 'z\([^:]*:/*[^/]*\)/'`
 265        while read path
 266        do
 267                case "$path" in
 268                \#* | '')
 269                        continue ;;
 270                /*)
 271                        echo "$top_$path/" ;;
 272                ../*)
 273                        # relative -- ugly but seems to work.
 274                        echo "$1/objects/$path/" ;;
 275                *)
 276                        # exit code may not be caught by the reader.
 277                        echo "bad alternate: $path"
 278                        exit 1 ;;
 279                esac
 280        done
 281}