Find the First Broken Quote

GitBeginner
Practice Now

Introduction

Little Pine Goods prepares pickup quotes for small gifts. A customer reports that the FRIEND10 offer no longer gives its promised discount. Recent history also contains useful product, wording and pickup updates, so returning the whole shop to an old version would lose valid work.

Run a normal order and the faulty gift order, then use a prepared deterministic business test to classify old versions. Practice a little manual Git bisection before letting the same test automate the search. Compare the first broken snapshot with its direct parent, leave the search, and repair the current shop while keeping the later updates. Deliver a complete customer quote file as well as the corrective commit.

Prerequisites are basic terminal navigation, commits, branches and simple log/diff reading. Git bisect, temporary detached checkouts, test exit statuses and the small offer-file edit are explained here. Python and the quote program are prepared; you run them without writing Python. This is a real local Git history and file-based quote tool on one training machine, with fictional orders and EUR prices. No website, hosted account or network deployment is needed. Use the default Terminal. The 50-minute duration is an author estimate.

Find the First Broken Quote

In this step, establish the correct business result, test real historical snapshots and identify the boundary where the discount became wrong.

Start in Terminal and enter the shop repository:

cd /home/labex/project/quote-desk/shop

cd changes this terminal's directory. If you mistype a path, use pwd to print your location and ls to list that directory, then repeat the full cd above. Ordinary navigation errors do not require a VM reset.

Read the customer request. cat displays a text file; .. means the parent directory:

cat ../request.txt

FRIEND10 promises 10% off the item subtotal. There is no shipping or tax. The gift order is three camp mugs at EUR 16.00 each: subtotal EUR 48.00, discount EUR 4.80, total EUR 43.20. The existing catalog, order and policy are the business facts; do not change them to fit a faulty result.

Run a normal order first. python3 runs the supplied program quote.py; its next argument is the prepared order file. You do not need to edit or understand Python source:

python3 quote.py ../orders/plain.order

The one-mug order uses coupon NONE. Expect subtotal and total EUR 16.00, discount EUR 0.00, the current welcome line and Saturday pickup until 16:00. This establishes a useful normal quote.

Run the reported order:

python3 quote.py ../orders/gift.order

To read the last command's native exit status, use the shell value $?. echo prints that value. Run it immediately after the quote command:

echo $?

Expect 0: the program ran successfully even though the monetary result is wrong.

The program runs, but the quote is wrong: discount EUR 0.48 and total EUR 47.52. A successful program exit is different from a correct business answer.

The prepared test lives outside the repository so checking out old versions cannot replace it. It runs the actual quote program for several quantities and a no-coupon control, comparing full results against the unchanged offer policy. Run it:

python3 /opt/labex/quote-desk/check.py

Read this test's status immediately, using the same shell value:

echo $?

Expect 1: this test detects the business mismatch.

Expect FAIL lines for FRIEND10 and a native exit status of 1. The NONE controls pass. The test returns 0 for correct quotes, 1 for this business failure, and 128 if it cannot test a version; an inability to test should stop the search, not be guessed to be a discount regression. This prepared history has no build failures or skipped versions.

Inspect the current branch and clean state. branch --show-current prints the branch; --short produces a compact file list:

git branch --show-current
git status --short

Expect main and no changed-file output. Keep the shop clean while searching. Read its history: --no-pager prints directly instead of entering a scrolling viewer, --oneline shortens entries, and --decorate labels branches and tags:

git --no-pager log --oneline --decorate

The fixed tag incident-tip marks the inherited current tip, and known-good marks the earlier working version. Commit subjects describe work, but their wording is not proof of when the quote failed. Preserve both tags and all inherited commits.

The test's --revision option runs the selected committed snapshot in a temporary isolated directory without changing your checkout or repairing it. Establish both ends with real behavior:

python3 /opt/labex/quote-desk/check.py --revision known-good
python3 /opt/labex/quote-desk/check.py --revision incident-tip

The first command must pass with status 0. The second must fail with status 1. A good version and a later bad version bound the search. This exercise has one introduction of the fault and no later fix in that interval.

Classify Two Versions by Hand

Git bisect narrows that interval by testing versions between the boundaries. Start with the known bad revision first and the known good revision second:

git bisect start incident-tip known-good

Git checks out a middle snapshot and prints the remaining interval. During the search, detached HEAD means you are viewing a commit directly instead of moving main. Do not edit or commit in these temporary versions.

Run the same test on this checked-out snapshot:

python3 /opt/labex/quote-desk/check.py

This prepared first selection fails with status 1. Classify that observed version as bad; bad describes the business test result, not its commit message:

git bisect bad

Git selects another snapshot. Test it rather than guessing:

python3 /opt/labex/quote-desk/check.py

This selection passes with status 0. Record that observation:

git bisect good

Git narrows the interval again. You have seen how each result removes part of the search space. To practice the automatic route from the same original boundaries, leave this incomplete search first. bisect reset clears the search state and returns to the branch and revision where it started; it does not undo commits:

git bisect reset
git branch --show-current

Expect main. If you classify a version incorrectly during practice, this same reset and a fresh start let you repeat using the actual test results, without discarding files.

Start again, then give bisect run the same complete test command. Git uses each native exit status to choose good or bad automatically:

git bisect start incident-tip known-good
git bisect run python3 /opt/labex/quote-desk/check.py

Expect several test runs and a line ending is the first bad commit. The search command itself finishes with status 0 when it successfully finds the boundary, even though some individual quote tests failed. Commit IDs may differ.

Git's bisect/bad reference points to the identified first bad commit. The current HEAD can still be the last tested good version; do not assume it is the reported result. Read the actual candidate patch. show selects that commit and its patch; -- separates the file path:

git --no-pager show bisect/bad -- discounts.txt

The FRIEND10 percentage changed from 10 to 1. Check both sides using the external test. A trailing ^ selects a commit's direct first parent, so bisect/bad^ is the version immediately before the candidate, not an entire range:

python3 /opt/labex/quote-desk/check.py --revision bisect/bad
python3 /opt/labex/quote-desk/check.py --revision bisect/bad^

Expect the candidate to fail with status 1 and its parent to pass with status 0. The values and real behavior agree. Leave the completed search open for this checkpoint; next you will return to the current shop before editing.

Repair the Current Shop and Deliver the Quote

In this step, leave the historical search, commit a focused correction on the current branch, and deliver a complete quote without losing later products or pickup information.

Stay in Terminal, in /home/labex/project/quote-desk/shop. Return to the original branch using the taught search reset:

git bisect reset
git branch --show-current
git --no-pager log -1 --oneline --decorate
git status --short

Expect main, the inherited tip marked incident-tip, and no changed-file output. The log option -1 limits the output to the newest commit. Do not repair a detached historical version or replace the entire shop with known-good: later valid work belongs in the result.

Read the small offer file and the current details you must preserve:

cat discounts.txt
cat welcome.txt pickup.txt care.txt
cat catalog.json

The current tree includes the Trail pin, the new welcome line and Saturday pickup until 16:00. Only FRIEND10's percentage is wrong. The offer file is one CODE=integer-percent setting per line; TRAIL15 stays 15 and STUDENT5 stays 5.

Replace just this small file. printf prints values according to a format: %s means text and \n adds a newline after each supplied value. Single quotes preserve the literal text. > writes the output into the named file, replacing that file only:

printf '%s\n' 'FRIEND10=10' 'TRAIL15=15' 'STUDENT5=5' > discounts.txt

Review the actual correction. A plain diff compares working files with the index, Git's staging area:

git --no-pager diff -- discounts.txt

Expect only FRIEND10 changing from 1 back to 10. Set a repository-local commit identity before recording the repair. --local avoids global configuration; quotes keep a name with spaces together. These fictional examples can be replaced:

git config --local user.name "Little Pine Maintainer"
git config --local user.email "maintainer@little-pine.example"

Stage that file with add. Inspect the staged patch with --cached, which compares the index with the current commit:

git add discounts.txt
git --no-pager diff --cached -- discounts.txt

Commit the focused correction. -m provides a meaningful message directly:

git commit -m "Restore the promised FRIEND10 discount"

Compare against the fixed inherited tip. This is one new corrective commit, retaining every original commit rather than rewriting history:

git --no-pager diff incident-tip HEAD
git --no-pager log -2 --oneline --decorate
git status --short

Expect just the percentage correction, your repair immediately after incident-tip, and a clean tracked state. The exact message and author values are not the success criterion.

Run the prepared test on the actual current program:

python3 /opt/labex/quote-desk/check.py

All cases now pass with status 0. Generate the customer's quote:

python3 quote.py ../orders/gift.order

Expect the current mug description and welcome line, quantity 3, FRIEND10, subtotal EUR 48.00, discount EUR 4.80, total EUR 43.20, and current pickup through Saturday 16:00.

Deliver that real output to the prepared quotes directory. As taught, > saves stdout in this named file; it does not change the order or program:

python3 quote.py ../orders/gift.order > ../quotes/mug-gift.txt
cat ../quotes/mug-gift.txt

Read the complete saved quote, not just its filename. The file is the customer's usable result, while the commit makes the fix repeatable.

Check the normal order and the later product, which must remain usable:

python3 quote.py ../orders/plain.order
python3 quote.py ../orders/new-item.order

The plain mug remains EUR 16.00. Two Trail pins with STUDENT5 have subtotal EUR 10.00, discount EUR 0.50 and total EUR 9.50. Both retain the current welcome and pickup details. The checkpoint observes the actual current commit, full preserved tree, historical boundary behavior and delivered quote; it does not grade a command transcript or a message keyword.

Summary

You used normal and faulty orders to define a business test, classified historical versions manually and automated the same search with Git bisect. You distinguished its first-bad reference from HEAD, verified the candidate and its parent, returned to main, and committed a focused repair without losing later shop updates. The customer received a complete correct quote.

The independent challenge changes the coupon, customer order and fault position, while using the same supplied program, policy and test format. Choose from the actual evidence rather than copying a commit offset.