diff options
Diffstat (limited to 'git-parse-remote.sh')
-rwxr-xr-x | git-parse-remote.sh | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/git-parse-remote.sh b/git-parse-remote.sh new file mode 100755 index 0000000000..5208ee6ce0 --- /dev/null +++ b/git-parse-remote.sh @@ -0,0 +1,297 @@ +#!/bin/sh + +# git-ls-remote could be called from outside a git managed repository; +# this would fail in that case and would issue an error message. +GIT_DIR=$(git-rev-parse --git-dir 2>/dev/null) || :; + +get_data_source () { + case "$1" in + */*) + echo '' + ;; + *) + if test "$(git-config --get "remote.$1.url")" + then + echo config + elif test -f "$GIT_DIR/remotes/$1" + then + echo remotes + elif test -f "$GIT_DIR/branches/$1" + then + echo branches + else + echo '' + fi ;; + esac +} + +get_remote_url () { + data_source=$(get_data_source "$1") + case "$data_source" in + '') + echo "$1" + ;; + config) + git-config --get "remote.$1.url" + ;; + remotes) + sed -ne '/^URL: */{ + s///p + q + }' "$GIT_DIR/remotes/$1" + ;; + branches) + sed -e 's/#.*//' "$GIT_DIR/branches/$1" + ;; + *) + die "internal error: get-remote-url $1" ;; + esac +} + +get_default_remote () { + curr_branch=$(git-symbolic-ref -q HEAD | sed -e 's|^refs/heads/||') + origin=$(git-config --get "branch.$curr_branch.remote") + echo ${origin:-origin} +} + +get_remote_default_refs_for_push () { + data_source=$(get_data_source "$1") + case "$data_source" in + '' | branches) + ;; # no default push mapping, just send matching refs. + config) + git-config --get-all "remote.$1.push" ;; + remotes) + sed -ne '/^Push: */{ + s///p + }' "$GIT_DIR/remotes/$1" ;; + *) + die "internal error: get-remote-default-ref-for-push $1" ;; + esac +} + +# Called from canon_refs_list_for_fetch -d "$remote", which +# is called from get_remote_default_refs_for_fetch to grok +# refspecs that are retrieved from the configuration, but not +# from get_remote_refs_for_fetch when it deals with refspecs +# supplied on the command line. $ls_remote_result has the list +# of refs available at remote. +# +# The first token returned is either "explicit" or "glob"; this +# is to help prevent randomly "globbed" ref from being chosen as +# a merge candidate +expand_refs_wildcard () { + remote="$1" + shift + first_one=yes + if test "$#" = 0 + then + echo empty + echo >&2 "Nothing specified for fetching with remote.$remote.fetch" + fi + for ref + do + lref=${ref#'+'} + # a non glob pattern is given back as-is. + expr "z$lref" : 'zrefs/.*/\*:refs/.*/\*$' >/dev/null || { + if test -n "$first_one" + then + echo "explicit" + first_one= + fi + echo "$ref" + continue + } + + # glob + if test -n "$first_one" + then + echo "glob" + first_one= + fi + from=`expr "z$lref" : 'z\(refs/.*/\)\*:refs/.*/\*$'` + to=`expr "z$lref" : 'zrefs/.*/\*:\(refs/.*/\)\*$'` + local_force= + test "z$lref" = "z$ref" || local_force='+' + echo "$ls_remote_result" | + sed -e '/\^{}$/d' | + ( + IFS=' ' + while read sha1 name + do + # ignore the ones that do not start with $from + mapped=${name#"$from"} + test "z$name" = "z$mapped" && continue + echo "${local_force}${name}:${to}${mapped}" + done + ) + done +} + +# Subroutine to canonicalize remote:local notation. +canon_refs_list_for_fetch () { + # If called from get_remote_default_refs_for_fetch + # leave the branches in branch.${curr_branch}.merge alone, + # or the first one otherwise; add prefix . to the rest + # to prevent the secondary branches to be merged by default. + merge_branches= + curr_branch= + if test "$1" = "-d" + then + shift ; remote="$1" ; shift + set $(expand_refs_wildcard "$remote" "$@") + is_explicit="$1" + shift + if test "$remote" = "$(get_default_remote)" + then + curr_branch=$(git-symbolic-ref -q HEAD | \ + sed -e 's|^refs/heads/||') + merge_branches=$(git-config \ + --get-all "branch.${curr_branch}.merge") + fi + if test -z "$merge_branches" && test $is_explicit != explicit + then + merge_branches=..this.will.never.match.any.ref.. + fi + fi + for ref + do + force= + case "$ref" in + +*) + ref=$(expr "z$ref" : 'z+\(.*\)') + force=+ + ;; + esac + expr "z$ref" : 'z.*:' >/dev/null || ref="${ref}:" + remote=$(expr "z$ref" : 'z\([^:]*\):') + local=$(expr "z$ref" : 'z[^:]*:\(.*\)') + dot_prefix=. + if test -z "$merge_branches" + then + merge_branches=$remote + dot_prefix= + else + for merge_branch in $merge_branches + do + [ "$remote" = "$merge_branch" ] && + dot_prefix= && break + done + fi + case "$remote" in + '' | HEAD ) remote=HEAD ;; + refs/heads/* | refs/tags/* | refs/remotes/*) ;; + heads/* | tags/* | remotes/* ) remote="refs/$remote" ;; + *) remote="refs/heads/$remote" ;; + esac + case "$local" in + '') local= ;; + refs/heads/* | refs/tags/* | refs/remotes/*) ;; + heads/* | tags/* | remotes/* ) local="refs/$local" ;; + *) local="refs/heads/$local" ;; + esac + + if local_ref_name=$(expr "z$local" : 'zrefs/\(.*\)') + then + git-check-ref-format "$local_ref_name" || + die "* refusing to create funny ref '$local_ref_name' locally" + fi + echo "${dot_prefix}${force}${remote}:${local}" + done +} + +# Returns list of src: (no store), or src:dst (store) +get_remote_default_refs_for_fetch () { + data_source=$(get_data_source "$1") + case "$data_source" in + '') + echo "HEAD:" ;; + config) + canon_refs_list_for_fetch -d "$1" \ + $(git-config --get-all "remote.$1.fetch") ;; + branches) + remote_branch=$(sed -ne '/#/s/.*#//p' "$GIT_DIR/branches/$1") + case "$remote_branch" in '') remote_branch=master ;; esac + echo "refs/heads/${remote_branch}:refs/heads/$1" + ;; + remotes) + canon_refs_list_for_fetch -d "$1" $(sed -ne '/^Pull: */{ + s///p + }' "$GIT_DIR/remotes/$1") + ;; + *) + die "internal error: get-remote-default-ref-for-push $1" ;; + esac +} + +get_remote_refs_for_push () { + case "$#" in + 0) die "internal error: get-remote-refs-for-push." ;; + 1) get_remote_default_refs_for_push "$@" ;; + *) shift; echo "$@" ;; + esac +} + +get_remote_refs_for_fetch () { + case "$#" in + 0) + die "internal error: get-remote-refs-for-fetch." ;; + 1) + get_remote_default_refs_for_fetch "$@" ;; + *) + shift + tag_just_seen= + for ref + do + if test "$tag_just_seen" + then + echo "refs/tags/${ref}:refs/tags/${ref}" + tag_just_seen= + continue + else + case "$ref" in + tag) + tag_just_seen=yes + continue + ;; + esac + fi + canon_refs_list_for_fetch "$ref" + done + ;; + esac +} + +resolve_alternates () { + # original URL (xxx.git) + top_=`expr "z$1" : 'z\([^:]*:/*[^/]*\)/'` + while read path + do + case "$path" in + \#* | '') + continue ;; + /*) + echo "$top_$path/" ;; + ../*) + # relative -- ugly but seems to work. + echo "$1/objects/$path/" ;; + *) + # exit code may not be caught by the reader. + echo "bad alternate: $path" + exit 1 ;; + esac + done +} + +get_uploadpack () { + data_source=$(get_data_source "$1") + case "$data_source" in + config) + uplp=$(git-config --get "remote.$1.uploadpack") + echo ${uplp:-git-upload-pack} + ;; + *) + echo "git-upload-pack" + ;; + esac +} |