৩.৬ রিবেইজ

রিবেজিং

গিটে, একটি ব্রাঞ্চ থেকে অন্য ব্রাঞ্চে পরিবর্তনগুলিকে সম্পূর্ণ করার দুটি প্রধান উপায় রয়েছে: মার্জ এবং রিবেস। এই বিভাগে আপনি শিখবেন রিবেসিং কী, কীভাবে এটি করতে হয়, কেন এটি একটি চমৎকার টুল এবং কোন ক্ষেত্রে আপনার এটি ব্যবহার করতে হবে না।

মৌলিক রিবেইজ

আপনি যদি বেসিক মার্জিং থেকে আগের একটি উদাহরণে ফিরে যান, আপনি দেখতে পাবেন যে আপনি আপনার কাজকে আলাদা করেছেন এবং দুটি ভিন্ন ব্রাঞ্চে কমিট দিয়েছেন।
চিত্র ৩৫ঃ সাধারণ divergent history
ব্রাঞ্চগুলিকে একীভূত করার সবচেয়ে সহজ উপায়, যেমনটি আমরা ইতিমধ্যেই কভার করেছি, মার্জ কমান্ড। এটি দুটি সর্বশেষ ব্রাঞ্চ স্ন্যাপশট (C3 এবং C4) এবং দুটির সর্বশেষ সাধারণ পূর্বপুরুষ (C2) এর মধ্যে একটি ত্রি-মুখী একত্রীকরণ করে, একটি নতুন স্ন্যাপশট তৈরি করে (এবং কমিট)।
চিত্র ৩৬ঃ মার্জিং করা যাতে diverged কাজের history integrate হয়
যাইহোক, আরেকটি উপায় আছে: আপনি C4 এ যে পরিবর্তনটি করা হয়েছিল তার প্যাচটি নিতে পারেন এবং C3 এর উপরে এটি পুনরায় প্রয়োগ করতে পারেন। গিটে, একে বলা হয় রিবেসিং। রিবেস কমান্ডের সাহায্যে, আপনি একটি ব্রাঞ্চে কমিট করা সমস্ত পরিবর্তন নিতে পারেন এবং সেগুলিকে অন্য ব্রাঞ্চে পুনরায় চালাতে পারেন।

এই উদাহরণের জন্য, আপনি experiment ব্রাঞ্চটি পরীক্ষা করবেন এবং তারপরে এটিকে master ব্রাঞ্চে নিম্নরূপ রিবেস করবেন:
				
					$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
				
			
এই ক্রিয়াকলাপটি দুটি ব্রাঞ্চের সাধারণ পূর্বপুরুষের কাছে গিয়ে কাজ করে (যেটিতে আপনি আছেন এবং যেটিতে আপনি রিবেসিং করছেন), আপনি যে ব্রাঞ্চে আছেন তার প্রতিটি কমিট দ্বারা পার্থক্যটি পাওয়ার পর, সেই পার্থক্যগুলিকে অস্থায়ীভাবে সংরক্ষণ করা ফাইল, বর্তমান ব্রাঞ্চটিকে আপনি যে ব্রাঞ্চে রিবেস করছেন সেই একই কমিটটিতে পুনরায় সেট করে এবং শেষে প্রতিটি পরিবর্তনকে পালাক্রমে প্রয়োগ করে।
চিত্র ৩৭ঃ C4-এ প্রবর্তিত পরিবর্তনটিকে C3-তে রিবেস করা
এই মুহুর্তে, আপনি master ব্রাঞ্চে ফিরে যেতে পারেন এবং fast-forward মার্জ করতে পারেন।
				
					$ git checkout master
$ git merge experiment
				
			
চিত্র ৩৮ঃ master ব্রাঞ্চকে fast-forward করা
এখন, C4′ দ্বারা নির্দেশিত স্ন্যাপশটটি মার্জ উদাহরণে C5 দ্বারা নির্দেশিত একটির মতোই। ইন্টিগ্রেশনের শেষ প্রোডাক্টের মধ্যে কোন পার্থক্য নেই, তবে রিবেস একটি পরিষ্কার history তৈরি করে। আপনি যদি একটি রিবেস হওয়া ব্রাঞ্চের লগ পরীক্ষা করেন তবে দেখবেন, এটি একটি linear history এর মতো দেখায়ঃ এটি এমনভাবে প্রদর্শিত হয় যে, সমস্ত কাজ সিরিজে সংগঠিত হয়েছে, এমনকি যখন এটি মূলত সমান্তরালে ঘটেছিল।

প্রায়শই, আপনার কমিটগুলি রিমোট ব্রাঞ্চে পরিষ্কারভাবে প্রয়োগ হয় তা নিশ্চিত করার জন্য আপনি এটি করবেন —-সম্ভবত এমন একটি প্রজেক্টে যেখানে আপনি contribute করার চেষ্টা করছেন কিন্তু আপনি তা বজায় রাখেন না। এই ক্ষেত্রে, আপনি একটি ব্রাঞ্চে আপনার কাজ করবেন এবং তারপরে মূল প্রজেক্টে আপনার প্যাচগুলি জমা দেওয়ার জন্য প্রস্তুত হলে আপনার কাজকে origin/master এ পুনঃস্থাপন করবেন। এইভাবে, রক্ষণাবেক্ষণকারীকে কোনো ইন্টিগ্রেশন কাজ করতে হবে না —শুধু একটি দ্রুত-ফরোয়ার্ড বা একটি clean প্রয়োগ।

মনে রাখবেন যে স্ন্যাপশটটি আপনার শেষ হওয়া চূড়ান্ত কমিটের দ্বারা নির্দেশ করা হয়েছে, সেটি রিবেসের জন্য রিবেস করা কমিটগুলির শেষ-ই হোক বা মার্জ করার পরে চূড়ান্ত মার্জ কমিট হোক, এটি মূলত একই স্ন্যাপশট — শুধুমাত্র history টা ভিন্ন। রিবেজিং কাজের এক লাইন থেকে অন্য লাইনে পুনরায় পরিবর্তন করে যে ক্রমে সেগুলি প্রবর্তন করা হয়েছিল, যেখানে মার্জিং এন্ডপয়েন্টগুলি নেয় এবং সেগুলিকে একত্রিত করে।

আরও মজাদার রিবেইজসমূহ

আপনি রিবেস টার্গেট ব্রাঞ্চ ছাড়া অন্য কিছুতে আপনার রিবেস রিপ্লে করতে পারেন। উদাহরণস্বরূপ, একটি history নিন যেমন একটি টপিক ব্রাঞ্চ থেকে অন্য টপিক ব্রাঞ্চের একটি history। আপনি আপনার প্রজেক্টে কিছু সার্ভার-সাইড কার্যকারিতা যোগ করতে একটি টপিক ব্রাঞ্চ (server) তৈরি করেছেন এবং একটি কমিট দিয়েছেন। তারপরে, আপনি ক্লায়েন্ট-সাইড পরিবর্তনগুলি (client) করতে এটিকে ব্রাঞ্চ করেছেন এবং কয়েকবার কমিট দিয়েছেন। অবশেষে, আপনি আপনার সার্ভার শাখায় ফিরে গিয়েছিলেন এবং আরও কয়েকটি কমিট করেছেন।
চিত্র ৩৯ঃ একটি টপিক ব্রাঞ্চ থেকে অন্য একটি টপিক ব্রাঞ্চে একটি history
ধরুন আপনি সিদ্ধান্ত নিয়েছেন যে আপনি আপনার ক্লায়েন্ট-সাইড পরিবর্তনগুলিকে আপনার মেইনলাইনে একটি রিলিজের জন্য মার্জ করতে চান, কিন্তু আপনি সার্ভার-সাইড পরিবর্তনগুলিকে আরও পরীক্ষা না করা পর্যন্ত hold রাখতে চান। আপনি ক্লায়েন্টের পরিবর্তনগুলি নিতে পারেন যা সার্ভারে নেই (C8 এবং C9) এবং গিট রিবেসের –onto বিকল্পটি ব্যবহার করে সেগুলিকে আপনার master ব্রাঞ্চে পুনরায় চালাতে পারেনঃ
				
					$ git rebase --onto master server client	
				
			
এটি মূলত বলে, “ক্লায়েন্ট ব্রাঞ্চটি নিন, সার্ভার ব্রাঞ্চ থেকে বিচ্ছিন্ন হওয়ার পর থেকে প্যাচগুলি বের করুন এবং ক্লায়েন্ট ব্রাঞ্চে এই প্যাচগুলি পুনরায় প্লে করুন যেন এটি সরাসরি master ব্রাঞ্চের উপর ভিত্তি করে।” এটি কিছুটা জটিল, তবে ফলাফলটি বেশ দুর্দান্ত।
চিত্র ৪০ঃ একটি টপিক ব্রাঞ্চের অন্য একটি টপিক ব্রাঞ্চে রিবেস করা
এখন আপনি আপনার master ব্রাঞ্চে fast-forward করতে পারেন (ক্লায়েন্ট ব্রাঞ্চ পরিবর্তনগুলি অন্তর্ভুক্ত করতে আপনার master ব্রাঞ্চকে fast-forward করা দেখুন):
				
					$ git checkout master
$ git merge client
				
			
চিত্র ৪১ঃ ক্লায়েন্ট ব্রাঞ্চ এর পরিবর্তনগুলি অন্তর্ভুক্ত করতে আপনার master ব্রাঞ্চকে fast-forward করা

ধরা যাক আপনি আপনার সার্ভার ব্রাঞ্চে পুল নেয়ার সিদ্ধান্ত নিয়েছেন। git rebase <basebranch> <topicbranch> ব্যবহার করে master ব্রাঞ্চে চেক আউট না করেই আপনি প্রথমে server ব্রাঞ্চ কে master ব্রাঞ্চে  রিবেস করতে পারেন,  —  যা আপনার জন্য টপিক ব্রাঞ্চে (এই ক্ষেত্রে, সার্ভার) চেক আউট করে এবং বেস ব্রাঞ্চে এটিকে পুনরায় প্লে করে। (master):

				
					$ git rebase master server
				
			

এটি আপনার master কাজের উপরে আপনার সার্ভারের কাজকে রিপ্লে করে, যেমনটি আপনার master ব্রাঞ্চের উপরে আপনার server ব্রাঞ্চের রিবেসিং-এ দেখানো হয়েছে।

চিত্র ৪২ঃ আপনার master ব্রাঞ্চের উপরে আপনার server শাখার ব্রাঞ্চের রিবেসিং
তারপর, আপনি বেস ব্রাঞ্চে (master) fast-forward করতে পারেন:
				
					$ git checkout master
$ git merge server
				
			
আপনি ক্লায়েন্ট এবং সার্ভার ব্রাঞ্চগুলিকে সরিয়ে ফেলতে পারেন কারণ সমস্ত কাজ মার্জ করা হয়েছে এবং আপনার আর সেগুলির প্রয়োজন নেই, এই সম্পূর্ণ প্রক্রিয়াটির জন্য আপনার history কে চূড়ান্ত কমিটের history-র মতো দেখাচ্ছে:
				
					$ git branch -d client
$ git branch -d server
				
			
চিত্র ৪৩ঃ সর্বশেষ কমিট history

রিবেজিং এর সমস্যাসমূহ

আহ, কিন্তু রিবেজের আনন্দ ও এর ত্রুটিগুলি ছাড়া নয়, যা একটি একক লাইনে সংক্ষিপ্ত করা যেতে পারেঃ

আপনার রিপোজিটরির বাইরে বিদ্যমান এবং অন্যদের উপর ভিত্তি করে কাজ থাকতে পারে এমন কমিটগুলিকে রিবেস করবেন না।

ভালো হয় যদি আপনি সেই নির্দেশিকা অনুসরণ করেন। আপনি যদি তা না করেন, লোকেরা আপনাকে ঘৃণা করবে এবং আপনি বন্ধুবান্ধব এবং পরিবারের দ্বারা অপমানিত হবেন।

আপনি যখন কিছু রিবেস করেন, তখন আপনি existing কমিট ত্যাগ করছেন এবং নতুন কমিট তৈরি করছেন যা দেখতে একই রকম কিন্তু ভিন্ন। আপনি যদি কমিটগুলিকে কোথাও পুশ দেন এবং অন্যরা সেগুলিকে পুল করে নিয়ে যায় এবং সেগুলির উপর ভিত্তি করে কাজ করেন এবং তারপর আপনি সেই কমিটগুলিকে গিট রিবেস দিয়ে পুনরায় লেখেন এবং সেগুলিকে আবার পুশ দেন, তাহলে আপনার সহযোগীদের তাদের কাজগুলি পুনরায় মার্জ করতে হবে এবং আপনি যখন চেষ্টা করবেন তাদের কাজগুলো পুল করার তখন জিনিসগুলি অগোছালো হয়ে যাবে।

আপনি যে কাজটি পাবলিক ভাবে করেছেন তা কীভাবে সমস্যা সৃষ্টি করতে পারে তার একটি উদাহরণ দেখা যাক। ধরুন আপনি একটি সেন্ট্রাল সার্ভার থেকে ক্লোন করেন এবং তারপর কিছু কাজ করেন। আপনার কমিট এর history টি এরকমটা দেখাচ্ছেঃ
চিত্র ৪৪ঃ একটি রিপোজিটরী ক্লোন করুন এবং এটির উপর কিছু কাজ করুন
এখন, অন্য কেউ আরও কাজ করে যার মধ্যে একটি মার্জ রয়েছে এবং সেই কাজটিকে কেন্দ্রীয় সার্ভারে পুশ করে দেয়। আপনি এটি ফেচ করুন এবং নতুন রিমোট ব্রাঞ্চটিকে আপনার কাজে মার্জ করুন, আপনার history টি এরকমটা দেখাবে:
চিত্র ৪৫ঃ আরও কমিট ফেচ করুন এবং তাদেরকে আপনার কাজে মার্জ করুন

এরপরে, যে ব্যক্তি মার্জ করার কাজটিকে পুশ দিয়েছে সে সিদ্ধান্ত নেয় ফিরে যাওয়ার এবং এর পরিবর্তে তাদের কাজ পুনরায় বসানোর; তারা একটি git push –force রান করে সার্ভারে history ওভাররাইট করার জন্য। তারপরে আপনি সেই সার্ভার থেকে চেক করে, নতুন কমিটগুলি নামিয়ে আনুন।

চিত্র ৪৬ঃ আপনার কাজের উপর ভিত্তি করা কমিট পরিত্যাগ করে, কেউ রিবেজ কমিটগুলিকে পুশ দেয়
এখন আপনারা দুজনেই বিব্রত। আপনি যদি একটি গিট পুল করেন, আপনি একটি মার্জ কমিট তৈরি করবেন যাতে history এর উভয় লাইন অন্তর্ভুক্ত থাকে এবং আপনার রিপোজিটরিটি এরকম দেখাবেঃ
চিত্র ৪৭ঃ আপনি একই কাজকে পুনরায় নতুন মার্জ কমিটে মার্জ করেন
যদি আপনি একটি git log চালান তখন আপনার history এরকম দেখায়, আপনি দুটি কমিট দেখতে পাবেন যার একই লেখক, তারিখ এবং বার্তা রয়েছে, যা বিভ্রান্তিকর হবে। তদ্ব্যতীত, আপনি যদি এই history-কে সার্ভারে ব্যাক আপ করেন তবে আপনি সেন্ট্রাল সার্ভারে সেই সমস্ত রিবেজ হওয়া কমিটগুলি পুনঃপ্রবর্তন করবেন, যা মানুষকে আরও বিভ্রান্ত করতে পারে। এটি অনুমান করা বেশ নিরাপদ যে অন্য ডেভেলাপার C4 এবং C6 এর history তে থাকতে চান না; যে কারণে তারা প্রথম স্থানে রিবেজ করেছে।

Rebase When You Rebase

আপনি যদি নিজেকে এইরকম পরিস্থিতিতে খুঁজে পান, গিট-এর আরও কিছু জাদু আছে যা আপনাকে সাহায্য করতে পারে। আপনার টিমের কেউ যদি এমন পরিবর্তনগুলিকে force পুশ দেয় যেগুলি আপনি যে কাজটির উপর ভিত্তি করে কাজটি করেছেন তা ওভাররাইট করে, তাহলে আপনার চ্যালেঞ্জ হল কোনটি আপনি লিখেছেন এবং কোনটি তারা পুনরায় লিখেছে তা খুঁজে বের করা।

দেখা যাচ্ছে যে কমিট SHA-1 চেকসাম ছাড়াও, গিট একটি চেকসামও গণনা করে যা শুধুমাত্র কমিটের সাথে প্রবর্তিত প্যাচের উপর ভিত্তি করে। একে “patch-id” বলা হয়।

আপনি যদি পুনঃলিখিত কাজটি পুল করে আনেন এবং আপনার অংশীদারের কাছ থেকে নতুন কমিটগুলির উপরে এটি পুনরায় স্থাপন করেন, তবে গিট প্রায়শই সফলভাবে খুঁজে বের করতে পারে যে এককভাবে কণ্টী আপনার এবং সেগুলি নতুন ব্রাঞ্চের উপরে আবার প্রয়োগ করতে পারে।

উদাহরণস্বরূপ, পূর্ববর্তী দৃশ্যে, আমরা যখন কেউ থাকি তখন একটি মার্জ করার পরিবর্তে রিবেসড কমিট পুশ করে, কমিট পরিত্যাগ করে আপনার কাজের উপর ভিত্তি করে আমরা git rebase teamone/master চালাব, ফলে গিটঃ

আমাদের ব্রাঞ্চের জন্য কোন কাজটি ইউনিক তা নির্ধারণ করবে (C2, C3, C4, C6, C7)

কোনটি মার্জ কমিট নয় তা নির্ধারণ করবে (C2, C3, C4)

target ব্রাঞ্চে কোনটি পুনরায় লেখা হয়নি তা নির্ধারণ করবে (কেবল C2 এবং C3, যেহেতু C4 হল C4′ এর মতো একই প্যাচ)

teamone/master শীর্ষে সেই কমিটগুলি প্রয়োগ করবে

সুতরাং ফলাফলের পরিবর্তে আমরা দেখতে পাচ্ছি, আপনি একই কাজে একটি নতুন মার্জ কমিটে পুনরায় মার্জ করবেন , আমরা force-pushed রিবেস কাজের উপরে রিবেসের মতো আরও কিছু দিয়ে সমাপ্ত করব।
চিত্র ৪৮ঃ force-pushed এর মাধ্যমে রিবেজকৃত কাজ এর top এ রিবেজ করুন
এটি শুধুমাত্র তখনই কাজ করে যখন আপনার সঙ্গীর তৈরি C4 এবং C4′ প্রায় একই প্যাচ হয়। অন্যথায় রিবেস বলতে পারবে না যে এটি একটি ডুপ্লিকেট এবং আরেকটি C4-এর মতো প্যাচ যোগ করবে (যা সম্ভবত পরিষ্কারভাবে প্রয়োগ করতে ব্যর্থ হবে, যেহেতু পরিবর্তনগুলি ইতিমধ্যেই অন্তত কিছুটা থাকবে)।

আপনি একটি সাধারণ git pull-এর পরিবর্তে একটি git pull –rebase চালিয়ে এটিকে সহজ করতে পারেন। অথবা আপনি এই ক্ষেত্রে একটি git rebase teamone/master ব্যবহার করে একটি গিট ফেচ দিয়ে ম্যানুয়ালি এটি করতে পারেন।

আপনি যদি git pull ব্যবহার করেন এবং –rebase-কে ডিফল্ট করতে চান, তাহলে আপনি pull.rebase কনফিগার মান সেট করতে পারেন git config –global pull.rebase true এর মত কিছু দিয়ে।

এটি সঠিক থাকবে যদি আপনি কেবলমাত্র সেই কমিটগুলিকে রিবেস করেন যা কখনও আপনার নিজের কম্পিউটার ছেড়ে যায়নি। আপনি যদি পুশ করা কমিটগুলিকে রিবেস করেন, কিন্তু অন্য কেউ কমিটগুলো বেজ করেনি, তখনও এটি সঠিক হবে। আপনি যদি এমন কমিটগুলিকে রিবেস করেন যেগুলি ইতিমধ্যেই পাবলিকলি পুশ করে দেওয়া হয়েছে, এবং লোকেরা সেই কমিটগুলির উপর ভিত্তি করে কাজ করতে পারে, তাহলে আপনি কিছু হতাশাজনক সমস্যা এবং আপনার সতীর্থদের অবজ্ঞার সম্মুখীন হতে পারেন।

যদি আপনি বা একজন সঙ্গী এটিকে কোনো সময়ে প্রয়োজনীয় মনে করেন, তবে নিশ্চিত করুন যে সবাই git pull –rebase চালাতে জানে যাতে এটি কিছুটা সহজ হয়।

রিবেজ বনাম মার্জ

এখন যেহেতু আপনি রিবেসিং এবং মারজিং হতে দেখেছেন, আপনি হয়তো ভাবছেন কোনটি ভাল। আমরা এর উত্তর দেওয়ার আগে, আসুন একটু পিছিয়ে যাই এবং history বলতে কী বোঝায় তা দেখি।

এই বিষয়ে একটি দৃষ্টিভঙ্গি হল যে আপনার রিপোজিটরির কমিটের history মূলত কী ঘটেছিল তার একটি রেকর্ড। এটি এমন একটি ঐতিহাসিক দলিল, যা অনেক মূল্যবান, এবং এর সাথে হেরফের করা উচিত নয়। এজায়গা থেকে, কমিট history পরিবর্তন প্রায় নিন্দাজনক; এটি পরিবর্তন করলে মনে হবে, আপনি আসলে যা ঘটেছে তা নিয়ে মিথ্যা বলছেন। তাহলে কি মার্জ কমিটের একটি অগোছালো সিরিজ ছিল? এটি মূলত এভাবেই ঘটেছে, এবং রিপজিটরিটি পরবর্তী উত্তরসূরির জন্য সংরক্ষণ করা উচিত।

বিপরীত দৃষ্টিকোণ হল যে কমিট history হল আপনার প্রজেক্টটি কীভাবে তৈরি করা হয়েছিল তার গল্প। আপনি একটি বইয়ের প্রথম খসড়া কখনও প্রকাশ করবেন না, তাহলে কেন আপনার অগোছালো কাজগুলো দেখাবেন? আপনি যখন একটি প্রজেক্টে কাজ করছেন, তখন আপনার সমস্ত ভুল পদক্ষেপ এবং শেষের পথের রেকর্ডের প্রয়োজন হতে পারে, কিন্তু যখন আপনার কাজটি বিশ্বকে দেখানোর সময় হয়, তখন আপনি কীভাবে A থেকে B তে গিয়েছেন, তার একটি আরও সুসংগত গল্প বলতে পারেন। এক্ষেত্রে লোকেরা মেইনলাইন ব্রাঞ্চে মার্জ হওয়ার আগে তাদের কমিটগুলিকে পুনরায় লিখতে rebase এবং filter-branch মতো টুলগুলি ব্যবহার করে। তারা রিবেস এবং ফিল্টার-ব্রাঞ্চের মতো টুলগুলি ব্যবহার করে, ভবিষ্যতের পাঠকদের জন্য সেরা গল্পটি বলার জন্য।

এখন, মার্জিং বা রিবেসিং করা ভাল কিনা এই প্রশ্নের উত্তরে: আশা করি আপনি দেখতে পাবেন যে এর উত্তর দেয়া এত সহজ নয়। গিট একটি শক্তিশালী টুল, এবং আপনাকে আপনার history-এর সাথে অনেক কিছু করার অনুমতি দেয়, কিন্তু প্রতিটি দল এবং প্রতিটি প্রজেক্ট আলাদা আলাদা। এখন যেহেতু আপনি জানেন যে এই দুটি জিনিস কীভাবে কাজ করে, আপনার নির্দিষ্ট পরিস্থিতির জন্য কোনটি সেরা তা সিদ্ধান্ত নেওয়ার দায়িত্ব ও তাই আপনার উপর নির্ভর করে।

আপনি উভয় ক্ষেত্রেই সেরাটি পেতে পারেনঃ আপনার কাজ clean up করার জন্য চাপ দেওয়ার আগে লোকাল পরিবর্তনগুলিকে রিবেস করুন, কিন্তু আপনি কোথাও পুশ করেছেন এমন কোনও কিছুকে রিবেস করবেন না।