To review, this repository has just under ten thousand commits and just under 400 tags. Migrating with “git svn clone” would have taken over 48 hours. Since the majority of the time was going to migrating the tags, I decided to migrate just the trunk/branches and then re-create the tags. After all they are just labels. This post describes the procedure.
Also see
Looking at the commit comments
Each migrated commit in git has a comment like:
git-svn-id: https://<url>/svn/projectName@8848 9a30da7b-550c-0410-b2c9-c7485123b453
This is good. It lets me map SVN commits (ex: 8848) to Git has (9a30da). This means it is possible to create the tags with a script.
Some “light googling” didn’t find such a script so I wrote my own.
Step 1 – Create a file containing all the SVN tag names to migrate
This is easy. Go to https://<svn url>/svn/tags/ in a browser and it gives you such a list. Just copy this to a file. My file had 396 lines in it. But copy/paste doesn’t charge per line so this was ok!
Step 2 – Map SVN tag names to SVN commit numbers and Git commit hashes
I wrote a script to create CSV of these pieces of informatio. I didn’t include creating the tags in that script so I could review the output in between. I spot checked and it looked reasonable. (the script took about 10 minutes to run against a remote SVN. But I had almost 400 tags so that’s not bad.)
The script is long so I included it at the bottom of the post.I put in a file named generateSvnGitMapping.sh
Step 3 – Actually create the Git tags
I ran another script I wrote to actually create the github tags. We had one SVN tag with a single quote in it. This tag was created in error. Since it was recreated with the proper name, I choose not to migrate it. I put this script in a file named generateTags.sh:
for line in `cat ../tagMapping-oneLine.txt` do echo $line echo ${line} | awk -F',' '{ print git tag -a $1 -m"re-creating tag for SVN @$2 commit" $3 }' done
Then I
- ran generateTags.sh > tags.sh
- Placed script in git repo directory: mv tags.sh new-git-repo
- cd new-git-repo
- Ran script ./tags.sh
- Delete script rm tags.sh
- Listed tags to ensure seemed reasonable: git tags -l
Step 4 – Push tags to GitLab (or GitHub)
git push --tags
The script for step 2
#!/bin/bash # To run, pass two parameters: # 1) The location of the local git repository # 2) The file containing the tag names you'd like to check # 3) The URL of the base SVN (not including /tags) # ------------------------------------------------ # gets svn revision number for a svn tag # $1 = svn url (ex: https://svn.com/svn) # $2 = tag (ex: my_tag) # sets variable svn_revision set_svn_revision() {&lt;br /&gt;&lt;br /&gt; # On Windows, this fails with E720232 write error: The pipe is being closed.&lt;br /&gt; #svn_revision=`svn log "$1/tags/\"/ --limit 1 | &lt;br /&gt; # head -2 | tail -1 | awk '{print $1}'`&lt;br /&gt; # On Windows, works if don't use head in pipe&lt;br /&gt; svn_log_output=`svn log "$1/tags/\"/ --limit 1` &lt;br /&gt; svn_revision=`echo "$svn_log_output" | head -2 | tail -1 | awk '{print $1}'` # remove leading "r" so just returns the number svn_revision=${svn_revision#r} } # ------------------------------------------------ # sets the git commit number for a svn revision # if no commits are found (or more than one comment has this tag), exits the program # $1 = svn commit (ex: r1234) # $2 = tag name (ex: my_tag) # sets variable git_commit set_git_commit() { # since didn't migrate tags, need commit right before the tag # this might be a few commits back in some cases so check 5 max_to_try=5 num_attempts=0 commit_right_before_tag="" previous_commit=$1 while [ "$commit_right_before_tag" == "" ]; do # add character before/after in git-svn log message to avoid ambiguity candidate_commit="@$previous_commit " num_lines=`git log --grep "$candidate_commit" | grep commit | wc -l` # if found a commit, use it. otherwise try some more if [ "$num_lines" -ne "0" ]; then commit_right_before_tag=$candidate_commit fi num_attempts=$(($num_attempts+1)) previous_commit=$(($previous_commit-1)) # if tried too many times, give up if [ "$num_attempts" -gt "$max_to_try" ]; then echo "commit ($1) for tag name ($2) not found. Aborting. Please check git repo or remove this tag from the input" exit fi done git_commit=`git log --grep "$commit_right_before_tag" | head -1 | awk '{print $2}'` } # ------------------------------------------------ if [[ $# -ne 3 ]] then echo "Requires three parameters:" echo "1) Path to git repo" echo "2) name of file containing tags" echo "3) url to svn" exit fi git_dir="$1" tag_names_file="$2" svn_url="$3" all_tag_names=`cat $tag_names_file` current_dir=`pwd` cd "$git_dir" for tag_name in `echo $all_tag_names` do&lt;br /&gt; # On Windows, need to strip carriage returns. (Not needed on Mac, but no harm)&lt;br /&gt; tag_name=`echo $tag_name | tr -d '\r'` tag_name_without_trailing_slash=${tag_name%/} set_svn_revision "$svn_url" "$tag_name" set_git_commit "$svn_revision" "$tag_name" echo "git tag -a "$tag_name_without_trailing_slash" -m \"re-creating tag for SVN @$svn_revision commit\" $git_commit" done cd $current_dir
Updated to run on Windows in Git Bash