ChatGPT解决这个技术问题 Extra ChatGPT

将现有 Git 存储库推送到 SVN

我一直在 Git 中完成所有工作并推送到 GitHub。我对软件和网站都非常满意,目前我不想改变我的工作习惯。

我的博士导师要求所有学生将他们的工作保存在大学托管的 SVN 存储库中。我发现了大量关于将现有 SVN 存储库拉入 Git 的文档和教程,但没有将 Git 存储库推送到新的 SVN 存储库。我希望一定有某种方法可以结合 git-svn 和一个新的分支和 rebase 以及所有这些美妙的术语来做到这一点,但我是一个 Git 新手,对它们中的任何一个都没有信心。

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

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

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

P
Peter Mortensen

我也需要这个,在 Bombe 的回答 + 一些摆弄的帮助下,我得到了它的工作。这是食谱:

导入 Git -> 颠覆

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 时,您可能会遇到冲突。通过添加状态为“未合并”的文件并恢复变基来解决这些问题。最终,您将完成;然后使用 dcommit 同步回 SVN 存储库。就这样。

保持存储库同步

您现在可以使用以下命令从 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

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

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

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

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


不错的答案。这是否也会弄乱提交日期?
好问题 - 不幸的是,我也不知道答案。这更像是我发现工作的实用指南。我不完全了解所有细节。关于提交日期,我想您可以进行测试并找出答案。请记住,您可以初始化一个本地(基于 fs)的 svn 存储库,以进行测试。
我已经使用“git rebase --onto trunk --root”代替步骤 5 执行了这些相同的步骤,并且取得了更大的成功。只有少数合并冲突需要解决,而不是吨。
在我的情况下,这个序列不起作用。始终显示消息“无法从 HEAD 历史记录中确定上游 SVN 信息”。所以,没有 dcommit 可能。
没关系,我试图变得聪明并省略 -s,因为我不想遵循 SVN 标准设置(主干/分支/标签/)。没有它根本无法让它工作。
B
BuZZ-dEE

以下是我们如何使它工作的:

在您机器上的某处克隆您的 Git 存储库。

打开 .git/config 并添加以下内容(来自 Maintaining a read-only SVN mirror of a Git repository):

[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

注意:我总是在之后废弃那个文件夹。


+1这实际上对我有用(没有主干/基地),与其他不断给出Unable to determine upstream SVN information from HEAD history.的答案相反
我尝试了这种技术,但它没有导入历史。顺便说一句,“git merge master”现在是“git merge --allow-unrelated-histories master”
如果您绝对想用 git 中的内容覆盖 SVN 中的内容,请使用 git merge -s recursive -Xtheirs --allow-unrelated-histories master
B
Benjol

直接使用 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

创建嫁接:

git replace --graft <root-commit-hash> <svn-trunk-commit-hash>

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

使移植物永久化:

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

放下移植物:

git replace -d <root-commit-hash>

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

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

git svn rebase

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

git svn dcommit

您能否更清楚地解释这种技术与上述技术有何不同。
当我尝试“git rev-parse svn/trunk”时,它报告未知的修订或路径不在工作树中。
这是唯一对我有用的答案,除了不需要 git filter-branch 和 drop graft 的步骤:我在创建嫁接后做了一个 rebase,然后做了 git svn dcommit。
我认为 rebase 可以与 --root 一起使用来管理第一次提交,因此启动答案的警告可能不再正确。
P
Peter Mortensen

在 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 trunk # git merge master # git svn dcommit 记住 .gitignore .svn 目录!
因为我刚刚做了同样的操作,所以我想明确指出现在(09 年 1 月),git 可以对根提交执行 rebase 操作。这使得该过程比许多旧文章所指出的要简单得多,请参阅 its.arubything.com/2009/1/4/… 上的评论
“-s” git svn init 选项有什么作用?我在 git svn 的手册页中看不到这一点。
再次阅读手册页,也许搜索“-s”,因为它在那里。它是“--stdlayout”的别名。
P
Peter Mortensen

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

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

如何:

有一个 SVN 存储库,我们要在其中导入我们的东西并使用 git-svn 克隆它: git svn clone https://path.to/svn/repository repo.git-svn` 去那里: cd repo.git-svn 添加Git 存储库的远程(在此示例中,我使用 C:/Projects/repo.git)。您想推送到 SVN 并为其命名 old-git: git remote add old-git file:///C/Projects/repo.git/ 从 old-git 存储库中的 master 分支获取信息到当前存储库: git fetch old-git master 将 old-git 远程的 master 分支检出到当前存储库中名为 old 的新分支中: git checkout -b old old-git/master` rebase 将 HEAD 放在 old- 之上混帐/大师。这将维护您的所有提交。这基本上是将您在 Git 中完成的所有工作放在您从 SVN 访问的工作之上。 git rebase master 现在回到你的 master 分支: git checkout master 你可以看到你有一个干净的提交历史。这就是您要推送到 SVN 的内容。将您的工作推送到 SVN:git svn dcommit

就这样。它非常干净,没有黑客攻击,一切都开箱即用。享受。


chani.wordpress.com/2012/01/25/… 也详细介绍了类似的过程
好像。然而,我发现她的方式很混乱,我的方式要短得多(比 19/23 少 8 步)。也许我没有正确理解她,但我认为她在第二个子弹中混合了 svn 和 git 命令。
啊,是的,不同之处在于您的进程将 git 导入到 SVN 存储库的根目录,而她的进程将其导入到子文件夹,这就是需要少数 git svn 准备的原因。
在第 7 步中,不应该有一个 git merge old 吗?对我来说,你似乎在做一个你没有改变的主人的dcommit?!
@Alexander 使用'git rebase master'我们产生了一个快进合并,这是一个没有合并提交的线性合并有两个父级。我们希望在这里有一个线性历史。
C
Community

我会使用 SubGit 提出一个非常简短的 4 个命令指令。有关详细信息,请参阅此 post


P
Peter Mortensen

我需要将现有的 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
P
Peter Mortensen

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

我没有尝试过 Git 到 SVN 的转换,但是对于 SVN -> SVN 示例见 this answer


P
Peter Mortensen

另一个有效的序列(每个步骤都有一些评论):

安装 git-svn 和 subversion 工具包: sudo apt-get install git-svn subversion 在 PROJECT_FOLDER 里面切换 cd PROJECT_FOLDER 在 Subversion 服务器上创建项目路径(不幸的是,当前的 git-svn 插件与 TortoiseSVN 相比存在缺陷)。它无法将源代码直接存储到 PROJECT_FOLDER。相反,默认情况下,它将所有代码上传到 PROJECT_FOLDER/trunk。 svn mkdir --parents protocol:///path/to/repo/PROJECT_FOLDER/trunk -m "创建 git repo 占位符"

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

初始化 .git 文件夹内的 git-svn 插件上下文 git svn init -s protocol:///path/to/repo/PROJECT_FOLDER 这是路径末尾不需要主干的地方 获取一个空的 Subversion 存储库信息 git svn fetch 这一步有助于将 Subversion 服务器与 git-svn 插件同步。这是 git-svn 插件建立远程/源路径并将其与服务器端的主干子文件夹相关联的时刻。在 git-svn 插件参与流程之前,重新设置旧的 Git 提交(此步骤是可选的)将新添加的文件提交到本地 Git 存储库(此步骤是可选的,仅在使用第 7 步时才适用): git commit -m "Importing Git repository" 将所有项目更改历史记录推送到 Subversion 服务器: git svn dcommit


P
Peter Mortensen

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

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


P
Peter Mortensen

如果您不必使用任何特定的 SVN,并且您使用的是 GitHub,则可以使用他们的 SVN 连接器。

更多信息在这里:Collaborating on GitHub with Subversion


SVN 什么?在(“......任何特定的 SVN 和......”)。 SVN版本? SVN客户端?或者是其他东西?
I
Indrek

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

必要的软件包: $ sudo apt-get install git subversion mercurial python-subversion Mercurial 需要通过将以下内容添加到 ~/.hgrc 来配置: [extensions] hgext.convert= 创建一些临时工作目录(我有几个要迁移的存储库所以我为 SVN 和 Git 版本创建了目录,以保持它们分开): $ mkdir svn $ mkdir git 创建一个空的本地 SVN 存储库: $ svnadmin create svn/project 克隆现有的 Git 存储库: $ git clone server/path/project .git git/project 让 Mercurial 做它的事情: $ hg convert --dest-type svn git/project svn/project 现在 SVN 存储库应该包含完整的提交历史,但不包含原始时间戳。如果这不是问题,请跳过下一部分到第 11 步。只需稍做工作,就可以更改每次提交的日期和时间。由于我的存储库很小,因此我可以手动完成。首先,使用以下内容在 SVN 存储库中创建一个 pre-revprop-change 挂钩,以允许修改必要的属性:#!/bin/bash exit 0;这个脚本必须是可执行的: $ chmod +x svn/project/hooks/pre-revprop-change Mercurial 创建了一个名为 project-wc 的 SVN 存储库的工作副本,所以切换到它并编辑提交时间: $ cd project-wc $ svn propedit svn:date --revprop -r 1 输入正确的日期和时间(注意时区!)并保存。您应该会收到一条消息“为属性 svn:date 在修订 1 上设置新值”。现在冲洗并重复每个其他版本。可选择检查提交历史以确保一切正常: $ svn log -r 1:HEAD 然后返回上一级: $ cd .. 转储存储库: $ svnadmin dump svn/project > project.dump 并加载转储你的 Subversion 服务器。完毕!

这个过程可能也可以直接在远程存储库之间工作,但我发现使用本地存储库更容易。修复提交时间需要做很多工作,但总体而言,这个过程比我发现的任何其他方法都简单得多。


张耀文

有三种方法:

rebase: 作为其他答案 commit id: find svn first commit id 和 git first commit id ,将它们回显到 .git/info/grafts:echo "git_id svn_id}" > .git/info/grafts 然后 git svn dcommit checkout each git提交,将文件复制到 svn_repo,svn 提交

bash 演示:github demo

v1.x:使用rebase和commit id

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


d
dangt85

就我而言,我必须从 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

P
Peter Mortensen

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

Git WordPress plugins and a bit of sanity scatter

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


该链接似乎已被有效破坏(“evansolomon.me 的服务器响应时间过长。”)。
P
Peter Mortensen

我只是想与接受的答案分享我的一些经验。在运行最后一步之前,我完成了所有步骤,一切都很好:

git svn dcommit

$ git svn dcommit 在 /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm 第 101 行使用未初始化值 $u 替换 (s///)。在连接中使用未初始化值 $u (.) 或/usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm 第 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

我换了

$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";
}

这解决了我的问题。


e
eftshift0

这就是我会做的。假设我的本地分支称为 main。填补空白,因为我不记得确切的 git svn 命令,因为我有一段时间没有使用它。

在 svn 中创建将用于项目的分支。

使用 git svn 克隆您想要的 svn 存储库(至少,您要使用的分支,这样您就不必获取我们不关心的其他数百万个修订)。

签出新 git repo 中的 svn 分支。

向此存储库添加一个远程,该远程指向您用于项目的原始 git 存储库。假设遥控器被称为the-real-stuff。

git fetch the-real-stuff # 这样我们就可以看到真正的 repo 中有什么

鉴于这是我们第一次将代码拉入 svn 中,我们必须欺骗 git 以便它可以“合并”该代码: git merge --allow-unrelated-histories the-real-stuff/main - m“在 svn 修订版中我想要的任何评论”。这将在本地“合并”两个分支。

git svn dcommit 以便您可以按现在的方式推送项目的内容。

继续处理原始的 git 存储库。然后,当您想推入 svn 时,请转到 git svn clone 并执行以下操作:

git fetch the-real-stuff # get visibility to the changes in the original git repo
git merge the-real-stuff/main -m "Whatever comment I want to show on this svn revision"
git svn dcommit

你完成了。

我喜欢使用 2 个 repo 的想法,这样我们就不会用 svn 的东西填写原始 repo,尽管可以将整个东西保存在一个 git repo 中。


P
Peter Mortensen

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

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

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

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

这样我就不必做任何变基,因为变基就像自由变基。