15

我们有两个 Subversion 存储库,每个都有一个项目。所以:

svn://server/svn/project_a
svn://server/svn/project_b

它们是独立的项目,并且位于具有完全独立的提交历史的独立存储库中。项目 A 有r1, r2, ... r100,项目 B 有r1, r2, ... r400

我们最终希望将这两个 SVN 存储库合并到一个 Git 存储库中。合并是否可以在 Git 中进行,或者应该首先在第三个临时 SVN 存储库中进行,我们最终希望看到:

git://server/svn/projects/

这是一个包含项目 A 和项目 B 的存储库。它们将存储在单独的文件夹中,例如:

git://server/svn/projects/project_a
git://server/svn/projects/project_b

所以不会有任何“合并”两者的冲突。我们能够完美地使用这个答案将单个 SVN 项目转移到单个 Git 项目中,其中包括提交历史记录。

我们希望将我们的两个 SVN 项目 A 和 B 合并到一个 Git 存储库中,但我们希望按日期合并提交。IE:

8b8dad: Project A, r1 (first commit in Git)
dbdffe: Project B, r1 (child of previous)
0ae7f7: Project B, r2 ...
615b51: Project A, r2 ...
916e59: Project A, r3 ...
85f241: Project B, r3 ...

这可能吗?我们是否应该将两个 SVN 存储库合并为一个,然后导入到 Git 中?还是更容易将它们分开,并在 Git 导入期间执行合并?

4

3 回答 3

8

所以我尝试了 Craig 的方法,但这最终让我对组合存储库的历史有点不满意。我发现将所有 svn 存储库签出到单独的 git 存储库中,然后将它们分支在一起,这创造了一个很好的历史,三个分支相遇。

因此,首先您执行“作者”步骤来创建 authors.txt:

someguy = Some Guy <someguy@yourcompany.com>
...
(no author) = no_author <no_author@no_author>

现在您必须使用 git 检查所有 svn 存储库:

mkdir proja projb projc ...

现在您必须为每个项目重复以下操作,并且由于您的存储库可能不是一个文件夹,因此请进行额外的提交:

cd proja
git svn init https://svn.mycompany.com/svn/proja --no-metadata
git config svn.authorsfile ../authors.txt
git svn fetch

#here comes the additional part:
mkdir -p proja                  #proja/proja
git mv -k * proja               #move everything in there
git commit -m "subtree proja"

然后我去做了我的新组合仓库,其中我为每个子项目使用了不同的分支:

mkdir ../superproj
cd ../supeproj
git init
git commit --allow-empty        #so that we have a master branch
git branch proja projb projc...

每个子项目都需要重复以下内容:

git checkout proja
git remote add proja_rm ../proja
git pull proja_rm              #probably add a branch (e.g. master)
git remote rm proja_rm         #cleanup

最后,您可以将整个东西组合到您的主人中

git checkout master
git merge proja projb projc...  #it all comes together
git push whereeveryouwant
于 2015-06-26T05:50:32.317 回答
4

这是我们最终要做的事情:

第 1 步:将 SVN 存储库合并到临时 SVN 存储库中

这需要访问 SVN 存储库(不是工作副本):

首先,创建要合并的每个存储库的转储文件:

svnadmin dump project_a > dumps/a.dmp
svnadmin dump project_b > dumps/b.dmp
svnadmin dump project_c > dumps/c.dmp

然后,创建一个新的存储库来容纳合并的存储库:

svnadmin create svn-temp-project

请注意,您必须将此存储库检出到工作副本中,并创建项目子目录,否则转储的加载将不起作用:

svn co file:///var/svn/svn-temp-project svn-temp-project-wc
cd svn-temp-project-wc
mkdir project_a
mkdir project_b
mkdir project_c
svn add . --force
svn ci -m "Added initial project directories."

然后,您可以将每个单独的转储文件加载到其自己的特定 (!!) 项目目录中:

svnadmin load svn-temp-project --parent-dir project_a < dumps/a.dmp
svnadmin load svn-temp-project --parent-dir project_b < dumps/b.dmp
svnadmin load svn-temp-project --parent-dir project_c < dumps/c.dmp

您现在有一个 3 合并的 SVN 存储库。

第二步:将3合并的SVN仓库迁移到Git仓库

以下步骤可以在本地机器上执行 - 不需要在您的服务器上进行。

首先,创建一个 git-svn 可以用来确定每个提交的作者的 authors.txt 文件。我用了:

someguy = Some Guy <someguy@yourcompany.com>
...
(no author) = no_author <no_author@no_author>

有了这个作者文件,您就可以:

cd projects/
mkdir my-git-repository
cd my-git-repository
git svn init https://svn.mycompany.com/svn/svn-temp-project --no-metadata
git config svn.authorsfile ../authors.txt
git svn fetch

第 3 步:清理

此方法适用于合并提交历史记录,您最终会得到类似 SVN 的目录:

repo/project_a/trunk
repo/project_a/branches
repo/project_a/tags
repo/project_b/trunk
repo/project_b/branches
repo/project_b/tags
...

因此,在推送之前,您应该将所有标签/分支迁移到 Git。我们没有这样做。我们的标签没有必要保留,因为我们有其他来源来检索它们,而且我们没有这些项目的任何分支。

删除branchestags目录后,我们将内容trunk/向下一层,所以一切都在项目特定的“根”级别。

于 2013-05-06T21:43:42.443 回答
3

这是我在 Linux shell 中所做的(未经测试):

  1. 将每个转换为自己的 git repo
  2. 使用空的第一次提交创建第三个 git 存储库

    git ci --allow-empty -m'Add empty, initial commit'

  3. 在空仓库中,将每个仓库添加为远程

    git remote add repoA 'path/to/git/repoA'
    git remote add repoB 'path/to/git/repoB'

  4. 将存储库获取到空的存储库中(这会将所有对象放入一个存储库)

    git fetch repoA
    git fetch repoB

  5. 获取每个 repo 中以 Unix 时间戳为前缀的提交列表(自 1970 年 1 月 1 日以来的秒数)

    git --no-pager log --format='%at %H' master >repoACommits
    git --no-pager log --format='%at %H' master >repoBCommits

  6. cat 将它们合二为一,排序(按时间戳)列表,剔除时间戳:

    cat repoACommits repoBCommits | sort | cut -d' ' -f2 >orderedCommits

  7. 在你的新仓库中,遍历列表,挑选每个(大概是掌握)

    git co master
    cat orderedCommits | while read commit; do git cherry-pick $commit; done

这都是理论上的,但我认为它会起作用。我不知道如果你在两者之间有合并冲突会发生什么。我不确定是否while会停止,或者继续尝试但未能继续。

我刚刚注意到您提到希望将 repo 中的每个工作都保存在最终文件夹中的单独文件夹中。您将需要神秘而强大的git filter-branch东西来首先分别运行每个 repo,完成将添加的内容移动到文件夹中的工作,每次提交。如果尚未在 SO 上回答,那可能值得提出一个新问题。

于 2013-05-04T04:22:49.113 回答