Tutorial Avanzado de Git

DUGLAS MORENODUGLAS MORENO 👁 2
Abrir en pestaña nueva ↗

Git Avanzado 🧙‍♂️

De duglasm.com

Rebase interactivo · Reflog · Bisect · Worktrees · Hooks · Filter-repo

Empezá presionando space

Agenda

  1. 🌳 Modelo interno: objects & refs
  2. 🎛️ Rebase interactivo quirúrgico
  3. ⏮️ Reflog: la máquina del tiempo
  4. 🍒 Cherry-pick con conflictos
  5. 🐞 Bisect automatizado
  6. 🌿 Worktrees paralelos
  7. 🪝 Hooks locales y de servidor
  8. 🧹 Reescribir historia con filter-repo
  9. 🚀 Tips de productividad

::right::

💡 Regla de oro

Nunca reescribas historia que ya fue pusheada a una rama compartida.
Salvo que sepas exactamente lo que estás haciendo — y avises al equipo.

1. Modelo interno de Git

Git es una base de datos de contenido direccionable. Todo es un objeto SHA-1.

# Ver el tipo de un objeto
git cat-file -t HEAD              # → commit

# Ver el contenido crudo
git cat-file -p HEAD              # → tree, parent, author, message

# Explorar el tree del commit actual
git ls-tree -r HEAD               # → blobs (archivos) con sus hashes

# Ver dónde apunta una ref
cat .git/refs/heads/main          # → SHA del último commit

Los cuatro objetos: blob (contenido) · tree (directorio) · commit (snapshot + metadata) · tag (ref anotada).

2. Rebase interactivo quirúrgico

Reordenar, aplastar, dividir y editar commits antes de mergear.

git rebase -i HEAD~5
pick a1b2c3d feat: agregar endpoint /users
squash e4f5g6h fix: typo en endpoint
reword h7i8j9k feat: paginación         # cambiar solo el mensaje
edit  k0l1m2n feat: filtros             # detenerse para modificar
drop  p3q4r5s wip: debug prints         # descartar completamente
fixup t6u7v8w fix: lint                 # como squash pero descarta mensaje

Dividir un commit (durante un edit):

git reset HEAD^                   # deshacer el commit, mantener cambios
git add -p                        # stagear por hunks
git commit -m "parte 1"
git commit -am "parte 2"
git rebase --continue

3. Reflog: la máquina del tiempo

Git registra cada movimiento de HEAD localmente por 90 días. Nada se pierde.

git reflog                        # historial completo de HEAD

# Recuperar una rama borrada
git reflog | grep "checkout: moving from feature/x"
git branch feature/x-rescatado HEAD@{15}

# Deshacer un rebase catastrófico
git reflog                        # buscar el estado previo
git reset --hard HEAD@{7}

# Reflog de una rama específica
git reflog show feature/pagos

🚨 Ojo: reflog es local. No sirve para recuperar cosas en el remoto.

✅ Antes de operaciones peligrosas: git tag backup-$(date +%s)

4. Cherry-pick con conflictos

Traer commits específicos desde otra rama sin mergear todo.

git cherry-pick abc1234            # un commit

git cherry-pick abc1234^..def5678  # un rango (inclusive)

# Con estrategia de merge y mantener autoría
git cherry-pick -x --strategy=recursive -X theirs abc1234

# Si hay conflicto
git cherry-pick --continue         # después de resolver
git cherry-pick --abort            # cancelar todo

Flag -x: agrega (cherry picked from commit ...) al mensaje. Oro puro para auditoría en hotfixes que van a main y release/*.

# Cherry-pick sin commitear (para revisar antes)
git cherry-pick -n abc1234
git diff --cached

5. Bisect: cazar bugs con búsqueda binaria

Encontrar el commit que rompió algo en log2(n) pasos.

git bisect start
git bisect bad                     # HEAD está roto

git bisect good v1.4.0             # esta versión andaba
# Git checkoutea el commit del medio → probás → marcás

git bisect good                    # o `git bisect bad`
# ... repetir hasta que Git identifica el culpable

git bisect reset                   # volver al estado inicial

Automatizado con un script que retorna 0 (good) o 1 (bad):

git bisect start HEAD v1.4.0
git bisect run npm test -- --grep "checkout flow"

Git corre el comando en cada bisección y te deja parado en el commit exacto. Es magia.

6. Worktrees: múltiples ramas simultáneas

Trabajar en varias branches en paralelo sin stash ni cambio de contexto.

# Crear un worktree nuevo apuntando a otra rama
git worktree add ../proyecto-hotfix hotfix/prod-caido

# Crear worktree con rama nueva
git worktree add -b feature/nuevo ../proyecto-feature main

# Listar todos
git worktree list

# Limpiar cuando terminaste
git worktree remove ../proyecto-hotfix

🎯 Caso de uso real: estás mid-feature, salta un hotfix crítico. En vez de stashear y cambiar de branch, creás un worktree en ../hotfix, resolvés ahí, y volvés al tuyo sin tocar nada. Cada worktree tiene su propio node_modules, cache, etc.

7. Hooks: automatizar todo

Scripts que Git ejecuta en momentos clave del ciclo de vida.

.git/hooks/
├── pre-commit        # antes de crear el commit
├── commit-msg        # validar mensaje (conventional commits)
├── pre-push          # antes de pushear
└── post-merge        # después de un pull
# .git/hooks/pre-commit — bloquear commits con TODO/FIXME
#!/usr/bin/env bash

if git diff --cached | grep -E "^\+.*\b(TODO|FIXME|console\.log)\b"; then
  echo "❌ Encontré TODO/FIXME/console.log en el staging"
  echo "   Usá 'git commit --no-verify' si es intencional"
  exit 1
fi

Compartir hooks con el equipo: husky, lefthook, o core.hooksPath:

git config core.hooksPath .githooks   # commiteás la carpeta al repo

8. Reescribir historia con git filter-repo

filter-branch está deprecado. La herramienta moderna es git-filter-repo.

# Borrar un archivo con secretos de TODA la historia
git filter-repo --path .env --invert-paths

# Reemplazar un email en todos los commits
git filter-repo --email-callback '
  return email.replace(b"viejo@empresa.com", b"nuevo@empresa.com")'

# Extraer un subdirectorio como repo independiente
git filter-repo --subdirectory-filter packages/ui

# Cambiar mensajes de commit masivamente
git filter-repo --message-callback '
  return message.replace(b"WIP:", b"chore:")'

⚠️ Después de reescribir historia compartida: todos deben re-clonar. Coordiná con el equipo.

9. Tips de productividad

# Aliases que cambian la vida
git config --global alias.lg \
  "log --graph --oneline --all --decorate"

git config --global alias.undo "reset HEAD~1 --mixed"
git config --global alias.amend "commit --amend --no-edit"
git config --global alias.wip "!git add -A && git commit -m 'wip'"

# Autocorrección
git config --global help.autocorrect 20

# Rebase por default en pull
git config --global pull.rebase true

# Recordar resolución de conflictos
git config --global rerere.enabled true

::right::

Flags que valen oro:

  • git log -S "texto"pickaxe: commits que agregaron/quitaron ese string
  • git log -L :funcion:archivo.py → historia de una función
  • git blame -w -C -C → ignorar whitespace y detectar copy-paste
  • git switch -c → alternativa moderna a checkout -b
  • git restore --staged → unstage sin reset
  • git maintenance start → GC automático en background

¡Gracias! 🚀

Ahora sos un git wizard

🌳
🎛️
⏮️
🍒
🐞
🌿
🪝
🧹
Preguntas · Debate · Café ☕

Comentarios (0)

Sé el primero en comentar.

Dejá tu comentario