如何将具有历史记录的SVN存储库迁移到新的Git存储库?

我阅读了Git手册、FAQ、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

我不希望它有那么简单,也不希望它是一个单一的命令,但我确实希望它不要试图解释任何东西-只是说在给定这个例子的情况下应该采取什么步骤。

529375 次浏览

魔法:

$ git svn clone http://svn/repo/here/trunk

Git和SVN的操作非常不同。你需要学习Git,如果你想跟踪SVN上游的变化,你需要学习git-svngit-svn主页有一个很好的例子部分

$ git svn --help

将您的Subversion存储库干净地迁移到Git存储库.首先,您必须创建一个文件,将您的Subversion提交作者名称映射到Git提交者,例如~/authors.txt

jmaddox = Jon Maddox <jon@gmail.com>bigpappa = Brian Biggs <bigpappa@gmail.com>

然后您可以将Subversion数据下载到Git存储库中:

mkdir repo && cd repogit svn init http://subversion/repo --no-metadatagit config svn.authorsfile ~/authors.txtgit svn fetch

如果您使用的是Mac,则可以通过安装git-core +svn从MacPorts获取git-svn

如果您的subversion存储库与您想要的git存储库位于同一台机器上,然后您可以将此语法用于init步骤,否则都一样:

git svn init file:///home/user/repoName --no-metadata

见官方git-svn管理页。特别是,在“基本示例”下查看:

跟踪和贡献整个Subversion管理的项目(完成使用主干,标签和分支):

# Clone a repo (like git clone):git svn clone http://svn.foo.org/project -T trunk -b branches -t tags

我建议在尝试不断使用git-svn之前熟悉Git,即保持SVN作为集中式存储库并在本地使用Git。

但是,对于具有所有历史记录的简单迁移,这里有几个简单的步骤:

初始化本地repo:

mkdir projectcd projectgit svn init http://svn.url

标记您要开始导入修订的距离:

git svn fetch -r42

(或仅对所有版本使用“git svn get”)

实际上,从那时起获取所有内容:

git svn rebase

您可以使用Gitk检查导入的结果。我不确定这是否适用于Windows,它适用于OSX和Linux:

gitk

当您在本地克隆SVN存储库时,您可能希望将其推送到集中式Git存储库以便于协作。

首先创建空的远程存储库(可能在github上?):

git remote add origin git@github.com:user/project-name.git

然后,可选地同步您的主分支,以便当远程主服务器和本地主服务器都包含新内容时,拉取操作将自动合并远程主服务器:

git config branch.master.remote origingit config branch.master.merge refs/heads/master

之后,您可能有兴趣尝试我自己的git_remote_branch工具,它有助于处理远程分支:

第一篇解释文章:“git远程分支

跟进最新版本:“是时候与git_remote_branch合作了

GitHub现在有一个从SVN存储库导入的功能。不过,我从未尝试过。

另一方面,当尝试使用git-svn dcomits进行git时,git-stash命令是天赐之物。

一个典型的过程:

  1. 设置git repo
  2. 在不同的文件上做一些工作
  3. 决定检查一些工作,使用git
  4. 决定svn-dcommit
  5. 得到可怕的“无法使用脏索引提交”错误。

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

git stash; git svn dcommit ; git stash apply

有效地将Git与Subversion结合使用是对git-svn的简单介绍。对于现有的SVN存储库,git-svn让这变得非常容易。如果你要开始一个新的存储库,首先创建一个空的SVN存储库,然后使用git-svn导入要比相反的方向容易得多。创建一个新的Git存储库然后导入到SVN是可以完成的,但这有点痛苦,特别是如果你是Git新手并希望保留提交历史记录。

创建一个用户文件(即users.txt),用于将SVN用户映射到Git:

user1 = First Last Name <email@address.com>user2 = First Last Name <email@address.com>...

您可以使用此单行代码从现有的SVN存储库构建模板:

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

如果找到丢失的SVN用户,SVN将停止,而不是在文件中。但在那之后,您可以更新文件并从中断的地方继续。

现在从存储库中提取SVN数据:

git svn clone --stdlayout --no-metadata --authors-file=users.txt svn://hostname/path dest_dir-tmp

此命令将在dest_dir-tmp中创建一个新的Git存储库并开始提取SVN存储库。请注意,“--std布局”标志意味着您有常见的“主干/、分支/、标签/”SVN布局。如果您的布局不同,请熟悉--tags--branches--trunk选项(一般为git svn help)。

允许所有常见协议:svn://http://https://。URL应该以基本存储库为目标,类似于http://svn.mycompany.com/myrepo/repository。URL字符串没有必须包含/trunk/tag/branches

请注意,在执行此命令后,它通常看起来像操作是“挂起/冻结”,并且在初始化新存储库后它可能会卡住很长时间是很正常的。最终,你会看到表明它正在迁移的日志消息。

另请注意,如果您省略了--no-metadata标志,Git将在提交消息中附加有关相应SVN修订的信息(即git-svn-id: svn://svn.mycompany.com/myrepo/<branchname/trunk>@<RevisionNumber> <Repository UUID>

如果未找到用户名,请更新您的users.txt文件:

cd dest_dir-tmpgit svn fetch

如果您有一个大项目,您可能需要重复最后一个命令几次,直到所有Subversion提交都被获取:

git svn fetch

完成后,Git将把SVNtrunk签出到一个新的分支中。任何其他分支都设置为远程。您可以使用以下命令查看其他SVN分支:

git branch -r

如果您想在存储库中保留其他远程分支,则需要手动为每个分支创建一个本地分支。(跳过主干/主干。)如果不这样做,分支将不会在最后一步中被克隆。

git checkout -b local_branch remote_branch# It's OK if local_branch and remote_branch are the same names

标签作为分支导入。您必须创建一个本地分支,制作一个标签并删除分支才能将它们作为Git中的标签。要使用标签“v1”执行此操作:

git checkout -b tag_v1 remotes/tags/v1git checkout mastergit tag v1 tag_v1git branch -D tag_v1

将您的GIT-SVN存储库克隆到一个干净的Git存储库中:

git clone dest_dir-tmp dest_dirrm -rf dest_dir-tmpcd dest_dir

您之前从远程分支创建的本地分支只会作为远程分支复制到新克隆的存储库中。(跳过主干/主干。)对于您要保留的每个分支:

git checkout -b local_branch origin/remote_branch

最后,从指向现已删除的临时存储库的干净Git存储库中删除远程:

git remote rm origin

我用了svn2git脚本,像魅力一样工作。

我强烈推荐我刚刚发现的这个短片系列。作者将引导您完成基本操作,并展示一些更高级的用法。

有一个新的解决方案可以从Subversion平滑迁移到Git(或同时使用两者):subgit

我自己也在做这个项目。我们在我们的存储库中使用SubGit——我的一些队友使用Git和一些Subversion,到目前为止它运行得很好。

要使用SubGit从Subversion迁移到Git,您需要运行:

$ subgit install svn_repos...TRANSLATION SUCCESSFUL

之后,您将在svn_repos/. git中获得Git存储库并可以克隆它,或者继续一起使用Subversion和这个新的Git存储库:SubGit将确保两者始终保持同步。

如果您的Subversion存储库包含多个项目,那么将在svn_repos/git目录中创建多个Git存储库。要在运行之前自定义翻译,请执行以下操作:

$ subgit configure svn_repos$ edit svn_repos/conf/subgit.conf (change mapping, add authors mapping, etc)$ subgit install svn_repos

使用subgit,您可以迁移到纯Git(而不是git-svn)并开始使用它,同时仍然保留Subversion,只要您需要它(例如,对于您已经配置的构建工具)。

希望这有帮助!

我只是想为Git社区做出贡献。我写了一个简单的bash脚本,它可以自动完成完全导入。与其他迁移工具不同,这个工具依赖于原生git而不是jGit。这个工具还支持具有大修订历史记录和/或大blob的存储库。它可以通过github获得:

此脚本将使用以下格式转换存储在SVN中的项目:

/trunk/Project1/Project2/branches/Project1/Project2/tags/Project1/Project2

这个方案也很受欢迎和支持:

/Project1/trunk/branches/tags/Project2/trunk/branches/tags

每个项目将通过项目名称进行同步:

Ex: ./migration https://svnurl.com/basepath project1

如果您希望转换完整的存储库,请使用以下语法:

Ex: ./migration https://svnurl.com/basepath .

TortoiseGit就是这样做的。看到这个博客文章:http://jimmykeen.net/articles/03-nov-2012/how-migrate-from-svn-to-git-windows-using-tortoise-clients

是的,我知道用链接回答不是很好,但这是一个解决方案,嗯?

一个只使用git、SVN和bash的稍微扩展的答案。它包括SVN存储库的步骤,这些存储库不使用具有主干/分支/标签目录布局的传统布局(SVN绝对没有强制执行这种布局)。

首先使用此bash脚本扫描您的SVN存储库以查找贡献的不同人员,并为映射文件生成模板:

#!/usr/bin/env bashauthors=$(svn log -q | grep -e '^r' | awk 'BEGIN { FS = "|" } ; { print $2 }' | sort | uniq)for author in ${authors}; doecho "${author} = NAME <USER@DOMAIN>";done

使用它来创建一个authors文件,您可以将svn用户名映射到用户名和电子邮件,由开发人员使用#1属性user.nameuser.email设置(请注意,对于像GitHub这样的服务,只有匹配的电子邮件就足够了)。

然后让#0将svn存储库克隆到git存储库,告诉它映射:

git svn clone --authors-file=authors --stdlayout svn://example.org/Folder/projectroot

这可能需要非常长的时间,因为git svn将单独检查每个存在的标签或分支的每个版本。(请注意,SVN中的标签只是真正的分支,所以它们在Git中最终是这样的)。你可以通过删除SVN中不需要的旧标签和分支来加速这一点。

在同一网络或同一服务器上的服务器上运行它也可以真正加快速度。此外,如果由于某种原因此过程被中断,您可以使用

git svn rebase --continue

在很多情况下,你在这里完成了。但是,如果您的SVN存储库有一个非常规的布局,您只需在SVN中有一个目录,您就想放在一个git分支中,您可以执行一些额外的步骤。

最简单的方法是在您的服务器上创建一个新的SVN存储库,该存储库遵循约定并使用svn copy将您的目录放在主干或分支中。如果您的目录一直位于存储库的根目录,这可能是唯一的方法,当我上次尝试时,这个git svn只是拒绝进行签出。

您也可以使用git执行此操作。对于git svn clone,只需使用您要放入git分支的目录。

跑步后

git branch --set-upstream master git-svngit svn rebase

请注意,这需要Git 1.7或更高版本。

这是一个没有依赖关系的简单外壳脚本,它将一个或多个SVN存储库转换为git并将它们推送到GitHub。

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

我经历了很多痛苦,将十几个SVN存储库从Google Code转移到GitHub。我使用Windows没有帮助。Ruby在我的旧Debian盒子上各种各样的坏了,让它在Windows上工作是一个笑话。其他解决方案无法与Cygwin路径一起工作。即使我有了一些工作,我也不知道如何让标签显示在GitHub上(秘密是——跟踪标签)。

最后,我拼凑了两个简短的脚本,链接在上面,它工作得很好。解决方案不需要比这更复杂!

在Atlassian网站上的这个指南是我找到的最好的指南之一:

https://www.atlassian.com/git/migration

这个工具-https://bitbucket.org/atlassian/svn-migration-scripts-对于生成authors.txt也非常有用。

如果您使用的是SourceTree,您可以直接从应用程序中执行此操作。转到文件->新建/克隆,然后执行以下操作:

  1. 输入远程SVN URL作为“源路径/URL”。
  2. 出现提示时输入凭据。
  3. 输入本地文件夹位置作为“目标路径”。
  4. 给它一个名字。
  5. 在高级选项中,从“创建本地”的下拉列表中选择“Git”类型的存储库".
  6. 您可以选择指定要克隆的修订版。
  7. 点击克隆。

在SourceTree中打开repo,您将看到您的提交消息也已迁移。

现在转到存储库->存储库设置并添加新的远程存储库详细信息。如果您愿意,请删除SVN远程(我通过“编辑配置文件”选项执行此操作。

准备好后将代码推送到新的远程存储库并自由编码。

您必须安装

gitgit-svn

复制自此链接http://john.albin.net/git/convert-subversion-to-git

1.检索所有Subversion提交者的列表

Subversion简单地列出了每次提交的用户名。Git的提交数据要丰富得多,但最简单的是,提交作者需要列出姓名和电子邮件。默认情况下,git-svn工具只会在作者和电子邮件字段中列出SVN用户名。但是只要做一点工作,你就可以创建一个所有SVN用户的列表以及他们对应的Git名称和电子邮件是什么。git-svn可以使用这个列表将普通的svn用户名转换为合适的Git提交者。

从本地Subversion签出的根目录,运行以下命令:

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

这将获取所有日志消息,提取用户名,消除任何重复的用户名,对用户名进行排序并将它们放入“authors-transform.txt”文件中。现在编辑文件中的每一行。例如,转换:

jwilkins = jwilkins <jwilkins>

到这个:

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

2.使用git-svn克隆Subversion仓库

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

这将执行标准的git-svn转换(使用您在步骤1中创建的authors-transform.txt文件),并将git存储库放置在主目录中的“~/temp”文件夹中。

3.将svn:忽略属性转换为. gitignore

如果您的svn存储库使用的是svn:忽略属性,您可以使用以下命令轻松将其转换为. gitignore文件:

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

4.将存储库推送到裸git存储库

首先,创建一个裸存储库并使其默认分支与svn的“主干”分支名称匹配。

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

然后将临时存储库推送到新的裸存储库。

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

您现在可以安全地删除~/temp存储库。

5.将“主干”分支重命名为“主”

您的主要开发分支将被命名为“主干”,与它在Subversion中的名称相匹配。您需要使用以下方法将其重命名为Git的标准“master”分支:

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

6.清理树枝和标签

git-svn将所有Subversion标签变成Git中“tags/name”形式的很短的分支。您需要使用以下方法将所有这些分支转换为实际的Git标签:

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

:-)但是,不要担心;您的unix shell将为以git for-each-ref开头的超长命令提供>次要提示符。

对于GitLab用户,我在这里列出了我如何从SVN迁移的要点:

https://gist.github.com/leftclickben/322b7a3042cbe97ed2af

从SVN迁移到GitLab的步骤

设置

  • SVN托管在svn.domain.com.au
  • SVN可以通过http访问(其他协议应该可以工作)。
  • GitLab托管在git.domain.com.au并且:
    • 使用命名空间dev-team创建一个组。
    • 至少创建了一个用户帐户,将其添加到组中,并且具有用于迁移的帐户的SSH密钥(使用ssh git@git.domain.com.au进行测试)。
    • 项目favourite-projectdev-team命名空间中创建。
  • 文件users.txt包含相关用户详细信息,每行一个用户,格式为username = First Last <address@domain.com.au>,其中username是SVN日志中给出的用户名。(有关详细信息,请参阅参考资料部分中的第一个链接,特别是用户Casey的回答)。

版本

  • 颠覆版本1.6.17(r1128011)
  • git版本1.9.1
  • GitLab版本7.2.1 ff1633f
  • Ubuntu服务器14.04

命令

bashgit svn clone --stdlayout --no-metadata -A users.txthttp://svn.domain.com.au/svn/repository/favourite-projectcd favourite-projectgit remote add gitlab git@git.domain.com.au:dev-team/favourite-project.gitgit push --set-upstream gitlab master

就是这样!在GitLab Web UI中重新加载项目页面,您将看到现在列出的所有提交和文件。

备注

  • 如果有未知用户,git svn clone命令将停止,在这种情况下,更新users.txtcd favourite-projectgit svn fetch将从停止的地方继续。
  • 需要SVN存储库的标准trunk-tags-branches布局。
  • git svn clone命令的SVN URL停止在trunk/tags/branches/之上的级别。
  • git svn clone命令会产生很多输出,包括顶部的一些警告;我忽略了警告。

subgit(vs蓝屏死机)

subgit import --svn-url url://svn.serv/Bla/Bla  directory/path/Local.git.Repo

就这些了。

+要从SVN更新,第一个命令创建一个Git存储库。

subgit import  directory/path/Local.git.Repo

我使用了一种方法立即迁移到Git以获得一个巨大的存储库。
当然,你需要一些准备。
但是你可能根本不会停止开发过程。

这是我的方式。

我的解决方案看起来像:

  • 将SVN迁移到Git存储库
  • 在团队切换到Git之前更新Git存储库

对于一个大的SVN存储库来说,迁移需要很多时间。
但是更新完成的迁移只需几秒钟。

当然,我正在使用subgit,妈妈。git-svn让我蓝屏死亡。只是不断。而git-svn让我对Git的“文件名太长”致命错误感到厌烦。

步骤

1.下载SubGit

2.准备迁移和更新命令。

假设我们是为Windows做的(移植到Linux很简单)。
在SubGit的安装bin目录(subgit-2. X. X\bin)中,创建两个. bat文件。

迁移文件/命令的内容:

start    subgit import --svn-url url://svn.serv/Bla/Bla  directory/path/Local.git.Repo

“start”命令在这里是可选的(Windows)。它允许在启动时查看错误,并在SubGit完成后打开一个shell。

您可以在此处添加类似git-svn的附加参数。我只使用#myCompanyDomain.com来修复SVN作者电子邮件地址的域。
我有标准的SVN存储库的结构(主干/分支/标签),我们没有“作者映射”的麻烦。所以我什么都不做了。

(如果您想迁移分支之类的标签,或者您的SVN有多个分支/标签文件夹,您可以考虑使用更详细的SubGit方法)

提示1:使用--minumteveYourSvnRevNumber快速查看事情是如何沸腾的(某种调试)。特别有用的是查看已解析的作者姓名或电子邮件。或者限制迁移历史深度。

提示2:迁移可能会中断(Ctrl+C)并通过运行下一个更新命令/文件来恢复。
我不建议这样做大存储库。我收到“内存不足Java+Windows异常”。

提示3:最好创建结果裸存储库的副本。

用于更新的文件/命令的内容:

start    subgit import  directory/path/Local.git.Repo

当您想要获取最后一个团队对您的Git存储库的提交时,您可以运行它任何时间。

警告!不要碰你的裸存储库(例如创建分支)。
下一个致命错误:

无法恢复的错误:不同步,无法同步…将Subversion修订翻译为Git提交…

3.运行第一个命令/文件。对于一个大的存储库来说需要很长的时间。对于我不起眼的存储库,需要30个小时。

就这样
您可以通过运行第二个文件/命令随时从SVN更新您的Git存储库。在将您的开发团队切换到Git之前。
只需要几秒钟



还有一个更有用的任务。

将您的本地Git存储库推送到远程Git存储库

这是你的案子吗?让我们继续。

  1. 配置您的遥控器

运行:

$ git remote add origin url://your/repo.git
  1. 准备将巨大的本地Git存储库初始发送到远程存储库

默认情况下,您的Git无法发送大块。致命:远程端意外挂断

让我们为它奔跑:

git config --global http.postBuffer 1073741824

524288000-500 MB1073741824-1 GB等

修复您的本地证书问题。如果您的git-server使用损坏的证书。

我已禁用证书。

您的Git服务器也可能有请求金额限制需要更正

  1. 推动所有迁移到团队的远程Git存储库。

使用本地Git运行:

git push origin --mirror

git推送来源'*:*'对于旧的Git版本)

如果您得到以下结果:错误:无法生成git:没有这样的文件或目录…对我来说,完全重新创建我的存储库解决了这个错误(30小时)。您可以尝试下一个命令

git push origin --allgit push origin --tags

或者尝试重新安装git对我没用)。或者您可以从所有标签创建分支并推送它们。或者,或者,或者…

对于复杂的情况,Eric S. Raymond的存储库是首选的工具。除了SVN之外,它还通过fast-export格式支持许多其他版本控制系统,还有CVS。作者报告了EmacsFreeBSD等古老存储库的成功转换。

该工具显然是旨在实现近乎完美的转换(例如将SVN的svn:ignore属性转换为.gitignore文件),即使对于历史悠久的困难存储库布局也是如此。在许多情况下,其他工具可能更容易使用。

在深入研究reposurgeon命令行的留档之前,请务必阅读出色的DVCS迁移指南,它逐步介绍了转换过程。

下载适用于Windows的Ruby安装程序并使用它安装最新版本。将Ruby可执行文件添加到您的路径。

  • 安装svn2git
  • 开始菜单->所有程序->Ruby->使用Ruby启动命令提示符
  • 然后键入“gem install svn2git”并输入

    Migrate Subversion存储库

  • 打开Ruby命令提示符并转到要迁移文件的目录

    然后svn2git超文本传输协议:// name]/svn/[仓库根]

  • 将项目迁移到Git可能需要几个小时,具体取决于项目代码大小。

  • 这个主要步骤有助于创建下面提到的Git存储库结构。

    SVN(/Project_components)主干-->Git masterSVN(/Project_components)分支-->Git分支SVN(/Project_components)标签-->Git标签

创建远程存储库并推送更改。

GitHub有一个导入器。创建存储库后,您可以通过其URL从现有存储库导入。它会询问您的凭据(如果适用)并从那里开始。

当它运行时,它会找到作者,你可以简单地将它们映射到GitHub上的用户。

我现在已经在几个存储库中使用了它,它非常准确,速度也快得多!一个大约4000次提交的存储库花了10分钟,之后我的朋友花了四天时间!

这里的几个答案指的是https://github.com/nirvdrum/svn2git,但对于大型存储库,这可能会很慢。我尝试使用https://github.com/svn-all-fast-export/svn2git,这是一个名称完全相同的工具,但用于将KDE从SVN迁移到Git。

稍微多一点的工作来设置它,但是当完成转换本身对我来说需要几分钟,而其他脚本需要几个小时。

有不同的方法可以实现这个目标。我尝试了其中的一些,发现在Windows操作系统上只安装了git和svn就可以真正工作。

先决条件:

  1. Windows上的git(我用过这个)https://git-scm.com/
  2. 安装了控制台工具的svn(我用过陆龟svn)
  3. SVN存储库的转储文件。svnadmin dump /path/to/repository > repo_name.svn_dump

实现最终目标的步骤(将所有具有历史记录的存储库移动到git,首先是本地git,然后是远程git)

  1. 在目录中创建空存储库(使用控制台工具或tortoiseSVN)REPO_NAME_FOLDERcd REPO_NAME_PARENT_FOLDER,将dumpfile.dump放入REPO_NAME_PARENT_FOLDER

  2. svnadmin load REPO_NAME_FOLDER < dumpfile.dump等待这个操作,可能会很长

  3. 这个命令是静默的,所以打开第二个cmd窗口:svnserve -d -R --root REPO_NAME_FOLDER为什么不直接使用file:///……?因为下一个命令将以Unable to open ... to URL:失败,感谢答案https://stackoverflow.com/a/6300968/4953065

  4. 创建新文件夹SOURCE_GIT_FOLDER

  5. cd SOURCE_GIT_FOLDER
  6. git svn clonesvn://localhost/等待此操作。

最后,我们得到了什么?

让我们检查我们的本地存储库:

git log

-看到你以前的记录了吗?-好的

所以现在您拥有功能齐全的本地git存储库,其中包含您的源代码和旧的svn历史记录。现在,如果您想将其移动到某个服务器,请使用以下命令:

git remote add origin https://fullurlpathtoyourrepo/reponame.gitgit push -u origin --all # pushes up the repo and its refs for the first timegit push -u origin --tags # pushes up any tags

在我的情况下,我不需要标签命令,因为我的仓库没有标签。

祝你好运!

我已经发布了一个将svn转换为git的分步指南(这里),包括将svn标签转换为git标签,将svn分支转换为git分支。

简短版本:

1)从特定的版本号克隆svn。(版本号必须是您要迁移的最旧版本)

git svn clone --username=yourSvnUsername -T trunk_subdir -t tags_subdir -b branches_subdir -r aRevisionNumber svn_url gitreponame

2)获取svn数据。这一步花费的时间最多。

cd gitreponamegit svn fetch

重复git svn提取,直到完成而没有错误

3)获取主分支更新

git svn rebase

4)通过复制引用从svn分支创建本地分支

cp .git/refs/remotes/origin/* .git/refs/heads/

5)将svn标签转换为git标签

git for-each-ref refs/remotes/origin/tags | sed 's#^.*\([[:xdigit:]]\{40\}\).*refs/remotes/origin/tags/\(.*\)$#\2 \1#g' | while read p; do git tag -m "tag from svn" $p; done

6)把仓库放在一个更好的地方,比如github

git remotes add newrepo git@github.com:aUser/aProjectName.gitgit push newrepo refs/heads/*git push --tags newrepo

如果你想要更多的细节,请阅读我的帖子或问我。

我们可以使用git svn clone命令,如下所示。

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

上面的命令将从SVN提交创建作者文件。

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

上面的命令将在创建SVN项目时为您提供第一个版本号。

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

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

问题是它不会将分支和标签转换为推送。你将不得不手动执行它们。例如下面的分支:

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

对于标签:

$git checkout origin/tags/MyDevBranch-1.0Note: checking out 'origin/tags/MyDevBranch-1.0'.You are in 'detached HEAD' state. You can look around, make experimentalchanges and commit them, and you can discard any commits you make in thisstate without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you maydo 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)MyDevBranchmasterremotes/origin/MyDevBranchremotes/origin/tags/MyDevBranch-1.0remotes/origin/trunk$ git tag -a MyDevBranch-1.0 -m "creating tag"$git tagMyDevBranch-1.0$

现在将master、分支和标签推送到远程git存储库。

$ git push origin master MyDevBranch MyDevBranch-1.0Counting 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实用程序删除了使用分支和标签的手动工作。

使用命令sudo gem install svn2git安装它。之后运行下面的命令。

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

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

$ git remote add origin https://github.com/pankaj0323/JDProjects.git$ git branch -aMyDevBranch* masterremotes/svn/MyDevBranchremotes/svn/trunk$ git tagMyDevBranch-1.0$ git push origin master MyDevBranch MyDevBranch-1.0

假设您有20个分支和标签,显然svn2git会为您节省大量时间,这就是为什么我更喜欢它而不是本机命令。它是本机git svn clone命令的一个很好的包装器。

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

将svn子模块/文件夹“MyModul”转换为没有标签和分支的历史记录的git。

要保留svn忽略列表,请在步骤1之后使用上述注释

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

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

list.txt格式:

repo1_namerepo2_name

users.txt格式:

(no author) = Prince Rogers <prince.rogers.nelson@payesley.park.org>

www-data是Apache Web服务器用户,需要权限才能通过HTTP推送更改。

我在Windows机器上,做了一个小批处理,通过调用将具有历史记录(但没有分支)的SVN存储库转移到GIT存储库

transfer.bat http://svn.my.address/svn/myrepo/trunk https://git.my.address/orga/myrepo

也许任何人都可以使用它。它创建了一个TMP文件夹,使用git签出那里的SVN存储库,并添加新的源并推送它…并再次删除该文件夹。

@echo offSET FROM=%1SET TO=%2SET TMP=tmp_%random%
echo from:  %FROM%echo to:    %TO%echo tmp:   %TMP%
pause
git svn clone  --no-metadata --authors-file=users.txt %FROM% %TMP%cd %TMP%git remote add origin %TO%git push --set-upstream origin master

cd ..echo delete %TMP% ...pause
rmdir /s /q %TMP%

您仍然需要users.txt与您的用户映射,如

User1 = User One <u.1@xxx.com>

为此,我使用svn2git库执行以下过程:

sudo apt-get安装git-core git-svn ruby
sudo gem安装svn2git
svn log--安静|grep-E"r[0-9]+ \| .+ \|" | Cut-d'|'-f2|ses's//g'|sort|uniq>authors.txt(此命令用于映射作者)

上述步骤应在您要从svn转换为git的文件夹中执行。

像这样在authors.txt中每行添加一个映射

anand = Anand Tripathi <email_id>trip = Tripathi Anand <email_id>

为新的git存储库创建一个文件夹并执行下面的命令,路径为authors.txt

svn2git <svn_repo_path> --nobranches --notags --notrunk --no-minimize-url --username <user_name> --verbose  --authors <author.txt_path>
If no trunk and no tag and branch is present then have to execute the above command else if root is trunk then mention rootistrunk or trunk is present then --trunk <trunk_name>

git远程添加来源
git ush--所有来源
#删除推送源

首先,归功于@cmcgint的回答。这对我来说是一个很好的起点,我将在这里发布的大部分内容都借鉴了它。然而,我移动的repos有多年的历史,这导致了一些问题(数百个分支和标签需要手动移动一个;稍后阅读更多)。

因此,经过几个小时的搜索和试验和错误,我能够整理一个脚本,使我能够轻松地将几个项目从SVN移动到GIT,我决定在这里分享我的发现,以防其他人处于我的位置。

我们开始吧


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

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

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

someuser = someuser <someuser>

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

someuser = Some User <someuser@somewhere.com>

现在使用您的作者文件启动克隆

git svn clone --stdlayout --no-metadata -r854:HEAD --authors-file=authors-transform.txt https://somesvnserver/somerepo/ temp
  • svn存储库遵循标准 /trunk /branches /tags布局
  • --no-元数据告诉git不要在每个git提交上盖章与svn提交相关的元数据。如果这不是单向转换,请删除此标签
  • -r854: HEAD仅从版本854获取历史记录。这是我遇到的第一个障碍;我转换的存储库在版本853有一个损坏的提交,所以它不会克隆。使用此参数允许您仅克隆部分历史记录。
  • temp是要初始化的目录的名称新的git repo

这一步可能需要一段时间,特别是在大型或旧的存储库上(我们的一个存储库大约需要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

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

现在是查看新存储库的好时机,并确保您有一个当地分支或标记来保存您想要保留的任何内容,因为远程分支将在稍后被删除。

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

cd ..git clone temp temp2cd temp2

现在,我们需要在将所有分支推送到最终远程之前再次检查所有分支,因此请从上面按照您最喜欢的方法进行操作。

如果您遵循gitflow,您可以重命名您的工作分支以进行开发。

git checkout -b WORKINGgit branch -m developgit push origin --delete WORKINGgit push origin -u develop

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

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

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

All in One-SVNGIT迁移的外壳脚本。使用占位符<>提及GITSVN详细信息

#!/bin/bash
######## Project namePROJECT_NAME="Helloworld"EMAIL="example mail"
#Credientials RepoGIT_USER='<git username>'GIT_PWD='<git password>'SVN_USER='<svn username>'SVN_PWD='<svn password>'
######## SVN repository to be migrated # Dont use https - error will be thrownBASE_SVN="<SVN URL>/Helloworld"
#Organization inside BASE_SVNBRANCHES="branches"TAGS="tags"TRUNK="trunk"
#Credientialsgit config --global user.name '<git username>'git config --global user.password '<git password>'git config --global credential.helper 'cache --timeout=3600'
######## GIT repository to migrate - Ensure already project created in GitGIT_URL=https://$GIT_USER:$GIT_PWD@<GIT URL>/Helloworld.git
############################### Don't need to change from here###########################
#Geral ConfigurationABSOLUTE_PATH=$(pwd)TMP=$ABSOLUTE_PATH/$PROJECT_NAME
#Branchs ConfigurationSVN_BRANCHES=$BASE_SVN/$BRANCHESSVN_TAGS=$BASE_SVN/$TAGSSVN_TRUNK=$BASE_SVN/$TRUNK
AUTHORS=$PROJECT_NAME"-authors.txt"
echo '[LOG] Starting migration of '$SVN_TRUNKecho '[LOG] Using: '$(git --version)echo '[LOG] Using: '$(svn --version | grep svn,)
mkdir $TMPechoecho '[DIR] cd' $TMPcd $TMP
echoecho '[LOG] Getting authors'svn --username $SVN_USER --password $SVN_PWD log -q $BASE_SVN | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2"@"$EMAIL">"}' | sort -u >> $AUTHORS
echoecho '[RUN] git svn clone --authors-file='$AUTHORS' --trunk='$TRUNK' --branches='$BRANCHES' --tags='$TAGS $BASE_SVN $TMPgit svn clone --authors-file=$AUTHORS --trunk=$TRUNK --branches=$BRANCHES --tags=$TAGS $BASE_SVN $TMP
#Not working so no need to mention it#--stdlayout $PROJECT_NAMEechoecho '[RUN] svn ls '$SVN_BRANCHESsvn ls $SVN_BRANCHES
echoecho 'git branch -a'git branch -a
echoecho '[LOG] Getting first revision'FIRST_REVISION=$( svn log -r 1:HEAD --limit 1 $BASE_SVN | awk -F '|' '/^r/ {sub("^ ", "", $1); sub(" $", "", $1); print $1}' )
echoecho '[RUN] git svn fetch -'$FIRST_REVISION':HEAD'git svn fetch -$FIRST_REVISION:HEAD
#Branches and Tagsechoecho '[RUN] svn ls '$SVN_BRANCHESfor BRANCH in $(svn ls $SVN_BRANCHES); doecho git branch ${BRANCH%/} remotes/svn/${BRANCH%/}git branch ${BRANCH%/} remotes/svn/${BRANCH%/}done
git for-each-ref --format="%(refname:short) %(objectname)" refs/remotes/origin/tags | grep -v "@" | cut -d / -f 3- |while read refdoecho git tag -a $ref -m 'import tag from svn'git tag -a $ref -m 'import tag from svn'done
git for-each-ref --format="%(refname:short)" refs/remotes/origin/tags | cut -d / -f 1- |while read refdogit branch -rd $refdone  
echoecho 'git tag'git tag
echoecho 'git show-ref --tags'git show-ref --tags
echoecho '[RUN] git remote add origin '$GIT_URLgit remote add origin $GIT_URL
echoecho '[RUN] git push'git push origin --all --forcegit push origin --tags
#echo git branch -d -r trunk#git branch -d -r trunk
git config --global credential.helper cacheecho 'Successful.'
  • 当您运行上述脚本时,它将从SVN获取分支和标签详细信息并将其放在.git文件夹下。
  • 交叉检查是否所有分支都在SVN中,应该在此.git/refs/heads文件夹下可用。
  • 如果缺少SVN中的某些分支,则手动将分支文件从.git/refs/remotes/origin/<branches>复制到.git/refs/heads
  • 仅复制分支(包括master)并忽略任何tagstrunk
  • 现在再次运行脚本。您可以在git存储库中看到所有branchestags