6c83c52cf422d44fd22b1df4e55da0de5e368581
   1#!/bin/sh
   2#
   3# git-submodules.sh: init, update or list git submodules
   4#
   5# Copyright (c) 2007 Lars Hjemli
   6
   7USAGE='[--quiet] [--cached] [status|init|update] [--] [<path>...]'
   8. git-sh-setup
   9require_work_tree
  10
  11init=
  12update=
  13status=
  14quiet=
  15cached=
  16
  17#
  18# print stuff on stdout unless -q was specified
  19#
  20say()
  21{
  22        if test -z "$quiet"
  23        then
  24                echo "$@"
  25        fi
  26}
  27
  28
  29#
  30# Clone a submodule
  31#
  32module_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#
  60modules_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 submodule."$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#
  85modules_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#
 131modules_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
 156while case "$#" in 0) break ;; esac
 157do
 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
 185done
 186
 187case "$init,$update,$status,$cached" in
 1881,,,)
 189        modules_init "$@"
 190        ;;
 191,1,,)
 192        modules_update "$@"
 193        ;;
 194,,*,*)
 195        modules_list "$@"
 196        ;;
 197*)
 198        usage
 199        ;;
 200esac