Um dos fatores mais importantes para mim ao aprender sobre um novo assunto é estudar a forma como o entendimento sobre ele evoluiu ao longo da história, pois acredito que, ao fazer isso, muito se revela sobre o contexto em que as pessoas passaram a estudá-lo e a utilidade que ele traz para a sociedade.
Nesse sentido, resolvi experimentar uma abordagem nova para mim, que consiste em criar minhas próprias versões de ferramentas de software comumente usadas. Meu intuito com isso não é apenas replicar cada ferramenta em sua “forma final”, mas compreender as possíveis escolhas que as levaram a ser como são.
É exatamente esse processo que pretendo relatar na série “Git: da pedra aos metais”, que se inicia com esta publicação. Nela, começarei criando a versão mais óbvia que eu conseguir pensar para o versionamento de código e, parte por parte, trarei novas melhorias até atingir um resultado semelhante ao próprio Git.
Ao mesmo tempo em que escrevo cada artigo, planejo realizar a implementação do sistema com a linguagem Rust e disponibilizar o código de cada versão juntamente às publicações. Até o final da série, minha expectativa é que o sistema implemente as funcionalidades a seguir:
-
persistência e restauração de versões (commit);
-
rastreamento de histórico (log);
-
ramificações do histórico (branching);
-
staging area (index).
Eu não recomendaria esta série para pessoas que nunca tiveram contato com o Git, pois pretendo implementar o sistema já levando em consideração alguns dos conceitos existentes em Git. Por outro lado, caso você já o tenha utilizado e queira aprender ainda mais sobre seu funcionamento, essa é a oportunidade!
Primeira abordagem: cada versão é uma cópia completa do repositório
Inicialmente, optei por uma abordagem trivial e que, provavelmente, todos já utilizamos para fazer backup de algum projeto: para cada versão que precisamos guardar, todo o conteúdo presente atualmente no diretório de trabalho é copiado para um novo diretório.
Esse trabalho é automatizado por meio da interação com uma interface de linha de comando (CLI), de forma semelhante ao Git, e essa CLI, nomeada genericamente como vcs
, conta com apenas três comandos: init
, commit <descricao>
e restore <versao>
.
Conforme sugerido pelo nome, a responsabilidade do comando init
é inicializar um repositório controlado pelo sistema no diretório atual, o que, ao menos por ora, consiste em criar um diretório oculto .vcs
para abrigar todos os arquivos relacionados ao controle de versão, de forma análoga ao diretório .git
do Git.
O comando commit
é responsável por criar o backup do repositório, o que, como discutimos anteriormente, trata-se apenas de copiar todo o conteúdo para um diretório específico dentro de .vcs
. Nesse caso, o diretório de cada backup recebe como nome um número sequencial, como 1, 2, 3 etc., indicativo de sua versão.
Para facilitar o trabalho de identificar qual é o número associado à versão atual, utilizei um arquivo version
dentro de .vcs
, que, a cada execução de commit
, tem seu conteúdo substituído pelo número da nova versão.
Finalmente, cada diretório de versão abriga um arquivo extra com o nome README
, cujo conteúdo é uma string informada pelo usuário durante o commit (commit <descricao>
) para ajudar a identificar as alterações introduzidas por cada um deles.
O último comando, restore <versao>
, recebe o encargo de restaurar o repositório para o exato estado em que se encontrava na versão informada, o que, na prática, consiste em apagar todo o conteúdo do diretório raiz do repositório, com exceção de .vcs
, e criar uma cópia de todos os arquivos salvos no backup da versão desejada para o diretório atual, com exceção de README
.
O conteúdo do diretório .vcs
se assemelha ao seguinte:
ls .vcs/
1 2 3 version
O conteúdo do diretório de uma versão específica contém uma cópia de todos os arquivos do próprio repositório juntamente a um arquivo README
com a descrição do commit:
ls .vcs/3/
README a.txt b.txt
Tudo o que fiz até aqui é basicamente o que já fazemos ao copiar backups de um projeto para a nuvem ou para um outro dispositivo de armazenamento local, com a única diferença sendo a automatização desse processo por meio da CLI.
Como já sabemos, essa abordagem é prática, mas carrega consigo alguns problemas. Na próxima parte desta série, vou enumerar e resolver alguns desses problemas para melhorar o sistema. Com isso, encerro a primeira parte por aqui! Até a próxima!
Repositório
O código-fonte desta primeira versão pode ser consultado no repositório do GitHub.
Atribuições
- Fotografia da capa por Azzedine Rouichi em Unsplash