Code

c501b7eafab96460bce4e48532d6bd05992e9829
[git.git] / git-submodule.sh
1 #!/bin/sh
2 #
3 # git-submodules.sh: add, init, update or list git submodules
4 #
5 # Copyright (c) 2007 Lars Hjemli
7 dashless=$(basename "$0" | sed -e 's/-/ /')
8 USAGE="[--quiet] add [-b branch] [--reference <repository>] [--] <repository> <path>
9    or: $dashless [--quiet] status [--cached] [--] [<path>...]
10    or: $dashless [--quiet] init [--] [<path>...]
11    or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference <repository>] [--merge] [--] [<path>...]
12    or: $dashless [--quiet] summary [--cached] [--summary-limit <n>] [commit] [--] [<path>...]
13    or: $dashless [--quiet] foreach [--recursive] <command>
14    or: $dashless [--quiet] sync [--] [<path>...]"
15 OPTIONS_SPEC=
16 . git-sh-setup
17 . git-parse-remote
18 require_work_tree
20 command=
21 branch=
22 reference=
23 cached=
24 nofetch=
25 update=
26 prefix=
28 # Resolve relative url by appending to parent's url
29 resolve_relative_url ()
30 {
31         remote=$(get_default_remote)
32         remoteurl=$(git config "remote.$remote.url") ||
33                 die "remote ($remote) does not have a url defined in .git/config"
34         url="$1"
35         remoteurl=${remoteurl%/}
36         while test -n "$url"
37         do
38                 case "$url" in
39                 ../*)
40                         url="${url#../}"
41                         remoteurl="${remoteurl%/*}"
42                         ;;
43                 ./*)
44                         url="${url#./}"
45                         ;;
46                 *)
47                         break;;
48                 esac
49         done
50         echo "$remoteurl/${url%/}"
51 }
53 #
54 # Get submodule info for registered submodules
55 # $@ = path to limit submodule list
56 #
57 module_list()
58 {
59         git ls-files --error-unmatch --stage -- "$@" | grep '^160000 '
60 }
62 #
63 # Map submodule path to submodule name
64 #
65 # $1 = path
66 #
67 module_name()
68 {
69         # Do we have "submodule.<something>.path = $1" defined in .gitmodules file?
70         re=$(printf '%s\n' "$1" | sed -e 's/[].[^$\\*]/\\&/g')
71         name=$( git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
72                 sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
73        test -z "$name" &&
74        die "No submodule mapping found in .gitmodules for path '$path'"
75        echo "$name"
76 }
78 #
79 # Clone a submodule
80 #
81 # Prior to calling, cmd_update checks that a possibly existing
82 # path is not a git repository.
83 # Likewise, cmd_add checks that path does not exist at all,
84 # since it is the location of a new submodule.
85 #
86 module_clone()
87 {
88         path=$1
89         url=$2
90         reference="$3"
92         # If there already is a directory at the submodule path,
93         # expect it to be empty (since that is the default checkout
94         # action) and try to remove it.
95         # Note: if $path is a symlink to a directory the test will
96         # succeed but the rmdir will fail. We might want to fix this.
97         if test -d "$path"
98         then
99                 rmdir "$path" 2>/dev/null ||
100                 die "Directory '$path' exist, but is neither empty nor a git repository"
101         fi
103         test -e "$path" &&
104         die "A file already exist at path '$path'"
106         if test -n "$reference"
107         then
108                 git-clone "$reference" -n "$url" "$path"
109         else
110                 git-clone -n "$url" "$path"
111         fi ||
112         die "Clone of '$url' into submodule path '$path' failed"
116 # Add a new submodule to the working tree, .gitmodules and the index
118 # $@ = repo path
120 # optional branch is stored in global branch variable
122 cmd_add()
124         # parse $args after "submodule ... add".
125         while test $# -ne 0
126         do
127                 case "$1" in
128                 -b | --branch)
129                         case "$2" in '') usage ;; esac
130                         branch=$2
131                         shift
132                         ;;
133                 -q|--quiet)
134                         GIT_QUIET=1
135                         ;;
136                 --reference)
137                         case "$2" in '') usage ;; esac
138                         reference="--reference=$2"
139                         shift
140                         ;;
141                 --reference=*)
142                         reference="$1"
143                         shift
144                         ;;
145                 --)
146                         shift
147                         break
148                         ;;
149                 -*)
150                         usage
151                         ;;
152                 *)
153                         break
154                         ;;
155                 esac
156                 shift
157         done
159         repo=$1
160         path=$2
162         if test -z "$repo" -o -z "$path"; then
163                 usage
164         fi
166         # assure repo is absolute or relative to parent
167         case "$repo" in
168         ./*|../*)
169                 # dereference source url relative to parent's url
170                 realrepo=$(resolve_relative_url "$repo") || exit
171                 ;;
172         *:*|/*)
173                 # absolute url
174                 realrepo=$repo
175                 ;;
176         *)
177                 die "repo URL: '$repo' must be absolute or begin with ./|../"
178         ;;
179         esac
181         # normalize path:
182         # multiple //; leading ./; /./; /../; trailing /
183         path=$(printf '%s/\n' "$path" |
184                 sed -e '
185                         s|//*|/|g
186                         s|^\(\./\)*||
187                         s|/\./|/|g
188                         :start
189                         s|\([^/]*\)/\.\./||
190                         tstart
191                         s|/*$||
192                 ')
193         git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
194         die "'$path' already exists in the index"
196         # perhaps the path exists and is already a git repo, else clone it
197         if test -e "$path"
198         then
199                 if test -d "$path"/.git -o -f "$path"/.git
200                 then
201                         echo "Adding existing repo at '$path' to the index"
202                 else
203                         die "'$path' already exists and is not a valid git repo"
204                 fi
206                 case "$repo" in
207                 ./*|../*)
208                         url=$(resolve_relative_url "$repo") || exit
209                     ;;
210                 *)
211                         url="$repo"
212                         ;;
213                 esac
214                 git config submodule."$path".url "$url"
215         else
217                 module_clone "$path" "$realrepo" "$reference" || exit
218                 (
219                         unset GIT_DIR
220                         cd "$path" &&
221                         # ash fails to wordsplit ${branch:+-b "$branch"...}
222                         case "$branch" in
223                         '') git checkout -f -q ;;
224                         ?*) git checkout -f -q -b "$branch" "origin/$branch" ;;
225                         esac
226                 ) || die "Unable to checkout submodule '$path'"
227         fi
229         git add "$path" ||
230         die "Failed to add submodule '$path'"
232         git config -f .gitmodules submodule."$path".path "$path" &&
233         git config -f .gitmodules submodule."$path".url "$repo" &&
234         git add .gitmodules ||
235         die "Failed to register submodule '$path'"
239 # Execute an arbitrary command sequence in each checked out
240 # submodule
242 # $@ = command to execute
244 cmd_foreach()
246         # parse $args after "submodule ... foreach".
247         while test $# -ne 0
248         do
249                 case "$1" in
250                 -q|--quiet)
251                         GIT_QUIET=1
252                         ;;
253                 --recursive)
254                         recursive=1
255                         ;;
256                 -*)
257                         usage
258                         ;;
259                 *)
260                         break
261                         ;;
262                 esac
263                 shift
264         done
266         module_list |
267         while read mode sha1 stage path
268         do
269                 if test -e "$path"/.git
270                 then
271                         say "Entering '$prefix$path'"
272                         name=$(module_name "$path")
273                         (
274                                 prefix="$prefix$path/"
275                                 unset GIT_DIR
276                                 cd "$path" &&
277                                 eval "$@" &&
278                                 if test -n "$recursive"
279                                 then
280                                         cmd_foreach "--recursive" "$@"
281                                 fi
282                         ) ||
283                         die "Stopping at '$path'; script returned non-zero status."
284                 fi
285         done
289 # Register submodules in .git/config
291 # $@ = requested paths (default to all)
293 cmd_init()
295         # parse $args after "submodule ... init".
296         while test $# -ne 0
297         do
298                 case "$1" in
299                 -q|--quiet)
300                         GIT_QUIET=1
301                         ;;
302                 --)
303                         shift
304                         break
305                         ;;
306                 -*)
307                         usage
308                         ;;
309                 *)
310                         break
311                         ;;
312                 esac
313                 shift
314         done
316         module_list "$@" |
317         while read mode sha1 stage path
318         do
319                 # Skip already registered paths
320                 name=$(module_name "$path") || exit
321                 url=$(git config submodule."$name".url)
322                 test -z "$url" || continue
324                 url=$(git config -f .gitmodules submodule."$name".url)
325                 test -z "$url" &&
326                 die "No url found for submodule path '$path' in .gitmodules"
328                 # Possibly a url relative to parent
329                 case "$url" in
330                 ./*|../*)
331                         url=$(resolve_relative_url "$url") || exit
332                         ;;
333                 esac
335                 git config submodule."$name".url "$url" ||
336                 die "Failed to register url for submodule path '$path'"
338                 upd="$(git config -f .gitmodules submodule."$name".update)"
339                 test -z "$upd" ||
340                 git config submodule."$name".update "$upd" ||
341                 die "Failed to register update mode for submodule path '$path'"
343                 say "Submodule '$name' ($url) registered for path '$path'"
344         done
348 # Update each submodule path to correct revision, using clone and checkout as needed
350 # $@ = requested paths (default to all)
352 cmd_update()
354         # parse $args after "submodule ... update".
355         while test $# -ne 0
356         do
357                 case "$1" in
358                 -q|--quiet)
359                         shift
360                         GIT_QUIET=1
361                         ;;
362                 -i|--init)
363                         init=1
364                         shift
365                         ;;
366                 -N|--no-fetch)
367                         shift
368                         nofetch=1
369                         ;;
370                 -r|--rebase)
371                         shift
372                         update="rebase"
373                         ;;
374                 --reference)
375                         case "$2" in '') usage ;; esac
376                         reference="--reference=$2"
377                         shift 2
378                         ;;
379                 --reference=*)
380                         reference="$1"
381                         shift
382                         ;;
383                 -m|--merge)
384                         shift
385                         update="merge"
386                         ;;
387                 --)
388                         shift
389                         break
390                         ;;
391                 -*)
392                         usage
393                         ;;
394                 *)
395                         break
396                         ;;
397                 esac
398         done
400         if test -n "$init"
401         then
402                 cmd_init "--" "$@" || return
403         fi
405         module_list "$@" |
406         while read mode sha1 stage path
407         do
408                 name=$(module_name "$path") || exit
409                 url=$(git config submodule."$name".url)
410                 update_module=$(git config submodule."$name".update)
411                 if test -z "$url"
412                 then
413                         # Only mention uninitialized submodules when its
414                         # path have been specified
415                         test "$#" != "0" &&
416                         say "Submodule path '$path' not initialized" &&
417                         say "Maybe you want to use 'update --init'?"
418                         continue
419                 fi
421                 if ! test -d "$path"/.git -o -f "$path"/.git
422                 then
423                         module_clone "$path" "$url" "$reference"|| exit
424                         subsha1=
425                 else
426                         subsha1=$(unset GIT_DIR; cd "$path" &&
427                                 git rev-parse --verify HEAD) ||
428                         die "Unable to find current revision in submodule path '$path'"
429                 fi
431                 if ! test -z "$update"
432                 then
433                         update_module=$update
434                 fi
436                 if test "$subsha1" != "$sha1"
437                 then
438                         force=
439                         if test -z "$subsha1"
440                         then
441                                 force="-f"
442                         fi
444                         if test -z "$nofetch"
445                         then
446                                 (unset GIT_DIR; cd "$path" &&
447                                         git-fetch) ||
448                                 die "Unable to fetch in submodule path '$path'"
449                         fi
451                         case "$update_module" in
452                         rebase)
453                                 command="git rebase"
454                                 action="rebase"
455                                 msg="rebased onto"
456                                 ;;
457                         merge)
458                                 command="git merge"
459                                 action="merge"
460                                 msg="merged in"
461                                 ;;
462                         *)
463                                 command="git checkout $force -q"
464                                 action="checkout"
465                                 msg="checked out"
466                                 ;;
467                         esac
469                         (unset GIT_DIR; cd "$path" && $command "$sha1") ||
470                         die "Unable to $action '$sha1' in submodule path '$path'"
471                         say "Submodule path '$path': $msg '$sha1'"
472                 fi
473         done
476 set_name_rev () {
477         revname=$( (
478                 unset GIT_DIR
479                 cd "$1" && {
480                         git describe "$2" 2>/dev/null ||
481                         git describe --tags "$2" 2>/dev/null ||
482                         git describe --contains "$2" 2>/dev/null ||
483                         git describe --all --always "$2"
484                 }
485         ) )
486         test -z "$revname" || revname=" ($revname)"
489 # Show commit summary for submodules in index or working tree
491 # If '--cached' is given, show summary between index and given commit,
492 # or between working tree and given commit
494 # $@ = [commit (default 'HEAD'),] requested paths (default all)
496 cmd_summary() {
497         summary_limit=-1
498         for_status=
500         # parse $args after "submodule ... summary".
501         while test $# -ne 0
502         do
503                 case "$1" in
504                 --cached)
505                         cached="$1"
506                         ;;
507                 --for-status)
508                         for_status="$1"
509                         ;;
510                 -n|--summary-limit)
511                         if summary_limit=$(($2 + 0)) 2>/dev/null && test "$summary_limit" = "$2"
512                         then
513                                 :
514                         else
515                                 usage
516                         fi
517                         shift
518                         ;;
519                 --)
520                         shift
521                         break
522                         ;;
523                 -*)
524                         usage
525                         ;;
526                 *)
527                         break
528                         ;;
529                 esac
530                 shift
531         done
533         test $summary_limit = 0 && return
535         if rev=$(git rev-parse -q --verify "$1^0")
536         then
537                 head=$rev
538                 shift
539         else
540                 head=HEAD
541         fi
543         cd_to_toplevel
544         # Get modified modules cared by user
545         modules=$(git diff-index $cached --raw $head -- "$@" |
546                 egrep '^:([0-7]* )?160000' |
547                 while read mod_src mod_dst sha1_src sha1_dst status name
548                 do
549                         # Always show modules deleted or type-changed (blob<->module)
550                         test $status = D -o $status = T && echo "$name" && continue
551                         # Also show added or modified modules which are checked out
552                         GIT_DIR="$name/.git" git-rev-parse --git-dir >/dev/null 2>&1 &&
553                         echo "$name"
554                 done
555         )
557         test -z "$modules" && return
559         git diff-index $cached --raw $head -- $modules |
560         egrep '^:([0-7]* )?160000' |
561         cut -c2- |
562         while read mod_src mod_dst sha1_src sha1_dst status name
563         do
564                 if test -z "$cached" &&
565                         test $sha1_dst = 0000000000000000000000000000000000000000
566                 then
567                         case "$mod_dst" in
568                         160000)
569                                 sha1_dst=$(GIT_DIR="$name/.git" git rev-parse HEAD)
570                                 ;;
571                         100644 | 100755 | 120000)
572                                 sha1_dst=$(git hash-object $name)
573                                 ;;
574                         000000)
575                                 ;; # removed
576                         *)
577                                 # unexpected type
578                                 echo >&2 "unexpected mode $mod_dst"
579                                 continue ;;
580                         esac
581                 fi
582                 missing_src=
583                 missing_dst=
585                 test $mod_src = 160000 &&
586                 ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_src^0 >/dev/null &&
587                 missing_src=t
589                 test $mod_dst = 160000 &&
590                 ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_dst^0 >/dev/null &&
591                 missing_dst=t
593                 total_commits=
594                 case "$missing_src,$missing_dst" in
595                 t,)
596                         errmsg="  Warn: $name doesn't contain commit $sha1_src"
597                         ;;
598                 ,t)
599                         errmsg="  Warn: $name doesn't contain commit $sha1_dst"
600                         ;;
601                 t,t)
602                         errmsg="  Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
603                         ;;
604                 *)
605                         errmsg=
606                         total_commits=$(
607                         if test $mod_src = 160000 -a $mod_dst = 160000
608                         then
609                                 range="$sha1_src...$sha1_dst"
610                         elif test $mod_src = 160000
611                         then
612                                 range=$sha1_src
613                         else
614                                 range=$sha1_dst
615                         fi
616                         GIT_DIR="$name/.git" \
617                         git log --pretty=oneline --first-parent $range | wc -l
618                         )
619                         total_commits=" ($(($total_commits + 0)))"
620                         ;;
621                 esac
623                 sha1_abbr_src=$(echo $sha1_src | cut -c1-7)
624                 sha1_abbr_dst=$(echo $sha1_dst | cut -c1-7)
625                 if test $status = T
626                 then
627                         if test $mod_dst = 160000
628                         then
629                                 echo "* $name $sha1_abbr_src(blob)->$sha1_abbr_dst(submodule)$total_commits:"
630                         else
631                                 echo "* $name $sha1_abbr_src(submodule)->$sha1_abbr_dst(blob)$total_commits:"
632                         fi
633                 else
634                         echo "* $name $sha1_abbr_src...$sha1_abbr_dst$total_commits:"
635                 fi
636                 if test -n "$errmsg"
637                 then
638                         # Don't give error msg for modification whose dst is not submodule
639                         # i.e. deleted or changed to blob
640                         test $mod_dst = 160000 && echo "$errmsg"
641                 else
642                         if test $mod_src = 160000 -a $mod_dst = 160000
643                         then
644                                 limit=
645                                 test $summary_limit -gt 0 && limit="-$summary_limit"
646                                 GIT_DIR="$name/.git" \
647                                 git log $limit --pretty='format:  %m %s' \
648                                 --first-parent $sha1_src...$sha1_dst
649                         elif test $mod_dst = 160000
650                         then
651                                 GIT_DIR="$name/.git" \
652                                 git log --pretty='format:  > %s' -1 $sha1_dst
653                         else
654                                 GIT_DIR="$name/.git" \
655                                 git log --pretty='format:  < %s' -1 $sha1_src
656                         fi
657                         echo
658                 fi
659                 echo
660         done |
661         if test -n "$for_status"; then
662                 echo "# Modified submodules:"
663                 echo "#"
664                 sed -e 's|^|# |' -e 's|^# $|#|'
665         else
666                 cat
667         fi
670 # List all submodules, prefixed with:
671 #  - submodule not initialized
672 #  + different revision checked out
674 # If --cached was specified the revision in the index will be printed
675 # instead of the currently checked out revision.
677 # $@ = requested paths (default to all)
679 cmd_status()
681         # parse $args after "submodule ... status".
682         while test $# -ne 0
683         do
684                 case "$1" in
685                 -q|--quiet)
686                         GIT_QUIET=1
687                         ;;
688                 --cached)
689                         cached=1
690                         ;;
691                 --)
692                         shift
693                         break
694                         ;;
695                 -*)
696                         usage
697                         ;;
698                 *)
699                         break
700                         ;;
701                 esac
702                 shift
703         done
705         module_list "$@" |
706         while read mode sha1 stage path
707         do
708                 name=$(module_name "$path") || exit
709                 url=$(git config submodule."$name".url)
710                 if test -z "$url" || ! test -d "$path"/.git -o -f "$path"/.git
711                 then
712                         say "-$sha1 $path"
713                         continue;
714                 fi
715                 set_name_rev "$path" "$sha1"
716                 if git diff-files --quiet -- "$path"
717                 then
718                         say " $sha1 $path$revname"
719                 else
720                         if test -z "$cached"
721                         then
722                                 sha1=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD)
723                                 set_name_rev "$path" "$sha1"
724                         fi
725                         say "+$sha1 $path$revname"
726                 fi
727         done
730 # Sync remote urls for submodules
731 # This makes the value for remote.$remote.url match the value
732 # specified in .gitmodules.
734 cmd_sync()
736         while test $# -ne 0
737         do
738                 case "$1" in
739                 -q|--quiet)
740                         GIT_QUIET=1
741                         shift
742                         ;;
743                 --)
744                         shift
745                         break
746                         ;;
747                 -*)
748                         usage
749                         ;;
750                 *)
751                         break
752                         ;;
753                 esac
754         done
755         cd_to_toplevel
756         module_list "$@" |
757         while read mode sha1 stage path
758         do
759                 name=$(module_name "$path")
760                 url=$(git config -f .gitmodules --get submodule."$name".url)
762                 # Possibly a url relative to parent
763                 case "$url" in
764                 ./*|../*)
765                         url=$(resolve_relative_url "$url") || exit
766                         ;;
767                 esac
769                 if test -e "$path"/.git
770                 then
771                 (
772                         unset GIT_DIR
773                         cd "$path"
774                         remote=$(get_default_remote)
775                         say "Synchronizing submodule url for '$name'"
776                         git config remote."$remote".url "$url"
777                 )
778                 fi
779         done
782 # This loop parses the command line arguments to find the
783 # subcommand name to dispatch.  Parsing of the subcommand specific
784 # options are primarily done by the subcommand implementations.
785 # Subcommand specific options such as --branch and --cached are
786 # parsed here as well, for backward compatibility.
788 while test $# != 0 && test -z "$command"
789 do
790         case "$1" in
791         add | foreach | init | update | status | summary | sync)
792                 command=$1
793                 ;;
794         -q|--quiet)
795                 GIT_QUIET=1
796                 ;;
797         -b|--branch)
798                 case "$2" in
799                 '')
800                         usage
801                         ;;
802                 esac
803                 branch="$2"; shift
804                 ;;
805         --cached)
806                 cached="$1"
807                 ;;
808         --)
809                 break
810                 ;;
811         -*)
812                 usage
813                 ;;
814         *)
815                 break
816                 ;;
817         esac
818         shift
819 done
821 # No command word defaults to "status"
822 test -n "$command" || command=status
824 # "-b branch" is accepted only by "add"
825 if test -n "$branch" && test "$command" != add
826 then
827         usage
828 fi
830 # "--cached" is accepted only by "status" and "summary"
831 if test -n "$cached" && test "$command" != status -a "$command" != summary
832 then
833         usage
834 fi
836 "cmd_$command" "$@"