Git
Git es la base del software moderno. En 2025, funcionalidades como Sparse Checkout y Scalar (para monorepos) se están volviendo comunes.
Cuándo Usarlo
- Ramas y Colaboración: Gestión de aislamiento de funcionalidades, pull requests, desarrollo trunk-based y revisiones de código en equipos distribuidos.
- Reescritura y Limpieza del Historial: Linealización de grafos de commits, squash de commits de trabajo en progreso y edición de mensajes mediante
git rebase -iantes de fusionar en las ramas principales. - Búsqueda Automatizada de Errores: Aislamiento de commits que introducen regresiones a lo largo de miles de revisiones mediante búsqueda binaria con
git bisect. - Contextos de Trabajo Concurrentes: Trabajar en parches urgentes sin necesidad de stashing o cambio de contexto de rama usando
git worktree. - Escalado de Repositorios Grandes: Optimización del rendimiento en monorepos enormes usando Git Sparse Checkout, Scalar y clones superficiales.
Inicio Rápido
# Clonar repositorio y crear una nueva rama de funcionalidad
git clone https://github.com/myorg/project.git
cd project
# Crear y cambiar a nueva rama usando el comando moderno
git switch -c feature/auth-flow
# Añadir, confirmar y enviar con seguimiento remoto
git add .
git commit -m "feat(auth): implement oauth2 authorization code flow"
git push -u origin feature/auth-flow
Conceptos Clave
La Arquitectura de 3 Árboles (Árbol de Trabajo, Índice, HEAD)
Git gestiona los archivos a través de tres estados distintos en lugar de simplemente rastrear cambios entre revisiones:
# 1. Árbol de Trabajo: Archivos modificados no confirmados en su editor
echo "export const API_URL = 'https://api.v2.internal';" >> config.ts
# 2. Índice (Área de Preparación): Contenido listo para la próxima confirmación
git add config.ts
# 3. HEAD: La última instantánea confirmada en la rama activa
git diff --staged # Inspeccionar diferencia entre el Área de Preparación y HEAD
git commit -m "chore(config): update internal API endpoint"
Grafo Acíclico Dirigido (DAG) y Objetos Inmutables
Cada commit en Git es un nodo inmutable que apunta a hashes de padres y a un árbol raíz de instantáneas blob.
# Inspeccionar el objeto sin procesar detrás de cualquier hash de commit o HEAD
git cat-file -p HEAD
# Salida:
# tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
# parent 8f3d1e1c3a628a58a98b47cf7d12a9e32049e712
# author Alice <[email protected]> 1727420400 +0000
# committer Alice <[email protected]> 1727420400 +0000
#
# feat(auth): implement oauth2 authorization code flow
Navegación Moderna de Ramas (git switch vs git restore)
Git moderno desambigua el sobrecargado comando git checkout en operaciones dedicadas:
# Cambio de Rama (reemplaza git checkout <rama>)
git switch main
git switch -c feature/payments # Crear y cambiar
# Restauración de Archivos (reemplaza git checkout -- <archivo>)
git restore src/app.ts # Descartar cambios no confirmados del directorio de trabajo
git restore --staged src/app.ts # Quitar archivo del índice y devolverlo al árbol de trabajo
Estrategias Rebase vs Merge
- Merge (
git merge <rama>): Preserva el contexto histórico completo con un commit de fusión de dos padres. Ideal para integrar ramas de lanzamiento de larga duración. - Rebase (
git rebase <upstream>): Replica los commits de una rama temática linealmente sobre la cabecera de upstream, evitando grafos enredados tipo "vía de ferrocarril". Ideal para limpiar ramas de funcionalidad antes de la revisión de PR.
# Rebase limpio de la rama de funcionalidad sobre la última main
git switch feature/auth-flow
git fetch origin main
git rebase origin/main
Patrones Comunes
Desarrollo Multirrama con Git Worktrees
Problema: Guardar trabajo no confirmado para cambiar de rama y corregir un error urgente de producción.
Solución: Extrae múltiples ramas en directorios separados simultáneamente:
# Crear carpeta de worktree paralela para la rama de parche
git worktree add ../hotfix-branch main
# Trabajar en el parche en un directorio separado sin tocar el espacio de trabajo actual
cd ../hotfix-branch
git commit -am "fix: patch critical auth vulnerability"
git push origin hotfix-branch
# Limpiar el worktree al terminar
cd ../project
git worktree remove ../hotfix-branch
Rebase Interactivo para un Historial de PR Limpio
Problema: La rama de funcionalidad contiene docenas de commits desordenados como "WIP", "fix typo" o "checkpoint".
Solución: Comprime y limpia el historial de forma interactiva antes de abrir un pull request.
# Rebase interactivo de los últimos 4 commits
git rebase -i HEAD~4
# En el editor interactivo:
# pick 8f3d1e1 feat(auth): add token generation
# squash 4b825dc fix typo in token payload
# squash a1c94e2 add missing import
# reword 91f7a02 feat(auth): add refresh token endpoint
Búsqueda Automatizada de Regresiones con Git Bisect
Problema: Se introdujo un error en algún lugar a lo largo de 500 commits, pero se desconoce el commit exacto.
Solución: Realiza una búsqueda binaria con un script de ejecución de pruebas automatizado.
# Iniciar sesión de bisect
git bisect start
git bisect bad HEAD # HEAD actual está roto
git bisect good v2.1.0 # v2.1.0 funcionaba correctamente
# Ejecutar automáticamente el script de pruebas en cada paso de bisect
git bisect run npm test -- --runInBand
# Git termina en el primer commit exacto que rompió la suite de pruebas
git bisect reset
Mejores Prácticas (2026)
Hacer:
- Usar
git switchygit restore: Evitar el sobrecargadogit checkoutpara prevenir cambios accidentales de rama o sobrescritura de archivos. - Hacer push con
--force-with-lease: Protegerse contra la sobrescritura de commits de colegas en ramas remotas. - Activar Mantenimiento en Segundo Plano: Ejecutar
git maintenance startpara optimizar packfiles, grafos de commits y rendimiento de fetch. - Firmar Commits con SSH / GPG: Garantizar la autenticidad de la autoría de los commits en pipelines de producción.
- Escribir Commits Convencionales: Usar prefijos estandarizados (
feat:,fix:,chore:,refactor:) para automatizar el versionado semántico y los changelogs.
No hacer:
- No hacer push forzado a ramas protegidas: Nunca reescribir el historial en
main,mastero ramas de lanzamiento compartidas. - No confirmar secretos o credenciales: Usar
.gitignorey git-secrets/trufflehog; una vez confirmados, las credenciales persisten en los blobs de packfile incluso si se eliminan después. - No usar archivos binarios grandes directamente: Almacenar pesos de modelos grandes o medios en Git LFS (Large File Storage) o S3.
- No fusionar árboles de trabajo sucios: Guardar (stash) o confirmar cambios antes de hacer pull o rebase para evitar conflictos de archivos accidentales.
Solución de Problemas
| Error | Causa | Solución |
|---|---|---|
fatal: refusing to merge unrelated histories | Hacer pull desde un repositorio inicializado de forma independiente sin commit raíz compartido. | Ejecutar git pull origin main --allow-unrelated-histories. |
HEAD detached at ... | Se extrajo un hash de commit específico en lugar de un nombre de rama. | Crear rama desde la posición actual: git switch -c recovery-branch. |
Merge conflict in file.txt | Commits concurrentes modificaron líneas idénticas en ramas opuestas. | Resolver marcadores de conflicto (<<<<<<<), preparar archivo (git add) y ejecutar git commit. |