我阅读了Git手册、常见问题解答、Git-SVN速成课程等,他们都解释了这一点和那一点,但你找不到像这样的简单说明:

SVN存储库位于:svn://myserver/path/to/svn/repos

Git存储库位于: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

我不希望它这么简单,也不希望它是一个命令。但我确实希望它不要试图解释任何事情——只是说在这个例子中应该采取什么步骤。


当前回答

首先,感谢@cmginty的回答。对我来说,这是一个很好的起点,我将在这里发布的很多内容都借鉴了它。然而,我正在移动的回购已经有多年的历史,这导致了信件回复后出现了一些问题(需要手动移动数百个分支和标签,稍后阅读更多内容)。

因此,经过数小时的搜索和反复尝试,我能够编写一个脚本,使我能够轻松地将几个项目从SVN转移到GIT,我决定在这里分享我的发现,以防其他人也站在我的立场上。

<tl;我们开始吧


首先,创建一个“作者”文件,将基本svn用户转换为更复杂的git用户。最简单的方法是使用命令从要移动的svn repo中提取所有用户。

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

这将生成一个名为authors-transform.txt的文件,其中包含对运行该文件的svn repo进行更改的每个用户的一行。

someuser = someuser <someuser>

更新以包括git的全名和电子邮件

someuser = Some User <someuser@somewhere.com>

现在使用authors文件启动克隆

git svn clone --stdlayout --no-metadata -r854:HEAD --authors-file=authors-transform.txt https://somesvnserver/somerepo/ temp

--stdlayout表示svn repo遵循标准/主干/分支/标签布局--no-metadata告诉git不要在每次git提交时标记与svn提交相关的元数据。如果这不是单向转换,请删除此标记-r854:HEAD仅从854修订版获取历史记录。这是我遇到的第一个障碍;我正在转换的回购在853版本中有一个“损坏”的提交,因此它不会克隆。使用此参数,您只能克隆部分历史记录。temp是要创建以初始化的目录的名称新的git回购

这一步骤可能需要一段时间,特别是在大型或旧回购协议中(我们的一个回购协议大约需要18小时)。您还可以使用-r开关只获取一个小的历史记录来查看克隆,然后再获取其余的历史记录。

移动到新目录

cd temp

如果只在克隆中提取了部分历史记录,则获取任何缺失的历史记录

git svn fetch

标记在克隆期间创建为分支。如果你只有几个,你可以一次转换一个。

git 1.0.0 origin/tags/1.0.0

然而,如果你有数百个标签,这是很乏味的,所以下面的脚本对我很有用。

for brname in `git branch -r | grep tags | awk '{gsub(/^[^\/]+\//,"",$1); print $1}'`; do echo $brname; tname=${brname:5}; echo $tname; git tag $tname origin/tags/$tname; done

您还需要签出所有要保留的分支

git checkout -b branchname origin/branches/branchname

如果你也有很多分支,这个脚本可能会有所帮助

for brname in `git branch -r | grep -v master | grep -v HEAD | grep -v trunk | grep -v tags | awk '{gsub(/^[^\/]+\//,"",$1); print $1}'`; do echo $brname; git checkout -b $brname origin/$brname; done

这将忽略主干分支,因为它已经作为主分支签出,并保存一个步骤,稍后删除重复的分支,以及忽略我们已经转换的/标记。

现在是查看新回购的好时机,并确保您有一个本地分支或标记,可以保存任何您想保留的内容,因为远程分支将在片刻后删除。

好的,现在让我们将我们签出的所有内容克隆到一个干净的repo(此处名为temp2)

cd ..
git clone temp temp2
cd temp2

现在,我们需要再次检查所有分支,然后再将它们推到最后的远程位置,所以请按照上面您最喜欢的方法操作。

如果您正在使用gitflow,您可以重命名工作分支以进行开发。

git checkout -b WORKING
git branch -m develop
git push origin --delete WORKING
git push origin -u develop

现在,如果一切看起来都很好,就可以将其推送到git存储库了

git remote set-url origin https://somebitbucketserver/somerepo.git
git push -u origin --all
git push origin --tags

我确实遇到了最后一个问题,那就是Control Freak最初阻止我推送我没有创建的标签,所以如果您的团队使用Control Freak,您可能需要禁用或调整初始推送的设置。

其他回答

我使用以下脚本读取了一个包含所有SVN存储库列表的文本文件,并将其转换为Git,然后使用gitclone--bare将其转换成Git存储库:

#!/bin/bash
file="list.txt"
while IFS= read -r repo_name
do
 printf '%s\n' "$repo_name"
 sudo git svn clone --shared --preserve-empty-dirs --authors-file=users.txt file:///programs/svn/$repo_name
 sudo git clone --bare /programs/git/$repo_name $repo_name.git
 sudo chown -R www-data:www-data $repo_name.git
 sudo rm -rf $repo_name
done <"$file"

list.txt的格式为:

repo1_name
repo2_name

users.txt的格式为:

(无作者)=罗杰斯王子<prince.rogers.nelson@payesley.park.org>

www数据是Apache web服务器用户,需要权限才能通过HTTP推送更改。

首先,感谢@cmginty的回答。对我来说,这是一个很好的起点,我将在这里发布的很多内容都借鉴了它。然而,我正在移动的回购已经有多年的历史,这导致了信件回复后出现了一些问题(需要手动移动数百个分支和标签,稍后阅读更多内容)。

因此,经过数小时的搜索和反复尝试,我能够编写一个脚本,使我能够轻松地将几个项目从SVN转移到GIT,我决定在这里分享我的发现,以防其他人也站在我的立场上。

<tl;我们开始吧


首先,创建一个“作者”文件,将基本svn用户转换为更复杂的git用户。最简单的方法是使用命令从要移动的svn repo中提取所有用户。

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

这将生成一个名为authors-transform.txt的文件,其中包含对运行该文件的svn repo进行更改的每个用户的一行。

someuser = someuser <someuser>

更新以包括git的全名和电子邮件

someuser = Some User <someuser@somewhere.com>

现在使用authors文件启动克隆

git svn clone --stdlayout --no-metadata -r854:HEAD --authors-file=authors-transform.txt https://somesvnserver/somerepo/ temp

--stdlayout表示svn repo遵循标准/主干/分支/标签布局--no-metadata告诉git不要在每次git提交时标记与svn提交相关的元数据。如果这不是单向转换,请删除此标记-r854:HEAD仅从854修订版获取历史记录。这是我遇到的第一个障碍;我正在转换的回购在853版本中有一个“损坏”的提交,因此它不会克隆。使用此参数,您只能克隆部分历史记录。temp是要创建以初始化的目录的名称新的git回购

这一步骤可能需要一段时间,特别是在大型或旧回购协议中(我们的一个回购协议大约需要18小时)。您还可以使用-r开关只获取一个小的历史记录来查看克隆,然后再获取其余的历史记录。

移动到新目录

cd temp

如果只在克隆中提取了部分历史记录,则获取任何缺失的历史记录

git svn fetch

标记在克隆期间创建为分支。如果你只有几个,你可以一次转换一个。

git 1.0.0 origin/tags/1.0.0

然而,如果你有数百个标签,这是很乏味的,所以下面的脚本对我很有用。

for brname in `git branch -r | grep tags | awk '{gsub(/^[^\/]+\//,"",$1); print $1}'`; do echo $brname; tname=${brname:5}; echo $tname; git tag $tname origin/tags/$tname; done

您还需要签出所有要保留的分支

git checkout -b branchname origin/branches/branchname

如果你也有很多分支,这个脚本可能会有所帮助

for brname in `git branch -r | grep -v master | grep -v HEAD | grep -v trunk | grep -v tags | awk '{gsub(/^[^\/]+\//,"",$1); print $1}'`; do echo $brname; git checkout -b $brname origin/$brname; done

这将忽略主干分支,因为它已经作为主分支签出,并保存一个步骤,稍后删除重复的分支,以及忽略我们已经转换的/标记。

现在是查看新回购的好时机,并确保您有一个本地分支或标记,可以保存任何您想保留的内容,因为远程分支将在片刻后删除。

好的,现在让我们将我们签出的所有内容克隆到一个干净的repo(此处名为temp2)

cd ..
git clone temp temp2
cd temp2

现在,我们需要再次检查所有分支,然后再将它们推到最后的远程位置,所以请按照上面您最喜欢的方法操作。

如果您正在使用gitflow,您可以重命名工作分支以进行开发。

git checkout -b WORKING
git branch -m develop
git push origin --delete WORKING
git push origin -u develop

现在,如果一切看起来都很好,就可以将其推送到git存储库了

git remote set-url origin https://somebitbucketserver/somerepo.git
git push -u origin --all
git push origin --tags

我确实遇到了最后一个问题,那就是Control Freak最初阻止我推送我没有创建的标签,所以如果您的团队使用Control Freak,您可能需要禁用或调整初始推送的设置。

另一方面,当尝试使用git-svn-dcommits进行git时,git-stash命令是一个天赐的选择。

典型流程:

设置git回购在不同的文件上做一些工作决定使用git检查一些工作决定svn dcommit得到可怕的“不能提交脏索引”错误。

解决方案(需要git 1.5.3+):

git stash; git svn dcommit ; git stash apply

这里有一个简单的shell脚本,它没有依赖关系,可以将一个或多个SVN存储库转换为git并将其推送到GitHub。

https://gist.github.com/NathanSweet/7327535

在大约30行脚本中:使用git SVN克隆,从SVN::ignore财产创建一个.gitignore文件,推入一个裸git存储库,重命名SVN主干为master,将SVN标记转换为git标记,并将其推送到GitHub,同时保留标记。

我经历了很多痛苦才将十几个SVN存储库从Google Code迁移到GitHub。我使用Windows并没有帮助。Ruby在我的旧Debian盒子上摔坏了,让它在Windows上运行简直是个笑话。其他解决方案无法使用Cygwin路径。即使我得到了一些有用的东西,我也不知道如何让标签显示在GitHub上(秘诀是——关注标签)。

最后,我拼凑了两个简短而简单的脚本,上面链接了起来,效果很好。解决方案不需要比这更复杂!

我们可以使用git-svnclone命令,如下所示。

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

上述命令将从SVN提交创建authors文件。

svn日志—复制时停止<svn_URL>

创建SVN项目时,上面的命令将为您提供第一个修订号。

git svn clone-r<svn_REV_NO>:HEAD--无最小化url--stdlayout--无元数据--作者文件authors.txt<svn_url>

以上命令将在本地创建Git存储库。

问题是它不会将分支和标签转换为推送。您必须手动执行这些操作。以下分支机构示例:

$ 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
$

对于标记:

$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
$

现在将master、branches和标记推送到远程git存储库。

$ 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实用程序

svn2git实用程序删除了带有分支和标记的手动工作。

使用命令sudogeminstallsvn2git安装它。之后运行以下命令。

$svn2git<SVN_URL>--authors.txt--修订版<SVN_REV_NO>

现在,您可以列出分支、标记并轻松推送它们。

$ 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

假设您有20个分支和标记,显然svn2git将为您节省大量时间,这就是为什么我比原生命令更喜欢它的原因。这是一个很好的原生git-svnclone命令包装器。

有关完整的示例,请参阅我的博客条目。