Introducción
Little Pine Goods prepara presupuestos de pequeños regalos para recoger en tienda. Un cliente informa de que la oferta FRIEND10 ya no aplica el descuento prometido. El historial reciente también contiene actualizaciones útiles de productos, textos y recogida, por lo que devolver toda la tienda a una versión antigua haría perder trabajo válido.
Ejecuta un pedido normal y el pedido de regalo defectuoso; después usa una prueba determinista de negocio preparada para clasificar versiones antiguas. Practica brevemente la bisección manual de Git antes de dejar que la misma prueba automatice la búsqueda. Compara la primera instantánea defectuosa con su padre directo, sal de la búsqueda y repara la tienda actual conservando las actualizaciones posteriores. Entrega un archivo de presupuesto completo para el cliente además del commit correctivo.
Los requisitos previos son la navegación básica por la terminal, los commits, las ramas y la lectura sencilla de log/diff. Aquí se explican Git bisect, los checkouts temporales con HEAD separado, los estados de salida de las pruebas y la pequeña edición del archivo de ofertas. Python y el programa de presupuestos están preparados; los ejecutas sin escribir Python. Se trata de un historial Git local real y una herramienta de presupuestos basada en archivos en una única máquina de formación, con pedidos ficticios y precios en EUR. No se necesita sitio web, cuenta de un servicio alojado ni despliegue en red. Usa la Terminal predeterminada. La duración de 50 minutos es una estimación del autor.
Encuentra el primer presupuesto defectuoso
En este paso, establecerás el resultado correcto del negocio, probarás instantáneas históricas reales e identificarás el límite en el que el descuento pasó a ser incorrecto.
Empieza en Terminal y entra en el repositorio de la tienda:
cd /home/labex/project/quote-desk/shop
cd cambia el directorio de esta terminal. Si escribes mal una ruta, usa pwd para mostrar tu ubicación y ls para listar ese directorio; después repite el comando cd completo de arriba. Los errores habituales de navegación no requieren reiniciar la VM.
Lee la solicitud del cliente. cat muestra un archivo de texto; .. significa el directorio padre:
cat ../request.txt
FRIEND10 promete un 10% de descuento sobre el subtotal de los artículos. No hay gastos de envío ni impuestos. El pedido de regalo son tres tazas de camping a EUR 16.00 cada una: subtotal EUR 48.00, descuento EUR 4.80, total EUR 43.20. El catálogo, el pedido y la política existentes son los datos del negocio; no los cambies para ajustarlos a un resultado defectuoso.
Ejecuta primero un pedido normal. python3 ejecuta el programa proporcionado quote.py; su siguiente argumento es el archivo de pedido preparado. No necesitas editar ni comprender el código fuente de Python:
python3 quote.py ../orders/plain.order
El pedido de una taza usa el cupón NONE. Se esperan subtotal y total de EUR 16.00, descuento de EUR 0.00, la frase de bienvenida actual y recogida el sábado hasta las 16:00. Esto establece un presupuesto normal útil.
Ejecuta el pedido del que se ha informado:
python3 quote.py ../orders/gift.order
Para leer el estado de salida nativo del último comando, usa el valor del intérprete de comandos $?. echo muestra ese valor. Ejecútalo inmediatamente después del comando del presupuesto:
echo $?
Se espera 0: el programa se ejecutó correctamente aunque el resultado monetario sea incorrecto.
El programa se ejecuta, pero el presupuesto es incorrecto: descuento EUR 0.48 y total EUR 47.52. Que el programa termine correctamente no es lo mismo que obtener una respuesta de negocio correcta.
La prueba preparada está fuera del repositorio para que extraer versiones antiguas no pueda reemplazarla. Ejecuta el programa real de presupuestos con varias cantidades y un control sin cupón, comparando los resultados completos con la política de ofertas sin cambios. Ejecútala:
python3 /opt/labex/quote-desk/check.py
Lee inmediatamente el estado de esta prueba usando el mismo valor del intérprete:
echo $?
Se espera 1: esta prueba detecta la discrepancia de negocio.
Se esperan líneas FAIL para FRIEND10 y un estado de salida nativo de 1. Los controles NONE pasan. La prueba devuelve 0 para presupuestos correctos, 1 para este fallo de negocio y 128 si no puede probar una versión; la imposibilidad de probar debe detener la búsqueda, no interpretarse por conjetura como una regresión del descuento. Este historial preparado no tiene fallos de compilación ni versiones omitidas.
Inspecciona la rama actual y el estado limpio. branch --show-current muestra la rama; --short produce una lista compacta de archivos:
git branch --show-current
git status --short
Se esperan main y ninguna salida de archivos modificados. Mantén la tienda limpia durante la búsqueda. Lee su historial: --no-pager muestra la salida directamente en lugar de entrar en un visor desplazable, --oneline abrevia las entradas y --decorate etiqueta las ramas y los tags:
git --no-pager log --oneline --decorate
La etiqueta fija incident-tip marca la punta actual recibida y known-good marca la versión anterior que funcionaba. Los asuntos de los commits describen el trabajo, pero su redacción no demuestra cuándo falló el presupuesto. Conserva ambas etiquetas y todos los commits recibidos.
La opción --revision de la prueba ejecuta la instantánea seleccionada guardada en un commit en un directorio temporal aislado, sin cambiar tu checkout ni repararlo. Establece ambos extremos con el comportamiento real:
python3 /opt/labex/quote-desk/check.py --revision known-good
python3 /opt/labex/quote-desk/check.py --revision incident-tip
El primer comando debe pasar con estado 0. El segundo debe fallar con estado 1. Una versión correcta y otra posterior defectuosa delimitan la búsqueda. Este ejercicio tiene una única introducción del fallo y ninguna corrección posterior dentro de ese intervalo.
Clasifica dos versiones a mano
Git bisect reduce ese intervalo probando versiones entre los límites. Empieza con la revisión defectuosa conocida en primer lugar y la revisión correcta conocida en segundo lugar:
git bisect start incident-tip known-good
Git extrae una instantánea intermedia y muestra el intervalo restante. Durante la búsqueda, detached HEAD significa que estás viendo un commit directamente en lugar de mover main. No edites ni crees commits en estas versiones temporales.
Ejecuta la misma prueba en esta instantánea extraída:
python3 /opt/labex/quote-desk/check.py
Esta primera selección preparada falla con estado 1. Clasifica esa versión observada como defectuosa; bad describe el resultado de la prueba de negocio, no su mensaje de commit:
git bisect bad
Git selecciona otra instantánea. Pruébala en lugar de adivinar:
python3 /opt/labex/quote-desk/check.py
Esta selección pasa con estado 0. Registra esa observación:
git bisect good
Git reduce el intervalo otra vez. Has visto cómo cada resultado elimina parte del espacio de búsqueda. Para practicar el proceso automático desde los mismos límites originales, sal primero de esta búsqueda incompleta. bisect reset limpia el estado de la búsqueda y vuelve a la rama y revisión donde comenzó; no deshace commits:
git bisect reset
git branch --show-current
Se espera main. Si clasificas una versión incorrectamente durante la práctica, este mismo reset y un nuevo inicio te permiten repetir usando los resultados reales de las pruebas, sin descartar archivos.
Deja que la prueba dirija la búsqueda
Empieza de nuevo y después proporciona a bisect run el mismo comando de prueba completo. Git usa cada estado de salida nativo para elegir automáticamente si la versión es correcta o defectuosa:
git bisect start incident-tip known-good
git bisect run python3 /opt/labex/quote-desk/check.py
Se esperan varias ejecuciones de la prueba y una línea que termine en is the first bad commit. El propio comando de búsqueda termina con estado 0 cuando encuentra correctamente el límite, aunque algunas pruebas individuales de presupuestos hayan fallado. Los identificadores de commit pueden ser distintos.
La referencia bisect/bad de Git apunta al primer commit defectuoso identificado. El HEAD actual todavía puede ser la última versión correcta probada; no supongas que es el resultado anunciado. Lee el parche real del candidato. show selecciona ese commit y su parche; -- separa la ruta de archivo:
git --no-pager show bisect/bad -- discounts.txt
El porcentaje de FRIEND10 cambió de 10 a 1. Comprueba ambos lados usando la prueba externa. Un ^ al final selecciona un único primer padre directo de un commit, por lo que bisect/bad^ es la versión inmediatamente anterior al candidato, no un intervalo completo:
python3 /opt/labex/quote-desk/check.py --revision bisect/bad
python3 /opt/labex/quote-desk/check.py --revision bisect/bad^
Se espera que el candidato falle con estado 1 y que su padre pase con estado 0. Los valores y el comportamiento real concuerdan. Deja abierta la búsqueda completada para este punto de comprobación; a continuación volverás a la tienda actual antes de editar.
Repara la tienda actual y entrega el presupuesto
En este paso, saldrás de la búsqueda histórica, guardarás una corrección centrada en el fallo en la rama actual y entregarás un presupuesto completo sin perder los productos posteriores ni la información de recogida.
Permanece en Terminal, en /home/labex/project/quote-desk/shop. Vuelve a la rama original usando el reset de búsqueda que has aprendido:
git bisect reset
git branch --show-current
git --no-pager log -1 --oneline --decorate
git status --short
Se esperan main, la punta recibida marcada por incident-tip y ninguna salida de archivos modificados. La opción -1 de log limita la salida al commit más reciente. No repares una versión histórica separada de la rama ni reemplaces toda la tienda por known-good: el trabajo válido posterior forma parte del resultado.
Lee el pequeño archivo de ofertas y los detalles actuales que debes conservar:
cat discounts.txt
cat welcome.txt pickup.txt care.txt
cat catalog.json
El árbol actual incluye el pin Trail, la nueva frase de bienvenida y recogida el sábado hasta las 16:00. Solo es incorrecto el porcentaje de FRIEND10. El archivo de ofertas contiene una configuración CODE=integer-percent por línea; TRAIL15 sigue siendo 15 y STUDENT5 sigue siendo 5.
Reemplaza únicamente este pequeño archivo. printf muestra valores según un formato: %s significa texto y \n añade un salto de línea después de cada valor proporcionado. Las comillas simples conservan el texto literal. > escribe la salida en el archivo indicado, reemplazando solo ese archivo:
printf '%s\n' 'FRIEND10=10' 'TRAIL15=15' 'STUDENT5=5' > discounts.txt
Revisa la corrección real. Una comparación simple compara los archivos de trabajo con el índice, el área de preparación de Git:
git --no-pager diff -- discounts.txt
Se espera únicamente que FRIEND10 vuelva de 1 a 10. Configura una identidad de commit local para el repositorio antes de registrar la reparación. --local evita la configuración global; las comillas mantienen unido un nombre con espacios. Puedes reemplazar estos ejemplos ficticios:
git config --local user.name "Little Pine Maintainer"
git config --local user.email "maintainer@little-pine.example"
Prepara ese archivo con add. Inspecciona el parche preparado con --cached, que compara el índice con el commit actual:
git add discounts.txt
git --no-pager diff --cached -- discounts.txt
Crea el commit de la corrección centrada en el fallo. -m proporciona directamente un mensaje con significado:
git commit -m "Restore the promised FRIEND10 discount"
Compara con la punta recibida fija. Se trata de un nuevo commit correctivo que conserva todos los commits originales en lugar de reescribir el historial:
git --no-pager diff incident-tip HEAD
git --no-pager log -2 --oneline --decorate
git status --short
Se esperan solo la corrección del porcentaje, tu reparación inmediatamente después de incident-tip y un estado limpio de los archivos bajo seguimiento. El mensaje exacto y los valores de identidad del autor no son el criterio de éxito.
Ejecuta la prueba preparada sobre el programa actual real:
python3 /opt/labex/quote-desk/check.py
Todos los casos pasan ahora con estado 0. Genera el presupuesto del cliente:
python3 quote.py ../orders/gift.order
Se esperan la descripción actual de la taza y la frase de bienvenida, cantidad 3, FRIEND10, subtotal EUR 48.00, descuento EUR 4.80, total EUR 43.20 y la recogida actual hasta el sábado a las 16:00.
Entrega esa salida real en el directorio preparado quotes. Como se ha enseñado, > guarda stdout en este archivo indicado; no cambia el pedido ni el programa:
python3 quote.py ../orders/gift.order > ../quotes/mug-gift.txt
cat ../quotes/mug-gift.txt
Lee el presupuesto guardado completo, no solo su nombre de archivo. El archivo es el resultado utilizable por el cliente, mientras que el commit hace que la corrección pueda repetirse.
Comprueba el pedido normal y el producto posterior, que deben seguir siendo utilizables:
python3 quote.py ../orders/plain.order
python3 quote.py ../orders/new-item.order
La taza sin descuento sigue en EUR 16.00. Dos pines Trail con STUDENT5 tienen subtotal EUR 10.00, descuento EUR 0.50 y total EUR 9.50. Ambos conservan los detalles actuales de bienvenida y recogida. El punto de comprobación observa el commit actual real, el árbol completo conservado, el comportamiento del límite histórico y el presupuesto entregado; no evalúa una transcripción de comandos ni una palabra clave del mensaje.
Resumen
Usaste pedidos normales y defectuosos para definir una prueba de negocio, clasificaste versiones históricas manualmente y automatizaste la misma búsqueda con Git bisect. Distinguiste su referencia al primer commit defectuoso de HEAD, verificaste el candidato y su padre, volviste a main y guardaste una reparación centrada en el fallo sin perder las actualizaciones posteriores de la tienda. El cliente recibió un presupuesto completo y correcto.
El desafío independiente cambia el cupón, el pedido del cliente y la posición del fallo, usando el mismo programa, política y formato de prueba proporcionados. Elige a partir de las pruebas reales en lugar de copiar un desplazamiento de commit.



