৮.২ গিট কাস্টমাইজ করা – গিট অ্যাট্রিবিউট
গিট অ্যাট্রিবিউটস
এই সেটিংস্ গুলোর মধ্যে কিছু সেটিং পাথ এর জন্যও সেট করা যায়, যেন গিট ওই সেটিংস্গুলো শুধুমাত্র একটা সাব-ফোল্ডার অথবা ফাইল এর সাবসেট এর উপর অ্যাপ্লাই করতে পারে। এই পাথ স্পেচেফিক সেটিংস্গুলকে গিট অ্যাট্রিবিউটস বলা হয় এবং এরা প্রোজেক্ট এর যেকোনো ডাইরেক্টরি এর মধ্যে (সাধারণত প্রোজেক্ট এর রুট ডাইরেক্টরি) .gitattributes নাম এর ফাইল এ সেট হয় অথবা .git/info/attributes ফাইল এ যদি না আপনি অ্যাট্রিবিউটস ফাইল প্রোজেক্ট এ না রাখতে চান।
অ্যাট্রিবিউটস দিয়ে আপনি, ফাইল বা ডাইরেক্টরির জন্য ভিন্ন মার্জ স্ট্রেজিটি সেট করতে পারেন, নন-টেক্স ফাইল কিভাবে গিট diff করবে, অথবা check in কিংবা check out করার আগে গিট যেন কনটেন্ট ফিল্টার করতে পারে. এই সেকশন এ, আপনি আপনার গিট প্রজেক্ট এর পাথ এ অ্যাট্রিবিউটস সেট করা জানতে পারবেন এবং অনুশীলনে এই বৈশিষ্ট্যটি ব্যবহার করার কয়েকটি উদাহরণ দেখতে পাবেন।
বাইনারি ফাইলস
একটি ভাল কৌশল যার জন্য আপনি গিট অ্যাট্রিবিউটস ব্যবহার করতে পারেন তা হল গিট কে বলা যে কোন ফাইলগুলি বাইনারি (কোন ক্ষেত্রে এটি অন্যথায় বের করতে নাও পারে) এবং সেই ফাইলগুলি কীভাবে পরিচালনা করবেন সে সম্পর্কে গিট কে বিশেষ নির্দেশনা দেওয়া। উদাহরণস্বরূপ, কিছু টেক্সট ফাইল মেশিন জেনারেটেড হতে পারে এবং সেটা diff করা যায় না, যেখানে কিছু বাইনারি ফাইল ভিন্ন হতে পারে। আপনি দেখতে পাবেন কিভাবে গিটকে বলতে হয় কোনটি।
বাইনারি ফাইল সনাক্তকরণ
কিছু ফাইল টেক্সট ফাইলের মত দেখতে কিন্তু বাবহার এর জন্য বাইনারি ডাটা হিসাবে গণ্য করা হয়।
উদাহরণস্বরূপ, ম্যাকওএস -এ এক্স-কোড প্রকল্পগুলিতে একটি ফাইল থাকে যা .pbxproj -এ শেষ হয়, যা মূলত একটি জেসন ডাটাসেট যা আইডিই দ্বারা ডিস্ক এ রাইট হয়, যা আপনার বিল্ড সেটিংস ইত্যাদি রেকর্ড করে। যদিও এটি টেকনিক্যালি একটি টেক্সট ফাইল (কারণ এটি সবই UTF-8), আপনি এটিকে এমনভাবে বিবেচনা করতে চান না কারণ এটি সত্যিই একটি লাইটওয়েট ডাটাবেজ – আপনি কন্টেন্ট গুলিকে মার্জ করতে পারবেন না যদি দু’জন ব্যক্তি এটিকে পরিবর্তন করে, এবং diffs সাধারণত হেল্পফুল না। এই ফাইল মেশিন দ্বারা বাবহার করার জন্য তৈরি হয়। সংক্ষেপে, আপনি এটিকে একটি বাইনারি ফাইলের মতো আচরণ করতে চান।
সমস্ত pbxproj ফাইলকে বাইনারি ডেটা হিসাবে বিবেচনা করতে গিটকে বলতে, আপনার .gitattributes ফাইলে নিম্নলিখিত লাইনটি যুক্ত করুন:
*.pbxproj binary
এখন, গিট CRLF সমস্যাগুলি কনভার্ট বা ফিক্স করার চেষ্টা করবে না; অথবা আপনি যখন আপনার প্রোজেক্ট এ git show বা git diff চালান তখন এই ফাইলের পরিবর্তনের জন্য কোনো diff compute বা print করার চেষ্টা করবে না।
বাইনারি ফাইলের পার্থক্য
আপনি বাইনারি ফাইলগুলিকে সফল ভাবে diff করতে গিট অ্যাট্রিবিউটের ফাংশনালিটি ব্যবহার করতে পারেন। আপনি গিট কে কীভাবে আপনার বাইনারি ডেটাকে একটি টেক্সট ফরমেট এ কনভার্ট করবেন তা বলে এই কাজটি করতে পারবেন যেন সেই ফাইল টি নরমাল diff দিয়ে কম্পেয়ার করা যায়।
প্রথমত, আপনি একটি সবচেয়ে বিরক্তিকর সমস্যার সমাধান করতে এই কৌশলটি ব্যবহার করতে পাড়েন: যা হল মাইক্রোসফ্ট ওয়ার্ড ডকুমেন্টস এর ভার্সন কন্ট্রোল করা। আপনি যদি ওয়ার্ড ডকুমেন্ট গুলিকে ভার্সন কন্ট্রোল করতে চান তবে আপনি সেগুলিকে একটি গিট রিপোজিটরি তে রাখতে পারেন এবং নিয়মিত কমিট করতে পারেন; কিন্তু তাতে কি লাভ? আপনি যদি git diff চালান তবে আপনি কেবল এইরকম কিছু দেখতে পাবেন:
$ git diff
diff --git a/chapter1.docx b/chapter1.docx
index 88839c4..4afcb7c 100644
Binary files a/chapter1.docx and b/chapter1.docx differ
আপনি সরাসরি দুটি ভার্সন তুলনা করতে পারবেন না যদি না আপনি সেগুলি পরীক্ষা করে দেখেন এবং ম্যানুয়ালি স্ক্যান করেন, তাই না? দেখা যাচ্ছে যে আপনি গিট অ্যাট্রিবিউস ব্যবহার করে এটি মোটামুটি ভালভাবে করতে পারেন। আপনার .gitattributes ফাইলে নিম্নলিখিত লাইনটি রাখুন:
*.docx diff=word
#!/bin/bash
docx2txt.pl "$1" -
সেই ফাইলটিকে `chmod a+x` করতে ভুলবেন না। অবশেষে, আপনি এই স্ক্রিপ্টটি ব্যবহার করতে গিট কনফিগার করতে পারেন:
$ git config diff.word.textconv docx2txt
এখন গিট জানবে যে যদি গিট দুটি স্ন্যাপশট এর মধ্যে diff করার চেষ্টা করে এবং যেকোন ফাইল যদি `.docx` এ শেষ হয়, তাহলে সেই ফাইলগুলিকে “ওয়ার্ড” ফিল্টার দিয়ে রান করতে হবে, যা `docx2txt` প্রোগ্রাম হিসেবে ডিফাইন করা হয়েছে। diff করার চেষ্টা করার আগে গিট কার্যকরভাবে আপনার ওয়ার্ড ফাইলগুলির টেক্সট বেইজ ভার্সন তৈরি করবে।
এখানে একটি উদাহরণ: এই বই এর অধ্যায় ১ ওয়ার্ড ফরমেট এ কনভার্ট হয়েছে এবং একটি গিট রিপোজিটরি তে কমিট হয়েছে। তারপর একটি নতুন প্যারাগ্রাফ যোগ করা হয়.
`git diff` নীচের আউটপুট দেখাবে:
$ git diff
diff --git a/chapter1.docx b/chapter1.docx
index 0b013ca..ba25db5 100644
--- a/chapter1.docx
+++ b/chapter1.docx
@@ -2,6 +2,7 @@
This chapter will be about getting started with গিট. We will begin at the beginning by explaining some background on version control tools, then move on to how to get গিট running on your system and finally how to get it setup to start working with. At the end of this chapter you should understand why Git is around, why you should use it and you should be all setup to do so.
1.1. About Version Control
What is "version control", and why should you care? Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later. For the examples in this book you will use software source code as the files being version controlled, though in reality you can do this with nearly any type of file on a computer.
+Testing: 1, 2, 3.
If you are a graphic or web designer and want to keep every version of an image or layout (which you would most certainly want to), a Version Control System (VCS) is a very wise thing to use. It allows you to revert files back to a previous state, revert the entire project back to a previous state, compare changes over time, see who last modified something that might be causing a problem, who introduced an issue and when, and more. Using a VCS also generally means that if you screw things up or lose files, you can easily recover. In addition, you get all this for very little overhead.
1.1.1. Local Version Control Systems
Many people's version-control method of choice is to copy files into another directory (perhaps a time-stamped directory, if they're clever). This approach is very common because it is so simple, but it is also incredibly error prone. It is easy to forget which directory you're in and accidentally write to the wrong file or copy over files you don't mean to.
গিট সফলভাবে এবং সংক্ষিপ্তভাবে আমাদের বলেছে যে আমরা “টেস্টিংঃ ১, ২, ৩” স্ট্রিং যোগ করেছি , যা সঠিক। এটি নিখুঁত নয় – ফর্ম্যাটিং পরিবর্তনগুলি এখানে প্রদর্শিত হবে না – তবে এটি অবশ্যই কাজ করে৷
আরেকটি আকর্ষণীয় সমস্যা যা আপনি এইভাবে সমাধান করতে পারেন তা হল দুইতি ইমেইজ ফাইলের diff বের করা। এটি করার একটি উপায় হল একটি ফিল্টারের মাধ্যমে ইমেজ ফাইল রান করা যা তাদের EXIF তথ্য বের করবে – মেটাডাটা যা বেশিরভাগ ইমেজ ফরম্যাটের সাথে থাকে। আপনি যদি `exiftool` প্রোগ্রামটি ডাউনলোড এবং ইনস্টল করেন, আপনি প্রোগ্রামটি ব্যবহার করে আপনার ইমেইজ গুলকে মেটাডাটা এর টেক্সট এ কনভার্ট করতে পারেন, যেন diff অন্তত চেইঞ্জ গুলোর টেক্সচুয়াল রিপ্রেজেন্টেশন দেখাতে পারে। আপনার `.gitattributes` ফাইলে নিম্নলিখিত লাইনটি লিখুন:
*.png diff=exif
এই টুল ব্যবহার করতে গিট কনফিগার করুন:
$ git config diff.exif.textconv exiftool
আপনি যদি আপনার প্রজেক্ট এ একটি ইমেইজ রিপ্লেস করেন এবং `git diff` চালান, আপনি এইরকম কিছু দেখতে পাবেন:
diff --git a/image.png b/image.png
index 88839c4..4afcb7c 100644
--- a/image.png
+++ b/image.png
@@ -1,12 +1,12 @@
ExifTool Version Number : 7.74
-File Size : 70 kB
-File Modification Date/Time : 2009:04:21 07:02:45-07:00
+File Size : 94 kB
+File Modification Date/Time : 2009:04:21 07:02:43-07:00
File Type : PNG
MIME Type : image/png
-Image Width : 1058
-Image Height : 889
+Image Width : 1056
+Image Height : 827
Bit Depth : 8
Color Type : RGB with Alpha
আপনি সহজেই দেখতে পারেন যে ফাইল সাইজ এবং মেইজ ডাইমেনশন উভয়ই পরিবর্তিত হয়েছে।
কীওয়ার্ড এক্সপেনশন
SVN- বা CVS- সিস্টেম ব্যবহার করা যারা অভ্যস্ত তারা প্রায়ই কীওয়ার্ড এক্সপেনশন ফিচার টা চায়.
গিটে এর প্রধান সমস্যা হল আপনি কমিট করার পরে কমিট সম্পর্কে তথ্য যে ফাইল এ লেখা থাকে তা পরিবর্তন করতে পারবেন না, কারণ গিট প্রথমে ফাইলটির চেকসাম করে। কিন্তু, আপনি কোন ফাইল check out করার পর তাতে টেক্সট অ্যাড করতে পারেন এবং কমিট করার আগে সেটা রিমুভ করতে পারেন। গিট অ্যাট্রিবিউট দিয়ে দুই ভাবে এটি করা যায়.
প্রথমে, ফাইল এর `$Id$` নামের ফিল্ডে এ ব্লব এর চেকসাম অটোমেটিক্যালি রাইট করতে পারেন।
আপনি যদি এই অ্যাট্রিবিউট এক বা একাধিক ফাইল এ সেট করেন, তারপর পরের বার যদি আপনি সেই ব্রাঞ্চ টা check out করেন , গিট সেই ফিল্ড কে ব্লব এর SHA-1 এ রিপ্লেস করবে। এটা লক্ষ করা জরুরী যে এই SHA-1 টি কমিট এর SHA-1 না, ব্লব এর SHA-1.আপনার `.gitattributes` ফাইলে নিম্নলিখিত লাইনটি লিখুন:
*.txt ident
একটি টেস্ট ফাইলে একটি `$Id$` রেফারেন্স এড করুন:
$ echo '$Id$' > test.txt
পরের বার যখন আপনি এই ফাইলটি check out করবেন, গিট ব্লব এর SHA-1 টি ইনজেক্ট করবে:
$ rm test.txt
$ git checkout -- test.txt
$ cat test.txt
$Id: 42812b7653c7b88933f8a9d6cad0ca16714b9bb3 $
![smudge](https://staging.vivasoftltd.com/wp-content/uploads/2023/02/smudge.png)
![clean](https://staging.vivasoftltd.com/wp-content/uploads/2023/02/clean.png)
আপনি আপনার `.gitattributes` ফাইলে ফিল্টার অ্যাট্রিবিউট সেট করে `\*.c` ফাইলগুলিকে “`ইন্ডেন্ট`” ফিল্টার দিয়ে ফিল্টার করে সেট আপ করতে পারেন:
*.c filter=indent
তারপর, গিট কে বলুন “ইন্ডেন্ট” ফিল্টার smudge এবং clean এর ক্ষেত্রে কী করে:
$ git config --global filter.indent.clean indent
$ git config --global filter.indent.smudge cat
এই ক্ষেত্রে, আপনি যখন `*.c` এর সাথে মেলে এমন ফাইল কমিট করেন, গিট তাদের স্টেজ করার আগে ইন্ডেন্ট প্রোগ্রাম চালাবে এবং ডিস্ক এ check out করার আগে `cat` প্রোগ্রাম চালাবে। `cat` প্রোগ্রাম আসলে বেশি কিছু করে না: এটা ইনপুট এ যে ডাটা আছে তাই দেখায়। এই কম্বিনেশন কার্যকরভাবে সমস্ত সি সোর্স কোড ফাইলকে কমিট করার আগে `ইন্ডেন্ট` এর মাধ্যমে ফিল্টারস করে।
আরেকটি মজাদার উদাহরণ হল `$Date$`কি-ওয়ার্ড এক্সপেনশন, RCS স্টাইলে এ। এটি সঠিকভাবে করতে, আপনার একটি ছোট স্ক্রিপ্ট দরকার যা একটি ফাইলের নাম ইনপুট নেবে, এই প্রোজেক্ট এর জন্য সর্বশেষ কমিট ডেইট বের করবে, এবং সেই ডেইট টি ফাইলে সেভ করবে। নিছের Ruby স্ক্রিপ্ট টি তাই করে:
#! /usr/bin/env ruby
data = STDIN.read
last_date = `git log --pretty=format:"%ad" -1`
puts data.gsub('$Date$', '$Date: ' + last_date.to_s + '$')
এই স্ক্রিপ্টটি `git log` কমান্ড থেকে লেটেস্ট কমিট ডেইট বের করবে এবং সেই রেজাল্ট stdin এর `$Date$` প্যাটার্ন এ লিখে দিবে – এটা আপনি যেকোনো ল্যাঙ্গুয়েজ এ ইমপ্লেমেন্ট করা যাবে। আপনি এই ফাইলটির নাম দিতে পারেন `expand_date` এবং আপনার পাথ এ রাখতে পারেন। এখন আপনাকে গিট এ একটি ফিল্টার সেটআপ করতে হবে (নাম দিতে পারেন `dater`) এবং তাকে checkout করার সময় smudge করার জন্য আপনার `expand_date` ফিল্টার টি ব্যাবহার করতে বলতে পারেন।
কমিট এর সময় clean করতে পার্ল এক্সপ্রেশন ব্যাবহার করতে পারেন।
$ git config filter.dater.smudge expand_date
$ git config filter.dater.clean 'perl -pe "s/\\\$Date[^\\\$]*\\\$/\\\$Date\\\$/"'
এই পার্ল স্নিপেট `$Date$` এর মধ্যে যা পাবে তা ফাকা করে ফেলবে, যেন ফাইল এর আগের জায়গাই যাওয়া যায়। এখন যেহেতু আপনার ফিল্টার রেডি হয়েছে, আপনি এটাকে কোন ফাইল টাইপ এর জন্য গিট অ্যাট্রিবিউট সেট করে এবং $Date$` কি-ওয়ার্ড এর ফাইল তৈরি করে টেস্ট করতে পারেন।
date*.txt filter=dater
$ echo '# $Date$' > date_test.txt
আপনি যদি সেই চেইঞ্জ গুলো কমিট করেন এবং আবার সেই ফাইল টি check out করেন তাহলে আপনি দেখতে পাবেন যে কি-ওয়ার্ড ঠিকমত সাবস্টিউট হয়েছেঃ
$ git add date_test.txt .gitattributes
$ git commit -m "Test date expansion in Git"
$ rm date_test.txt
$ git checkout date_test.txt
$ cat date_test.txt
# $Date: Tue Apr 21 07:26:52 2009 -0700$
আপনি দেখতে পাচ্ছেন যে এই টেকনিক টি কাস্টমাইজড এপ্লিকেশন এর ক্ষেত্রে অনেক পাওয়ারফুল হতে পারে। অবশ্য আপনাকে এই ব্যাপারে সাবধান থাকতে হবে, কারন .gitattributes ফাইলটি প্রোজেক্ট এ কমিট এবং শেয়ার হবে, কিন্তু ড্রাইভার (`dater`) শেয়ার হবে না, তাই এটি সব যায়গায় কাজ করবে না। আপনি যখন ফিল্টার গুলো ডিজাইন করবেন, এমন ভাবে ডিজাইন করবেন যেন তা গ্রেস্ফুল ফেইল করে এবং প্রজেক্ট যেন ঠিকমত কাজ করে।
এক্সপোর্ট ইউর রিপোজিটরি
আপনার প্রোজেক্ট এর এক্সপোর্ট করার সময় আপনি গিট এট্রিবিউট দিয়ে কিছু ইন্টারেস্টিং কাজ করতে পারেন।
export-ignore
আপনি গিট কে বলতে পারেন যে সে আপনার প্রোজেক্ট আর্কাইভ করার সময় নির্দিষ্ট কিছু ফাইল বা ফোল্ডার এক্সপোর্ট না করে। আপনি যদি একটি ফাইল অথবা ফোল্ডার আর্কাইভ এ রাখতে চান না কিন্তু আপনার প্রোজেক্ট এ checked in করে রাখতে চান, আপনি এটা করতে পারবেন export-ignore এট্রিবিউট দিয়ে।
উদাহরণ স্বরূপ,ধরুন আপনার প্রোজেক্ট এর test/ সাবডিরেক্টরি তে কিছু টেস্ট ফাইলস আছে কিন্তু সেই ফাইল গুলো আপনার প্রজেক্ট এর টারবাল এক্সপোর্ট এ রাখার কোন প্রয়োজন নেই। আপনি এই জন্য আপনার গিট এট্রিবিউটস ফাইল এ নীচের লাইন অ্যাড করতে পারেন।
test/ export-ignore
এখন আপনি যখন git archive দিয়ে আপনার প্রজেক্ট এর টারবাল ক্রিয়েট করবেন, সেই ফোল্ডার আর্কাইভ এ থাকবে না।
export-subst
যখন আপনি ডেপ্লয়মেন্ট এর জন্য ফাইলগুলো এক্সপোর্ট করবেন তখন export-subst এট্রিবিউট দিয়ে মার্ক করা ফাইলগুলিতে git log এর ফরম্যাটিং এবং কি-ওয়ার্ড এক্সপেনশন প্রসেসিং অ্যাপ্লাই করতে পারেন।
উদাহরণস্বরূপ, আপনি যদি আপনার প্রজেক্ট এ LAST_COMMIT নামে একটি ফাইল রাখতে চান, এবং যখন git archive রান হবে তখনকার সর্বশেষ কমিট এর মেটাডাটা অটোমেটিক্যালি অ্যাড করতে চান, আপনার .gitattributes এবং LAST_COMMIT আপনি নীচের মত করে সেটআপ করতে পারেন:
LAST_COMMIT export-subst
$ echo 'Last commit date: $Format:%cd by %aN$' > LAST_COMMIT
$ git add LAST_COMMIT .gitattributes
$ git commit -am 'adding LAST_COMMIT file for archives'
আপনি যখন git archive রান করবেন তখন আর্কাইভ করা ফাইল এর কন্টেন্ট নীচের মত দেখাবে:
$ git archive HEAD | tar xCf ../deployment-testing -
$ cat ../deployment-testing/LAST_COMMIT
Last commit date: Tue Apr 21 08:38:48 2009 -0700 by Scott Chacon
এই সাবস্টিটিউশন গুলো উদাহরণস্বরূপ কমিট মেসেজ এবং যেকোনো git notes, এবং git log ওয়ার্ড র্যাপিং করে দেখাবে:
$ echo '$Format:Last commit: %h by %aN at %cd%n%+w(76,6,9)%B$' > LAST_COMMIT
$ git commit -am 'export-subst uses git log'\''s custom formatter
git archive uses git log'\''s `pretty=format:` processor
directly, and strips the surrounding `$Format:` and `$`
markup from the output.
'
$ git archive @ | tar xfO - LAST_COMMIT
Last commit: 312ccc8 by Jim Hill at Fri May 8 09:14:04 2015 -0700
export-subst uses git log's custom formatter
git archive uses git log's `pretty=format:` processor directly, and
strips the surrounding `$Format:` and `$` markup from the output.
যে আর্কাইভ টি তৈরি হয় তা ডেপ্লয়মেন্ট এর জন্য উপযুক্ত, কিন্তু এটি ডেভেলপমেন্ট এর জন্য উপযুক্ত নয়।
মার্জ স্ট্রেটেজিজ
আপনি গিট এট্রিবিউট দিয়ে গিট কে নির্দিষ্ট ফাইল এর জন্য ভিন্ন মার্জ স্ট্রেটেজিজ ব্যবহার করতে বলতে পারেন। একটি কার্যকর অপশন হল যে, নির্দিষ্ট কিছু ফাইল এ কনফ্লিক্ট হলে গিট যেন সেই ফাইল গুলো মার্জ না করে, পরিবর্তে সে যেন আপনার সাইড এর মার্জ টা সিলেক্ট করে।
এটি সহায়ক যদি আপনার প্রজেক্টের একটি ব্রাঞ্চ আলাদা হয়ে যায় বা বিশেষায়িত হয়, তবে আপনি এটি থেকে পরিবর্তনগুলিকে আবার একত্রিত করতে সক্ষম হতে চান এবং আপনি নির্দিষ্ট ফাইলগুলিকে ইগনোর করতে চান। বলুন আপনার কাছে database.xml নামক একটি ডাটাবেস সেটিংস ফাইল আছে যা দুটি ব্রাঞ্চে ভিন্ন, এবং আপনি ডাটাবেস ফাইলটি এলোমেলো না করে আপনার অন্য ব্রাঞ্চে একত্রিত করতে চান। আপনি এই মত একটি বৈশিষ্ট্য সেট আপ করতে পারেন:
database.xml merge=ours
এবং তারপর একটি ডামি `ours` মার্জ স্ট্রেটেজি এর সাথে ডিফাইন করুন:
And then define a dummy `ours` merge strategy with:
$ git config --global merge.ours.driver true
আপনি যদি অন্য ব্রাঞ্চে মার্জ করেন, তাহলে database.xml ফাইলের সাথে মার্জ কনফ্লিক্টস এর পরিবর্তে, আপনি এরকম কিছু দেখতে পাবেন:
$ git merge topic
Auto-merging database.xml
Merge made by recursive.
এই ক্ষেত্রে, database.xml আপনার কাছে যে ভার্সনটি ছিল সেখানেই থাকবে।