Git & GitHub
Controle de versão, commits, branches, merge, rebase e colaboração com Pull Requests. Porque "salvar e rezar" não é estratégia de desenvolvimento.
Introdução ao Git e Controle de Versão
Sabe aquele momento em que você mexe num arquivo, tudo quebra e você não lembra mais o que estava funcionando antes? Pois é. É exatamente pra isso que existe o controle de versão: um sistema que registra todas as alterações feitas nos seus arquivos ao longo do tempo, permitindo que você volte a qualquer ponto da história do projeto como se fosse um ctrl+Z infinito — mas muito mais poderoso.
A síndrome do arquivo_final_v3_AGORA_VAI.docx
Todo mundo já viveu isso: projeto.zip, projeto_backup.zip,
projeto_final.zip, projeto_final_MESMO.zip,
projeto_final_v2_nao_apaga.zip…
Com Git, você nunca mais precisa desse circo. Um único projeto,
toda a história preservada, sem duplicar pasta nenhuma.
Git vs GitHub — não é a mesma coisa!
Essa confusão é clássica. Git é a ferramenta de controle de versão que roda no seu computador — ela não precisa de internet, não precisa de conta, não precisa de nada. GitHub é uma plataforma online que hospeda repositórios Git e adiciona funcionalidades de colaboração: Pull Requests, Issues, Actions, etc. É basicamente o LinkedIn dos devs, só que com código.
🛠️ Git
- Software livre instalado localmente
- Criado por Linus Torvalds em 2005
- Funciona 100% offline
- Gerencia versões no seu HD
- Não tem interface web própria
☁️ GitHub
- Plataforma online (pertence à Microsoft)
- Lançado em 2008
- Precisa de internet e conta
- Hospeda repositórios Git na nuvem
- Tem PRs, Issues, Actions, Pages…
Curiosidade histórica: Linus Torvalds — o mesmo cara que criou o Linux — desenvolveu o Git em apenas alguns dias de abril de 2005. O motivo? A ferramenta que o kernel do Linux usava (BitKeeper) mudou sua licença e o Linus, literalmente, escreveu o substituto num fim de semana. Faz sentido que a ferramenta seja ridiculamente eficiente, né?
Instalação e configuração inicial
Depois de instalar o Git (git-scm.com), a primeira coisa é se apresentar pra ele. Esses dados vão aparecer em todos os seus commits:
# Configurar seu nome e e-mail (feito uma única vez por máquina)
git config --global user.name "Seu Nome Aqui"
git config --global user.email "seu@email.com"
# Definir o editor padrão (ex: VS Code)
git config --global core.editor "code --wait"
# Ver todas as configurações
git config --list
Iniciando um repositório
Você tem dois caminhos: criar um repositório novo do zero, ou clonar um existente de algum lugar.
# Criar um repositório novo na pasta atual
git init
# Criar um repositório numa pasta com nome específico
git init meu-projeto
# Clonar um repositório existente (do GitHub, por exemplo)
git clone https://github.com/usuario/repositorio.git
# Clonar numa pasta com nome diferente
git clone https://github.com/usuario/repositorio.git minha-pasta
Os 3 estados do Git
Todo arquivo no seu projeto vive em um desses três estados. Entender isso é fundamental pra não ficar perdido quando o Git parece não estar salvando o que você quer:
Commits
Um commit é um snapshot do seu projeto num determinado momento. Não é só "salvar o arquivo" — é registrar o estado completo de todos os arquivos rastreados, com autor, data, hora e uma mensagem explicando o que mudou. Pense como fotografias: cada commit é uma foto do seu código.
A metáfora da foto: Commit é como tirar uma foto do código. Não adianta tirar a foto depois da bagunça. Se você commitar um bug, ele ficará no histórico para sempre — mas isso não é problema, porque você pode criar outro commit consertando. O histórico é sagrado: não se apaga, se corrige.
git status — o termômetro do projeto
Antes de qualquer coisa, git status mostra exatamente o que está acontecendo:
arquivos modificados, adicionados, deletados, o que está na staging area e o que não está.
Use esse comando o tempo todo — não tem custo nenhum.
# Ver o estado atual do repositório
git status
# Versão curta e compacta
git status -s
git add — preparando o commit
O git add move arquivos do Working Directory para a Staging Area.
Você tem controle total sobre o que entra em cada commit:
# Adicionar um arquivo específico
git add index.html
# Adicionar múltiplos arquivos
git add style.css script.js
# Adicionar TUDO na pasta atual (cuidado!)
git add .
# Adicionar todos os arquivos com determinada extensão
git add "*.css"
# Modo interativo: escolher pedaços específicos de um arquivo
git add -p style.css
# O Git mostra cada trecho modificado e pergunta: stage? (y/n/q/a/d/?)
Dica: O git add -p (patch mode) é um dos comandos mais
poderosos do Git. Ele permite que você adicione apenas partes de um arquivo,
não o arquivo inteiro. Útil quando você fez duas coisas diferentes num mesmo arquivo
e quer commitar separado. Sênior move.
git commit — registrando o snapshot
# Commitar com mensagem inline
git commit -m "feat: adiciona página de contato"
# Adicionar e commitar arquivos já rastreados de uma vez
git commit -am "fix: corrige layout no mobile"
# Abrir editor para mensagem mais detalhada
git commit
# Corrigir o último commit (mensagem ou arquivos esquecidos)
git commit --amend -m "feat: adiciona página de contato com validação"
# ⚠️ Só use --amend se o commit ainda não foi enviado ao GitHub!
Como escrever uma boa mensagem de commit
Mensagem de commit ruim: "arrumei coisa", "wip", "teste",
"aaaa". Seis meses depois ninguém (incluindo você) vai entender o que foi feito.
O padrão Conventional Commits resolve isso com um formato simples:
| Tipo | Quando usar | Exemplo |
|---|---|---|
feat |
Nova funcionalidade para o usuário | feat: adiciona login com Google |
fix |
Correção de bug | fix: corrige erro 404 na rota /perfil |
docs |
Mudanças na documentação | docs: atualiza README com instruções de setup |
style |
Formatação, espaços, vírgulas (sem lógica) | style: formata arquivo com prettier |
refactor |
Refatoração sem mudar comportamento | refactor: extrai lógica de auth para serviço |
test |
Adicionar ou corrigir testes | test: adiciona testes para UserService |
chore |
Tarefas de manutenção (deps, config) | chore: atualiza dependências do npm |
perf |
Melhoria de performance | perf: otimiza query de busca de produtos |
git log — vendo o histórico
# Histórico completo
git log
# Versão compacta (uma linha por commit)
git log --oneline
# Com gráfico de branches (muito útil!)
git log --oneline --graph --all
# Filtrar por autor
git log --author="Seu Nome"
# Ver os últimos 5 commits
git log -5
# Ver mudanças de cada commit
git log -p
git diff — comparando versões
# Ver mudanças não staged (Working Directory vs Staging)
git diff
# Ver mudanças que já estão staged (Staging vs último commit)
git diff --staged
# Comparar dois commits específicos
git diff abc1234 def5678
# Comparar duas branches
git diff main feature/login
# Ver apenas os nomes dos arquivos que mudaram
git diff --name-only
.gitignore — o que o Git não deve ver
Tem arquivos que não devem entrar no repositório jamais: dependências (pesadas e regeneráveis), arquivos de configuração com senhas, builds e arquivos temporários do editor. O .gitignore lista esses arquivos e o Git simplesmente os ignora.
# Dependências (Node.js)
node_modules/
# Variáveis de ambiente — NUNCA commitar senhas!
.env
.env.local
.env.*.local
# Builds e distribuição
dist/
build/
out/
# Logs
*.log
npm-debug.log*
# Sistema operacional
.DS_Store
Thumbs.db
# Editor (VS Code)
.vscode/
*.swp
# PHP
vendor/
.phpunit.result.cache
Atenção total: Se você commitar um arquivo .env com
senhas de banco de dados ou API keys e enviar pro GitHub, essas credenciais ficam
públicas para o mundo inteiro — e bots vasculham o GitHub em tempo real atrás
exatamente disso. Adicione .env no .gitignore antes do
primeiro commit. Sem exceções.
Branches
Uma branch (ramificação) é como uma linha do tempo paralela do seu projeto. Você pode criar uma branch, fazer uma porção de mudanças radicais, e o código original na branch principal fica completamente intacto. Se as mudanças ficarem boas, você une as duas linhas do tempo. Se não ficarem, descarta e pronto.
Analogia de videogame: Lembra quando você salvava o jogo antes de uma missão difícil e abria um segundo save slot pra "tentar sem estragar o principal"? Branches funcionam exatamente assim — um save state paralelo onde você pode experimentar à vontade sem medo de quebrar o que já está funcionando.
Branch main/master
Todo repositório começa com uma branch padrão. Historicamente chamada de
master, hoje o GitHub e a maioria das ferramentas usa main.
Ela representa o estado "oficial" e estável do projeto.
Gerenciando branches
# Listar todas as branches locais
git branch
# Listar branches locais E remotas
git branch -a
# Criar uma nova branch
git branch feature/nova-funcionalidade
# Trocar para uma branch existente (forma clássica)
git checkout feature/nova-funcionalidade
# Trocar para uma branch existente (forma moderna — Git 2.23+)
git switch feature/nova-funcionalidade
# Criar E trocar para nova branch ao mesmo tempo (clássico)
git checkout -b feature/carrinho-de-compras
# Criar E trocar para nova branch ao mesmo tempo (moderno)
git switch -c feature/carrinho-de-compras
# Renomear a branch atual
git branch -m novo-nome
# Deletar uma branch (seguro — só deleta se já foi mergeada)
git branch -d feature/funcionalidade-concluida
# Deletar uma branch à força (cuidado!)
git branch -D feature/experimento-descartado
Estratégia de nomenclatura
Dar nome certo para branches torna o projeto muito mais organizado quando tem várias pessoas trabalhando:
feature/login-social,
feature/dashboard-admin
fix/menu-mobile-sobreposto
hotfix/pagamento-quebrando
Visualizando branches
O histórico com branches pode ser visualizado com git log --graph.
Aqui está um exemplo de como ele fica:
Merge e Rebase
Criar branches é fácil. O desafio (e a mágica) do Git é unir essas
linhas do tempo de volta. Existem duas formas principais de fazer isso: merge
e rebase — cada uma com suas vantagens e os seus momentos certos de usar.
git merge — unindo branches
O merge integra o histórico de uma branch em outra. Existem dois tipos de merge:
⚡ Fast-forward
Acontece quando a branch principal não teve commits novos desde que a feature branch foi criada. O Git simplesmente "avança" o ponteiro — limpo e sem commit de merge extra.
🔀 3-way Merge
Quando a branch principal teve commits depois que a feature branch foi criada, o Git cria um "commit de merge" que une os dois históricos. Preserva o contexto de quando cada mudança foi feita.
# Primeiro: ir para a branch que vai RECEBER as mudanças
git switch main
# Fazer o merge da feature branch na main
git merge feature/login
# Forçar um merge commit mesmo que seja fast-forward possível
git merge --no-ff feature/login
# Abandonar um merge que deu errado
git merge --abort
Conflitos de merge — calma, acontece com todo mundo
Um conflito acontece quando duas branches editaram a mesma linha do mesmo arquivo. O Git não sabe qual versão manter — e pede sua ajuda. O arquivo conflitado fica assim:
<<<<<<< HEAD (branch atual — main)
<h1>Bem-vindo ao nosso site!</h1>
=======
<h1>Olá, seja bem-vindo!</h1>
>>>>>>> feature/novo-titulo
Para resolver: edite o arquivo manualmente, escolhendo qual versão manter (ou combinando
as duas), remova as marcações do Git (<<<, ===, >>>)
e em seguida:
# 1. Editar os arquivos conflitados manualmente
# 2. Marcar como resolvido
git add index.html
# 3. Concluir o merge
git commit
# O Git já sugere uma mensagem de merge — é só confirmar
git rebase — reescrevendo a história
O rebase "move" seus commits para cima dos commits da branch alvo, como se você tivesse começado a trabalhar a partir do estado mais recente. Isso deixa o histórico mais linear e limpo, sem commits de merge extras.
# Estando na feature branch, fazer rebase em cima da main
git switch feature/login
git rebase main
# Se houver conflito: resolver, adicionar e continuar
git add arquivo-resolvido.js
git rebase --continue
# Abandonar o rebase se as coisas ficarem complicadas
git rebase --abort
Regra de ouro do rebase: Nunca faça rebase em uma branch pública/compartilhada. O rebase reescreve o histórico de commits — se outras pessoas já baixaram esses commits, você vai criar um caos danado de conflitos pra todo mundo. Use rebase apenas em branches locais que só você está mexendo.
git stash — guardando mudanças temporariamente
Você estava no meio de uma feature, aí chega uma demanda urgente. Mas você não quer commitar código incompleto. É aí que entra o stash: um baú temporário que guarda suas mudanças não commitadas pra você resolver outra coisa e voltar depois.
# Guardar mudanças não commitadas no baú
git stash
# Guardar com uma descrição
git stash push -m "wip: implementando carrinho"
# Ver o que tem no baú
git stash list
# Recuperar o último stash (remove do baú)
git stash pop
# Aplicar um stash específico (mantém no baú)
git stash apply stash@{2}
# Deletar um stash específico
git stash drop stash@{0}
# Limpar todos os stashes
git stash clear
git reset — desfazendo commits
Às vezes você commitou algo que não devia, ou quer refazer o último commit.
O git reset permite voltar no tempo — mas com cuidado:
| Modo | Commits | Staging Area | Working Directory | Quando usar |
|---|---|---|---|---|
--soft |
Desfaz | Mantém | Mantém | Quer refazer a mensagem ou separar em commits |
--mixed (padrão) |
Desfaz | Limpa | Mantém | Quer reescolher o que vai no commit |
--hard |
Desfaz | Limpa | Limpa | Abandonar tudo mesmo — sem volta! |
# Desfazer o último commit, mas manter as mudanças staged
git reset --soft HEAD~1
# Desfazer o último commit e tirar da staging area
git reset HEAD~1
# Desfazer os últimos 3 commits E as mudanças (IRREVERSÍVEL!)
git reset --hard HEAD~3
# Voltar para um commit específico pelo hash
git reset --hard abc1234
git revert — desfazendo sem reescrever história
O git revert é a alternativa segura ao reset --hard:
em vez de apagar commits, ele cria um novo commit que desfaz as mudanças.
Perfeito para uso em branches compartilhadas ou já enviadas ao GitHub.
# Reverter o último commit criando um novo commit "undoing"
git revert HEAD
# Reverter um commit específico pelo hash
git revert abc1234
# Reverter sem abrir o editor de mensagem
git revert --no-edit HEAD
reset vs revert: Userevertquando o commit já foi para o GitHub ou quando outras pessoas já têm aquele código. Useresetapenas para histórico local ainda não compartilhado. — Regra prática do dia a dia
git cherry-pick — trazendo um commit específico
O cherry-pick copia um commit de qualquer branch e o aplica na branch
atual. É como dizer: "Quero só aquele commit específico, sem trazer todo o resto
da branch." Muito útil para levar uma correção de bug para produção sem precisar
fazer merge da feature branch inteira.
Analogia: imagine que a branch feature/nova-tela
tem 10 commits. Nove são trabalho em progresso, mas o décimo corrige um bug
crítico que também afeta a main. Com cherry-pick, você copia
só esse commit para a main — sem levar nenhum dos outros nove.
# 1. Descubra o hash do commit que você quer copiar
git log --oneline feature/nova-tela
# → a3f8d12 fix: corrige validação de email ← este!
# → b9e2c45 wip: tela em progresso
# → c2b3e56 wip: componente incompleto
# 2. Vá para a branch que vai RECEBER o commit
git switch main
# 3. Aplique o commit pelo hash
git cherry-pick a3f8d12
# → O commit é copiado para a main com um novo hash
# Cherry-pick de múltiplos commits (um por um)
git cherry-pick a3f8d12 c4d9e01
# Cherry-pick de um intervalo de commits (do mais antigo ao mais novo)
git cherry-pick abc123..def456
# Aplicar sem commitar imediatamente (fica na staging area)
git cherry-pick --no-commit a3f8d12
# Se houver conflito: resolver o arquivo, depois continuar
git add arquivo-resolvido.js
git cherry-pick --continue
# Ou abandonar o cherry-pick se ficar complicado
git cherry-pick --abort
Cherry-pick duplica o commit — ele cria uma cópia com um novo hash na branch de destino. O commit original permanece intacto na branch de origem. Se depois você fizer merge dessas duas branches, o Git pode mostrar um conflito aparente naquele trecho, já que o mesmo código foi introduzido por dois commits diferentes. Use com consciência.
GitHub e Pull Requests
Agora que você domina o Git localmente, é hora de conectar tudo ao mundo. O GitHub transforma seu repositório local em algo colaborativo, versionado na nuvem e visível pra recrutadores, parceiros e a comunidade open source.
GitHub é o LinkedIn dos devs — só que muito mais honesto. No LinkedIn as pessoas inventam skills. No GitHub o código está lá pra qualquer um ver. Mantenha seu perfil ativo, commite projetos reais e cuide bem do seu README. Recrutadores e CTOs olham pra isso.
Conectando ao repositório remoto
# Adicionar o repositório remoto (origin é só um apelido)
git remote add origin https://github.com/seunome/meu-projeto.git
# Ver os remotes configurados
git remote -v
# Enviar a branch main pro GitHub pela primeira vez (-u define o tracking)
git push -u origin main
# Envios seguintes (já com tracking configurado)
git push
# Enviar uma branch nova pro GitHub
git push -u origin feature/nova-pagina
Baixando atualizações do remoto
# Baixar E integrar atualizações (fetch + merge)
git pull
# Baixar com rebase em vez de merge (histórico mais limpo)
git pull --rebase
# Só baixar, sem integrar (ver o que mudou antes de mexer)
git fetch
git fetch origin
# Ver a diferença entre local e remoto após o fetch
git diff main origin/main
fetch vs pull: O fetch baixa as atualizações mas
não altera seu código local. O pull baixa e já faz o merge.
Em projetos com muita gente, prefira fetch primeiro pra ver o que
mudou antes de integrar tudo de uma vez.
Fork vs Clone
🍴 Fork
Cria uma cópia do repositório de outra pessoa na sua conta do GitHub. É o ponto de partida para contribuir em projetos open source: você faz o fork, trabalha na sua cópia, e depois abre um Pull Request para o projeto original.
📥 Clone
Baixa um repositório (do GitHub ou qualquer outro lugar) para o seu computador. Você clona o seu próprio projeto, o fork que você fez, ou qualquer repositório público que queira explorar localmente.
O fluxo completo do Pull Request
O Pull Request (PR) é a forma padrão de propor mudanças em um projeto — seja open source ou em equipe. O fluxo é sempre o mesmo:
Crie seu próprio fork pelo botão no GitHub, depois clone localmente:
git clone https://github.com/seucusuario/projeto-forked.git
Nunca trabalhe direto na main. Use
git switch -c feature/minha-contribuicao
Commits pequenos e focados são muito melhor do que um commit gigante. Siga o padrão Conventional Commits.
git push -u origin feature/minha-contribuicao
O GitHub vai mostrar um botão "Compare & pull request". Clique, escreva um título claro, descreva o que mudou e por quê, e envie.
Os mantenedores do projeto (ou seus colegas de equipe) revisam o código, deixam comentários, pedem ajustes. É um processo colaborativo, não uma avaliação — todo mundo aprende nessa etapa.
Aprovado o PR, o mantenedor faz o merge. Sua contribuição agora faz parte oficial do projeto. Parabéns! 🎉
Issues e README — os pilares de um bom projeto
Um repositório profissional tem mais do que só código:
Cheat Sheet — Comandos do Dia a Dia
Os comandos que você vai usar nos próximos 90% das interações com o Git. Guarda essa tabela e consulta sempre que travar.
| Categoria | Comando | O que faz |
|---|---|---|
| Setup | git init |
Inicia um repositório Git na pasta atual |
git clone <url> |
Clona um repositório remoto localmente | |
git config --global user.name "…" |
Define seu nome nos commits | |
| Status | git status |
Mostra o estado atual do repositório |
git diff |
Mostra mudanças não staged | |
git diff --staged |
Mostra mudanças staged vs último commit | |
git log --oneline --graph |
Histórico compacto com gráfico de branches | |
| Staging | git add <arquivo> |
Adiciona arquivo à staging area |
git add . |
Adiciona tudo à staging area | |
git add -p |
Adiciona trechos específicos (patch mode) | |
git restore --staged <arquivo> |
Remove arquivo da staging area | |
| Commit | git commit -m "mensagem" |
Cria um commit com mensagem |
git commit --amend |
Corrige o último commit (local only!) | |
| Branches | git branch |
Lista branches locais |
git switch -c <nome> |
Cria e muda para nova branch | |
git switch <nome> |
Troca para branch existente | |
git branch -d <nome> |
Deleta branch (seguro) | |
| Merge | git merge <branch> |
Faz merge de uma branch na atual |
git merge --abort |
Cancela um merge em andamento | |
git rebase <branch> |
Faz rebase na branch especificada | |
git stash |
Guarda mudanças temporariamente | |
git stash pop |
Recupera o último stash | |
| Desfazer | git reset HEAD~1 |
Desfaz o último commit (mantém arquivos) |
git reset --hard HEAD~1 |
Desfaz commit E mudanças (irreversível!) | |
git revert HEAD |
Cria commit que desfaz o último (seguro) | |
| Cherry-pick | git cherry-pick <hash> |
Copia um commit específico para a branch atual |
git cherry-pick --no-commit <hash> |
Aplica as mudanças sem commitar (fica na staging) | |
git cherry-pick --abort |
Cancela um cherry-pick em andamento | |
| Remoto | git remote add origin <url> |
Adiciona repositório remoto |
git push -u origin main |
Envia branch ao remoto pela 1ª vez | |
git push |
Envia commits ao remoto | |
git pull |
Baixa e integra atualizações do remoto | |
git fetch |
Baixa atualizações sem integrar |
Resumo do Módulo — O que você aprendeu
- Git é uma ferramenta de controle de versão criada por Linus Torvalds; GitHub é a plataforma online para hospedar repositórios Git.
- Todo arquivo vive em um dos 3 estados: Working Directory, Staging Area ou Repository.
- Configure seu nome e e-mail com
git config --globalantes de começar qualquer projeto. - Commits são snapshots imutáveis do projeto — escreva mensagens claras seguindo Conventional Commits.
- Use
.gitignorepara não commitarnode_modules,.env, builds e arquivos de sistema. - Branches permitem desenvolver funcionalidades em paralelo sem afetar o código principal.
- Prefira
git switchegit switch -c(comandos modernos) ao invés degit checkout. - Merge integra branches; conflitos são resolvidos manualmente editando os arquivos marcados pelo Git.
- Nunca faça rebase em branches públicas/compartilhadas — use apenas em branches locais.
- Use
git stashpra guardar trabalho em progresso egit revertpra desfazer com segurança. - O fluxo de Pull Request é: fork → branch → commits → push → PR → code review → merge.
- Cuide do seu perfil no GitHub: projetos reais, READMEs bem escritos e commits frequentes.