c59759baa63c241170fd112de907b32da65d6ccb
   1#!/bin/bash
   2#
   3# git-subtree.sh: split/join git repositories in subdirectories of this one
   4#
   5# Copyright (c) 2009 Avery Pennarun <apenwarr@gmail.com>
   6#
   7OPTS_SPEC="\
   8git subtree split <revisions> -- <subdir>
   9git subtree merge 
  10
  11git subtree does foo and bar!
  12--
  13h,help   show the help
  14q        quiet
  15v        verbose
  16"
  17eval $(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)
  18. git-sh-setup
  19require_work_tree
  20
  21quiet=
  22command=
  23
  24debug()
  25{
  26        if [ -z "$quiet" ]; then
  27                echo "$@" >&2
  28        fi
  29}
  30
  31assert()
  32{
  33        if "$@"; then
  34                :
  35        else
  36                die "assertion failed: " "$@"
  37        fi
  38}
  39
  40
  41#echo "Options: $*"
  42
  43while [ $# -gt 0 ]; do
  44        opt="$1"
  45        shift
  46        case "$opt" in
  47                -q) quiet=1 ;;
  48                --) break ;;
  49        esac
  50done
  51
  52command="$1"
  53shift
  54case "$command" in
  55        split|merge) ;;
  56        *) die "Unknown command '$command'" ;;
  57esac
  58
  59revs=$(git rev-parse --default HEAD --revs-only "$@") || exit $?
  60dirs="$(git rev-parse --sq --no-revs --no-flags "$@")" || exit $?
  61
  62#echo "dirs is {$dirs}"
  63eval $(echo set -- $dirs)
  64if [ "$#" -ne 1 ]; then
  65        die "Must provide exactly one subtree dir (got $#)"
  66fi
  67dir="$1"
  68
  69debug "command: {$command}"
  70debug "quiet: {$quiet}"
  71debug "revs: {$revs}"
  72debug "dir: {$dir}"
  73
  74cache_setup()
  75{
  76        cachedir="$GIT_DIR/subtree-cache/$$"
  77        rm -rf "$cachedir" || die "Can't delete old cachedir: $cachedir"
  78        mkdir -p "$cachedir" || die "Can't create new cachedir: $cachedir"
  79        debug "Using cachedir: $cachedir" >&2
  80        echo "$cachedir"
  81}
  82
  83cache_get()
  84{
  85        for oldrev in $*; do
  86                if [ -r "$cachedir/$oldrev" ]; then
  87                        read newrev <"$cachedir/$oldrev"
  88                        echo $newrev
  89                fi
  90        done
  91}
  92
  93cache_set()
  94{
  95        oldrev="$1"
  96        newrev="$2"
  97        if [ -e "$cachedir/$oldrev" ]; then
  98                die "cache for $oldrev already exists!"
  99        fi
 100        echo "$newrev" >"$cachedir/$oldrev"
 101}
 102
 103cmd_split()
 104{
 105        debug "Splitting $dir..."
 106        cache_setup || exit $?
 107        
 108        git rev-list --reverse --parents $revs -- "$dir" |
 109        while read rev parents; do
 110                newparents=$(cache_get $parents)
 111                debug
 112                debug "Processing commit: $rev / $newparents"
 113                
 114                git ls-tree $rev -- "$dir" |
 115                while read mode type tree name; do
 116                        assert [ "$name" = "$dir" ]
 117                        debug "  tree is: $tree"
 118                        p=""
 119                        for parent in $newparents; do
 120                                p="$p -p $parent"
 121                        done
 122                        newrev=$(echo synthetic | git commit-tree $tree $p) \
 123                                || die "Can't create new commit for $rev / $tree"
 124                        echo "  newrev is: $newrev"
 125                        cache_set $rev $newrev
 126                done || exit $?
 127        done || exit $?
 128        
 129        exit 0
 130}
 131
 132cmd_merge()
 133{
 134        die "merge command not implemented yet"
 135}
 136
 137"cmd_$command"