Migrando repositórios do SVN para o GIT

Posted on Sat 14 December 2019 in Sysadmin • 3 min read

Nesse post vou mostrar como migrar projetos do svn para o git.

Vou partir do principio que já entende como o Subversion e o Git se comportam.

Para tudo ocorrer como esperado, o nosso ambiente precisa estar seguinte forma:

  • Cliente svn instalado
  • Cliente git mais recente instalado
  • Pacote git-svn
  • PATH configurado que inclua o cliente git,svn e git-svn

Primeiramente vamos obter os autores do repositorio svn

$ cd ~/
$ svn log --no-auth-cache -q http://svn.yourcompany/svn/repos/sample-repo/ \ 
| awk -F '|' '/^r/ {sub("^ ", "", $2);
        sub(" $", "", $2); print $2" = "$2" <"$2">"}' \
| sort -u >authors-transform.txt

Agora vamos 'clonar' localmente o nosso repositorio, esse processo pode demorar horas dependendo do tamanho do repositorio. Aqui o --stdlayout indica que o repositório segue o modelo tradicional, com pastas trunk, tags e branches.

$ cd ~/
$ git svn --username <usuario> --password <password> \
  clone http://svn.yourcompany/svn/repos/sample-repo/ \
  --no-metadata -A authors-transform.txt --stdlayout

Após finalizar, vamos criar um repositorio git do tipo bare e vamos indicar que o branch atual é o trunk

$ mkdir -p ~/sample-repo.git
$ cd ~/sample-repo.git
$ git init --bare
$ git symbolic-ref HEAD refs/heads/trunk

Agora temos um clone completo do repositório svn no diretório sample-repo, e um repositório git bare em sample-repo.git Vamos fazer um push do repositório svn clonado para o repositório git local. Configuramos tambem para que o push seja dos branches refs/remotes e dos refs/heads.

$ cd ~/sample-repo
$ git remote add bare ~/sample-repo.git
$ git config remote.bare.push 'refs/remotes/*:refs/heads/*'
$ git push bare

No final do passo anterior, o repositório svn será copiado para o git, mas precisaremos acertar algumas convenções git. Vamos renomear Trunk para *Master

$ cd ~/sample-repo.git
$ git branch -m trunk master

Precisaremos fazer uma limpeza de branches no git.

$ cd ~/sample-repo.git
$ git for-each-ref --format='%(refname)' refs/heads/origin/tags |
  cut -d / -f 5 |
  while read ref
    do
      echo $ref
      echo ""
      git tag "$ref" "origin/tags/$ref";
      git branch -D "origin/tags/$ref";
    done

E pra finalizar, vamos fazer o push para o servidor git da empresa

$ cd ~/sample-repo.git
$ git remote add origin https://username:password@gitserver/repo-sample
$ git push -u origin --all
$ git push -u origin --tags

Para facilitar o processo, criei um script para executar com maior facilidade.

Ele se encontra abaixo e no meu Github

Bons commits!! :)

#!/bin/bash 

if [[ -z "$1" || -z "$2" ]] ;then
    echo "Argument Null. Exiting"
    exit 1
else
    if [[ $1 != http?(s)://svn/* || $2 != git@git* ]]; then
        echo -e "Invalid URL. Exiting"
        echo -e "How to insert parameters:\n${0##*/} SVN GIT"
        exit 1
    else
        SVN=$1
        REPO_GIT=$2
    fi
fi

alias svn="svn --non-interactive --trust-server-cert"
PROJECT=${SVN##*/}

function create_dirs(){
    echo ""
    echo "Creating Directories $PROJECT"
    echo "---------------------------------------------"
    if [ -d ~/$PROJECT.git ]; then
        echo -e "Removing old directories | $PROJECT.git"
        rm -rf ~/$PROJECT.git
    fi
    if [ -d ~/repo-$PROJECT ]; then
        echo -e "Removing old directories  | repo-$PROJECT"
        rm -rf ~/repo-$PROJECT
    fi
    mkdir -p ~/repo-$PROJECT
    mkdir -p ~/$PROJECT.git
    if [ $? -eq 0 ]; then
        echo "Directories created"
        clone_repo_svn
    fi
}

function clone_repo_svn(){
    cd ~/repo-$PROJECT
    echo ""
    echo "Cloning repositories SVN - $SVN"
    echo "---------------------------------------------"
    svn log --no-auth-cache -q $SVN \ 
        | awk -F '|' '/^r/ {sub("^ ", "", $2); \
                sub(" $", "", $2); print $2" = "$2" <"$2">"}' \
        | sort -u >authors-transform.txt
    echo ""
    time git svn clone $SVN --no-metadata -A authors-transform.txt --stdlayout 
    if [ $? -eq 1 ]; then
        echo -e "Error cloning repositories\n"
        exit 1
    else
        git_config
    fi
}


function git_config(){
    echo ""
    echo "Convert to GIT - $PROJECT"
    echo "---------------------------------------------"
    cd ~/$PROJECT.git
    git init --bare
    git symbolic-ref HEAD refs/heads/trunk
    cd ~/repo-$PROJECT/$PROJECT
    git remote add bare ~/$PROJECT.git/
    git config remote.bare.push 'refs/remotes/*:refs/heads/*'
    git push bare
    cd ~/$PROJECT.git/
    git branch -m origin/trunk master
    git for-each-ref --format='%(refname)' refs/heads/origin/tags | 
    cut -d / -f 5 |
    while read ref
    do
      echo $ref
      echo ""
      git tag "$ref" "origin/tags/$ref";
      git branch -D "origin/tags/$ref";
    done
    git_pull
}

function git_pull(){
    echo ""
    echo "Push GIT - $REPO_GIT"
    echo "---------------------------------------------"
    cd ~/$PROJECT.git
    git remote add origin $REPO_GIT
    git push -u origin --all
    git push -u origin --tags
}

function main(){
    create_dirs
}

main