我们有两个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
所以不会有任何“合并”两者的冲突。我们能够完美地使用this answer将单个SVN项目转移到单个Git项目中,并包含提交历史记录。
我们希望将我们的两个SVN项目A和B合并到一个Git存储库中,但我们希望按日期合并提交。即:
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导入期间执行合并?
答案 0 :(得分:6)
所以我尝试了Craig的方法,但这最终让我在组合存储库上留下了一些不尽如人意的历史。我发现将所有svn repos签出到单独的git,然后将它们分支在一起创造了一个很好的历史,其中三个分支相遇。
首先,你做了#34;作者"步骤创建authors.txt:
someguy = Some Guy <someguy@yourcompany.com>
...
(no author) = no_author <no_author@no_author>
现在你必须使用git检查所有svn repos:
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
答案 1 :(得分: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存储库。
步骤2:将3合并的SVN存储库迁移到Git存储库
可以在本地计算机上执行以下步骤 - 不需要在您的服务器上执行。
首先,创建一个authors.txt文件,git-svn可以使用它来确定每个提交的作者。我用过:
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。 我们没有这样做。我们的标签不需要保留,因为我们有其他来源来检索它们,而且我们没有这些项目的任何分支。
删除branches
和tags
目录后,我们将trunk/
的内容删除了一个级别,因此所有内容都处于项目特定的“根”级别。
答案 2 :(得分:3)
这是我在Linux shell中做的事情(未经测试):
使用空的第一次提交
制作第三个git repo git ci --allow-empty -m'Add empty, initial commit'
在空仓库中,将每个仓库添加为远程仓库
git remote add repoA 'path/to/git/repoA'
git remote add repoB 'path/to/git/repoB'
将repos提取到空的repos中(这会将所有对象合并到一个repo中)
git fetch repoA
git fetch repoB
获取前缀为Unix时间戳的每个仓库中的提交列表(自1970年1月1日起的秒数)
git --no-pager log --format='%at %H' master >repoACommits
git --no-pager log --format='%at %H' master >repoBCommits
将它们两者合二为一,排序(按时间戳)列表,剔除时间戳:
cat repoACommits repoBCommits | sort | cut -d' ' -f2 >orderedCommits
在你的新回购中,通过列表,每个挑选(大概是掌握)
git co master
cat orderedCommits | while read commit; do git cherry-pick $commit; done
这都是理论上的,但我认为它会起作用。我不知道如果你们之间发生合并冲突会发生什么。我不确定while
是否会停止,或继续尝试并且无法继续。
我刚刚注意到你提到想要将repo的每个工作保存在最终文件夹中的不同文件夹中。你需要神秘而强大的git filter-branch
来首先分别浏览每个repo,然后执行将添加的东西移动到文件夹中的工作。这可能值得一个新问题,如果它还没有在SO上回答。