有很多关于从SVN迁移到git的信息,但我正在寻找一种将git镜像到SVN的方法,在SVN中,git repo是预先存在的,SVN repo需要更新git repo的内容,然后保持最新。(这是一面镜子,我不需要双向同步(。
(为什么?因为dev已经迁移到git,但管理层只信任svn。这为我们争取了改变态度的时间…(
我发现最接近我想要的东西是在这里,但我遇到了与那里评论中的人相同的问题:SVN日志被合并消息污染了。
主要的问题是有两个完全独立的历史,没有办法将它们永久地结合在一起。gitsvn必须从现有的svn repo开始,因此初始提交就是从那里开始的。但我不想永久地重写我的git repo的历史,以使其基于SVN初始提交。
这个答案让我走了很多路,我认为我已经完成了,在第一次同步时,这很好,但问题是它试图将所有历史从git重新绑定到svn分支上,尽管该分支已经包含了大部分历史。这最终会尝试进行"向后"合并(将旧版本的文件合并到新版本(,这会产生无法解决的冲突(每次都必须再次进行(。
所以我改采樱桃。
无论如何,这里是设置:这是一个完整的遍历,它在本地创建所有内容。它可以适应你已经拥有的一切。
创建裸git回购
#(create and cd to a test folder)
git --bare init bare.git
创建本地git工作回购
#(cd to test folder)
mkdir gitrepo
cd gitrepo
echo 'First content' > file.txt
git add .
git commit -m "Initial git commit"
git remote add origin [absolute path to bare.git]
git push origin master
此时,添加到本地git工作repo的新文件已同步到裸repo。
创建空的subversion
svn mkdir --parents [path to desired svn repo including /trunk] -m "Initial commit"
将裸机克隆到镜像存储中
#(cd to test folder)
git clone [absolute path to bare.git] mirror
cd mirror
code .gitconfig # I'm using VSCode here: edit with whatever you want
将以下行添加到文件中:
[svn-remote "svn"]
url = [path to svn repo including /trunk]
fetch = :refs/remotes/git-svn
提交到svn
git svn fetch
git rebase --onto remotes/git-svn --root master
git svn dcommit
这将从svn中获取空的"第一次提交",将从裸repo克隆的所有更改重新绑定到它上,然后将数据提交回svn。在这一点上,所有的回购都是同步的。
(请注意,对于具有大量历史的现有回购,如果master
的过去历史中存在分支/合并,则可能需要进行一些手动合并(。
设置必要的分支
最初的设置让我们看到master
指向svn。所以
git checkout -b svn
git checkout -B master origin/master
git checkout -b previous
其思想是svn
分支跟踪svn远程,master
跟踪原点/主节点,previous
指向主节点/svn的最后一个同步。通过这种方式,我们可以使用从previous
到master
的提交范围来确定要挑选的内容。
设置挂钩
要进行设置以使同步到svn步骤是自动的,请在裸repo的hooks
文件夹中创建文件post-receive
。内容如下:
#!/bin/sh
#
# After receiving pushed commits, move to Mirror and update to svn
unset GIT_DIR # weird but without this, cd doesn't influence execution directory
cd ..\mirror
git checkout master
git pull origin
git checkout svn
git cherry-pick previous..master
git svn dcommit
git checkout previous
git merge --ff master
exit