৭.১১ গিট টুলস – সাবমডিউলস
সাবমডিউলস
অনেক সময় এমন হতে পারে যে একটি প্রজেক্ট এ কাজ করার সময় উক্ত প্রজেক্ট এর মধ্যে আমাদের অন্য প্রজেক্টকে ব্যবহারের প্রয়োজন হয়। এমনও হতে পারে যে ব্যবহৃত প্রজেক্টটি একটি তৃতীয় পাক্ষিক লাইব্রেরি অথবা আমরা প্রজেক্টটি আলাদা ভাবে তৈরী করতে চাচ্ছি যাতে একে অন্যান্য প্যারেন্ট প্রজেক্ট এ ব্যবহার করতে পারি। এইরকম অবস্থায় একটি সমস্যা দেখা দেয়, আর তা হলো, আপনি দুইটি প্রজেক্ট কেই আলাদা রাখতে চাচ্ছেন আবার একটি কে অন্যটির মধ্যে থেকে ব্যবহারের সুবিধাও চাচ্ছেন।
একটি উদাহরণ দেখা যাক, ধরা যাক, আপনি একটি ওয়েবসাইট তৈরী করছেন এবং তাতে এটম ফিডস যোগ করতে চাচ্ছেন। এটম জেনারেশন এর কোডটুকু আপনি নিজে না লিখে একটি লাইব্রেরি ব্যবহার করতে চাইছেন। এক্ষেত্রে আপনাকে হয় কোডটুকু কোন শেয়ার্ড লাইব্রেরি যেমন: সিপান ইন্সটল(CPAN install) অথবা রুবি জেম(Ruby gem) থেকে ইনক্লুড করতে হবে অথবা, সোর্স কোডটুকু আপনার নিজের প্রজেক্ট এ কপি করে নিয়ে আসতে হবে। কোড ইনক্লুড এর ক্ষেত্রে ঝামেলা হলো একে পরবর্তীতে নিজের মতো করে পরিবর্তন বা পরিবর্ধন করা যায় না এবং তার চেয়েও কষ্টসাধ্য একে ডেপ্লয় করা, কারণ, আপনাকে উক্ত লাইব্রেরিটি সকল ক্লায়েন্ট এর কাছে সজলভ্য করতে হবে। আবার, কোড কপি করে আপনার প্রজেক্টে ব্যবহার করে নিজের মতো করে পরিবর্তন করে নিলে, পরবর্তীতে উক্ত লাইব্রেরির কোন আপডেট আসলে তা আবার আপনার কোড এ সংজোযন সংযোজন এর ক্ষেত্রে ঝামেলা দেখা দিবে।
গিট সাবমডিউল ব্যবহার করে এই সমস্যাটির সমাধান করা যায়। সাবমডিউলগুলি আপনাকে একটি গিট রিপোজিটরিতে অন্য গিট রিপোজিটরিকে সাবডিরেক্টরি হিসাবে রাখতে দেয়। এটি আপনাকে আপনার প্রজেক্টে অন্য রিপোজিটরি ক্লোন করতে এবং আপনার কমিটসগুলোকে আলাদা রাখতে দেয়।
সাবমডিউলস শুরু করা যাক
আমরা একটি সহজাত প্রজেক্ট তৈরীর মাধ্যমে আলোচনা শুরু করব এবং আলোচনার সুবিধার্থে সম্পূর্ণ প্রজেক্টটিকে প্রধান ও কিছু উপ-প্রজেক্ট এ ভাগ করে নেব।
চলুন, পূর্ব-বিদ্যমান একটি গিট রিপোজিটরি কে আমাদের রিপোজিটরিতে সংযোজন এর মাধ্যমে আমরা কাজ শুরু করি। একটি নতুন সাবমডিউল সংযোজনের জন্য আপনাকে git submodule add কমান্ডটির পর প্রজেক্টটির সম্পূর্ণ বা রিলেটিভ পাথ দিয়ে দিতে হবে। আমরা এই উদাহরণটি দেখানোর জন্য যে লাইব্রেরিটি সংযোজন করবো তার নাম ডিবি-কানেক্টর (DbConnector)।
$ git submodule add https://github.com/chaconinc/DbConnector
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
সাবমডিউলগুলি সাবপ্রজেক্টটিকে একটি ডিরেক্টরিতে রাখবে, প্রথমত তার নাম সে দিবে উক্ত রিপোজিটরির নাম যা এইক্ষেত্রে ডিবি-কানেক্টর (DbConnector)। আপনি চাইলে অন্য কোন প্রজেক্ট এর পাথ ও দিতে পারেন, যদি আপনি অন্য কোথাও যেতে চান।
আপনি যদি এখন git status কমান্ডটি রান করেন তাহলে এমন কিছু জিনিস দেখতে পারবেন-
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD ..." to unstage)
new file: .gitmodules
new file: DbConnector
প্রথমে আপনার নতুন .gitmodules ফাইলটি লক্ষ্য করা উচিত। এটি একটি কনফিগারেশন ফাইল যা প্রোজেক্টের ইউ আর এল (URL) এবং লোকাল সাবডিরেক্টরির মধ্যে ম্যাপিং করে যাতে আপনি এটি পুল করেছেন:
[submodule "DbConnector"]
path = DbConnector
url = https://github.com/chaconinc/DbConnector
আপনার যদি একাধিক সাবমডিউল থাকে তবে এই ফাইলটিতে আপনার একাধিক এন্ট্রি থাকবে। আপনাকে মনে রাখতে হবে যে এই ফাইলটি আপনার অন্যান্য ফাইলের সাথে সংস্করণ-নিয়ন্ত্রিত, যেমন আপনার .gitignore ফাইল। এটি আপনার বাকি প্রজেক্টের সাথে পুশ এবং পুল করা । এইভাবে অন্যরা যারা এই প্রজেক্টটি ক্লোন করবে তারা জানবে যে সাবমডিউলের প্রজেক্টগুলো কোথা থেকে পেতে হবে।
বিঃদ্রঃ
যেহেতু .gitmodules ফাইলের ইউ আর এল (URL) অন্যরা প্রথমে ক্লোন/ফেচ করার চেষ্টা করবে, তাই সম্ভব হলে তারা অ্যাক্সেস করতে পারে এমন একটি ইউ আর এল ব্যবহার করবেন। উদাহরণ স্বরূপ, আপনি যদি ভিন্ন একটি ইউ আর এল ব্যবহার করতে চান তাহলে এমন একটি ইউ আর এল ব্যবহার করুন যা অন্যরা সহজে অ্যাক্সেস করতে পারবে। আপনি আপনার নিজের ব্যবহারের জন্য
git config submodule.DbConnector.url PRIVATE_URL দিয়ে স্থানীয়ভাবে এই মানটিকে ওভাররাইট করতে পারেন। প্রযোজ্য হলে, একটি আপেক্ষিক ইউ আর এল (URL) ব্যবহার করতে পারেন।
গিট স্ট্যাটাস (git status) আউটপুটে অন্যান্য লিস্টিং গুলো হল প্রজেক্ট ফোল্ডার এন্ট্রি। আপনি যদি এটিতে git diff চালান তবে আপনি আকর্ষণীয় কিছু দেখতে পাবেন:
$ git diff --cached DbConnector
diff --git a/DbConnector b/DbConnector
new file mode 160000
index 0000000..c3f01dc
--- /dev/null
+++ b/DbConnector
@@ -0,0 +1 @@
+Subproject commit c3f01dc8862123d317dd46284b05b6892c7b29bc
যদিও ডিবি-কানেক্টর (DbConnector) আপনার কাজের ডিরেক্টরিতে একটি সাবডিরেক্টরি, গিট এটিকে একটি সাবমডিউল হিসাবে দেখে এবং আপনি যখন সেই ডিরেক্টরিতে না থাকেন তখন এটির বিষয়বস্তু ট্র্যাক করে না। গিট উক্ত ডিরেক্টরিকে প্রধান রিপোজিটরি থেকে একটি কমিট হিসেবে দেখে।
$ git diff --cached --submodule
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..71fc376
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "DbConnector"]
+ path = DbConnector
+ url = https://github.com/chaconinc/DbConnector
Submodule DbConnector 0000000...c3f01dc (new submodule)
যখন আপনি কমিট করবেন, তখন আপনি এমন কিছু দেখবেন-
$ git commit -am 'Add DbConnector module'
[master fb9093c] Add DbConnector module
2 files changed, 4 insertions(+)
create mode 100644 .gitmodules
create mode 160000 DbConnector
ডিবি-কানেক্টর (DbConnector) এন্ট্রির জন্য 160000 মোড লক্ষ্য করুন। এটি গিটে একটি বিশেষ মোড যার মূলত অর্থ হল আপনি একটি কমিট এর মাধ্যমে একটি সাবডিরেক্টরি বা ফাইলের পরিবর্তে একটি ডিরেক্টরিকে এন্ট্রি হিসাবে রেকর্ড করছেন।
শেষমেষ পরিবর্তন গুলো পুশ করে দিন-
$ git push origin master
সাবমডিউলস সহ একটি প্রজেকট ক্লোনিং
এখানে আমরা একটি সাবমডিউল সহ একটি প্রজেক্ট কে ক্লোন করব। যখন আপনি এই ধরনের একটি প্রজেক্ট ক্লোন করেন, ডিফল্টরূপে আপনি একটি ডিরেক্টরি পান যেখানে সাবমডিউলগুলো থাকবে, কিন্তু এখনও তাদের মধ্যে কোনো ফাইল পাওয়া যাবে না।
$ git clone https://github.com/chaconinc/MainProject
Cloning into 'MainProject'...
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 14 (delta 1), reused 13 (delta 0)
Unpacking objects: 100% (14/14), done.
Checking connectivity... done.
$ cd MainProject
$ ls -la
total 16
drwxr-xr-x 9 schacon staff 306 Sep 17 15:21 .
drwxr-xr-x 7 schacon staff 238 Sep 17 15:21 ..
drwxr-xr-x 13 schacon staff 442 Sep 17 15:21 .git
-rw-r--r-- 1 schacon staff 92 Sep 17 15:21 .gitmodules
drwxr-xr-x 2 schacon staff 68 Sep 17 15:21 DbConnector
-rw-r--r-- 1 schacon staff 756 Sep 17 15:21 Makefile
drwxr-xr-x 3 schacon staff 102 Sep 17 15:21 includes
drwxr-xr-x 4 schacon staff 136 Sep 17 15:21 scripts
drwxr-xr-x 4 schacon staff 136 Sep 17 15:21 src
$ cd DbConnector/
$ ls
$
ডিবি-কানেক্টর (DbConnector) ডিরেক্টরিটি আপনি পাবেন কিন্তু, তা ফাঁকা পাবেন। আপনাকে অবশ্যই দুটি কমান্ড চালাতে হবে: git submodule init কমান্ডটি লোকাল কনফিগারেশন ফাইল শুরু করতে এবং git submodule update সেই প্রকল্প থেকে সমস্ত ডেটা আনতে। এখন আপনি আপনার সুপার প্রজেক্টে তালিকাভুক্ত কমিট এ চেকআউট করতে পারবেন।
$ git submodule init
Submodule 'DbConnector' (https://github.com/chaconinc/DbConnector) registered for path 'DbConnector'
$ git submodule update
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Submodule path 'DbConnector': checked out 'c3f01dc8862123d317dd46284b05b6892c7b29bc'
এখন আপনার ডিবি-কানেক্টর (DbConnector) সাবডিরেক্টরি ঠিক সেই অবস্থায় চলে গেলো পূর্বে যখন আপনি কমিটি করেছিলেন।
এটি করার সহজতর আরো একটি উপায় আছে, আপনি যদি git clone কমান্ডে –recurse-submodules পাস করেন, তাহলে এটি রিপজিটোরির প্রতিটি সাবমডিউল স্বয়ংক্রিয়ভাবে আরম্ভ ও আপডেট করবে, যদি রিপোজিটরির যেকোনো সাবমডিউলের আবার নিজেদের ও সাবমডিউলস থাকে।
$ git clone --recurse-submodules https://github.com/chaconinc/MainProject
Cloning into 'MainProject'...
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 14 (delta 1), reused 13 (delta 0)
Unpacking objects: 100% (14/14), done.
Checking connectivity... done.
Submodule 'DbConnector' (https://github.com/chaconinc/DbConnector) registered for path 'DbConnector'
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Submodule path 'DbConnector': checked out 'c3f01dc8862123d317dd46284b05b6892c7b29bc'
আপনি যদি ইতিমধ্যেই প্রজেক্টটি ক্লোন করে থাকেন এবং –recurse-submodules দিতে ভুলে যান, তাহলে আপনি git submodule init এবং git submodule update এর ধাপগুলিকে git submodule update –init চালিয়ে একত্রিত করতে পারেন। যেকোনো নেস্টেড সাবমডিউল শুরু করতে, ফেচ করতে এবং চেকআউট করতে, আপনি ফুলপ্রুফ গিট সাবমডিউল আপডেট –init –recursive ব্যবহার করতে পারেন।
সাবমডিউল সহ একটি প্রজেক্টে কাজ করা যাক
এখন আমাদের কাছে সাবমডিউল সহ একটি প্রকল্পের অনুলিপি রয়েছে এবং আমরা মূল প্রকল্প এবং সাবমডিউল প্রকল্প উভয় ক্ষেত্রেই আমাদের সতীর্থদের সাথে সহযোগিতা করব।
রিমোট সাবমডিউল অগ্রবর্তী পরিবর্তনগুলো পুল করা
একটি প্রজেক্টে সাবমডিউল ব্যবহার করার সহজতম মডেলটি হবে যদি আপনি কেবল একটি সাবপ্রজেক্ট ব্যবহার করেন এবং সময়ে সময়ে এটি থেকে আপডেট পেতে চান কিন্তু আসলে আপনার চেকআউটে কিছু পরিবর্তন করতে চান না। একটি সহজাত উদাহরণের মাধ্যমে দেখা যাক-
আপনি যদি একটি সাবমডিউলে নতুন কাজগুলো নিয়ে আসতে চান, আপনি সাব প্রজেক্ট ডিরেক্টরিতে যেতে পারেন এবং লোকাল কোড আপডেট করতে গিট ফেচ কমান্ড চালাতে পারেন এবং গিট এর অগ্রবর্তী শাখাকে মার্জ করতে পারেন।
$ git fetch
From https://github.com/chaconinc/DbConnector
c3f01dc..d0354fc master -> origin/master
$ git merge origin/master
Updating c3f01dc..d0354fc
Fast-forward
scripts/connect.sh | 1 +
src/db.c | 1 +
2 files changed, 2 insertions(+)
এখন আপনি যদি মূল প্রজেক্টে ফিরে যান এবং git diff –submodule চালান তবে আপনি দেখতে পাবেন যে সাবমডিউল আপডেট করা হয়েছে এবং এতে যোগ করা কমিটগুলির একটি তালিকা পাবেন। আপনি যদি প্রতিবার git diff চালাতে –submodule টাইপ করতে না চান, তাহলে আপনি “log” এ diff.submodule কনফিগার মান সেট করে এটিকে ডিফল্ট ফর্ম্যাট হিসাবে সেট করে দিতে পারেন।
$ git config --global diff.submodule log
$ git diff
Submodule DbConnector c3f01dc..d0354fc:
> more efficient db routine
> better connection routine
আপনি যদি এই অবস্থায় কমিট করেন, তাহলে আপনি সাবমডিউলকে লক করে ফেলবেন নতুন কোড আনয়ন এর ক্ষেত্রে যখন অন্যরা আপডেট করবে।
এটি করার একটি সহজ উপায়ও রয়েছে, যদি আপনি ম্যানুয়ালি আনতে এবং সাবডিরেক্টরিতে মার্জ না করতে পছন্দ করেন। আপনি যদি git submodule update –remote কমান্ডটি চালান, গিট আপনার সাবমডিউলগুলিতে যাবে এবং ফেচ এবং আপডেট করে দিবে।
$ git submodule update --remote DbConnector
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 2), reused 4 (delta 2)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector
3f19983..d0354fc master -> origin/master
Submodule path 'DbConnector': checked out 'd0354fc054692d3906c85c3af05ddce39a1c0644'
এই কমান্ডটি ডিফল্টরূপে অনুমান করবে যে আপনি রিমোট সাবমডিউল রিপোজিটরির ডিফল্ট ব্রাঞ্চে চেকআউট আপডেট করতে চান (যা রিমোটে HEAD দ্বারা নির্দেশিত)। তবে আপনি চাইলে এটিকে আলাদা কিছুতে সেট করতে পারেন। উদাহরণস্বরূপ, আপনি যদি এটিকে আপনার ডিবিকানেক্টর (DbConnector) এর কোন “স্থিতিশীল” শাখাতে সেট করতে চান তাহলে, .gitmodules ফাইলটিতে (যাতে অন্য সবাই এটি ট্র্যাক করতে পারে) সেট করতে পারেন, অথবা শুধুমাত্র আপনার স্থানীয় .git/config ফাইলে সেট করতে পারেন। .gitmodules ফাইলে সেট করা যাক:
$ git config -f .gitmodules submodule.DbConnector.branch stable
$ git submodule update --remote
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 2), reused 4 (delta 2)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector
27cf5d3..c87d55d stable -> origin/stable
Submodule path 'DbConnector': checked out 'c87d55d4c6d4b05ee34fbc8cb6f7bf4585ae6687'
যদি আপনি -f .gitmodules এমনটি করেন তাহলে, শুধু আপনার জন্যই পরিবর্তনগুলো হবে কিন্তু এটি রিপোজিটরির সাথে ট্র্যাক রাখা সমীচীন হবে যাতে সবাই তা করতে পারে। যখন আমরা এই মুহুর্তে গিট স্ট্যাটাস চালাই, গিট আমাদের দেখাবে যে আমাদের সাবমডিউলে “নতুন কমিটস” রয়েছে।
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: .gitmodules
modified: DbConnector (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
আপনি যদি কনফিগারেশন সেটিং status.submodulesummary সেট করেন, Git আপনাকে আপনার সাবমডিউলের পরিবর্তনের একটি সংক্ষিপ্ত সারাংশও দেখাবে:
$ git config status.submodulesummary 1
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: .gitmodules
modified: DbConnector (new commits)
Submodules changed but not updated:
* DbConnector c3f01dc...c87d55d (4):
> catch non-null terminated lines
এই মুহুর্তে আপনি যদি গিট ডিফ (git diff) চালান তবে আমরা উভয়ই দেখতে পাব যে আমরা আমাদের .gitmodules ফাইলটি সংশোধন করেছি এবং এছাড়াও অনেকগুলি কমিট রয়েছে যা আমরা পুল নিয়েছি এবং আমাদের সাবমডিউল প্রজেক্টে কমিট উপজোগী।
$ git diff
diff --git a/.gitmodules b/.gitmodules
index 6fc0b3d..fd1cc29 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
[submodule "DbConnector"]
path = DbConnector
url = https://github.com/chaconinc/DbConnector
+ branch = stable
Submodule DbConnector c3f01dc..c87d55d:
> catch non-null terminated lines
> more robust error handling
> more efficient db routine
> better connection routine
এটি বেশ দুর্দান্ত কারণ আমরা আসলে আমাদের সাবমডিউলে কমিটের লগ দেখতে পাচ্ছি যা আমরা করতে যাচ্ছি। একবার কমিট করা হলেও, আপনি যখন git log -p চালাবেন তখন আপনি এটি দেখতে পাবেন।
$ git log -p --submodule
commit 0a24cfc121a8a3c118e0105ae4ae4c00281cf7ae
Author: Scott Chacon
Date: Wed Sep 17 16:37:02 2014 +0200
updating DbConnector for bug fixes
diff --git a/.gitmodules b/.gitmodules
index 6fc0b3d..fd1cc29 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
[submodule "DbConnector"]
path = DbConnector
url = https://github.com/chaconinc/DbConnector
+ branch = stable
Submodule DbConnector c3f01dc..c87d55d:
> catch non-null terminated lines
> more robust error handling
> more efficient db routine
> better connection routine
আপনি যখন git submodule update –remote চালান তখন গিট ডিফল্টভাবে আপনার সমস্ত সাবমডিউলগুলো আপডেট করার চেষ্টা করবে। আপনার যদি অনেকগুলো সাবমডিউল থাকে তবে আপনি কোন নির্দিষ্ট সাবমডিউল আপডেট করতে চাইলে তার নাম পাস করতে পারেন।
রিমোট প্রজেক্ট থেকে অগ্রবর্তী পরিবর্তনগুলো আনয়ন
এখন আমরা আমাদের সহজোগী কোডারদের দিক থেকে চিন্তা করি যাদের কাছে মেইনপ্রজেক্ট রিপোজিটরির নিজস্ব স্থানীয় ক্লোন রয়েছে। আপনার নতুন কমিটের পরিবর্তনগুলি পেতে কেবল গিট পুল চালানোই যথেষ্ট নয়:
$ git pull
From https://github.com/chaconinc/MainProject
fb9093c..0a24cfc master -> origin/master
Fetching submodule DbConnector
From https://github.com/chaconinc/DbConnector
c3f01dc..c87d55d stable -> origin/stable
Updating fb9093c..0a24cfc
Fast-forward
.gitmodules | 2 +-
DbConnector | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: DbConnector (new commits)
Submodules changed but not updated:
* DbConnector c87d55d...c3f01dc (4):
< catch non-null terminated lines
< more robust error handling
< more efficient db routine
< better connection routine
no changes added to commit (use "git add" and/or "git commit -a")
ডিফল্টরূপে, গিট পুল কমান্ড পুনরাবৃত্তিমূলকভাবে সাবমডিউল পরিবর্তন আনে, যেমনটি আমরা উপরের প্রথম কমান্ডের আউটপুটে দেখতে পাচ্ছি। যাইহোক, এটি সাবমডিউলকে আপডেট করে না। এটি গিট স্ট্যাটাস (git status) কমান্ডের আউটপুট দ্বারা দেখানো হয়, যা দেখায় যে সাবমডিউলটি “পরিবর্তিত” এবং “নতুন কমিটস” রয়েছে। আরও কী, বন্ধনীগুলো নতুন কমিট বিন্দু বাম (<) দেখাচ্ছে, নির্দেশ করে যে এই কমিটগুলো মেইনপ্রজেক্টে রেকর্ড করা হয়েছে কিন্তু লোকাল ডিবিকানেক্টর (DbConnector) চেকআউটে উপস্থিত নেই। আপডেটটি চূড়ান্ত করতে, আপনাকে গিট সাবমডিউল আপডেট চালাতে হবে:
$ git submodule update --init --recursive
Submodule path 'vendor/plugins/demo': checked out '48679c6302815f6c76f1fe30625d795d9e55fc56'
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean
কোনো ঝামেলা যাতে না হয় তার জন্য আপনাকে –init সহ git submodule update কমান্ড রান করা উচিৎ কারণ আপনআর মেইন প্রজেক্ট পুলের মাধ্যমে আসা কমিটসগুলো নতুন সাবমডিউল সংযোজন করতে পারে, নাম্বার, –recursive উপ-কমান্ড এর মাধ্যমে কোনো নেস্টেড সাবমডিউল আস্তে পারে।
আপনি যদি এই প্রক্রিয়াটিকে স্বয়ংক্রিয় করতে চান, আপনি git pull কমান্ডে –recurse-submodules উপ-কমান্ড যোগ করতে পারেন (Git 2.14 থেকে)। এটি পুলের ঠিক পরেই গিট রান গিট সাবমডিউল আপডেট ( git submodule update) করবে, সাবমডিউলগুলিকে সঠিক অবস্থায় রাখবে। তাছাড়া, আপনি যদি গিটকে সবসময় –recurse-submodules এর সাথে পুল করতে চান, তাহলে আপনি কনফিগারেশন অপশন submodule.recurse-কে true-এ সেট করতে পারেন (এটি Git 2.15 থেকে গিট পুলের জন্য কাজ করে)। এই অপশনটি Git সমর্থিত সমস্ত কমান্ডের জন্য –recurse-submodules ব্যবহার করবে (ক্লোন ব্যতীত)।
সুপারপ্রজেক্ট এর আপডেটগুলো পুল সময় একটি বিশেষ পরিস্থিতি ঘটতে পারে: এটি হতে পারে যে অগ্রবর্তী রিপোজিটরি আপনার পুল করা কমিটগুলির একটিতে .gitmodules ফাইলের সাবমডিউলের ইউ আর এল (URL) পরিবর্তন করেছে। উদাহরণস্বরূপ এটি ঘটতে পারে যদি সাবমডিউল প্রজেক্ট তার হোস্টিং প্ল্যাটফর্ম পরিবর্তন করে। সেক্ষেত্রে, git pull –recurse-submodules, অথবা git submodule update, ব্যর্থ হওয়া সম্ভব যদি সুপারপ্রজেক্ট একটি সাবমডিউল কমিট উল্লেখ করে যা আপনার রিপোজিটরিতে স্থানীয়ভাবে কনফিগার করা সাবমডিউল রিমোটে পাওয়া যায় না। এই পরিস্থিতির প্রতিকার করার জন্য, গিট সাবমডিউল সিঙ্ক কমান্ড প্রয়োজন:
# copy the new URL to your local config
$ git submodule sync --recursive
# update the submodule from the new URL
$ git submodule update --init --recursive
একটি সাবমডিউলে কাজ করা
এটা খুবই সম্ভব যে আপনি যদি সাবমডিউল ব্যবহার করেন তবে আপনি তা করছেন কারণ আপনি মূল প্রজেক্টের কোডে একই সময়ে সাবমডিউলের (বা বেশ কয়েকটি সাবমডিউল জুড়ে) কোডে কাজ করতে চান। অন্যথায় আপনি সম্ভবত এর পরিবর্তে একটি সহজ নির্ভরতা ব্যবস্থাপনা সিস্টেম ব্যবহার করবেন (যেমন মাভেন (Maven) বা রুবিজেমস (Rubygems))।
সুতরাং এখন মূল প্রকল্পের মতো একই সময়ে সাবমডিউলে পরিবর্তন করার এবং একই সময়ে সেই পরিবর্তনগুলোকে কমিট করার এবং প্রকাশ করার একটি উদাহরণ দিয়ে যাওয়া যাক।
এখন পর্যন্ত, যখন আমরা সাবমডিউল রিপোজিটরি থেকে পরিবর্তন আনতে গিট সাবমডিউল আপডেট কমান্ড চালাই, তখন গিট পরিবর্তনগুলি পাবে এবং সাবডিরেক্টরিতে ফাইলগুলি আপডেট করবে কিন্তু সাব-রিপোজিটরিটিকে “বিচ্ছিন্ন হেড” অবস্থায় ছেড়ে দেবে। এর মানে হলো, ট্র্যাক করার মতো কোনো কার্যকর স্থানীয় ব্রাঞ্চ (যেমন মাস্টার, উদাহরণস্বরূপ) থাকবে না। কোনো পরিবর্তন ট্র্যাক করতে পারে এমন কর্জকরী ব্রাঞ্চ নেই, যার মানে হলো, আপনি সাবমডিউলে পরিবর্তনগুলি কমিট করলেও, পরের বার আপনি যখন গিট সাবমডিউল আপডেট চালাবেন তখন সেই পরিবর্তনগুলি সম্ভবত হারিয়ে যাবে। আপনি যদি সাবমডিউলের পরিবর্তনগুলি ট্র্যাক করতে চান তবে আপনাকে কিছু অতিরিক্ত পদক্ষেপ করতে হবে।
আপনার সাবমডিউল সেট আপ করতে যাতে প্রবেশ করা এবং ভেতরে ঢুকে পরিবর্তন করা যাতে সহজ হয়, আপনাকে দুটি জিনিস করতে হবে। আপনাকে প্রতিটি সাবমডিউলে যেতে হবে এবং কার্যকর একটি ব্রাঞ্চ খুঁজে বের করতে হবে। তারপর আপনাকে গিট কে বযে দিতে হবে যে, কি করতে হবে যদি আপনি কোনো পরিবর্তন করেন এবং এর পর git submodule update –remote কমান্ডটি অগ্রবর্তী কাজকে পুল করে নিয়ে আসে। বিকল্পগুলো হল যে আপনি সেগুলোকে আপনার স্থানীয় কাজের মধ্যে একত্রিত করতে পারেন, অথবা আপনি নতুন পরিবর্তনগুলোর উপরে আপনার স্থানীয় কাজগুলিকে রিবেস করার চেষ্টা করতে পারেন৷
প্রথমত, আসুন আমাদের সাবমডিউল ডিরেক্টরিতে যাই এবং একটি ব্রাঞ্চ দেখি-
$ cd DbConnector/
$ git checkout stable
Switched to branch 'stable'
আসুন “মার্জ” অপশনের মাধ্যমে আমাদের সাবমডিউল আপডেট করার চেষ্টা করি। এটি ম্যানুয়ালি নির্দিষ্ট করতে, আমরা আমাদের আপডেট করলে –merge অপশনটি যোগ করতে পারি। এখানে আমরা দেখব যে এই সাবমডিউলটির সার্ভারে একটি পরিবর্তন হয়েছে এবং এটি একত্রিত হয়ে গেছে।
$ cd ..
$ git submodule update --remote --merge
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 2), reused 4 (delta 2)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector
c87d55d..92c7337 stable -> origin/stable
Updating c87d55d..92c7337
Fast-forward
src/main.c | 1 +
1 file changed, 1 insertion(+)
Submodule path 'DbConnector': merged in '92c7337b30ef9e0893e758dac2459d07362ab5ea'
আমরা যদি ডিবিকানেক্টর (DbConnector) ডিরেক্টরিতে যাই, আমরা দেখব ইতিমধ্যেই আমাদের স্থানীয় স্থিতিশীল শাখায় নতুন পরিবর্তনগুলি একত্রিত হয়েছে। এখন দেখা যাক কি হয় যখন আমরা লাইব্রেরিতে আমাদের নিজস্ব স্থানীয় পরিবর্তন করি এবং অন্য কেউ একই সময়ে অন্য একটি পরিবর্তন পুশ করে।
$ cd DbConnector/
$ vim src/db.c
$ git commit -am 'Unicode support'
[stable f906e16] Unicode support
1 file changed, 1 insertion(+)
এখন যদি আমরা আমাদের সাবমডিউল আপডেট করি তাহলে আমরা দেখতে পাব যখন আমরা একটি স্থানীয় পরিবর্তন করি এবং অগ্রবর্তী কোডে একটি পরিবর্তন আসে তখন আমাদের অন্তর্ভুক্ত করতে হবে।
$ cd ..
$ git submodule update --remote --rebase
First, rewinding head to replay your work on top of it...
Applying: Unicode support
Submodule path 'DbConnector': rebased into '5d60ef9bbebf5a0c1c1050f242ceeb54ad58da94'
আপনি যদি –rebase বা –merge করতে ভুলে যান তাহলে, Git সার্ভারে যা আছে তা নিয়ে আপনার সাবমডিউল আপডেট করে দিবে এবং আপনার প্রজেক্টকে একটি বিচ্ছিন্ন হেড স্টেটে রিসেট করবে।
$ git submodule update --remote
Submodule path 'DbConnector': checked out '5d60ef9bbebf5a0c1c1050f242ceeb54ad58da94'
যদি এমনটি হয়, চিন্তার কোনো কারণ নেই, আপনি আপনার ডিরেক্টরিতে যাবেন এবং আপনার ব্রাঞ্চে আবার চেক-আউট করতে পারেন (যেটিতে এখনও আপনার কাজ আছে) এবং ম্যানুয়ালি অরিজিন/স্টেবল (বা আপনি যে কোনও রিমোট ব্রাঞ্চ চান) ব্রাঞ্চ মার্জ বা রিবেস করতে পারেন।
আপনি যদি আপনার সাবমডিউলে আপনার পরিবর্তনগুলো কমিট না করে থাকেন এবং আপনি একটি সাবমডিউল আপডেট চালান যা সমস্যা সৃষ্টি করতে পারে, গিট পরিবর্তনগুলো ফেচ করবে কিন্তু অসংরক্ষিত কাজ ওভাররাইট করবে না।
$ git submodule update --remote
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 4 (delta 0), reused 4 (delta 0)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector
5d60ef9..c75e92a stable -> origin/stable
error: Your local changes to the following files would be overwritten by checkout:
scripts/setup.sh
Please, commit your changes or stash them before you can switch branches.
Aborting
Unable to checkout 'c75e92a2b3855c9e5b66f915308390d9db204aca' in submodule path 'DbConnector'
আপনি যদি এমন কোনো পরিবর্তন আনেন যা অগ্রবর্তী কোনো কাজের সাথে কনফ্লিক্ট তৈরী করে, গিট্ আপনাকে জানাবে যখন আপনি আপডেট রান করবেন।
$ git submodule update --remote --merge
Auto-merging scripts/setup.sh
CONFLICT (content): Merge conflict in scripts/setup.sh
Recorded preimage for 'scripts/setup.sh'
Automatic merge failed; fix conflicts and then commit the result.
Unable to merge 'c75e92a2b3855c9e5b66f915308390d9db204aca' in submodule path 'DbConnector'
আপনি সাবমডিউল ডিরেক্টরিতে যেতে পারেন এবং কনফ্লিক্ট ঠিক করতে পারেন ঠিক যেমনটা আপনি সাধারণত করেন।
সাবমডিউল এর পরিবর্তন পাবলিশ করা
এখন আমাদের সাবমডিউল ডিরেক্টরিতে কিছু পরিবর্তন আছে। এর মধ্যে কিছু আমাদের আপডেটের মাধ্যমে অগ্রবর্তী ব্রাঞ্চ থেকে আনা হয়েছে এবং অন্যগুলো স্থানীয়ভাবে তৈরি করা হয়েছে এবং এখনও অন্য কারও কাছে উপলব্ধ নয় কারণ আমরা এখনও সেগুলো পুশ করিনি৷
$ git diff
Submodule DbConnector c87d55d..82d2ad3:
> Merge from origin/stable
> Update setup script
> Unicode support
> Remove unnecessary method
> Add new option for conn pooling
যদি আমরা মূল প্রজেক্টে কমিট করি এবং আপ-পুশ করি সাবমডিউলের পরিবর্তনগুলোকে পুশ না দিয়ে, তবে অন্যরা যারা আমাদের পরিবর্তনগুলো চেক-আউট করার চেষ্টা করবে তারা সমস্যায় পড়বে কারণ তাদের সাবমডিউলের পরিবর্তনগুলো পাওয়ার কোন উপায় থাকবে না। এই পরিবর্তনগুলো শুধুমাত্র আমাদের স্থানীয় অনুলিপিতে বিদ্যমান থাকবে।
এইরকম যাতে না হয় তা নিশ্চিত করার জন্য, আপনি গিটকে মূল প্রজেক্টটি পুশ করার আগে আপনার সমস্ত সাবমডিউল সঠিকভাবে পুশ করা হয়েছে কিনা তা পরীক্ষা করতে বলতে পারেন। git push কমান্ডটি –recurse-submodules আর্গুমেন্ট নেয় যা হয় “চেক” বা “অন-ডিমান্ড” এ সেট করা যেতে পারে। কমিট করা সাবমডিউল পরিবর্তনগুলোর কোনওটি পুশ করা না হলে “চেক” বিকল্পটি পুশকে ব্যর্থ করে দেবে।
$ git push --recurse-submodules=check
The following submodule paths contain changes that can
not be found on any remote:
DbConnector
Please try
git push --recurse-submodules=on-demand
or cd to the path and use
git push
to push them to a remote
আপনি দেখতে পাচ্ছেন, এটি আমাদের পরবর্তীতে কী করতে চাই সে সম্পর্কে কিছু সহায়ক পরামর্শও দেয়। সহজ বিকল্পটি হল প্রতিটি সাবমডিউলে যাওয়া এবং বাহ্যিকভাবে উপলব্ধ তা নিশ্চিত করতে ম্যানুয়ালি রিমোটে পুশ দেওয়া এবং তারপরে আবার এই পুশটি চেষ্টা করুন। আপনি যদি সমস্ত পুশের জন্য প্রথমে চেক করে নিতে চান তবে আপনি git config push.recurseSubmodules চেক করে এই আচরণটিকে ডিফল্ট করতে পারেন। অন্য বিকল্পটি হল “অন-ডিমান্ড” মান ব্যবহার করা, যা আপনার জন্য এটি করার চেষ্টা করবে।
$ git push --recurse-submodules=on-demand
Pushing submodule 'DbConnector'
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (9/9), 917 bytes | 0 bytes/s, done.
Total 9 (delta 3), reused 0 (delta 0)
To https://github.com/chaconinc/DbConnector
c75e92a..82d2ad3 stable -> stable
Counting objects: 2, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 266 bytes | 0 bytes/s, done.
Total 2 (delta 1), reused 0 (delta 0)
To https://github.com/chaconinc/MainProject
3d6d338..9a377d1 master -> master
আপনি সেখানে দেখতে পাচ্ছেন, গিট ডিবি-কানেক্টর (DbConnector) মডিউলে যাচ্ছে এবং মূল প্রজেক্টটি পুশ করার আগে সাবমডিউলকে পুশ দিয়েছে। যদি সেই সাবমডিউল পুশ কোনো কারণে ব্যর্থ হয়, মূল প্রজেক্ট পুশও ব্যর্থ হবে। আপনি git config push.recurseSubmodules অন-ডিমান্ড করে এই আচরণটিকে ডিফল্ট করতে পারেন।
সাবমডিউলের পরিবর্তনগুলো একত্রিকরণ
আপনি যদি অন্য কারোর সাথে একই সময়ে একটি সাবমডিউল রেফারেন্স পরিবর্তন করেন তবে আপনি কিছু সমস্যায় পড়তে পারেন। অর্থাৎ, যদি সাবমডিউলের ইতিহাসগুলো ভিন্ন হয়ে থাকে এবং একটি সুপারপ্রজেক্টের আলাদা ব্রাঞ্চগুলোতে ভিন্ন কমিট থাকে, তবে এটি ঠিক করতে আপনার কিছুটা কাজ করতে হতে পারে।
যদি কমিটিগুলোর মধ্যে একটি অন্যটির সরাসরি জনক হয় (একটি দ্রুত-ফরোয়ার্ড মার্জ), তবে গিট কেবল মার্জের জন্য পরবর্তীটি বেছে নেবে, যাতে কোনো সমস্যা না হয়।
গিট্ আপনার জন্য একটি ছোট মার্জ করারও চেষ্টা করবে না। যদি সাবমডিউলটি বিচ্ছিন্ন হয়ে যায় এবং একত্রীকরণের প্রয়োজন হয়, আপনি এমন কিছু পাবেন যা দেখতে এইরকম:
$ git pull
remote: Counting objects: 2, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 2 (delta 1), reused 2 (delta 1)
Unpacking objects: 100% (2/2), done.
From https://github.com/chaconinc/MainProject
9a377d1..eb974f8 master -> origin/master
Fetching submodule DbConnector
warning: Failed to merge submodule DbConnector (merge following commits not found)
Auto-merging DbConnector
CONFLICT (submodule): Merge conflict in DbConnector
Automatic merge failed; fix conflicts and then commit the result.
তাই মূলত এখানে যা ঘটেছে তা হল গিট বের করেছে যে সাবমডিউলের ইতিহাসে দুটি ব্রাঞ্চের রেকর্ড পয়েন্ট ভিন্ন এবং একত্রিত করা প্রয়োজন। এটি “মার্জ ফলো করা কমিট পাওয়া যায়নি” হিসাবে ব্যাখ্যা করে, যা বিভ্রান্তিকর কিন্তু আমরা একটু পরে ব্যাখ্যা করব কেন এমন হয়।
উক্ত সমস্যা সমাধানের জন্য, সাবমডিউলটি কোন অবস্থায় থাকা উচিত তা আপনাকে বের করতে হবে। আশ্চর্যের বিষয় হল, গিট আপনার সাহায্যার্থে তেমন তথ্য দেয় না, এমনকি ইতিহাসের উভয় পক্ষের কমিটের SHA-1গুলোও নয়। ভাগ্যক্রমে, এটা বের করা সহজ। আপনি যদি গিট ডিফ (git diff) চালান তবে আপনি উভয় ব্রাঞ্চের রেকর্ড করা কমিটগুলির SHA-1 পেতে পারেন যা আপনি একত্রিত করার চেষ্টা করছেন।
$ git diff
diff --cc DbConnector
index eb41d76,c771610..0000000
--- a/DbConnector
+++ b/DbConnector
সুতরাং, এই ক্ষেত্রে, eb41d76 হল আমাদের সাবমডিউলের কমিট যা আমাদের কাছে ছিল এবং c771610 হল আপস্ট্রিমের কমিট। যদি আমরা আমাদের সাবমডিউল ডিরেক্টরিতে যাই, এটি ইতিমধ্যেই eb41d76-এ থাকা উচিত কারণ মার্জ এটিকে পরিবর্তন করবে না। যে কারণেই হোক না কেন, আপনি এটির দিকে নির্দেশ করে একটি ব্রাঞ্চ তৈরি এবং চেকআউট করতে পারেন।
অন্য দিক থেকে কমিটের SHA-1 অনেক গুরুত্বপূর্ণ। এটি আপনাকে মার্জ এবং রিসোলভ করতে হবে। আপনি হয় সরাসরি SHA-1-এর সাথে মার্জ করার চেষ্টা করতে পারেন, অথবা আপনি এটির জন্য একটি ব্রাঞ্চ তৈরি করতে পারেন এবং তারপরে এটিকে মার্জ করার চেষ্টা করতে পারেন। আমরা পরামর্শ দেব, এমনকি যদি শুধুমাত্র একটি সুন্দর মার্জ কমিট মেসেজ করতে হয়।
সুতরাং, আমরা আমাদের সাবমডিউল ডিরেক্টরিতে যাব, গিট ডিফ থেকে দ্বিতীয় SHA-1 এর উপর ভিত্তি করে “ট্রাই-মার্জ” নামে একটি ব্রাঞ্চ তৈরি করব এবং ম্যানুয়ালি মার্জ করব।
$ cd DbConnector
$ git rev-parse HEAD
eb41d764bccf88be77aced643c13a7fa86714135
$ git branch try-merge c771610
$ git merge try-merge
Auto-merging src/main.c
CONFLICT (content): Merge conflict in src/main.c
Recorded preimage for 'src/main.c'
Automatic merge failed; fix conflicts and then commit the result.
আমরা এখানে একটি প্রকৃত মার্জ কনফ্লিক্ট পেয়েছি, তাই যদি আমরা এটি সমাধান করি এবং এটি কমিট করি, তাহলে আমরা ফলাফল সহ মূল প্রজেক্টটি আপডেট করতে পারি।
$ vim src/main.c (1)
$ git add src/main.c
$ git commit -am 'merged our changes'
Recorded resolution for 'src/main.c'.
[master 9fd905e] merged our changes
$ cd .. (2)
$ git diff (3)
diff --cc DbConnector
index eb41d76,c771610..0000000
--- a/DbConnector
+++ b/DbConnector
@@@ -1,1 -1,1 +1,1 @@@
- Subproject commit eb41d764bccf88be77aced643c13a7fa86714135
-Subproject commit c77161012afbbe1f58b5053316ead08f4b7e6d1d
++Subproject commit 9fd905e5d7f45a0d4cbc43d1ee550f16a30e825a
$ git add DbConnector (4)
$ git commit -m "Merge Tom's Changes" (5)
[master 10d2c60] Merge Tom's Changes
১. প্রথমে আমরা কনফ্লিক্ট সমাধান করি।
২. তারপর আমরা মূল প্রজেক্ট ডিরেক্টরিতে ফিরে যাই।
৩. আমরা আবার SHA-1s চেক করতে পারি।
৪. কনফ্লিক্ট করা সাবমডিউল এন্ট্রি সমাধান করুন।
৫. আমাদের কমিটিগুলো মার্জ করা।
এটা একটু বিভ্রান্তিকর হতে পারে, কিন্তু এটা সত্যিই খুব কঠিন নয়।
মজার বিষয় হলো, গিট নিজে পরিচালনা করতে পারে এমন আরেকটি কেস রয়েছে। যদি সাবমডিউল ডিরেক্টরিতে একটি মার্জ কমিট বিদ্যমান থাকে যা এর ইতিহাসে উভয় কমিট ধারণ করে, গিট আপনাকে সম্ভাব্য সমাধান হিসাবে এটির পরামর্শ দেবে। এটি দেখায় যে সাবমডিউল প্রজেক্টের কোনো পর্যায়ে, কেউ এই দুটি কমিট ধারণকারী ব্রাঞ্চগুলোকে একত্রিত করেছে, তাই সম্ভবত আপনি এটি চাইবেন।
এই কারণেই আগের এরর ম্যাসেজটি ছিল “মার্জ ফলো করা কমিট পাওয়া যায়নি”, কারণ এটি তা করতে পারেনি। এটি বিভ্রান্তিকর কারণ কে বা এটি করার চেষ্টা করবে?
যদি এটি একটি একক গ্রহণযোগ্য মার্জ কমিট খুঁজে পায়, তাহলে আপনি এরকম কিছু দেখতে পাবেন:
$ git merge origin/master
warning: Failed to merge submodule DbConnector (not fast-forward)
Found a possible merge resolution for the submodule:
9fd905e5d7f45a0d4cbc43d1ee550f16a30e825a: > merged our changes
If this is correct simply add it to the index for example
by using:
git update-index --cacheinfo 160000 9fd905e5d7f45a0d4cbc43d1ee550f16a30e825a "DbConnector"
which will accept this suggestion.
Auto-merging DbConnector
CONFLICT (submodule): Merge conflict in DbConnector
Automatic merge failed; fix conflicts and then commit the result.
Git যে কমান্ড প্রস্তাব করছে তা সূচকটি আপডেট করবে যেন আপনি গিট অ্যাড চালান (যা কনফ্লিক্ট দূর করে), তারপর কমিট করুন। যদিও আপনার সম্ভবত এটি করা উচিত নয়। আপনি খুব সহজেই সাবমডিউল ডিরেক্টরিতে যেতে পারেন, পার্থক্যটি কী তা দেখতে পারেন, কোনো কমিট এ দ্রুত-ফরোয়ার্ড করতে পারেন, এটি সঠিকভাবে পরীক্ষা করতে পারেন এবং তারপর এটি কমিট করতে পারেন।
$ cd DbConnector/
$ git merge 9fd905e
Updating eb41d76..9fd905e
Fast-forward
$ cd ..
$ git add DbConnector
$ git commit -am 'Fast forward to a common submodule child'
এটি একই জিনিস করে, তবে অন্তত এইভাবে আপনি যাচাই করতে পারেন যে এটি কাজ করছে এবং আপনার কাজ হয়ে গেলে আপনার সাবমডিউল ডিরেক্টরিতে কোডটি রয়েছে।
সাবমডিউল টিপস
সাবমডিউলগুলোর সাথে কাজকে একটু সহজ করতে আপনি কিছু জিনিস করতে পারেন।
সাবমডিউল ফর-ইচ
প্রতিটি সাবমডিউলে কিছু অবাধ কমান্ড চালানোর জন্য একটি foreach সাবমডিউল কমান্ড রয়েছে। আপনার যদি একই প্রজেক্টে অনেকগুলো সাবমডিউল থাকে তবে এটি সত্যিই সহায়ক হতে পারে।
উদাহরণস্বরূপ, ধরা যাক আমরা একটি নতুন ফিচার শুরু করতে চাই বা একটি বাগফিক্স করতে চাই এবং আমাদের বেশ কয়েকটি সাবমডিউলে কাজ চলছে। আমরা সহজেই আমাদের সমস্ত সাবমডিউলে সমস্ত কাজ স্ট্যাস (stash) করে রাখতে পারি।
$ git submodule foreach 'git stash'
Entering 'CryptoLibrary'
No local changes to save
Entering 'DbConnector'
Saved working directory and index state WIP on stable: 82d2ad3 Merge from origin/stable
HEAD is now at 82d2ad3 Merge from origin/stable
তারপরে আমরা একটি নতুন ব্রাঞ্চ তৈরি করতে পারি এবং আমাদের সমস্ত সাবমডিউলগুলো এটিতে নিয়ে যেতে পারি।
$ git submodule foreach 'git checkout -b featureA'
Entering 'CryptoLibrary'
Switched to a new branch 'featureA'
Entering 'DbConnector'
Switched to a new branch 'featureA'
আপনি একটি ধারণা পেয়ে গেছেন। একটি সত্যিই দরকারী জিনিস যা আপনি করতে পারেন তা হলো আপনার মূল প্রজেক্ট এবং আপনার সমস্ত সাবপ্রজেক্টে কী পরিবর্তন করা হয়েছে তার একটি চমৎকার ইউনিফাইড পার্থক্য তৈরি করতে পারেন।
$ git diff; git submodule foreach 'git diff'
Submodule DbConnector contains modified content
diff --git a/src/main.c b/src/main.c
index 210f1ae..1f0acdc 100644
--- a/src/main.c
+++ b/src/main.c
@@ -245,6 +245,8 @@ static int handle_alias(int *argcp, const char ***argv)
commit_pager_choice();
+ url = url_decode(url_orig);
+
/* build alias_argv */
alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1));
alias_argv[0] = alias_string + 1;
Entering 'DbConnector'
diff --git a/src/db.c b/src/db.c
index 1aaefb6..5297645 100644
--- a/src/db.c
+++ b/src/db.c
@@ -93,6 +93,11 @@ char *url_decode_mem(const char *url, int len)
return url_decode_internal(&url, len, NULL, &out, 0);
}
+char *url_decode(const char *url)
+{
+ return url_decode_mem(url, strlen(url));
+}
+
char *url_decode_parameter_name(const char **query)
{
struct strbuf out = STRBUF_INIT;
এখানে আমরা দেখতে পাচ্ছি যে আমরা একটি সাবমডিউলে একটি ফাংশন সংজ্ঞায়িত করছি এবং এটিকে মূল প্রজেক্টে কল করছি। এটি স্পষ্টতই একটি সরলীকৃত উদাহরণ, তবে আশা করি এটি আপনাকে কীভাবে কার্যকর হচ্ছে তার একটি ধারণা দেয়।
কিছু দরকারী উপনাম
আপনি এই কমান্ডগুলোর কয়েকটির জন্য কিছু উপনাম সেট আপ করতে পারেন কারণ সেগুলো বেশ দীর্ঘ হতে পারে এবং আপনি সেগুলিকে ডিফল্ট করার জন্য বেশিরভাগের জন্য কনফিগারেশন অপশন সেট করতে পারবেন না। আমরা গিট অ্যালিয়াসেসে গিট উপনাম সেট আপ করেছি, তবে আপনি যদি গিট-এ সাবমডিউলগুলোতে অনেক বেশি কাজ করার মনঃস্থির করেন তবে আপনি কী সেট আপ করতে চান তার একটি উদাহরণ এখানে দেওয়া হলো।
$ git config alias.sdiff '!'"git diff && git submodule foreach 'git diff'"
$ git config alias.spush 'push --recurse-submodules=on-demand'
$ git config alias.supdate 'submodule update --remote --merge'
এইভাবে আপনি git supdate রান করতে পারেন যদি আপনার সাবমডিউলগুলো আপডেট করতে চান অথবা, git spush চালাতে পারেন যদি সাবমডিউলগুলোর নির্ভরতা যাচাইয়ের সাথে পুশ করতে চান।
সাবমডিউল এর সমস্যাবলী
সাবমডিউল ব্যবহার করা অবশ্য সমস্যাবিহীন নয়।
ব্রাঞ্চ সুইচ করা
উদাহরণস্বরূপ, তাদের মধ্যে গিট 2.13 এর চেয়ে পুরানো গিট সংস্করণগুলোতে সাবমডিউল সহ ব্রাঞ্চগুলো পরিবর্তন করা জটিল হতে পারে। আপনি যদি একটি নতুন ব্রাঞ্চ তৈরি করেন, সেখানে একটি সাবমডিউল যোগ করুন এবং তারপর সেই সাবমডিউল ছাড়াই একটি ব্রাঞ্চে ফিরে যান, আপনার কাছে তখন ও একটি আনট্র্যাকড ডিরেক্টরি হিসাবে সাবমডিউল ডিরেক্টরি থেকে যাবে:
git --version
git version 2.12.2
$ git checkout -b add-crypto
Switched to a new branch 'add-crypto'
$ git submodule add https://github.com/chaconinc/CryptoLibrary
Cloning into 'CryptoLibrary'...
...
$ git commit -am 'Add crypto library'
[add-crypto 4445836] Add crypto library
2 files changed, 4 insertions(+)
create mode 160000 CryptoLibrary
$ git checkout master
warning: unable to rmdir CryptoLibrary: Directory not empty
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
(use "git add ..." to include in what will be committed)
CryptoLibrary/
nothing added to commit but untracked files present (use "git add" to track)
ডিরেক্টরিটি সরানো কঠিন নয়, তবে সেখানে এটি থাকা কিছুটা বিভ্রান্তিকর হতে পারে। যদি আপনি এটিকে সরিয়ে দেন এবং তারপরে সেই সাবমডিউলটি আছে এমন ব্রাঞ্চে ফিরে যান, তাহলে আপনাকে submodule update --init চালাতে হবে পুনরুদ্ধার করতে।
$ git clean -ffdx
Removing CryptoLibrary/
$ git checkout add-crypto
Switched to branch 'add-crypto'
$ ls CryptoLibrary/
$ git submodule update --init
Submodule path 'CryptoLibrary': checked out 'b8dda6aa182ea4464f3f3264b11e0268545172af'
$ ls CryptoLibrary/
Makefile includes scripts src
সত্যি বলতে এটি খুব কঠিন নয়, কিন্তু এটি একটু বিভ্রান্তিকর হতে পারে।
নতুন গিট সংস্করণে (Git >= 2.13) গিট চেকআউট কমান্ডে –recurse-submodules ফ্ল্যাগ যোগ করে এই সবকে সহজ করে দিয়েছে, যা আমরা কোন ব্রাঞ্চে স্যুইচ করছি তার জন্য সাবমডিউলগুলোকে সঠিক অবস্থায় রাখে।
$ git --version
git version 2.13.3
$ git checkout -b add-crypto
Switched to a new branch 'add-crypto'
$ git submodule add https://github.com/chaconinc/CryptoLibrary
Cloning into 'CryptoLibrary'...
...
$ git commit -am 'Add crypto library'
[add-crypto 4445836] Add crypto library
2 files changed, 4 insertions(+)
create mode 160000 CryptoLibrary
$ git checkout --recurse-submodules master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean
গিট চেকআউটের সাথে –recurse-submodules ফ্ল্যাগ ব্যবহার করা যেতে পারে যখন আপনি সুপারপ্রজেক্টের বিভিন্ন ব্রাঞ্চে কাজ করেন, প্রতিটিতে আপনার সাবমডিউল বিভিন্ন কমিটের দিকে নির্দেশ করে। প্রকৃতপক্ষে, আপনি যদি বিভিন্ন কমিটে সাবমডিউল রেকর্ড করে এমন ব্রাঞ্চগুলোর মধ্যে স্যুইচ করেন এবং গিট স্ট্যাটাস এক্সিকিউট করেন তবে সাবমডিউলটি “পরিবর্তিত” হিসাবে প্রদর্শিত হবে এবং “নতুন কমিট” নির্দেশ করবে। কারণ ব্রাঞ্চ পরিবর্তন করার সময় সাবমডিউল এর স্টেট ডিফল্টভাবে বহন করা হয় না।
এটি সত্যিই বিভ্রান্তিকর হতে পারে, তাই আপনার প্রোজেক্টে সাবমডিউল থাকলে git checkout –recurse-submodules কমান্ড এর মাধ্যমে চেকআউট করা ভালো হবে। পুরানো গিট সংস্করণগুলোর জন্য যেখানে –recurse-submodules ফ্ল্যাগ নেই, চেকআউটের পরে আপনি সাবমডিউলগুলিকে সঠিক অবস্থায় রাখতে git submodule update –init –recursive ব্যবহার করতে পারেন।
ভাগ্যক্রমে, আপনি গিট (>=2.14) কে সর্বদা –recurse-submodules ফ্ল্যাগ ব্যবহার করতে বলতে পারেন কনফিগারেশন অপশন submodule.recurse: git config submodule.recurse true সেট করার মাধ্যমে। উপরে উল্লিখিত হিসাবে, –recurse-submodules অপশন (গিট ক্লোন ছাড়া) আছে এমন প্রতিটি কমান্ডের জন্য গিট রিকারসকে সাবমডিউলে পরিণত করবে।
তারপরে, যখন আপনি ফিরে যান, আপনি কিছু কারণে একটি খালি CryptoLibrary ডিরেক্টরি পাবেন এবং git submodule update এর মাধমেও এটি ঠিক নাও করতে পারে। আপনাকে আপনার সাবমডিউল ডিরেক্টরিতে যেতে হবে এবং একটি গিট চেকআউট চালাতে হবে, আপনার সব ফাইল ফিরে পেতে। আপনি একাধিক সাবমডিউলের জন্য একটি সাবমডিউল ফর-ইচ স্ক্রিপ্ট চালাতে পারেন।
এটি লক্ষ্য করা গুরুত্বপূর্ণ যে সাবমডিউলগুলি আজকাল তাদের সমস্ত গিট ডেটা প্রজেক্টের .git ডিরেক্টরিতে রাখে, তাই গিটের অনেক পুরানো সংস্করণের বিপরীতে, একটি সাবমডিউল ডিরেক্টরি নষ্ট হলেও আপনার কাছে থাকা কমিট বা ব্রাঞ্চ হারাবে না।
এই টুলসগুলির সাহায্যে, সাবমডিউল মেথড পরস্পর সম্পর্কিত তবে পৃথক প্রজেক্ট ডেভেলপের জন্য একটি মোটামুটি সহজ এবং কার্যকর পদ্ধতি হতে পারে।
সাবডিরেক্টরি থেকে সাবমডিউলে স্যুইচ করা
অন্য অনেকে যে সতর্কতা অবলম্বন করে তা হল সাবডিরেক্টরি থেকে সাবমডিউলে স্যুইচ করা। আপনি যদি আপনার প্রজেক্টের ফাইলগুলি ট্র্যাক রাখেন এবং আপনি সেগুলিকে একটি সাবমডিউলে স্থানান্তর করতে চান তবে আপনাকে অবশ্যই সতর্ক হতে হবে বা গিট আপনার উপর রেগে যাবে। ধরুন, যে আপনার কাছে আপনার প্রজেক্টের একটি সাবডিরেক্টরিতে ফাইল রয়েছে এবং আপনি এটিকে একটি সাবমডিউলে স্যুইচ করতে চান। আপনি যদি সাবডিরেক্টরি মুছে ফেলেন এবং তারপর সাবমডিউল অ্যাড চালান, গিট আপনাকে চিৎকার করে:
$ rm -Rf CryptoLibrary/
$ git submodule add https://github.com/chaconinc/CryptoLibrary
'CryptoLibrary' already exists in the index
আপনাকে প্রথমে CryptoLibrary ডিরেক্টরিটি আনস্টেজ করতে হবে। তারপর আপনি সাবমডিউল যোগ করতে পারবেন:
$ git rm -r CryptoLibrary
$ git submodule add https://github.com/chaconinc/CryptoLibrary
Cloning into 'CryptoLibrary'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100```% (11/11), done.
Checking connectivity... done.
এখন ধরুন আপনি একটি ব্রাঞ্চে এটি করেছেন। এখন, আপনি যদি এমন একটি শাখায় ফিরে যাওয়ার চেষ্টা করেন যেখানে সেই ফাইলগুলি এখনও একটি সাবমডিউলের পরিবর্তে প্রকৃত প্রজেক্ট ট্রি তে রয়েছে – আপনি এই ইরোর পাবেন:
$ git checkout master
error: The following untracked working tree files would be overwritten by checkout:
CryptoLibrary/Makefile
CryptoLibrary/includes/crypto.h
...
Please move or remove them before you can switch branches.
Aborting
আপনি checkout -f দিয়ে এটিকে স্যুইচ করতে বাধ্য করতে পারেন, তবে সতর্ক থাকুন যে সেখানে আপনার অসংরক্ষিত পরিবর্তনগুলি নেই কারণ সেগুলি সেই কমান্ডের মাধ্যমে ওভাররাইট হয়ে যেতে পারে।
$ git checkout -f master
warning: unable to rmdir CryptoLibrary: Directory not empty
Switched to branch 'master'
তারপরে, যখন আপনি ফিরে যান, আপনি কিছু কারণে একটি খালি CryptoLibrary ডিরেক্টরি পাবেন এবং git submodule update এর মাধমেও এটি ঠিক নাও করতে পারে। আপনাকে আপনার সাবমডিউল ডিরেক্টরিতে যেতে হবে এবং একটি গিট চেকআউট চালাতে হবে, আপনার সব ফাইল ফিরে পেতে। আপনি একাধিক সাবমডিউলের জন্য একটি সাবমডিউল ফর-ইচ স্ক্রিপ্ট চালাতে পারেন।
এটি লক্ষ্য করা গুরুত্বপূর্ণ যে সাবমডিউলগুলি আজকাল তাদের সমস্ত গিট ডেটা প্রজেক্টের .git ডিরেক্টরিতে রাখে, তাই গিটের অনেক পুরানো সংস্করণের বিপরীতে, একটি সাবমডিউল ডিরেক্টরি নষ্ট হলেও আপনার কাছে থাকা কমিট বা ব্রাঞ্চ হারাবে না।
এই টুলসগুলির সাহায্যে, সাবমডিউল মেথড পরস্পর সম্পর্কিত তবে পৃথক প্রজেক্ট ডেভেলপের জন্য একটি মোটামুটি সহজ এবং কার্যকর পদ্ধতি হতে পারে।