Pular para o conteúdo

Controle de Versão

Este material complementa os slides do Tópico 04 e aprofunda o uso de Git como ferramenta de controle de versão.
O objetivo é que você entenda não apenas “qual comando usar”, mas também o que está acontecendo por trás e por que isso é importante em Engenharia de Software.

Imagine um TCC em grupo sendo editado via e-mail, com arquivos como:

  • tcc-final.docx
  • tcc-final2.docx
  • tcc-final2-definitivo.docx

É quase certo que alguém vai sobrescrever o arquivo errado.
Um sistema de controle de versão é um histórico organizado de tudo o que aconteceu com o código (ou qualquer conjunto de arquivos).

Com controle de versão, você pode:

  • registrar quem mudou o quê e quando;
  • voltar para versões anteriores;
  • trabalhar em paralelo com outras pessoas (branches);
  • investigar rapidamente a origem de bugs (quem quebrou o quê).

Em projetos reais, usar Git é tão obrigatório quanto ter um compilador.

O Git é um sistema de controle de versão distribuído:

  • Cada pessoa tem uma cópia completa do repositório (com histórico) na máquina local;
  • Repositórios remotos (GitHub, GitLab, etc.) atuam como “pontos de encontro” para sincronizar trabalho;
  • Você pode trabalhar offline e fazer push/pull quando tiver internet.

Principais características:

  • muito rápido para operações locais;
  • trabalha muito bem com branches e merges;
  • garante integridade dos dados usando hashes (SHA-1 / SHA-256 nas versões mais novas).

Analogia:
Pense em um Google Docs offline: cada pessoa tem seu histórico completo, mas consegue sincronizar com um servidor quando quer compartilhar.

Após instalar o Git, configure o nome e e-mail que serão gravados em cada commit:

Terminal window
git config --global user.name "Alan Turing"
git config --global user.email "alan@turing.com"

Alguns pontos importantes:

  • --global aplica a configuração para todos os repositórios do seu usuário;
  • sem --global, a configuração vale apenas para o repositório atual (útil se você quiser e-mails diferentes em projetos distintos).

Essa configuração é identificação, não autenticação.
A autenticação com GitHub/GitLab normalmente envolve tokens, SSH ou credenciais configuradas separadamente.

Uma chave para entender Git é visualizar as três áreas:

  1. Working Directory (diretório de trabalho)
    Onde você edita os arquivos no seu sistema de arquivos.

  2. Staging Area (index)
    Uma “lista de alterações” que você escolheu para entrar no próximo commit.

  3. Local Repository (repositório local)
    Onde ficam os commits já registrados, dentro da pasta .git.

Analogia de cozinha:

  • Working Directory = bancada onde você prepara vários pratos;
  • Staging Area = bandeja onde você coloca apenas os pratos que vão sair agora;
  • Commit no Local Repository = o registro no cardápio do que foi servido naquele dia.

Quando você executa git init, o Git cria uma pasta oculta:

.git/

Ela contém:

  • histórico de commits;
  • configuração de branches, tags e remotos;
  • índice da staging area.

Se essa pasta for apagada, o seu código continua lá, mas o histórico some: a pasta deixa de ser um repositório Git.

Cada arquivo pode estar em um de quatro estados básicos:

  • Untracked: o Git ainda não está controlando esse arquivo;
  • Unmodified: igual à última versão commitada;
  • Modified: foi alterado no diretório de trabalho;
  • Staged: as alterações foram marcadas para entrar no próximo commit.

Fluxo típico:

  1. Cria/edita um arquivo → Untracked ou Modified;
  2. git addStaged;
  3. git commit → volta a Unmodified com um novo “snapshot”.

Apesar de existirem clientes gráficos, o terminal ainda é a forma mais potente e usada profissionalmente.

Duas formas comuns:

  1. clicar com o botão direito na pasta do projeto → Git Bash Here;
  2. abrir o app Git Bash e navegar até a pasta com cd.
ComandoDescrição
cd <caminho>entra em uma pasta
cd ..volta uma pasta
lslista arquivos da pasta atual
pwdmostra o caminho completo da pasta

Esses comandos não são exclusivos do Git; fazem parte da experiência de terminal (bash).

Para transformar uma pasta qualquer em um repositório Git:

Terminal window
git init
  • você precisa estar dentro da pasta desejada (verifique com pwd);
  • a pasta não pode já ter um repositório Git (não pode existir .git).

É válido tanto para projetos novos quanto para pastas que já têm código.

Depois de criar ou alterar arquivos:

Terminal window
git add .
  • o ponto (.) significa: “tudo a partir deste diretório para baixo”;
  • você também pode adicionar apenas arquivos/pastas específicas:
Terminal window
git add src/Main.java
git add documentos/relatorio.md

Um commit é um “ponto de salvamento” com:

  • um conjunto de alterações;
  • um autor (nome + e-mail);
  • uma mensagem descritiva;
  • um hash único de identificação.
Terminal window
git commit -m "Implementa cadastro de usuários"

Você pode adicionar uma descrição mais longa:

Terminal window
git commit -m "Implementa login" -m "Adiciona autenticação básica com token JWT..."

Em times profissionais, uma boa mensagem de commit:

  • resume a intenção (“o que” e, se necessário, “por que”);
  • evita ruídos como “arrumei coisas”, “mexi aqui”.

Um branch é uma linha de desenvolvimento independente.

  • O branch padrão costuma ser main ou master;
  • Branches permitem desenvolver novas features ou corrigir bugs sem quebrar o código estável.

Analogia de ficção científica:
Um branch é uma realidade paralela do projeto. Você pode experimentar ideias loucas naquele universo; se der certo, junta (merge) com a linha principal.

Terminal window
# cria um novo branch chamado developer
git branch developer
# deleta o branch developer (se já tiver sido integrado)
git branch -d developer
# lista branches locais e remotos
git branch -a
# troca para o branch developer
git checkout developer
# cria um branch "órfão", sem histórico anterior
git checkout --orphan developer

Na prática, você vai usar muito git checkout -b nome-da-feature para criar e já mudar para o novo branch:

Terminal window
git checkout -b feature/cadastro-produtos

merge é o processo de combinar o trabalho de dois branches.

Exemplo: juntar o branch developer em main:

Terminal window
git checkout main
git merge developer

Alguns cenários:

  • fast-forward: main não tem commits novos; o ponteiro só “avança” para o commit mais recente de developer;
  • merge commit: ambos têm commits; o Git cria um commit especial que une as duas linhas;
  • conflitos: quando a mesma parte de um arquivo foi alterada de formas incompatíveis em branches diferentes.

Em caso de conflito, o Git marca trechos assim:

<<<<<<< HEAD
versão em main
=======
versão em developer
>>>>>>> developer

Você precisa editar o arquivo, decidir o que fica, remover as marcações e então:

Terminal window
git add arquivo_com_resolucao
git commit # se o Git não criar o commit automaticamente

Um repositório remoto é uma cópia do seu repositório hospedada em outro lugar (GitHub, GitLab, Bitbucket, etc.).

Ele serve como:

  • backup;
  • ponto central de colaboração;
  • origem para pull/merge requests.

Se alguém já criou o repositório:

Terminal window
git clone https://gitlab.com/rVenson/linguagemdeprogramacao.git

O comando:

  1. cria uma pasta com o nome do projeto;
  2. baixa o histórico inteiro;
  3. configura um remoto padrão chamado origin.

Também é possível clonar de um caminho local:

Terminal window
git clone /c/Users/rvenson/Documents/LinguagemDeProgramacao

Se você começou localmente com git init e só depois criou o remoto:

Terminal window
git remote add origin https://gitlab.com/rVenson/linguagemdeprogramacao.git
  • origin é apenas um nome (convenção) para esse remoto;
  • use git remote -v para listar os remotos configurados.

Depois disso, você pode fazer:

Terminal window
git push -u origin main

para mandar o branch main para o servidor e registrá-lo como “upstream”.

Duas operações diferentes, mas parecidas no nome:

  • git fetch: baixa as novidades do servidor (novos commits, branches), mas não muda seus arquivos nem o branch atual;
  • git pull: faz fetch + integra automaticamente as mudanças no branch atual (geralmente por merge).

Fluxo comum antes de começar a trabalhar:

Terminal window
git pull origin main

para garantir que você está começando do estado mais recente.

Depois de criar commits localmente, você publica as alterações com git push:

Terminal window
git push # se o branch já tiver upstream definido
git push origin # envia o branch atual para 'origin'
git push origin main

Para um branch novo, normalmente:

Terminal window
git push -u origin feature/cadastro-produtos

O -u faz com que, no futuro, você possa usar apenas git push e git pull sem precisar especificar origin feature/cadastro-produtos.

O arquivo .gitignore, na raiz do projeto, lista os arquivos/pastas que não devem ser versionados:

  • binários compilados (.class, bin/, target/);
  • arquivos temporários da IDE;
  • logs, caches;
  • arquivos locais de configuração.

Exemplo:

Terminal window
# Ignora toda a pasta bin dentro do projeto
bin/
# Ignora todos os arquivos com final .import
*.import
# Ignora o arquivo project.config
project.config

Uma boa prática é usar geradores de .gitignore específicos para cada stack/IDE.
Um serviço popular é o antigo gitignore.io, hoje em:

Você escolhe, por exemplo, Java, Maven, IntelliJ, e ele gera um .gitignore adequado.

  • Prefira vários commits pequenos, cada um focado em uma coisa, a um gigante “monolito” com tudo misturado;
  • Isso facilita entender o histórico e reverter apenas partes específicas se algo quebrar.

Use frases no imperativo curto, em geral na forma:

  • Adiciona validação de CPF;
  • Corrige cálculo de imposto;
  • Remove dependência não utilizada.

Evite mensagens genéricas como “ajustes”, “update”, “mexi aqui”.

Organizar o trabalho por branches facilita revisão:

  • feature/cadastro-usuarios
  • bugfix/erro-login
  • hotfix/falha-producao

Na integração, use Pull Requests (GitHub) ou Merge Requests (GitLab) para discussão e revisão de código.

Use .gitignore para:

  • não poluir o repositório;
  • evitar subir credenciais, arquivos sensíveis ou ruído (logs, caches).

Um fluxo simplificado de trabalho em um projeto Java com Git:

  1. Obter o código

    Terminal window
    git clone <url-do-repo>
    cd projeto
  2. Criar um branch de trabalho

    Terminal window
    git checkout -b feature/nova-funcionalidade
  3. Implementar e testar

    • editar código;
    • rodar testes;
    • executar o programa.
  4. Verificar o que mudou

    Terminal window
    git status
    git diff
  5. Preparar e commitar

    Terminal window
    git add .
    git commit -m "Implementa nova funcionalidade X"
  6. Enviar para o remoto

    Terminal window
    git push -u origin feature/nova-funcionalidade
  7. Abrir um Merge Request / Pull Request

    • pedir revisão;
    • discutir alterações;
    • integrar no branch principal (main/develop).

Para praticar:

Neste tópico você viu:

  • o que é controle de versão e por que ele é essencial em projetos de software;
  • como o Git organiza o trabalho em working directory, staging e repositório local;
  • como criar repositórios, fazer commits, trabalhar com branches e resolver merges;
  • como configurar e usar repositórios remotos, além de ignorar arquivos com .gitignore;
  • boas práticas para usar Git de forma profissional em equipes.

Dominar Git desde o início do curso torna muito mais fácil colaborar em projetos, entregar trabalhos organizados e evoluir para fluxos de desenvolvimento usados no mercado.