从 SVN 迁移后断开 GIT 个分支

Disconnected GIT branches after migrating from SVN

尝试了几十个帖子,但仍然没有得到我想要的。

前言: 我们最初有一个非常大的 SVN 存储库,没有主干(标准结构)等。因此,我正在工作的项目也没有结构(在子文件夹内)。我在这个项目上工作了大约几个月,然后遇到了我需要一个分支来进行生产修复的情况。因此,我只将我的项目代码重组为主干、标签和分支(即 SVN 存储库中的子目录)。然后根据历史,我创建了一个名为 Live 的分支,并为生产做了一个修复并部署了它。然后,我将此修复合并到我的 trunk 中,没有任何问题。我们继续致力于 trunk 并继续部署,但由于 SVN 不必要的复杂性,我们没有将 trunk 合并到 Live 尽管我们的部署很少。 (这一切都在 SVN 中)

迁移: 我们最近决定设置一个新的 TFS 服务器并通过 GIT 进行版本控制。所以,在安装完成后,我有一个任务是将这个项目的代码迁移到 GIT。我开始使用 "git svn clone" 在我的本地 PC 上执行此操作,很高兴看到我的所有历史记录都已迁移。分支机构为:

问题是分支断开(没有加入节点):-(

请看下图:

根据上图,master 分支从突出显示的提交(节点)开始,但 Live 分支仅从 SVN 第一次提交开始。

理想情况下,当真正创建时,我希望将 master 和 Live 上的所有内容都显示为来自 master 的分支。此外,当我尝试检查 Live 分支时,我收到警告,它是分离的 HEAD,我可能不会 get/push 提交到主(即 HEAD)分支。

有人可以向我发送解决此问题的步骤吗?

我认为可能的解决方案:

这个过程可能会有负面影响,所以我很谨慎。

更新: 根据 "Live@2656" 重命名分支并创建主控。现在,尝试将 "Svn-trunk" 合并到 master(新分支)- 我得到以下错误:

fatal: refusing to merge unrelated histories
Done

也许从一个新的 git svn clone 开始,因为这样可以避免一些头痛。此外,将此类获得的 git 存储库的副本保存在安全的地方也不是一个坏主意:)

还有两种方法您可以尝试...

可能性 #1 - 修复结构

更简洁的方法是重建存储库的真实结构。如果我没理解错的话,trunk 是在历史的某个时刻创建的。如果您能够在历史记录中找到那个点,您也许可以使用git rebase <SHA of that spot in branch Live> 将历史记录重新连接在一起。不过,可能会出现一些冲突。

但是,如果您在 SVN 上将一些开发进度合并回 Live,您在合并时可能会遇到困难。为了避免这种情况,您可以将这些合并重建为适当的合并提交,但如果您不必拥有适当的历史记录,这可能不值得花时间...

可能性 #2 - 只是变基

如果您根本不关心正确的历史记录,或者更简单的解决方案...

git checkout master
git rebase Live

您唯一需要确定的是解决可能的冲突。

对于一次性迁移 git-svn 不是 转换存储库或部分存储库的正确工具。如果您想使用 Git 作为现有 SVN 服务器的前端,这是一个很好的工具,但是对于一次性转换,您应该 而不是 使用 git-svn,但是svn2git 更适合这个用例。

有很多名为 svn2git 的工具,最好的可能是来自 https://github.com/svn-all-fast-export/svn2git 的 KDE。我强烈建议使用 svn2git 工具。这是我所知道的最好的可用规则文件,而且您可以非常灵活地使用它的规则文件。

您将能够轻松地配置 svn2gits 规则文件以从当前 SVN 布局中生成您想要的结果,包括可能存在的任何像您这样的复杂历史,并包括生成多个 Git从一个 SVN 存储库中提取一个存储库,或者将不同的 SVN 存储库合并为一个 Git 个存储库,如果你愿意,可以在一个 运行 中干净利落地。

如果您不是 100% 了解存储库的历史,http://blog.hartwork.org/?p=763 中的 svneverever 是一个很好的工具,可以在将 SVN 存储库迁移到 Git 时调查其历史.


尽管 git-svn 更容易入手,但除了它的灵活性之外,还有一些其他原因说明为什么使用 KDE svn2git 而不是 git-svn 更好:

  • svn2git(如果使用了正确的),历史重建得更好更干净,对于具有分支和合并等的更复杂的历史尤其如此
  • 标签是真正的标签,而不是 Git
  • 中的分支
  • with git-svn 标签包含一个额外的空提交,这也使它们不属于分支,因此正常的 fetch 将不会得到它们,直到您将 --tags 给命令,因为默认情况下也只获取指向已获取分支的标签。使用正确的 svn2git 标签是它们所属的地方
  • 如果您更改了 SVN 中的布局,您可以使用 svn2git 轻松配置它,使用 git-svn 您最终将丢失历史记录
  • 使用 svn2git 您还可以轻松地将一个 SVN 存储库拆分为多个 Git 个存储库
  • 或将同一个 SVN 根中的多个 SVN 存储库轻松合并为一个 Git 存储库
  • 正确 svn2git 的转换速度比 git-svn
  • 快无数倍

你看,git-svn 更差而 KDE svn2git 更优越的原因有很多。 :-)

我有一个类似的问题,其中一些(不是全部)SVN 分支和标签与主干断开连接。

Rebase 对我不起作用,但我通过重写历史修复了它们。

  1. 在树干中找到 branches/tags 应该连接的点。
  2. 对于标签,只需删除现有标签并在正确的提交上重新创建它。
  3. 对于分支,您需要使用 cherry-picks 报告所有提交。我想保留原始提交日期,以便在查看历史提交时看起来不像是 2 天前完成的。为此,您可以使用 GIT_COMMITTER_DATE 变量。

您首先需要导出变量:

# create and checkout a new branch where the disconnected branch should be inserted in trunk
git checkout -b <name of the branch> <sha where to insert>

# generate the list of commands to execute
git log <your_disconnected_branch> | grep -P "(^commit|^Date:)" | tac | sed 's/commit /git cherry-pick /g' | sed 's/Date:   \(.*\)$/GIT_COMMITTER_DATE=""/g'

# copy the output of the previous command

# export the GIT_COMMITTER_DATE variable
export GIT_COMMITTER_DATE

# paste the output of the log command, it should look like the following (without leading # sign):
#GIT_COMMITTER_DATE="Wed Jun 1 17:18:55 2016 +0000"
#git cherry-pick 54f30ac8071b5f935bf12595ab922542ce9d348e
#GIT_COMMITTER_DATE="Wed Jun 1 17:20:08 2016 +0000"
#git cherry-pick 5188d54f6d4bf09b06a108a887fdc6ec84f68919
#GIT_COMMITTER_DATE="Wed Jun 1 17:21:22 2016 +0000"
#git cherry-pick d47cbcfbd3fbd4c92e68fa2cfe92b555c7abaf8c

git日志命令的解释:

  1. git log your_disconnected_branch ----> 获取断开连接分支中所有提交的列表。
  2. grep -P "(^commit|^Date:)" ----> 删除除包含提交 ID 和日期的行之外的所有行。
  3. tac ----> 反转文件的顺序,以便以相反的顺序插入提交。这具有在提交之前设置提交日期的额外好处。
  4. 's/commit /git cherry-pick /g' ----> 将 commit id 行转换为 cherry-pick
  5. sed 's/Date: (.*)$/GIT_COMMITTER_DATE=""/g' ----> 将日期行转换为 GIT_COMMITTER_DATE 变量的赋值

最后,别忘了用

清除你的 GIT_COMMITTER_DATE
GIT_COMMITTER_DATE=

以防止您以后的所有操作都显得非常陈旧。