Inicialmente, utilizei o Git em um projeto particular onde era o único desenvolvedor. Entre os comandos relacionados a natureza distribuída do Git, eu precisava somente do pull e clone, de modo a manter o mesmo projeto em vários lugares.
Mais tarde, quis publicar meu código com o Git, e incluir as alterações dos contribuidores. Tive que aprender como gerenciar projetos com vários desenvolvedores de todas as partes do mundo. Felizmente, esse é o forte do Git, e indiscutivelmente sua razão de existir.
Cada commit tem um nome de autor e e-mail, que pode ser mostrado pelo git log. O Git utiliza as configurações do sistema para preencher esses campos. Para fazer o preenchimento explícito, digite:
$ git config --global user.name "John Doe" $ git config --global user.email johndoe@example.com
Omita o flag global para configurar essas opções somente para o repositório atual.
Suponha que você tenha acesso SSH a um servidor web, mas que o Git não esteja instalado. Embora não tão eficiente quanto seu protocolo nativo, o Git pode se comunicar via HTTP.
Baixe, compile e instale o Git em sua conta, e crie um repositório no seu diretório web:
$ GIT_DIR=proj.git git init $ cd proj.git $ git --bare update-server-info $ cp hooks/post-update.sample hooks/post-update
Para versões mais antigas do Git, o comando copy falha e você deve executar:
$ chmod a+x hooks/post-update
Agora você pode publicar suas últimas edições via SSH de qualquer clone:
$ git push web.server:/path/to/proj.git master
E qualquer um pode obter seu projeto com:
$ git clone http://web.server/proj.git
Deseja sincronizar os repositórios sem servidores, ou mesmo sem uma conexão de rede? Precisa improvisar durante uma emergência? Vimos que git fast-export e git fast-import podem converter repositórios para um único arquivo e vice-versa. Podemos enviar esses arquivos para outros lugares fazendo o transporte de repositórios git sob qualquer meio, mas uma ferramenta mais eficiente é o git bundle.
O emissor cria um bundle:
$ git bundle create somefile HEAD
E então transporta o pacote, somefile
, para outro lugar: por e-mail,
pen-drive (ou mesmo uma saida impressa xxd e um scanner com ocr,
sinais binários pelo telefone, sinais de fumaça, etc). O
receptor recupera os commits do pacote executando:
$ git pull somefile
O receptor pode inclusive fazer isso em um diretório
vazio. Apesar do seu tamanho, somefile
contém todo o repositório git
original.
Em grandes projetos, podemos eliminar o desperdício fazendo o empacotamento somente das mudanças que o outro repositório necessita. Por exemplo, suponha que o commit “1b6d…” é o commit mais recente compartilhado por ambas as partes:
$ git bundle create somefile HEAD ^1b6d
Se executado frequentemente, podemos esquecer que commit foi feito por último. A página de ajuda sugere utilizar tags para resolver esse problema. Isto é, após enviar um pacote, digite:
$ git tag -f lastbundle HEAD
e crie um novo pacote de atualização com:
$ git bundle create newbundle HEAD ^lastbundle
Patches são representações textuais das suas mudanças que podem ser facilmente entendidas pelos computadores e pelos seres humanos. Isso tem um forte apelo. Você pode mandar um patch por e-mail para os desenvolvedores não importando que sistema de versão eles estão utilizando. Como os desenvolvedores podem ler o e-mail, eles podem ver o que você editou.
Da mesma maneira, do seu lado, tudo o que você precisa é de uma conta de e-mail: não é necessário configurar um repositório online do Git.
Lembrando do primeiro capítulo:
$ git diff 1b6d > my.patch
produz um patch que pode ser colado em um e-mail para discussão. Em um repositório Git, digite:
$ git apply < my.patch
para aplicar o patch.
Em configurações mais formais, quando o nome do autor e talvez sua assinatura precisem ser armazenadas, podemos gerar os patches correspondentes a partir de um certo ponto com o comando:
$ git format-patch 1b6d
Os arquivos resultantes podem ser fornecidos ao git-send-email, ou enviados manualmente. Você também pode especificar uma faixa de commits:
$ git format-patch 1b6d..HEAD^^
No lado do receptor, salve o e-mail como um arquivo, e entre com:
$ git am < email.txt
Isso aplica o patch de entrada e também cria um commit, incluindo as informações tais como o autor.
Com um navegador cliente de e-mail, pode ser necessário clicar o botão para ver o e-mail em seu formato original antes de salvar o patch para um arquivo.
Existem pequenas diferenças para os clientes de e-mail baseados em mbox, mas se você utiliza algum desses, provavelmente é o tipo de pessoa que pode resolver os problemas sem ler o manual.
Após fazer o clone de um repositório, executar o git push ou git pull irá automaticamente fazer o push ou pull da URL original. Como o Git faz isso? O segredo reside nas opções de configuração criadas com o clone. Vamos dar uma olhada:
$ git config --list
A opção remote.origin.url
controla a URL de origem; “origin” é um apelido dados ao
repositório fonte. Da mesma maneira que a convenção do branch
“master”, podemos mudar ou deletar esse apelido mas
geralmente não existe um motivo para fazê-lo.
Se o repositório original for movido, podemos atualizar a URL via:
$ git config remote.origin.url git://new.url/proj.git
A opção branch.master.merge
especifica o branch remoto default em um git pull. Durante a clonagem
inicial, ele é configurado para o branch atual do repositório
fonte, mesmo que o HEAD do repositório fonte subsequentemente
mova para um branch diferente, um pull posterior irá seguir
fielmente o branch original.
Essa opção somente aplica ao repositório que fizemos a
clonagem em primeiro lugar, que é armazenado na opção
branch.master.remote
. Se
fizermos um pull de outro repositório devemos estabelecer
explicitamente que branch desejamos:
$ git pull git://example.com/other.git master
Isso explica por que alguns de nossos exemplos de pull e push não possuem argumentos.
Quando clonamos um repositório, clonamos também todos os seus branches. Voce pode não ter notado isso porque o Git sempre esconde os branches: mas podemos solicitá-los especificamente. Isso previne os branches no repositório remoto de interferir com seus branches, e também torna o Git mais fácil para os iniciantes.
Liste os branches remotos com:
$ git branch -r
Voce deve obter uma saída como:
origin/HEAD origin/master origin/experimental
Eles representam branches e a HEAD de um repositório remoto, e pode ser utilizado em comandos normais do Git. Por exemplo, suponha que você fez vários commits, e gostaria de comparar contra a última versão buscada (fetched). Você pode buscar nos logs pelo hash apropriado SHA1, mas é muito mais fácil digitar:
$ git diff origin/HEAD
Ou você pode ver o que o branch “experimental” contém:
$ git log origin/experimental
Suponha que dois desenvolvedores estão trabalhando em nosso projeto, e que queremos manter o controle de ambos. Podemos seguir mais de um repositório a qualquer hora com:
$ git remote add other git://example.com/some_repo.git $ git pull other some_branch
Agora temos merged em um branch a partir do segundo repositório, e temos fácil acesso a todos os branches de todos os repositórios:
$ git diff origin/experimental^ other/some_branch~5
Mas e se só queremos comparar as suas alterações sem afetar o trabalho de ambos? Em outras palavras, queremos examinar seus branches sem ter que suas alterações invadam nosso diretório de trabalho. Então ao invés de pull, execute:
$ git fetch # Fetch from origin, the default. $ git fetch other # Fetch from the second programmer.
Isso faz com que somente busque os históricos. Embora o diretório de trabalho continue intocado, podemos fazer referencia a qualquer branch de qualquer repositório em um comando Git pois agora possuímos uma copia local.
Lembre-se de nos bastidores, um pull é simplesmente um fetch e um merge. Geralmente fazemos um pull pois queremos fazer um merge do ultimo commit após o fetch; essa situação é uma exceção notável.
Veja git help remote para saber como remover repositórios remotos, ignorar certos branches e outras informações.
Para meus projetos, eu gosto que contribuidores para preparar os repositórios a partir dos quais eu possa fazer um pull. Alguns serviços hospedeiros de Git permite que você hospede seu próprio fork de um projeto com o clique de um botão.
Após ter buscado (fetch) uma árvore, eu executo comandos Git para navegar e examinar as alterações, que idealmente estão bem organizadas e bem descritas. Faço merge de minhas próprias alterações, e talvez faça edições posteriores. Uma vez satisfeito, eu faço um push para o repositório principal.
Embora eu receba infrequentes contribuições, eu acredito que essa abordagem funciona bem. Veja esse post do blog do Linus Torvalds.
Continuar no mundo Git é mais conveniente do que fazer patch de arquivos, já que ele me salva de convertê-los para commits Git. Além disso, o Git trata dos detalhes tais como registrar o nome do autor e seu endereço de e-mail, bem como o dia e hora, alem de pedir ao autor para descrever sua própria alteração.