git bisect: যে কমিট কোড ভেঙেছে তা কীভাবে খুঁজে বের করবেন
git bisect বাইনারি সার্চের মাধ্যমে ইতিহাস ঘেঁটে সেই কমিট খুঁজে বের করে, যেখানে ভুলটি প্রথম ঢুকেছে। git bisect start চালান, খারাপ কমিটকে git bisect bad এবং নির্ভুলভাবে কাজ করা কমিটকে git bisect good <হ্যাশ> দিয়ে চিহ্নিত করুন, তারপর Git যে কমিটগুলো দেখায় সেগুলো যাচাই করুন, যতক্ষণ না দোষী কমিট নাম পায়; শেষে git bisect reset।
git bisect বাইনারি সার্চের পদ্ধতিতে সেই কমিট খোঁজে, যা ভুলটি ঢুকিয়েছে। আপনি একটি কমিট দেন যেখানে বাগ আছে, আর একটি যেখানে ছিল না। Git আপনাকে দুইয়ের মাঝখানে নিয়ে যায় এবং জিজ্ঞেস করে: "এখানে ঠিক আছে, না ভুল?" প্রতিটি উত্তর অর্ধেক প্রার্থী বাদ দেয়, তাই এক হাজার কমিটের মধ্যে দোষীকে প্রায় ১০ বার যাচাই করে পাওয়া যায়।
এটি বিশেষভাবে মূল্যবান, যখন ভুলটি সহজে বোঝা যায় না: টেস্ট ফেল করছে, পারফরম্যান্স কমেছে, লেআউট ভেঙেছে, অথচ diff দেখে কিছু বোঝা যাচ্ছে না। শত শত পরিবর্তন না পড়ে একই সরল প্রশ্নটি কয়েকবার করলেই হয়।
ইতিহাসে বাইনারি সার্চ কীভাবে কাজ করে
ধরুন, কাজ করা সংস্করণ v2.3 আর বর্তমান main-এর মাঝে ২০০টি কমিট আছে। Git মাঝের কমিটটি যাচাই করতে দেয়। সেখানে ভুল থাকলে ভুলটি প্রথম অর্ধেকে ঢুকেছে, না থাকলে দ্বিতীয় অর্ধেকে। প্রতি ধাপে প্রার্থীর সংখ্যা অর্ধেক হয়: ২০০, ১০০, ৫০, ২৫, ১৩, ৭, ৪, ২, ১। দুশো কমিটের বদলে আট বার যাচাই।
এর জন্য মূল শর্ত: "ভাঙা" অবস্থাটি ধারাবাহিক হতে হবে। ভুল এসে গেলে, মিলিয়ে গেলে, আবার এলে bisect একটি পরিবর্তন খুঁজে দেবে, কিন্তু সেটি আপনার দরকারেরটি নাও হতে পারে।
git bisect ধাপে ধাপে: ম্যানুয়াল মোড
১. একটি ভালো ও একটি খারাপ কমিট খুঁজুন
খারাপটি সাধারণত বর্তমান HEAD। ভালো হলো যেকোনো কমিট, যেখানে নিশ্চিতভাবে সবকিছু কাজ করত: গত রিলিজের ট্যাগ, এক সপ্তাহ আগের কমিট। প্রার্থী খুঁজতে কাজে লাগবে git log --oneline, git tag বা git log --since="2 weeks ago"।
২. সেশন শুরু করুন
git bisect start
git bisect bad # বর্তমান কমিট ভাঙা
git bisect good v2.3 # রিলিজ v2.3-এ সবকিছু কাজ করত
Bisecting: 99 revisions left to test after this (roughly 7 steps)
[4f5e6d7c...] ফ্রন্টএন্ডের ডিপেনডেন্সি আপডেট
একই কাজ এক লাইনে: git bisect start HEAD v2.3 — প্রথমে খারাপ, তারপর ভালো। Git সঙ্গে সঙ্গে ওয়ার্কিং ডিরেক্টরি মাঝের কমিটে সরিয়ে দেয় (detached HEAD অবস্থায়)।
৩. যাচাই করুন এবং চিহ্নিত করুন
প্রকল্প বিল্ড করুন, টেস্ট চালান, বা হাতে বাগটি পুনরুৎপাদন করুন। তারপর ফলাফল জানান:
git bisect good # এখানে কাজ করছে
Bisecting: 49 revisions left to test after this (roughly 6 steps)
git bisect bad # এখানে ভাঙা
Bisecting: 24 revisions left to test after this (roughly 5 steps)
৪. ফলাফল পান
একটি মাত্র প্রার্থী বাকি থাকলে Git সেটি দেখায়:
a1b2c3d4e5f6... is the first bad commit
commit a1b2c3d4e5f6...
Author: Rafiq Hossain <rafiq@example.com>
Date: Tue Sep 29 11:40:12 2026 +0300
কার্টের হিসাব ক্যাশে রাখা
src/cart.js | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
৫. সেশন শেষ করুন
git bisect reset
কমান্ডটি আপনাকে যে ব্রাঞ্চ থেকে শুরু করেছিলেন সেখানে ফিরিয়ে আনে। এই ধাপ ভুলবেন না: সেশন বন্ধ না হওয়া পর্যন্ত আপনি detached HEAD-এ থাকেন, এবং নতুন কমিট সহজেই হারিয়ে যেতে পারে। git bisect reset HEAD আপনাকে পাওয়া কমিটেই রাখে, আর git bisect reset <কমিট> নির্দিষ্ট যেকোনো কমিটে।
স্বয়ংক্রিয় অনুসন্ধান: git bisect run
যাচাইটি একটি কমান্ড দিয়ে লেখা গেলে পুরো কাজটি Git-কে দিন। git bisect run প্রতি ধাপে একটি স্ক্রিপ্ট চালায় এবং রিটার্ন কোড দেখে নিজেই চিহ্নিত করে:
| রিটার্ন কোড | অর্থ |
|---|---|
| 0 | good — কমিট ভালো |
| 1–127, 125 বাদে | bad — কমিট খারাপ |
| 125 | skip — কমিট যাচাই করা সম্ভব নয়, বাদ দাও |
| 127-এর বেশি (বা <0) | bisect বন্ধ করা (যেমন স্ক্রিপ্ট সিগন্যালে ভেঙে গেছে) |
চালানোর উদাহরণ:
git bisect start HEAD v2.3
git bisect run npm test
git bisect run pytest tests/test_cart.py -x
git bisect run make check
জটিল যাচাইয়ের জন্য ছোট একটি স্ক্রিপ্ট লিখুন। গুরুত্বপূর্ণ হলো "বিল্ড হয়নি" আর "বাগ পুনরুৎপাদিত হয়েছে" আলাদা করা, নইলে bisect ভাঙা বিল্ডকে খোঁজা বাগ ভেবে বসবে:
#!/bin/sh
# check.sh
npm ci --silent || exit 125 # ডিপেনডেন্সি বসাতে ব্যর্থ — বাদ দাও
npm run build || exit 125 # বিল্ড হয়নি — বাদ দাও
node scripts/check-cart-total.js # 0 — ঠিক আছে, 1 — বাগ
chmod +x check.sh
git bisect run ./check.sh
স্ক্রিপ্টটি ট্র্যাক করা ফাইলের বাইরে বা এমন ফোল্ডারে রাখুন, যা সব যাচাই করা কমিটে আছে: bisect ওয়ার্কিং ডিরেক্টরি বদলায়, তাই সম্প্রতি যোগ করা ফাইল পুরনো কমিটে হারিয়ে যাবে। সবচেয়ে নিরাপদ হলো স্ক্রিপ্টটি /tmp বা রিপোজিটরির বাইরের যেকোনো ফোল্ডারে রাখা।
এমন টেস্ট যা আগে ছিল না
একটি সাধারণ পরিস্থিতি: আপনি বাগটি পুনরুৎপাদনকারী টেস্ট লিখেছেন, কিন্তু পুরনো কমিটে ফাইলটি নেই। সমাধান একই, রিপোজিটরির বাইরে একটি কপি রাখুন:
cp tests/test_regression.py /tmp/
git bisect run pytest /tmp/test_regression.py
git bisect skip: যখন কমিট যাচাই করা যায় না
কখনো মাঝের কমিট বিল্ড হয় না, বা অন্য কারণে ভেঙে পড়ে। সেটিকে good বা bad চিহ্নিত করা যাবে না, তাতে ফল ভুল হবে। তাই সেটি বাদ দিন:
git bisect skip
git bisect skip v2.4..v2.4.3 # একটি পরিসর বাদ দেওয়া
Git তখন পাশের কমিট বেছে নেয়। বাদ দেওয়া কমিটগুলো যদি সীমানায় পড়ে, শেষে একটির বদলে "সম্ভাব্য দোষীদের" তালিকা দেখাবে; তখন তাদের diff হাতে দেখুন।
good ও bad-এর বদলে নিজের শব্দ
bisect শুধু বাগ খোঁজে না। ধরুন, আপনি জানতে চান কোন কমিটের পর পেজ দ্রুত লোড হতে শুরু করেছে। দ্রুত কমিটগুলোকে "খারাপ" বলা বিভ্রান্তিকর, তাই বিকল্প শব্দ আছে:
git bisect start --term-old=slow --term-new=fast
git bisect fast HEAD
git bisect slow v2.3
বিল্ট-ইন সমার্থক শব্দ old ও new: git bisect new, git bisect old। নিয়ম একটাই: "পুরনো" অবস্থাটি আগের কমিটে থাকতে হবে।
সেশনের লগ: log, replay, visualize
git bisect log— আপনার সব চিহ্ন দেখায়। সেশন দীর্ঘ হলে ফাইলে সংরক্ষণ করুন।git bisect replay ফাইল— লগ থেকে সেশন আবার চালায়। ষষ্ঠ ধাপে ভুল করেছেন? লগ সংরক্ষণ করুন, ভুল লাইন মুছুন,git bisect resetদিন এবংreplayচালান।git bisect visualize(বাgit bisect view) — বাকি প্রার্থীদের দেখায়;--onelineদিলে git log দিয়ে দেখায়।
git bisect log > /tmp/bisect.log
# লগ সম্পাদনা
git bisect reset
git bisect replay /tmp/bisect.log
Bisect ও merge কমিট
অনেক merge-সম্বলিত ইতিহাসে bisect আপনাকে একটি মার্জ করা শাখার ভেতরে নিয়ে যেতে পারে: সেই কমিটগুলোতে, যেগুলো main-এর সঙ্গে মেলানোর আগে তৈরি হয়েছিল এবং তাই ভিন্ন ভিত্তিতে দাঁড়িয়ে। আগে বুঝতে চাইলে কোন merge বাগ এনেছে, ব্যবহার করুন:
git bisect start --first-parent
তখন Git শুধু merge কমিটের প্রথম প্যারেন্ট ধরে এগোয়, অর্থাৎ মূল ব্রাঞ্চের ইতিহাস ধরে। দোষী merge পাওয়া গেলে সংশ্লিষ্ট শাখার ভেতরে দ্বিতীয় bisect চালানো যায়।
সাধারণ ভুল
- good ও bad উল্টে ফেলা। ফলাফল অর্থহীন হবে।
git bisect logওreplayদিয়ে সেশন ঠিক করুন, নতুন করে শুরু না করেই। - অপরিষ্কার ওয়ার্কিং ডিরেক্টরি। অকমিট করা পরিবর্তন কমিট বদলে বাধা দেয় এবং যাচাইকে প্রভাবিত করে। শুরুর আগে কমিট বা
git stashকরুন। - বিল্ডের অবশিষ্ট ফাইল। অন্য কমিটের পুরনো ক্যাশ বা
node_modulesভুল ফল দেয়। স্ক্রিপ্টে পরিষ্কার বিল্ড করুন। - অস্থির (flaky) টেস্ট। টেস্ট নিজে থেকে মাঝে মাঝে ফেল করলে bisect একটি এলোমেলো কমিট ধরে নেবে। কয়েকবার চালান, অথবা খোঁজার আগে টেস্টটি ঠিক করুন।
- reset ভুলে যাওয়া। detached HEAD-এ থেকে কাজ শুরু করলেন। হারানো কমিট খুঁজতে reflog সাহায্য করবে।
উদাহরণ: শুরু থেকে শেষ পর্যন্ত একটি রিগ্রেশন খোঁজা
ব্যবহারকারীরা জানাচ্ছেন ডিসকাউন্ট থাকলে কার্টের মোট হিসাব ভুল আসছে। v2.3 রিলিজে সব ঠিক ছিল, main-এ নেই। একটি সংক্ষিপ্ত যাচাই লিখে অনুসন্ধান চালাই:
cat > /tmp/check.sh <<'SH'
#!/bin/sh
npm ci --silent || exit 125
node -e "const c=require('./src/cart'); process.exit(c.total([{price:100}], 0.1) === 90 ? 0 : 1)"
SH
chmod +x /tmp/check.sh
git stash # অকমিট করা পরিবর্তন সরানো
git bisect start HEAD v2.3
git bisect run /tmp/check.sh
...
a1b2c3d4e5f6... is the first bad commit
git bisect log > /tmp/cart-bisect.log
git bisect reset
git stash pop
একশো কমিটের পুরো অনুসন্ধান আপনার হস্তক্ষেপ ছাড়াই চলে, আপনি অন্য কাজ করতে পারেন। সংরক্ষিত লগ কাজে লাগে, যখন সহকর্মীদের দেখাতে হয় দোষীকে কীভাবে পাওয়া গেল।
খুঁজে পাওয়া কমিট দিয়ে কী করবেন
দোষী কমিট পাওয়ার পর পুরোটা দেখুন: git show a1b2c3d। একটি ছোট কমিট, যার স্পষ্ট বার্তা আছে, সঙ্গে সঙ্গে কারণ বলে দেয়। এ কারণেই দলগুলো ছোট, অবিভাজ্য কমিট পছন্দ করে: "fix stuff" ধরনের বিশাল কমিট থেকে bisect প্রায় কাজে আসে না। এরপর দুটি পথ: নতুন কমিটে ভুল ঠিক করা, অথবা পুরো পরিবর্তনটি ব্যর্থ হলে এবং প্রকাশিত হয়ে গেলে git revert a1b2c3d দিয়ে বাতিল করা।
সারসংক্ষেপ
git bisect রিগ্রেশন খোঁজাকে শত শত ডিফ পড়া থেকে কয়েকটি "কাজ করছে / করছে না" উত্তরে নামিয়ে আনে, আর git bisect run দিয়ে তা একটি কমান্ডে। প্রয়োজন শুধু দুটি মাইলফলক, একটি ভালো ও একটি খারাপ কমিট, এবং একটি পুনরুৎপাদনযোগ্য যাচাই। ইতিহাস পড়া, কমিটে নেভিগেট করা ও তাতে ভুল খোঁজা Git কোর্সে বাস্তব অনুশীলনে শেখানো হয়।
সাধারণ প্রশ্ন
git bisect কয়টি ধাপে শেষ হয়?
মোটামুটি কমিটের সংখ্যার log2: ১০০টি কমিটের জন্য প্রায় ৭ ধাপ, ১০০০টির জন্য প্রায় ১০। Git নিজেই roughly N steps বলে অনুমান দেখায়।
ভালো কমিট না জানলে কি bisect চালানো যায়?
অন্তত একটি লাগে। একটি নিশ্চিতভাবে পুরনো কমিট বা রিলিজ ট্যাগ নিন এবং হাতে যাচাই করুন; বিস্তৃত পরিসরে বাড়তি ধাপ খুব সামান্য খরচ।
git bisect কি রিপোজিটরির ইতিহাস বদলায়?
না। এটি শুধু কমিটের মধ্যে ওয়ার্কিং ডিরেক্টরি সরায় এবং চিহ্নগুলো refs/bisect-এর অস্থায়ী রেফারেন্সে রাখে, যা git bisect reset দিলে মুছে যায়।
একাধিক ভালো কমিট দেওয়া যায় কি?
হ্যাঁ, git bisect good-এ একাধিক কমিট দেওয়া যায়। এতে পরিসর আরও সংকীর্ণ হয়, বিশেষত শাখাযুক্ত ইতিহাসে।
bisect কি শুধু বাগ খোঁজার জন্য?
না, যেকোনো পরিবর্তনের মুহূর্ত খোঁজা যায়: কখন ফাইল এল, কখন বিল্ড দ্রুত হলো, কখন আচরণ বদলাল। এর জন্য old/new শব্দ বা --term-old ও --term-new সুবিধাজনক।
“শূন্য থেকে আত্মবিশ্বাসী ডেভেলপার পর্যন্ত গিট” কোর্সে বিষয়টি অনুশীলনসহ বিস্তারিত শেখানো হয়েছে।
কোর্সে যান