介绍
Little Pine Goods 为小礼品提供到店取货报价。一位顾客反馈,FRIEND10 优惠不再提供承诺的折扣。近期历史还包含有用的商品、文案和取货信息更新,因此将整个商店退回旧版会丢失有效工作。
先运行正常订单和有问题的礼品订单,再使用准备好的确定性业务测试判断旧版本。先手动练习少量 Git 二分查找,再让同一个测试自动完成搜索。将首个错误快照与其直接父提交对比,退出搜索,然后修复当前商店,同时保留后续更新。除了修正提交,还要交付完整的顾客报价文件。
前置要求是基本的终端目录切换、提交、分支和简单日志/差异阅读。本实验会解释 Git bisect、临时分离检出、测试退出状态,以及小型优惠文件的编辑。Python 和报价程序已经准备好;你只需运行,不必编写 Python。这是真实的本地 Git 历史和基于文件的报价工具,运行在一台教学机器上,订单为虚构内容,价格使用 EUR。不需要网站、托管账号或网络部署。使用默认的 Terminal。50 分钟的时长为作者估计。
找出首次出现错误报价的提交
本步骤中,你将确定正确的业务结果,测试真实历史快照,并找出折扣开始出错的边界。
从 Terminal 开始,进入商店仓库:
cd /home/labex/project/quote-desk/shop
cd 改变当前终端的目录。如果路径拼错,可用 pwd 打印当前位置、用 ls 列出该目录,再重新执行上面的完整 cd 命令。普通目录切换错误不需要重置 VM。
读取顾客请求。cat 显示文本文件;.. 表示父目录:
cat ../request.txt
FRIEND10 承诺对商品小计减免 10%。没有运费或税费。礼品订单包含三个单价 EUR 16.00 的露营杯:小计 EUR 48.00,折扣 EUR 4.80,总价 EUR 43.20。现有目录、订单和优惠规则就是业务事实;不要修改它们来迎合错误结果。
先运行正常订单。python3 运行提供的程序 quote.py;后面的参数是准备好的订单文件。你不需要编辑或理解 Python 源码:
python3 quote.py ../orders/plain.order
单杯订单使用优惠码 NONE。预期小计和总价均为 EUR 16.00,折扣 EUR 0.00,并显示当前欢迎语及周六截至 16:00 的取货信息。这确定了正常可用的报价结果。
运行顾客反馈的订单:
python3 quote.py ../orders/gift.order
要读取上一条命令的原生退出状态,请使用 shell 值 $?。echo 打印该值。在报价命令之后立即运行:
echo $?
预期为 0:尽管金额结果错误,程序本身仍成功运行。
程序能运行,但报价错误:折扣为 EUR 0.48,总价为 EUR 47.52。程序成功退出与业务答案正确是两回事。
准备好的测试位于仓库之外,因此检出旧版本无法替换它。它使用多个数量及无优惠码对照订单运行真实报价程序,将完整结果与未改变的优惠规则对比。运行它:
python3 /opt/labex/quote-desk/check.py
立即使用同一个 shell 值读取该测试的状态:
echo $?
预期为 1:这个测试检测到了业务结果不符。
预期 FRIEND10 出现 FAIL 行,原生退出状态为 1。 NONE 对照通过。测试在报价正确时返回 0,发生此类业务错误时返回 1,无法测试某版本时返回 128;无法测试应让搜索停止,而不能猜测为折扣回归。本次准备好的历史没有构建失败或需要跳过的版本。
检查当前分支和干净状态。branch --show-current 打印分支;--short 生成简洁文件列表:
git branch --show-current
git status --short
预期为 main,没有已更改文件输出。搜索期间保持商店干净。读取历史:--no-pager 直接打印,不进入可滚动查看器;--oneline 简化条目;--decorate 标记分支和标签:
git --no-pager log --oneline --decorate
固定标签 incident-tip 标记接手时的当前末端,known-good 标记较早的正常版本。提交主题描述工作,但其措辞不能证明报价何时出错。保留两个标签和全部接手的提交。
测试的 --revision 选项在临时隔离目录中运行选定的已提交快照,不改变当前检出,也不修复该快照。通过真实行为确定两端:
python3 /opt/labex/quote-desk/check.py --revision known-good
python3 /opt/labex/quote-desk/check.py --revision incident-tip
第一条命令必须通过,状态为 0。第二条必须失败,状态为 1。 一个正常版本和之后的错误版本界定了搜索范围。本练习中,该区间内只有一次故障引入,之后没有修复。
手动判断两个版本
Git bisect 通过测试两个边界之间的版本来缩小区间。开始时先给出已知错误版本,再给出已知正常版本:
git bisect start incident-tip known-good
Git 检出一个中间快照并打印剩余区间。搜索期间,分离 HEAD 表示你直接查看某个提交,而不是移动 main。不要在这些临时版本中编辑或提交。
对当前检出的快照运行同一个测试:
python3 /opt/labex/quote-desk/check.py
本场景第一次选出的版本会失败,状态为 1。 将观察到的版本判定为 bad;bad 描述业务测试结果,而不是提交信息:
git bisect bad
Git 选择另一个快照。请测试它,不要猜测:
python3 /opt/labex/quote-desk/check.py
这次选择的版本通过,状态为 0。记录这一观察:
git bisect good
Git 再次缩小区间。你已经看到每个结果如何排除一部分搜索范围。为了从同一组原始边界练习自动流程,先退出这次未完成搜索。bisect reset 清除搜索状态,返回开始时的分支和版本;它不会撤销提交:
git bisect reset
git branch --show-current
预期为 main。练习中若误判某版本,可通过同样的 reset 和重新开始,依据真实测试结果重做,而不丢弃文件。
让测试驱动搜索
重新开始,然后把同一条完整测试命令交给 bisect run。Git 使用每次原生退出状态自动选择 good 或 bad:
git bisect start incident-tip known-good
git bisect run python3 /opt/labex/quote-desk/check.py
预期会运行多次测试,并显示以 is the first bad commit 结尾的一行。搜索成功找到边界时,搜索命令本身以状态 0 结束,尽管部分单次报价测试失败。提交 ID 可能不同。
Git 的 bisect/bad 引用指向识别出的首个错误提交。当前 HEAD 仍可能是最后测试的正常版本;不要假定它就是报告的结果。读取实际候选提交的补丁。show 选择该提交及其补丁;-- 分隔文件路径:
git --no-pager show bisect/bad -- discounts.txt
FRIEND10 百分比从 10 变为 1。使用外部测试检查边界两侧。末尾的 ^ 选择提交的直接第一父提交,因此 bisect/bad^ 是候选提交之前紧邻的版本,而不是整个范围:
python3 /opt/labex/quote-desk/check.py --revision bisect/bad
python3 /opt/labex/quote-desk/check.py --revision bisect/bad^
预期候选提交失败,状态为 1;其父提交通过,状态为 0。 设置值与真实行为一致。为本检查点保持已完成搜索开启;接下来,你将先返回当前商店再编辑。
修复当前商店并交付报价
本步骤中,你将退出历史搜索,在当前分支提交范围集中的更正,并交付完整报价,同时保留后续商品和取货信息。
留在 Terminal 中,目录为 /home/labex/project/quote-desk/shop。使用已学过的搜索 reset 返回原分支:
git bisect reset
git branch --show-current
git --no-pager log -1 --oneline --decorate
git status --short
预期为 main、标有 incident-tip 的接手末端提交,且没有已更改文件输出。日志选项 -1 将输出限制为最新提交。不要修复分离的历史版本,也不要用 known-good 替换整个商店:后续有效工作也应保留在结果中。
读取小型优惠文件,以及必须保留的当前详情:
cat discounts.txt
cat welcome.txt pickup.txt care.txt
cat catalog.json
当前文件树包含 Trail pin、新欢迎语及周六截至 16:00 的取货信息。只有 FRIEND10 百分比错误。优惠文件每行包含一项 CODE=integer-percent 设置;TRAIL15 保持 15,STUDENT5 保持 5。
仅替换这个小文件。printf 按格式打印值:%s 表示文本,\n 在每个提供的值后添加换行。单引号保留字面文本。> 将输出写入指定文件,只替换该文件:
printf '%s\n' 'FRIEND10=10' 'TRAIL15=15' 'STUDENT5=5' > discounts.txt
查看实际更正。普通 diff 对比工作文件与索引,也就是 Git 的暂存区:
git --no-pager diff -- discounts.txt
预期只有 FRIEND10 从 1 恢复为 10。记录修复前,设置仓库本地提交身份。--local 避免改变全局配置;引号将含空格的姓名作为一个整体。这些虚构示例可以替换:
git config --local user.name "Little Pine Maintainer"
git config --local user.email "maintainer@little-pine.example"
使用 add 暂存该文件。使用 --cached 检查已暂存补丁,它对比索引与当前提交:
git add discounts.txt
git --no-pager diff --cached -- discounts.txt
提交范围集中的更正。-m 直接提供有意义的信息:
git commit -m "Restore the promised FRIEND10 discount"
与固定的接手末端提交对比。这是一个新的修正提交,会保留每个原始提交,而不是改写历史:
git --no-pager diff incident-tip HEAD
git --no-pager log -2 --oneline --decorate
git status --short
预期只有百分比更正,修复直接接在 incident-tip 之后,已跟踪状态干净。具体信息措辞和作者值不是成功标准。
对实际当前程序运行准备好的测试:
python3 /opt/labex/quote-desk/check.py
现在全部用例通过,状态为 0。生成顾客报价:
python3 quote.py ../orders/gift.order
预期包含当前杯子描述和欢迎语、数量 3、FRIEND10、小计 EUR 48.00、折扣 EUR 4.80、总价 EUR 43.20,以及当前截至周六 16:00 的取货信息。
将真实输出交付到准备好的 quotes 目录。按照之前所学,> 将标准输出保存到指定文件,不改变订单或程序:
python3 quote.py ../orders/gift.order > ../quotes/mug-gift.txt
cat ../quotes/mug-gift.txt
读取保存的完整报价,而不只是看文件名。文件是顾客可用的结果,提交则让修复可重复应用于后续订单。
检查仍须可用的正常订单和后续商品:
python3 quote.py ../orders/plain.order
python3 quote.py ../orders/new-item.order
普通杯子价格仍为 EUR 16.00。两个 Trail pin 使用 STUDENT5 时,小计 EUR 10.00、折扣 EUR 0.50、总价 EUR 9.50。两者均保留当前欢迎语和取货详情。检查点观察实际当前提交、保留的完整文件树、历史边界行为和交付报价;不评分命令记录或提交信息关键词。
总结
你使用正常和错误订单定义业务测试,手动判断历史版本,再通过 Git bisect 自动运行相同搜索。你区分了首个错误引用与 HEAD,验证候选提交及其父提交,返回 main,并提交范围集中的修复,没有丢失后续商店更新。顾客获得了完整正确的报价。
独立挑战更换了优惠码、顾客订单和故障位置,但使用相同的现成程序、规则和测试格式。请根据实际证据选择,而不是照搬提交偏移。



