How do I migrate an SVN repository with history to

2018-12-31 06:38发布

I read the Git manual, FAQ, Git - SVN crash course, etc. and they all explain this and that, but nowhere can you find a simple instruction like:

SVN repository in: svn://myserver/path/to/svn/repos

Git repository in: git://myserver/path/to/git/repos

git-do-the-magic-svn-import-with-history \
svn://myserver/path/to/svn/repos \
git://myserver/path/to/git/repos

I don't expect it to be that simple, and I don't expect it to be a single command. But I do expect it not to try to explain anything - just to say what steps to take given this example.

30条回答
柔情千种
2楼-- · 2018-12-31 06:53

reposurgeon

For complicated cases, reposurgeon by Eric S. Raymond is the tool of choice. In addition to SVN, it supports many other version control systems via the fast-export format, and also CVS. The author reports successful conversions of ancient repositories such as Emacs and FreeBSD.

The tool apparently aims at near perfect conversion (such as converting SVN's svn:ignore properties to .gitignore files) even for difficult repository layouts with a long history. For many cases, other tools might be easier to use.

Before delving into the documentation of the reposurgeon command line, be sure to read the excellent DVCS migration guide which goes over the conversion process step by step.

查看更多
高级女魔头
3楼-- · 2018-12-31 06:53

You have to Install

git
git-svn

Copied from this link http://john.albin.net/git/convert-subversion-to-git.

1. Retrieve a list of all Subversion committers

Subversion simply lists the username for each commit. Git’s commits have much richer data, but at its simplest, the commit author needs to have a name and email listed. By default the git-svn tool will just list the SVN username in both the author and email fields. But with a little bit of work, you can create a list of all SVN users and what their corresponding Git name and emails are. This list can be used by git-svn to transform plain svn usernames into proper Git committers.

From the root of your local Subversion checkout, run this command:

svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u > authors-transform.txt

That will grab all the log messages, pluck out the usernames, eliminate any duplicate usernames, sort the usernames and place them into a “authors-transform.txt” file. Now edit each line in the file. For example, convert:

jwilkins = jwilkins <jwilkins>

into this:

jwilkins = John Albin Wilkins <johnalbin@example.com>

2. Clone the Subversion repository using git-svn

git svn clone [SVN repo URL] --no-metadata -A authors-transform.txt --stdlayout ~/temp

This will do the standard git-svn transformation (using the authors-transform.txt file you created in step 1) and place the git repository in the “~/temp” folder inside your home directory.

3. Convert svn:ignore properties to .gitignore

If your svn repo was using svn:ignore properties, you can easily convert this to a .gitignore file using:

cd ~/temp
git svn show-ignore > .gitignore
git add .gitignore
git commit -m 'Convert svn:ignore properties to .gitignore.'

4. Push repository to a bare git repository

First, create a bare repository and make its default branch match svn’s “trunk” branch name.

git init --bare ~/new-bare.git
cd ~/new-bare.git
git symbolic-ref HEAD refs/heads/trunk

Then push the temp repository to the new bare repository.

cd ~/temp
git remote add bare ~/new-bare.git
git config remote.bare.push 'refs/remotes/*:refs/heads/*'
git push bare

You can now safely delete the ~/temp repository.

5. Rename “trunk” branch to “master”

Your main development branch will be named “trunk” which matches the name it was in Subversion. You’ll want to rename it to Git’s standard “master” branch using:

cd ~/new-bare.git
git branch -m trunk master

6. Clean up branches and tags

git-svn makes all of Subversions tags into very-short branches in Git of the form “tags/name”. You’ll want to convert all those branches into actual Git tags using:

cd ~/new-bare.git
git for-each-ref --format='%(refname)' refs/heads/tags |
cut -d / -f 4 |
while read ref
do
  git tag "$ref" "refs/heads/tags/$ref";
  git branch -D "tags/$ref";
done

This step will take a bit of typing. :-) But, don’t worry; your unix shell will provide a > secondary prompt for the extra-long command that starts with git for-each-ref.

查看更多
皆成旧梦
5楼-- · 2018-12-31 06:54

We can use git svn clone commands as below.

  • svn log -q <SVN_URL> | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u > authors.txt

Above command will create authors file from SVN commits.

  • svn log --stop-on-copy <SVN_URL>

Above command will give you first revision number when your SVN project got created.

  • git svn clone -r<SVN_REV_NO>:HEAD --no-minimize-url --stdlayout --no-metadata --authors-file authors.txt <SVN_URL>

Above command will create the Git repository in local.

Problem is that it won't convert branches and tags to push. You will have to do them manually. For example below for branches:

$ git remote add origin https://github.com/pankaj0323/JDProjects.git
$ git branch -a
* master
  remotes/origin/MyDevBranch
  remotes/origin/tags/MyDevBranch-1.0
  remotes/origin/trunk
$$ git checkout -b MyDevBranch origin/MyDevBranch
Branch MyDevBranch set up to track remote branch MyDevBranch from origin.
Switched to a new branch 'MyDevBranch'
$ git branch -a
* MyDevBranch
  master
  remotes/origin/MyDevBranch
  remotes/origin/tags/MyDevBranch-1.0
  remotes/origin/trunk
$

For tags:

$git checkout origin/tags/MyDevBranch-1.0
Note: checking out 'origin/tags/MyDevBranch-1.0'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at 3041d81... Creating a tag
$ git branch -a
* (detached from origin/tags/MyDevBranch-1.0)
  MyDevBranch
  master
  remotes/origin/MyDevBranch
  remotes/origin/tags/MyDevBranch-1.0
  remotes/origin/trunk
$ git tag -a MyDevBranch-1.0 -m "creating tag"
$git tag
MyDevBranch-1.0
$

Now push master, branches and tags to remote git repository.

$ git push origin master MyDevBranch MyDevBranch-1.0
Counting objects: 14, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (14/14), 2.28 KiB | 0 bytes/s, done.
Total 14 (delta 3), reused 0 (delta 0)
To https://github.com/pankaj0323/JDProjects.git
 * [new branch]      master -> master
 * [new branch]      MyDevBranch -> MyDevBranch
 * [new tag]         MyDevBranch-1.0 -> MyDevBranch-1.0
$

svn2git utility

svn2git utility removes manual efforts with branches and tags.

Install it using command sudo gem install svn2git. After that run below command.

  • $ svn2git <SVN_URL> --authors authors.txt --revision <SVN_REV_NO>

Now you can list the branches, tags and push them easily.

$ git remote add origin https://github.com/pankaj0323/JDProjects.git
$ git branch -a
  MyDevBranch
* master
  remotes/svn/MyDevBranch
  remotes/svn/trunk
$ git tag
  MyDevBranch-1.0
$ git push origin master MyDevBranch MyDevBranch-1.0

Imagine you have 20 branches and tags, obviously svn2git will save you a lot of time and that's why I like it better than native commands. It's a nice wrapper around native git svn clone command.

For a complete example, refer my blog entry.

查看更多
余欢
6楼-- · 2018-12-31 06:54

As another aside, the git-stash command is a godsend when trying to git with git-svn dcommits.

A typical process:

  1. set up git repo
  2. do some work on different files
  3. decide to check some of the work in, using git
  4. decide to svn-dcommit
  5. get the dreaded "cannot commit with a dirty index" error.

The solution (requires git 1.5.3+):

git stash; git svn dcommit ; git stash apply
查看更多
不流泪的眼
7楼-- · 2018-12-31 06:54

Effectively using Git with Subversion is a gentle introduction to git-svn. For existing SVN repositories, git-svn makes this super easy. If you're starting a new repository, it's vastly easier to first create an empty SVN repository and then import using git-svn than it is going in the opposite direction. Creating a new Git repository then importing into SVN can be done, but it is a bit painful, especially if you're new to Git and hope to preserve the commit history.

查看更多
登录 后发表回答