Git
Controle de versão distribuído. Cada clone é um repositório completo com histórico inteiro.
Conceitos Fundamentais
git add
git commit
Objetos Git
Cada objeto = SHA-1 do conteúdo. Git é um banco de dados endereçável por conteúdo.
Commit pai
Todo commit aponta para o commit anterior (seu "pai"). Isso forma a cadeia que é o histórico:
A ← B ← C ← D (HEAD)
# D tem pai C, C tem pai B, B tem pai A
# A não tem pai — primeiro commit do repo
# Git não guarda diffs, guarda snapshots. Diff = comparar snapshot do commit com snapshot do pai
Merge commit tem 2 pais. O objeto armazena ambas as referências:
tree abc123
parent f1e2d3 ← pai 1 (branch atual)
parent 9a8b7c ← pai 2 (branch mergeada)
# histórico visual
* D (merge) — pai1=B, pai2=C
|\
| * C — pai=A
* | B — pai=A
|/
* A
Conflito ocorre quando pai1 e pai2 modificaram a mesma linha. Git pausa, pede resolução manual, depois cria o merge commit com os 2 pais.
git show :1:arquivo # versão do ancestral comum (base)
git show :2:arquivo # versão pai 1
git show :3:arquivo # versão pai 2
HEAD
Configuração
git config --global user.name "Alfredo Petri"
git config --global user.email "alfredo_petri@hotmail.com"
git config --global core.editor nvim
git config --global init.defaultBranch main
git config --global push.default current
git config --global pull.rebase true
# aliases
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --decorate --all"
git config --global alias.undo "reset HEAD~1 --mixed"
git config --global alias.pushf "push --force-with-lease"
git config --list --global
Iniciar Repositório
# novo repo local
git init
git init meu-projeto && cd meu-projeto
# clonar
git clone https://github.com/user/repo.git
git clone git@github.com:user/repo.git # SSH
git clone https://... meu-nome-local # renomear
git clone --depth=1 https://... # shallow (sem histórico)
Fluxo Básico
# status
git status
git status -s # compacto: M modified, A added, ? untracked
# staging
git add arquivo.txt
git add .
git add -p # interativo — escolher hunks
# commit
git commit -m "feat: adicionar login"
git commit -am "fix" # add tracked + commit (sem untracked)
# histórico
git log --oneline --graph --decorate --all
git log -n 5
git log -- arquivo.txt
git log --author="Alfredo" --since="2 weeks ago"
# diff
git diff # working tree vs staging
git diff --staged # staging vs último commit
git diff main..feature # entre branches
Branches
# listar
git branch # locais
git branch -r # remotas
git branch -a # todas
git branch -v # com último commit
# criar e trocar
git switch -c feature/login # criar + trocar (moderno)
git checkout -b feature/login # equivalente antigo
# renomear / deletar
git branch -m feature/login feature/auth
git branch -d feature/auth # só se mergeada
git branch -D feature/auth # forçar
Merge
git switch main
# fast-forward (padrão quando possível — sem commit extra)
git merge feature/auth
# sempre criar commit de merge
git merge --no-ff feature/auth
# abortar se tiver conflito
git merge --abort
Rebase
# rebase feature em cima de main (move os commits)
git switch feature/auth
git rebase main
# rebase interativo — editar histórico
git rebase -i HEAD~3 # últimos 3 commits
git rebase -i main # todos commits exclusivos da branch
Comandos dentro do editor de rebase interativo:
| Comando | Ação |
|---|---|
| pick | manter commit sem mudança |
| reword | manter, editar mensagem |
| squash | juntar com commit anterior, editar mensagem |
| fixup | juntar com anterior, descartar mensagem |
| drop | remover commit |
| edit | pausar para amend |
git rebase --abort # cancelar
git rebase --continue # continuar após resolver conflito
Remotos
# ver remotos
git remote -v
# adicionar
git remote add origin git@github.com:user/repo.git
git remote add upstream git@github.com:original/repo.git
# remover / renomear
git remote remove origin
git remote rename origin old-origin
# fetch — baixar sem merge
git fetch origin
git fetch --all
# pull
git pull # fetch + merge/rebase
git pull origin main
git pull --rebase origin main
# push
git push -u origin main # define upstream + push
git push # push para upstream configurado
git push --tags # push tags
git push origin --delete feature/auth # deletar branch remota
git push --force-with-lease # force seguro (falha se remoto mudou)
Desfazer Mudanças
# descartar mudanças no working tree (não staged)
git restore arquivo.txt
# tirar do staging (mantém mudanças)
git restore --staged arquivo.txt
# desfazer último commit — manter staging
git reset --soft HEAD~1
# desfazer último commit — manter working tree
git reset --mixed HEAD~1 # (padrão)
# desfazer último commit — DESCARTAR TUDO
git reset --hard HEAD~1
# reverter commit (cria commit inverso — seguro para branches públicas)
git revert abc123
# corrigir último commit
git commit --amend -m "mensagem corrigida"
git add esquecido.txt && git commit --amend --no-edit
# limpar untracked
git clean -n # dry run — mostrar o que seria deletado
git clean -fd # deletar arquivos e diretórios
Stash
Guarda mudanças temporariamente sem commitar. Útil ao trocar de branch com trabalho inacabado.
git stash # guardar working tree + staging
git stash push -m "wip: auth" # com nome descritivo
git stash -u # incluir untracked files
git stash list # listar
git stash show # diff do último
git stash show stash@{1} # diff de stash específico
git stash pop # aplicar e remover último
git stash apply # aplicar sem remover
git stash apply stash@{2} # stash específico
git stash drop # remover último
git stash clear # remover todos
# criar branch a partir de stash
git stash branch feature/nova stash@{0}
Inspecionar Histórico
# buscar texto em commits
git log -S "funcaoXYZ" # commits que adicionaram/removeram
git log -G "regex" # commits cujo diff bate com regex
git log --grep="fix" # mensagens contendo
# conteúdo de arquivo em commit específico
git show abc123:caminho/arquivo.txt
# quem escreveu cada linha
git blame arquivo.txt
git blame -L 10,30 arquivo.txt
# encontrar commit que introduziu um bug
git bisect start
git bisect bad # commit atual tem o bug
git bisect good v1.0.0 # esta tag estava boa
# git testa commits binariamente, para cada:
# git bisect good / git bisect bad
git bisect reset
# ver referências (inclui deletadas — último recurso)
git reflog
git reflog show main
Cherry-pick
Aplica commits específicos de outra branch sem mergear tudo.
git cherry-pick abc123 # um commit
git cherry-pick abc123..def456 # range
git cherry-pick abc123 --no-commit # aplicar sem commitar
git cherry-pick --abort
git cherry-pick --continue
.gitignore
# extensões e arquivos
*.log
*.env
.DS_Store
Thumbs.db
# diretórios
node_modules/
dist/
.next/
build/
# exceção
!important.log
# qualquer nível de profundidade
**/build/
# apenas na raiz
/config.local.js
# ignorar arquivo já rastreado
echo "config.local.js" >> .gitignore
git rm --cached config.local.js
git commit -m "chore: untrack config.local.js"
# diagnóstico
git status --ignored
git check-ignore -v arquivo.txt
github.com/github/gitignore — Node, Python, macOS, etc.Mensagens de Commit — Conventional Commits
():
[corpo — o porquê, não o quê]
[rodapé — BREAKING CHANGE: ..., Closes #123]
git commit -m "feat(auth): add JWT refresh token rotation"
git commit -m "fix(api): handle null user on session expiry"
git commit -m "chore: upgrade vite to 5.4.0"
git commit -m "docs: add docker compose examples to README"
Regras: linha de assunto ≤ 72 chars · verbo imperativo (add, fix, remove) · sem ponto final · corpo separado por linha em branco.
Workflows
Feature Branch (padrão)
Squash antes do PR
# juntar últimos 4 commits em 1 limpo
git rebase -i HEAD~4
# trocar pick → squash em todos exceto o primeiro
# editar mensagem consolidada
git push --force-with-lease
Hotfix
git switch main
git switch -c hotfix/critical-bug
# corrigir e commitar
git switch main
git merge --no-ff hotfix/critical-bug
git tag -a v1.0.1 -m "Hotfix: description"
git branch -d hotfix/critical-bug
git push && git push --tags
Aliases
# ~/.gitconfig
[alias]
st = status
co = checkout
sw = switch
br = branch
lg = log --oneline --graph --decorate --all
ll = log --oneline -20
last = log -1 HEAD
undo = reset HEAD~1 --mixed
unstage = restore --staged
aliases = config --get-regexp alias
pushf = push --force-with-lease
gone = !git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -D
Comandos de Emergência
# recuperar commit deletado (até 90 dias)
git reflog
git switch -c recover-branch abc123
# arquivo deletado antes do commit
git restore arquivo-deletado.txt
# desfazer reset --hard
git reflog
git reset --hard abc123 # SHA antes do reset
# ver as 3 versões num conflito de merge
git show :1:arquivo.txt # ancestral comum
git show :2:arquivo.txt # nossa versão (HEAD)
git show :3:arquivo.txt # versão deles
# force push acidental em branch compartilhada
git reflog show origin/main
git push origin SHA_ANTES:main
GitHub CLI
# autenticar
gh auth login
# PRs
gh pr create --title "feat: login" --body "..."
gh pr list
gh pr view 42
gh pr checkout 42
gh pr merge 42 --squash
gh pr merge 42 --rebase
# Issues
gh issue create --title "Bug: ..."
gh issue list
gh issue close 10
# Repo
gh repo clone user/repo
gh repo fork user/repo --clone
# Actions
gh run list
gh run view 123
gh run watch 123
Referência Rápida
| Situação | Comando |
|---|---|
| Desfazer último commit, manter mudanças | git reset HEAD~1 |
| Descartar mudanças em arquivo | git restore arquivo |
| Tirar arquivo do staging | git restore --staged arquivo |
| Guardar trabalho sem commitar | git stash |
| Buscar commit que quebrou algo | git bisect start |
| Aplicar commit de outra branch | git cherry-pick abc123 |
| Ver quem escreveu linha | git blame arquivo |
| Recuperar algo deletado | git reflog |
| Limpar arquivos não rastreados | git clean -fd |
| Comparar branches | git diff main..feature |
| Force push seguro | git push --force-with-lease |
| Histórico visual | git log --oneline --graph --all |
| Ver conteúdo de arquivo em commit | git show abc123:path/file |
| Ignorar arquivo já rastreado | git rm --cached arquivo |