DEVEL UP: Controle de versão – Conceitos

O que acontece quando um desenvolvedor em seu time causa uma falha fatal no código, e ninguém tem um backup? Neste tutorial da série DEVEL UP, falaremos sobre como gerenciar versões à prova de falhas no seu projeto.

Quando começamos a desenvolver um jogo em equipe, precisamos de algum método para manter os arquivos atualizados nos computadores de cada integrante. É comum usar meios como Pen Drives, ou então sincronização online pelo Google Drive.

Sistema de armazenamento de arquivos online da Google.

No entanto, meios de compartilhamento de arquivos em nuvem causam um problema grave: se alguém fizer alguma alteração errada, todos os integrantes terão o mesmo erro. A não ser que alguém tenha feito uma cópia previamente, o projeto pode ser perdido.

Além disso, ainda que a cópia tenha sido feita, a versão da cópia pode ser de muito tempo atrás, ou seja, muitas alterações corretas também serão perdidas. A não ser que você seja um robô, no entanto, provavelmente você não vai se lembrar de fazer backups temporários. Como resolver isso?

Uma maneira é usar o que chamamos de Source Control Management, também conhecido como Controle de Versão ou Versionamento. A técnica consiste em usar aplicações que permitam armazenar múltiplas versões de um conjunto de arquivos. Ao modificar os arquivos, a aplicação detecta as mudanças e permite o desenvolvedor a criar uma versão do projeto. Na imagem abaixo, podemos ver cada círculo como uma versão do projeto.

SCM-1
Diagrama de versionamento básico.

Também podemos ver isso como os checkpoints e saves em jogos eletrônicos, onde salvamos nosso progresso em uma certa etapa – a diferença é que todo save será em um novo slot obrigatoriamente, ao contrário do que acontece normalmente nos jogos.

Exemplo de sistema de saves no jogo The Elder Scrolls V: Skyrim

Então ao usar Controle de Versão, todos começam em uma versão inicial. Quando alguém faz uma mudança no código, ou mesmo adiciona arquivos no projeto, ele pode salvar a mudança em uma nova versão. Em controle de versão, chamamos esta operação de Commit, pois estamos cometendo as mudanças. A imagem abaixo mostra a operação em funcionamento.

Operação de Commit

Temos uma cópia local do projeto, que chamamos de Working Copy. Cometemos as alterações, e estas vão ser enviadas para um servidor. O servidor recebe a atualização, e envia a confirmação da mudança de versão para a cópia local.

Quando criamos algum erro no projeto enquanto estamos editando, podemos desfazer alterações em nossos arquivos, voltando para a última versão que funcionava. Chamamos esta operação de descarte de alterações. Se criarmos uma versão errada, podemos fazer uma Reversão, ou seja, criar uma nova versão que reverte as alterações da última versão.

Exemplo de processo de reversão de uma versão.

A imagem acima mostra um exemplo do processo de reversão. No caso, a segunda versão do diagrama é revertida após a terceira, mostrando o poder de reverter até mesmo mudanças antigas. É muito melhor programar em equipe com a tranquilidade de que, se alguém fizer algo errado, há como consertar!

Então, isso são algumas das maravilhas do Controle de Versão. Mesmo assim, podemos ter algumas dores de cabeça. Quando duas pessoas editam o mesmo arquivo ao mesmo tempo, as alterações de cada um entrarão em conflito. A forma rápida de resolver isso é descartando as alterações feitas por um, e apenas salvando as de outro.

No entanto, controle de versão oferece uma operação para resolução de conflitos chamada Merge. O que acontece é que nem sempre as alterações sobre um arquivo excluem uma à outra. Isso é especialmente verdadeiro em arquivos de texto: se duas pessoas alteram linhas diferentes de código, não deveria haver nenhum problema!

A aplicação de controle de versão é capaz de unir as duas versões em uma só, agregando as duas versões. Mas também há casos em que ambos os desenvolvedores fazem alterações na mesma linha de texto, o que causa Merge Conflicts.

Neste caso, a equipe deverá decidir manualmente quais partes do código vão para a versão final. A maioria das aplicações de controle de versão oferecem ferramentas visuais para auxiliar nisso.

Em desenvolvimento de aplicações grandes, e principalmente jogos, milhares de conflitos podem ocorrer, muitas vezes em arquivos não-textuais gerados pela Game Engine, como arquivos que descrevem mapa ou imagens. Resolver todos estes conflitos, durante todo o tempo, tomaria muito tempo da equipe, e não seria útil no final das contas.

Para este problema, existe uma solução chamada Ramificação. O que fazemos é criar uma árvore de versões, onde cada desenvolvedor pode criar versões em um ramo, sem ter conflitos com outros ramos. A imagem abaixo mostra um esquema com dois ramos: um de features e um de desenvolvimento geral.

Utilizando o esquema acima, um programador pode fazer alterações no código e realizar teste na features branch (inglês para ramo), enquanto que um level designer pode criar mapas e testar com uma versão estável, sem se preocupar com bugs que possam surgir em novas features.

Quando o programador termina de desenvolver a feature, testa e prova que é funcional, ele pode fazer a operação de Merge entre ramos, ou seja, unir as mudanças do features branch no ramo principal. Desta forma, eliminamos toda a dor de cabeça que uma mudança incompleta de um membro da equipe possa causar no trabalho de outro.

Bom, neste post vimos alguns conceitos de Controle de Versão. Poderíamos fazer um tutorial muito extensivo sobre todas as outras operações e ferramentas envolvidas, mas acreditamos que pelo conceito geral, você possa ir atrás das ferramentas e aprender com facilidade.

Veja também:

Abaixo, listaremos algumas das ferramentas para controle de versão mais utilizadas atualmente, de forma que você pesquise e decida qual é a melhor para seu projeto. Clique nos links abaixo para saber mais:

GIT

SVN

Outros