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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2244252/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 07:50:22  来源:igfitidea点击:

How to import svn branches and tags into git-svn?

svngitgit-svn

提问by Luís Guilherme

I have got a central SVN repository I must commit to, but I've got a passion for git (like any other developer I know). The case is well known.

我有一个必须提交的中央 SVN 存储库,但我对 git 充满热情(就像我认识的任何其他开发人员一样)。这个案子是众所周知的。

Then I read about git-svn and gave it a try. Since I don't need the full history, just from two months or so, I did like this:

然后我阅读了 git-svn 并尝试了一下。由于我不需要完整的历史记录,只需两个月左右,我就这样做了:

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

SubProject had, as usual, the subdirectories trunk, tagsand branches. Great.

像往常一样,SubProject 有子目录trunk,tagsbranches. 伟大的。

Then, in order to get the last revision, I did

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

git svn rebase

Some downloads later, great. Last revision, logs, etc. Ok, now I'll switch to my feature branch.

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

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

The questions are: Where are my branches? Have I done something wrong? How should I do in order to get my branches in the new git repo?

问题是:我的分支机构在哪里?我做错了什么吗?我应该怎么做才能在新的 git repo 中获取我的分支?

git-svn, wherever I have read about it, dealt wisely with branches and tags, but the behaviour is not what I expected. Thanks!

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

EDIT: I have just found out that git svn fetchwill do it. But it will get all revisions, which is something I wouldn't like.

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

回答by Vanuan

You'll need several steps.

你需要几个步骤。

  1. supply proper trunk, branches and tags folder names and fetch svn repo:

    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.

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

    git svn init -t tags -b branches -T trunk https://mysvn.com/svnrepo
    git svn fetch
    
  2. 由于 svn 中的标签是真正的分支,因此从标签分支创建 git 标签:

    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. 删除标签分支

    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. 由于在上一步中标记的标签指向提交“创建标签”,我们需要派生“真实”标签,即“创建标签”提交的父项。

    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. 我们现在要做的就是删除旧标签。

回答by n.r.

This draws on Vanuan's answer above, but it preserves the messageof the original svntag in the new gittag.

这借鉴了上面 Vanuan 的回答,但它在新标签中保留了原始标签的消息svngit

$ 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

回答by Mohamed EL HABIB

This is the same as nicolai.rostov's answer above, but i just change the refs path I replaced refs/remotes/tagsby refs/remotes/origin/tagsI'm using git version 2.1.1into cygwinterminal.

这与上面 nicolai.rostov 的回答相同,但我只是更改了我替换的 refs 路径refs/remotes/tagsrefs/remotes/origin/tags我正在使用 git 版本2.1.1进入cygwin终端。

$ 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

回答by rmk

You say that you haven't gotten your branches in your checkout.

你说你在结账时没有得到你的分支机构。

This is likely a problem with the layout of your svn repo.

这可能是 svn 存储库布局的问题。

The 'standard layout' is:

“标准布局”是:

branches/

branches/

tags/

tags/

trunk/

trunk/

If you have your layout like this:

如果你有这样的布局:

branches/user1/

branches/user1/

branches/user2/

branches/user2/

Then, you will lose your branches when you do git svn fetch / clone.

然后,当您执行 git svn fetch / clone 时,您将丢失分支。

To fix this, you should give the argument

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

--branches=branches/*/*to git clone.

--branches=branches/*/*git克隆。

回答by VonC

If you want to see your branches when doing a git branch after a import from svn, you should use the ruby script svn2git (and git2svn)

如果您想在从 svn 导入后执行 git 分支时查看您的分支,您应该使用 ruby​​ 脚本svn2git(和 git2svn)

It is better than git svn clone because if you have this code in svn:

它比 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-svnwill go through the commit history to build a new git repo.
It will import all branches and tags as remote SVN branches, whereas what you really want is git-native local branches and git tag objects. So after importing this project, you would get:

git-svn将通过提交历史来构建一个新的 git repo。
它会将所有分支和标签作为远程 SVN 分支导入,而您真正想要的是 git-native 本地分支和 git tag 对象。所以导入这个项目后,你会得到:

  $ 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 ]

After svn2gitis done with your project, you'll get this instead:

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

回答by carolnogueira

I wrote a script to help migrate as you want. The script is not perfect, but I hope this could help you:

我编写了一个脚本来帮助您根据需要进行迁移。该脚本并不完美,但我希望这可以帮助您:

For more information, you can visit: https://github.com/MPDFT/svn-to-git

更多信息可以访问: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("^ ", "", ); sub(" $", "", ); print " = "" <""@"$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("^ ", "", ); sub(" $", "", ); print }' )

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.'

回答by Qianlong

For those who have to work on Windws at work, here is a solution up-to-date with git version 2.17.0 (and theoretically also works for versions before)

对于那些必须在工作中使用 Windws 的人,这里有一个最新的 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"

回答by cweiske

I had the same problem - tags and branches were missing when I specified the revision:

我遇到了同样的问题 - 指定修订版时缺少标签和分支:

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

The fix was to specifiy a range of revisions, -r 34000:HEAD:

修复是指定一系列修订,-r 34000:HEAD

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

The git mailing list gave me the hint.

git的邮件列表给我的暗示。