Fast-Forward Merge কী?
আগের উদাহরণগুলোতে দুই branch দুই দিকে এগিয়েছিল। কিন্তু ধরুন পরিস্থিতি এমন:
D---E---F main
\
A---B---C feature
আপনি feature branch বানানোর পর main-এ নতুন কোনো commit আসেনি। feature-এর history-তে main-এর সব commit ইতিমধ্যেই আছে — main হলো feature-এর সরাসরি পূর্বপুরুষ (ancestor)।
এখন git merge feature করলে Git দেখে: "মার্জ করার তো কিছুই নেই, দুই লাইনের মধ্যে কোনো divergence-ই হয়নি।" তাই কোনো merge commit না বানিয়ে Git শুধু main-এর pointer-টা সামনে সরিয়ে C-তে নিয়ে যায়:
D---E---F---A---B---C main, feature
এটাই fast-forward। প্রথম আলোচনার কথা মনে করুন — branch যেহেতু শুধুই একটা pointer, তাই এখানে "merge" মানে আক্ষরিক অর্থে একটা ফাইলে নতুন hash লেখা। কোনো নতুন commit তৈরি হয় না, কোনো conflict সম্ভবই না। এজন্যই নাম fast-forward।
লক্ষ্য করুন: rebase করার পর merge করলে সবসময় fast-forward হয় — কারণ rebase-ই তো feature-কে main-এর মাথায় বসিয়ে দেয়, ফলে linear অবস্থা তৈরি হয়ে যায়।
সমস্যাটা কোথায়?
Fast-forward-এর পর history দেখে বোঝার উপায় নেই যে A, B, C কখনো একটা আলাদা feature branch ছিল। সব commit main-এর সরল লাইনে মিশে গেছে। তিনটা commit মিলে যে একটা logical unit — একটা feature — ছিল, সেই তথ্যটা হারিয়ে যায়।
--no-ff কেন ইচ্ছাকৃতভাবে ব্যবহার করবেন
git merge --no-ff feature
এটা Git-কে বলে: "fast-forward সম্ভব হলেও কোরো না, জোর করে একটা merge commit বানাও।"
D---E---F---------M main
\ /
A---B---C feature
এখন history-তে "bump"-টা রয়ে গেল। কেন এটা চাইবেন:
১. Feature-এর সীমানা দৃশ্যমান থাকে। git log --graph-এ পরিষ্কার দেখা যায় কোন commit-গুলো কোন feature-এর অংশ। ছয় মাস পরে "এই ফিচারটা কী কী commit নিয়ে এসেছিল?" প্রশ্নের উত্তর merge commit-টাই দিয়ে দেয়।
২. পুরো feature এক কমান্ডে revert করা যায়। এটাই সবচেয়ে বড় ব্যবহারিক কারণ। Feature-টা production-এ সমস্যা করলে:
git revert -m 1 <merge-commit-hash>
এক ধাক্কায় পুরো feature undo। Fast-forward হয়ে থাকলে A, B, C আলাদা আলাদা revert করতে হতো, আর মাঝে অন্য কাজ ঢুকে গেলে সেটা আরো জটিল।
৩. Merge commit-টা metadata-র জায়গা। PR নম্বর, reviewer, ticket ID — সব ওখানে থাকে। GitHub-এর "Create a merge commit" অপশন আসলে --no-ff-ই করে, এজন্যই merge commit-গুলোতে "Merge pull request #123..." লেখা দেখেন।
বিখ্যাত git-flow মডেল এই কারণেই সব feature merge-এ --no-ff বাধ্যতামূলক করেছিল।
উল্টো দিক: fast-forward-ই যখন কাম্য
সবসময় --no-ff ভালো — তা না। যেখানে fast-forward-ই চাইবেন:
git pull-এ: origin/main-এ নতুন commit এসেছে, আপনার লোকালে কিছু নেই — এখানে merge commit বানানো অর্থহীন আবর্জনা। বরং অনেকেgit config pull.ff onlyসেট করেন, যাতে fast-forward সম্ভব না হলে pull ব্যর্থ হয় এবং আপনি সচেতনভাবে সিদ্ধান্ত নিতে পারেন।- Squash-merge workflow-তে: feature পুরোটা এক commit হয়ে main-এ ঢুকছে — তখন branch-boundary রাখার প্রশ্নই নেই, ওই এক commit-ই পুরো feature।
সারমর্ম
| Fast-forward | --no-ff |
|
|---|---|---|
| নতুন commit | হয় না, শুধু pointer সরে | merge commit তৈরি হয় |
| History | সরলরেখা, branch-এর চিহ্ন নেই | branch-এর কাঠামো সংরক্ষিত |
| Feature revert | commit ধরে ধরে | এক কমান্ডে |
| উপযুক্ত | pull, sync, ছোটখাটো আপডেট | feature/release merge |
Interview-তে এক লাইনে বলতে চাইলে: "Fast-forward হলো merge-এর নামে শুধু pointer সরানো; --no-ff দিয়ে আমরা ইচ্ছাকৃতভাবে merge commit রাখি যাতে feature-এর সীমানা history-তে টিকে থাকে এবং প্রয়োজনে পুরো feature-টা atomically revert করা যায়।"