具有非标准布局的Git-SVN迁移不显示合并 [英] Git-svn migration with non-standard layout doesn't show merges
问题描述
在尝试了该网站的一些选项和大量提示以及其他建议之后,我陷入了困境.我的主要问题是:我想将SVN存储库(的一部分)迁移到Git,以保留历史记录.SVN布局是非标准的,在 git svn clone
之后,我确实看到了正确的分支出现,但是当我尝试例如将 master
合并到一个分支中,我发现冲突都说都添加了一组文件.如果我看看例如 gitg
我看到了分支,但它们似乎从未从 master
/trunk分支(因此从这个角度看,两者都添加"的冲突似乎是合乎逻辑的),我也看不到任何分支图中的合并(例如,从主干到分支)(提交在那里,它们只是不链接到 gitg
的图形显示中的分支).实际上,对于某些分支,我什至看到两个相同的提交,一个接一个,另一个提交给master,一个提交给分支.我在SVN中创建分支的方式是使用 svn copy
.
更多详细信息:
存储库布局: SVN存储库布局的略微简化的示意图(结构相同,名称不同,某些目录已被省略)
pkg项目1项目2解放分行专案1-功能1项目1解放Project1-修补程序项目1解放库功能标签项目1v0.1.0v0.2.0项目1解放项目2v0.1.0
Lib
目录与Project1紧密相关,但也被其他人使用.这就是为什么我(从v0.2.0开始)在分支和标记中创建 Project1
和 Lib
子目录结构的原因.
我的 git svn
工作流程:这是我用来克隆SVN存储库的最有前途的命令:
git svn clone \--prefix = svn/\--trunk = pkg \--branches = branches \--tags =标签/Project1 \-A authors.txt \--ignore-paths ='^ pkg/(?! Project1 | Lib)'\svn + ssh://user@svn.r-forge.r-project.org/svnroot/MyTool SVN2GitMigration
这里有-ignore-paths
选项,因此我只保留两个目录( Project
和 Lib
)我有兴趣.我没有过滤分支,因为只有一个分支与 Project1
不直接相关.
之后,我将远程分支转换为本地分支(并删除远程分支),然后将标签转换为适当的Git标签.
编辑开始:对提交进行更仔细的检查后发现,我有很多空的提交.事实证明,这是由于-ignore-paths
选项所致:空的提交是在目录树中被忽略的部分中完成的.因此,此选项的行为并不符合我的预期.回到绘图板...编辑结束
EDIT2 实际上,使用 git filter-branch --tag-name-filter cat --prune-empty---all
,我设法删除了空提交 EDIT2 END
合并问题的可能原因:分支/标记不是单个SVN提交,因为它们首先包含一个在其中创建 branches/Project1-featureX
目录的提交,然后是两条 svn copy
行,其中我从主干中复制 Project1
和 Lib
目录.
非常欢迎提出有关如何正确转换此SVN存储库的建议!如果,这意味着以某种方式失去 Lib
没什么大不了的.迁移完成后,我仍打算将两者分开.
经过反复试验,我通过以下方式解决了我的问题:
准备
首先,我初始化了一个没有任何分支或标签的存储库:
git svn init \--prefix = svn/\--trunk = pkg/Project1 \svn + ssh://user@svn.r-forge.r-project.org/svnroot/MyTool \SVN2GitMigration
接下来,我添加了作者信息:
cd SVN2GitMigrationgit config svn.authorsfile ../authors.txt
此后,我的 .git/config
文件具有以下内容:
[核心]repositoryformatversion = 0filemode = true裸=假logallrefupdates = true[svn-remote"svn"]网址= svn + ssh://user@svn.r-forge.r-project.org/svnroot/MyTool \提取= pkg/Project1:refs/remotes/svn/trunk[svn]authorsfile = ../authors.txt
为了获取分支和标签,我将该文件更改为:
[核心]repositoryformatversion = 0filemode = true裸=假logallrefupdates = true[svn-remote"svn"]网址= svn + ssh://user@svn.r-forge.r-project.org/svnroot/MyTool \提取= pkg/Project1:refs/remotes/svn/trunk标签=标签/Project1/{v0.4.2,v0.4.1,v0.4.0,v0.3.0,v0.2.2,v0.2.0}/Project1:refs/remotes/svn/tags/*标签=标签/项目1/{v0.2.1,v0.1-9e,v0.1.3}:引用/远程处理/svn/标签/*分支=分支/{Project1-v0.4.2-fixes,Project1-v0.4.1-fixes,Project1-refactor,Project1-feature1}/Project1:refs/remotes/svn/*分支=分支/{Project1-feature2}:引用/远程/svn/*[svn]authorsfile = ../authors.txt
请注意,每行 branch
和 tags
行如何在 {}
中包含目录名称列表,即使其中仅包含一个目录名称也是如此.没有这个,获取将无法进行.
下载SVN数据
要下载并转换SVN存储库,请运行:
git svn提取
后处理
此后,需要一些后处理.要将删除标记和分支转换为适当的本地标记和分支并删除远程标记和分支,请运行:
for`git branch -r | grep -v标签|中的分支|grep -v干|sed's/svn \///'`;做git branch $ branch遥控器/svn/$ branch;完毕用于`git branch -r | grep标签|中的标签sed's; svn/tags/;;'`;做git tag $ tag remotes/svn/tags/$ tag;完毕对于`git branch -r`中的br;做git branch -d -r $ br完毕
将 svn:ignore
属性转换为 .gitignore
文件
git svn show-ignore>.gitignoregit添加.gitignoregit commit -m基于svn:ignore属性添加了.gitignore文件"
使用 gitg
或 gitk
检查git repo后,发现许多合并丢失了(未在图中显示),因此我不得不手工嫁接这些合并通过将父提交哈希添加到 .git/info/grafts
文件(文件格式为 merge_hash parent1_hash parent2_hash
).请注意, gitk
显示了嫁接,而 gitg
直到被永久化后才显示.
使提交永久使用
git filter-branch --tag-name-filter cat---all
并删除由 git filter-branch
运行创建的备份:
git for-each-ref --format =%(refname)" refs/original/|xargs -n 1 git update-ref -d
总结
现在所有内容都已转换,将存储库克隆到一个裸露的存储库中:
git clone --bare SVN2GitMigration Project1.git
并将其推送到Github:
cd Project1.gitgit push --mirror https://github.com/mygithubuser/Project1.git
参考文献
感谢以下站点为您指出正确的方向:
- http://john.albin.net/git/convert-subversion-to-git
- http://www.sailmaker.co.uk/blog/2013/05/05/migrating-from-svn-to-git-preserving-branches-and-tags-3/
- http://blokspeed.net/blog/2010/09/conversion-from-subversion-to-git/
- http://blog.agavi.org/post/16865375185/fixing-svn-merge-history-in-git-repositories
- http://patrickbougie.com/2013/03/18/convert-svn-to-git-repository/
- git svn指定非标准svn存储库布局上的分支和标签
After trying several options and a bunch of hints from this site and others I'm stuck. My main question is the following: I'd like to migrate (part of) an SVN repository to Git, preserving history. The SVN layout is non-standard and after git svn clone
I do see the right branches appear, but when I try to e.g. merge master
into a branch, I get conflicts that say both added a set of files. If I take a look in e.g. gitg
I see the branches, but they never seem to branch from master
/trunk (so the "both added" conflicts seem logical from that perspective), nor do I see any of the merges (e.g. from trunk to a branch) in the graph (the commits are there, they just don't link to branches in the graphical display of gitg
). In fact, for some branches I even see two identical commits one after the other (one for master, one for the branch).
The way I created the branches in SVN was using svn copy
.
Some more details:
Repository layout: A slightly simplified schematic of the SVN repo layout (the structure is the same, names are different, some directories have been omitted)
pkg
Project1
Project2
Lib
branches
Project1-feature1
Project1
Lib
Project1-hotfix
Project1
Lib
Lib-feature
tags
Project1
v0.1.0
v0.2.0
Project1
Lib
Project2
v0.1.0
The Lib
directory is closely associated with Project1, but also used by others. That is why I (starting with v0.2.0) created to Project1
and Lib
subdirectory structure in the branches and tags.
My git svn
workflow: This is the most promising command I used to clone the SVN repo:
git svn clone \
--prefix=svn/ \
--trunk=pkg \
--branches=branches \
--tags=tags/Project1 \
-A authors.txt \
--ignore-paths='^pkg/(?!Project1|Lib)' \
svn+ssh://user@svn.r-forge.r-project.org/svnroot/MyTool SVN2GitMigration
The --ignore-paths
option is there so that I keep only the two directories (Project
and Lib
) in which I'm interested. I do not filter on branches since there is only one branch not directly related to Project1
.
After that I convert the remote branches to local branches (and remove the remote branches), then convert the tags to proper Git tags.
EDIT START: Closer inspection of the commits reveals that I have many empty commits. These turn out to be due to the --ignore-paths
option: the empty commits are done in parts of the directory tree that are ignored. So this option doesn't really behave as I expected.
Back to the drawing board...
EDIT END
EDIT2
Actually, using git filter-branch --tag-name-filter cat --prune-empty -- --all
I managed to remove the empty commits
EDIT2 END
Possible cause of my merge problems: Branches/Tags are not single SVN commits because they first consist of a commit in which I create the branches/Project1-featureX
directory, followed by two svn copy
lines in which I copy the Project1
and Lib
directories from trunk.
Suggestions on how to properly convert this SVN repo are very welcome! If, somehow this means loosing Lib
that isn't a big deal. I'm planning to separate the two anyway once the migration has finished.
After a lot of trial and error I solved my problem in the following way:
Preparation
First I initialised a repository without any branches or tags:
git svn init \
--prefix=svn/ \
--trunk=pkg/Project1 \
svn+ssh://user@svn.r-forge.r-project.org/svnroot/MyTool \
SVN2GitMigration
Next I added the author information:
cd SVN2GitMigration
git config svn.authorsfile ../authors.txt
After this, my .git/config
file had the following contents:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[svn-remote "svn"]
url = svn+ssh://user@svn.r-forge.r-project.org/svnroot/MyTool \
fetch = pkg/Project1:refs/remotes/svn/trunk
[svn]
authorsfile = ../authors.txt
In order to get the branches and tags I changed that file to:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[svn-remote "svn"]
url = svn+ssh://user@svn.r-forge.r-project.org/svnroot/MyTool \
fetch = pkg/Project1:refs/remotes/svn/trunk
tags = tags/Project1/{v0.4.2,v0.4.1,v0.4.0,v0.3.0,v0.2.2,v0.2.0}/Project1:refs/remotes/svn/tags/*
tags = tags/Project1/{v0.2.1,v0.1-9e,v0.1.3}:refs/remotes/svn/tags/*
branches = branches/{Project1-v0.4.2-fixes,Project1-v0.4.1-fixes,Project1-refactor,Project1-feature1}/Project1:refs/remotes/svn/*
branches = branches/{Project1-feature2}:refs/remotes/svn/*
[svn]
authorsfile = ../authors.txt
Notice how each branches
and tags
line has a list of directory names in {}
, even if it only contains one directory name. Without this, the fetching won't work.
Download the SVN data
To download and convert the SVN repository run:
git svn fetch
Postprocessing
After this, some post-processing is required. To convert the remove tags and branches to proper local tags and branches and delete the remote ones run:
for branch in `git branch -r |grep -v tags| grep -v trunk | sed 's/svn\///'`; do
git branch $branch remotes/svn/$branch;
done
for tag in `git branch -r |grep tags| sed 's;svn/tags/;;'`; do
git tag $tag remotes/svn/tags/$tag;
done
for br in `git branch -r`; do
git branch -d -r $br
done
Convert the svn:ignore
properties to a .gitignore
file
git svn show-ignore > .gitignore
git add .gitignore
git commit -m "Added .gitignore file based on the svn:ignore properties"
After inspecting the git repo with gitg
or gitk
it turned out that many merges were missing (not show in the graph), so I had to graft those by hand by adding the parent commit hashes to the .git/info/grafts
file (the file format is merge_hash parent1_hash parent2_hash
). Note that gitk
shows the grafts, whereas gitg
doesn't until they are made permanent.
To make the commits permanent use
git filter-branch --tag-name-filter cat -- --all
and to remove the backups created by git filter-branch
run:
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
Wrapping up
Now that everything is converted, clone the repository into a bare one:
git clone --bare SVN2GitMigration Project1.git
and push that to Github:
cd Project1.git
git push --mirror https://github.com/mygithubuser/Project1.git
References
Thanks to the following sites for pointing to the right directions:
- http://john.albin.net/git/convert-subversion-to-git
- http://www.sailmaker.co.uk/blog/2013/05/05/migrating-from-svn-to-git-preserving-branches-and-tags-3/
- http://blokspeed.net/blog/2010/09/converting-from-subversion-to-git/
- http://blog.agavi.org/post/16865375185/fixing-svn-merge-history-in-git-repositories
- http://patrickbougie.com/2013/03/18/convert-svn-to-git-repository/
- git svn specify branches and tags on a non standard svn repository layout
这篇关于具有非标准布局的Git-SVN迁移不显示合并的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!