git-submodule.shon commit filter-branch: subdirectory filter needs --full-history (cfabd6e)
   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# Run clone + checkout on missing submodules
  30#
  31# $@ = requested paths (default to all)
  32#
  33modules_init()
  34{
  35        git ls-files --stage -- "$@" | grep -e '^160000 ' |
  36        while read mode sha1 stage path
  37        do
  38                # Skip submodule paths that already contain a .git directory.
  39                # This will also trigger if $path is a symlink to a git
  40                # repository
  41                test -d "$path"/.git && continue
  42
  43                # If there already is a directory at the submodule path,
  44                # expect it to be empty (since that is the default checkout
  45                # action) and try to remove it.
  46                # Note: if $path is a symlink to a directory the test will
  47                # succeed but the rmdir will fail. We might want to fix this.
  48                if test -d "$path"
  49                then
  50                        rmdir "$path" 2>/dev/null ||
  51                        die "Directory '$path' exist, but is neither empty nor a git repository"
  52                fi
  53
  54                test -e "$path" &&
  55                die "A file already exist at path '$path'"
  56
  57                url=$(GIT_CONFIG=.gitmodules git-config module."$path".url)
  58                test -z "$url" &&
  59                die "No url found for submodule '$path' in .gitmodules"
  60
  61                # MAYBE FIXME: this would be the place to check GIT_CONFIG
  62                # for a preferred url for this submodule, possibly like this:
  63                #
  64                # modname=$(GIT_CONFIG=.gitmodules git-config module."$path".name)
  65                # alturl=$(git-config module."$modname".url)
  66                #
  67                # This would let the versioned .gitmodules file use the submodule
  68                # path as key, while the unversioned GIT_CONFIG would use the
  69                # logical modulename (if present) as key. But this would need
  70                # another fallback mechanism if the module wasn't named.
  71
  72                git-clone -n "$url" "$path" ||
  73                die "Clone of submodule '$path' failed"
  74
  75                (unset GIT_DIR && cd "$path" && git-checkout -q "$sha1") ||
  76                die "Checkout of submodule '$path' failed"
  77
  78                say "Submodule '$path' initialized"
  79        done
  80}
  81
  82#
  83# Checkout correct revision of each initialized submodule
  84#
  85# $@ = requested paths (default to all)
  86#
  87modules_update()
  88{
  89        git ls-files --stage -- "$@" | grep -e '^160000 ' |
  90        while read mode sha1 stage path
  91        do
  92                if ! test -d "$path"/.git
  93                then
  94                        # Only mention uninitialized submodules when its
  95                        # path have been specified
  96                        test "$#" != "0" &&
  97                        say "Submodule '$path' not initialized"
  98                        continue;
  99                fi
 100                subsha1=$(unset GIT_DIR && cd "$path" &&
 101                        git-rev-parse --verify HEAD) ||
 102                die "Unable to find current revision of submodule '$path'"
 103
 104                if test "$subsha1" != "$sha1"
 105                then
 106                        (unset GIT_DIR && cd "$path" && git-fetch &&
 107                                git-checkout -q "$sha1") ||
 108                        die "Unable to checkout '$sha1' in submodule '$path'"
 109
 110                        say "Submodule '$path': checked out '$sha1'"
 111                fi
 112        done
 113}
 114
 115#
 116# List all registered submodules, prefixed with:
 117#  - submodule not initialized
 118#  + different revision checked out
 119#
 120# If --cached was specified the revision in the index will be printed
 121# instead of the currently checked out revision.
 122#
 123# $@ = requested paths (default to all)
 124#
 125modules_list()
 126{
 127        git ls-files --stage -- "$@" | grep -e '^160000 ' |
 128        while read mode sha1 stage path
 129        do
 130                if ! test -d "$path"/.git
 131                then
 132                        say "-$sha1 $path"
 133                        continue;
 134                fi
 135                revname=$(unset GIT_DIR && cd "$path" && git-describe $sha1)
 136                if git diff-files --quiet -- "$path"
 137                then
 138                        say " $sha1 $path ($revname)"
 139                else
 140                        if test -z "$cached"
 141                        then
 142                                sha1=$(unset GIT_DIR && cd "$path" && git-rev-parse --verify HEAD)
 143                                revname=$(unset GIT_DIR && cd "$path" && git-describe $sha1)
 144                        fi
 145                        say "+$sha1 $path ($revname)"
 146                fi
 147        done
 148}
 149
 150while case "$#" in 0) break ;; esac
 151do
 152        case "$1" in
 153        init)
 154                init=1
 155                ;;
 156        update)
 157                update=1
 158                ;;
 159        status)
 160                status=1
 161                ;;
 162        -q|--quiet)
 163                quiet=1
 164                ;;
 165        --cached)
 166                cached=1
 167                ;;
 168        --)
 169                break
 170                ;;
 171        -*)
 172                usage
 173                ;;
 174        *)
 175                break
 176                ;;
 177        esac
 178        shift
 179done
 180
 181case "$init,$update,$status,$cached" in
 1821,,,)
 183        modules_init "$@"
 184        ;;
 185,1,,)
 186        modules_update "$@"
 187        ;;
 188,,*,*)
 189        modules_list "$@"
 190        ;;
 191*)
 192        usage
 193        ;;
 194esac