As três zonas do Git
O Git não é "uma pasta com cópias". Uma mudança viaja por três zonas antes de ser gravada na história do projeto:
- Working directory (diretório de trabalho): seus arquivos exatamente como você os edita. Aqui o Git ainda não conhece as mudanças.
- Staging area (índice): a "sala de embarque". Você escolhe quais mudanças entram
no próximo commit com
git add. - Histórico (repositório local): a sequência imutável de commits. Só
git commitmove algo para cá.
git status # o que há em cada zona?
git add arquivo.js # working -> staging (você prepara a mudança)
git add . # prepara TUDO o que foi modificado
git commit -m "feat: adiciona login" # staging -> histórico
Ideia-chave: só
git commitescreve no histórico.git addnão cria um ponto de salvamento; apenas prepara o que entrará no próximo commit.
Um commit é um instantâneo identificado por um hash (SHA), com autor, data, mensagem e um ponteiro para o seu commit pai. Essa cadeia de pais é a história.
Branches
Uma branch é um ponteiro leve para um commit. Criar uma branch é quase de graça e
permite que você trabalhe em paralelo sem tocar em main:
git branch # lista as branches (a atual com *)
git switch -c feature/login # cria e muda para uma branch nova
git switch main # volta para main
git log --oneline --graph # veja a árvore de commits
HEAD é um ponteiro para "onde você está" (normalmente a branch atual).
Integrar trabalho: merge vs rebase
Quando sua branch e main avançaram separadamente, é preciso integrar. Duas
estratégias:
git merge
Cria um commit de merge que une as duas histórias. Não reescreve nada: preserva o grafo real de como o trabalho aconteceu.
git switch main
git merge feature/login # cria um merge commit que une as duas branches
git rebase
Reaplica seus commits em cima da ponta de main, como se você os tivesse
escrito a partir dali. O resultado é uma história linear, sem commits de
merge.
git switch feature/login
git rebase main # move seus commits em cima de main (os reescreve)
Quando usar cada um?
- merge para integrar uma branch em
main(especialmente ao fechar um PR): preserva o contexto e é seguro em branches compartilhadas. - rebase para limpar a sua própria branch antes de abrir o PR (deixá-la em
dia com
main, agrupar commits). História linear e fácil de ler.
Regra de ouro: nunca faça
rebasede commits que você já publicou e outros baixaram. Reescrever história compartilhada quebra o repo dos seus colegas. Faça rebase em privado, merge em público.
Resolver conflitos
Um conflito ocorre quando merge/rebase não consegue combinar duas mudanças sobre as mesmas linhas. O Git marca o arquivo assim:
<<<<<<< HEAD
const saudacao = "Olá";
=======
const saudacao = "Oi";
>>>>>>> feature/login
Você edita o arquivo deixando a versão final (apagando os marcadores), e depois:
git add arquivo.js # marca o conflito como resolvido
git commit # no merge: fecha o merge
# ou, se você estava em rebase:
git rebase --continue
git rebase --abort # cancela e volta ao estado anterior
Desfazer: revert vs reset
git revert <commit>: cria um commit novo que inverte as mudanças de outro. Não apaga história -> é a forma segura em branches compartilhadas.
git revert a1b2c3d # adiciona um commit que desfaz a1b2c3d
git reset: move a branch para outro commit, descartando os posteriores do histórico. Reescreve história -> use só em mudanças locais.
git reset --soft HEAD~1 # desfaz o último commit, deixa as mudanças no staging
git reset --mixed HEAD~1 # (padrão) desfaz commit e staging; preserva os arquivos
git reset --hard HEAD~1 # desfaz TUDO, inclusive seus arquivos (perigoso)
Resumo: em algo já publicado, revert. Em commits locais que você ainda não compartilhou, reset.