将现有Git存储库推送到SVN

Pushing an existing Git repository to SVN

我在Git做了所有的工作,一直在推动Github。我对这个软件和这个网站都很满意,我不想在这一点上改变我的工作实践。

我的博士顾问要求所有学生将他们的工作保存在大学主办的SVN资源库中。我已经找到了大量的文档和教程,它们将把一个现有的SVN存储库拉入Git中,而不是将一个Git存储库推到一个新的SVN存储库中。我希望有一些方法可以做到这一点,结合Git SVN和一个新的分支,重新平衡和所有这些美妙的条款,但我是一个Git新手,并没有任何信心。

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

如果这有什么不同的话,我将是唯一一个致力于SVN的人。


我也需要这个,在庞贝的回答的帮助下,再加上四处闲逛,我就成功了。食谱如下:

导入Git->Subversion

1
2
3
4
5
6
7
8
9
10
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之后,您会收到这样一条神秘的信息:

Using higher level of URL: protocol:///path/to/repo/PROJECT => protocol:///path/to/repo

忽略这一点。

当你跑5时,你可能会遇到冲突。通过添加状态为"未合并"的文件并恢复REBASE来解决这些问题。最后,您将完成;然后使用dcommit同步回SVN存储库。这就是全部。

保持存储库同步

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

1
2
git svn fetch
git rebase trunk

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

1
git svn dcommit

最后说明

在应用到活动存储库之前,您可能希望在本地副本上尝试此操作。您可以将Git存储库复制到临时位置;只需使用cp -r,因为所有数据都在存储库中。然后,可以使用以下方法设置基于文件的测试存储库:

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

并检查一份工作副本,使用:

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

这将允许你在做出任何持久的改变之前,玩弄事物。

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

如果您不小心用错误的URL运行了git svn init,并且您还没有足够的智能来备份您的工作(不要问…),那么就不能再运行相同的命令。但是,您可以通过发出以下命令来撤消更改:

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

拆下[svn-remote"svn"]段。

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


我们的工作原理如下:

在计算机上的某个地方克隆Git存储库。

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

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

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

1
2
3
git svn fetch svn
git checkout -b svn git-svn
git merge master

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

1
2
3
git checkout --theirs .
git add .
git commit -m"some message"

最后,您可以向SVN提交:

1
git svn dcommit

注意:以后我总是把那个文件夹扔掉。


直接使用git rebase将丢失第一次提交。Git对它有不同的看法,不能重新平衡它。

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

我将在这里转录解决方案,但学分是为北京?氡

初始化git svn:

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

前缀为您提供远程跟踪分支,如"svn/trunk",这很好,因为如果您只将本地分支称为"trunk",则不会得到不明确的名称。-s是标准主干/标签/分支布局的快捷方式。

从SVN获取初始资料:

1
git svn fetch

现在查找根提交的散列(应该显示单个提交):

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

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

1
git rev-parse svn/trunk

创建移植:

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

现在,"gitk"应该将svn/trunk显示为您的主分支所基于的第一个提交。

永久移植:

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

放弃移植:

1
rm .git/info/grafts

Gitk仍应在主人的祖先中显示svn/trunk

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

1
git svn rebase

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

1
git svn dcommit


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

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

更改为Git管理的项目并初始化Git SVN。

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

这将创建一个提交,因为您的SVN项目目录仍然是空的。现在把所有的事情都放在承诺上,git svn dcommit,你应该这样做。不过,这会严重破坏你的提交日期。


git->svn,具有完整的提交历史记录

我有一个Git项目,必须将它转移到SVN。这就是我如何做到的,保持了整个提交历史。唯一会丢失的是原始提交时间,因为libsvn将在执行git svn dcommit时设置本地时间。

Howto:

  • 有一个SVN存储库,我们希望在其中导入我们的资料并使用Git SVN进行克隆:

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

    1
    cd repo.git-svn

  • 添加git存储库的远程版本(在本例中,我使用的是c:/projects/repo.git)。你想推到svn并给它起一个名字old git:

    1
    git remote add old-git file:///C/Projects/repo.git/
  • 从旧git存储库的主分支获取信息到当前存储库:

    1
    git fetch old-git master

  • 将旧git-remote的主分支签入当前存储库中名为old的新分支:

    1
    git checkout -b old old-git/master`
  • 重新定位以将头部放在旧git/master的顶部。这将保持你所有的承诺。它的基本功能是将您在Git中完成的所有工作放在您从SVN访问的工作之上。

    1
    git rebase master

  • 现在回到主分支:

    1
    git checkout master

    你可以看到你有一个干净的提交历史。这就是你想要推给SVN的。

  • 将您的工作推至SVN:

    1
    git svn dcommit
  • 这就是全部。它非常干净,没有黑客攻击,而且所有东西都是开箱即用的。享受。


    我建议在使用subgit的4个命令中使用一个非常短的指令。详情请参阅本帖。


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

    我就是这样做到的:

    1
    2
    3
    4
    5
    6
    7
    8
    $ 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的修订,那么您可以使用Tailt来保持SVN存储库的同步。它可以在不同的源代码管理系统之间复制修订,并使用在Git中所做的更改来更新SVN。

    我没有尝试过Git-to-SVN转换,但是对于SVN->SVN示例,请参阅这个答案。


    我想分享一个在WordPress社区中使用的很棒的工具,叫做分散。

    Git WordPress插件和一些健全的分散

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


    如果您不必使用任何特定的SVN,并且您使用的是Github,那么您可以使用它们的SVN连接器。

    这里有更多信息:在Github上与Subversion协作


    您可以创建一个新的SVN存储库。导出Git项目(充实.git文件)。将其添加到SVN存储库中(使用Git中的内容初始化存储库)。然后使用说明在新的Git项目中导入SVN存储库。

    但这将丢失您以前的Git历史。


    有三种方法:

  • 重新平衡:就像其他答案一样

  • commit id:找到svn first commit id和git first commit id,回传到.git/info/grafts:echo"git_id svn_id}"> .git/info/grafts,然后是git svn dcommit

  • 签出每个git提交,将文件复制到svn_repo,svn commit

  • Bash演示:Github演示

    v1.x:使用rebase和commit id

    V2.X:使用复制文件,然后SVN提交


    我只想和大家分享我的一些经验。在跑最后一步之前,我做了所有的步骤,一切都很好:

    1
    git svn dcommit

    $ git svn dcommit

    Use of uninitialized value $u in substitution (s///) at /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm line 101.

    Use of uninitialized value $u in concatenation (.) or string at /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm line 101.
    refs/remotes/origin/HEAD: 'https://192.168.2.101/svn/PROJECT_NAME' not found in ''

    我找到了这个线程https://github.com/nirvdrum/svn2git/issues/50,最后找到了我在下面的文件101行中应用的解决方案。/usr/lib/perl5/vendor_perl/5.22/git/svn.pm

    我换了

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

    具有

    1
    2
    3
    4
    5
    6
    7
    8
    if (!$u) {
        $u = $pathname;
    }
    else {
           $u =~ s!^\Q$url\E(/|$)!! or die
         "$refname: '$url' not found in '$u'
    ";
    }

    这解决了我的问题。


    在我的情况下,我必须从SVN发起一个清洁项目。

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

    添加所有项目源…

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

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

  • 必要的包装:

    1
    $ sudo apt-get install git subversion mercurial python-subversion

  • Mercurial需要通过在~/.hgrc中添加以下内容进行配置:

    1
    2
    [extensions]
    hgext.convert=
  • 创建一些临时工作目录(我有几个要迁移的存储库,因此我为SVN和Git版本创建了目录,以使它们保持独立):

    1
    2
    $ mkdir svn
    $ mkdir git

  • 生成空的本地SVN存储库:

    1
    $ svnadmin create svn/project

  • 克隆现有的Git存储库:

    1
    $ git clone server/path/project.git git/project

  • 让Mercurial做它的事:

    1
    $ hg convert --dest-type svn git/project svn/project

  • 现在,SVN存储库应该包含完整的提交历史记录,但不包含原始时间戳。如果这不是问题,请跳过下一部分到步骤11。

  • 只要做一点工作,就可以更改每次提交的日期和时间。因为我的存储库相当小,所以我可以手动操作。首先,在SVN存储库中创建一个包含以下内容的pre-revprop-change钩子,以允许修改必要的属性:

    1
    2
    #!/bin/bash
    exit 0;

    必须使此脚本可执行:

    1
    $ chmod +x svn/project/hooks/pre-revprop-change

  • Mercurial创建了一个名为project wc的SVN存储库的工作副本,因此切换到它并编辑提交时间:

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

    输入正确的日期和时间(注意时区!)然后保存。您应该会收到一条消息,说明"为属性svn设置新值:修订版1上的日期"。现在冲洗并对其他版本重复。

  • 或者检查提交历史记录以确保一切正常:

    1
    $ svn log -r 1:HEAD

    然后返回一个级别:

    1
    $ cd ..

  • 转储存储库:

    1
    $ svnadmin dump svn/project > project.dump

  • 并将转储文件加载到Subversion服务器上。完成!

  • 这个过程也可能直接在远程存储库之间工作,但我发现使用本地存储库更容易。修复提交时间是一项艰巨的工作,但总的来说,这个过程比我发现的任何其他方法都要简单得多。


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

  • 安装git-svnsubversion工具包:

    1
    sudo apt-get install git-svn subversion
  • PROJECT_FOLDER内部切换

    1
    cd PROJECT_FOLDER

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

    svn mkdir--parents protocol:///path/to/repo/project_folder/trunk-m"创建git repo占位符"

  • 这是路径末端的trunk是强制的地方。

  • 初始化.git文件夹中的git-svn插件上下文

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

    这是一个不需要trunk在道路尽头的地方。

  • 获取空的subversion存储库信息

    1
    git svn fetch

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

  • git-svn插件参与进程之前,重新设置旧的git提交(此步骤是可选的)

    1
    git rebase origin/trunk
  • 添加要提交的新的/修改过的文件(此步骤对于git活动是常规的,并且是可选的)

    1
    git add .

  • 将新添加的文件提交到本地Git存储库(此步骤是可选的,仅在使用步骤7时适用):

    1
    git commit -m"Importing Git repository"

  • 将所有项目更改历史推送到Subversion服务器中:

    1
    git svn dcommit

  • 如果您不想将在Git中所做的每个提交提交到SVN存储库,该怎么办?如果您只想有选择地向管道发送提交,该怎么办?嗯,我有更好的解决办法。

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

    然后我将单独的SVN本地工作副本保存在单独的文件夹中。这就是我从SVN提交的内容,我只是使用SVN命令行实用程序。

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

    这样我就不必再做任何重新平衡,因为重新平衡就像自由基一样。