Quem já teve de descobrir, num servidor de produção, «quem mudou isto, e quando?» percebe depressa porque é que o git se tornou o padrão do desenvolvimento de software. O git regista a história completa de um projeto — cada alteração, quem a fez e quando — e permite voltar atrás, abrir linhas de trabalho paralelas e colaborar sem pisar o trabalho dos outros.
Neste guia percorremos o fluxo do dia a dia no terminal: configuração, as três áreas, commits e histórico, ramos e fusões, remotos e como desfazer erros com segurança. E um aviso: o histórico guarda tudo — incluindo os segredos que lá nunca deviam ter entrado.
Veja o guia em vídeo
Prefere ver antes de experimentar? No canal HJFR-IT no YouTube mostramos o git opção a opção, com o resultado de cada comando no ecrã — narrado em português e com legendas.
O que faz o git
O git é um sistema de controlo de versões distribuído: cada cópia de um repositório contém a história completa, guardada numa pasta escondida chamada .git. A forma geral é sempre a mesma — git, um subcomando e as respetivas opções:
git <subcomando> [opções] [argumentos]
git help <subcomando> # o manual de cada subcomando
Configuração e começar um repositório
Antes do primeiro commit, o git precisa de saber quem é: cada commit fica assinado com um nome e um email. Com --global, a configuração é gravada uma única vez em ~/.gitconfig e serve para todos os repositórios.
git config --global user.name "Aluno HJFR"
git config --global user.email aluno@example.com
git init— transforma a pasta atual num repositório novo e vazio, criando a pasta.gitonde vai viver a história.git clone URL— a forma mais comum: copia um repositório existente, de uma plataforma de alojamento de código ou de um servidor interno, com toda a história e já ligado à origem remota, oorigin.
As três áreas: trabalho, staging e repositório
Para entender o git é essencial perceber as suas três áreas. O diretório de trabalho é onde edita os ficheiros; a staging (ou índice) é a zona intermédia onde prepara o próximo commit; o repositório é a história permanente.
git status, a bússola
O git status diz onde está cada coisa: o que mudou e não foi preparado, o que já está na staging e o que o git não segue (untracked). Use-o constantemente.
git add: preparar o próximo commit
git add ficheiro— passa um ficheiro concreto para a staging.git add -A— prepara tudo de uma vez: novos, modificados e apagados. Prático, mas apanha também o que não devia.git add -p— o modo patch mostra cada bloco de alterações (hunk) e pergunta se entra. Assim divide um trabalho confuso em commits coerentes.
O que nunca deve ser seguido — segredos, artefactos de compilação — lista-se no .gitignore, um padrão por linha (por exemplo .env ou build/). Atenção: só atua sobre ficheiros ainda não seguidos; um ficheiro que já esteja no índice tem de sair com git rm --cached.
Commits e histórico
O commit é o coração do git: grava na história o que está na staging, criando um instantâneo com um identificador único (o hash). A mensagem deve descrever o porquê da alteração, não só o quê.
git commit -m "mensagem"— grava a staging com uma mensagem.git commit -am "mensagem"— prepara e grava de uma vez os ficheiros já seguidos, saltando ogit add. Não apanha ficheiros novos.git commit --amend— corrige o último commit (a mensagem ou algo esquecido). Cria um commit novo, com outro hash: só antes de o enviar para o remoto.
Para ver a história, git log --oneline --graph dá uma linha por commit e o desenho dos ramos; HEAD -> main é o ponteiro que indica onde está. O git log -p mostra também as alterações de cada commit.
$ git log --oneline --graph
* 4d40940 (HEAD -> main) Muda a porta para 8080
* 0e453d0 Desliga o modo debug
* 3d3acf5 Primeira versão do site
Ramos e merge
Um ramo é uma linha de trabalho independente: experimenta-se uma funcionalidade sem tocar no código principal e junta-se quando estiver pronta. Criar um ramo é instantâneo — é só um novo ponteiro.
git branch— lista os ramos e marca com*o atual.git switch -c nome— cria um ramo e muda para ele; a forma clássica equivalente égit checkout -b nome.git switch mainegit merge nome— volta ao ramo principal e traz para ele o trabalho do outro ramo.
Quando há conflito
Se as alterações não colidirem, a fusão é automática (e, se o ramo principal não avançou, é um simples fast-forward). Se os dois ramos mudaram as mesmas linhas, o git assinala um conflito e marca os dois lados no ficheiro:
<<<<<<< HEAD
<footer>Contactos</footer>
=======
<a href="/login">Entrar</a>
>>>>>>> feature/login
Resolve-se à mão, retirando as marcas, e completa-se a fusão com git add e git commit.
Repositórios remotos
Um remoto é uma versão do repositório noutro servidor, tipicamente chamado origin, e permite colaborar e ter cópias fora da sua máquina. O git remote -v lista os remotos e os endereços. Para sincronizar há três comandos:
git fetch— descarrega as alterações do remoto sem as juntar ao seu trabalho: só atualiza oorigin/main, para ver o que mudou antes de integrar.git pull— um fetch seguido de um merge: traz e integra logo no ramo atual.git push— envia os seus commits. Na primeira vez, o-uliga o ramo local ao remoto (o upstream); daí em diante,pushepullsabem para onde ir.
git remote add origin git@git.hjfr-info.pt:aluno/lab.git
git push -u origin main
git fetch && git log --oneline main..origin/main
git pull
Desfazer alterações com segurança
git restore ficheiro— descarta as alterações não gravadas, voltando à última versão. O trabalho não guardado perde-se.git restore --staged ficheiro— o oposto doadd: tira da staging, mas mantém as alterações.git reset --soft HEAD~1— desfaz o último commit e mantém tudo preparado.git reset --mixed HEAD~1— o modo padrão: desfaz e tira da staging, mas mantém as alterações nos ficheiros.git reset --hard HEAD~1— o perigoso: desfaz e apaga tudo, voltando ao estado do commit.
O reset reescreve a história: em commits já enviados, use o git revert, que cria um commit novo a anular o antigo. E o git stash é uma gaveta temporária: guarda o trabalho em curso para trocar de tarefa a meio; git stash pop recupera-o.
Inspecionar: diff, blame, show e tags
git diff— as alterações ainda fora da staging; com--staged, o que já está preparado, ou seja, exatamente o que vai no próximo commit.git blame ficheiro— o commit, o autor e a data de cada linha.git show commit— a mensagem e as alterações de um commit.git tag -a v1.0 -m "Versão 1.0"— marca uma versão; envia-se comgit push --follow-tags.
Ficam de fora o rebase, para reorganizar a história, e o cherry-pick, para trazer um commit isolado.
git em cibersegurança
O histórico não esquece. Um .env apanhado por um git add -A descuidado fica no commit, e apagá-lo depois não o tira da história: um git log -p | grep -E "KEY|PASS" encontra-o em segundos. Se o commit não saiu da máquina, um --amend resolve; se já foi enviado, o segredo está comprometido — troque-o e só depois limpe a história, por exemplo com git filter-repo.
Prevenir é mais barato do que limpar. Um .gitignore desde o primeiro dia, a revisão com git diff --staged e um hook de pre-commit que procure credenciais evitam a maioria dos incidentes. E nunca deixe a pasta .git na raiz pública de um site: um /.git/ acessível por HTTP permite reconstruir o código e o histórico.
Rastreabilidade e assinaturas. Em resposta a incidentes, git log, git blame e git show dizem o que mudou, quando e por quem — mas o autor de um commit é texto definido com git config, fácil de falsificar. Assinar commits e tags (git commit -S, git tag -s, com chave GPG ou SSH) e verificá-los com git log --show-signature garante a autoria.
Experimente no simulador interativo
O simulador recria um pequeno projeto em ~/lab, com um .env que guarda uma chave de API fictícia. À esquerda vê as três áreas, com os ficheiros a mudar de área a cada comando, e o grafo de commits com ramos, HEAD, origin/main e tags; à direita, o terminal. Demonstrar tudo percorre 40 passos, do git init à tag v1.0, com um segredo esquecido e um conflito pelo meio; Anterior e Seguinte navegam passo a passo e Repor estado volta ao início. Experimente também clicar em qualquer comando.
Erros comuns e boas práticas
- Usar
git add -Asem.gitignore: prepara tudo, incluindo credenciais. Crie o.gitignoreantes do primeiro commit. - Fazer commit sem rever:
git statusegit diff --stagedantes de gravar. - Reescrever história partilhada:
resetou--amendem commits enviados baralham a equipa. Usegit revert. - Usar
reset --hardpor reflexo: apaga as alterações locais sem retorno. Para arrumar o trabalho por uns minutos, prefira ogit stash. - Confundir
fetchcompull: o primeiro só descarrega, o segundo também integra. Na dúvida,fetchprimeiro. - Mensagens vagas: «alterações» não diz nada daqui a seis meses. Explique o porquê.
Conclusão
Config e init, status e add, commit e log, ramos e merge, fetch, pull e push, e restore, reset, revert e stash: é o fluxo completo do dia a dia. A regra que fica é simples — reveja o que entra no commit, porque o histórico não esquece.
Os remotos do tipo git@servidor:projeto.git autenticam-se com chaves SSH — veja como as gerir no artigo sobre ssh e scp. E para procurar padrões no código e no histórico, o grep é o companheiro natural do git log -p.
Workshop — Linha de Comandos Linux
Quer passar da leitura à prática, com exercícios reais e acompanhamento? No workshop Linha de Comandos Linux da HJFR trabalha estes e outros comandos da série — da administração do dia a dia à resposta a incidentes.
Este artigo faz parte da série «Comandos Linux, um a um» do blog HJFR — fique atento aos próximos comandos.
