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