如何将 svn 分支和标记导入 git-svn?

我有一个中央 SVN 存储库,我必须承诺,但我有一个热情的 git (像任何其他开发人员我知道)。这个案子是众所周知的。

然后我读到了 git-svn,并尝试了一下。因为我不需要完整的历史,仅仅从两个月左右,我喜欢这样:

git svn clone -r 34000 -s https://svn.ourdomain.com/svn/repos/Project/SubProject

子项目像往常一样有子目录 trunktagsbranches

然后,为了得到最后的修订,我做了

git svn rebase

一些下载后,很好。最后的修订,日志等。好,现在我将切换到我的功能分支。

$ git branch
* master
$ git branch -r
trunk
$ git branch -a
* master
remotes/trunk

问题是: 我的树枝在哪里?我做错什么了吗?我应该怎样做才能得到我的分支机构在新的 git 回购?

Git-svn,无论我在哪里读到它,都明智地处理了分支和标记,但是这种行为并不是我所期望的。谢谢!

编辑 : 我刚刚发现 git svn fetch可以做到这一点。但它会得到所有的修订,这是我不喜欢的东西。

60312 次浏览

如果您希望在从 svn 导入之后执行 git 分支时看到您的分支,那么应该使用 Ruby 脚本 < strong > svn2git (and git2svn)

它比 git svn clone 好,因为如果你在 svn 中有这段代码:

  trunk
...
branches
1.x
2.x
tags
1.0.0
1.0.1
1.0.2
1.1.0
2.0.0

git-svn将遍历提交历史以构建一个新的 git 回购。
它将所有分支和标记作为远程 SVN 分支导入,而您真正需要的是 git 本地分支和 git 标记对象。 所以在导入这个项目之后,你会得到:

  $ git branch
* master
$ git branch -a
* master
1.x
2.x
tags/1.0.0
tags/1.0.1
tags/1.0.2
tags/1.1.0
tags/2.0.0
trunk
$ git tag -l
[ empty ]

svn2git完成你的项目之后,你会得到这个:

  $ git branch
* master
1.x
2.x
$ git tag -l
1.0.0
1.0.1
1.0.2
1.1.0
2.0.0

你说你还没有得到你的支行在你的结帐。

这可能是一个与您的 svn 回购布局问题。

「标准布局」为:

branches/

tags/

trunk/

如果你的布局是这样的:

branches/user1/

branches/user2/

然后,当您执行 git svn get/xon 操作时,您将丢失您的分支。

为了解决这个问题,你应该给出论点

--branches=branches/*/*呼叫克隆人。

你需要几个步骤。

  1. 提供正确的主干、分支和标签文件夹名称并获取 svn 回购:

    git svn init -t tags -b branches -T trunk https://mysvn.com/svnrepo
    git svn fetch
    
  2. Since tags in svn are real branches, create git tags from tag branches:

    git for-each-ref --format="%(refname:short) %(objectname)" refs/remotes/tags |  cut -d / -f 3- |
    while read ref
    do
    echo git tag -a $ref -m 'import tag from svn'
    done
    
  3. Delete tag branches

    git for-each-ref --format="%(refname:short)" refs/remotes/tags | cut -d / -f 2- |
    while read ref
    do
    echo git branch -rd $ref
    done
    
  4. Since tags marked in the previous step point to a commit "create tag", we need to derive "real" tags, i.e. parents of "create tag" commits.

    git for-each-ref --format="%(refname:short)" refs/tags |
    while read ref
    do
    tag=`echo $ref | sed 's/_/./g'` # give tags a new name
    echo $ref -\> $tag
    git tag -a $tag `git rev-list -2 $ref | tail -1` -m "proper svn tag"
    done
    
  5. All we have to do now is to remove old tags.

这利用了 Vanuan 上面的答案,但是它在新的 git标记中保留了原来 svn标记的 信息

$ git for-each-ref --format="%(refname:short) %(objectname)" refs/remotes/tags \
| while read BRANCH REF
do
TAG_NAME=${BRANCH#*/}
BODY="$(git log -1 --format=format:%B $REF)"


echo "ref=$REF parent=$(git rev-parse $REF^) tagname=$TAG_NAME body=$BODY" >&2


git tag -a -m "$BODY" $TAG_NAME $REF^  &&\
git branch -r -d $BRANCH
done

这和上面 Nicolaii.rostov 的答案一样,但是我只是改变了参考路径 我用 refs/remotes/origin/tags代替了 refs/remotes/tags 我使用 git 版本 2.1.1cygwin终端。

$ git for-each-ref --format="%(refname:short) %(objectname)" refs/remotes/origin/tags \
| while read BRANCH REF
do
TAG_NAME=${BRANCH#*/}
BODY="$(git log -1 --format=format:%B $REF)"


echo "ref=$REF parent=$(git rev-parse $REF^) tagname=$TAG_NAME body=$BODY" >&2


git tag -a -m "$BODY" $TAG_NAME $REF^  &&\
git branch -r -d $BRANCH
done

我遇到了同样的问题——当我指定修订时,标签和分支都丢失了:

$ git svn clone -r 34000 -s https://...

解决办法是指定一系列的修订,-r 34000:HEAD:

$ git svn clone -r 34000:HEAD -s https://...

Git 邮件列表给了我提示。

对于那些必须在工作中使用 Windows 的人来说,这里有一个使用 git 2.17.0的最新解决方案(理论上也适用于以前的版本)

git svn init -t tags -b branches -T trunk https://mysvn.com/svnrepo


git svn fetch


for /f "tokens=1-2 delims= " %a in ('git for-each-ref --format="%(refname:lstrip=-1) %(objectname)" refs/remotes/origin/tags') do git tag -a %a %b -m "import tag from svn"

我写了一个脚本来帮助您按照需要进行迁移。剧本并不完美,但我希望这能帮到你:

欲了解更多信息,请访问: https://github.com/MPDFT/svn-to-git

#!/bin/bash


####### Project name
PROJECT_NAME="myproject"
EMAIL="mycompany.com"


###########################
####### SVN
# SVN repository to be migrated
BASE_SVN="http://svn.mycompany.com/svn/repo/sistemas/myproject"


# Organization inside BASE_SVN
BRANCHES="branches"
TAGS="tags"
TRUNK="trunk"


###########################
####### GIT
# Git repository to migrate
GIT_URL="https://git.mycompany.com/git/repo/sistemas/myproject.git"


###########################
#### Don't need to change from here
###########################


# Geral Configuration
ABSOLUTE_PATH=$(pwd)
TMP=$ABSOLUTE_PATH/"migration-"$PROJECT_NAME


# Branchs Configuration
SVN_BRANCHES=$BASE_SVN/$BRANCHES
SVN_TAGS=$BASE_SVN/$TAGS
SVN_TRUNK=$BASE_SVN/$TRUNK


AUTHORS=$PROJECT_NAME"-authors.txt"


echo '[LOG] Starting migration of '$SVN_TRUNK
echo '[LOG] Using: '$(git --version)
echo '[LOG] Using: '$(svn --version | grep svn,)


mkdir $TMP
cd $TMP


echo
echo '[LOG] Getting authors'
svn log -q $BASE_SVN | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2"@"$EMAIL">"}' | sort -u >> $AUTHORS


echo
echo '[RUN] git svn clone --authors-file='$AUTHORS' --trunk='$TRUNK' --branches='$BRANCHES' --tags='$TAGS $BASE_SVN $TMP
git svn clone --authors-file=$AUTHORS --trunk=$TRUNK --branches=$BRANCHES --tags=$TAGS $BASE_SVN $TMP


echo
echo '[LOG] Getting first revision'
FIRST_REVISION=$( svn log -r 1:HEAD --limit 1 $BASE_SVN | awk -F '|' '/^r/ {sub("^ ", "", $1); sub(" $", "", $1); print $1}' )


echo
echo '[RUN] git svn fetch -'$FIRST_REVISION':HEAD'
git svn fetch -$FIRST_REVISION:HEAD


echo
echo '[RUN] git remote add origin '$GIT_URL
git remote add origin $GIT_URL


echo
echo '[RUN] svn ls '$SVN_BRANCHES
for BRANCH in $(svn ls $SVN_BRANCHES); do
echo git branch ${BRANCH%/} remotes/svn/${BRANCH%/}
git branch ${BRANCH%/} remotes/svn/${BRANCH%/}
done


git for-each-ref --format="%(refname:short) %(objectname)" refs/remotes/origin/tags | grep -v "@" | cut -d / -f 3- |
while read ref
do
echo git tag -a $ref -m 'import tag from svn'
git tag -a $ref -m 'import tag from svn'
done


git for-each-ref --format="%(refname:short)" refs/remotes/origin/tags | cut -d / -f 1- |
while read ref
do
git branch -rd $ref
done


echo
echo '[RUN] git push'
git push origin --all --force
git push origin --tags


echo 'Sucessufull.'

为了将一个新的 SVN 分支拉入本地 Git-SVN 存储库,我找到了一个简单的方法,它不需要编辑任何配置文件。

您只需要将要添加到本地 git-svn 存储库的分支中最后一次提交的修订号。

如果您有一个新分支的最新 SVN 签出并且安装了 TortoiseSVN,您可以右键单击该文件夹并使用“ TortoiseSVN/Show Log”。

记下最上面的提交(例如45065)。

现在在 Git Bash 中使用以下命令:

git svn fetch -r45065

注意: 您需要将数字 45065替换为提交数字。
Git 现在将把新的远程分支拖放到本地存储库中。

然后,您可以通过创建一个本地分支来检查它。我使用 Git Extension 签出新的分支,使用“ Remote-Branch”和选项“ Create local Branch with name: ...”。
提示: 您可以从您的本地分支名称中删除“ source/”前缀,因为这样可以避免警告“ refname‘ Origin/V8.0’是不明确的”.