1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
== Git Multiplayer ==
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.
=== Quem sou eu? ===
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.
=== Git sob SSH, HTTP ===
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
=== Git sobre qualquer coisa ===
Deseja sincronizar os repositórios sem servidores, ou mesmo sem uma conexão de rede? Precisa improvisar durante uma emergência? Vimos que <<makinghistory, *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: A moeda Universal ===
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.
=== Sinto muito, mas mudamos ===
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.
=== Branches Remotos ===
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
=== Remotos Múltiplos ===
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.
=== Minhas preferencias ===
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 http://torvalds-family.blogspot.com/2009/06/happiness-is-warm-scm.html[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.
|