git push: পরিবর্তন রিমোট রিপোজিটরিতে কীভাবে পাঠাবেন
git push লোকাল ব্রাঞ্চের যেসব কমিট সার্ভারে নেই, সেগুলো রিমোটে পাঠায় এবং সেখানে ব্রাঞ্চের পয়েন্টার সরায়। প্রথমবার ব্রাঞ্চ পাঠাতে git push -u origin ব্রাঞ্চ-নাম, এরপর শুধু git push। সার্ভারে অন্যের কমিট থাকলে আগে git pull দিয়ে সেগুলো নিন, force push নয়।
git push কী করে
git push বর্তমান লোকাল ব্রাঞ্চের সেই কমিটগুলো নেয়, যেগুলো সার্ভারে নেই, সেগুলো দূরবর্তী রিপোজিটরিতে (সাধারণত নাম origin) পাঠায় এবং সেখানে ব্রাঞ্চের পয়েন্টারকে আপনার সর্বশেষ কমিটে সরায়। কাজের ফোল্ডারের ফাইল বা অকমিট পরিবর্তন কোথাও যায় না: যায় শুধু ইতিহাস, মানে কমিট।
মনে রাখুন, push "সিঙ্ক" নয়। এটি এক দিকে কাজ করে: লোকাল থেকে রিমোটে। অন্যদের পরিবর্তন পেতে লাগে git fetch বা git pull। এই দিকনির্দেশ গুলিয়ে ফেললে নতুনদের বেশিরভাগ সমস্যা আসে।
Git-এর আরেকটি নিয়ম: ডিফল্টে push শুধু "এগিয়ে যাওয়া" (fast-forward) হিসেবে গ্রহণ করা হয়। সার্ভার আপনার কমিট নেবে যদি সেগুলো সার্ভারের বিদ্যমান ইতিহাসকে এগিয়ে নেয়। অন্য কেউ আগে তাঁর কমিট পাঠিয়ে থাকলে আপনার push প্রত্যাখ্যাত হবে: এটি ত্রুটি নয়, এটি সুরক্ষা।
সিনট্যাক্স
git push [<remote>] [<লোকাল-ব্রাঞ্চ>[:<রিমোট-ব্রাঞ্চ>]]
আর্গুমেন্ট ছাড়া git push বর্তমান ব্রাঞ্চকে তার upstream (অনুসরণকারী) ব্রাঞ্চে পাঠায়। স্পষ্ট রূপটি কাজে লাগে যখন upstream এখনো সেট হয়নি, অথবা ব্রাঞ্চ অন্য নামে পাঠাতে চান:
git push origin main # লোকাল main-কে origin/main-এ পাঠানো
git push origin feature/login # feature/login ব্রাঞ্চ পাঠানো
git push origin fix:hotfix-123 # লোকাল fix-কে সার্ভারে hotfix-123 নামে
git push origin HEAD # বর্তমান ব্রাঞ্চ একই নামে
প্রথমবার পরিবর্তন পাঠানো
নতুন প্রকল্প থেকে GitHub বা GitLab-এর কোড পর্যন্ত পথটি এমন। আগে সার্ভারে একটি ফাঁকা রিপোজিটরি বানান, তারপর লোকালের সঙ্গে যুক্ত করে ব্রাঞ্চ পাঠান।
git init
git add .
git commit -m "প্রথম কমিট"
git branch -M main
git remote add origin git@github.com:user/project.git
git push -u origin main
-u ফ্ল্যাগ (পূর্ণ রূপ --set-upstream) লোকাল main-কে রিমোট origin/main-এর সঙ্গে যুক্ত করে। এরপর ওই ব্রাঞ্চে শুধু git push ও git pull লিখলেই চলে, এবং git status দেখায় সার্ভারের তুলনায় আপনি কতটা এগিয়ে বা পিছিয়ে।
রিমোট কোথায় নির্দেশ করছে দেখতে git remote -v। ঠিকানা ভুল হলে git remote set-url origin <নতুন-ঠিকানা> দিয়ে ঠিক করুন, রিপোজিটরি মুছে নতুন করে বানাবেন না।
নতুন ব্রাঞ্চ পাঠানো
কাজের জন্য ব্রাঞ্চ বানিয়ে কমিট করে git push লিখলে Git জানায়:
fatal: The current branch feature/login has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin feature/login
এটি ত্রুটি নয়, পরামর্শ: ব্রাঞ্চের সার্ভারে কোনো জোড়া নেই। পরামর্শ অনুযায়ী কমান্ড চালান, অথবা সংক্ষিপ্ত git push -u origin feature/login। সব নতুন ব্রাঞ্চে এটি নিজে থেকে হওয়ার জন্য সেটিং আছে (Git 2.37 থেকে):
git config --global push.autoSetupRemote true
git push প্রত্যাখ্যাত: rejected, non-fast-forward
দলগত কাজে সবচেয়ে সাধারণ পরিস্থিতি:
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'github.com:user/project.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally.
সহকর্মী আপনার আগে কমিট পাঠিয়েছেন। আপনার ইতিহাস ও সার্ভারের ইতিহাস আলাদা হয়ে গেছে, এবং Git যদি আপনার push নিত, সহকর্মীর কমিট হারিয়ে যেত। ঠিক উপায়: আগে পরিবর্তন নিন, তারপর নিজের কমিট তার ওপরে সাজান:
git pull --rebase # অন্যের কমিট নিন, নিজেরগুলো ওপরে সাজান
# কনফ্লিক্ট হলে: ফাইল ঠিক করা, git add, git rebase --continue
git push
--rebase-এর বদলে সাধারণ git pull চালালে একটি merge কমিট আসবে। দুটোই ঠিক; বেশিরভাগ দল নিজের স্থানীয় কমিটের জন্য rebase পছন্দ করে, যাতে ইতিহাস সরল থাকে। মূল কথা: এই প্রত্যাখ্যানকে --force দিয়ে "সমাধান" করবেন না।
git push --force ও --force-with-lease
জোর করে পাঠানোর দরকার হয় যখন আপনি নিজের ব্রাঞ্চের ইতিহাস ইচ্ছাকৃতভাবে বদলেছেন: git commit --amend, git rebase বা রিভিউয়ের আগে কমিট জোড়া দেওয়া। সাধারণ push এমন ব্রাঞ্চ নেবে না, কারণ সার্ভারের পুরনো কমিট নতুন কমিটের পূর্বপুরুষ আর নয়।
git push --force-with-lease
--force-with-lease সার্ভারের ব্রাঞ্চ শুধু তখনই ওভাররাইট করে, যদি সেটি ঠিক সেখানেই থাকে যেখানে আপনার লোকাল Git শেষবার দেখেছিল (origin/<ব্রাঞ্চ>-এর ঠিকানায়)। সহকর্মী এর মধ্যে কিছু পাঠিয়ে থাকলে কমান্ড প্রত্যাখ্যান করবে, এবং তাঁর কাজ মুছে যাবে না। সাধারণ --force (-f) এমন কোনো যাচাই করে না, চুপচাপ সব ওভাররাইট করে।
একটি সূক্ষ্মতা: force push-এর আগে git fetch চালালে origin/<ব্রাঞ্চ> হালনাগাদ হয়ে যায়, এবং সুরক্ষা কাজ করে না, কারণ Git ভাবে আপনি অন্যের কমিট "দেখে ফেলেছেন"। তাই কী এসেছে না দেখে fetch-এর পর force push করবেন না।
| কমান্ড | কী করে | কখন ব্যবহার |
|---|---|---|
git push | শুধু fast-forward | সবসময় ডিফল্টে |
git push --force-with-lease | যাচাইসহ ওভাররাইট | নিজের ব্রাঞ্চে rebase বা amend-এর পর |
git push --force | যাচাই ছাড়া ওভাররাইট | প্রায় কখনো না; শেয়ার্ড ব্রাঞ্চে কখনোই না |
শেয়ার্ড ব্রাঞ্চ (main, develop) জোর করে push করা যায় না: যারা পুরনো ইতিহাস নিয়েছেন, তাঁদের ইতিহাস সার্ভারের সঙ্গে বিচ্ছিন্ন হয়ে যাবে। সাধারণত এসব ব্রাঞ্চ রিপোজিটরির সেটিংসে সুরক্ষিত থাকে, এবং সার্ভার protected branch hook declined ফেরত দেয়।
ট্যাগ পাঠানো
সাধারণ git push ট্যাগ পাঠায় না। সেগুলো স্পষ্টভাবে দিতে হয়:
git tag -a v1.2.0 -m "রিলিজ 1.2.0"
git push origin v1.2.0 # একটি ট্যাগ
git push --tags # সব লোকাল ট্যাগ
git push --follow-tags # কমিট ও সেই কমিটগুলোর ব্যাখ্যামূলক ট্যাগ
--follow-tags --tags-এর চেয়ে ভালো: এটি এলোমেলো লোকাল হালকা ট্যাগ পাঠায় না, শুধু ব্যাখ্যামূলক ট্যাগ যেগুলো পাঠানো কমিট থেকে পৌঁছানো যায়।
সার্ভার থেকে ব্রাঞ্চ মোছা
মোছাও push দিয়ে হয়:
git push origin --delete feature/login
# পুরনো বাক্যরীতি, একই কাজ করে:
git push origin :feature/login
লোকাল ব্রাঞ্চ এতে থেকে যায়, তাকে মুছতে git branch -d feature/login। সহকর্মীদের কাছে তখনো origin/feature/login ঝুলে থাকবে, যতক্ষণ না তাঁরা git fetch --prune চালান।
git push-এর কাজের ফ্ল্যাগ
| ফ্ল্যাগ | কাজ |
|---|---|
-u, --set-upstream | রিমোট ব্রাঞ্চকে upstream হিসেবে মনে রাখা |
-n, --dry-run | কী যাবে দেখানো, কিছু না পাঠিয়ে |
--all | সব লোকাল ব্রাঞ্চ পাঠানো |
--tags / --follow-tags | ট্যাগ পাঠানো |
-d, --delete | সার্ভার থেকে ব্রাঞ্চ বা ট্যাগ মোছা |
--force-with-lease | নিরাপদে ইতিহাস ওভাররাইট |
-v, --verbose | বিস্তারিত আউটপুট |
--no-verify | pre-push হুক বাদ (সচেতনভাবে ব্যবহার করুন) |
git push-এর সাধারণ ত্রুটি ও সমাধান
Permission denied (publickey)
সার্ভার আপনার SSH কী গ্রহণ করেনি। দেখুন কী আছে কি না (ls ~/.ssh), পাবলিক অংশ অ্যাকাউন্টে যুক্ত কি না, এবং সংযোগ কাজ করছে কি না: ssh -T git@github.com। Remote HTTPS-এ থাকলে Git কী নয়, লগইন ও টোকেন চাইবে; git remote -v দেখুন।
HTTPS-এ Authentication failed
GitHub ও অনেক সার্ভিস অনেক আগে থেকেই HTTPS-এ অ্যাকাউন্টের পাসওয়ার্ড নেয় না। প্রয়োজন ব্যক্তিগত অ্যাক্সেস টোকেন, অথবা SSH-এ যাওয়া। টোকেন মনে রাখতে credential helper সাহায্য করে: git config --global credential.helper store (খোলা অবস্থায় সংরক্ষণ করে) বা আপনার OS-এর ক্রেডেনশিয়াল ম্যানেজার।
src refspec main does not match any
এই নামে ব্রাঞ্চ নেই। সাধারণত ফাঁকা রিপোজিটরিতে এখনো কোনো কমিট হয়নি, অথবা ব্রাঞ্চের নাম master। git branch দেখুন, কমিট করুন, অথবা নাম বদলান: git branch -M main।
Everything up-to-date, অথচ পরিবর্তন আছে
কমিট করতে ভুলে গেছেন। git push কমিট পাঠায়, ফাইল নয়। git status দেখুন, তারপর git add ও git commit। দ্বিতীয় সম্ভাবনা: আপনি এমন ব্রাঞ্চে আছেন, যেটি আপনি সার্ভারে আশা করছেন না।
ফাইল অনেক বড়
সার্ভিসগুলো একটি ফাইলের আকার সীমিত করে (GitHub-এ ১০০ MB)। ফাইল আগেই ইতিহাসে ঢুকে গেলে নতুন কমিটে মুছলেই হবে না: ইতিহাস পুনর্লিখতে হবে, অথবা যে কমিটগুলো এখনো পাঠানো হয়নি সেখান থেকে বাদ দিতে হবে (git reset --soft, তারপর আবার কমিট)। বড় বাইনারি ফাইলের জন্য Git LFS ব্যবহার হয়।
git push দিয়ে কাজের চক্র
git switch -c feature/x— কাজের জন্য ব্রাঞ্চ।- ছোট, যৌক্তিক ধাপে কমিট।
git fetchওgit rebase origin/main— সর্বশেষ মূল ব্রাঞ্চ টেনে নেওয়া।git push -u origin feature/x— ব্রাঞ্চ প্রকাশ।- pull request খোলা; রিভিউয়ের পর অতিরিক্ত কমিট ও সাধারণ
git push। - ইতিহাস পুনর্লিখতে হলে —
git push --force-with-lease।
পাঠানোর আগে দেখে নিন কী যাবে: git log origin/main..HEAD --oneline সেইসব কমিট দেখায়, যেগুলো সার্ভারে এখনো নেই।
একবার সেট করা কয়েকটি সেটিং
কয়েকটি গ্লোবাল সেটিং push-এর বেশিরভাগ বিস্ময় দূর করে। push.default ঠিক করে আর্গুমেন্ট ছাড়া git push কী পাঠাবে। আধুনিক সংস্করণে ডিফল্ট simple: শুধু বর্তমান ব্রাঞ্চ এবং একই নামের upstream-এ যায়। এটি সাধারণত বদলানোর দরকার নেই, তবে পুরনো কনফিগে matching থাকলে তা দেখে নিন, কারণ সেটি নামে মেলে এমন সব ব্রাঞ্চ একসঙ্গে পাঠায়।
git config --global push.default simple
git config --global push.autoSetupRemote true
git config --global push.followTags true
git config --global pull.rebase true
push.followTags --follow-tags-কে ডিফল্ট আচরণ বানায়, আর pull.rebase push প্রত্যাখ্যাত হলে আগে অন্যের পরিবর্তন নেওয়ার সময় অতিরিক্ত merge কমিট এড়ায়।
pre-push হুক
.git/hooks/pre-push ফাইল পাঠানোর আগে চলে। সেটি অশূন্য কোডে শেষ হলে push আটকে যায়। দলগুলো প্রায়ই সেখানে টেস্ট বা লিন্টার চালায়, যাতে ভাঙা কোড সার্ভারে না যায়। --no-verify দিয়ে হুক এড়ানো শুধু তখনই ঠিক, যখন আপনি নিশ্চিত জানেন কেন সেটি ব্যর্থ হচ্ছে।
সারসংক্ষেপ
git push আপনার কমিট রিমোট রিপোজিটরিতে প্রকাশ করে, এবং শুধু এক দিকে কাজ করে। প্রথমবার ব্রাঞ্চ পাঠাতে -u দিন, প্রত্যাখ্যাত হলে আগে pull করে নিন, আর নিজের ব্রাঞ্চের পুনর্লিখিত ইতিহাস পাঠাতে শুধু --force-with-lease। ব্রাঞ্চ ও ট্যাগ সার্ভারে পাঠানো, মোছা এবং SSH কী সেটআপ সবই Git কোর্সে বাস্তব অনুশীলনে শেখানো হয়।
সাধারণ প্রশ্ন
git push কি কমিট না করা পরিবর্তন পাঠায়?
না। Push শুধু কমিট পাঠায়; ওয়ার্কিং ফোল্ডার ও ইনডেক্সের পরিবর্তন কমিট না করা পর্যন্ত লোকালে থাকে।
git push কীভাবে বাতিল করব?
নিজের ব্রাঞ্চে কমিটটি লোকালি সরিয়ে (git reset) git push --force-with-lease দিয়ে পাঠান। শেয়ার্ড ব্রাঞ্চে নিরাপদ উপায় হলো git revert দিয়ে উল্টো কমিট বানিয়ে সাধারণ push।
শুধু একটি কমিট পাঠানো যায় কি?
হ্যাঁ, তার হ্যাশ দিয়ে: git push origin abc1234:main সেই কমিট পর্যন্ত পুরো ইতিহাস পাঠায়, তার পরের কমিট নয়। পূর্বপুরুষ ছাড়া কোনো কমিট পাঠানো যায় না।
git push ও git push origin main-এর পার্থক্য কী?
আর্গুমেন্ট ছাড়া Git বর্তমান ব্রাঞ্চের সেট করা upstream ব্যবহার করে, আর স্পষ্ট রূপে রিমোট ও ব্রাঞ্চ নির্দিষ্ট থাকে, এবং upstream সেট না থাকলেও চলে।
একই সঙ্গে দুটি রিপোজিটরিতে কীভাবে পাঠাব?
দ্বিতীয় remote যোগ করে নাম ধরে পাঠান, অথবা origin-এ দুটি push ঠিকানা যোগ করুন: git remote set-url --add --push origin ঠিকানা (দুটো ঠিকানার জন্যই চালাতে হবে, মূল ঠিকানাসহ, নইলে push শুধু দ্বিতীয়টিতে যাবে)।
“শূন্য থেকে আত্মবিশ্বাসী ডেভেলপার পর্যন্ত গিট” কোর্সে বিষয়টি অনুশীলনসহ বিস্তারিত শেখানো হয়েছে।
কোর্সে যান