git stash: কাজ অসমাপ্ত, কিন্তু জায়গা ছাড়তে হবে

সমস্যাটা যেখান থেকে আসে

আপনি feature branch-এ অর্ধেক কাজ করেছেন — কোড compile-ও হয় না এখনো — হঠাৎ production-এ বাগ, এক্ষুনি hotfix branch-এ যেতে হবে। কিন্তু:

  • Commit করবেন? অর্ধসমাপ্ত, ভাঙা কোড commit করতে মন চায় না
  • Checkout করবেন? Uncommitted পরিবর্তন নিয়ে branch বদলাতে Git প্রায়ই বাধা দেবে (conflict-এর ঝুঁকিতে)

git stash এই তৃতীয় দরজা: working directory আর staging-এর সব পরিবর্তন তুলে একটা তাকের উপর রেখে দেয়, আপনার working directory ফিরে যায় পরিষ্কার HEAD-এর অবস্থায়।

git stash                      # সব uncommitted পরিবর্তন তাকে তুলুন
# ... hotfix করুন, deploy করুন ...
git checkout feature-x
git stash pop                  # তাক থেকে নামিয়ে কাজ চালিয়ে যান

ভেতরে কী — তাক-টা আসলে commit!

চেনা প্যাটার্ন: Git-এ প্রায় সবকিছুই commit। Stash-ও ব্যতিক্রম নয় — ভেতরে ভেতরে Git আপনার working directory আর index-এর snapshot নিয়ে বিশেষ commit বানায়, শুধু সেটা কোনো branch-এ থাকে না — থাকে refs/stash নামের আলাদা reference-এ, stack (LIFO) আকারে:

git stash list
# stash@{0}: WIP on feature-x: a3f5c9d Add discount service   ← সর্বশেষ
# stash@{1}: WIP on main: e4f5g6h Update readme

এ কারণেই stash-করা কাজও reflog-দর্শনে "নিরাপদ" — commit হয়ে গেছে মানে Git-এর object store-এ ঢুকে গেছে।

কাজের কয়েকটা রূপ:

git stash push -m "discount WIP - half-done validation"   # নাম দিন! পরে চিনবেন
git stash push OrderService.java                          # শুধু নির্দিষ্ট ফাইল
git stash show -p stash@{0}                               # ভেতরে কী আছে দেখুন
git stash branch rescue-branch stash@{0}                  # stash থেকে সরাসরি নতুন branch

শেষেরটা লুকানো রত্ন: stash করার পর মূল branch অনেক এগিয়ে গেলে pop-এ conflict হতে পারে — stash branch তখন যে-commit-এ stash করেছিলেন সেখান থেকেই branch বানিয়ে stash apply করে দেয়, conflict-এর সম্ভাবনা শূন্য।


pop বনাম apply: এক অক্ষরের পার্থক্য, এক দুর্ঘটনার দূরত্ব

দুটোই stash-এর পরিবর্তন working directory-তে ফিরিয়ে আনে। পার্থক্য শুধু তারপর কী হয়:

git stash pop git stash apply
পরিবর্তন ফেরায়
Stash তালিকা থেকে মুছে দেয় ❌ — stash থেকে যায়
উপমা তাক থেকে নামিয়ে আনা তাকের জিনিসের ফটোকপি নেওয়া

কখন কোনটা:

  • pop — স্বাভাবিক, এক-জায়গায়-ফেরত workflow। কাজ ফিরে পেলেন, তাক পরিষ্কার।
  • apply — যখন stash-টা রাখতে চান: একই পরিবর্তন একাধিক branch-এ লাগবে (যেমন একটা debug-config দুই জায়গায় পরীক্ষা করবেন), বা ঝুঁকিপূর্ণ অবস্থায় সাবধানি সংস্করণ হিসেবে।

সূক্ষ্ম কিন্তু জরুরি আচরণ: pop-এ যদি conflict হয় (stash-এর পর ওই ফাইলগুলো বদলে গেছে), Git পরিবর্তন apply করে marker বসাবে ঠিকই — কিন্তু stash-টা মুছবে না। এটা আসলে সুরক্ষা: conflict-সমাধান ভজঘট হলেও মূল stash অক্ষত। conflict মিটিয়ে নিজে git stash drop করতে হবে।

আর ভুল করে দরকারি stash pop/drop করে ফেললে? এতক্ষণের অভ্যাসমতো — ঘাবড়াবেন না, stash তো commit-ই ছিল:

git fsck --unreachable | grep commit    # এতিম stash-commit খুঁজুন
git stash apply <hash>                  # বা cherry-pick জাতীয় উদ্ধার

(এরা branch-reflog-এ থাকে না বলে fsck-ই ভরসা — আরেকটা কারণ গুরুত্বপূর্ণ কাজে stash নয়, আসল commit।)


Untracked ফাইল: ডিফল্টে stash-এর চোখের আড়ালে

এটা সবচেয়ে বড় stash-বিভ্রান্তি, আর interview-প্রশ্নের তৃতীয় অংশ। ডিফল্ট git stash নেয় শুধু tracked ফাইলের পরিবর্তন — staged + unstaged। কিন্তু:

  • নতুন বানানো, কখনো git add হয়নি এমন ফাইল → stash ছোঁবেই না, working directory-তে পড়ে থাকবে
  • .gitignore-করা ফাইল → অবশ্যই না

ফাঁদটা বাস্তবে যেভাবে ধরা দেয়: নতুন class-ফাইল সহ feature-এর কাজ stash করলেন, branch বদলালেন — নতুন ফাইলটা এই branch-এও ঘুরছে, ভুল branch-এর build-এ ঢুকে বিভ্রান্তি।

সমাধান — দুই স্তরের flag:

git stash -u                   # --include-untracked: নতুন ফাইলও নাও
git stash -a                   # --all: ignored ফাইল সহ সব — খুব কমই লাগে
কী stash হয় (ডিফল্ট) -u -a
Tracked পরিবর্তন
Untracked নতুন ফাইল
Ignored (build/, .env...)

ব্যবহারিক অভ্যাস: git stash -u-ই আপনার ডিফল্ট হোক — "নতুন ফাইল রয়ে গেছে" বিভ্রান্তিটা আর হবে না। -a সাবধানে — target/, node_modules জাতীয় দৈত্য stash-এ ঢুকিয়ে অকারণ ভার।

আরেকটা কাজের flag উল্টোদিকে: git stash --keep-index — staged জিনিস রেখে শুধু unstaged stash করে; "commit-এর জন্য যা সাজিয়েছি তা ঠিক আছে কি না একা টেস্ট করি" — এই কাজে দারুণ।


Stash বনাম WIP-commit — সৎ তুলনা

সিনিয়র উত্তরে এটুকু যোগ করলে পূর্ণতা পায়: stash-এর প্রতিযোগী হলো স্রেফ একটা WIP commit (git commit -m "WIP" — পরে reset --soft বা rebase -i fixup দিয়ে গোছানো, যেগুলো আগেই শিখেছি)। Stash জিতবে দ্রুত, ক্ষণস্থায়ী context-switch-এ; WIP-commit জিতবে কাজটা কয়েক ঘণ্টার বেশি রাখতে হলে — কারণ commit branch-এর সাথে বাঁধা, নামধারী, push-যোগ্য (ব্যাকআপ!), আর stash-stack-এ stash@{3}-এর মতো নামহীন জঞ্জাল জমে হারিয়ে যাওয়ার জিনিস। Stash তাক, commit সিন্দুক।

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

"Stash হলো uncommitted কাজ (staged+unstaged) branch-নিরপেক্ষ একটা LIFO তাকে তুলে working directory পরিষ্কার করা — ভেতরে এগুলো আসলে refs/stash-এ রাখা বিশেষ commit; pop = apply + তালিকা থেকে মোছা (তবে conflict হলে মোছে না — সুরক্ষা), apply = কপি রেখে লাগানো — একাধিক জায়গায় লাগবে বা সাবধান থাকতে চাইলে apply; আর ডিফল্ট stash নতুন untracked ফাইল নেয়ই না — সেজন্য -u, ignored-সহ চাইলে -a; দীর্ঘমেয়াদে রাখতে হলে অবশ্য stash নয়, WIP-commit।"

Share