Como exportar o histórico de revisão de mercurial ou git para cvs?

Eu vou estar trabalhando com outras pessoas no código de um projeto que usa cvs. Queremos usar um vcs distribuído para fazer o nosso trabalho e quando terminarmos ou talvez de vez em quando queremos cometer o nosso código e todo o nosso histórico de revisão para cvs. Não temos access de gravação ao repository cvs do projeto, por isso não podemos cometer com muita frequência. Qual ferramenta podemos usar para exportar nosso histórico de revisões para o cvs? Atualmente, estávamos pensando em usar o git ou o mercurial, mas poderíamos usar outros vcs distribuídos se isso facilitasse a exportação.

Felizmente para aqueles de nós que ainda são forçados a usar o CVS, o git fornece ferramentas muito boas para fazer exatamente o que você está querendo fazer. Minhas sugestões (e o que fazemos aqui no $ work):

Criando o clone inicial

Use git cvsimport para clonar o histórico de revisões do CVS em um repository git. Eu uso a seguinte invocação:

 % git cvsimport -d $CVSROOT -C dir_to_create -r cvs -k \ -A /path/to/authors/file cvs_module_to_checkout 

A opção -A é opcional, mas ajuda a fazer com que seu histórico de revisão que é importado do CVS pareça mais parecido com um git (veja man git-cvsimport para mais informações sobre como isso é configurado).

Dependendo do tamanho e do histórico do repository CVS, essa primeira importação levará um tempo muito longo. Você pode adicionar um -v ao comando acima se quiser ter a tranqüilidade de saber que algo está de fato acontecendo.

Uma vez que este processo esteja completo, você terá um branch master que deve refletir o HEAD do CVS (com a exceção de que o git cvsimport por padrão ignora os últimos 10 minutos de commits para evitar pegar um commit que está git cvsimport ). Você pode então usar o git log e os amigos para examinar todo o histórico do repository, como se estivesse usando o git desde o começo.

Ajustes de configuração

Existem alguns ajustes na configuração que facilitarão as importações incrementais do CVS (assim como as exportações) no futuro. Eles não estão documentados na página man do git cvsimport , então eu suponho que eles poderiam ser alterados sem aviso prévio, mas, FWIW:

 % git config cvsimport.module cvs_module_to_checkout % git config cvsimport.r cvs % git config cvsimport.d $CVSROOT 

Todas essas opções podem ser especificadas na linha de comando para que você possa pular esta etapa com segurança.

Importações Incrementais

O git cvsimport subseqüente deve ser muito mais rápido que a primeira invocação. No entanto, ele faz um cvs rlog em todos os diretórios (mesmo aqueles que têm apenas arquivos no Attic ), de modo que ainda pode levar alguns minutos. Se você especificou as configurações sugeridas acima, tudo que você precisa fazer é executar:

 % git cvsimport 

Se você não configurou suas configurações para especificar os padrões, precisará especificá-los na linha de comando:

 % git cvsimport -r cvs -d $CVSROOT cvs_module_to_checkout 

De qualquer maneira, duas coisas para ter em mente:

  1. Verifique se você está no diretório raiz do seu repository git. Se você estiver em qualquer outro lugar, ele tentará fazer um novo cvsimport que vai durar uma eternidade.
  2. Certifique-se de estar em sua ramificação master para que as alterações possam ser mescladas (ou realocadas) em suas ramificações locais / de tópico.

Fazendo alterações locais

Na prática, recomendo sempre fazer alterações nas ramificações e apenas mesclar para o master quando você estiver pronto para exportar essas alterações de volta para o repository CVS. Você pode usar qualquer stream de trabalho que desejar em suas ramificações (mesclar, rebasing, squashing, etc), mas é claro que as regras de rebasing padrão se aplicam: não rebase se alguém tiver baseado suas alterações em sua ramificação.

Exportando Mudanças para o CVS

O comando git cvsexportcommit permite que você exporte uma única confirmação para o servidor CVS. Você pode especificar um único ID de confirmação (ou qualquer coisa que descreva um commit específico, conforme definido em man git-rev-parse ). Um diff é então gerado, aplicado a um checkout do CVS e então (opcionalmente) comprometido com o CVS usando o cliente cvs real. Você poderia exportar cada micro commit em seus ramos de tópicos, mas geralmente eu gostaria de criar um commit de mesclagem em um master atualizado e exportar esse commit de merge simples para o CVS. Quando você exporta um commit de merge, você tem que dizer ao git qual commit pai usar para gerar o diff. Além disso, isso não funcionará se sua mesclagem for um avanço rápido (consulte a seção “COMO FUNCIONA A FUSÃO” do man git-merge para obter uma descrição de uma mesclagem rápida), portanto, é necessário usar o --no-ff opção ao executar a mesclagem. Aqui está um exemplo:

 # on master % git merge --no-ff --log -m "Optional commit message here" topic/branch/name % git cvsexportcommit -w /path/to/cvs/checkout -u -p -c ORIG_HEAD HEAD 

Você pode ver o que cada uma dessas opções significa na página man do git-cvsexportcommit . Você tem a opção de configurar a opção -w na sua configuração do git:

 % git config cvsexportcommit.cvsdir /path/to/cvs/checkout 

Se o patch falhar por qualquer razão, minha experiência é que você (infelizmente) provavelmente estará melhor copiando os arquivos alterados manualmente e confirmando usando o cliente cvs. Isso não deve acontecer, no entanto, se você tiver certeza de que o master está atualizado com o CVS antes de mesclar sua ramificação de tópicos.

Se o commit falhar por qualquer razão (problemas de rede / permissions, etc), você pode pegar o comando impresso no seu terminal no final da saída de erro e executá-lo no seu diretório de trabalho do CVS. Geralmente parece algo como isto:

 % cvs commit -F .msg file1 file2 file3 etc 

Na próxima vez que você fizer um git cvsimport (esperando pelo menos 10 minutos), você verá o patch de sua confirmação exportada reimportada para o seu repository local. Eles terão IDs de commit diferentes, já que o commit do CVS terá um timestamp diferente e possivelmente um nome de committer diferente (dependendo se você configurou um arquivo de autores em seu cvsimport inicial acima).

Clonando seu clone do CVS

Se você tiver mais de uma pessoa precisando fazer o cvsimport , seria mais eficiente ter um único repository git que executa o cvsimport e ter todos os outros repositorys criados como um clone. Isso funciona perfeitamente e o repository clonado pode realizar compromissos de compartilhamento de vídeo exatamente como descrito acima. Há, no entanto, uma ressalva. Devido ao modo como os commits do CVS retornam através de diferentes IDs de commit (como descrito acima), você não quer que sua ramificação clonada rastreie o repository git central. Por padrão, é assim que o git clone configura seu repository, mas isso é facilmente corrigido:

 % git clone [CENTRAL_REPO_HERE] % cd [NEW_GIT_REPO_DIR_HERE] % git config --unset branch.master.remote % git config --unset branch.master.merge 

Depois de remover essas configurações, você terá que dizer explicitamente de onde e de onde extrair quando quiser extrair novos commits do repository central:

 % git pull origin master 

No geral, eu achei este stream de trabalho bastante gerenciável e a “próxima melhor coisa” ao migrar completamente para o git não é prático.

Você não deve confiar cvsimport cegamente e verificar se a tree importada corresponde ao que está no repository do CVS. Eu fiz isso compartilhando o novo projeto usando o plug-in do eclipse CVS e descobri que havia inconsistências.

Dois commits que foram feitos em menos de um minuto com a mesma mensagem de commit (a fim de reverter um arquivo deletado erroneamente) foram agrupados em um commit grande, o que resultou em um arquivo ausente da tree.

Consegui resolver esse problema modificando o parâmetro ‘fuzz’ para menos de um minuto.

exemplo:

 % git cvsimport -d $CVSROOT -C dir_to_create -r cvs -k \ -A /path/to/authors/file cvs_module_to_checkout -z 15 

linha de fundo: verifique sua tree após a importação

Além da resposta de Brian Phillips: há também o git-cvsserver que funciona como o servidor CVS, mas na verdade acessa o repository git … mas tem algumas limitações.