5f8b0f6c598601756a68fe9df5cc065b791627d9
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}
81
82cache_get()
83{
84 for oldrev in $*; do
85 if [ -r "$cachedir/$oldrev" ]; then
86 read newrev <"$cachedir/$oldrev"
87 echo $newrev
88 fi
89 done
90}
91
92cache_set()
93{
94 oldrev="$1"
95 newrev="$2"
96 if [ "$oldrev" != "latest" -a -e "$cachedir/$oldrev" ]; then
97 die "cache for $oldrev already exists!"
98 fi
99 echo "$newrev" >"$cachedir/$oldrev"
100}
101
102copy_commit()
103{
104 # We're doing to set some environment vars here, so
105 # do it in a subshell to get rid of them safely later
106 git log -1 --pretty=format:'%an%n%ae%n%ad%n%cn%n%ce%n%cd%n%s%n%n%b' "$1" |
107 (
108 read GIT_AUTHOR_NAME
109 read GIT_AUTHOR_EMAIL
110 read GIT_AUTHOR_DATE
111 read GIT_COMMITTER_NAME
112 read GIT_COMMITTER_EMAIL
113 read GIT_COMMITTER_DATE
114 export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
115 export GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_COMMITTER_DATE
116 git commit-tree "$2" $3 # reads the rest of stdin
117 ) || die "Can't copy commit $1"
118}
119
120cmd_split()
121{
122 debug "Splitting $dir..."
123 cache_setup || exit $?
124
125 git rev-list --reverse --parents $revs -- "$dir" |
126 while read rev parents; do
127 newparents=$(cache_get $parents)
128 debug
129 debug "Processing commit: $rev / $newparents"
130
131 git ls-tree $rev -- "$dir" |
132 while read mode type tree name; do
133 assert [ "$name" = "$dir" ]
134 debug " tree is: $tree"
135 p=""
136 for parent in $newparents; do
137 p="$p -p $parent"
138 done
139
140 newrev=$(copy_commit $rev $tree "$p") || exit $?
141 debug " newrev is: $newrev"
142 cache_set $rev $newrev
143 cache_set latest $newrev
144 done || exit $?
145 done || exit $?
146 latest=$(cache_get latest)
147 if [ -z "$latest" ]; then
148 die "No new revisions were found"
149 fi
150 echo $latest
151 exit 0
152}
153
154cmd_merge()
155{
156 die "merge command not implemented yet"
157}
158
159"cmd_$command"