将现有的Git存储库推送到SVN


384

我一直在Git中完成所有工作,并推送到GitHub。我对软件和站点都感到非常满意,并且目前我不希望更改自己的工作方式。

我的博士顾问要求所有学生将他们的工作保存在该大学托管的SVN存储库中。我已经找到了大量有关将现有SVN信息库放入Git的文档和教程,但没有关于将Git信息库推送到新的SVN信息库的内容。我希望一定有某种方法可以将git-svn和一个新鲜的分支,重新定级以及所有这些奇妙的条件结合起来使用,但是我是Git新手,对任何一个都不感到自信。

然后,当我选择时,我只想运行几个命令即可将提交推送到该SVN存储库。我希望继续使用Git,只是让SVN存储库镜像Git中的内容。

如果有任何不同,我将是唯一致力于SVN的人。


1
注意:执行此操作可能会丢失原始的日期戳。新日期将基于导入到Subversion的时间。
nobar 2013年

对于那些寻找更多的最新消息一些可以自己搜索到的自动化过程中发现以下职位有帮助:deliciousbrains.com/deploying-wordpress-plugins-travis
乔希Habdas

Answers:


402

我也需要这个,并且在Bombe的答案和一些摆弄的帮助下,我开始了它的工作。这是食谱:

导入Git-> Subversion

1. cd /path/to/git/localrepo
2. svn mkdir --parents protocol:///path/to/repo/PROJECT/trunk -m "Importing git repo"
3. git svn init protocol:///path/to/repo/PROJECT -s
4. git svn fetch
5. git rebase origin/trunk
5.1.  git status
5.2.  git add (conflicted-files)
5.3.  git rebase --continue
5.4.  (repeat 5.1.)
6. git svn dcommit

在#3之后,您将获得如下所示的隐秘消息:

使用更高级别的URL: protocol:///path/to/repo/PROJECT => protocol:///path/to/repo

只是忽略这一点。

当您运行#5时,可能会遇到冲突。通过添加状态为“未合并”的文件并恢复基准来解决这些问题。最终,您会完成;然后使用同步回SVN存储库dcommit。就这样。

保持存储库同步

现在,您可以使用以下命令从SVN同步到Git:

git svn fetch
git rebase trunk

要从Git同步到SVN,请使用:

git svn dcommit

最后说明

在应用到实时存储库之前,您可能希望在本地副本上进行尝试。您可以将Git存储库的副本复制到一个临时位置。只需使用cp -r,因为所有数据都在存储库本身中。然后,您可以使用以下方法建立基于文件的测试存储库:

svnadmin create /home/name/tmp/test-repo

并使用以下命令检出工作副本:

svn co file:///home/name/tmp/test-repo svn-working-copy

这样,您就可以在进行任何持久更改之前先尝试一下。

附录:如果您搞砸了 git svn init

如果您不小心git svn init使用了错误的URL 运行,并且您不够聪明,无法备份您的工作(不要问...),则不能仅再次运行同一命令。但是,您可以通过发出以下命令来撤消更改:

rm -rf .git/svn
edit .git/config

并删除节[svn-remote "svn"]部分。

然后,您可以重新运行git svn init


2
好答案。这还会搞乱提交日期吗?
德鲁·诺阿克斯

4
好问题-不幸的是,我都不知道答案。这是我发现可行的实用指南。我不完全了解所有细节。关于提交日期,我想您可以进行测试并找出答案。请记住,您可以初始化本地(基于fs的)svn存储库,以进行测试。
troelskn 2010年

10
我已经使用“ git rebase --onto trunk --root”代替了步骤5,执行了相同的步骤,并且获得更多的成功。只有少数合并冲突需要解决,而不是吨。
kubi

5
在我的情况下,此顺序无效。总是显示一条消息“无法从HEAD历史确定上游SVN信息”。因此,没有可能提交。
Fedir RYKHTIK '01年

2
没关系,我试图变得聪明一点,并省略了-s,因为我不想遵循SVN标准设置(主干/分支/标签/)。没有它,就无法使其正常工作。
詹姆斯·麦克马洪

33

这是我们使其运作的方式:

在您机器上的某个地方克隆您的Git存储库。

打开.git / config并添加以下内容(从维护Git存储库的只读SVN镜像):

[svn-remote "svn"]
    url = https://your.svn.repo
    fetch = :refs/remotes/git-svn

现在,从控制台窗口中键入以下内容:

git svn fetch svn
git checkout -b svn git-svn
git merge master

现在,如果由于任何原因在此处中断,请键入以下三行:

git checkout --theirs .
git add .
git commit -m "some message"

最后,您可以使用SVN:

git svn dcommit

注意:此后我总是会废弃该文件夹。


6
+1这实际上对我Unable to determine upstream SVN information from HEAD history.
有用


2
我尝试了这种技术,但是没有导入历史记录。顺便说一句,“ git merge master”现在是“ git merge --allow-unrelated-histories master”
Berend de Boer 2016年

1
如果您绝对想用git中的内容覆盖SVN中的内容,请使用git merge -s recursive -Xtheirs --allow-unrelated-histories master
user1475814

28

使用git rebase直接将失去第一次提交。Git对待它与众不同,因此无法对其进行基础调整。

有一个可以保留完整历史记录的过程:http : //kerneltrap.org/mailarchive/git/2008/10/26/3815034

我将在此处转录解决方案,但要感谢Björn。

初始化git-svn:

git svn init -s --prefix=svn/ https://svn/svn/SANDBOX/warren/test2

--prefix为您提供了诸如“ svn / trunk”之类的远程跟踪分支,这很好,因为如果您将本地分支称为“ trunk”,则不会得到含糊不清的名称。并且-s是标准主干/标签/分支布局的快捷方式。

从SVN获取初始内容:

git svn fetch

现在查找您的根提交的哈希值(应该显示一个提交):

git rev-list --parents master | grep '^.\{40\}$'

然后获取空主干提交的哈希值:

git rev-parse svn/trunk

创建移植:

echo <root-commit-hash> <svn-trunk-commit-hash> >> .git/info/grafts

现在,“ gitk”应该显示svn/trunk为您的master分支所基​​于的第一个提交。

使移植物永久:

git filter-branch -- ^svn/trunk --all

放下嫁接物:

rm .git/info/grafts

gitk应该仍然显示svn/trunk在master的祖先中。

在主干上线性化您的历史记录:

git svn rebase

现在,“ git svn dcommit -n”应该告诉您它将要提交到主干。

git svn dcommit

您能否更清楚地说明此技术与上面的区别。
cmcginty

3
当我尝试“ git rev-parse svn / trunk”时,它报告未知的修订或路径不在工作树中。
亚当·内斯

这是唯一对我有用的答案,除了不需要git filter-branch和dropgraf的步骤:创建移植后我做了一个变基,然后git svn dcommit。
fc7

8

在Subversion存储库中为您的项目创建一个新目录。

# svn mkdir --parents svn://ip/path/project/trunk

转到您的Git管理的项目并初始化git-svn。

# git svn init svn://ip/path/project -s
# git svn fetch

这将创建一个提交,因为您的SVN项目目录仍然为空。现在,所有内容都基于该提交,git svn dcommit您应该完成了。但是,它将严重破坏您的提交日期。


我按照hassox.blogspot.com/2007/12/using-git-with-svn.html的说明使用了此答案, 我遵循了以下命令,然后单击 “ #git branch -a”以查看中继名称。然后:#git checkout -b local-svn干线#git merge master#git svn dcommit记住要.gitignore .svn目录!
cflewis

当我执行相同的操作时,我想明确指出,一段时间(09年1月),git可以对根提交执行rebase操作。这使该过程比许多旧文章所表明的要简单得多,请参阅其评论。arubything.com/ 2009/1/4 /…
Louis Jacomet 2010年

“ -s” git svn init选项有什么作用?我在git svn的手册页中看不到这一点。
弥敦道

再次阅读手册页,也许搜索“ -s”,因为它在那里。它是“ --stdlayout”的别名。
孟买

7

Git->具有完整提交历史记录的SVN

我有一个Git项目,不得不将其移至SVN。这就是我的方法,保留了整个提交历史。唯一丢失的是原始提交时间,因为libSVN在执行操作时会设置本地时间git svn dcommit

如何:

  1. 有一个SVN存储库,我们想将我们的东西导入其中,并用git-svn克隆它:

    git svn clone https://path.to/svn/repository repo.git-svn`
    
  2. 去那里:

    cd repo.git-svn
    
  3. 添加Git存储库的远程目录(在本示例中,我使用C:/Projects/repo.git)。您想推送到SVN并为其命名为old-git:

    git remote add old-git file:///C/Projects/repo.git/
    
  4. 从master分支将信息从old-git存储库获取到当前存储库:

    git fetch old-git master
    
  5. 将old-git远程服务器的master分支检出到当前存储库中名为old的新分支中:

    git checkout -b old old-git/master`
    
  6. 调整基础以将HEAD放在old-git / master之上。这将保留您的所有提交。这基本上是将您在Git中完成的所有工作放在您从SVN访问的工作之上。

    git rebase master
    
  7. 现在回到您的master分支:

    git checkout master
    

    并且您可以看到您拥有干净的提交历史记录。这就是您要推送到SVN的内容。

  8. 将您的工作推向SVN:

    git svn dcommit
    

就这样。它非常干净,没有黑客入侵,一切都开箱即用。请享用。



好像。但是,我发现她的方式非常令人困惑,而且我的方法要短得多(比19/23多了8步)。也许我没有正确理解她,但我认为她在第二个项目符号中混用了svn和git命令。
–codingdave

嗯,是的,不同之处在于您的流程将git导入到SVN存储库的根目录,而她的流程将其导入到一个子文件夹,这就是为什么git svn需要一些准备的原因。
TWiStErRob

在第7步中,不应该有git merge old吗?对我来说,您似乎是要更改您的母版吗?!
亚历山大

@Alexander使用'git rebase master'产生一个快速合并,这是一个线性合并,没有具有两个父级的合并提交。我们想在这里有一个线性历史。
–codingdave


3

我需要将现有的Git存储库提交到一个空的SVN存储库。

这就是我设法做到的:

$ git checkout master
$ git branch svn
$ git svn init -s --prefix=svn/ --username <user> https://path.to.repo.com/svn/project/
$ git checkout svn
$ git svn fetch
$ git reset --hard remotes/svn/trunk
$ git merge master
$ git svn dcommit

它没有问题。我希望这可以帮助别人。

由于必须使用与SVN信息库不同的用户名来授权自己(我origin使用私钥/公钥身份验证),因此必须使用该--username属性。


您可能需要先安装git-svn才能看到,请参见stackoverflow.com/questions/527037/git-svn-not-a-git-command
flexponsive

2

如果您想继续使用Git作为主要存储库,而只是需要不时地将修订版本“导出”到SVN,则可以使用Tailor使SVN存储库保持同步。它可以在不同的源代码管理系统之间复制修订,并使用您在Git中所做的更改来更新SVN。

我没有尝试过从Git到SVN的转换,但是对于SVN-> SVN示例,请参见此答案


2

另一个有效的序列(每个步骤都带有一些注释):

  1. 安装git-svnsubversion工具包:

    sudo apt-get install git-svn subversion
    
  2. 切换到 PROJECT_FOLDER

    cd PROJECT_FOLDER
    
  3. 在Subversion服务器上创建项目路径(不幸的git-svn是,与TortoiseSVN相比,当前插件存在缺陷)。无法将源代码直接存储到中PROJECT_FOLDER。相反,默认情况下,它将所有代码上传到中PROJECT_FOLDER/trunk

    svn mkdir --parents协议:/// path / to / repo / PROJECT_FOLDER / trunk -m“创建git repo占位符”

这是trunk路径末尾必填的地方

  1. 初始化文件夹git-svn内的插件上下文.git

    git svn init -s protocol:///path/to/repo/PROJECT_FOLDER
    

    trunk不需要路径末端的地方

  2. 获取空的Subversion存储库信息

    git svn fetch
    

    此步骤有助于将Subversion服务器与git-svn插件同步。这是git-svn插件建立remotes/origin路径并将其与trunk服务器端子文件夹关联的时刻。

  3. 对旧的Git提交进行重新基准化是在git-svn插件参与该过程之前发生的(此步骤是可选的

    git rebase origin/trunk
    
  4. 添加新的/修改的文件以提交(此步骤对于Git活动是常规的,是可选的

    git add .
    
  5. 将新添加的文件提交到本地Git存储库中(此步骤是可选的,并且仅在使用了步骤7的情况下才适用):

    git commit -m "Importing Git repository"
    
  6. 将所有项目更改历史记录推送到Subversion服务器中:

    git svn dcommit
    

1

您可以创建一个新的SVN存储库。导出您的Git项目(充实.git文件)。将其添加到SVN存储库(使用您到目前为止在Git中拥有的资源初始化存储库)。然后,按照说明在新的Git项目中导入SVN存储库。

但这会丢失您以前的Git历史记录。



1

我想分享一个在WordPress社区中使用的很棒的工具Scatter

Git WordPress插件和一些理智的分散

这使用户能够将其Git存储库自动发送到wordpress.org SVN。从理论上讲,该代码可以应用于任何SVN存储库。


链接似乎已有效断开(“ evansolomon.me上的服务器响应时间过长。”)。
彼得·莫滕森

1

最近,我不得不将几个Git存储库迁移到SVN,在尝试了所有可以找到的解决方案之后,最终对我有用的Mercurial(是的,使用第三个 VCS)。使用本指南,我提出了以下过程(在Linux上,但是基本思想也应在Windows上起作用)。

  1. 必要的软件包:

    $ sudo apt-get install git subversion mercurial python-subversion
    
  2. 需要通过添加以下内容来配置Mercurial ~/.hgrc

    [extensions]
    hgext.convert=
    
  3. 创建一些临时工作目录(我有几个要迁移的存储库,所以我为SVN和Git版本创建了目录,以使它们分开):

    $ mkdir svn
    $ mkdir git
    
  4. 创建一个空的本地SVN存储库:

    $ svnadmin create svn/project
    
  5. 克隆现有的Git存储库:

    $ git clone server/path/project.git git/project
    
  6. 让Mercurial做它的事:

    $ hg convert --dest-type svn git/project svn/project
    
  7. 现在,SVN存储库应包含完整的提交历史记录,但不包含原始时间戳。如果这不是问题,请跳过下一部分转到步骤11。

  8. 只需做一些工作,即可更改每次提交的日期和时间。由于我的存储库很小,因此手动进行是可行的。首先,pre-revprop-change在SVN存储库中使用以下内容创建一个挂钩,以允许修改必要的属性:

    #!/bin/bash
    exit 0;
    

    该脚本必须可执行:

    $ chmod +x svn/project/hooks/pre-revprop-change
    
  9. Mercurial创建了SVN信息库的工作副本,名为project -wc,因此请切换至该副本并编辑提交时间:

    $ cd project-wc
    $ svn propedit svn:date --revprop -r 1
    

    输入正确的日期和时间(注意时区!)并保存。您应该收到一条消息,提示“为修订版1的属性svn:date设置新值”。
    现在冲洗并重复进行其他修订。

  10. (可选)检查提交历史记录,以确保一切都正常:

    $ svn log -r 1:HEAD
    

    然后回到上一级:

    $ cd ..
    
  11. 转储存储库:

    $ svnadmin dump svn/project > project.dump
    
  12. 并将转储加载到您的Subversion服务器上。做完了!

此过程可能也可以直接在远程存储库之间工作,但是我发现使用本地存储库更容易。固定提交时间是很多工作,但是总的来说,该过程比我发现的任何其他方法都简单得多。


1

有三种方法:

  1. 变基:作为其他答案

  2. 提交ID:找到SVN第一次提交身份证件和Git会先提交ID,呼应其进入的.git /信息/移植:echo "git_id svn_id}" > .git/info/grafts然后git svn dcommit

  3. 签出每个git commit,将文件复制到svn_repo中,svn commit

bash演示: github演示

v1.x:使用rebase并提交ID

v2.x:使用复制文件,然后svn commit


0

就我而言,我必须从SVN启动一个干净的项目

$ Project> git svn init protocol://path/to/repo -s
$ Project> git svn fetch

添加所有项目资源...

$ Project> git add .
$ Project> git commit -m "Importing project sources"
$ Project> git svn dcommit

0

我只是想分享一些我接受的答案。在执行最后一步之前,我做了所有步骤,一切都很好:

git svn dcommit

$ git svn dcommit

在/usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm第101行中使用未初始化的值$ u替换(s ///)。

在串联(。)或/usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm第101行的字符串中使用未初始化的值$ u。refs / remotes / origin / HEAD:' https : //192.168.2.101/ svn / PROJECT_NAME '在''中找不到

我找到了线程https://github.com/nirvdrum/svn2git/issues/50,最后找到了我在第101行的以下文件中应用的解决方案 /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm

我更换了

$u =~ s!^\Q$url\E(/|$)!! or die

if (!$u) {
    $u = $pathname;
} 
else {
       $u =~ s!^\Q$url\E(/|$)!! or die
      "$refname: '$url' not found in '$u'\n";
}

这解决了我的问题。


-1

如果您不想将您在Git中所做的每个提交提交到SVN存储库,该怎么办?如果您只想选择性地将提交提交到管道怎么办?好吧,我有一个更好的解决方案。

我保留了一个本地Git存储库,我所做的就是从SVN提取并合并。这样,我可以确保包括所有与SVN相同的更改,但是我将提交历史与SVN完全分开。

然后,我将一个单独的SVN本地工作副本保存在一个单独的文件夹中。那就是我从中提交回SVN的那个,我为此简单地使用SVN命令行实用程序。

当我准备将本地Git存储库的状态提交到SVN时,我只需将整个文件混乱复制到本地SVN工作副本中,然后使用SVN而不是Git从那里提交。

这样,我就不必进行任何基础调整,因为基础调整就像自由基础一样。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.