৭.১০ গিট টুলস – গিট দিয়ে ডিবাগিং

গিট দিয়ে ডিবাগিং

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

ফাইল এনোটেশন (File Annotation)

যদি কোডে আমরা কোনো বাগ খুঁজে পাই এবং জানতে চাই, কখন বা কেন সেই ভুলটির সুত্রপাত হলো, ফাইল এনোটেশন সেক্ষেত্রে একটা ভালো পদ্ধতি। যেকোনো ফাইলের যেকোনো লাইন পরিবর্তন করার জন্য সর্বশেষ কোন কমিটটা ব্যবহার হয়েছিল তা দেখা যাবে এটা দিয়ে। সুতরাং কোডের কোথাও যদি ভুল পাওয়া যায়, তখন git blame কমান্ডটি চালালে, সেই লাইনটি তৈরির জন্য কোন কমিটটা দায়ী ছিল, তা নির্ধারন করে ফাইলে সেটা চিহ্নিত (annotation) করে দিবে।

এখানে উদাহরণ হিসাবে, git blame দিয়ে Makefile  ফাইলটিতে (টপ-লেভেল লিনাক্স কার্নেলের একটি ফাইল), কোন লাইনের জন্য কোন কমিট ও কমিট-রচয়িতা দায়ী, তা বের করে দিচ্ছে। সেই সাথে কমান্ডে -L  অপশন ব্যবহার করে, ফাইলের শুধু 69 থেকে 82 – এই লাইন নম্বরগুলোর জন্য আউটপুট সীমিত করে দেয়া যাচ্ছে:

				
					$ git blame -L 69,82 Makefile
b8b0618cf6fab (Cheng Renquan  2009-05-26 16:03:07 +0800 69) ifeq ("$(origin V)", "command line")
b8b0618cf6fab (Cheng Renquan  2009-05-26 16:03:07 +0800 70)   KBUILD_VERBOSE = $(V)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 71) endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72) ifndef KBUILD_VERBOSE
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73)   KBUILD_VERBOSE = 0
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 74) endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75)
066b7ed955808 (Michal Marek   2014-07-04 14:29:30 +0200 76) ifeq ($(KBUILD_VERBOSE),1)
066b7ed955808 (Michal Marek   2014-07-04 14:29:30 +0200 77)   quiet =
066b7ed955808 (Michal Marek   2014-07-04 14:29:30 +0200 78)   Q =
066b7ed955808 (Michal Marek   2014-07-04 14:29:30 +0200 79) else
066b7ed955808 (Michal Marek   2014-07-04 14:29:30 +0200 80)   quiet=quiet_
066b7ed955808 (Michal Marek   2014-07-04 14:29:30 +0200 81)   Q = @
066b7ed955808 (Michal Marek   2014-07-04 14:29:30 +0200 82) endif
				
			

খেয়াল করি, আউটপুটের প্রতিটি লাইনে, প্রথম অংশটি কমিট-হ্যাশের (sha-1) প্রাথমিক অংশ। এই কমিটটি ফাইলের সেই লাইনটিকে শেষবার পরিবর্তন করেছিলো। পরের দুটি অংশ হল কমিট রচয়িতার নাম এবং কমিটের তারিখ-সময়, যেটা দিয়ে সহজেই জানা যাবে – কে কখন সেই লাইনটি পরিবর্তন করেছিলো। তারপরের অংশে দেখাচ্ছে লাইন নম্বর এবং ফাইলে ওই লাইনের কন্টেন্ট। এছাড়াও ^1da177e4c3f4  কমিট লাইনগুলি খেয়াল করি। এখানে শুরুতে ^ চিহ্ন দিয়ে বোঝাচ্ছে – ফাইলের এই লাইনগুলো, ওই গিট রিপোজিটরির সর্বপ্রথম কমিটে প্রবর্তিত হয়েছিল এবং তখন থেকেই অপরিবর্তিত রয়েছে। এখানে যদিও ^ চিহ্নের ব্যবহার একটু বিভ্রান্তিকর, কারণ আমরা দেখেছি, এটা দিয়ে গিট অন্তত তিনটি উপায়ে কমিট-হ্যাশের পরিবর্তন করতে পারে।

গিটের আরেকটি চমৎকার ব্যাপার হল, এটি ফাইলের নাম পরিবর্তনকে সরাসরি লিপিবদ্ধ না করে, স্ন্যাপশটগুলি লিপিবদ্ধ করে এবং তারপরে নামের পরিবর্তন কী হয়েছে তা বের করে। তাতে যে সুবিধাটা হয় – ফাইল থেকে ফাইলে কোডের স্থানান্তর হলে, সেই গতিবিধিগুলোও বের করে ফেলা যায়। এই ব্যাপারগুলো আমরা দেখতে পারবো git blame কমান্ডে -C অপশনটি ব্যবহার করে। এটি ফাইলটিকে বিশ্লেষণ করে, এতে থাকা কোডের কোনো অংশ, অন্য কোনো ফাইল থেকে অনুলিপি করা হয়েছে, তা বোঝার চেষ্টা করে। উদাহরণস্বরূপ, ধরা যাক GITServerHandler.m ফাইলটির কন্টেন্ট ভাগ করে একাধিক ফাইলে নেয়া হয়েছে, যার মধ্যে একটি হল GITPackUpload.m । এখন git blame -C কমান্ড ব্যবহার করে,  GITPackUpload.m ফাইলের কোডের কোন অংশগুলো কোথা থেকে এসেছে, তা দেখা যাবেঃ

				
					$ git blame -C -L 141,153 GITPackUpload.m
f344f58d GITServerHandler.m (Scott 2009-01-04 141)
f344f58d GITServerHandler.m (Scott 2009-01-04 142) - (void) gatherObjectShasFromC
f344f58d GITServerHandler.m (Scott 2009-01-04 143) {
70befddd GITServerHandler.m (Scott 2009-03-22 144)         //NSLog(@"GATHER COMMI
ad11ac80 GITPackUpload.m    (Scott 2009-03-24 145)
ad11ac80 GITPackUpload.m    (Scott 2009-03-24 146)         NSString *parentSha;
ad11ac80 GITPackUpload.m    (Scott 2009-03-24 147)         GITCommit *commit = [g
ad11ac80 GITPackUpload.m    (Scott 2009-03-24 148)
ad11ac80 GITPackUpload.m    (Scott 2009-03-24 149)         //NSLog(@"GATHER COMMI
ad11ac80 GITPackUpload.m    (Scott 2009-03-24 150)
56ef2caf GITServerHandler.m (Scott 2009-01-05 151)         if(commit) {
56ef2caf GITServerHandler.m (Scott 2009-01-05 152)                 [refDict setOb
56ef2caf GITServerHandler.m (Scott 2009-01-05 153)
				
			

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

বাইনারি অনুসন্ধান

ফাইল এনোটেশন পদ্ধতি সাহায্য করতে পারবে যখন আমরা জানবো যে কোডে সমস্যাটি কোথায়। কিন্তু ধরা যাক, আমরা জানি না কেন সমস্যা হচ্ছে। আর কোডটি শেষবার যখন কাজ করেছিলো, তারপর থেকে হয়ত ডজনখানেক কিংবা শ’খানেক কমিট হয়ে গেছে। এক্ষেত্রে git bisect কমান্ডটি আমাদের কাজ লাগতে পারে। bisect কমান্ডটি কমিটগুলোর ইতিহাসে একটি বাইনারি অনুসন্ধান চালায়, যাতে তাড়াতাড়ি সনাক্ত করা যায় যে, কোন কমিট থেকে সমস্যাটি দেখা দিয়েছিলো।

ধরা যাক একটি প্রোডাকশন এনভায়রনমেন্টে কোডের রিলিজ দেয়া হয়েছে, কিন্তু এমন কিছু বাগ রিপোর্ট আসছে যা ডেভেলপমেন্ট এনভায়রনমেন্টে ঘটছে না, এবং বের করা যাচ্ছে না যা কেন এমনটি হচ্ছে। শুধু সমস্যাটা যে হচ্ছে সেটা বোঝা যাচ্ছে। bisect ব্যবহার করে, কোন কমিটের কারনে বাগটা হচ্ছে, সেটা খোঁজা যাবে। প্রথমে git bisect start কমান্ড দিয়ে প্রক্রিয়াটি শুরু করি। তারপর git bisect bad  দিয়ে সিস্টেমকে জানাই যে বর্তমান কমিটটায় বাগ আছে। তারপরে শেষ যে কমিটগুলো বাগমুক্ত ছিল, সেরকম একটি কমিটের হ্যাশ বা ট্যাগ দিয়ে সিস্টেমকে জানাই যে কখন কোডটি ভালোভাবে কাজ করেছিলো।  এটার কমান্ড হচ্ছেঃ git bisect good <good_commit>

				
					$ git bisect start
$ git bisect bad
$ git bisect good v1.0
Bisecting: 6 revisions left to test after this
[ecb6e1bc347ccecc5f9350d878ce677feb13d3b2] Error handling on repo
				
			

উপরের উদাহরণে গিট বের করেছে যে, ভালো ও খারাপ চিহ্নিত করা কমিটের মাঝখানে আরো প্রায় ১২ টি কমিট এসেছে এবং এদের মাঝামাঝি একটি কমিটকে সক্রিয় (checkout) করে দিয়েছে যাতে বাগটি এখানে আছে কিনা পরীক্ষা করে দেখা যায়। যদি আমাদের পরীক্ষায় বাগটি আবার পাওয়া যায়, তাহলে বোঝা গেল – সক্রিয় করা মাঝের কমিটটা বা তারও আগের কোন একটা কমিটে বাগটার সুত্রপাত হয়। ধরা যাক আমাদের পরীক্ষায় বাগটা পাওয়া যায়নি, অর্থাৎ সক্রিয় করা কমিটটার পরের কোনো কমিটে বাগটার সুত্রপাত হয়েছে। বর্তমান সক্রিয় কমিটটা যে বাগমুক্ত সেটা সেটা আমরা এখন সিস্টেমকে জানিয়ে দিতে পারি git bisect good লিখে। এতে সিস্টেম পরের কোন কমিটে বাগ খুঁজতে তৎপর হবে:

				
					$ git bisect good
Bisecting: 3 revisions left to test after this
[b047b02ea83310a70fd603dc8cd7a6cd13d15c04] Secure this thing
				
			

এখন আবার অন্য একটি কমিট সক্রিয় (checkout) হলো, যা একটু আগে পরীক্ষা করা কমিট এবং শুরুতে খারাপ হিসাবে চিহ্নিত করা কমিটের মাঝামাঝি। আবার পরীক্ষা চালাই যা বাগটা আছে কিনা। ধরা যাক এবার বাগটা পাওয়া গেল। তাই সিস্টেমকে সেটা জানাই git bisect bad কমান্ডটা দিয়েঃ

				
					$ git bisect bad
Bisecting: 1 revisions left to test after this
[f71ce38690acf49c1f3c9bea38e09d82a5ce6014] Drop exceptions table
				
			

এবার ধরা যাক এই কমিটটায় বাগ পাওয়া যায়নি। সেটা গিটকে git bisect good দিয়ে জানাই। এখন গিটের কাছে সুনির্দিষ্ট তথ্য আছে যে ঠিক কখন বা কোন কমিটে বাগটি প্রথম এসেছিল। গিট সেই কমিটের হ্যাশ, কোন ফাইলগুলি পরিবর্তন হয়েছিলো – এসব সহ বিস্তারিত তথ্য আউটপুটে দেখাবেঃ

				
					$ git bisect good
b047b02ea83310a70fd603dc8cd7a6cd13d15c04 is first bad commit
commit b047b02ea83310a70fd603dc8cd7a6cd13d15c04
Author: PJ Hyett <pjhyett@example.com>
Date:   Tue Jan 27 14:48:32 2009 -0800

    Secure this thing

:040000 040000 40ee3e7821b895e52c1695092db9bdc4c61d1730
f24d3c6ebcfc639b1a3814550e62d60b8e68a8e4 M  config
				
			

কাজ শেষে এবার খেয়াল করে git bisect reset দিয়ে (বাইনারি সার্চ শুরুর) পুর্বের অবস্থায় ফিরে যাই। নয়তো অনেক কিছু ঠিকমত কাজ করবে নাঃ

				
					$ git bisect reset
				
			

এটি একটি শক্তিশালী টুল যা কয়েক মিনিটের মধ্যে কয়েকশ কমিট চেক করে বাগের সুত্রপাত হওয়া কমিটটাকে বের করতে সাহায্য করে। git bisect এর এই পুরো ব্যাপারটাকে স্বয়ংক্রিয় করে ফেলা যাবে যদি এমন একটি টেস্ট-স্ক্রিপ্ট লেখা হয় যেটা exit 0 করবে যদি সক্রিয় কমিট বাগমুক্ত হয় আর non-zero  exit করবে যদি বাগ থাকে। চাইলে bisect start  দিয়ে একইসাথে শুরুতে  খারাপ ও ভালো কমিটটা গিটকে দেখিয়ে দেয়া যায়। প্রথমটা মানটা খারাপ কমিটের ও দ্বিতীয়টা ভাল কমিটেরঃ

				
					$ git bisect start HEAD v1.0
$ git bisect run test-error.sh
				
			

এভাবে স্বয়ংক্রিয়ভাবে test-error.sh স্ক্রিপ্টটি প্রতিটি চেক-আউট করা কমিটের উপর চলে যতক্ষণ না গিট প্রথম বাগযুক্ত কমিটটা খুঁজে পায়। এছাড়াও make বা make tests এর মত কিছু একটা ব্যবহার করা যেতে পারে স্বয়ংক্রিয় টেস্ট চালানোর জন্য।