t4200: use cut instead of sed
[git/peff.git] / git-submodule.sh
blobfb01d94498a6fb496ede44ed61a2298ae3a61ecd
1 #!/bin/sh
3 # git-submodules.sh: add, init, update or list git submodules
5 # Copyright (c) 2007 Lars Hjemli
7 USAGE='[--quiet] [--cached] [add <repo> [-b branch]|status|init|update] [--] [<path>...]'
8 OPTIONS_SPEC=
9 . git-sh-setup
10 require_work_tree
12 command=
13 branch=
14 quiet=
15 cached=
18 # print stuff on stdout unless -q was specified
20 say()
22 if test -z "$quiet"
23 then
24 echo "$@"
28 # NEEDSWORK: identical function exists in get_repo_base in clone.sh
29 get_repo_base() {
31 cd "`/bin/pwd`" &&
32 cd "$1" || cd "$1.git" &&
34 cd .git
35 pwd
37 ) 2>/dev/null
40 # Resolve relative url by appending to parent's url
41 resolve_relative_url ()
43 branch="$(git symbolic-ref HEAD 2>/dev/null)"
44 remote="$(git config branch.${branch#refs/heads/}.remote)"
45 remote="${remote:-origin}"
46 remoteurl="$(git config remote.$remote.url)" ||
47 die "remote ($remote) does not have a url in .git/config"
48 url="$1"
49 while test -n "$url"
51 case "$url" in
52 ../*)
53 url="${url#../}"
54 remoteurl="${remoteurl%/*}"
56 ./*)
57 url="${url#./}"
60 break;;
61 esac
62 done
63 echo "$remoteurl/$url"
67 # Map submodule path to submodule name
69 # $1 = path
71 module_name()
73 # Do we have "submodule.<something>.path = $1" defined in .gitmodules file?
74 name=$(git config --literal-match -f .gitmodules \
75 --get-regexp 'submodule\..*\.path$' "$1" |
76 sed -e 's/submodule\.//' -e 's/\.path.*//')
77 test -z "$name" &&
78 die "No submodule mapping found in .gitmodules for path '$path'"
79 echo "$name"
83 # Clone a submodule
85 # Prior to calling, cmd_update checks that a possibly existing
86 # path is not a git repository.
87 # Likewise, cmd_add checks that path does not exist at all,
88 # since it is the location of a new submodule.
90 module_clone()
92 path=$1
93 url=$2
95 # If there already is a directory at the submodule path,
96 # expect it to be empty (since that is the default checkout
97 # action) and try to remove it.
98 # Note: if $path is a symlink to a directory the test will
99 # succeed but the rmdir will fail. We might want to fix this.
100 if test -d "$path"
101 then
102 rmdir "$path" 2>/dev/null ||
103 die "Directory '$path' exist, but is neither empty nor a git repository"
106 test -e "$path" &&
107 die "A file already exist at path '$path'"
109 git-clone -n "$url" "$path" ||
110 die "Clone of '$url' into submodule path '$path' failed"
114 # Add a new submodule to the working tree, .gitmodules and the index
116 # $@ = repo [path]
118 # optional branch is stored in global branch variable
120 cmd_add()
122 # parse $args after "submodule ... add".
123 while test $# -ne 0
125 case "$1" in
126 -b | --branch)
127 case "$2" in '') usage ;; esac
128 branch=$2
129 shift
131 -q|--quiet)
132 quiet=1
135 shift
136 break
139 usage
142 break
144 esac
145 shift
146 done
148 repo=$1
149 path=$2
151 if test -z "$repo"; then
152 usage
155 # Guess path from repo if not specified or strip trailing slashes
156 if test -z "$path"; then
157 path=$(echo "$repo" | sed -e 's|/*$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g')
158 else
159 path=$(echo "$path" | sed -e 's|/*$||')
162 git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
163 die "'$path' already exists in the index"
165 # perhaps the path exists and is already a git repo, else clone it
166 if test -e "$path"
167 then
168 if test -d "$path/.git" &&
169 test "$(unset GIT_DIR; cd $path; git rev-parse --git-dir)" = ".git"
170 then
171 echo "Adding existing repo at '$path' to the index"
172 else
173 die "'$path' already exists and is not a valid git repo"
175 else
176 case "$repo" in
177 ./*|../*)
178 # dereference source url relative to parent's url
179 realrepo="$(resolve_relative_url $repo)" ;;
181 # Turn the source into an absolute path if
182 # it is local
183 if base=$(get_repo_base "$repo"); then
184 repo="$base"
186 realrepo=$repo
188 esac
190 module_clone "$path" "$realrepo" || exit
191 (unset GIT_DIR; cd "$path" && git checkout -q ${branch:+-b "$branch" "origin/$branch"}) ||
192 die "Unable to checkout submodule '$path'"
195 git add "$path" ||
196 die "Failed to add submodule '$path'"
198 GIT_CONFIG=.gitmodules git config submodule."$path".path "$path" &&
199 GIT_CONFIG=.gitmodules git config submodule."$path".url "$repo" &&
200 git add .gitmodules ||
201 die "Failed to register submodule '$path'"
205 # Register submodules in .git/config
207 # $@ = requested paths (default to all)
209 cmd_init()
211 # parse $args after "submodule ... init".
212 while test $# -ne 0
214 case "$1" in
215 -q|--quiet)
216 quiet=1
219 shift
220 break
223 usage
226 break
228 esac
229 shift
230 done
232 git ls-files --stage -- "$@" | grep '^160000 ' |
233 while read mode sha1 stage path
235 # Skip already registered paths
236 name=$(module_name "$path") || exit
237 url=$(git config submodule."$name".url)
238 test -z "$url" || continue
240 url=$(GIT_CONFIG=.gitmodules git config submodule."$name".url)
241 test -z "$url" &&
242 die "No url found for submodule path '$path' in .gitmodules"
244 # Possibly a url relative to parent
245 case "$url" in
246 ./*|../*)
247 url="$(resolve_relative_url "$url")"
249 esac
251 git config submodule."$name".url "$url" ||
252 die "Failed to register url for submodule path '$path'"
254 say "Submodule '$name' ($url) registered for path '$path'"
255 done
259 # Update each submodule path to correct revision, using clone and checkout as needed
261 # $@ = requested paths (default to all)
263 cmd_update()
265 # parse $args after "submodule ... update".
266 while test $# -ne 0
268 case "$1" in
269 -q|--quiet)
270 quiet=1
273 shift
274 break
277 usage
280 break
282 esac
283 shift
284 done
286 git ls-files --stage -- "$@" | grep '^160000 ' |
287 while read mode sha1 stage path
289 name=$(module_name "$path") || exit
290 url=$(git config submodule."$name".url)
291 if test -z "$url"
292 then
293 # Only mention uninitialized submodules when its
294 # path have been specified
295 test "$#" != "0" &&
296 say "Submodule path '$path' not initialized"
297 continue
300 if ! test -d "$path"/.git
301 then
302 module_clone "$path" "$url" || exit
303 subsha1=
304 else
305 subsha1=$(unset GIT_DIR; cd "$path" &&
306 git rev-parse --verify HEAD) ||
307 die "Unable to find current revision in submodule path '$path'"
310 if test "$subsha1" != "$sha1"
311 then
312 (unset GIT_DIR; cd "$path" && git-fetch &&
313 git-checkout -q "$sha1") ||
314 die "Unable to checkout '$sha1' in submodule path '$path'"
316 say "Submodule path '$path': checked out '$sha1'"
318 done
321 set_name_rev () {
322 revname=$( (
323 unset GIT_DIR
324 cd "$1" && {
325 git describe "$2" 2>/dev/null ||
326 git describe --tags "$2" 2>/dev/null ||
327 git describe --contains --tags "$2"
330 test -z "$revname" || revname=" ($revname)"
334 # List all submodules, prefixed with:
335 # - submodule not initialized
336 # + different revision checked out
338 # If --cached was specified the revision in the index will be printed
339 # instead of the currently checked out revision.
341 # $@ = requested paths (default to all)
343 cmd_status()
345 # parse $args after "submodule ... status".
346 while test $# -ne 0
348 case "$1" in
349 -q|--quiet)
350 quiet=1
352 --cached)
353 cached=1
356 shift
357 break
360 usage
363 break
365 esac
366 shift
367 done
369 git ls-files --stage -- "$@" | grep '^160000 ' |
370 while read mode sha1 stage path
372 name=$(module_name "$path") || exit
373 url=$(git config submodule."$name".url)
374 if test -z "$url" || ! test -d "$path"/.git
375 then
376 say "-$sha1 $path"
377 continue;
379 set_name_rev "$path" "$sha1"
380 if git diff-files --quiet -- "$path"
381 then
382 say " $sha1 $path$revname"
383 else
384 if test -z "$cached"
385 then
386 sha1=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD)
387 set_name_rev "$path" "$sha1"
389 say "+$sha1 $path$revname"
391 done
394 # This loop parses the command line arguments to find the
395 # subcommand name to dispatch. Parsing of the subcommand specific
396 # options are primarily done by the subcommand implementations.
397 # Subcommand specific options such as --branch and --cached are
398 # parsed here as well, for backward compatibility.
400 while test $# != 0 && test -z "$command"
402 case "$1" in
403 add | init | update | status)
404 command=$1
406 -q|--quiet)
407 quiet=1
409 -b|--branch)
410 case "$2" in
412 usage
414 esac
415 branch="$2"; shift
417 --cached)
418 cached=1
421 break
424 usage
427 break
429 esac
430 shift
431 done
433 # No command word defaults to "status"
434 test -n "$command" || command=status
436 # "-b branch" is accepted only by "add"
437 if test -n "$branch" && test "$command" != add
438 then
439 usage
442 # "--cached" is accepted only by "status"
443 if test -n "$cached" && test "$command" != status
444 then
445 usage
448 "cmd_$command" "$@"