Continuando nossa jornada de Configuração como código, vamos introduzir uma ferramenta muito conhecida daqueles que trabalham em desenvolvimento de código. O Git é um sistema de controle de versão distribuído, criado por um desenvolvedor pouco famoso, chamado Linus Torvalds (sim, o criador do Linux). É um sistema grátis e open source e é adequado para gerir tanto projetos pequenos, quanto projetos grandes. Esta introdução ao Git foi inspirada num livro muito bom, chamado Ry's Git Tutorial, este livro, assim como o software git é grátis e altamente recomendado.

Afinal, o que é VCS

Os sistemas de controle de versão são uma categoria de ferramentas de software que ajudam uma equipe de software a gerenciar mudanças no código-fonte ao longo do tempo. O software de controle de versão mantém um registro de todas as modificações do código em um tipo especial de banco de dados. Se um erro for cometido, os desenvolvedores podem voltar no tempo e comparar as versões anteriores do código para ajudar a corrigir o erro de forma rápida e eficiente.

O VCS permite que você reverta os arquivos selecionados para um estado anterior, reverta todo o projeto para um estado anterior, compare as alterações ao longo do tempo, veja quem modificou pela última vez algo que pode estar causando um problema, quem o introduziu e quando, e muito mais. Usar um VCS geralmente também significa que, se você estragar as coisas ou perder arquivos, poderá recuperar facilmente.

A história do Projeto

Em palavras simples, um sistema VCS permite gravar toda a história de um projeto. Além de gravar a história, o sistema permite voltar à qualquer ponto dessa história, de forma fácil e rápida.

Tem mais, nós podemos criar histórias paralelas, o grande diferencial do Git em relação à outros sistemas de versionamento é que ele permite a criação dessas histórias paralelas de forma ágil. Além disso, é possível ao final do desenvolvimento desta história paralela, juntá-la à história principal.

Já imaginou poder voltar à qualquer ponto da história e corrigir erros para que eles não afetem nosso futuro? É isso que o Git permite, como vamos ver ao longo dessa introdução.

VCS Distribuído

Diagrama de VCS Distribuído
Fonte: https://git-scm.com/about/distributed

O Git é um sistema de VCS distribuído, D-VCS usa um modelo peer-to-peer para o versionamento de código. Não existe um repositório central, em vez disso, cada usuário que contribui para o código-fonte tem uma cópia completa do repositório, incluindo todo seu histórico de mudanças. Portanto, se qualquer servidor morre, qualquer desenvolvedor poderá restaurar a cópia exata do código-fonte.

Este modelo trás algumas vantagens:

  • Permite trabalhar no código sem estar conectado à Internet
  • Permite um trabalho individual, ou seja, cada desenvolvedor pode contribuir de forma independente
  • Permite que vários tipos de fluxos de trabalho possam ser utilizados
Logo do Serviço GitHub
Fonte: https://github.com/logos

Pode ser um pouco confuso entender o Github ou o Gitlab como plataformas distribuídas, uma vez que temos a cópia do nosso projeto em um servidor central porém, perceba que a grande sacada está em saber que todo o repositório será clonado para cada máquina de cada desenvolvedor. O que ocorre é que elegemos um servidor central como um repositório compartilhado.

Como o Git Funciona

Vamos pensar no Git como uma implementação de um sistema de arquivos que possui algumas ferramentas que nos permitem controlar a versão de todos os arquivos e pastas presentes em um dado repositório. O Git trata nossos arquivos como um fluxo de estado, ou seja, toda vez que o estado do nosso arquivo é alterado, o Git irá tirar uma foto - snapshot - de todos os documentos de nosso repositório e guardar isso num banco de dados. Para ser eficiente, todos os arquivos que não foram alterados nessa mudança de estado, não são copiados novamente pelo Git, em vez disso o Git apenas referencia esses arquivos inalterados no snapshot anterior.

Os Três Estados

O estado dos arquivos de nosso repositório não é alterado à cada mudança que fazemos neles, caso fosse, seria um sistema de versionamento bem ruim, não contando com os constantes erros que cometemos enquanto estamos trabalhando em um arquivo.

Precisamos ser explícitos quando queremos alterar o estado de nossos arquivos. O Git possui três estados principais nos quais seus arquivos podem estar:

  • committed
  • modified
  • staged

committed significa que o estado daquele arquivo está armazenado no banco de dados, modified significa que o arquivo foi alterado, porém o mesmo ainda não foi armazenado no banco de dados, ou seja, ainda não foi realizado o commit do arquivo, staged significa que o arquivo modificado foi marcado para fazer parte da próxima alteração de estado, ou seja, do próximo commit.

Os três estados nos levam às três seções de um diretório Git.

  • repository (diretório .git)
  • working directory
  • staging area
As Três seções do Git
Fonte: https://git-scm.com/about/staging-area

O diretório .git é onde o Git armazena os metadados e o banco de dados de objetos de seu projeto. Este é o principal diretório do Git, o qual é copiado quando fazemos um clone do nosso repositório para uma máquina.

O working directory é a cópia de uma versão do projeto. Os arquivos contidos neste diretório são aqueles que foram resgatados do banco de dados compactado do diretório Git e colocados no disco para que se possa fazer alterações.

A staging area é um arquivo, geralmente contido no diretório .git, que armazena informações sobre o que vai ser incluído no nosso próximo commit.

Para mudar entre estes estados, utilizamos uma interface de linha de comando - cli - do próprio Git, como veremos mais a frente.

Como o Git Armazena as Mudanças de Estado

Ilustração do Hash SHA-1
Ilustração do Hash SHA-1

O Git usa um algoritmo de hash chamado SHA-1. O SHA-1 é representado por uma sequência de 40 caracteres hexadecimais, esta sequência é calculada com base no conteúdo da estrutura de arquivos existente no momento em que fazemos o commit, ou seja, que tiramos a foto - snapshot - do estado atual do nosso diretório para armazená-lo no banco de dados do Git.

A utilização de um algoritmo tal qual o SHA-1, estabelece um parâmetro de integridade ao banco de dados. Como a sequência que chamamos de hash é construída a partir dos conteúdos dos arquivos presentes no repositório, conseguimos garantir que qualquer alteração seja percebida.

Ao utilizar o Git, vamos ficar bastante acostumados em usar o hash para realizarmos diversas operações, pois é este hash que precisamos referenciar para termos acesso à um snapshot.

Ramificação ou Branching

Como falamos anteriormente, num sistema distribuído, temos a vantagem de cada desenvolvedor trabalhar em sua própria máquina com uma cópia local exata do repositório compartilhado. Porém, para que seja possível construir um fluxo de trabalho eficiente, o sistema de versionamento precisa permitir que haja ramificação no repositório, ou seja, permitir a criação de uma história paralela.

Vamos explicar com exemplos, para que fique mais claro. Branching é a funcionalidade mais importante do Git e precisamos compreendê-la bem para evoluirmos e usarmos a ferramenta com eficiência.

No Git, um branch é uma linha independente de desenvolvimento. Por exemplo, se você quiser experimentar uma nova ideia sem usar o Git, você pode copiar todos os seus arquivos de projeto em outro diretório e começar a fazer suas mudanças. Se você gostou do resultado, pode copiar os arquivos modificados de volta para o projeto original. Caso contrário, você simplesmente excluiria todo o experimento e esqueceria sobre ele.

Esta é exatamente a funcionalidade oferecida pelo sistema de Branching do Git, porém com alguns facilitadores. Primeiro, os branches apresentam um método à prova de erros para incorporar mudanças de um experimento. Em segundo lugar, eles permitem que você armazene todos os seus experimentos em um único diretório, o que torna muito mais fácil controlá-los e compartilhá-los com outras pessoas.

Vamos imaginar que temos um código base, mas que precisamos incluir uma feature, ou seja, uma nova funcionalidade em nosso código. Poderíamos alterar diretamente nossos arquivos, porém se cometermos algum erro, vamos atrapalhar o desenvolvimento de qualquer outro colaborador.

Para impedir que tenhamos este tipo de problema, criamos um novo branch no nosso repositório, este branch é apenas local, podemos desenvolver a nova feature sem qualquer problema e depois de termos certeza de que este novo desenvolvimento não atrapalha o código original, podemos fazer um merge no branch principal.

Sempre que criamos um repositório, através do comando git init, por padrão temos o branch principal, que chamamos de master - este nome deve mudar para main em breve - podemos tratar este branch como o principal.

Ramificação do Git
Fonte: https://dev.to/womakerscode/tutorial-git-o-que-sao-branches-ramos-no-git-57pn

Para criar um novo branch, usamos um outro comando chamado git branch <nome-do-branch>, podemos também usar um atalho e além de criar o novo branch já mudar nosso working directory para o novo branch. Para isso, usamos o comando git checkout -b <nome-do-branch>.

Uma vez que tenhamos nosso branch criado e tenhamos atualizado o nosso working directory podemos começar a desenvolver nossa nova funcionalidade.

Após desenvolver a nova funcionalidade e garantir que não temos impacto no branch principal, estaremos prontos para fazer um merge. O merge nada mais é do que juntar as modificações que fizemos em nosso branch com o master. Após juntar nossas alterações com o branch principal, podemos também enviar estas modificações ao repositório compartilhado, para isso, podemos utilizar um outro comando: git push.

Após utilizarmos o git push, o repositório compartilhado estará atualizado com as últimas alterações que fizemos e qualquer outro desenvolvedor que colabore conosco no projeto, poderá atualizar seu próprio repositório local através do comando git pull.

Concluindo

Vimos o que é o Git, como ele funciona e entendemos sua principal funcionalidade que é a possibilidade de criar branches e desenvolver o código de forma individual, sem atrapalhar o desenvolvimento de outros colaboradores, e sem ser atrapalhado também.

Eu gostaria de recomendar fortemente o livro do Ryan mas também é possível utilizar o livro Pro Git que também é de graça. A diferença entre eles é que o livro do Ryan é prático, mão na massa, e vai te levar passo a passo pelos comandos do Git, os fluxos de trabalho e etc. O livro Pro Git já é mais teórico, embora tenha exemplos funcionais.

Como qualquer outro aprendizado, para consolidar é preciso utilizar. Por isso, no próximo artigo, vamos entender como aplicar as funcionalidades do Git na prática para lidar com nossos arquivos de configuração escritos em YAML como vimos no artigo passado.