Menu
৫.৩ ডিস্ট্রিবিউটেড গিট – প্রজেক্ট মেইনটেইন
প্রজেক্ট মেইনটেইন
কীভাবে একটি প্রজেক্টে কার্যকরভাবে অবদান রাখতে হয় তা জানার পাশাপাশি আপনাকে সেই প্রজেক্টটি মেইনটেইন এর উপায়ও জানতে হবে এবং এই মেইনটেইন এর প্রসেস টা কিছু বিষয়ের উপর ভিত্তি করে গঠিত যেমন – ফর্ম্যাট-প্যাচের মাধ্যমে তৈরি হওয়া প্যাচগুলি গ্রহণ এবং প্রয়োগ করা, যা ইমেইল করে জানানো হয় অথবা রিমোট প্রজেক্ট হিসেবে যুক্ত করারিপোজিটোরিতে পরিবর্তনগুলো ইন্টিগ্রেট করা। আবার ক্যাননিকেল রিপোজিটরি মেইনটেইন কিংবা প্যাচগুলো ভেরিফাই বা এপ্রোভ করতে চাইলে কিভাবে অন্যান্য কন্ট্রিবিউটরদের বোধগম্য ও টেকসই উপায়ে এক্সেপ্ট কাজ করে তা জানতে হবে।টপিক ব্রাঞ্চে কাজ
আপনি যখন নতুন কাজকে ইন্টিগ্রেট করার কথা ভাবছেন, তখন টপিক ব্রাঞ্চে সেটি ট্রাই করে দেখা একটি ভাল আইডিয়া যেহেতু টপিক ব্রাঞ্চ নতুন কাজকে ট্রাই আউট করে দেখার কনসেপ্ট থেকেই তৈরি। এক্ষেত্রে এককভাবে একটী প্যাচকে ধরে কাজ করা এবং তা সঠিকভাবে কাজ না করলে সহজেই ফিরে আসার সুযোগ থাকে। আপনি যদি কাজের থিম অনুযায়ী একটি ব্রাঞ্চ তৈরি করে কাজ করেন যা সাধারনত বর্ণনামূলক (যেমন – ruby_client), সেক্ষেত্রে ব্রাঞ্চটিকে কিছুক্ষণের জন্য পরিত্যাক্ত করলেও পরবর্তীতে তাতে আবার তাতে আবার ফিরে যেতে পারবেন। গিট প্রজেক্টের মেইন্টেইনারের নেমস্পেস এর একটি প্রবণতা থাকতে পারে, যেমন – sc/ruby_client, যেখানে sc হল যে কাযে কন্ট্রিবিউশন করছে তার নামের শর্টফর্ম। আমরা জানি, master branch এর উপর ভিত্তি করে নিম্নলিখিত উপাইয়ে branch তৈরি করা যায়
$ git branch sc/ruby_client master
অথবা নতুনভাবে তৈরিকৃত ব্রাঞ্চে তৎক্ষণাৎ সুইচ করার জন্য checkout -b অপশন হিসেবে ব্যাবহার করা হয়।
$ git checkout -b sc/ruby_client master
অতপর এই টপিক ব্রাঞ্চে আপনি আপনার কন্ট্রিবিউটেড কাজ যুক্ত করতে প্রস্তুত হবেন এবং তা লং টার্ম ব্রাঞ্চগুলোর সাথে মার্জ করবেন কিনা তার সিদ্ধান্ত নিতে পারবেন।
ইমেইল থেকে প্যাচ আপ্লাই
আপনি যদি প্রজেক্টে ইন্টিগ্রেট করতে হবে এমন কোন প্যাচ ইমেইলে রিসিভ করেন, সেই প্যাচটি মূল্যায়ন করার জন্য টপিক ব্রাঞ্চে যুক্ত করতে হবে যে ২ পদ্ধতিতে করা যায়: git apply অথবা git am ব্যবহার করে।Applying a Patch with apply
যদি আপনি কারো থেকে git diff এর মাধ্যমে তৈরি করা প্যাচ কিংবা ইউনিক্স diff কমান্ডের কোন প্রকরণ রিসিভ করেন তবে আপনি git apply এর মাধ্যমে তা অ্যাাপ্লাই করতে পারেন। উদাহরণস্বরুপ যদি আপনি /tmp/patch-ruby-client.patch এরকম একটি প্যাচ সেভ করেন, তবে নিম্নলিখিতভাবে আপনি প্যাচটি অ্যাাপ্লাই করতে পারেন:
$ git apply /tmp/patch-ruby-client.patch
এতে আপনার ওয়ার্কিং ডিরেক্টরির ফাইল মডিফাই হবে। প্যাচ অ্যাাপ্লাই করার জন্য patch -p1 কমান্ড ব্যবহারেও একই কাজ করে যদিও অল্প কিছু সূক্ষ পার্থক্য এতে রয়েছে। আবার git diff ফরমেটে থাকলে এর মাধ্যমে ফাইল হ্যান্ডেলিং যেমন – কোন ফাইল অ্যাাড, ডিলিট ও রিনেম করা যায় যা patch ব্যবহারে করা যায় না।
git apply হল একটি সকল ফাইল অ্যাাপ্লাই ব সকল ফাইল বাতিলের একটি মডেল, যার মাধ্যমে হয়তো সকল ফাইলই অ্যাপ্লাই করা হয় কিংবা সকল ফাইলই বাতিল করা হয়। অপরদিকে patch এর মাধ্যমে কোন প্যাচ ফাইল আংশিকভাবে অ্যাপ্লাই করার সুযোগ থাকে যা আমাদের ওয়ার্কিং ডিরেক্টরিকে একটি উদ্ভট স্টেট এ ছেড়ে যায়। patch থেকে git apply অনেক বেশি রক্ষণশীল উপায়ে কাজ করে কারণ আপনাকে নিজ থেকে কোন git apply করে দিবে না বরং আপনাকে পরিবর্তন গুলো স্টেজ ও ম্যানুয়ালি কমিট করতে হবে। git apply ব্যবহার করার আগে git apply –check কমান্ডটি ব্যবহার করে কোন প্যাচের স্বচ্ছতা চেক করা যায়।
git apply হল একটি সকল ফাইল অ্যাাপ্লাই ব সকল ফাইল বাতিলের একটি মডেল, যার মাধ্যমে হয়তো সকল ফাইলই অ্যাপ্লাই করা হয় কিংবা সকল ফাইলই বাতিল করা হয়। অপরদিকে patch এর মাধ্যমে কোন প্যাচ ফাইল আংশিকভাবে অ্যাপ্লাই করার সুযোগ থাকে যা আমাদের ওয়ার্কিং ডিরেক্টরিকে একটি উদ্ভট স্টেট এ ছেড়ে যায়। patch থেকে git apply অনেক বেশি রক্ষণশীল উপায়ে কাজ করে কারণ আপনাকে নিজ থেকে কোন git apply করে দিবে না বরং আপনাকে পরিবর্তন গুলো স্টেজ ও ম্যানুয়ালি কমিট করতে হবে। git apply ব্যবহার করার আগে git apply –check কমান্ডটি ব্যবহার করে কোন প্যাচের স্বচ্ছতা চেক করা যায়।
$ git apply --check 0001-see-if-this-helps-the-gem.patch
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
যদি কোন আউটপুট না আসে, তবে তা কোন প্যাচের স্বচ্ছতাতে নির্দেশ করবে অর্থাৎ প্যাচটি সম্পূর্ণ ক্লিন তা বুঝাবে, আর ফেইল হলে এই কমান্ড একটি নন জিরো স্ট্যাটসের মাধ্যমে এক্সিট নিয়ে নিবে, যাতে আপনি চাইলে তা স্ক্রিপ্টে ব্যবহার করতে পারেন।
am এর মাধ্যমে প্যাচ অ্যাপ্লাই
কন্ট্রিবিউটর যদি একজন গিট ব্যবহারী হয় এবং সে প্যাচ তৈরি করার জন্য format-patch কমান্ডটি ব্যবহার করে, তবে আপনার কাজ আরও সহজ হয়ে যাবে কারণ প্যাচ তখন আপনার জন্য অথোরের ইনফরমেশন ও একটি কমিট মেসেজ ধারণ করবে। তাই আপনি যদি কন্ট্রিবিউটরদের প্যাচ তৈরি করার জন্য diff এর পরিবর্তে format-patch ব্যবহারে উৎসাহী করতে পারেন, তবে আপনার লিগেসি প্যাচ বা ওই ধরনের কোন বিষয়ের ক্ষেত্রে শুধুমাত্র git apply ব্যবহার করলেই হয়ে যাবে।এখন format-patch এর মাধ্যমে প্যাচ তৈরি করতে চাইলে আপনাকে git am ব্যবহার করতে হবে। কার্যত git am mbox ফাইল রিড করার জন্য তৈরি করা হয়েছিল যা মূলত এক বা একাধিক ইমেইলকে একটি টেক্সট ফাইলে স্টোর করার জন্য একটি প্লেইন টেক্সট ফরমেট। এটি অনেকটা নিম্নরূপ দেখায়
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] Add limit to log function
Limit log functionality to the first 20
এই আউটপুটটি একটি বৈধ mbox ইমেইল ফরম্যাটকে প্রতিনিধিত্ব করে। যদি কেউ আপনাকে git send-email কমান্ডটি ব্যবহার করে প্যাচটি সঠিকভাবে ইমেইল করে এবং আপনি তা mbox ফরম্যটে ডাউনলোড করেন, তবে আপনি git am কে ওয়ি ফাইলে পয়েন্ট করতে পারবেন যা সামনে যত প্যাচ পাবে সবগুলোই অ্যাাপ্লাই করা শুরু করবে। যদি আপনি একটা মেইল ক্লায়েন্ট run করেন যা বেশ কয়টি ইমেইলকে mbox ফরম্যাটে সেইভ করতে পারে, তাহলে আপনি সকল প্যাচ সিরিজকে একটি ফাইলে সেইভ করে পরবর্তীতে git am ব্যবহার করে সবার জন্যে একত্রে অ্যাপ্লাই করতে পারবেন।
কেউ যদি কোন টিকেটিং সিস্টেমে কমান্ডের মাধ্যমে প্যাচ আপলোড করে বা এ জাতীয় কিছু করে তবে আপনি লোকালি ফাইলটাকে সেভ করে পরবর্তীতে ওই সেইভড ফাইলকে আপনার ডিসকে প্রেরণ করতে পারবেন ও কমান্ডটি এপ্লাই করতে পারবেন।
কেউ যদি কোন টিকেটিং সিস্টেমে কমান্ডের মাধ্যমে প্যাচ আপলোড করে বা এ জাতীয় কিছু করে তবে আপনি লোকালি ফাইলটাকে সেভ করে পরবর্তীতে ওই সেইভড ফাইলকে আপনার ডিসকে প্রেরণ করতে পারবেন ও কমান্ডটি এপ্লাই করতে পারবেন।
$ git am 0001-limit-log-function.patch
Applying: Add limit to log function
এটি পরিষ্কারভাবে প্রয়োগ সম্পন্ন হবে এবং আপনার জন্য একটি অটোমেটিক কমিট করে দেবে। অথরের তথ্য ইমেইল এর ফরম ও ডেট হেডার থেকে নেয়া হবে এবং কমিডের মেসেজটি ওই ইমেইলটি র সাবজেক্ট এবং বডি থেকে নেয়া হবে। উদাহরণস্বরূপ যদি একটি প্যাচ উপরোক্ত mbox উদাহরণ থেকে নেয়া হয় তবে এটি নিম্নলিখিতভাবে জেনারেট হবে
$ git log --pretty=fuller -1
commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Author: Jessica Smith
AuthorDate: Sun Apr 6 10:17:23 2008 -0700
Commit: Scott Chacon
CommitDate: Thu Apr 9 09:19:06 2009 -0700
Add limit to log function
Limit log functionality to the first 20
কমিটের ইনফরমেশন যে ব্যক্তি প্যাচ এপ্লাই করেছে এবং প্যাচ এপ্লাইয়ের সময় কে নির্দেশ করবে। অথরের তথ্যের ক্ষেত্রে মূলত যে প্যাচটি তৈরি করেছিল ও কখন করেছিল তার তথ্য থাকবে।
কিন্তু এমনটাও হতে পারে যে প্যাচ টি পরিষ্কারভাবে ক্রিয়েট হলো না। বরং প্যাচ যে ব্রাঞ্চ থেকে ক্রিয়েট করা হয়েছিল তা থেকে মেইন ব্রাঞ্চ অনেকটা অপসারিত হয়ে যেতে পারে অথবা প্যাচটি অন্য কোন প্যাচের উপর নির্ভর করে যা এখনো এপ্লাই করা হয়নি। এই ক্ষেত্রে git am কমান্ডের প্রক্রিয়াটি ফেল করবে এবং আপনি কি করতে চান তা জিজ্ঞেস করবে
কিন্তু এমনটাও হতে পারে যে প্যাচ টি পরিষ্কারভাবে ক্রিয়েট হলো না। বরং প্যাচ যে ব্রাঞ্চ থেকে ক্রিয়েট করা হয়েছিল তা থেকে মেইন ব্রাঞ্চ অনেকটা অপসারিত হয়ে যেতে পারে অথবা প্যাচটি অন্য কোন প্যাচের উপর নির্ভর করে যা এখনো এপ্লাই করা হয়নি। এই ক্ষেত্রে git am কমান্ডের প্রক্রিয়াটি ফেল করবে এবং আপনি কি করতে চান তা জিজ্ঞেস করবে
$ git am 0001-see-if-this-helps-the-gem.patch
Applying: See if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Patch failed at 0001.
When you have resolved this problem run "git am --resolved".
If you would prefer to skip this patch, instead run "git am --skip".
To restore the original branch and stop patching run "git am --abort".
এই কমান্ড যেকোনো ফাইল থেকে কনফ্লিক্ট মার্কারদের চিহ্নিত করে নিবে অনেকটা মার্জ কিংবা রিবেসের মতো। একই পদ্ধতিতে এই সমস্যাটির সমাধান করা যাবে যেমন conflict এডিট করা, নতুন ফাইল স্টেজ করা এবং পরবর্তী প্যাচে যাওয়ার জন্য git am –resolved কমান্ডটি রান করা।
$ (fix the file)
$ git add ticgit.gemspec
$ git am --resolved
Applying: See if this helps the gem
যদি আপনি চান যে গিট সম্পূর্ণ নিজে থেকে আর একটু ইন্টেলিজেন্ট ভাবে সমাধান করে করবে তবে আপনি a3 কমান্ডটি অপশন হিসেবে পাস করতে পারেন যা গিটকে থ্রি ওয়ে মার্জ পদ্ধতিতে সমাধান করবে। তবে এই অপশনটি কোন ডিফল্ট নয় কারণ প্যাচ যে কমিটের কথা বলবে তা আপনার রিপোজিটরিতে না থাকলে এক্ষেত্রে কাজ করবে না। আর যদি কমিটটি থেকে থাকে এবং যদি প্যাচ পাবলিক কমিট এর ভিত্তিতে হয় তবে -3 অপশনটি অনেক বেশি উপযোগী হবে conflicted প্যাঁচ এপ্লাই এর ক্ষেত্রে।
$ git am -3 0001-see-if-this-helps-the-gem.patch
Applying: See if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.
এক্ষেত্রে -3 অপশন টি ছাড়া প্যাচকে একটি conflict হিসেবে গণ্য করা হবে যেহেতু -3অপশনটি স্বচ্ছ প্যাচের ক্ষেত্রে ব্যবহার করা হয়। যদি আপনি mboxথেকে কয়েকটি প্যাচ এপ্লাই করেন সেক্ষেত্রে আপনি ইন্টারেক্টিভ মুডে কমান্ডটি এপ্লাই করতে পারবেন যেখানে প্রতি প্যাচে তা থামবে এবং আপনাকে জিজ্ঞেস করবে আপনি তা এপ্লাই করতে চান কিনা।
$ git am -3 -i mbox
Commit Body is:
--------------------------
See if this helps the gem
--------------------------
Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all
যদি আপনার বেশ কয়েকটি প্যাচ সেভ থাকে তবে এটি উত্তম রূপে কাজ করবে কারণ আপনি প্রথম প্যাচটি দেখতে পারবেন যদি না আপনি মনে করতে পারেন যে এটি কি ছিল অথবা আপনি করেছেন এমন কোন প্যাচ এপ্লাই না করেন।
যখন আপনার টপিকের জন্য সমস্ত প্যাচ এপ্লাই হয়ে যায় এবং আপনার ব্রাঞ্চে কমিট হয়, তখন আপনি লং রানিং ব্রাঞ্চ এর ক্ষেত্রে কিভাবে ইন্টিগ্রেট করবেন তা সিদ্ধান্ত নিতে পারেন।
রিমোট ব্রাঞ্চে চেকআউট
যদি আপনার কন্ট্রিবিউশন একজন গিট ইউজার থেকে আসে যে নিজের রিপোজিটরি সেটাপ করেছে এবং তাতে বেশ কয়েকটি পরিবর্তন পুশ করেছে এবং পরবর্তীতে আপনাকে রিপোজিটরের ইউআরএল এবং রিমোট ব্রাঞ্চের নাম প্রেরণ করে যাতে চেঞ্জ গুলো হয়েছে আপনি তাদের রিমোট হিসেবে এড করতে পারবেন এবং লোকালি মার্জ করতে পারবেন। উদাহরণস্বরূপ যদি জেসিকা আপনাকে একটি ইমেইল করে বলে যে সে তার ruby-client ব্রাঞ্চে কিছু গুরুত্বপূর্ণ ফিক্স নতুন ফিচার এ্যাড করেছে আপনি তাদের রিমোট ভাবে এড করে টেস্ট করতে পারেন এবং আপনার লোকাল ব্রাঞ্চে তা চেক করতে পারেন।
$ git remote add jessica git://github.com/jessica/myproject.git
$ git fetch jessica
$ git checkout -b rubyclient jessica/ruby-client
পরবর্তীতে সে যদি আপনাকে আবার ইমেইল করে যাতে আরেকটি গুরুত্বপূর্ণ ফিচার আছে সে ক্ষেত্রে আপনি সরাসরি fetch এবং checkout করবেন কারণ আপনার ইতি মধ্যেই রিমোট সেটআপ রয়েছে।
যদি আপনি একজন ব্যক্তির সাথে নিয়মিত কাজ করেন তবে এটাই সবথেকে উত্তম পদ্ধতি। যদি কারোর একটা সিঙ্গেল পেজ থাকে যা ইতোমধ্যেই কনট্রিবিউট করেছে তাহলে ইমেইলের মাধ্যমে তা একসেপ্ট করা কম সময় সাপেক্ষ হবে সকলকে তাদের নিজের সার্ভারে কনজিউম করার থেকে এবং আরো কিছু পেজ পেতে রিমোট কে কন্টিনিউ ভাবে এড কিংবা রিমুভ করা যাবে।
এই পদ্ধতির অন্য আরেকটি সুবিধা হল যে আপনি কমেন্টের হিস্টোরি গুলো পেয়ে যাবেন যদিও আপনার march করার ক্ষেত্রে সমস্যা হয় সেক্ষেত্রেও আপনি হিস্টোরির কোথায় কাজ আছে তা জানবেন। a -3 সাপ্লাই করার থেকে একটি সঠিক three-way merge টাই default এবং আশা করা যায় প্যাচটা একটা পাবলিক কমিট থেকে উৎপন্ন যাতে আপনার আক্সেস রয়েছে। যদি আপনি কোন ব্যাক্তির সাথে নিয়মিত কাজ না করেন তবুও আপনি তার থেকে এই উপায়ে pull নিচে চান, তবে আপনি git pull কমান্ডে রিমোট রিপোজিটরির URL দিয়ে দিতে পারেন। এই pull টা শুধুমাত্র একবারের জন্যই এবং এতে রিমোট রেফারেন্স হিসেবে URL সেইভ থাকে না।
যদি আপনি একজন ব্যক্তির সাথে নিয়মিত কাজ করেন তবে এটাই সবথেকে উত্তম পদ্ধতি। যদি কারোর একটা সিঙ্গেল পেজ থাকে যা ইতোমধ্যেই কনট্রিবিউট করেছে তাহলে ইমেইলের মাধ্যমে তা একসেপ্ট করা কম সময় সাপেক্ষ হবে সকলকে তাদের নিজের সার্ভারে কনজিউম করার থেকে এবং আরো কিছু পেজ পেতে রিমোট কে কন্টিনিউ ভাবে এড কিংবা রিমুভ করা যাবে।
এই পদ্ধতির অন্য আরেকটি সুবিধা হল যে আপনি কমেন্টের হিস্টোরি গুলো পেয়ে যাবেন যদিও আপনার march করার ক্ষেত্রে সমস্যা হয় সেক্ষেত্রেও আপনি হিস্টোরির কোথায় কাজ আছে তা জানবেন। a -3 সাপ্লাই করার থেকে একটি সঠিক three-way merge টাই default এবং আশা করা যায় প্যাচটা একটা পাবলিক কমিট থেকে উৎপন্ন যাতে আপনার আক্সেস রয়েছে। যদি আপনি কোন ব্যাক্তির সাথে নিয়মিত কাজ না করেন তবুও আপনি তার থেকে এই উপায়ে pull নিচে চান, তবে আপনি git pull কমান্ডে রিমোট রিপোজিটরির URL দিয়ে দিতে পারেন। এই pull টা শুধুমাত্র একবারের জন্যই এবং এতে রিমোট রেফারেন্স হিসেবে URL সেইভ থাকে না।
$ git pull https://github.com/onetimeguy/project
From https://github.com/onetimeguy/project
* branch HEAD -> FETCH_HEAD
Merge made by the 'recursive' strategy.
Determining What Is Introduced
এখন আপনার একটি টপিক ব্রাঞ্চ আছে যেখানে আপনার করা কাজগুলো রয়েছে। এখন আসলে এগুলো নিয়ে আপনি কি করবেন? এই সেকশনটিতে বেশ কিছু কমান্ড নিয়ে আলোচনা করা হয়েছে, যেগুলো আপনার টপিক ব্রাঞ্চকে মেইন ব্রাঞ্চে মার্জ করার জন্য কি কি কাজ করতে হবে তা নির্দেশ করে।যেসব কমিট টপিক ব্রাঞ্চে রয়েছে কিন্তু মাস্টার ব্রাঞ্চে নেই সেগুলো রিভিও করে নেয় ভাল। আপনি master ব্রাঞ্চে ব্রাঞ্চ নামের পূর্বে –not কমান্ডটি অ্যাড করার মাধ্যমে master ব্রাঞ্চের কমিটগুলোকে বাদ দিতে পারেন। এটি master..contrib এর মতোন একই কাজ করে। যেমন যদি আপনার কন্ট্রিবিউটর আপনাকে ২ টি প্যাচ সেন্ড করে এবং আপনি contrib নামে একটি ব্রাঞ্চ তৈরি করেন ও তাতে প্যাচ ২ টা অ্যাপ্লাই করতে চান তবে আপনি নিচের কোডটি রান করতে পারেন।
$ git log contrib --not master
commit 5b6235bd297351589efc4d73316f0a68d484f118
Author: Scott Chacon
Date: Fri Oct 24 09:53:59 2008 -0700
See if this helps the gem
commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
Author: Scott Chacon
Date: Mon Oct 22 19:38:36 2008 -0700
Update gemspec to hopefully work better
প্রতিটা কমিট কি কি নতুন পরিবর্তন নিয়ে এসেছে তা দেখার জন্য আপনি git log এ -p অপশনটি পাস করতে পারেন।
আবার যদি টপিক ব্রাঞ্চটি অন্য ব্রাঞ্চে মার্জ করতে কি কি কনফ্লিক্ট আসতে পারে তা চেক করতে চান সেক্ষেত্রে একটি উদ্ভট ট্রিক্স ব্যবহার করে আপনি সঠিক ফলাফল পেতে পারেন। সেক্ষেত্রে আপনি এই কমান্ডটি রান করতে পারেন
আবার যদি টপিক ব্রাঞ্চটি অন্য ব্রাঞ্চে মার্জ করতে কি কি কনফ্লিক্ট আসতে পারে তা চেক করতে চান সেক্ষেত্রে একটি উদ্ভট ট্রিক্স ব্যবহার করে আপনি সঠিক ফলাফল পেতে পারেন। সেক্ষেত্রে আপনি এই কমান্ডটি রান করতে পারেন
$ git diff master
এই কমান্ডটি আপনাকে সকল diff দেখাবে কিন্তু কিছুটা ভুলও দেখাতে পারে। যদি আপনার টপিক ব্রাঞ্চ থেকে master ব্রাঞ্চ অনেক এগিয়ে থাকে, তবে আপনি একটা উদ্ভট রেসাল্ট দেখতে পাবেন কারণ গিট আপনার টপিক ব্রাঞ্চের শেষ কমিটের স্ন্যাপশটের সাথে master এর শেষ কমিটের তুলনা করে। উদাহরণস্বরূপ যদি আপনি master এর কোন ফাইলে একটি লাইন অ্যাড করেন, স্ন্যাপশটের একটি সরাসরি তুলনা এমন দেখাবে যে, টপিক ব্রাঞ্চ ওয়ি লাইনটিকে রিমোভ করতে যাচ্ছে। যদি master আপনার টপিক ব্রাঞ্চের সরাসরি ancestor হয়, সেক্ষেত্রে কোন সমস্যা হবে না কিন্তু যদি ২ টা হিস্টোরি ডাইভার্জ করে তাহলে diff তা এমন দেখাবে যে তাতে মনে হবে যে আপনি টপিক ব্রাঞ্চে সকল নতুন কাজ অ্যাড করছেন এবং master ব্রাঞ্চ থেকে সকল unique কাজ রিমোভ করে দিচ্ছেন।
আপনি মূলত যা দেখতে চান তা হচ্ছে টপিক ব্রাঞ্চে কি কি কাজ যুক্ত হবে যদি আপনি master এ তা মার্জ করেন। টপিক ব্রাঞ্চের সর্বশেষ কমিটের সাথে master ব্রাঞ্চ এর প্রথম common ancestor এর Git compare করে আপনি এই কাজ করতে পারেন। মূলত আপনি আলাদা করে common ancestor বের করে ও তাতে আপনার diff রান করে তা বের করতে পারেন।
আপনি মূলত যা দেখতে চান তা হচ্ছে টপিক ব্রাঞ্চে কি কি কাজ যুক্ত হবে যদি আপনি master এ তা মার্জ করেন। টপিক ব্রাঞ্চের সর্বশেষ কমিটের সাথে master ব্রাঞ্চ এর প্রথম common ancestor এর Git compare করে আপনি এই কাজ করতে পারেন। মূলত আপনি আলাদা করে common ancestor বের করে ও তাতে আপনার diff রান করে তা বের করতে পারেন।
$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db
অথবা
$ git diff $(git merge-base contrib master)
আলাদাভাবে এই দুটোর কোনটাই বিশেষভাবে সুবিধাজনক নয়। তাই গিট আরেকটা shorthand provide করে যা মূলত একই কাজ করে। এর নাম হল the triple-dot syntax.
$ git diff master...contrib
এই কমান্ডটা মূলত master ব্রাঞ্চ থেকে তৈরি হওইয়ার পর থেকে আপনার টপিক ব্রাঞ্চের সকল কাজগুলো প্রদর্শন করে।
Integrating Contributed Work
যখন আপনার টপিক ব্রাঞ্চের সকল কাজ একটি মেইনলাইন ব্রাঞ্চে ইন্টিগ্রেট করার জন্য প্রস্তুত হয়, তখন একটা প্রশন মাথায় আসে যে, কিভাবে এটা করব! আবার মেইনটেইনের জন্য বাকি ওয়ার্কফ্লো কেমন হবে তার প্রশ্নও মাথায় ঘুরপাক খায়। এক্ষেত্রে বেশকিছু উপায় রয়েছে এই কাজটি করার যা নিচে ব্যাখ্যা করা হল।Merging Workflows
master ব্রাঞ্চে সকল কাজ মার্জ করা একটা সাধারণ workflow. এক্ষেত্রে master ব্রাঞ্চটিতে স্টেবল কোড থাকবে। যখন আপনার টপিক ব্রাঞ্চের কাজটা কমপ্লিট হয়েছে বুঝতে পারবেন বা কারোর করা কাজ ভেরিয়াই করা শেষ করবেন তখন আপনি তা master ব্রাঞ্চে মার্জ করবেন ও সেই টপিক ব্রাঞ্চটি ডিলিট করে দিবেন। উদাহরণস্বরূপ আমাদের ২ টি ব্রাঞ্চ আছে যাদের নাম ruby_client ও php_client এবং আপনি ruby_client এর পর php_client কে মার্জ করলে, একটা টপিক ব্রাঞ্চ মার্জ করার পর আপনার হিস্টোরি এমন দেখাবে
এটা হল সবচেয়ে সহজ একটি workflow কিন্তু এটা সমস্যার কারণ হতে পারে যদি আপনি বড় বা কোণ স্টেবল প্রজেক্টের কাজ করেন যেখানে আপনি যা করেছেন তা নিয়ে অনেক বেশি সচেতন থাকতে চান।
যদি আপনার আরও বেশি গুরুত্বপূর্ণ প্রজেক্ট থাকে, সেক্ষেত্রে আপনি ২ ধাপের মার্জ সাইকেল ব্যবহার করতে পারেন। এক্ষেত্রে আপনার ২ টা লং রানিং ব্রাঞ্চ থাকবে master ও develop যেখানে নতুন কাজগুলো develop ব্রাঞ্চে যাবে আর অনেক স্টেবল রিলিজ এর ক্ষেত্রে master ব্রাঞ্চটি আপডেট করা হবে এবং নিয়মিত এই ২ টা ব্রাঞ্চ public repository তে পুশ করা হবে। অর্থাৎ প্রতিবার প্রতিবার টপিক ব্রাঞ্চটি master ব্রাঞ্চে মার্জ করা হবে এবং রিলিজের আগে স্টেবল কাজগুলো মাস্টার ব্রাঞ্চে নিয়ে যেতে হবে।
যদি আপনার আরও বেশি গুরুত্বপূর্ণ প্রজেক্ট থাকে, সেক্ষেত্রে আপনি ২ ধাপের মার্জ সাইকেল ব্যবহার করতে পারেন। এক্ষেত্রে আপনার ২ টা লং রানিং ব্রাঞ্চ থাকবে master ও develop যেখানে নতুন কাজগুলো develop ব্রাঞ্চে যাবে আর অনেক স্টেবল রিলিজ এর ক্ষেত্রে master ব্রাঞ্চটি আপডেট করা হবে এবং নিয়মিত এই ২ টা ব্রাঞ্চ public repository তে পুশ করা হবে। অর্থাৎ প্রতিবার প্রতিবার টপিক ব্রাঞ্চটি master ব্রাঞ্চে মার্জ করা হবে এবং রিলিজের আগে স্টেবল কাজগুলো মাস্টার ব্রাঞ্চে নিয়ে যেতে হবে।
ফলে যখন কেউ আপনার রিপোজিটরি ক্লোন করবে, তারা সর্বশেষ স্টেবল ভার্সন দেখতে master এ যাবে অথবা cutting-edge কন্টেন্ট এর জন্য develop এ যাবে। আপনি integrate ব্রাঞ্চ এর মাধ্যমে এই কনসেপ্টটাকে আরও বড় করতে পারেন যেখানে সকল কাজ একত্রে মার্জ করা হবে। পরে যখন ওই ব্রাঞ্চের কাজগুলো স্টেবল হবে ও টেস্ট কেইস গুল পাস করবে তখন আপনি তা ডেভেলপ ব্রাঞ্চে মার্জ করবেন এবং পরবর্তীতে আরও স্টেবলের সাপেক্ষে master ব্রাঞ্চে মার্জ করবেন।
Large-Merging Workflows
গিট প্রজেক্টের ৪ টি লং রানিং ব্রাঞ্চ রয়েছে। নতুন কাজের জন্য master, next, and seen এবং মেইনটেনেন্স এর জন্য maint। যখন একজন কন্ট্রিবিউটর এর দ্বারা নতুন কোন কাজ আসে তখন এটি মেইনটেনারের রিপোজিটরির টপিক ব্রাঞ্চে কালেক্ট করা হয়। এক্ষেত্রে টপিকগুলো সেইফ কি না বা কনসাম্পশনের জন্য প্রস্তুত কিনা তার উপর ভিত্তি করে মূল্যায়ন করা হয়। যদি তারা সেইফ হয় তবে তাদের next এ মার্জ করা হয় এবং ব্রাঞ্চটি পুশ করা হয় যাতে সকলেই এই ইন্টিগ্রেটেড টপিকটা পেয়ে যায়।
কিন্তু যদি এই টপিকে আরও কাজ করতে হয়, তবে তাদের seen ব্রাঞ্চে মার্জ করা হয় এবং পরবর্তীতে যখন এটা স্টেবল হয়, তখন এই টপিকগুলো আবার master এ রি-মার্জ হয়। next এবং seen ব্রাঞ্চগুলোও তখন master ব্রাঞ্চ থেকে রিবিল্ট হয়। ফলে master সবসময় সামনের দিকে মুভ করে, next প্রয়োজনসাপেক্ষে rebase করে আর seen প্রায়ই rebase হয়।
যখন একটি টপিক ব্রাঞ্চ master এ মার্জ হয়, তখন তা রিপোজিটরি থেকে রিমোভ হয়ে যায়। গিট প্রজেক্টের maint নামে একটি ব্রাঞ্চ রয়েছে, যা সর্বশেষ রিলিজ থেকে ফর্ক করা হয় যাতে করে মেইনটেনেন্স রিলিজ দরকার হলে তাতে ব্যাকপোর্টেড প্যাচ অ্যাপ্লাই করা যায়। এভাবে যখন আপনি একটা গিট রিপোজিটোরি ক্লোন করেন, আপনি ৪ টি ব্রাঞ্চে চেকআউট করে বিভিন্ন বিষয়ের উপর ভিত্তি করে ডেভেলপমেন্টের ভিন্ন ভিন্ন স্টেজে যেতে পারবেন।
Rebasing and Cherry-Picking Workflows
একটা লিনিয়ার হিস্টোরি মেইনটেইন করার জন্য কিছু মেইনটেনার মার্জ করা থেকে তাদের master branch এর টপে rebase বা cherry-pick করাকে প্রাধান্য দিয়ে থাকে। যখন আপনার টপিক ব্রাঞ্চে কাজ করতে হবে ও আপনি তা ইন্টিগ্রেট করতে চান তখন আপনি ওই ব্রাঞ্চে মুভ করবেন ও রিবেইস কমান্ড ব্যাবহারের মাধ্যমে master ব্রাঞ্চের টপে চেঞ্জগুলো রিবিল্ড করতে পারেন। যদি এটা সঠিকভাবে কাজ করে তাহলে আপনার master ব্রাঞ্চটাকে দ্রুত অগ্রগামী করতে পারবেন এবং সবশেষে একটা লিনিয়ার প্রজেক্ট হিস্টোরি সংরক্ষণ করতে পারবেন। কাজগুলোকে এক ব্রাঞ্চ থেকে অন্য ব্রাঞ্চে মুভ করানোর অন্য একটি পদ্ধতি হল cherry-pick যা মূলত একটি সিঙ্গেল কমিট রিবেইস করার মতোন পদ্ধতি। এটি একটি কমিট থেকে পাওয়া প্যাচকে আপনি বর্তমানে যে ব্রাঞ্চে আছেন তাতে পুনরায় ব্যবহার করার চেস্টা করে। যদি আপনার একটি টপিক ব্রাঞ্চে বেশ কয়েকটি কমিট থাকে এবং আপনি তাদের মধ্য থেকে যেকোন একটিকে অ্যাপ্লাই করতে চান অথবা আপনার একটি টপিক ব্রাঞ্চে শুধুমাত্র একটিই কমিট থাকে কিন্তু আপনি রিবেইস থেকে চেরি পিক কে prefer করেন, সেক্ষেত্রে বেশি উপযোগি। যেমন ধরন আপনি নিম্নোল্লিখিত একটি প্রজেক্ট আছে।
যদই আপনি আপনার master ব্রাঞ্চে e43a6 কমিটটি পুল করতে চান, আপনি এটি run করতে পারেন,
$ git cherry-pick e43a6
Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index fails."
3 files changed, 17 insertions(+), 3 deletions(-)
এতে e43a6 থেকে পাওয়া একই চেঞ্জ গুলো পুল হবে কিন্তু আপনি একটি নতুন কমিট SHA-1 ভ্যালু পাবেন কারণ এক্ষেত্রে অ্যাাপ্লাই এর তারিখের মাঝে ভিন্নতা রয়েছে। এখন আপনার হিস্টোরিটা অনেকটা এরুপ দেখাবে:
এখন আপনি আপনার টপিক ব্রাঞ্চকে রিমোভ ও যেসব কমিট পুল করতে চান না তাদের drop করে দিতে পারেন।
Rerere
যদি আপনি অনেক বেশি মার্জিং ও রিবেইসিং করেন কিংবা কোন লং লিভড টপিক ব্রাঞ্চকে মেইনটেইন করে আসেন, সেক্ষেত্রে গিটের rerere ফিচারটি আপনাকে সাহায্য করতে পারবে। Rerere এর পূর্ণরূপ হলো “reuse recorded resolution”, যা মেন্যুয়াল কনফ্লিক্ট সমাধানের একটা শর্টকাট পদ্ধতি। rerere যখন enabled থাকে, তখন গিট প্রতিটা মার্জ থেকে pre- ও post-images এর সেটকে সংরক্ষণ করে থাকে এবং যদি দেখে যে আপনি অলরেডি ফিক্স করেছেন এমন ধরনের কোন কনফ্লিক্ট আছে, এটা নিজে থেকেই লাস্ট টাইমের ফিক্সটা ব্যবহার করে সমাধান করে দিবে।এই ফিচারটা ২ ভাগে আসে – configuration setting ও command. configuration setting টা হল rerere.enabled এবং একে গ্লোবাল কনফিগে put করা অনেক সহজ।
$ git config --global rerere.enabled true
এখন যখনই কনফ্লিক্ট রিসলভ করে এমন মার্জ করা হয়, এই সমাধানটা ভবিষ্যতে ব্যবহারের জন্য cache এ থেকে যায়।
git rerere কমান্ড ব্যবহারের মাধ্যমে cache এর সাথে interact করা যায়। যখন এটা একাকি ইনভোক করা হয়, গিট সমধানের ডেটাবেস চেক করে এবং এই মার্জ কনফ্লিক্টের সাথে মিল খুজে বের করা ও তা সমাধানের চেষ্টা করে (যদিও rerere.enabled true সেট থাকলে এই কাজটি অটোমেটিকই হয়)। অবশ্য কি রেকর্ড করা হবে, cache থেকে নির্দিষ্ট কোণ সমাধান মুছে ফেলা বা পুরো cache টাকেই মুছে ফেলা এসবের জন্য কিছু sub command রয়েছে যা Rerere section এ আলোচনা করা হয়েছে।
git rerere কমান্ড ব্যবহারের মাধ্যমে cache এর সাথে interact করা যায়। যখন এটা একাকি ইনভোক করা হয়, গিট সমধানের ডেটাবেস চেক করে এবং এই মার্জ কনফ্লিক্টের সাথে মিল খুজে বের করা ও তা সমাধানের চেষ্টা করে (যদিও rerere.enabled true সেট থাকলে এই কাজটি অটোমেটিকই হয়)। অবশ্য কি রেকর্ড করা হবে, cache থেকে নির্দিষ্ট কোণ সমাধান মুছে ফেলা বা পুরো cache টাকেই মুছে ফেলা এসবের জন্য কিছু sub command রয়েছে যা Rerere section এ আলোচনা করা হয়েছে।
Tagging Your Releases
যখন আপনি একটি রিলিজ কাট করার সিদ্ধান্ত নেন তখন আপনি সম্ভবত একটি একটা ট্যাগ অ্যাাসাইন করতে চাইবেন, যাতে আপনি এগিয়ে যাওয়ার সাথে প্রতিটি ধাপেই সেই রিলিজটি ট্যাগ করতে পারেন। যদি আপনি মেইনটেনার হিসেবে ট্যাগকে সাইন করতে চান সেক্ষেত্রে ট্যাগিং টা নিম্নরূপে দেখাবে
$ git tag -s v1.5 -m 'my signed 1.5 tag'
You need a passphrase to unlock the secret key for
user: "Scott Chacon "
1024-bit DSA key, ID F721C45A, created 2009-02-09
ট্যাগকে সাইন করতে চাইলে ট্যাগ সাইন করার জন্য যে পাবলিক PGP key থাকে তার ডিস্ট্রিবিউশনের ক্ষেত্রে আপনি সমস্যার সম্মুখীন হতে পারেন। গিট প্রজেক্তের মেইনটেনার রিপোসিটরিতে পাবলিক key কে blob হিসেবে সেট করার মাধ্যমে এই সমস্যাটির সমাধান করবে। পরবর্তীতে একটা ট্যাগ অ্যাড করবে যা সরাসরি ঐ কন্টেন্টকে পয়েন্ট করবে। gpg –list-keys কমান্ডটি রান করার মাধ্যমে, আপনি কোন কি রান করবেন তা বের করতে পারবেন।
$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub 1024D/F721C45A 2009-02-09 [expires: 2010-02-09]
uid Scott Chacon
sub 2048g/45D02282 2009-02-09 [expires: 2010-02-09]
পরবর্তীতে git hash-object কমান্ডের মাধ্যমে এই key টা এক্সপোর্ট ও পাইপিং করে গিট ডেটাবেসে সরাসরি import করতে পারবেন যা গিটে ঐ কন্টেন্টগুলোর সাথে একটা নতুন blob যুক্ত করবে ও blob এর SHA-1 key টা back করবে।
$ gpg -a --export F721C45A | git hash-object -w --stdin
659ef797d181633c87ec71ac3f9ba29fe5775b92
এখন hash-object কমান্ডটি ব্যবহারের মাধ্যমে নতুন SHA-1 value তৈরি করার মাধ্যমে গিটে আপনার key এর কন্টেন্টগুলো আছে তাতে সরাসরি পয়েন্ট করে একটি ট্যাগ তৈরি করতে পারেন।
$ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92
যদি আপনি git push –tags কমান্ডটি রান করে তাহলে maintainer-pgp-pub ট্যাগটি সকলের সাথে শেয়ার হয়ে যাবে। যদি কেউ একটা ট্যাগ ভেরিফাই করতে চায়, তাহলে সরাসরি ডেটাবেসের বাইরে blob কে pull করে নিয়ে এসে PGP key কে import করতে পারবেন ও পরে তা GPG তে ইমপোর্ট করবেন।
$ git show maintainer-pgp-pub | gpg --import
সকল সাইন করা ট্যাগ ভেরিফাই করার জন্য এই ট্যাগটি ব্যবহার করা যাবে। আবার git show কমান্ডটি ব্যবহারের মাধ্যমে আপনি এন্ড ইউজারের আরও ডিটেইল ইনফর্মেশন ও ও ট্যাগ ভেরিফিকেশন করতে পারবেন।
Generating a Build Number
যেহেতু গিট প্রতিটা কমিটের সাথে v123 এভাবে নাম্বার ক্রমবর্ধন করে না, তাই যদি আপনি আপনার কমিটের সাথে হিউম্যান রিডেবল নাম পেতে চান, সেক্ষেত্রে কমিটের সাথে git describe কমান্ডটি চালাতে হবে। এর রেসপন্সসরূপ, এই কমিটের পূর্ববর্তী মোস্ট রিসেন্ট ট্যাগগুলোর নাম সম্বলিত একটি স্ট্রিং জেনারেট করবে যা হবে সর্বশেষ কমিটের পর থেকে কমিটের সংখ্যা ও একটি পার্শিয়াল SHA-1 ভ্যালু (-g এখানে git কে নির্দেশ করে)।
$ git describe master
v1.6.2-rc1-20-g8c5b85c
এভাবে আপনি মানুষের বোধগম্য নামে স্ন্যাপশট এক্সপোর্ট করতে পারেন। আবার যদি আপনি গিট রিপোজিটোরি থেকে ক্লোন করা সোর্স কোড থেকে গিট বিল্ড করে থাকেন সেক্ষেত্রে git –version কমান্ডটি আপনাকে একই ফলাফল দিবে। আর আপনি সরাসরি ট্যাগ করা এমন কমিট ব্যাখ্যা করতে চাইলে, এর মাধ্যমে আপনি শুধু আপনি ট্যাগ এর নামগুলো পাবেন। সাধারণত git describe এর কিছু অ্যানোটেড ট্যাগের প্রয়োজন হয়(যেমন -a or -s)। যদি আপনি lightweight(নন অ্যানোটেড ট্যাগ) এর সুবিধা নিতে চান সেক্ষেত্রে –tags অপশনটি কমান্ডের সাথে অ্যাড করুন। অবশ্য আপনি git checkout বা git show কমান্ডের টার্গেট হিসেবে এই স্ট্রিংটি ব্যবহার করতে পারেন যদিও এটি SHA-1 এর সংক্ষিপ্ত ভ্যালুর উপর নির্ভর করে , তাই এটি চিরজীবনের জন্য ভ্যালিড হবে না। যেমন লিনাক্স কার্নেল সম্প্রতি ৮ থেকে ১০ ক্যারেক্টারে জাম্প করেছে যাতে করে SHA-1 object এর uniqueness নিশ্চিত করতে পারে। তাই পূর্ববর্তী git describe কমান্ড এর আউটপুটগুলো invalidated হয়ে যাবে।
Preparing a Release
এবার সময় এসেছে একটা বিল্ড রিলিজ করার। এক্ষেত্রে git archive কমান্ডটি ব্যবহার করে যারা গিট ব্যবহারকারী নয় তাদের জন্য একটি সর্বশেষ স্ন্যাপশটের একটা আর্কাইভ বানিয়ে ফেলতে পারবেন।
$ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz
$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz
যদি কেউ সেই টার্বলটি ওপেন করে, তবে তারা সেই প্রজেক্ট ডিরেক্টরির সর্বশেষ স্ন্যাপচ্যাটগুলো পেয়ে যাবেন। একইভাবে আপনি git archive এ –format=zip কমান্ডটি পাস করার মাধ্যমে একটি জিপ আর্কাইভ তৈরি করে ফেলতে পারবেন।
$ git archive master --prefix='project/' --format=zip > `git describe master`.zip
আভাবে আপনি আপনার প্রজেক্ট রিলিজের একটা টার্বল ও একটি জিপ আর্কাইভ তৈরি করে ফেলতে পারবেন, যা আপনি আপনার ওয়েবসাইটে আপলোড কিংবা ইমেইলের মাধ্যমে বাকিদের সেন্ড করতে পারবেন।
শর্টলগ
এখন আপনার মেইনিং লিস্ট থেকে সকলকে মেইল করার সময়, যারা আপনার প্রজেক্ট নিয়ে জানতে আগ্রগী। git shortlog কমান্ডটি ব্যবহার করে প্রজেক্ট এর পূর্ববর্তী পরিবর্তনগুলো পর আর কি কি পরিবর্তন এসেছে তা খুব সহজেই পেতে পারেন। এটি আপনাকে কমিট রেঞ্জের একটী সারমর্ম দিবে, উদাহরণস্বরূপ – পূর্ববর্তী রিলিজ এর পর থেকে সকল কমিটের সারমর্ম। যদি আপনার পূর্ববর্তী রিলিজের নাম v1.0.1 হয়, তবে
$ git shortlog --no-merges master --not v1.0.1
Chris Wanstrath (6):
Add support for annotated tags to Grit::Tag
Add packed-refs annotated tag support.
Add Grit::Commit#to_patch
Update version and History.txt
Remove stray `puts`
Make ls_tree ignore nils
Tom Preston-Werner (4):
fix dates in history
dynamic version method
Version bump to 1.0.2
Regenerated gemspec for version 1.0.2
এভাবে আপনি অথোরের দ্বারা গ্রুপ করা v1.0.1 এর সকল সামারি স্বচ্ছভাবে পেয়ে যাবেন, যা আপনি আপনার মেইলিং লিস্টে ইমেইল করতে পারবেন।