Obtener el proyecto
Crea tu copia local con archivos, ramas e historial.
git clone URLAprende qué operaciones existen, cuándo se utilizan y en qué orden aparecen durante el desarrollo de un proyecto real con varios programadores.
Antes de escribir un comando, pregúntate qué operación necesitas realizar.
Crea tu copia local con archivos, ramas e historial.
git clone URLConsulta el estado del servidor sin fusionar cambios todavía.
git fetch --pruneComprende qué cambió, quién lo hizo y dónde estás.
git log --oneline --graphgit show HASHInspecciona cambios locales antes de preparar un commit.
git diffgit diff --stagedCrea una rama por tarea para aislar modificaciones.
git switch -c feature/perfilPrepara una unidad lógica y crea un commit descriptivo.
git add archivogit commit -m "mensaje"Integra trabajo revisado y resuelve conflictos si aparecen.
git merge nombre-ramagit merge --abortRevierte un cambio compartido sin reescribir el historial.
git revert HASHEste ciclo se repite para cada tarea que entra al equipo.
La persona se incorpora al proyecto y obtiene una copia local completa. origin queda configurado como remoto principal.
$ git clone https://github.com/equipo/plataforma.git $ cd plataforma $ git remote -v
Antes de crear una tarea, consulta lo que publicó el resto del equipo. fetch descarga referencias y pull integra los cambios de la rama actual.
$ git switch main $ git fetch --prune $ git pull --ff-only
Crea una rama descriptiva desde una base actualizada. Así varias personas pueden avanzar sin alterar main.
$ git switch -c feature/perfil-usuario
Inspecciona diferencias, prepara solo los archivos relacionados y crea commits que narren el avance.
$ git status $ git diff $ git add src/perfil.js $ git commit -m "Añade formulario de perfil"
Trae las referencias recientes. Según la convención del equipo, fusiona main o reaplica tus commits con rebase.
$ git fetch origin
$ git merge origin/main
# o, si el equipo lo acordó:
$ git rebase origin/mainEl equipo revisa la propuesta antes de integrarla. Las correcciones solicitadas se añaden como commits nuevos.
$ git push -u origin feature/perfil-usuario
El pull request aprobado se fusiona en main. Si aparece un conflicto, conserva el contenido correcto, prepara el archivo y confirma la resolución.
$ git merge feature/perfil-usuario
# si existe un conflicto:
$ git add archivo-resuelto
$ git commitSi un cambio publicado causa un problema, crea un commit inverso. Así el equipo mantiene una auditoría clara.
$ git log --oneline $ git revert HASH $ git push origin main
Cada desarrollador mantiene su copia local y sus ramas. El repositorio remoto funciona como punto de encuentro y main representa la versión integrada.
Sigue la secuencia como si trabajaras en la terminal de un equipo real.
Te incorporas al equipo de una tienda en línea. Tu tarea es añadir una página de favoritos sin alterar el trabajo del resto del equipo.
Trabajas en el equipo web de una tienda en línea. El repositorio central vive en GitHub y la rama main siempre debe conservar una versión desplegable. Ana acaba de publicar ajustes del catálogo mientras tú recibes una tarea nueva: añadir la página de favoritos y el botón que permite guardar productos.
No debes editar directamente main. Crearás una rama aislada, revisarás cada diferencia antes de confirmarla, integrarás los cambios recientes del equipo y publicarás tu propuesta para revisión mediante pull request.
Como trabajas desde un equipo nuevo, necesitas una copia local completa. git clone descarga los archivos, el historial de commits y las referencias de ramas. Además, configura automáticamente origin como alias del repositorio compartido. Después entras en la carpeta y verificas que las direcciones de lectura y publicación sean correctas.
$ git clone https://github.com/equipo/tienda-web.git Cloning into 'tienda-web'... $ cd tienda-web $ git remote -v origin https://github.com/equipo/tienda-web.git (fetch) origin https://github.com/equipo/tienda-web.git (push)
Antes de modificar archivos, confirma que estás en main y que no existen cambios locales accidentales. git fetch --prune actualiza tu visión del servidor y elimina referencias obsoletas sin tocar tu directorio de trabajo. Después, git pull --ff-only adelanta tu rama local únicamente si puede hacerlo sin crear una fusión inesperada.
$ git status On branch main nothing to commit, working tree clean $ git fetch --prune From github.com:equipo/tienda-web a02d91f..be8923d main -> origin/main $ git pull --ff-only Updating a02d91f..be8923d Fast-forward
Crea una rama desde el main actualizado. El prefijo feature/ comunica que estás desarrollando una capacidad nueva y el nombre favoritos identifica la tarea. Desde este momento puedes crear commits sin alterar la versión estable que usa el resto del equipo.
$ git switch -c feature/favoritos
Switched to a new branch 'feature/favoritos'Después de programar, no confirmes cambios a ciegas. git status --short ofrece un inventario compacto: M indica un archivo modificado y ?? uno nuevo sin seguimiento. git diff muestra las líneas exactas que todavía no preparaste. Esta revisión evita incluir archivos temporales, trazas de depuración o credenciales por error.
$ git status --short M src/pages/Favoritos.js ?? src/components/BotonFavorito.js $ git diff + export function BotonFavorito({ productoId }) { + return <button>Guardar favorito</button> + }
Selecciona únicamente los archivos de la funcionalidad con git add. El área de preparación funciona como una cesta: decide qué formará parte del próximo commit. Revisa esa cesta con git diff --staged y crea un mensaje que explique la intención del cambio, no solo los archivos modificados.
$ git add src/pages/Favoritos.js src/components/BotonFavorito.js $ git diff --staged # muestra exactamente lo que formará parte del commit $ git commit -m "Añade gestión básica de favoritos" [feature/favoritos 3f821a7] Añade gestión básica de favoritos 2 files changed, 48 insertions(+)
Mientras desarrollabas, otras personas pudieron integrar cambios. Descarga las referencias recientes con git fetch origin e integra origin/main dentro de tu rama. Resolver incompatibilidades aquí reduce sorpresas durante la revisión y comprueba que tu trabajo convive con la versión más reciente del equipo.
$ git fetch origin
$ git merge origin/main
Merge made by the 'ort' strategy.
$ git log --oneline --graph --decorate -5Envía la rama al remoto para que el equipo pueda verla. La opción -u establece la relación de seguimiento entre la rama local y la remota; en futuras actualizaciones bastará con ejecutar git push. El pull request será el espacio de revisión, conversación y validación automática antes de integrar en main.
$ git push -u origin feature/favoritos
branch 'feature/favoritos' set up to track
'origin/feature/favoritos'.Dos personas modificaron el mismo componente. Después de integrar la solución, una regresión llega a producción y debes revertirla de forma trazable.
Trabajas en feature/login-social para añadir acceso con un proveedor externo. Al mismo tiempo, Julia corrigió el comportamiento responsive del encabezado y su pull request ya llegó a main. Ambas tareas modifican src/components/Header.js, por lo que Git no puede decidir automáticamente qué versión conservar.
Después de resolver el conflicto y publicar la integración, las métricas de producción muestran que el login falla en móviles. Debes estabilizar el sistema sin borrar la historia compartida y conservar una vía de recuperación por si necesitas inspeccionar el estado anterior.
Tu ajuste responsive todavía no forma una unidad lista para commit, pero necesitas actualizar main. git stash push guarda temporalmente los cambios del directorio de trabajo y deja la rama limpia. El mensaje descriptivo permite reconocer el trabajo guardado si acumulas varios stashes.
$ git status --short M src/components/Header.js $ git stash push -m "WIP ajuste responsive del header" Saved working directory and index state $ git switch main
Ya con el directorio limpio, actualiza main mediante un avance lineal. Regresa a tu rama y usa git stash pop: aplica el cambio guardado y elimina esa entrada del stash si la aplicación funciona. Comprueba el resultado antes de continuar.
$ git pull --ff-only
$ git switch feature/login-social
$ git stash pop
On branch feature/login-social
Changes not staged for commit:
modified: src/components/Header.jsFusiona la rama principal actualizada dentro de tu rama de funcionalidad. Git combina automáticamente los archivos compatibles, pero se detiene en Header.js porque ambas líneas de desarrollo editaron la misma zona. git status identifica los archivos que requieren una decisión humana.
$ git merge main Auto-merging src/components/Header.js CONFLICT (content): Merge conflict in src/components/Header.js Automatic merge failed; fix conflicts and then commit the result. $ git status both modified: src/components/Header.js
Abre el archivo y busca las marcas de conflicto. HEAD representa tu rama actual; la sección inferior proviene de main. Conserva una versión que combine el login social con el diseño compacto, elimina las marcas y ejecuta las pruebas. Solo después prepara el archivo y confirma la resolución.
<<<<<<< HEAD
<Header socialLogin />
=======
<Header compact />
>>>>>>> main
$ npm test
$ git add src/components/Header.js
$ git commit -m "Resuelve conflicto del encabezado"Publica la rama con el merge resuelto. El pull request permite revisar tanto la funcionalidad como la decisión tomada durante el conflicto. Cuando las pruebas y la revisión terminan, la propuesta se integra en main y el despliegue automatizado la lleva a producción.
$ git push -u origin feature/login-social
# pull request revisado y fusionado en mainTras desplegar, el monitoreo detecta errores de autenticación en móviles. Primero actualiza main y localiza el merge problemático en el historial. git revert crea un commit nuevo que invierte el cambio publicado: la historia permanece intacta y el equipo puede auditar qué ocurrió y por qué se deshizo.
$ git switch main $ git pull --ff-only $ git log --oneline -5 98fd421 Merge pull request #184 from feature/login-social 751e20a Resuelve conflicto del encabezado $ git revert 98fd421 [main 61fa011] Revert "Merge pull request #184..." $ git push origin main
Imagina que necesitas inspeccionar la resolución anterior o que una rama local fue eliminada por accidente. git reflog registra movimientos recientes de HEAD en tu equipo, incluso cuando un commit ya no aparece en el historial visible. Crea una rama de recuperación desde el hash elegido para investigar sin alterar main.
$ git reflog
61fa011 HEAD@{0}: revert: Revert "Merge pull request #184"
98fd421 HEAD@{1}: pull --ff-only: Fast-forward
751e20a HEAD@{2}: commit: Resuelve conflicto del encabezado
$ git switch -c recovery/header 751e20aDos ramas instalaron librerías diferentes. El archivo generado entra en conflicto y editarlo manualmente puede dejar una instalación aparentemente válida pero inconsistente.
Tu rama feature/reportes añadió chart.js para visualizar ventas. Mientras trabajabas, main incorporó date-fns para procesar fechas. Ambas instalaciones modificaron package.json y package-lock.json.
El lockfile describe el árbol exacto de dependencias. Resolver sus cientos de líneas a mano puede conservar hashes o versiones incompatibles sin que el error sea evidente durante la revisión.
package-lock.json.Descarga el estado reciente del servidor e integra origin/main en tu rama. Hacerlo antes de publicar permite resolver el conflicto localmente y probar la combinación real que llegará a revisión.
$ git switch feature/reportes
$ git fetch origin
$ git merge origin/main
CONFLICT (content): Merge conflict in package.json
CONFLICT (content): Merge conflict in package-lock.jsongit status enumera los archivos no fusionados. git diff --name-only --diff-filter=U reduce la salida exclusivamente a rutas con conflicto para evitar olvidar alguna.
$ git status
$ git diff --name-only --diff-filter=U
package-lock.json
package.jsonEdita package.json y conserva ambas dependencias. Después acepta temporalmente una versión del lockfile y regénéralo con el gestor de paquetes. npm install --package-lock-only reconstruye el árbol a partir del manifiesto resuelto.
# package.json conserva chart.js y date-fns
$ git checkout --ours package-lock.json
$ npm install --package-lock-only
$ npm ci
$ npm testPrepara ambos archivos y verifica que Git ya no reporte rutas sin fusionar. El commit explica que resolviste el conflicto de dependencias.
$ git add package.json package-lock.json $ git status $ git commit -m "Integra dependencias de reportes y fechas"
Evita git add . antes de revisar el lockfile: podrías confirmar marcas de conflicto o archivos generados no deseados. Evita editar manualmente cada bloque de package-lock.json y no ejecutes git reset --hard: perderías trabajo local sin resolver la causa.
Una rama reorganizó carpetas mientras otra corrigió lógica dentro del archivo original. Git necesita ayuda para determinar dónde debe vivir la versión final.
Tu rama fix/calculo-impuestos corrigió una fórmula en src/utils/precios.js. Paralelamente, main reorganizó utilidades y trasladó ese archivo a src/domain/precios.js.
Si eliges una versión completa sin inspeccionar el cambio, puedes recuperar la fórmula antigua o perder el nuevo diseño de carpetas. La solución correcta conserva la ubicación nueva y reaplica la corrección funcional.
src/domain con la fórmula corregida.Después de traer referencias recientes, fusiona origin/main. Git informa un conflicto de modificación frente a renombrado: tu rama modificó la ruta antigua y main movió el archivo.
$ git fetch origin
$ git merge origin/main
CONFLICT (modify/delete): src/utils/precios.js deleted in origin/main
and modified in HEAD.git status muestra la situación general. git show permite leer cada versión sin modificar archivos: HEAD contiene tu corrección y origin/main la estructura nueva.
$ git status $ git show HEAD:src/utils/precios.js $ git show origin/main:src/domain/precios.js
Edita src/domain/precios.js e incorpora únicamente la fórmula corregida. Después elimina la ruta antigua con git rm. Este comando registra explícitamente que el archivo anterior ya no debe existir.
# edita src/domain/precios.js y aplica la fórmula correcta
$ git rm src/utils/precios.js
$ git add src/domain/precios.js
$ npm testgit diff --staged --name-status muestra el resultado preparado. Debes ver la eliminación de la ruta antigua y la modificación de la nueva antes de crear el commit.
$ git diff --staged --name-status
M src/domain/precios.js
D src/utils/precios.js
$ git commit -m "Conserva corrección fiscal tras reorganizar precios"Evita git checkout --ours . o git checkout --theirs . sobre todo el repositorio: una de esas órdenes puede descartar silenciosamente la refactorización o tu corrección. Evita recrear la ruta antigua; generaría dos fuentes de verdad difíciles de mantener.
Producción falla mientras tienes cambios locales a medio terminar. Debes aislar la corrección, publicarla con rapidez y volver a tu tarea sin contaminar ninguna rama.
Estás desarrollando feature/nuevo-checkout con varios archivos modificados. El monitoreo reporta que los cupones aplican el descuento dos veces en producción. La corrección debe salir desde la versión desplegada, no desde tu funcionalidad incompleta.
Mezclar ambos trabajos aumentaría el alcance del despliegue urgente y podría introducir fallos no relacionados. La estrategia correcta guarda el trabajo temporalmente, crea una rama de hotfix desde origin/main y publica un cambio mínimo.
Comprueba qué cambió y guarda archivos rastreados y nuevos con git stash push -u. La opción -u incluye archivos todavía no seguidos por Git, algo frecuente durante una funcionalidad en desarrollo.
$ git status --short
$ git stash push -u -m "WIP nuevo checkout antes de hotfix"
$ git status
nothing to commit, working tree cleanActualiza referencias remotas y crea una rama directamente desde origin/main. Así la corrección parte de la misma base que producción y no arrastra commits de tu funcionalidad.
$ git fetch origin
$ git switch -c hotfix/cupon-duplicado origin/main
Switched to a new branch 'hotfix/cupon-duplicado'Modifica solo la lógica del cupón, ejecuta pruebas específicas y revisa la diferencia. Preparar la ruta explícita evita incluir archivos accidentales.
$ npm test -- cupones $ git diff $ git add src/domain/cupones.js $ git commit -m "Evita aplicar dos veces el descuento del cupón" $ git show --stat --oneline HEAD
Envía la rama para revisión urgente. Después de integrar y desplegar el hotfix, vuelve a la rama original y recupera tu trabajo temporal. git stash pop aplica los cambios y elimina el stash solo si puede hacerlo correctamente.
$ git push -u origin hotfix/cupon-duplicado
# pull request aprobado, fusionado y desplegado
$ git switch feature/nuevo-checkout
$ git stash list
$ git stash popEvita confirmar el hotfix dentro de feature/nuevo-checkout y evita git push --force sobre main. Tampoco uses git reset --hard para limpiar rápidamente tu directorio: destruiría el trabajo local que intentas proteger.
La empresa ficticia NovaCode exige que todo cambio esté asociado a un ticket, pase por revisión y llegue a main exclusivamente mediante pull request.
main y release/* están protegidas: nadie publica directamente.fix/NC-1842-validacion-email.Soporte reporta que el registro permite correos sin dominio. Debes corregir la validación sin saltarte el proceso de auditoría. Aunque el cambio es pequeño, publicarlo directamente en main rompería la trazabilidad exigida por la empresa.
Descarga referencias y adelanta tu copia local sin generar merges accidentales. La política exige comenzar desde la última versión aprobada.
$ git switch main $ git fetch --prune origin $ git pull --ff-only
El nombre incorpora tipo, ticket y propósito. Así herramientas de CI y auditoría pueden relacionar automáticamente código, tarea y revisión.
$ git switch -c fix/NC-1842-validacion-email
Ejecuta las pruebas de la validación, inspecciona la diferencia y crea un commit con el ticket al inicio.
$ npm test -- registro $ git diff $ git add src/domain/validarEmail.js $ git commit -m "NC-1842 Corrige validación de dominio en email" $ git push -u origin fix/NC-1842-validacion-email
No uses git push origin main ni git push --force. El pull request, las dos aprobaciones y el CI no son burocracia decorativa: permiten detectar regresiones y demostrar quién autorizó el cambio.
NovaCode desarrolla software para clientes regulados. Cada commit que llega a una rama de entrega debe estar firmado criptográficamente.
Necesitas incorporar una librería para exportar reportes CSV. La dependencia debe quedar reproducible, pasar el escaneo de vulnerabilidades y llevar una firma verificable antes de solicitar revisión.
Antes de trabajar, consulta la identidad local y la clave de firma. La opción commit.gpgsign true evita olvidar la firma en commits posteriores.
$ git config user.email $ git config user.signingkey $ git config commit.gpgsign true
Usa el gestor de paquetes para actualizar manifiesto y lockfile. Después ejecuta el escaneo y las pruebas antes de preparar cambios.
$ npm install csv-stringify $ npm audit --audit-level=high $ npm test $ git diff -- package.json package-lock.json
-S firma explícitamente el commit. git log --show-signature permite verificar localmente que la firma acompaña al cambio.
$ git add package.json package-lock.json $ git commit -S -m "NC-1910 Añade exportación segura de reportes CSV" $ git log --show-signature -1 $ git push -u origin feature/NC-1910-exportar-csv
No uses git add . sin inspeccionar git status. Podrías incluir un archivo .env, un token o una configuración local. Tampoco desactives la firma para resolver deprisa un error de configuración.
Dos ramas crearon migraciones con el mismo número secuencial. Elegir una y borrar la otra rompería el despliegue de una funcionalidad.
Tu rama añade 042_add_invoice_status.sql; otra tarea ya fusionada añadió 042_add_customer_segment.sql. Ambas son válidas, pero el sistema de migraciones requiere identificadores únicos y ordenados.
043 y validar subida y reversión.Trae el estado aprobado y fusiona. Después lista las migraciones para comprender el orden real antes de renombrar archivos.
$ git fetch origin
$ git merge origin/main
$ ls db/migrations
042_add_customer_segment.sql
042_add_invoice_status.sqlgit mv registra el traslado de forma explícita y conserva la trazabilidad. No modifiques la migración de clientes porque ya forma parte de main.
$ git mv db/migrations/042_add_invoice_status.sql db/migrations/043_add_invoice_status.sql
Aplica las migraciones sobre una base temporal, ejecuta pruebas y comprueba la reversión. Una migración que solo funciona hacia adelante deja al equipo sin recuperación durante un despliegue fallido.
$ npm run db:test:create $ npm run db:migrate $ npm test -- database $ npm run db:rollback $ git add db/migrations $ git commit -m "NC-1974 Reordena migración de estado de factura"
No edites ni borres 042_add_customer_segment.sql. Tampoco uses git checkout --ours .: descartaría silenciosamente la migración integrada y el problema reaparecería al desplegar.
Una corrección crítica debe llegar a producción y también permanecer en la siguiente versión sin mezclar funcionalidades todavía no aprobadas.
release/2.4 solo acepta correcciones aprobadas.main.cherry-pick del commit aprobado.La versión 2.4 desplegada calcula mal un impuesto regional. main ya contiene funcionalidades para 2.5 que no pueden llegar a producción. Debes corregir release/2.4 y propagar exactamente el mismo commit a main.
Partir de origin/release/2.4 garantiza que no incluirás trabajo futuro. El nombre de rama comunica versión, ticket y propósito.
$ git fetch origin $ git switch -c hotfix/NC-2041-impuesto origin/release/2.4
Ejecuta pruebas específicas y prepara solo el archivo fiscal. Guarda el hash porque será la unidad exacta que propagarás.
$ npm test -- impuestos
$ git add src/domain/impuestos.js
$ git commit -m "NC-2041 Corrige impuesto regional en release 2.4"
$ git log --oneline -1
c712ab9 NC-2041 Corrige impuesto regional en release 2.4
$ git push -u origin hotfix/NC-2041-impuestoTras fusionar el pull request de release, crea una rama desde origin/main y aplica solo el hash aprobado con git cherry-pick. Si aparece conflicto, resuélvelo y continúa con git cherry-pick --continue.
$ git switch -c backport/NC-2041-main origin/main $ git cherry-pick c712ab9 $ npm test -- impuestos $ git push -u origin backport/NC-2041-main
No uses git merge main sobre release/2.4: arrastraría funcionalidades de 2.5 aún no aprobadas. No copies archivos manualmente; perderías la relación trazable con el commit corregido.
Dos equipos modificaron la autorización de descuentos. La empresa exige documentar la decisión funcional y conservar evidencia de pruebas.
--ours o --theirs.El equipo comercial permitió descuentos de hasta 20% para clientes premium. En paralelo, el equipo antifraude añadió una revisión manual para cualquier descuento superior a 15%. Ambas reglas son válidas y deben convivir.
Integra origin/main y lista solo las rutas no resueltas. Esto evita distraerte con cambios compatibles que Git ya fusionó correctamente.
$ git fetch origin
$ git merge origin/main
$ git diff --name-only --diff-filter=U
src/domain/descuentos.js
test/descuentos.test.jsLee las dos variantes sin sobrescribir archivos. :2: representa tu lado del merge y :3: el lado entrante. Esta comparación ayuda a diseñar una tercera solución que preserve ambas reglas.
$ git show :2:src/domain/descuentos.js $ git show :3:src/domain/descuentos.js
Tras confirmar la regla con el responsable funcional, edita la solución combinada y prueba valores alrededor de los límites: 15%, 16% y 20%.
# edita descuentos.js y descuentos.test.js $ npm test -- descuentos ✓ premium permite descuento de 15% ✓ premium requiere revisión manual con 16% ✓ premium permite hasta 20% $ git add src/domain/descuentos.js test/descuentos.test.js
Confirma con un mensaje que explique la política resultante. El historial debe permitir entender la decisión meses después sin reconstruir toda la conversación.
$ git commit -m "NC-2118 Combina límite premium con revisión antifraude" $ git push -u origin feature/NC-2118-descuentos
No ejecutes git checkout --ours . ni git checkout --theirs .. Ambas alternativas eliminan una regla válida sin producir un error técnico inmediato: el fallo sería funcional, silencioso y difícil de detectar sin pruebas de borde.
Un token de acceso llegó al repositorio remoto. Eliminar el archivo en un commit nuevo no basta: la credencial permanece visible en el historial.
Durante una revisión detectas que config/payment.env contiene un token del proveedor de pagos. El archivo fue incluido en un commit de la rama remota feature/checkout. Aunque todavía no llegó a main, cualquier persona con acceso al repositorio puede leerlo.
La primera acción ocurre fuera de Git: revoca el token desde el gestor seguro del proveedor y genera uno nuevo. Git no puede invalidar una credencial filtrada. Registra el incidente según el procedimiento interno.
Elimina el archivo del índice con git rm --cached, pero conserva tu copia local. Añádelo a .gitignore y sustituye el valor por una referencia documentada a la variable segura.
$ git switch feature/checkout $ git rm --cached config/payment.env $ echo "config/payment.env" >> .gitignore $ git add .gitignore config/payment.env.example $ git commit -m "NC-SEC-331 Retira credencial y documenta variable segura"
Busca el archivo y posibles variantes dentro del historial. La limpieza histórica debe realizarse con el equipo avisado porque cambia hashes y obliga a recrear ramas afectadas.
$ git log --all -- config/payment.env
$ git grep -n "PAYMENT_TOKEN" $(git rev-list --all)
# seguridad coordina la limpieza con git filter-repoTras el procedimiento coordinado, confirma que el archivo no aparece en el historial remoto y que el escáner de secretos aprueba la rama antes de reabrir publicaciones.
$ git fetch --all --prune
$ git log --all -- config/payment.env
$ npm run security:secrets
✓ No exposed credentials foundNo basta con ejecutar git rm y continuar: el token seguiría en commits anteriores. Tampoco uses git push --force --all sin coordinación; podrías destruir trabajo remoto y dejar clones inconsistentes. Nunca pegues el token nuevo en otro archivo versionado.
Una versión desplegada incrementa los errores HTTP 500. La prioridad es restaurar el servicio conservando evidencia suficiente para investigar.
El despliegue de release/3.8.0 termina correctamente, pero la tasa de error sube del 0.2% al 18%. El historial muestra que el pull request #742 modificó el adaptador de pagos. No hay tiempo para diseñar una solución nueva durante la degradación.
Trabaja desde una copia limpia y actualizada. git log --first-parent simplifica el historial de main mostrando integraciones principales.
$ git switch main
$ git pull --ff-only
$ git log --first-parent --oneline -10
4e91bc2 Merge pull request #742 from feature/payment-adapterAunque el incidente sea urgente, la rama protegida conserva el mismo proceso. git revert -m 1 revierte un merge manteniendo como base el primer padre, que corresponde a main antes de integrar el PR.
$ git switch -c revert/NC-INC-508-payment-adapter
$ git revert -m 1 4e91bc2
[revert/NC-INC-508-payment-adapter 91ad801] Revert "Merge pull request #742..."Comprueba el flujo crítico de pagos y publica la rama para un pull request de emergencia. El equipo puede revisar exactamente qué se revierte.
$ npm test -- payments $ git show --stat HEAD $ git push -u origin revert/NC-INC-508-payment-adapter
Después de estabilizar producción, crea una rama desde el commit defectuoso para investigar sin reintroducirlo en main.
$ git switch -c investigation/NC-INC-508 4e91bc2 $ git show --name-status 4e91bc2
No uses git reset --hard HEAD~1 ni force push sobre main. Borrarías evidencia, romperías clones del equipo y dificultarías saber qué versión estuvo desplegada. Tampoco intentes una refactorización extensa mientras producción sigue degradada.
Un rebase mal resuelto parece haber eliminado dos días de trabajo. La recuperación debe preservar la rama remota y crear una copia verificable antes de continuar.
--force-with-lease cuando la reescritura autorizada sea imprescindible.En feature/NC-2250-panel ejecutaste un rebase para incorporar origin/main. Durante la resolución elegiste una versión incorrecta y luego abortaste tarde. Dos commits ya no aparecen en git log, pero todavía pueden estar registrados en el reflog local.
No ejecutes nuevos reset, rebase o limpieza. Consulta el estado para saber si Git todavía considera activo el rebase. Si continúa activo, cancélalo de forma explícita.
$ git status
rebase in progress
$ git rebase --abortgit reflog registra movimientos locales de HEAD. Identifica la referencia anterior al inicio del rebase y crea inmediatamente una rama de respaldo.
$ git reflog --date=local
81bd9a2 HEAD@{4}: rebase (start): checkout origin/main
cc72e18 HEAD@{5}: commit: NC-2250 Añade filtros del panel
$ git switch -c recovery/NC-2250-panel cc72e18Inspecciona qué commits existen únicamente en la rama recuperada. git log remoto..local lista el trabajo pendiente sin modificar referencias.
$ git fetch origin
$ git log --oneline origin/feature/NC-2250-panel..recovery/NC-2250-panel
cc72e18 NC-2250 Añade filtros del panel
bd418a0 NC-2250 Conecta consulta del panelPublicar la recuperación con otro nombre evita sobrescribir la referencia remota existente. El equipo compara ambas ramas antes de decidir si reemplaza la anterior.
$ npm test $ git push -u origin recovery/NC-2250-panel
No uses git push --force: podrías borrar commits remotos creados por otra persona. Si después de una revisión se autoriza reemplazar una rama personal, usa git push --force-with-lease, que falla si el remoto avanzó inesperadamente.
Dos ramas editaron la infraestructura del mismo servicio. Una fusión textual incorrecta podría crear dos bases de datos o eliminar reglas de red en producción.
Tu rama incrementa la capacidad de la base de datos en infra/prod/database.tf. En paralelo, main añadió cifrado administrado al mismo recurso. Git detecta conflicto en el bloque Terraform. Ambas modificaciones deben conservarse.
Actualiza referencias, integra y lista archivos conflictivos. Evita editar otros módulos hasta resolver el recurso afectado.
$ git fetch origin
$ git merge origin/main
$ git diff --name-only --diff-filter=U
infra/prod/database.tfLee las variantes del índice de merge. Necesitas comprender la intención de cada equipo: capacidad por rendimiento y cifrado por cumplimiento.
$ git show :2:infra/prod/database.tf $ git show :3:infra/prod/database.tf
Después de combinar ambos atributos, prepara el archivo y ejecuta validaciones estáticas. terraform plan muestra el efecto esperado sin aplicarlo.
# conserva allocated_storage y storage_encrypted $ terraform fmt -check infra/prod $ terraform validate $ terraform plan -out plan.tfplan Plan: 0 to add, 1 to change, 0 to destroy. $ git add infra/prod/database.tf $ git commit -m "NC-2298 Combina capacidad y cifrado de base de datos"
El pull request adjunta el plan. Plataforma revisa que no haya destrucciones y CI aplica el cambio tras aprobación.
$ git push -u origin feature/NC-2298-database-capacity
No uses terraform apply desde tu equipo y no resuelvas con git checkout --ours o --theirs. Podrías perder cifrado, ignorar capacidad o recrear infraestructura sin revisión.
Dos equipos preparan soluciones parciales para una vulnerabilidad. Debes construir un parche único, firmado y verificable sin mezclar trabajo experimental.
cherry-pick.Una vulnerabilidad permite evadir validaciones en la API. Backend preparó el commit 7bd31c2 con la validación y QA preparó a81e930 con pruebas de regresión. Ambos commits viven en ramas separadas junto a otros experimentos que no deben llegar a producción.
Actualiza referencias y crea una rama de parche desde la versión exacta en producción. No partas de main, que puede incluir cambios futuros.
$ git fetch --prune origin $ git switch -c security/NC-INC-612-input-validation origin/release/3.8
git cherry-pick incorpora commits concretos sin fusionar todas las ramas de origen. Aplica primero la corrección y después sus pruebas para que el historial sea legible.
$ git cherry-pick 7bd31c2 $ git cherry-pick a81e930 $ git log --oneline -3
Ejecuta pruebas y escaneo de seguridad. Si la empresa exige un commit integrador firmado, crea uno vacío que documente la aprobación del paquete exacto.
$ npm test -- security $ npm run security:scan $ git commit --allow-empty -S -m "NC-INC-612 Certifica parche de validación de entradas" $ git log --show-signature -1
La rama se publica y los equipos de backend y seguridad revisan hashes, firma y resultados automatizados antes de desplegar.
$ git push -u origin security/NC-INC-612-input-validation
No uses git merge feature/backend-next ni copies archivos manualmente. El merge arrastraría commits no auditados; la copia perdería autoría y trazabilidad. Evita también saltarte pruebas porque el parche parezca pequeño.
El equipo de seguridad confirma que una dependencia transitiva ejecuta código malicioso durante la instalación. La corrección debe propagarse con rapidez sin introducir versiones inconsistentes entre servicios.
NovaCode mantiene 18 servicios y 100 desarrolladores. El escáner central detecta que analytics-helper@4.2.1, dependencia transitiva de dashboard-sdk, fue comprometida. El paquete aparece en seis aplicaciones. La versión desplegada funciona, pero cualquier instalación nueva puede ejecutar código no confiable en equipos de desarrollo o runners de CI.
Seguridad bloquea temporalmente merges no esenciales. Plataforma publica una versión corregida de dashboard-sdk que fija la dependencia transitiva segura. Tu responsabilidad es remediar el portal administrativo sin arrastrar funcionalidades futuras.
Rápido, pero puede actualizar cientos de paquetes no relacionados. Aumenta el cambio y dificulta atribuir una regresión.
No es fiable: el gestor de paquetes puede ignorar una edición inconsistente o regenerarla de forma distinta en CI.
Es la solución óptima: conserva el mecanismo normal del gestor, minimiza cambios y genera evidencia reproducible.
git fetch --prune origin descarga referencias remotas y elimina referencias obsoletas sin tocar archivos locales. git switch -c crea una rama aislada desde la release desplegada; así no incluyes trabajo futuro de main.
$ git fetch --prune origin $ git switch -c security/NC-INC-701-dashboard-sdk origin/release/4.6
npm install dashboard-sdk@5.1.3 --save-exact fija la versión aprobada y regenera el árbol de dependencias. git diff --stat resume qué archivos cambiaron; el diff acotado permite confirmar que solo se modificaron manifiesto y lockfile.
$ npm install dashboard-sdk@5.1.3 --save-exact $ git diff --stat $ git diff -- package.json package-lock.json
npm ci instala exactamente lo descrito por el lockfile y falla si manifiesto y lockfile divergen. El escaneo, el SBOM y las pruebas aportan evidencia para seguridad y auditoría.
$ npm ci
$ npm audit --audit-level=high
$ npm run security:sbom
$ npm test
✓ 318 tests passed
✓ No high vulnerabilities foundgit add prepara solo los dos archivos esperados. git diff --staged revisa la versión exacta que entrará al commit. La firma -S demuestra autoría y el ticket conecta el cambio con el incidente.
$ git add package.json package-lock.json $ git diff --staged $ git commit -S -m "NC-INC-701 Actualiza dashboard-sdk comprometido" $ git push -u origin security/NC-INC-701-dashboard-sdk
No borres el lockfile, no ejecutes actualizaciones masivas y no copies un lockfile desde otro servicio. Esas acciones introducen diferencias difíciles de atribuir. No omitas npm ci: una instalación local exitosa no garantiza que CI reproduzca el mismo árbol.
Una regresión afecta autenticación en la release activa mientras decenas de commits para la próxima versión ya viven en main. La solución debe corregir ambas líneas sin mezclar calendarios de entrega.
NovaCode opera una plataforma B2B. Producción ejecuta release/7.2, pero main ya contiene 46 commits de la futura versión 7.3, incluyendo una refactorización parcial del módulo de autenticación. Un error en el refresco de sesión desconecta usuarios cada 20 minutos.
El cambio correcto ocupa pocas líneas, pero fusionar main dentro de la release incorporaría trabajo no probado. Tras arreglar producción, la misma intención debe adaptarse a la estructura nueva de main.
Incorrecto: desplazaría 46 commits no aprobados hacia producción y ampliaría drásticamente el riesgo.
Peligroso: la estructura difiere entre versiones y la copia manual pierde la relación entre commits.
Óptimo: aísla el parche de producción y conserva trazabilidad al adaptarlo a la nueva estructura.
git fetch origin actualiza referencias. La nueva rama parte explícitamente de origin/release/7.2, no de tu rama actual ni de main.
$ git fetch origin $ git switch -c hotfix/NC-INC-733-session-refresh origin/release/7.2
Las pruebas acotadas validan el flujo afectado. git diff --check detecta errores de espacios y marcas accidentales. git show --stat HEAD confirma que el commit no creció más de lo esperado.
$ npm test -- session-refresh $ git diff --check $ git add src/auth/session.js test/session.test.js $ git commit -m "NC-INC-733 Corrige renovación de sesión en release 7.2" $ git show --stat HEAD $ git push -u origin hotfix/NC-INC-733-session-refresh
Tras integrar el hotfix, toma su hash. git cherry-pick intenta reaplicar únicamente ese commit sobre una rama nacida desde origin/main. Como autenticación cambió en 7.3, Git señala el conflicto en lugar de ocultarlo.
$ git switch -c backport/NC-INC-733-main origin/main
$ git cherry-pick f28a319
CONFLICT (content): Merge conflict in src/auth/sessionManager.jsResuelve el conflicto conservando la corrección dentro del nuevo sessionManager. Después prepara el archivo y continúa la operación suspendida. --continue finaliza el cherry-pick sin crear un commit adicional desconectado.
# adapta la corrección en src/auth/sessionManager.js
$ git add src/auth/sessionManager.js test/sessionManager.test.js
$ git cherry-pick --continue
$ npm test -- session
$ git push -u origin backport/NC-INC-733-mainNo uses git merge main sobre la release y no resuelvas el cherry-pick con --ours sin inspección. La aplicación puede compilar mientras la sesión sigue fallando en un borde. No publiques directamente en ninguna rama protegida.
Un pull request aparentemente rutinario muestra que Terraform eliminará recursos compartidos. Debes detener la entrega, identificar la causa y producir una corrección verificable.
apply tras aprobación.Un equipo prepara feature/NC-2402-network-segmentation. El plan automático del pull request informa 12 to destroy, incluyendo una base de datos compartida y reglas de red usadas por tres servicios. La causa probable es un conflicto resuelto incorrectamente en infra/prod/shared.tf: alguien aceptó un lado completo y eliminó bloques aún necesarios.
El error todavía no llegó a producción gracias a la política de revisión. Debes preservar evidencia, restaurar la intención correcta desde el historial y generar un plan sin destrucciones.
Inaceptable: convertiría una detección preventiva en un incidente real.
Muy riesgoso: puede desacoplar la realidad de la configuración y ocultar recursos huérfanos.
Óptimo: mantiene Git como fuente de verdad, conserva evidencia y permite revisar el efecto antes de aplicar.
No modifiques el pull request original. Actualiza referencias y crea una rama desde la rama problemática para mantener el estado detectado como punto de comparación.
$ git fetch origin $ git switch -c fix/NC-2402-restore-shared-resources origin/feature/NC-2402-network-segmentation
git log --follow -- muestra el historial del archivo incluso si fue renombrado. git blame atribuye líneas actuales y git show HASH:path permite leer una versión anterior sin sobrescribir el directorio.
$ git log --follow --oneline -- infra/prod/shared.tf $ git blame infra/prod/shared.tf $ git show 891bc20:infra/prod/shared.tf
Edita el archivo actual e incorpora únicamente los bloques compartidos omitidos. Después valida formato y sintaxis. terraform plan -detailed-exitcode distingue entre error, ausencia de cambios y plan con cambios.
# restaura los bloques compartidos dentro del archivo actual $ terraform fmt -check infra/prod $ terraform validate $ terraform plan -detailed-exitcode -out safe.tfplan Plan: 3 to add, 4 to change, 0 to destroy.
Prepara exclusivamente la configuración restaurada. El commit explica la causa para que auditoría pueda relacionar la prevención con el conflicto anterior.
$ git add infra/prod/shared.tf $ git diff --staged $ git commit -S -m "NC-2402 Restaura recursos compartidos omitidos en merge" $ git push -u origin fix/NC-2402-restore-shared-resources
No uses terraform state rm, terraform import ni terraform apply durante el diagnóstico salvo procedimiento específico de plataforma. Esas órdenes alteran estado o infraestructura y pueden ocultar la causa original. Evita también restaurar el archivo completo con git checkout HASH -- archivo: borraría cambios válidos posteriores.
Construye y publica una plataforma de pedidos para una multinacional siguiendo un flujo completo: arquitectura, ramas, desarrollo paralelo, pruebas, seguridad, release, despliegue y respuesta postproducción.
main siempre debe ser desplegable y está protegida por pull requests.release/* con aprobación de plataforma y negocio.GlobalCommerce necesita order-hub, una API para recibir pedidos, calcular impuestos regionales y publicar eventos de facturación. El sistema debe operar en varios países, tolerar despliegues progresivos y permitir que equipos independientes trabajen sin bloquearse.
La guía recorre las fases reales del proyecto. En cada una aparece un conflicto habitual. La meta no es memorizar comandos: es entender qué estado del repositorio necesitas, qué riesgo estás controlando y qué evidencia dejarás para el siguiente equipo.
El equipo de plataforma crea la base común antes de que lleguen contribuciones.
Situación: el repositorio nace vacío. Si cada equipo inventa estructura, formato y exclusiones, las primeras revisiones se llenarán de ruido. La prioridad es establecer una línea base mínima y auditable.
$ mkdir order-hub && cd order-hub $ git init -b main $ printf "node_modules/\n.env\ncoverage/\n" > .gitignore $ git add README.md .gitignore package.json $ git commit -S -m "GC-001 Inicializa servicio order-hub" $ git remote add origin git@github.com:globalcommerce/order-hub.git $ git push -u origin main
git init -b main crea el repositorio con nombre de rama explícito.
git add selecciona archivos concretos para evitar incluir secretos o artefactos.
-S firma el commit inicial y -u enlaza la rama local con el remoto.
Un desarrollador propone confirmar un archivo .env.example con credenciales “temporales”. Se acepta documentar nombres de variables, pero nunca valores reales.
git add .durante la inicialización sin revisar git status --short.git statusgit log --show-signature -1git remote -vTres equipos implementan pedidos, impuestos y facturación sin editar main directamente.
Situación: Madrid desarrolla feature/GC-110-create-order, Quito trabaja en feature/GC-112-regional-tax y Toronto publica feature/GC-114-billing-event. Cada tarea parte del mismo main actualizado.
$ git clone git@github.com:globalcommerce/order-hub.git
$ cd order-hub
$ git fetch --prune origin
$ git switch -c feature/GC-110-create-order origin/main
# desarrolla una unidad pequeña
$ git status --short
$ git diff
$ git add src/orders/createOrder.js test/createOrder.test.js
$ git commit -S -m "GC-110 Añade creación básica de pedidos"
clone descarga archivos, historial y remoto.
fetch --prune actualiza referencias sin mezclar cambios.
switch -c ... origin/main crea una rama aislada desde la base remota aprobada.
diff permite revisar líneas antes de preparar el commit.
Dos equipos quieren modificar src/config/routes.js. En vez de reservar el archivo durante días, cada equipo mantiene commits pequeños y sincroniza con frecuencia para resolver diferencias pronto.
git pullsin saber en qué rama estás. Prefiere fetch y una integración explícita.npm test -- createOrdergit diff --checkgit log --oneline --decorate -3Impuestos necesita una propiedad que el equipo de pedidos nombró de otra forma.
Conflicto presentado: pedidos publica countryCode, mientras impuestos implementó country. Git puede fusionar los archivos porque no editan las mismas líneas, pero la aplicación falla en ejecución. Es un conflicto semántico, más difícil de detectar que un conflicto textual.
Insuficiente: Git no entiende contratos de negocio.
Tardío y riesgoso.
Óptimo: detecta el problema antes del merge.
$ git fetch origin $ git merge origin/main $ npm run test:integration -- order-tax FAIL expected tax calculation for countryCode=EC # adapta impuestos para consumir countryCode $ git add src/tax/calculateTax.js test/integration/orderTax.test.js $ git commit -S -m "GC-112 Unifica contrato regional de pedidos e impuestos"
merge origin/main incorpora la versión aprobada en tu rama antes de publicar.
La prueba de integración verifica la interacción entre módulos, no solo funciones aisladas.
Los conflictos semánticos no aparecen como marcas <<<. Define pruebas de contrato y ejecútalas en CI. Una fusión técnicamente limpia no garantiza software correcto.
git pushantes de probar la integración con la base reciente.npm run test:integrationnpm run lintnpm run typecheckEl código funciona, pero una consulta nueva degrada el tiempo de respuesta.
Conflicto presentado: durante la revisión, CI detecta que el endpoint de pedidos sube de 120 ms a 1.8 s porque consulta impuestos fila por fila. El cambio es correcto funcionalmente, pero no cumple el presupuesto de rendimiento de 300 ms.
$ git push -u origin feature/GC-110-create-order # abre PR hacia main; CI ejecuta validaciones $ npm run test:performance -- create-order FAIL p95=1800ms budget=300ms # optimiza consulta y añade prueba de regresión $ git add src/orders/createOrder.js test/performance/createOrder.perf.js $ git commit -S -m "GC-110 Reduce consultas repetidas al crear pedidos" $ git push
push -u publica la rama y establece seguimiento.
El segundo push actualiza el mismo pull request con la optimización.
Subir el timeout oculta el problema. Añadir caché global introduce invalidación compleja. La solución elegida agrupa consultas dentro de la operación y deja una prueba de presupuesto.
Evita:git commit --amenddespués de compartir la rama si el equipo ya revisa hashes concretos; añade un commit claro.npm testnpm run test:integrationnpm run test:performancenpm run security:scanDos funcionalidades agregan migraciones con el mismo número secuencial.
Conflicto presentado: al crear release/1.0.0, aparecen dos archivos 014_*.sql. Ambos son necesarios. Las migraciones compartidas son inmutables porque editar una ya ejecutada deja entornos divergentes.
$ git switch -c release/1.0.0 origin/main
$ ls db/migrations
014_add_tax_region.sql
014_add_invoice_event.sql
$ git mv db/migrations/014_add_invoice_event.sql db/migrations/015_add_invoice_event.sql
$ npm run db:test:create
$ npm run db:migrate
$ npm run db:rollback
$ git add db/migrations
$ git commit -S -m "GC-160 Ordena migraciones para release 1.0.0"
git mv registra el renombrado de manera explícita.
Las pruebas de migración y rollback garantizan que despliegue y recuperación funcionan en una base limpia.
Renombrar la migración aún no desplegada. Editar la primera o unir ambas operaciones crearía diferencias entre entornos y haría más difícil revertir una sola funcionalidad.
Evita:git checkout --ours .porque descartaría silenciosamente una migración válida.npm cinpm run db:migratenpm testnpm run security:sbomLa release aprobada se etiqueta y despliega primero a una fracción del tráfico.
Situación: CI aprobó pruebas unitarias, integración, rendimiento, migraciones y seguridad. Plataforma crea una etiqueta firmada para identificar exactamente el artefacto desplegado.
$ git switch release/1.0.0 $ git pull --ff-only $ git tag -s v1.0.0 -m "GlobalCommerce order-hub v1.0.0" $ git push origin v1.0.0 $ git show --show-signature v1.0.0
tag -s crea una etiqueta firmada e inmutable para relacionar commit, artefacto y despliegue.
show --show-signature verifica localmente la firma antes de promocionar el artefacto.
Despliega primero al 5% del tráfico, observa latencia p95, errores y saturación de base de datos. Promueve gradualmente solo si las métricas permanecen dentro del presupuesto.
Evita:git tag -fsobre una versión publicada: cambiaría qué código representa una etiqueta ya auditada.errores HTTPlatencia p95CPU y memoriacolas de eventosEl canary revela duplicación de eventos de facturación bajo concurrencia.
Conflicto presentado: al 5% de tráfico, algunos reintentos publican dos eventos. La aplicación supera pruebas funcionales normales, pero falla bajo concurrencia. Debes detener la promoción y restaurar estabilidad antes de diseñar una corrección definitiva.
No auditable y demasiado riesgoso.
Amplía el impacto económico.
Óptimo: reduce impacto y conserva evidencia.
$ git switch -c revert/GC-INC-021-billing origin/release/1.0.0 $ git log --first-parent --oneline -5 $ git revert HASH_DEL_MERGE $ npm test -- billing $ git push -u origin revert/GC-INC-021-billing
log --first-parent simplifica la búsqueda del cambio integrado.
revert crea un commit inverso auditable sin borrar la historia desplegada.
La rapidez no consiste en omitir controles. Consiste en elegir una operación pequeña y reversible. Después del rollback, crea una rama de investigación y añade una prueba concurrente que reproduzca el fallo.
Evita:git reset --hardy force push sobre ramas compartidas: eliminarían evidencia y romperían clones del equipo.servicio establetimeline documentadaprueba de regresiónpostmortem sin culpaProyecto de contratación para una empresa transnacional de ingeniería de software. La evaluación mide criterio técnico, claridad, seguridad, rendimiento y capacidad de entregar una solución auditable.
El servicio order-api recibe solicitudes desde aplicaciones móviles, web y socios externos. Algunos clientes reintentan una petición cuando la red es lenta. El balanceador también puede reenviar solicitudes después de un timeout. En ocasiones, dos instancias procesan el mismo pedido casi al mismo tiempo.
El síntoma visible es grave: algunos clientes reciben dos pedidos y dos cargos para una sola compra. Existe un intento de protección en memoria mediante un Set, pero cada instancia mantiene su propia copia, se pierde al reiniciar y no coordina concurrencia distribuida.
El equipo solicita una solución incremental. No puedes rediseñar todos los servicios ni depender de una migración riesgosa durante el primer despliegue. Debes explicar cómo detectar duplicados, cómo responder a reintentos, qué almacenar, qué probar y cómo desplegar sin interrumpir operaciones.
Primero reduce incertidumbre. No escribas código hasta entender el contrato, el fallo y el camino de despliegue.
Para una clave de idempotencia dada, existe como máximo un pedido confirmado. Repetir la misma solicitud devuelve el mismo resultado. Reutilizar la clave con otro payload devuelve error.
Una respuesta senior compara opciones y declara por qué descarta soluciones seductoras pero incompletas.
Muy rápido, pero incorrecto en un entorno distribuido. No sobrevive reinicios y dos nodos pueden aceptar la misma clave.
Insuficiente: dos peticiones pueden leer “no existe” simultáneamente y crear duplicados. Es una carrera clásica check-then-act.
Puede ayudar como optimización, pero no debe ser la única barrera para una operación financiera.
Óptimo: la base compartida arbitra concurrencia de forma atómica y deja evidencia persistente.
La solución usa una tabla idempotency_records con clave única, hash del payload, estado y respuesta serializada. La restricción de unicidad es la garantía primaria. Una caché podría añadirse después para rendimiento, nunca como fuente de verdad.
La base de datos expresa la invariante para que todas las instancias compartan la misma garantía.
-- db/migrations/021_create_idempotency_records.sql
CREATE TABLE idempotency_records (
idempotency_key VARCHAR(128) PRIMARY KEY,
request_hash VARCHAR(64) NOT NULL,
status VARCHAR(24) NOT NULL,
response_json JSONB,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
expires_at TIMESTAMP NOT NULL
);
CREATE INDEX idx_idempotency_expiry
ON idempotency_records (expires_at);
Decisiones: la clave primaria impide duplicados atómicamente. request_hash detecta reutilización incorrecta. status representa operaciones en curso o completadas. expires_at permite limpieza controlada. El índice evita escaneos completos durante esa limpieza.
La primera fase añade una tabla sin alterar rutas existentes. Si el canary falla, desactiva el feature flag antes de retirar la tabla. Nunca elimines estructuras mientras instancias antiguas o nuevas puedan seguir usándolas.
El código separa validación, almacenamiento y lógica de negocio para mantener pruebas rápidas y razonamiento claro.
// src/orders/createOrder.js
export async function createOrder({ key, payload, repository, payments }) {
if (!key) return createLegacyOrder({ payload, repository, payments });
const requestHash = hashPayload(payload);
const existing = await repository.findIdempotencyRecord(key);
if (existing) {
if (existing.requestHash !== requestHash) {
throw new IdempotencyConflictError("Key reused with different payload");
}
if (existing.status === "completed") return existing.response;
throw new OrderInProgressError("Order is already being processed");
}
const claimed = await repository.tryClaimKey({ key, requestHash });
if (!claimed) return createOrder({ key, payload, repository, payments });
const response = await payments.chargeAndCreateOrder(payload);
await repository.completeKey({ key, response });
return response;
}
Lectura técnica: los clientes antiguos siguen el camino legado durante una transición controlada. Los nuevos envían una clave. La consulta temprana optimiza reintentos conocidos, pero tryClaimKey con restricción única sigue siendo la defensa real contra carreras. Si otra instancia reclama primero, la operación reevalúa el estado.
// src/orders/idempotencyRepository.js
export async function tryClaimKey(db, { key, requestHash }) {
const result = await db.query(`
INSERT INTO idempotency_records
(idempotency_key, request_hash, status, expires_at)
VALUES ($1, $2, 'processing', NOW() + INTERVAL '24 hours')
ON CONFLICT (idempotency_key) DO NOTHING
RETURNING idempotency_key
`, [key, requestHash]);
return result.rowCount === 1;
}
Decisión de rendimiento: el índice primario convierte la reclamación en una operación acotada. No mantengas una transacción abierta mientras llamas a un proveedor externo: bloquearía conexiones y elevaría latencia bajo carga.
La prueba importante no es solo el camino feliz: debes demostrar comportamiento bajo concurrencia y fallos parciales.
Misma clave y payload devuelve misma respuesta. Misma clave y payload distinto produce conflicto. Cliente antiguo conserva comportamiento.
Dos peticiones simultáneas compiten contra una base real. Solo una crea pedido y cargo.
Prueba carga normal y ráfagas de reintentos. Mide p95, conexiones y contención del índice.
Confirma que logs no contienen payload completo, tokens ni datos de pago.
Simula caída tras reclamar clave y define recuperación de registros atascados.
Aplica y revierte esquema en base temporal. Comprueba compatibilidad entre versiones.
// test/integration/createOrder.concurrent.test.js
it("creates one charge for concurrent retries", async () => {
const requests = Array.from({ length: 20 }, () =>
api.createOrder({ key: "checkout-901", payload })
);
const responses = await Promise.allSettled(requests);
expect(await db.countOrdersFor("checkout-901")).toBe(1);
expect(payments.charge).toHaveBeenCalledTimes(1);
expect(responses.some(isSuccessful)).toBe(true);
});
npm testnpm run test:integrationnpm run test:loadnpm run security:scannpm run db:migrate:testLa forma de publicar es parte de la solución técnica, no una tarea posterior.
$ git fetch --prune origin
$ git switch -c feature/OS-4821-order-idempotency origin/main
# añade migración, repositorio, servicio y pruebas
$ git status --short
$ git diff --check
$ git add db/migrations/021_create_idempotency_records.sql
$ git commit -S -m "OS-4821 Añade almacenamiento idempotente"
$ git add src/orders test
$ git commit -S -m "OS-4821 Protege creación de pedidos concurrentes"
$ git push -u origin feature/OS-4821-order-idempotency
Dos commits separan esquema y comportamiento. Facilitan revisión, reversión y diagnóstico.
diff --check detecta problemas básicos antes de consumir tiempo de CI.
La firma -S cumple trazabilidad.
El pull request incluye plan de despliegue y rollback.
Primero despliega la tabla. Después activa la lógica detrás de un feature flag para 1% del tráfico, luego 10%, 50% y 100%. Observa duplicados, latencia, errores y registros atascados entre cada paso.
La madurez aparece tanto en los límites declarados como en el código entregado.
git add .Puede incluir secretos, logs o cambios no relacionados. Usa rutas explícitas después de revisar estado.
git push --forceReescribe historia compartida y rompe trazabilidad. Usa pull request y commits nuevos.
git reset --hardPuede destruir evidencia o trabajo local durante diagnóstico. Crea ramas de respaldo.
SELECT antes de INSERT sin uniqueNo resuelve concurrencia distribuida. Dos instancias pueden leer el mismo estado.
Lock de transacción durante pagoAgota conexiones y degrada p95. Reclama clave brevemente y procesa fuera del lock.
Activación al 100%Amplía impacto antes de observar métricas reales. Usa feature flag y canary.
No solo “funciona en mi máquina”. Espera una solución razonada, medible, operable y reversible. También espera que distingas la garantía de corrección de las optimizaciones posteriores.
git diffgit fetch --prunegit show HASHgit merge ramagit merge --abortgit revert HASH