Как импортировать ветки svn и теги в git -svn?

У меня есть центральный SVN-репозиторий, который я должен выполнить, но у меня есть страсть к git (как и любой другой разработчик, которого я знаю). Дело хорошо известно.

Потом я прочитал о git-svn и попробовал. Поскольку мне не нужна полная история, примерно через два месяца, я сделал так:

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

Подпроект имел, как обычно, подкаталоги trunk, tags и branches. Отлично.

Затем, чтобы получить последнюю ревизию, я сделал

git svn rebase

Некоторые загрузки позже, отлично. Последняя ревизия, логи и т.д. Хорошо, теперь я переключусь на свою ветку функций.

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

Вопросы: где мои ветки? Я сделал что-то не так? Как мне поступить, чтобы мои ветки попали в новый репозиторий git?

git-svn, где бы я ни читал об этом, имел дело с ветками и тегами, но поведение не то, что я ожидал. Спасибо!

РЕДАКТИРОВАТЬ: Я только что узнал, что git svn fetch сделает это. Но он получит все ревизии, что мне не понравится.

Ответ 1

Вам понадобится несколько шагов.

  • укажите правильные имена папок, ветвей и тегов и выберите svn repo:

    git svn init -t tags -b branches -T trunk https://mysvn.com/svnrepo
    git svn fetch
    
  • Так как теги в 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
    
  • Удаление ветвей тегов

    git for-each-ref --format="%(refname:short)" refs/remotes/tags | cut -d / -f 2- |
    while read ref
    do 
      echo git branch -rd $ref
    done
    
  • Так как теги, отмеченные на предыдущем шаге, указывают на фиксацию "создать тег", нам нужно получить "реальные" теги, т.е. совершают записи "создания тега".

    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
    
  • Все, что нам нужно сделать, это удалить старые теги.

Ответ 2

Это опирается на ответ Vanuan выше, но он сохраняет сообщение исходного тега svn в новом теге git.

$ 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

Ответ 3

Это то же самое, что и ответить nicolai.rostov выше, но я просто изменяю путь refs Я заменил refs/remotes/tags на refs/remotes/origin/tags Я использую git version 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

Ответ 4

Вы говорите, что вы не получили свои ветки в своем оформлении.

Вероятно, это проблема с компоновкой вашего репозитория svn.

"Стандартный макет":

branches/

tags/

trunk/

Если у вас есть свой макет, как это:

branches/user1/

branches/user2/

Затем вы потеряете свои ветки, когда будете делать git svn fetch/clone.

Чтобы исправить это, вы должны указать аргумент

--branches=branches/*/* до git клона.

Ответ 5

Если вы хотите видеть свои ветки при выполнении ветки git после импорта из svn, вы должны использовать ruby ​​script svn2git (и 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

Ответ 6

Я написал скрипт, чтобы помочь мигрировать, как вы хотите. Сценарий не идеален, но я надеюсь, что это поможет вам:

Для получения дополнительной информации вы можете посетить: 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.'

Ответ 7

Для тех, кто должен работать над 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"

Ответ 8

У меня была та же проблема - теги и ветки отсутствовали, когда я указал ревизию:

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

Исправление заключалось в том, чтобы указать диапазон изменений, -r 34000:HEAD:

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

Список рассылки git дал мне подсказку.