Rework pre-commit script to handle renamed files.
[git-scripts.git] / git-svn-new-branch
blob1953bf62b521215f238f487759e00477224767fc
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 exec_path=$(git --exec-path)
38 . $exec_path/git-sh-setup
39 require_work_tree
40 cd_to_toplevel
41 set_reflog_action svn-new-branch
43 # Get require_work_tree from git-rebase--interactive.sh
44 require_clean_work_tree () {
45 # test if working tree is dirty
46 git rev-parse --verify HEAD > /dev/null &&
47 git update-index --ignore-submodules --refresh &&
48 git diff-files --quiet --ignore-submodules &&
49 git diff-index --cached --quiet HEAD --ignore-submodules -- ||
50 die "Working tree is dirty"
53 parse_command_line () {
54 requires_url=${1:-True}
55 dryrun=""
57 shift # remove requires_url
59 TEMP=`getopt -o dp: --long dry-run,prefix: -n git-svn-new-branch -- "$@"`
60 if [ $? != 0 ]; then exit 1; fi
61 eval set -- "$TEMP"
63 while true ; do
64 case "$1" in
65 -d|--dry-run) dryrun=echo;
66 echo "Restart without --dry-run if you want to execute"\
67 "the following commands:"
68 shift;;
69 -p|--prefix) prefix="$2"; shift 2;;
70 --) shift; break ;;
71 *) exit 1;;
72 esac
73 done
75 if [ $requires_url = True ]; then
76 URL=$1
78 if [ "$URL" == "" ]; then
79 echo "Missing URL"
80 exit 1
83 if [ "$2" = "" ]; then
84 branch_name=$(basename $URL)
85 local_branch=$prefix$branch_name
86 else
87 branch_name=$2
88 local_branch=$prefix$(basename $branch_name)
91 echo
92 echo Track $URL on branch: $branch_name
93 echo on local branch : $local_branch
94 echo
98 abort () {
99 parse_command_line False "$@"
100 require_clean_work_tree
101 head=$(grep HEAD .git/SVN_NEW_BRANCH | sed -e "s/HEAD: //")
102 branch_name=$(grep BRANCH_NAME .git/SVN_NEW_BRANCH |
103 sed -e s"/BRANCH_NAME: //")
104 $dryrun git checkout $head
105 $dryrun git update-ref -d refs/remotes/$branch_name
106 $dryrun find .git -name "*_map*" -print -exec rm -f {} \;
107 $dryrun git branch -D $local_branch
111 get_new_branch () {
112 # Verify HEAD
113 head=$(git symbolic-ref -q HEAD) ||
114 head=$(git rev-parse --verify HEAD) ||
115 die "Bad HEAD - I need a HEAD"
117 require_clean_work_tree
119 rm -f .git/SVN_NEW_BRANCH
120 echo HEAD: ${head#refs/heads/} >> .git/SVN_NEW_BRANCH
122 parse_command_line True "$@"
124 echo BRANCH_NAME: $branch_name >> .git/SVN_NEW_BRANCH
126 echo Check if local branches exist
128 if [ "$(git branch -r | grep $branch_name)" != "" ]; then
129 die Remote branch $branch_name already imported.
132 if [ "$(git branch | grep $local_branch)" != "" ]; then
133 die Local branch $local_branch already present.
136 echo Check if remote branch exists
138 svn list $URL > /dev/null 2>&1
140 if [ $? = 1 ]; then
141 die The given URL does not exists.
144 if [ "$dryrun" == "" ]; then
145 git config svn-remote.$local_branch.url $URL
146 git config svn-remote.$local_branch.fetch :refs/remotes/$branch_name
148 echo Fetch branch data
149 git svn fetch --no-follow-parent $local_branch
150 git branch --track $local_branch $branch_name
152 echo Only branch history has been fetched, consider using
153 echo $program attach --prefix=\"$prefix\" $URL $branch_name
154 echo to attach the old history to the branch.
158 attach_branch () {
159 parse_command_line True "$@"
161 echo Finding branch point
162 rsvn=$(get_branch_point $URL)
163 if [ "$rsvn" = "" ]; then
164 die "Can not find branch point"
167 echo Subversion branch point: $rsvn
169 nrsvn=$(find_nearest_rev $rsvn)
171 rgit=$(git svn find-rev r$nrsvn)
172 # Run it twice to avoid the svn rebuilding .rev_map messages
173 rgit=$(git svn find-rev r$nrsvn)
175 if [ "$rgit" = "" ]; then
176 echo "Can not find corresponding Git rev !"
177 echo "Maybe the subversion repository is set incorrectly, trying different approach"
178 rgit=$(find_previous_svn_rev $URL)
179 if [ "$rgit" = "" ]; then
180 die "Could not find git revision for branch point"
184 echo Corresponding Git revision: $rgit
185 echo
187 git log $rgit^..$rgit | cat -
189 echo Checkout local branch
190 $dryrun git checkout $local_branch
192 $dryrun git filter-branch -f --tag-name-filter cat \
193 --parent-filter "sed -e 's/^$/-p $rgit/'" $local_branch &&
194 $dryrun git reset --hard $local_branch &&
195 $dryrun git update-ref refs/remotes/$branch_name $local_branch &&
196 $dryrun find .git -name "*_map*" -print -exec rm -f {} \; &&
197 $dryrun git svn rebase
198 ) || die "Failed ! Use --abort to revert all changes"
201 get_branch_point () {
202 branch=$1
203 rev=$(svn log --verbose --stop-on-copy $branch | grep '(from' |
204 grep -E -o ":([0-9]+)" | cut -c2- | tail -1)
205 echo $rev
208 find_previous_svn_rev () {
209 branch=$1
210 rev_on_branch=$(svn log -q --stop-on-copy $branch | fgrep r | wc -l)
212 # "+5" is to give us some more revisions to work with, in case the svn
213 # repository is really messed up
214 fetch=`expr $rev_on_branch + 5`
215 prev=$(svn log -q $branch | fgrep r | head -$fetch | grep -o -E 'r[0-9]+' | cut -c2-)
217 for p in $prev; do
218 # When the repository is messed up, it seems that "find-rev" will not
219 # work correctly either, so try differently
220 # rgit=$(git svn find-rev r$p)
222 rgit=$(git log | grep -e commit -e git-svn-id | grep "@$p " -B1 | head -1 | cut -f2 -d\ )
224 if [ "$rgit" != "" ]; then
225 echo $rgit
226 return
227 else
228 echo "No matching git revision for subversion's $p" >/dev/stderr
230 done
232 echo ""
235 find_nearest_rev () {
236 rev=$1
237 nrev=$(
239 echo $rev;
240 git svn log --oneline | grep -o -E 'r[0-9]+' | cut -c2-
241 ) | sort -n | grep -E "^$rev" -B1 | head -1)
242 echo $nrev
245 test "$#" = "0" && usage && exit 1;
247 case $1 in
248 -h|*help)
249 usage;;
250 *abort)
251 shift
252 abort "$@";
253 exit $?
255 *branch-point)
256 shift
257 test "$1" != "" && get_branch_point "$@"
259 *attach)
260 shift
261 attach_branch "$@"
263 *find-nearest-rev)
264 shift
265 test "$1" != "" && find_nearest_rev "$@"
267 *checkout)
268 shift
269 test "$1" != "" && get_new_branch "$@";;
271 echo "Invalid command : $1"
272 exit 1;;
273 esac