3 # git-subtree.sh: split/join git repositories in subdirectories of this one
5 # Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com>
8 git subtree split [--rejoin] [--onto rev] <commit...> -- <path>
11 git subtree does foo and bar!
16 onto= existing subtree revision to search for parent
17 rejoin merge the new branch back into HEAD
19 eval $
(echo "$OPTS_SPEC" | git rev-parse
--parseopt -- "$@" ||
echo exit $?
)
30 if [ -z "$quiet" ]; then
40 die
"assertion failed: " "$@"
47 while [ $# -gt 0 ]; do
52 --onto) onto
="$1"; shift ;;
62 *) die
"Unknown command '$command'" ;;
65 revs
=$
(git rev-parse
--default HEAD
--revs-only "$@") ||
exit $?
66 dirs="$(git rev-parse --sq --no-revs --no-flags "$@
")" ||
exit $?
68 #echo "dirs is {$dirs}"
69 eval $
(echo set -- $dirs)
70 if [ "$#" -ne 1 ]; then
71 die
"Must provide exactly one subtree dir (got $#)"
75 debug
"command: {$command}"
76 debug
"quiet: {$quiet}"
82 cachedir
="$GIT_DIR/subtree-cache/$$"
83 rm -rf "$cachedir" || die
"Can't delete old cachedir: $cachedir"
84 mkdir
-p "$cachedir" || die
"Can't create new cachedir: $cachedir"
85 debug
"Using cachedir: $cachedir" >&2
91 if [ -r "$cachedir/$oldrev" ]; then
92 read newrev
<"$cachedir/$oldrev"
102 if [ "$oldrev" != "latest_old" \
103 -a "$oldrev" != "latest_new" \
104 -a -e "$cachedir/$oldrev" ]; then
105 die
"cache for $oldrev already exists!"
107 echo "$newrev" >"$cachedir/$oldrev"
110 find_existing_splits
()
112 debug
"Looking for prior splits..."
115 git log
--grep="^git-subtree-dir: $dir\$" \
116 --pretty=format
:'%s%n%n%b%nEND' "$revs" |
117 while read a b junk
; do
119 git-subtree-mainline
:) main
="$b" ;;
120 git-subtree-split
:) sub
="$b" ;;
122 if [ -n "$main" -a -n "$sub" ]; then
123 debug
" Prior: $main -> $sub"
125 echo "^$main^ ^$sub^"
136 # We're doing to set some environment vars here, so
137 # do it in a subshell to get rid of them safely later
138 git log
-1 --pretty=format
:'%an%n%ae%n%ad%n%cn%n%ce%n%cd%n%s%n%n%b' "$1" |
141 read GIT_AUTHOR_EMAIL
143 read GIT_COMMITTER_NAME
144 read GIT_COMMITTER_EMAIL
145 read GIT_COMMITTER_DATE
146 export GIT_AUTHOR_NAME \
150 GIT_COMMITTER_EMAIL \
152 git commit-tree
"$2" $3 # reads the rest of stdin
153 ) || die
"Can't copy commit $1"
162 Split '$dir/' into commit '$latest_new'
164 git-subtree-dir: $dir
165 git-subtree-mainline: $latest_old
166 git-subtree-split: $latest_new
172 git ls-tree
"$1" -- "$dir" |
173 while read mode
type tree name
; do
174 assert
[ "$name" = "$dir" ]
184 if [ $# -ne 1 ]; then
185 return 0 # weird parents, consider it changed
187 ptree
=$
(tree_for_commit
$1)
188 if [ "$ptree" != "$tree" ]; then
191 return 1 # not changed
198 debug
"Splitting $dir..."
199 cache_setup ||
exit $?
201 if [ -n "$onto" ]; then
202 echo "Reading history for --onto=$onto..."
205 # the 'onto' history is already just the subdir, so
206 # any parent we find there can be used verbatim
212 unrevs
="$(find_existing_splits "$dir" "$revs")"
214 debug
"git rev-list --reverse $revs $unrevs"
215 git rev-list
--reverse --parents $revs $unrevsx |
216 while read rev parents
; do
218 debug
"Processing commit: $rev"
219 exists
=$
(cache_get
$rev)
220 if [ -n "$exists" ]; then
221 debug
" prior: $exists"
224 debug
" parents: $parents"
225 newparents
=$
(cache_get
$parents)
226 debug
" newparents: $newparents"
228 tree
=$
(tree_for_commit
$rev)
229 debug
" tree is: $tree"
230 [ -z $tree ] && continue
233 for parent
in $newparents; do
237 if tree_changed
$tree $parents; then
238 newrev
=$
(copy_commit
$rev $tree "$p") ||
exit $?
242 debug
" newrev is: $newrev"
243 cache_set
$rev $newrev
244 cache_set latest_new
$newrev
245 cache_set latest_old
$rev
247 latest_new
=$
(cache_get latest_new
)
248 if [ -z "$latest_new" ]; then
249 die
"No new revisions were found"
252 if [ -n "$rejoin" ]; then
253 debug
"Merging split branch into HEAD..."
254 latest_old
=$
(cache_get latest_old
)
256 -m "$(merge_msg $dir $latest_old $latest_new)" \
265 die
"merge command not implemented yet"