Migrando repositórios CVS para o Git

O Git vem cada vez mais se consolidando como o sistema de versionamento de arquivos em projetos de software, especialmente na comunidade open source, onde é comum que dezenas de desenvolvedores trabalhem no mesmo repositório. Imagine ainda que estes desenvolvedores estão distribuídos ao redor do mundo, e que é necessário um bom nível de controle para evitar que desenvolvedores menos experientes tomem decisões equivocadas e acabem comprometendo a credibilidade da ferramenta perante o mercado.

Em épocas de cvs/svn, este controle era feito através de permissões bem específicas. Apenas alguns usuários eram considerados commiters e tinham poder de escrever no repositório. Outros desenvolvedores, caso quisessem contribuir, precisavam distribuir suas sugestões na forma de patches até ganhar a confiança dos donos do projeto e também permissão de commiter. Já com o Git tudo ficou mais fácil, qualquer pessoa pode fazer um clone do repositório, criar um branch para implementar sua sugestão e depois abrir uma solicitação – um pull request – para que suas mudanças sejam incorporadas à linha principal de desenvolvimento. Esta solicitação passa então por uma revisão e só depois de aprovada é de fato integrada ao branch principal, tornando o processo bem mais simples.

Neste processo todo, além do ganho no controle de commits do repositório, ganhamos também um processo de revisão de código estruturado através de pull requests e a facilidade de trabalhar de forma distribuída: cada funcionalidade ou correção de bug em um branch específico, que depois será ou não integrado ao branch principal.

Mas e no mundo corporativo?

Tudo isso parece bastante atraente para o mundo corporativo, onde o controle de acesso ao fonte e code review são fundamentos importantes. Mas há um outro lado da moeda: muitas empresas possuem sistemas que começaram a ser escritos nos anos 80, 90, com um um histórico de 20-30 anos de commits em repositórios CVS. Perder este histórico e começar tudo zero a partir da versão mais recente do HEAD não parece uma boa ideia – como alguém poderia analisar as mudanças feitas em um arquivo qualquer? Teríamos que manter o CVS ativo apenas para consulta por muito tempo até o projeto no Git ganhar um histórico próprio.

Felizmente existem no mercado ferramentas que permitem migrar todo o histórico do CVS para o Git. A seguir vamos monstrar como migrar um repositório fictício.

Preparação do ambiente

Vamos precisar inicialmente de um ambiente Linux diferente do servidor CVS, mas que tenha acesso SSH ao servidor.

  • Conecte-se como root neste ambiente e instale o client git mais novo –  recomendamos pelo menos a versão 2.x.
  • Faça download e descompacte o cvs2svn-2.4.0 em uma pasta qualquer. Vamos usar /usr/local/cvs2svn-2.4.0 como exemplo;
  • Volte para um usuário sem acesso de root;
  • Adicione a pasta /usr/local/cvs2svn-2.4.0 ao path:
    • export PATH=$PATH:/usr/local/cvs2svn-2.4.0
  • Confira a versão do rodando git –version:
    $ git –version
    git version 2.3.5

Pronto, ambiente instalado. Vamos agora aos passos para executar de fato o processo:

Executando o processo

Inicialmente faça cópia do repositório do projeto no cvs para a máquina local. Copie também a pasta CVSROOT, onde ficam metadados do cvs. Nos comandos abaixo, estamos supondo que a máquina que roda o servidor cvs é cvsserver, e o cvs path é /home/cvs.

scp -r username@cvsserver:/home/cvs/meuprojeto /home/cvs2git/meuprojeto
scp -r username@cvsserver:/home/cvs/CVSROOT /home/cvs2git/CVSROOT

Iremos agora converter o projeto do formato do CVS para o formato esperado pelo Git:

cvs2git --encoding=Cp1252 --encoding=UTF-8 --tmpdir=/tmp/cvs2git --blobfile=/tmp/git-blob.dat --dumpfile=/tmp/git-dump.dat --username cvs2git /home/cvs2git/meuprojeto

Neste comando temos inicialmente as opções –encoding indicando os possíveis encodings dos arquivos no cvs. Logo depois temos –tmpdir especificando um diretório temporário. –blobfile e –dumpfile especificam os arquivos que serão saída deste processo, e serão usados posteriormente. –username especifica o usuário que será usado para os commits no Git. E finalmente especificamos o caminho do projeto na máquina local.

Note que este processo pode ser bastante demorado – algumas horas – e precisar de bastante espaço em disco para os arquivos temporários e arquivos de saída, se o histórico do projeto CVS for muito grande. Ao final do processo são mostradas estatísticas da migração. Veja abaixo um exemplo, onde o processo todo durou cerca de 1h30 e foram usados mais de 2GB de espaço em disco.

cvs2svn Statistics:
------------------
Total CVS Files:              3680
Total CVS Revisions:         22140
Total CVS Branches:         204981
Total CVS Tags:            3214420
Total Unique Tags:            1311
Total Unique Branches:          93
CVS Repos Size in KB:       379447
Total SVN Commits:            7735
First Revision Date:    Tue Feb 19 11:07:16 2002
Last Revision Date:     Tue Jan  6 17:07:05 2015
------------------
Timings (seconds):
------------------
1174   pass1    CollectRevsPass
   1   pass2    CleanMetadataPass
   1   pass3    CollateSymbolsPass
2114   pass4    FilterSymbolsPass
   1   pass5    SortRevisionsPass
  38   pass6    SortSymbolsPass
 349   pass7    InitializeChangesetsPass
  39   pass8    BreakRevisionChangesetCyclesPass
  46   pass9    RevisionTopologicalSortPass
 309   pass10   BreakSymbolChangesetCyclesPass
 361   pass11   BreakAllChangesetCyclesPass
 351   pass12   TopologicalSortPass
 364   pass13   CreateRevsPass
  78   pass14   SortSymbolOpeningsClosingsPass
   8   pass15   IndexSymbolsPass
 289   pass16   OutputPass
5524   total


$ ls -lh /tmp
total 2.2G
-rw-rw-r-- 1 cvs2git cvs2git 2.2G 2015-01-09 09:53 git-blob.dat
-rw-rw-r-- 1 cvs2git cvs2git 5.8M 2015-01-09 10:40 git-dump.dat
drwxrwxr-x 2 cvs2git cvs2git 4.0K 2015-01-09 10:40 cvs2git

Feito este trabalho de migração, agora o processo fica mais simples. Precisamos criar primeiramente um repositório git no formato bare, ou seja, sem uma working copy:

mkdir /home/git2cvs/meuprojeto.git
cd /home/git2cvs/meuprojeto.git
git --bare init

E agora importamos os arquivos de saída do processo anterior:

cat /tmp/git-blob.dat /tmp/git-dump.dat | git fast-import

Finalmente precisamos fazer o push nosso repositório local para um repositório corporativo:

Faça inicialmente um clone deste repositório em outra pasta:

mkdir /home/git2cvs/tmpdir
cd /home/git2cvs/tmpdir
git clone --bare /home/git2cvs/meuprojeto.git
cd meuprojeto.git

Adicione agora um repositório remoto, referente ao servidor oficial da empresa, e faça push do repositório:

git remote add companyrepo http://username@gitserver/scm/demo/meuprojeto.git
git push --all companyrepo
git push --tags companyrepo

Note que a url usada no primeiro comando deve ser obtida na ferramenta no gerenciador de repositórios oficial da empresa.

Git na MATERA

A MATERA entende os benefícios que o Git traz para um ambiente corporativo e está em processo de migração gradual dos seus repositórios cvs e svn para esta tecnologia. Estamos utilizando o processo acima para migração dos projetos cvs e outro processo bastante similar para svn. Como ferramenta de gerenciamento de repositórios adotamos e recomendamos o Atlassian Stash. Esperamos que o git e o Stash tragam produtividade no desenvolvimento, e agilidade no processo de code review, de forma a aumentar a qualidade do produto final, impactando diretamente a percepção de nossos clientes.

Links externos:

Por LUIS SERGIO F. CARNEIRO

Postado em: 30 de abril de 2015

Confira outros artigos do nosso blog

REST não é JSON

21 de agosto de 2017

Bruno Sofiato

[Webinar] Profile de aplicações Java com Oracle Mission Control e Flight Recorder

24 de julho de 2017

Danival Calegari

Criando Mocks de serviços REST com SoapUI

27 de junho de 2017

Monise Costa

JavaScript 6: diferença entre var, let e const

09 de maio de 2017

Otávio Felipe do Prado

Deixe seu comentário