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 #
7 OPTS_SPEC="\
8 git subtree split <revisions> -- <subdir>
9 git subtree merge
11 git subtree does foo and bar!
12 --
13 h,help show the help
14 q quiet
15 v verbose
16 "
17 eval $(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)
18 . git-sh-setup
19 require_work_tree
21 quiet=
22 command=
24 debug()
25 {
26 if [ -z "$quiet" ]; then
27 echo "$@" >&2
28 fi
29 }
31 assert()
32 {
33 if "$@"; then
34 :
35 else
36 die "assertion failed: " "$@"
37 fi
38 }
41 #echo "Options: $*"
43 while [ $# -gt 0 ]; do
44 opt="$1"
45 shift
46 case "$opt" in
47 -q) quiet=1 ;;
48 --) break ;;
49 esac
50 done
52 command="$1"
53 shift
54 case "$command" in
55 split|merge) ;;
56 *) die "Unknown command '$command'" ;;
57 esac
59 revs=$(git rev-parse --default HEAD --revs-only "$@") || exit $?
60 dirs="$(git rev-parse --sq --no-revs --no-flags "$@")" || exit $?
62 #echo "dirs is {$dirs}"
63 eval $(echo set -- $dirs)
64 if [ "$#" -ne 1 ]; then
65 die "Must provide exactly one subtree dir (got $#)"
66 fi
67 dir="$1"
69 debug "command: {$command}"
70 debug "quiet: {$quiet}"
71 debug "revs: {$revs}"
72 debug "dir: {$dir}"
74 cache_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 }
83 cache_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 }
93 cache_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 }
103 cmd_split()
104 {
105 debug "Splitting $dir..."
106 cache_setup || exit $?
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"
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 $?
129 exit 0
130 }
132 cmd_merge()
133 {
134 die "merge command not implemented yet"
135 }
137 "cmd_$command"