Git na prática: do primeiro commit ao workflow profissional
Do git init ao workflow de times — iniciando projetos, padrões de commits e branches, resolução de situações comuns e sincronização com repositórios remotos.
Git é a ferramenta mais usada no desenvolvimento de software — e também a mais mal usada. A maioria aprende o básico (add, commit, push) e para por aí, usando o histórico como lixeira em vez de documentação. Este tutorial cobre desde o início de um projeto até o workflow usado em times profissionais.
1. Configuração inicial (faça uma vez)
Antes de usar o Git em qualquer projeto, configure seu nome e email. Esses dados aparecem em cada commit que você fizer.
git config --global user.name "Seu Nome"
git config --global user.email "seu@email.com"
# Editor padrão para mensagens de commit
git config --global core.editor "code --wait" # VS Code
# git config --global core.editor "nano" # nano
# Verificar tudo que foi configurado
git config --list
2. Iniciando um projeto
Cenário A: projeto novo, do zero
# Cria a pasta e entra nela
mkdir meu-projeto && cd meu-projeto
# Inicia o repositório Git
git init
# Cria o .gitignore antes do primeiro commit
echo "venv/
__pycache__/
*.pyc
.env
db.sqlite3
staticfiles/
media/
.DS_Store" > .gitignore
# Primeiro commit
git add .
git commit -m "chore: setup inicial do projeto"
Cenário B: clonar um projeto existente do GitHub
# Clona o repositório
git clone https://github.com/usuario/repositorio.git
# Clona em uma pasta com nome diferente
git clone https://github.com/usuario/repositorio.git meu-nome
# Já entra na pasta certa
cd repositorio
Cenário C: projeto local já existente, subir para o GitHub
# Inicia o Git no projeto que já existe
git init
git add .
git commit -m "chore: primeiro commit"
# Conecta ao repositório remoto (crie ele no GitHub primeiro, sem README)
git remote add origin https://github.com/usuario/repositorio.git
# Sobe o código
git push -u origin main
O-udefine a branch remota como padrão para essa local. Depois disso, bastagit pushsem argumentos.
3. O ciclo diário: add, commit, push
# Ver o que mudou
git status
# Ver as diferenças linha a linha
git diff
# Adicionar arquivo específico
git add arquivo.py
# Adicionar tudo
git add .
# Commitar com mensagem
git commit -m "feat: adiciona página de perfil do usuário"
# Ver histórico
git log --oneline
# Subir para o GitHub
git push
4. Padrão de mensagens de commit (Conventional Commits)
Mensagens como "ajuste", "correção" ou "wip" não dizem nada. O padrão Conventional Commits define uma estrutura que qualquer pessoa do time (ou você mesmo em 6 meses) consegue entender.
O formato é:
tipo(escopo opcional): descrição curta no imperativo
corpo opcional — explica o "por quê", não o "o quê"
rodapé opcional — referência a issues, breaking changes
Tipos principais
| Tipo | Quando usar | Exemplo |
|---|---|---|
feat | Nova funcionalidade | feat: adiciona login com Google |
fix | Correção de bug | fix: corrige upload de avatar no Vercel |
docs | Documentação | docs: atualiza README com setup do Cloudinary |
style | Formatação, sem lógica | style: aplica padding mobile no container |
refactor | Refatoração sem novo comportamento | refactor: extrai lógica de email para service |
test | Testes | test: adiciona testes para view de tutoriais |
chore | Tarefas de manutenção, deps, config | chore: adiciona cloudinary ao requirements.txt |
perf | Melhoria de performance | perf: adiciona select_related nas queries de tutorial |
Exemplos reais bem escritos
# Simples e direto
git commit -m "feat: adiciona filtro por tag na listagem de tutoriais"
# Com escopo
git commit -m "fix(auth): corrige redirect após login via Google"
# Com corpo explicando o porquê
git commit -m "fix: troca DEFAULT_FILE_STORAGE por STORAGES dict
Django 6.0 ignorou silenciosamente a configuração legada,
causando erro 500 no upload de avatares na Vercel.
O novo formato STORAGES é obrigatório a partir do Django 4.2."
# Referenciando uma issue do GitHub
git commit -m "feat: implementa newsletter semanal
Closes #42"
5. Branches: trabalhando em paralelo
Nunca desenvolva diretamente na branch main. Crie uma branch para cada funcionalidade ou correção — assim você pode trabalhar em múltiplas coisas sem misturar código incompleto.
# Ver branches existentes
git branch
# Criar e já mudar para a nova branch
git checkout -b nome-da-branch
# ou, na sintaxe moderna:
git switch -c nome-da-branch
# Mudar de branch
git switch main
# Deletar branch local (após merge)
git branch -d feat/pagina-perfil
# Deletar branch remota
git push origin --delete feat/pagina-perfil
6. Padrão de nomenclatura de branches
O padrão mais adotado usa um prefixo que indica o tipo, seguido de uma descrição curta em kebab-case:
| Prefixo | Uso | Exemplo |
|---|---|---|
feat/ | Nova funcionalidade | feat/pagina-perfil-usuario |
fix/ | Correção de bug | fix/upload-avatar-vercel |
hotfix/ | Correção urgente em produção | hotfix/erro-500-login |
refactor/ | Refatoração | refactor/settings-cloudinary |
docs/ | Documentação | docs/atualiza-readme-deploy |
chore/ | Manutenção, dependências | chore/atualiza-django-6 |
test/ | Adição de testes | test/cobertura-views-tutoriais |
Use apenas letras minúsculas, números e hífens. Nunca espaços, underscores ou caracteres especiais no nome da branch.
7. Integrando branches: merge e rebase
Merge — une os históricos
# Estando na main, traz o conteúdo da feature branch
git switch main
git merge feat/pagina-perfil
# Sobe o resultado
git push
Rebase — reescreve o histórico de forma linear
# Na sua feature branch, atualiza com o que está na main
git switch feat/pagina-perfil
git rebase main
# Resolve conflitos se houver, depois:
git rebase --continue
# Volta para main e faz o merge (agora linear, sem commits de merge)
git switch main
git merge feat/pagina-perfil
Usemergepara branches compartilhadas (preserva o histórico real). Userebasepara atualizar sua branch local com o que chegou na main antes de abrir um Pull Request.
8. Resolvendo situações comuns
Desfazer o último commit (mas manter as mudanças)
git reset --soft HEAD~1
# Mudanças voltam para staged — você pode editar e commitar de novo
Corrigir a mensagem do último commit
git commit --amend -m "feat: mensagem corrigida"
# Atenção: não use amend em commits já enviados ao GitHub
Desfazer mudanças num arquivo antes do commit
# Descarta as mudanças e volta ao último commit
git checkout -- arquivo.py
# ou:
git restore arquivo.py
Guardar mudanças temporariamente sem commitar (stash)
# Guarda tudo que está modificado
git stash
# Recupera as mudanças guardadas
git stash pop
# Lista todos os stashes
git stash list
# Descarta o stash sem aplicar
git stash drop
Trazer um commit específico de outra branch (cherry-pick)
# Copia o commit abc1234 para a branch atual
git cherry-pick abc1234
Ver quem modificou cada linha de um arquivo
git blame arquivo.py
Encontrar qual commit introduziu um bug (bisect)
git bisect start
git bisect bad # o commit atual tem o bug
git bisect good v1.0 # essa tag/commit não tinha o bug
# Git vai navegando pelos commits — você testa e responde:
git bisect good # ou
git bisect bad
# Quando terminar:
git bisect reset
9. Mantendo o repositório sincronizado
# Baixa mudanças do remoto SEM aplicar
git fetch origin
# Baixa E aplica (fetch + merge)
git pull
# Pull com rebase (histórico mais limpo)
git pull --rebase
# Ver o que mudou no remoto antes de aplicar
git fetch origin
git log HEAD..origin/main --oneline
10. Tags: marcando versões
# Cria uma tag anotada na versão atual
git tag -a v1.0.0 -m "Versão 1.0.0 — MVP lançado"
# Lista todas as tags
git tag
# Sobe as tags para o GitHub
git push origin --tags
# Taguear um commit antigo
git tag -a v0.9.0 abc1234 -m "Versão 0.9.0"
11. .gitignore: o que nunca deve subir
Para projetos Django/Python, o .gitignore mínimo recomendado:
# Ambiente virtual
venv/
.venv/
env/
# Python
__pycache__/
*.pyc
*.pyo
*.pyd
*.egg-info/
dist/
build/
# Django
db.sqlite3
*.log
media/
staticfiles/
# Variáveis de ambiente — NUNCA commitar
.env
.env.local
.env.production
# Sistema operacional
.DS_Store # macOS
Thumbs.db # Windows
# IDEs
.vscode/
.idea/
*.swp
Se você commitou o.envpor acidente, não basta adicionar ao.gitignore. Você precisa removê-lo do histórico e considerar as credenciais comprometidas — troque todas as senhas e chaves imediatamente.
Resumo: o workflow do dia a dia
# 1. Atualiza a main
git switch main
git pull
# 2. Cria branch para a tarefa
git switch -c feat/nome-da-funcionalidade
# 3. Desenvolve, commitando com frequência
git add .
git commit -m "feat: descrição clara do que foi feito"
# 4. Antes de abrir PR, atualiza com o que chegou na main
git rebase main
# 5. Sobe a branch
git push -u origin feat/nome-da-funcionalidade
# 6. Abre Pull Request no GitHub
# 7. Após aprovação e merge, limpa localmente
git switch main
git pull
git branch -d feat/nome-da-funcionalidade