ভুল Branch-এ Commit: উদ্ধার অভিযান

খুবই সাধারণ দুর্ঘটনা — main-এ আছেন ভুলে গেছেন, কাজ শেষ করে commit-ও দিয়ে ফেলেছেন। সুখবর: আগের আলোচনাগুলোর অস্ত্রগুলো দিয়েই এটা মেটে, আর সমাধানটা নির্ভর করে তিনটা প্রশ্নের উত্তরে:

  1. Push হয়ে গেছে কি?
  2. যে branch-এ যাওয়ার কথা ছিল সেটা আছে, নাকি বানাতে হবে?
  3. কয়টা commit?

দৃশ্য ১: Push হয়নি, সঠিক branch এখনো নেই (সবচেয়ে সহজ)

আপনি main-এ commit করেছেন, আসলে চেয়েছিলেন নতুন feature branch। মজার ব্যাপার — কাজ ইতিমধ্যেই সঠিক জায়গায় আছে, শুধু ভুল লেবেল লাগানো। প্রথম আলোচনা মনে করুন: branch তো স্রেফ pointer।

git branch feature-x          # এখানেই নতুন pointer — commit-টা এখন দুই নামে
git reset --hard HEAD~1       # main-কে এক ধাপ পেছনে টানুন
git checkout feature-x        # কাজ চালিয়ে যান

ছবিতে:

আগে:   A---B---C   main            (C ভুল জায়গায়)
পরে:   A---B       main
              \
               C   feature-x       (C এখন সঠিক ঘরে)

--hard এখানে নিরাপদ কারণ C-এর দিকে feature-x pointer তাক করা আছে — commit পরিত্যক্ত হচ্ছে না। তবে reset-আলোচনার সতর্কতা মনে রাখুন: working directory-তে uncommitted কাজ থাকলে আগে git stash, নয়তো সেটা হারাবে।

আরো ছোট সংস্করণ (নতুন Git-এ):

git switch -c feature-x       # commit সহই নতুন branch-এ চলে গেলেন
git branch -f main HEAD~1     # main-কে পেছনে বসিয়ে দিন

দৃশ্য ২: Push হয়নি, সঠিক branch আগে থেকেই আছে

এবার শুধু pointer সরালে হবে না — commit-টাকে অন্য branch-এর মাথায় replay করতে হবে। চেনা লাগছে? এটাই cherry-pick-এর আরেকটা ক্লাসিক ব্যবহার (সেই আলোচনায় এক লাইনে বলেছিলাম):

git log -1                    # ভুল commit-এর hash টুকে নিন (ধরুন c3d4e5f)
git checkout feature-x
git cherry-pick c3d4e5f       # সঠিক branch-এ কপি (নতুন hash-এ)
git checkout main
git reset --hard HEAD~1       # ভুল জায়গা থেকে সরান
আগে:   A---B---C        main       D---E   feature-x
পরে:   A---B            main       D---E---C'   feature-x

খেয়াল করুন C আর C′ — cherry-pick-আলোচনার সেই সত্য: এটা কপি নয়, নতুন commit, কারণ parent বদলেছে।

একাধিক commit হলে:

git cherry-pick <প্রথম-hash>^..<শেষ-hash>   # range
git checkout main
git reset --hard HEAD~3                      # তিনটা হলে তিন ধাপ

ক্রম গুরুত্বপূর্ণ: আগে cherry-pick, পরে reset। উল্টো করলে সাময়িকভাবে commit-গুলো pointer-হীন হয়ে যায় — reflog থেকে উদ্ধারযোগ্য ঠিকই, কিন্তু অকারণ ঝুঁকি কেন নেবেন।


দৃশ্য ৩: Push হয়ে গেছে ⚠️

এখানেই আগের দুই আলোচনার সেই সোনালি নিয়ম সিদ্ধান্ত নিয়ে নেয়। প্রশ্ন করুন: branch-টা কি shared/protected?

ক) Shared branch (যেমন main) — revert-এর রাস্তা:

# ১. কাজটা সঠিক branch-এ নিন
git checkout feature-x
git cherry-pick c3d4e5f

# ২. ভুল branch-এ reset নয় — revert
git checkout main
git revert c3d4e5f
git push

main-এর history-তে থাকবে: ভুল commit + তার revert — দেখতে একটু অগোছালো, কিন্তু কারো লোকাল ভাঙে না, force-push নেই, CI/PR flow অক্ষত। Reset + force-push করলে রাফি-দুর্ঘটনার পুরো চিত্রনাট্য আবার — আর protected branch হলে সে দরজা এমনিতেই বন্ধ।

খ) নিজের প্রাইভেট branch-এ push করেছেন (যেমন নিজের PR branch, কেউ ছোঁয়নি): দৃশ্য ১/২-এর মতোই reset করে

git push --force-with-lease

— rebase-আলোচনার সেই সিটবেল্ট সহ।


বোনাস: commit-ই করেননি, শুধু ভুল branch-এ এডিট করছেন

সবচেয়ে মধুর সংস্করণ — কিছুই করতে হয় না প্রায়:

git switch -c feature-x    # অথবা বিদ্যমান branch হলে: git switch feature-x

Uncommitted পরিবর্তন সাধারণত switch-এর সাথেই যায়। Git বাধা দিলে (conflict-এর সম্ভাবনায়):

git stash
git switch feature-x
git stash pop

ভবিষ্যতে যেন না হয়

সিনিয়র উত্তরের শেষাংশ — প্রতিরোধ:

  • Shell prompt-এ branch-এর নাম (Starship, oh-my-zsh, বা IntelliJ-র status bar) — অর্ধেক দুর্ঘটনা এখানেই শেষ
  • Branch protection: main-এ সরাসরি push নিষিদ্ধ করলে ভুল commit push-ই হতে পারবে না — CI-ও ধরবে
  • অভ্যাস: কাজ শুরুর আগে git status-এ এক পলক — কোথায় আছি?

এক লাইনে (interview-সংস্করণ)

"মূলনীতি: commit তো graph-এ ঠিকই আছে, শুধু pointer-গুলো ঠিক করতে হবে — branch না থাকলে ওখানেই git branch বানিয়ে ভুল branch-কে reset; branch থাকলে সঠিকটায় cherry-pick করে ভুলটায় reset; আর push হয়ে গেলে সোনালি নিয়ম — নিজের branch হলে reset + --force-with-lease, shared branch হলে reset ছুঁয়েও দেখা নয়, revert।"

Share