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