quarta-feira, 23 de junho de 2010

Git Submodules - um recurso para gerenciar dependências no lugar de svn externals.

Submodules & GIT - usando bibliotecas externas.

Quem está acostumado em gerenciar suas bibliotecas em svn usando o recurso externals, quando considera usar o GIT, geralmente tem dúvida a respeito de como trabalhar. Já escrevi aqui um artivo a respeito de svn externals e agora que estou migrando pro git então escrevo este aqui também para quem quiser me acompanhar.

Dois recursos normalmente surgem quando pesquisamos a respeito do assunto:
  • submodules
  • subtree merge strategy
Vamos tratar aqui do primeiro, porém quem quiser pesquisar o segundo, veja a comparação entre submodules e subtree merge strategy na documentação.

O que são submodules?

Na documentação diz que submodules ou submódulos permitem repositórios externos serem adicionados dentro de um subdiretório dedicado da arvore do nosso projeto, sempre apontando para um commit específico.

Bom... uma parte de cada vez:

repositórios externos
são outros repositórios em git.

diretórios dedicado
o diretório onde o submódulo fica tem sua arvore específica, inclusive a pasta .git com suas próprias configurações. Não pode ser feito merge com a arvore do repositório pai.

commit específico
quando adicionamos um submódulo a uma arvore, estamos adicionando um commit específico. Isso quer dizer que atrelamos ele a uma versão (um SHA). Toda vez que alguém baixar este projeto e pedir o submódulo ele vai receber esta versão mesmo que o repositório original esteja bem mais adiantado.

Isso é legal. Quero um pra mim. Como eu faço para criar um submódulo?

você deve usar um comando semelhante à este aqui (nessa hora o melhor mesmo é consultar o manual do git):

git submodule add [URL do repositório] [pasta de destino]
git submodule add http://github.com/brunoreis/pspec.git extlibs/pspec


com isso ele vai criar um repositório para o pspec na pasta extlibs/pspec. Vale a pena dar uma olhada nesta pasta, dentro do diretório .git, e ver o que tem nos arquivos texto de configuração. Com certeza vai auxiliar a encaixar as peças do quebra-cabeças. Ah, e também olhe o .git da raiz do seu projeto.

Bom, então é só isso? Meu submódulo está criado, posso mandar meu projeto para o github e ficar famoso porque uso submódulos e o pspec para especificar e testar meu software?

Muita hora nessa calma! Ainda temos algumas coisas a fazer antes. Ao criar o submodule, como já dissemos antes, atrelamos ele a um SHA específico. Os arquivos do repositório, a princípio, não ficam dentro do nosso repositório, mas o SHA sim. Temos então que adicionar o subdiretório criado à arvore original para que ele possa ser integrado ao nosso repositório.

Fazemos assim:
git add extlibs/pspec
git commig -m "agora sim com pspec"

Agora está lá... e se quiser subir para o repo de origem, não esqueça de fazer um push.

Isso quer dizer que quem fizer checkout no meu projeto já vai baixar o submódulo?

Não. Como já falei antes, você mandou apenas o SHA. Assim quando você fizer checkout vai trazer apenas uma referência à aquele submodulo, sem baixar o conteúdo do mesmo. Então após fazer checkout do seu repo, você ainda vai ter que fazer o seguinte:
git submodules init
git submodules update

Com isso ele vai trazer o conteúdo do(s) submódulos de acordo com o SHA de cada um.

E como eu faço pra saber se um projeto que baixei tem submódulos?

essa é fácil, é só rodar
git submodules

ele mostra os submódulos e também o SHA de cada um.

Beleza, mas agora eu sei que tem algo novo que eu preciso em um submódulo, como eu atualizo ele?

Simples, como o submódulo tem lá sua arvore e seu .git, etc.. porém este repositório está atrelado a um commit (sha) específico. Então precisamos fazer um checkout do branch que você quer, ex:

git checkout master

depois disso você pode usar

git pull

para atualizar.

Ah, e lembre-se de que depois que você fez isso, você tem que adicionar novamente o submodule ao repositório e fazer um commit (da atualização do SHA) para que os outros possam ter essa atualização.

Ao fazer essa atualização não coloque uma barra depois do nome do submodule. Se você fizer isso vai bagunçar tudo. Ou seja, use:
submodule add extlibs/pspec


mas NÃO USE

submodule add extlibs/pspec/ <--------------- Essa barra faz @#$@%@!!


Ta bom, ta bom....Hum.... e....

Se eu quiser atualizar todos de uma vez?

É só fazer assim:

git submodule foreach "git pull"

Esse comando eu achei muito interessante. Ele roda por todos os submódulos e executa o comando que for passado para ele, no noso caso o pull. Não esqueça de mandar esta alteração adicionando os submodules novamente à arvore principal.

Beleza, mas agora que estou no meu projeto, vi que tem um bug no repositório do submódulo. Tem como eu arrumar isso sem fazer checkout do sub em outro diretório?

Sim. Você pode entrar no dir do submódulo, fazer um checkout, alterar, fazer um commit e mandar novamente para o repo original.

Se você fizer isso e encontrar um erro dizendo que o original não aceita commits deste, leia este post a respeito do uso de "bare repositories".

Ta Bom.

Espero que você tenha sucesso usando os submódulos. Eles me parecem bem mais simples e dinâmicos que os externals do svn. Ainda estou aprendendo o git, então deve ter algo aqui que pode ser feito de uma maneira melhor ou então algo que você não entendeu. Peço que você acrescente seu comentário que se eu puder, respondo. Assim agregamos mais informações para os próximos não terem que ficar pesquisando as mesmas coisas que nós.

Sucesso!

--------------
Ah...

Algumas referências citadas e usadas aqui:

http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html

http://book.git-scm.com/5_submodules.html

https://git.wiki.kernel.org/index.php/GitSubmoduleTutorial

http://stackoverflow.com/questions/804545/what-is-this-git-warning-message-when-pushing-changes-to-a-remote-repository

Um comentário: