Add support for submodules.
[git-scripts.git] / git-svn-new-branch
blobc5dfcb150bcc5021a60c1bf7ecd8b1a21c9c8e3d
1 #! /bin/sh
3 program=$0
5 prefix="svn-"
6 USAGE='abort|branch-point|checkout|attach [--dry-run] URL [branch_name]'
7 LONG_USAGE=" Commands:
9 abort : to abort an import
10 branch-point : return branch point svn revision
11 checkout : retrieve a new branch
12 attach : attach previously imported (see above) branch to
13 corresponding branch point.
14 Options:
16 URL : the full url to subversion branch
17 branch_name : the name of the remote branch to use
18 (default is the name of the subversion branch)
19 the local branch name is the basename of this name,
20 prefixed with '$prefix'
21 --dry-run : nothing will changed in the local Git repository
22 --prefix=name : prefix to apply to the name of the local branch
24 A common usage is:
26 $ git svn-new-branch checkout svn+ssh://server/svn/branches/relA
27 $ git svn-new-branch attach svn+ssh://server/svn/branches/relA
29 Before attaching, it is possible to check the branch-point that will be
30 used to connect the branch history to the master:
32 $ git svn-new-branch branch-point svn+ssh://server/svn/branches/relA
35 OPTIONS_SPEC=
37 # Use default C as language to ensure that the regexp parsing Subversion
38 # outout are maching.
39 export LANG=C
41 exec_path=$(git --exec-path)
42 . $exec_path/git-sh-setup
43 require_work_tree
44 cd_to_toplevel
45 set_reflog_action svn-new-branch
47 # Get require_work_tree from git-rebase--interactive.sh
48 require_clean_work_tree () {
49 # test if working tree is dirty
50 git rev-parse --verify HEAD > /dev/null &&
51 git update-index --ignore-submodules --refresh &&
52 git diff-files --quiet --ignore-submodules &&
53 git diff-index --cached --quiet HEAD --ignore-submodules -- ||
54 die "Working tree is dirty"
57 parse_command_line () {
58 requires_url=${1:-True}
59 dryrun=""
61 shift # remove requires_url
63 TEMP=`getopt -o dp: --long dry-run,prefix: -n git-svn-new-branch -- "$@"`
64 if [ $? != 0 ]; then exit 1; fi
65 eval set -- "$TEMP"
67 while true ; do
68 case "$1" in
69 -d|--dry-run) dryrun=echo;
70 echo "Restart without --dry-run if you want to execute"\
71 "the following commands:"
72 shift;;
73 -p|--prefix) prefix="$2"; shift 2;;
74 --) shift; break ;;
75 *) exit 1;;
76 esac
77 done
79 if [ $requires_url = True ]; then
80 URL=$1
82 if [ "$URL" = "" ]; then
83 echo "Missing URL"
84 exit 1
87 if [ "$2" = "" ]; then
88 branch_name=$(basename $URL)
89 local_branch=$prefix$branch_name
90 else
91 branch_name=$2
92 local_branch=$prefix$(basename $branch_name)
95 echo
96 echo Track $URL on branch: $branch_name
97 echo on local branch : $local_branch
98 echo
102 abort () {
103 parse_command_line False "$@"
104 require_clean_work_tree
105 head=$(grep HEAD .git/SVN_NEW_BRANCH | sed -e "s/HEAD: //")
106 branch_name=$(grep BRANCH_NAME .git/SVN_NEW_BRANCH |
107 sed -e s"/BRANCH_NAME: //")
108 $dryrun git checkout $head
109 $dryrun git update-ref -d refs/remotes/$branch_name
110 $dryrun find .git -name "*_map*" -print -exec rm -f {} \;
111 $dryrun git branch -D $local_branch
115 get_new_branch () {
116 # Verify HEAD
117 head=$(git symbolic-ref -q HEAD) ||
118 head=$(git rev-parse --verify HEAD) ||
119 die "Bad HEAD - I need a HEAD"
121 require_clean_work_tree
123 rm -f .git/SVN_NEW_BRANCH
124 echo HEAD: ${head#refs/heads/} >> .git/SVN_NEW_BRANCH
126 parse_command_line True "$@"
128 echo BRANCH_NAME: $branch_name >> .git/SVN_NEW_BRANCH
130 echo Check if local branches exist
132 if [ "$(git branch -r | grep $branch_name)" != "" ]; then
133 die Remote branch $branch_name already imported.
136 if [ "$(git branch | grep $local_branch)" != "" ]; then
137 die Local branch $local_branch already present.
140 echo Check if remote branch exists
142 svn list $URL > /dev/null 2>&1
144 if [ $? = 1 ]; then
145 die The given URL does not exists.
148 if [ "$dryrun" = "" ]; then
149 git config svn-remote.$local_branch.url $URL
150 git config svn-remote.$local_branch.fetch :refs/remotes/$branch_name
152 echo Fetch branch data
153 git svn fetch --no-follow-parent $local_branch
154 git branch --track $local_branch $branch_name
156 echo Only branch history has been fetched, consider using
157 echo $program attach --prefix=\"$prefix\" $URL $branch_name
158 echo to attach the old history to the branch.
162 attach_branch () {
163 parse_command_line True "$@"
165 echo Finding branch point
166 rsvn=$(get_branch_point $URL)
167 if [ "$rsvn" = "" ]; then
168 die "Can not find branch point"
171 echo Subversion branch point: $rsvn
173 nrsvn=$(find_nearest_rev $rsvn)
175 rgit=$(git svn find-rev r$nrsvn)
176 # Run it twice to avoid the svn rebuilding .rev_map messages
177 rgit=$(git svn find-rev r$nrsvn)
179 if [ "$rgit" = "" ]; then
180 echo "Can not find corresponding Git rev !"
181 echo "Maybe the subversion repository is set incorrectly, trying different approach"
182 rgit=$(find_previous_svn_rev $URL)
183 if [ "$rgit" = "" ]; then
184 die "Could not find git revision for branch point"
188 echo Corresponding Git revision: $rgit
189 echo
191 git log $rgit^..$rgit | cat -
193 echo Checkout local branch
194 $dryrun git checkout $local_branch
196 $dryrun git filter-branch -f --tag-name-filter cat \
197 --parent-filter "sed -e 's/^$/-p $rgit/'" $local_branch &&
198 $dryrun git reset --hard $local_branch &&
199 $dryrun git update-ref refs/remotes/$branch_name $local_branch &&
200 $dryrun find .git -name "*_map*" -print -exec rm -f {} \; &&
201 $dryrun git svn rebase
202 ) || die "Failed ! Use --abort to revert all changes"
205 get_branch_point () {
206 branch=$1
207 rev=$(svn log --verbose --stop-on-copy $branch | grep '(from' |
208 grep -E -o ":([0-9]+)" | cut -c2- | tail -1)
209 echo $rev
212 find_previous_svn_rev () {
213 branch=$1
214 rev_on_branch=$(svn log -q --stop-on-copy $branch | fgrep r | wc -l)
216 # "+5" is to give us some more revisions to work with, in case the svn
217 # repository is really messed up
218 fetch=`expr $rev_on_branch + 5`
219 prev=$(svn log -q $branch | fgrep r | head -$fetch | grep -o -E 'r[0-9]+' | cut -c2-)
221 for p in $prev; do
222 # When the repository is messed up, it seems that "find-rev" will not
223 # work correctly either, so try differently
224 # rgit=$(git svn find-rev r$p)
226 rgit=$(git log | grep -e commit -e git-svn-id | grep "@$p " -B1 | head -1 | cut -f2 -d\ )
228 if [ "$rgit" != "" ]; then
229 echo $rgit
230 return
231 else
232 echo "No matching git revision for subversion's $p" >/dev/stderr
234 done
236 echo ""
239 find_nearest_rev () {
240 rev=$1
241 nrev=$(
243 echo $rev;
244 git svn log --oneline | grep -o -E 'r[0-9]+' | cut -c2-
245 ) | sort -n | grep -E "^$rev" -B1 | head -1)
246 echo $nrev
249 test "$#" = "0" && usage && exit 1;
251 case $1 in
252 -h|*help)
253 usage;;
254 *abort)
255 shift
256 abort "$@";
257 exit $?
259 *branch-point)
260 shift
261 test "$1" != "" && get_branch_point "$@"
263 *attach)
264 shift
265 attach_branch "$@"
267 *find-nearest-rev)
268 shift
269 test "$1" != "" && find_nearest_rev "$@"
271 *checkout)
272 shift
273 test "$1" != "" && get_new_branch "$@";;
275 echo "Invalid command : $1"
276 exit 1;;
277 esac