Desenvolvimento

27 mar, 2012

Dica Git da semana: pushing and pulling

Publicidade

A dica Git desta semana é sobre a obtenção de mudanças e de outras fontes.

Entendendo os repositórios

Um repositório git é essencialmente uma árvore de commits, de tal modo que em qualquer ponto na história dos commit você terá tanto uma representação completa do conteúdo do repositório, como uma referência de volta a um (ou mais) pais. Cada nó nesta árvore é identificado exclusivamente pela sua hash SHA-1 (ou uma abreviatura única), que é derivada a partir dos seus conteúdos, incluindo o ponteiro de volta para o pai anterior(s).

A principal vantagem deste modelo é que se dois desenvolvedores estiverem fazendo o commit da mesma alteração, sempre resultará na mesma identidade do nó.

A segunda vantagem deste modelo é que, quando mover conteúdo entre os repositórios, você não precisa mover toda a árvore de commits. Você pode identificar a raíz comum entre duas árvores e basta enviar esses conteúdos. Por exemplo, se você tiver dois desenvolvedores cujas árvores se parecerem com:

  • Desenvolvedor 1    A <- B <- C <- D
  • Desenvolvedor 2    A <- B <- E <- F

Então, quando o Desenvolvedor 1 quiser passar suas mudanças para o Desenvolvedor 2, o último nó comum conhecido será o B, por isso é necessário apenas para o Desenvolvedor 1 enviar commits C e D. Por outro lado, se o Desenvolvedor 2 desejar enviar seus conjuntos de mudanças ao Desenvolvedor 1, ele só precisa enviar E e F.

Entendendo remotes

Os remotes permitem que um desenvolvedor controle o estado de repositórios localizados em máquinas remotas e forneça um mecanismo para copiar commits de um para outro. Ao clonar um repositório, uma origem remota chamada origin é automaticamente configurada para rastrear o estado do repositório remoto. Por padrão, as operações de cópia commits entre os repositórios (empurrar, puxar e buscar) trabalham sobre a origem remota, a menos que você especifique o contrário.

Ao contrário de um sistema centralizado de controle de versão, não existe o conceito de um único repositório central. Então, quando copiar commits, você precisa especificar qual repositório copiar. Se você configurar um repositório compartilhado, então, este será “o trabalho de todos”. Um sistema de controle de versão distribuído abre a possibilidade de muitos modelos organizacionais – mas não vamos falar a respeito deles agora.

Um remote é configurado com uma URL que assume a mesma forma do que a utilizada para clonar. Geralmente, HTTP e URLs git são apenas leitura, enquanto HTTPS e SSH são utilizadas para ler e gravar.

Pushing and pulling

Para o objetivo desta dica, vamos criar um novo clone do repositório em uma máquina diferente e usá-lo para empurrar. Isso pode levar a várias formas:

  • file:///path/to/somewhere.git – um repositório de arquivos locais, iniciado com git init –bare /path/to/somewhere.git
  • ssh://host/path/to/somewhere.git – repositório de arquivos remotos, iniciado com ssh host git init –bare /path/to/somewhere.git
  • ssh://git@github.com/username/repositoryname.git – repositório criado em GitHub
    Para adicionar este como um novo remoto, execute:
git remote add github ssh://git@github.com/username/repositoryname.git 

Depois disso, você pode usar o nome “github” para se referir a esta origem remota. Se já usou uma URL diferente, então não hesite em escolher um outro nome. Um exemplo é: em uma URL SSH você pode querer usar o nome do host (não qualificado). Caso queira, por exemplo, enviar o código para github, você pode fazer:

git push github

Este tomará todas as alterações que não estavam no repositório remoto (no ramo atual) e as moverá para o servidor remoto. Note que, se houver alterações posteriores no remote, você pode ter uma mensagem “non fast-forward push rejected” – isto significa apenas que alguém levou seus commits antes de você, e se você empurrar as alterações, suas mudanças substiuirão as deles.

O inverso da operação push ou é pull ou fetch. Ambas irão derrubar commits a partir do repositório remoto, no entanto, o pull vai mesclar essas alterações em sua filial local; ao mesmo tempo que o fetch fará com que o commits estejam disponíveis para inspeção.

# Get the latest changes without merging
git fetch github
# Get the latest changes and merge them in
git pull github

No exemplo dos desenvolvedores acima, se o Desenvolvedor 1 era para empurrar a sua mudança para o GitHub, e Desenvolvedor 2 para puxar as mudanças em seu repositório, seria automaticamente criado um nó de junção que une as duas árvores . Um nó de mesclagem é um que tem dois ou mais pais commits, neste caso, teríamos que criar um G commit cujos pais eram D e F.

Se o Desenvolvedor 2 levar suas alterações de volta para o GitHub (isto é a confirmação de mesclagem), então este estará disponível para o Desenvolvedor 1 puxar. Neste caso, não será necessário que o Desenvolvedor 1 crie um nó para merge (uma vez que o merge já foi realizado naquele ponto) e, no lugar, terá um fast-foward merge. Um fast-foward merge é simplesmente aquele que se move para frente através da história dos commits; em outras palavras, se ele vai de A a D, é considerado um fast-forward merge.

Vamos olhar mais para os merges e para a diferença entre fetch e pull! Mas por agora, se estiver criando uma cópia de backup do seu repositório (ou simplesmente quiser disponibilizá-lo para os outros no GitHub), então agora você terá as ferramentas para conseguir isso.

***

Texto original disponível em: http://alblue.bandlem.com/2011/03/git-tip-of-week-pushing-and-pulling.html