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

100

Vou trabalhar com outras pessoas no código de um projeto que usa cvs. Queremos usar um vcs distribuído para fazer nosso trabalho e quando terminarmos ou talvez de vez em quando queremos comprometer nosso código e todo o nosso histórico de revisão para cvs. Não temos acesso de gravação ao repositório cvs do projeto, então não podemos fazer commit com muita frequência. Que ferramenta podemos usar para exportar nosso histórico de revisões para cvs? Atualmente estávamos pensando em usar git ou mercurial, mas poderíamos usar outro vcs distribuído se pudesse tornar a exportação mais fácil.

tatsuhirosatou
fonte
Quando você diz "CVS distribuído", acho que quer dizer "VCS distrubted" ou "DVCS", que significa "sistema de controle de versão distribuído".
Patrick McElhaney
Quero dizer um sistema de controle de versão distribuído.
tatsuhirosatou

Respostas:

237

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ê deseja. Minhas sugestões (e o que fazemos aqui no $ work):

Criando o Clone Inicial

Use git cvsimportpara clonar o histórico de revisão do CVS em um repositório 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 -Aopção é opcional, mas ajuda a fazer seu histórico de revisão que é importado do CVS parecer mais com o git (veja man git-cvsimportpara mais informações sobre como isso é configurado).

Dependendo do tamanho e do histórico do repositório CVS, esta primeira importação levará MUITO tempo. Você pode adicionar um -v ao comando acima se quiser tranquilidade de que algo está de fato acontecendo.

Uma vez que este processo for completado, você terá um masterbranch que deve refletir o HEAD do CVS (com a exceção que git cvsimportpor padrão ignora os últimos 10 minutos de commits para evitar pegar um commit que está pela metade). Você pode então usar git loge amigos para examinar todo o histórico do repositório, como se ele estivesse usando o git desde o início.

Ajustes de configuração

Existem alguns ajustes de configuração que tornarão as importações incrementais do CVS (bem como as exportações) mais fáceis no futuro. Eles não estão documentados na git cvsimportpágina do manual, então suponho que possam 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 subseqüente git cvsimportdeve ser muito mais rápido do que a primeira chamada. No entanto, ele faz um cvs rlogem cada diretório (mesmo aqueles que têm apenas arquivos Attic), portanto, 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 definiu suas configurações para especificar os padrões, você precisará especificá-los na linha de comando:

% git cvsimport -r cvs -d $CVSROOT cvs_module_to_checkout

De qualquer forma, duas coisas devem ser lembradas:

  1. Certifique-se de estar no diretório raiz do seu repositório git. Se você estiver em qualquer outro lugar, ele tentará fazer um novo cvsimportque levará uma eternidade.
  2. Certifique-se de estar em seu masterbranch para que as mudanças possam ser mescladas (ou rebased) em seus branches locais / tópicos.

Fazendo Mudanças Locais

Na prática, eu recomendo sempre fazer mudanças nos branches e apenas mesclar masterquando você estiver pronto para exportar essas mudanças de volta para o repositório CVS. Você pode usar qualquer fluxo de trabalho que desejar em seus branches (mesclagem, rebase, esmagamento, etc), mas é claro que as regras de rebase padrão se aplicam: não faça rebase se alguém mais estiver baseando suas alterações em seu branch.

Exportando alterações para CVS

O git cvsexportcommitcomando permite exportar um único commit para o servidor CVS. Você pode especificar um único ID de confirmação (ou qualquer coisa que descreva uma confirmação específica 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 cvscliente real . Você poderia exportar cada micro commit em seus branches de tópico, mas geralmente eu gosto de criar um merge commit em um up-to-date mastere exportar aquele único merge commit para CVS. Quando você exporta um commit de mesclagem, 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 man git-mergemesclagem " de para uma descrição de uma mesclagem de avanço rápido), então você deve usar o--no-ffopção ao realizar a fusão. 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 de manual de git-cvsexportcommit . Você tem a opção de definir a -wopção em sua configuração git:

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

Se o patch falhar por qualquer razão, minha experiência é que você (infelizmente) provavelmente ficará melhor copiando os arquivos alterados manualmente e fazendo commit usando o cliente cvs. Isso não deve acontecer, no entanto, se você se certificar de que masterestá atualizado com o CVS antes de mesclar seu branch de tópico no.

Se o commit falhar por qualquer motivo (problemas de rede / permissões, etc), você pode pegar o comando impresso em seu terminal no final da saída de erro e executá-lo em seu diretório de trabalho CVS. Geralmente é algo assim:

% cvs commit -F .msg file1 file2 file3 etc

Na próxima vez que você fizer um git cvsimport(aguardando pelo menos 10 minutos), deverá ver o patch de seu commit exportado reimportado para seu repositório 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 autor na inicial cvsimportacima).

Clonando seu clone CVS

Se você tiver mais de uma pessoa precisando fazer o cvsimport, seria mais eficiente ter um único repositório git que execute o cvsimport e ter todos os outros repositórios criados como um clone. Isso funciona perfeitamente e o repositório clonado pode executar cvsexportcommits conforme descrito acima. Há, no entanto, uma ressalva. Devido à maneira como os commits do CVS voltam com diferentes IDs de commit (como descrito acima), você não quer que seu branch clonado rastreie o repositório git central. Por padrão, é assim que git cloneconfigura seu repositório, 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 do que puxar quando quiser obter novos commits do repositório central:

% git pull origin master

No geral, descobri que esse fluxo de trabalho é bastante gerenciável e a "próxima melhor coisa" quando migrar completamente para o git não é prático.

Brian Phillips
fonte
3
Obrigado. Isso me ajudou imensamente, especialmente a dica sobre o uso de uma mesclagem não fastforward para agrupar as alterações do CVS em um único commit.
skiphoppy
8
Para registro, a opção -A que você sugere usar para git-cvsimport é mencionada na página de manual como sendo "não recomendada ... se você pretende exportar as alterações de volta para o CVS mais tarde com git-cvsexportcommit (1)." No meu caso, na verdade gosto da maneira como os autores se apresentam.
skiphoppy
2
Obrigado pelas dicas. Uma coisa útil que fiz foi adicionar "cvs =! Git cvsimport -k -a" em [alias] em meu .gitconfig. Isso faz com que "git cvs" faça DTRT (do topo da árvore).
bstpierre
1
Se você não tem o git cvsimportDebian, tenteapt-get install git-cvs
Tino
5
Mac OSX mavricks carece inteiramente de cvs e parece que o git cvsimport depende de cvs. Initialized empty Git repository in /Users/gus/projects/foo/foobar/.git/ Can't exec "cvsps": No such file or directory at /Applications/Xcode.app/Contents/Developer/usr/libexec/git-core/git-cvsimport line 777. Could not start cvsps: No such file or directory git cvsimport: fatal: cvsps reported errorEntão, infelizmente, isso não resolve a ausência de CVS :(
Gus
22

Você não deve confiar cvsimport cegamente e verificar se a árvore importada corresponde ao que está no repositório CVS. Eu fiz isso compartilhando o novo projeto usando o plug-in 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 excluído erroneamente) foram agrupados em um grande commit, o que resultou em um arquivo ausente da árvore.

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 árvore após importar

shil88
fonte
3

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

Jakub Narębski
fonte