git-submodule: remember to checkout after clone
[git] / git-submodule.sh
1 #!/bin/sh
2 #
3 # git-submodules.sh: init, update or list git submodules
4 #
5 # Copyright (c) 2007 Lars Hjemli
6
7 USAGE='[--quiet] [--cached] [status|init|update] [--] [<path>...]'
8 . git-sh-setup
9 require_work_tree
10
11 init=
12 update=
13 status=
14 quiet=
15 cached=
16
17 #
18 # print stuff on stdout unless -q was specified
19 #
20 say()
21 {
22         if test -z "$quiet"
23         then
24                 echo "$@"
25         fi
26 }
27
28
29 #
30 # Clone a submodule
31 #
32 module_clone()
33 {
34         path=$1
35         url=$2
36
37         # If there already is a directory at the submodule path,
38         # expect it to be empty (since that is the default checkout
39         # action) and try to remove it.
40         # Note: if $path is a symlink to a directory the test will
41         # succeed but the rmdir will fail. We might want to fix this.
42         if test -d "$path"
43         then
44                 rmdir "$path" 2>/dev/null ||
45                 die "Directory '$path' exist, but is neither empty nor a git repository"
46         fi
47
48         test -e "$path" &&
49         die "A file already exist at path '$path'"
50
51         git-clone -n "$url" "$path" ||
52         die "Clone of submodule '$path' failed"
53 }
54
55 #
56 # Register submodules in .git/config
57 #
58 # $@ = requested paths (default to all)
59 #
60 modules_init()
61 {
62         git ls-files --stage -- "$@" | grep -e '^160000 ' |
63         while read mode sha1 stage path
64         do
65                 # Skip already registered paths
66                 url=$(git-config submodule."$path".url)
67                 test -z "$url" || continue
68
69                 url=$(GIT_CONFIG=.gitmodules git-config module."$path".url)
70                 test -z "$url" &&
71                 die "No url found for submodule '$path' in .gitmodules"
72
73                 git-config submodule."$path".url "$url" ||
74                 die "Failed to register url for submodule '$path'"
75
76                 say "Submodule '$path' registered with url '$url'"
77         done
78 }
79
80 #
81 # Update each submodule path to correct revision, using clone and checkout as needed
82 #
83 # $@ = requested paths (default to all)
84 #
85 modules_update()
86 {
87         git ls-files --stage -- "$@" | grep -e '^160000 ' |
88         while read mode sha1 stage path
89         do
90                 url=$(git-config submodule."$path".url)
91                 if test -z "$url"
92                 then
93                         # Only mention uninitialized submodules when its
94                         # path have been specified
95                         test "$#" != "0" &&
96                         say "Submodule '$path' not initialized"
97                         continue
98                 fi
99
100                 if ! test -d "$path"/.git
101                 then
102                         module_clone "$path" "$url" || exit
103                         subsha1=
104                 else
105                         subsha1=$(unset GIT_DIR && cd "$path" &&
106                                 git-rev-parse --verify HEAD) ||
107                         die "Unable to find current revision of submodule '$path'"
108                 fi
109
110                 if test "$subsha1" != "$sha1"
111                 then
112                         (unset GIT_DIR && cd "$path" && git-fetch &&
113                                 git-checkout -q "$sha1") ||
114                         die "Unable to checkout '$sha1' in submodule '$path'"
115
116                         say "Submodule '$path': checked out '$sha1'"
117                 fi
118         done
119 }
120
121 #
122 # List all registered submodules, prefixed with:
123 #  - submodule not initialized
124 #  + different revision checked out
125 #
126 # If --cached was specified the revision in the index will be printed
127 # instead of the currently checked out revision.
128 #
129 # $@ = requested paths (default to all)
130 #
131 modules_list()
132 {
133         git ls-files --stage -- "$@" | grep -e '^160000 ' |
134         while read mode sha1 stage path
135         do
136                 if ! test -d "$path"/.git
137                 then
138                         say "-$sha1 $path"
139                         continue;
140                 fi
141                 revname=$(unset GIT_DIR && cd "$path" && git-describe $sha1)
142                 if git diff-files --quiet -- "$path"
143                 then
144                         say " $sha1 $path ($revname)"
145                 else
146                         if test -z "$cached"
147                         then
148                                 sha1=$(unset GIT_DIR && cd "$path" && git-rev-parse --verify HEAD)
149                                 revname=$(unset GIT_DIR && cd "$path" && git-describe $sha1)
150                         fi
151                         say "+$sha1 $path ($revname)"
152                 fi
153         done
154 }
155
156 while case "$#" in 0) break ;; esac
157 do
158         case "$1" in
159         init)
160                 init=1
161                 ;;
162         update)
163                 update=1
164                 ;;
165         status)
166                 status=1
167                 ;;
168         -q|--quiet)
169                 quiet=1
170                 ;;
171         --cached)
172                 cached=1
173                 ;;
174         --)
175                 break
176                 ;;
177         -*)
178                 usage
179                 ;;
180         *)
181                 break
182                 ;;
183         esac
184         shift
185 done
186
187 case "$init,$update,$status,$cached" in
188 1,,,)
189         modules_init "$@"
190         ;;
191 ,1,,)
192         modules_update "$@"
193         ;;
194 ,,*,*)
195         modules_list "$@"
196         ;;
197 *)
198         usage
199         ;;
200 esac