git-svn:与svn switch –relocate相当的是什么?
我通过git-svn镜像的svn仓库已经改变了URL。
在香草svn你只是做svn switch --relocate old_url_base new_url_base
。
我怎样才能做到这一点使用git-svn?
只需更改configuration文件中的svn url即可。
这很好地处理我的情况:
https://git.wiki.kernel.org/index.php/GitSvnSwitch
我克隆使用file://
协议,并希望切换到http://
协议。
编辑.git/config
的[svn-remote "svn"]
部分的url
设置是很诱人的,但是它本身不起作用。 一般来说,您需要遵循以下步骤:
- 将svn-remote
url
设置切换到新名称。 - 运行
git svn fetch
。 这需要从svn获取至less一个新版本! - 将svn-remote
url
设置更改回原始URL。 - 运行
git svn rebase -l
来执行本地rebase(使用最后一次fetch操作中的更改)。 - 将svn-remote
url
设置更改回新的URL。 - 现在,
git svn rebase
应该可以再次运行。
冒险的灵魂可能想尝试--rewrite-root
。
你可以看看下面的工作是否正常:
-
如果
svn-remote.svn.rewriteRoot
在configuration文件(.git/config
)中不存在:git config svn-remote.svn.rewriteRoot <currentRepositoryURL>
-
如果
svn-remote.svn.rewriteUUID
在configuration文件中不存在:git config svn-remote.svn.rewriteUUID <currentRepositoryUUID>
currentRepositoryUUID
可以从.git/svn/.metadata
。 -
git config svn-remote.svn.url <newRepositoryURL>
不幸的是,这些答案中的大部分链接都不起作用,所以我将从git wiki中复制一些信息以供将来参考。
这个解决scheme为我工作:
-
编辑
.git/config
的svn-remote
url
(或fetch
path)指向新的域/ url /path -
运行git
git svn fetch
。 这需要从svn获取至less一个新版本! -
如果你现在尝试
git svn rebase
,你会得到这样的错误信息:Unable to determine upstream SVN information from working tree history
我认为这是因为
git svn
被这样一个事实所困惑,即在获取之前你的最新提交将会有一个指向旧path的git-svn-id
,这个path与.git/config
find的path不匹配。 -
作为解决方法,将
svn-remote
url
(或fetch
path)更改回原始域/ url /path -
现在再次运行
git svn rebase -l
来执行一个本地rebase,并在最后一次fetch操作中进行更改。 这一次它会工作,显然是因为git svn
不会被新头的git-svn-id
与.git/config
中的git-svn-id
不匹配的事实混淆。 -
最后,将
svn-remote
url
(或fetch
path)更改回新的域/ url /path -
在这一点上
git svn rebase
应该再次工作!
原始信息在这里find。
Git svn严重依赖于svn的URL。 每个从svn导入的提交都有一个包含svn URL的git-svn-id
。
一个有效的重定位策略是在新的仓库上调用git-svn clone
,并将这些更改合并到新的仓库中。 有关更详细的过程,请参阅此文章:
http://www.sanityinc.com/articles/relocating-git-svn-repositories
git filter-branch
这个脚本 ,从博客条目 ,已经为我工作。 提供旧的和新的repo URL作为参数,就像svn switch --relocate
。
该脚本调用git filter-branch
来replace提交消息中的git-svn-id
中的Subversion URL,更新.git/config
,并使用git svn rebase
重新创buildgit-svn
元数据。 虽然git svn clone
可能是更强大的解决scheme,但是filter-branch
方法对于巨大的存储库(几个小时与几天)来说工作得更快。
#!/bin/sh # Must be called with two command-line args. # Example: git-svn-relocate.sh http://old.server https://new.server if [ $# -ne 2 ] then echo "Please invoke this script with two command-line arguments (old and new SVN URLs)." exit $E_NO_ARGS fi # Prepare URLs for regex search and replace. oldUrl=`echo $1 | awk '{gsub("[\\\.]", "\\\\\\\&");print}'` newUrl=`echo $2 | awk '{gsub("[\\\&]", "\\\\\\\&");print}'` filter="sed \"s|^git-svn-id: $oldUrl|git-svn-id: $newUrl|g\"" git filter-branch --msg-filter "$filter" -- --all sed -i.backup -e "s|$oldUrl|$newUrl|g" .git/config rm -rf .git/svn git svn rebase
git_fast_filter
但比git-filter-branch
(即分钟而不是小时)更快,但在精神上相似,则是使用git_fast_filter
。 但是,这需要更多的编码,并且没有整齐的随时可用的解决scheme。 与git-filter-branch
,这将创build一个旧的回购。 假设master
节点指向最后一个SVN提交。
- 从Gitorious回购中克隆
git_fast_filter
。 - 在克隆
git_fast_filter
的同一目录下创build一个Python脚本,使用chmod +x
设置可执行位。 调整旧的和新的存储库path。 (脚本的内容也粘贴在下面。) - 使用
git init
初始化一个新的目标仓库,将工作目录更改为这个新的仓库。 -
执行以下pipe道:
(cd path/to/old/repo && git-fast-export --branches --tags --progress=100) | \ path/to/git_fast_filter/commit_filter.py | git-fast-import
-
复制
.git/config
,以及其他相关的文件.git/info
从旧的回购到新的回购。 - 删除
.git/svn
。 -
让
git-svn
知道新的版本号映射-
执行
git branch refs/remotes/git-svn master
- 你的git-svn遥控器可能与
refs/remotes/git-svn
,请咨询.git/config
,svn-remote
部分
- 你的git-svn遥控器可能与
-
执行
git svn info
。 如果这个命令冻结,有些事情是错误的。 它应该重build修订号映射。 -
删除假分支
refs/remotes/git-svn
,它会被git-svn
重新创build
-
- 通过调用
git svn rebase
同步。
以下是commit_filter.py
的内容,根据需要replaceIN_REPO
和OUT_REPO
的值:
#!/usr/bin/python from git_fast_filter import Commit, FastExportFilter import re import sys IN_REPO = "https://svn.code.sf.net/p/matsim/code" OUT_REPO = "https://svn.code.sf.net/p/matsim/source" IN_REPO_RE = re.compile("^git-svn-id: %s" % re.escape(IN_REPO), re.M) OUT_REPO_RE = "git-svn-id: %s" % OUT_REPO def my_commit_callback(commit): commit.message = IN_REPO_RE.sub(OUT_REPO_RE, commit.message) sys.stderr.write(".") filter = FastExportFilter(commit_callback = my_commit_callback) filter.run()
上面的git svn rebase -l
解决scheme对我不起作用。 我决定以不同的方式去做:
- 克隆旧的SVN回购成git回购新
old
SVN到git回购new
- 把
old
变成new
-
cd new
-
git fetch ../old
-
git tag old FETCH_HEAD
-
-
old
(因为old
根目录中的树木是相同的)-
git checkout master
(假设master
分支指向SVN头,干净的克隆就是这种情况,否则在你启动之前需要提交dcommit)。 -
git rebase --root --onto old
-
- 重新构build
new
的git-svn元数据来考虑rebase-
git update-ref --no-deref refs/remotes/git-svn master
(根据你的克隆方式调整远程ref,例如可以是refs/remotes/svn/trunk
) -
rm -r .git/svn
-
git svn info
-
基于对这个问题的其他一些反应,我想出了一个处理git-svn重定位的Ruby脚本。 你可以在https://gist.github.com/henderea/6e779b66be3580c9a584find它。;
它处理重定位而不检出另一个副本,甚至可以处理在一个或多个分支中存在未被推入的更改(因为中断了常规逻辑)的情况。 它使用git filter-branch回答(对于主要逻辑)的东西,以及将分支从一个回购实例复制到另一个实例(用于以未推送的更改复制分支)的答案。
我一直在使用它来重新定位一堆我工作的git-svn repos,而这个版本的脚本(我已经经历了无数次的迭代)似乎对我有用。 这不是超快的,但它似乎处理我遇到的所有情况,并导致完全重新安置的回购。
该脚本使您可以select在进行任何更改之前创build回购副本,以便您可以使用此选项创build备份。 如果您在任何分支中有未取消推送的更改,则需要创build副本。
该脚本不使用普通MRI Ruby安装中没有包含的任何gem或其他库。 它使用MRI中包含的readline和fileutils库。
希望我的脚本能够certificate对别人有用。 随意对脚本进行更改。
注意:我只在OS X 10.10 Yosemite上使用git 2.3.0 / 2.3.1和Ruby 2.2.0testing了这个脚本(因为这是我使用的环境),但我也希望它能在其他环境中工作。 虽然没有关于Windows的保证。