Code

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