Vivasoft-logo

১০.৬ গিট ইন্টার্নালস – ট্রান্সফার প্রোটোকল

ট্রান্সফার প্রোটোকল

গিট দুটি প্রধান উপায়ে দুটি রিপোজিটরি এর মধ্যে ডেটা স্থানান্তর করতে পারে: “ডাম্ব” প্রোটোকল এবং “স্মার্ট” প্রোটোকল। এই অনুচ্ছেদে এই দুটি প্রধান প্রোটোকল কিভাবে কাজ করে তা সংক্ষিপ্তভাবে আলোচনা করা হবে।

ডাম্ব প্রোটোকল

যদি HTTP দিয়ে একটি শুধুমাত্র পাঠযোগ্য (read only) রিপোজিটরি সেট-আপ করা হয়, তাহলে সম্ভবত ডাম্ব প্রোটোকল ব্যবহার করে এটা করা হয়েছে। এই প্রোটোকলটিকে “ডাম্ব” বলা হয় কারণ এটি ট্রান্সপোর্ট প্রক্রিয়া চলাকালে সার্ভারে কোনও গিট-নির্দিষ্ট কোডের ব্যাবহার করে না; তাই বিষয়বস্তু আনার প্রক্রিয়া হলো অনেক গুলো HTTP GET রিকোয়েস্ট, যেখানে ক্লায়েন্টকে সার্ভারে গিট রিপোজিটরির নকশা অনুমান করে নিতে হয়।
বিঃদ্রঃ ডাম্ব প্রোটোকল আজকাল খুবই কম ব্যবহৃত হয়। এটা দিয়ে রিপোজিটরি সুরক্ষিত করা বা ব্যক্তিগত কাজে ব্যবহার করা খুবই কঠিন, তাই বেশিরভাগ গিট হোস্ট (ক্লাউড-ভিত্তিক এবং নিজ-প্রাঙ্গন (on-prem), উভয়ক্ষেত্রেই) এটি ব্যবহার করতে নিরূৎসাহিত করা হয়। সাধারণভাবে পরামর্শ দেওয়া হয় যাতে সবাই স্মার্ট প্রোটোকল ব্যবহার করে, পরবর্তী অনুচ্ছেদগুলোতে এ নিয়ে বর্ণনা করা হবে। দৃষ্টান্তস্বরূপ, সিম্পল গিট লাইব্রেরির জন্য http-fetch প্রক্রিয়াটি অনুসরণ করি:
				
					$ git clone http://server/simplegit-progit.git
				
			
এই কমান্ডটি প্রথমত যে কাজটি করে তা হল info/refs ফাইল গুলো নিয়ে আসে। এই ফাইলটি update-server-info কমান্ডটি দ্বারা লেখা হয়েছে, তাই আপনাকে HTTP ট্রান্সপোর্ট সঠিকভাবে কাজ করানোর জন্য এটিকে একটি post-receive হুক হিসেবে সক্রিয় করতে হবে:
				
					=> GET info/refs
ca82a6dff817ec66f44342007202690a93763949     refs/heads/master

				
			
এখন আপনার কাছে রিমোট রেফারেন্স গুলো এবং তাদের SHA-1 এর একটি তালিকা রয়েছে। এরপর, HEAD রেফারেন্সটি খুঁজতে হবে যাতে পরবর্তীতে কোথায় চেক-আউট করতে হবে তা জানা যায়:
				
					=> GET HEAD
ref: refs/heads/master

				
			
প্রক্রিয়াটি সম্পন্ন হওয়ার পর master ব্রাঞ্চে চেক আউট করতে হবে। এই মুহুর্তে, পরবর্তী প্রক্রিয়া শুরু করা যায়। কারণ এখানে শুরুর স্থান হল কমিট অবজেক্ট ca82a6 যা info/refs ফাইলে আছে, ফেচ করা শুরু করার জন্য:
				
					=> GET objects/ca/82a6dff817ec66f44342007202690a93763949
(179 bytes of binary data)

				
			
এরপর একটি অবজেক্ট পাওয়া যাবে যেটা সার্ভার এ লুজ ভাবে বিন্যস্ত ছিল, যা স্ট্যাটিক HTTP GET রিকোয়েস্টের রেসপন্স। এটাকে zlib-uncompress করলে বিস্তারিত হেডার এবং কমিট বিষয়বস্তু দেখা যাবে:
				
					$ git cat-file -p ca82a6dff817ec66f44342007202690a93763949
tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
parent 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
author Scott Chacon <schacon@gmail.com> 1205815931 -0700
committer Scott Chacon <schacon@gmail.com> 1240030591 -0700

Change version number

				
			
এর পরে, আপনার কাছে পুনরুদ্ধার করার জন্য আরও দুটি অবজেক্ট আছে – cfda3b, যেটি এইমাত্র পুনরুদ্ধিত কমিট এর ট্রি এর বিষয়বস্তু; আর প্যারেন্ট কমিট 085bb3:
				
					=> GET objects/08/5bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
(179 bytes of data)

				
			
এর দ্বারা পরবর্তী কমিট অবজেক্ট পাওয়া যায়, ট্রি অবজেক্টটটি পাওয়ার জন্য:
				
					=> GET objects/cf/da3bf379e4f8dba8717dee55aab78aef7f4daf
(404 - Not Found)

				
			
ওহো – দেখে মনে হচ্ছে সেই ট্রি অবজেক্টটি সার্ভারে লুজ ভাবে সাজানো নেই, তাই আপনি একটি 404 রেসপন্স পাবেন। এর জন্য কয়েকটি কারণ রয়েছে – অবজেক্টটি একটি বিকল্প রিপোজিটরিতে থাকতে পারে, অথবা এটি এই রিপোজিটরির একটি প্যাকফাইলে থাকতে পারে। গিট প্রথমে বিকল্প তালিকাগুলো অনুসন্ধান করে:
				
					=> GET objects/info/http-alternates
(empty file)

				
			
এটি যদি বিকল্প URL গুলোর একটি তালিকা উপস্থাপন করে, তাহলে গিট সেখানে লুজ ফাইল এবং প্যাকফাইলগুলির অনুসন্ধান করে – এটি একটি চমৎকার পদ্ধতি যার মাধ্যমে ফর্ক করা প্রজেক্টগুলো ডিস্কে পরস্পর এর মধ্যে অবজেক্ট আদান প্রদান করতে পারে। যাইহোক, যেহেতু এই ক্ষেত্রে কোনও বিকল্প তালিকা পাওয়া যায়নি, তাহলে অবজেক্টটি অবশ্যই একটি প্যাকফাইল হিসেবে থাকবে। সার্ভারে কোন কোন প্যাকফাইলগুলো আছে তা দেখার জন্য objects/info/packs ফাইলটি দরকার, যেটাতে একটি তালিকা রয়েছে (এগুলো update-server-info দ্বারাও তৈরি করা হয়ে থাকে):
				
					=> GET objects/info/packs
P pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack

				
			
সার্ভারে শুধুমাত্র একটি প্যাকফাইল রয়েছে, তাই অবজেক্টটি সুস্পষ্টভাবেই সেখানে রয়েছে, তবে তা নিশ্চিত করার জন্য তালিকা ফাইলটি দেখা যায়। সার্ভারে একাধিক প্যাকফাইল থাকলেও সুবিধা আছে, যাতে কোন প্যাকফাইলে প্রয়োজনীয় অবজেক্টটি রয়েছে তা দেখতে পারা যায়:
				
					=> GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.idx
(4k of binary data)

				
			
এখন প্যাকফাইলের তালিকাটি থেকে দেখতে পারা যাবে যে প্রয়োজনীয় অবজেক্টটি এতে আছে কিনা – কারণ প্যাকফাইলে অবজেক্টের SHA-1 গুলো এবং ওদের অফসেটগুলো তালিকাভুক্ত করা থাকে। আপনার অবজেক্ট ঐখানে আছে, তাই বিনা দ্বিধায় পুরো প্যাকফাইলটি নিয়ে আসতে পারেন:
				
					=> GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack
(13k of binary data)

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

স্মার্ট প্রোটোকল

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

ডেটা আপলোডিং

কোন রিমোট প্রসেসে ডেটা আপলোড করার জন্য গিট send-pack এবং receive-pack প্রসেস দুটি ব্যবহার করে। send-pack প্রসেসটি ক্লায়েন্টে রান করে এবং রিমোট-সাইডের receive-pack প্রসেসে কানেক্ট করে।

SSH

উদাহরণস্বরূপ, আপনি আপনার প্রজেক্টে git push origin master রান করলেন যেখানে origin এর URL এমনভাবে দেওয়া যাতে করে সে SSH প্রোটোকল ব্যবহার করে। গিট send-process শুরু করে, যা সার্ভারের সাথে SSH এর মাধ্যমে কানেক্ট করে। এই প্রসেসটি রিমোট সার্ভারে যে কমান্ডটি রান করানোর চেষ্টা করে সেটি নিম্নরূপঃ
				
					$ ssh -x git@server "git-receive-pack 'simplegit-progit.git'"
00a5ca82a6dff817ec66f4437202690a93763949 refs/heads/master□report-status \
    delete-refs side-band-64k quiet ofs-delta \
    agent=git/2:2.1.1+github-607-gfba4028 delete-refs
0000

				
			
প্রতিটা রেফারেন্সের জন্য git-receive-pack কমান্ড একটা লাইন রেসপন্স করে – এই ক্ষেত্রে, শুধুমাত্র master ব্র্যাঞ্চ এবং এর SHA-1। এছাড়া প্রথম লাইনে সার্ভার কি কি করতে পারবে সেগুলোরও একটা তালিকা থাকে (এখানে report-status, delete-refs, এছাড়াও আরো কিছু, ক্লায়েন্ট শনাক্তকারী বৈশিষ্ট্য রয়েছে)।

এখানে খন্ডে খন্ডে ডেটা পাঠানো হয়। প্রতিটা খন্ড শুরু হয় চার অংকের হেক্সাডেসিমাল মান দিয়ে, যা দিয়ে খন্ডটা কত সাইজের (নিজের ৪ বাইট দৈর্ঘ্য সহ) তা নির্দিষ্ট করা হয়। খন্ডগুলোতে সাধারণতঃ এক লাইন ডেটা থাকে এবং শেষে একটা লাইনফিড থাকে। এখানে প্রথম খন্ড শুরু হচ্ছে 00a5 দিয়ে, যা 165 এর হেক্সাডেসিমাল মান, অর্থাৎ খন্ডটা 165 বাইট সাইজের। পরের খন্ডটা 0000, অর্থাৎ সার্ভারের রেফারেন্স তালিকা করা শেষ।

এখন, যেহেতু এটি সার্ভারের অবস্থা জানে, send-pack প্রসেস নির্ধারণ করে কী কী কমিট এর কাছে আছে যা সার্ভারে নেই। প্রতিটা রেফারেন্সের জন্য যা এই পুশে আপডেট হবে, send-pack প্রসেস সার্ভারের receive-pack প্রসেসকে জানায়। উদাহরণস্বরূপ, যদি master ব্র্যাঞ্চ আপডেট হয় এবং একটা experimental নতুনভাবে যোগ করা হয়, তাহলে send-pack রেসপন্সটা নিম্নরূপ হতে পারেঃ
				
					0076ca82a6dff817ec66f44342007202690a93763949 15027957951b64cf874c3557a0f3547bd83b3ff6 \
    refs/heads/master report-status
006c0000000000000000000000000000000000000000 cdfdb42577e2506715f8cfeacdbabc092bf63e8d \
    refs/heads/experiment
0000

				
			
যেসব আপডেট হবে সেসবের প্রতিটা রেফারেন্সের জন্য গিট একটি লাইন পাঠায় যাতে লাইনের দৈর্ঘ্য (লেন্থ) থাকে, আগের SHA-1, নতুন SHA-1 আর যে রেফারেন্স আপডেট হচ্ছে সে রেফারেন্স। প্রথম লাইনে ক্লায়েন্ট কি কি করতে পারে সেগুলোও থাকে। experiment রেফারেন্সটা নতুন করে যোগ হয়েছে তাই SHA-1 এ সব মান শুন্য – এর দ্বারা বোঝায় যে ঐখানে এর আগে কিছুই ছিলো না। আবার, যদি ডান পাশে সব শুন্য থাকে, তাহলে কোন রেফারেন্স মুছে ফেলা হয়েছে, মানে আগেরটার বিপরীত।

এরপর, ক্লায়েন্ট সবগুলা অবজেক্টের একটি প্যাকফাইল পাঠায় যা সার্ভারের কাছে এ মুহুর্তে নেই। অবশেষে, সার্ভার সফলতা (বা ব্যর্থতা) নির্দেশ করে একটি রেসপন্স পাঠায়:
				
					000eunpack ok
				
			

HTTP(S)

এই প্রসেসটি HTTP এর মতই প্রায়, তবে হ্যান্ডশেকিংটা একটু আলাদা। কানেকশন শুরু করার জন্য রিকোয়েস্টটি নিম্মরূপঃ
				
					=> GET http://server/simplegit-progit.git/info/refs?service=git-receive-pack
001f# service=git-receive-pack
00ab6c5f0e45abd7832bf23074a333f739977c9e8188 refs/heads/master□report-status \
    delete-refs side-band-64k quiet ofs-delta \
    agent=git/2:2.1.1~vmg-bitmaps-bugaloo-608-g116744e
0000

				
			
প্রথম ক্লায়েন্ট-সার্ভার আদান-প্রদান এর দ্বারা শেষ হয়। তারপর ক্লায়েন্ট send-pack এর ডেটা/তথ্য সমেত একটা POST রিকোয়েস্ট পাঠায়:
				
					=> POST http://server/simplegit-progit.git/git-receive-pack
				
			
POST রিকোয়েস্টে send-pack এর আউটপুট আর প্যাকফাইলটাকে পে-লোড হিসেবে পাঠায়। সার্ভার এরপর HTTP রেসপন্সের মাধ্যমে সফল বা ব্যর্থ হওয়ার এর নির্দেশনা দেয়। এটা মনে রাখতে হবে যে HTTP প্রোটোকলটি এই খন্ড খন্ড ডেটা, ট্রান্সফার এনকোডিং-এর ভিতরে একীভূত করতে পারে।

ডেটা ডাউনলোডিং

ডেটা ডাউনলোডের সময়ে fetch-pack আর upload-pack প্রসেস দুটি জড়িত থাকে। ক্লায়েন্ট কি কি ডেটা ডাউনলোড করবে তা বুঝার জন্য fetch-pack প্রসেস শুরু করে যেটা রিমোট সাইডের upload-pack প্রসেসের সাথে কানেক্ট হয়।

SSH

যদি SSH ব্যবহার করে ডেটা আনা হয়, তাহলে fetch-pack নিচে দেওয়া কমান্ডের মত কিছু রান করে:
				
					$ ssh -x git@server "git-upload-pack 'simplegit-progit.git'"
				
			
fetch-pack কানেক্ট হওয়ার পর upload-pack নিচের মত কিছু ফেরত পাঠায়:
				
					00dfca82a6dff817ec66f44342007202690a93763949 HEAD□multi_ack thin-pack \
    side-band side-band-64k ofs-delta shallow no-progress include-tag \
    multi_ack_detailed symref=HEAD:refs/heads/master \
    agent=git/2:2.1.1+github-607-gfba4028
003fe2409a098dc3e53539a9028a94b6224db9d6a6b6 refs/heads/master
0000

				
			
এটা receive-pack থেকে যে রেসপন্স আসে, সেটার মতই, তবে এর কার্যক্ষমত ভিন্ন। এটা HEAD কোথায় নির্দেশ (symref=HEAD:refs/heads/master) করে আছে সেটাও পাঠায় যাতে করে ক্লায়েন্ট বুঝতে পারে যে যদি এটা ক্লোন হয়ে থাকে তাহলে কি কি চেক-আউট করতে হবে। এমতাবস্থায়, fetch-pack প্রসেস দেখে কি কি অবজেক্ট এর কাছে আছে এবং রেসপন্স পাঠায় কী কী লাগবে “want” আর SHA-1 লিখে; এটা এর কাছে যা যা আছে এর জন্য “have” আর সংশ্লিষ্ট SHA-1 লিখে এবং তালিকার শেষে এটি “done” লিখে যাতে করে upload-pack প্রসেস প্রয়োজনীয় ডেটার প্যাকফাইল পাঠানো শুরু করে।
				
					003cwant ca82a6dff817ec66f44342007202690a93763949 ofs-delta
0032have 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
0009done
0000

				
			

HTTP(S)

ডেটা ফেচ করার ক্ষেত্রে হ্যান্ডশেকের জন্য দুইটি HTTP রিকোয়েস্ট লাগে। প্রথমটি হচ্ছে ডাম্ব প্রোটোকলে ব্যবহৃত এন্ডপয়েন্টে GET রিকোয়েস্ট:
				
					=> GET $GIT_URL/info/refs?service=git-upload-pack
001e# service=git-upload-pack
00e7ca82a6dff817ec66f44342007202690a93763949 HEAD□multi_ack thin-pack \
    side-band side-band-64k ofs-delta shallow no-progress include-tag \
    multi_ack_detailed no-done symref=HEAD:refs/heads/master \
    agent=git/2:2.1.1+github-607-gfba4028
003fca82a6dff817ec66f44342007202690a93763949 refs/heads/master
0000

				
			
এটা SSH কানেকশনের git-upload-pack-এর মতই প্রায়, কিন্তু দ্বিতীয় আদান-প্রদানটি আলাদা রিকোয়েস্টে সম্পন্ন হয়:
				
					=> POST $GIT_URL/git-upload-pack HTTP/1.0
0032want 0a53e9ddeaddad63ad106860237bbf53411d11a7
0032have 441b40d833fdfa93eb2908e52742248faf0ee993
0000

				
			
এই ফরম্যাটটিও উপরের ফরম্যাটের মতই। এই রিকোয়েস্টের রেসপন্স সফলতা বা ব্যর্থতা নির্দেশ করে, এবং সেই সাথে প্যাকফাইলটিও অন্তর্ভুক্ত করে।

প্রোটোকল সারসংক্ষেপ

এই অধ্যায়ে স্থানান্তর প্রোটোকলগুলির প্রাথমিক বিষয়বস্তু আলোচনা করা হয়েছে। প্রোটোকলের আরো অনেক বৈশিষ্ট্য রয়েছে, যেমন multi-ack বা side-band, কিন্তু সেগুলো নিয়ে আলোচনা করা এই বইয়ের উদ্দেশ্যের বাইরে। এখানে ক্লায়েন্ট আর সার্ভারের অভ্যন্তরীন একটা সাধারণ ধারণা দেওয়ার চেষ্টা করা হয়েছে; আরো বিষদভাবে জানার প্রয়োজন হলে আপনাকে গিটের সোর্স কোড দেখতে হবে।