এই পর্বে যা শিখবেন
- Version control ছাড়া দলের কাজে কীভাবে কাজ হারায়, আর version control ঠিক কী কী দেয়
- Local, centralized আর distributed VCS-এর গঠন, locking বনাম merging, আর server বন্ধ থাকলে কী হয়
- Git-এর জন্মকথা, তার নকশার লক্ষ্য, আর snapshot বনাম delta-র ধারণা
- Git আর GitHub/GitLab/Bitbucket-এর পার্থক্য; command line, GUI আর IDE
- Windows, macOS আর Linux-এ Git install, প্রথমবারের
git configআরgit help
১ · final_v2_real_final.docx — সমস্যাটা চিনে নিই
আপনার কম্পিউটারে কি এমন একটি ফোল্ডার আছে? report.docx, report_final.docx, report_final_v2.docx, report_final_v2_real_final.docx. প্রতিটি নাম একটি ছোট আশার গল্প: “এটাই শেষ।” কিন্তু এক সপ্তাহ পরে আর মনে থাকে না কোনটিতে কী বদলেছিলেন, আর কেন।
একা কাজ করলে এটা বিরক্তিকর, দলে কাজ করলে বিপজ্জনক। তিনজন মিলে কোড লিখছেন; কেউ ইমেইলে zip পাঠান, কেউ শেয়ার্ড ফোল্ডারে ফাইল রাখেন। তখন তিনটি প্রশ্নের উত্তর কেউ জানেন না: এখন আসল কপি কোনটি? গতকাল কে কী বদলেছেন? যে bug আজ দেখা দিল, সেটা কোন পরিবর্তনে এল?
পাড়ার মুদি দোকানের হিসাবের খাতার কথা ভাবুন। দোকানি পুরোনো পাতা ছিঁড়ে ফেলেন না; প্রতিটি লেনদেন তারিখসহ নিচে নিচে লেখেন, ভুল হলে কেটে নতুন লাইন লেখেন। এখন ভাবুন, দোকানের দুই কর্মচারী একই খাতার দুটি ফটোকপিতে আলাদা আলাদা লিখলেন, আর সন্ধ্যায় একজন নিজের কপিটাকেই “আসল খাতা” বলে রেখে দিলেন। অন্যজনের সারাদিনের হিসাব কোথায় গেল? Version control হলো দলের কোডের জন্য সেই যত্নের হিসাবের খাতা — যেখানে প্রতিটি পরিবর্তন তারিখ, লেখক আর কারণসহ জমা থাকে, আর কারও লেখা চুপচাপ মুছে যায় না।
নিচের স্টেপারে একটি কাল্পনিক অনলাইন বাজার অ্যাপের দুই developer, Rina আর Karim, একটি শেয়ার্ড ফোল্ডারে price.js ফাইলে কাজ করছেন। কোনো version control নেই। “পরে” চেপে দেখুন কাজ কীভাবে হারায়:
| শেয়ার্ড price.js | |
| Rina-র কপি | |
| Karim-এর কপি | |
| ফোল্ডারের ফাইলগুলো | |
| ক্ষতি |
- সকাল ৯টা। শেয়ার্ড ফোল্ডারে
price.js-এর একটি মাত্র কপি (v1): দামের সাথে ৫% VAT যোগ হয়, কোনো discount নেই। - দুজনেই কপি নিলেন। Rina-কে বলা হয়েছে ঈদের discount যোগ করতে, Karim-কে VAT-এর একটি bug ঠিক করতে। দুজনেই নিজের কম্পিউটারে v1 কপি করলেন — কেউ জানেন না অন্যজনও একই ফাইলে হাত দিচ্ছেন।
- দুজনে আলাদা অংশ বদলালেন। Rina discount-এর function লিখলেন, Karim VAT-এর হিসাব ঠিক করলেন। পরিবর্তন দুটি আসলে ফাইলের আলাদা জায়গায় — মেলানো খুব সহজ হতো।
- সকাল ১১টা — Rina save করলেন। সাবধানতার জন্য পুরোনোটাকে
price_old.jsনামে রেখে নিজের কপি শেয়ার্ড ফোল্ডারে বসালেন। এখন শেয়ার্ড ফাইলে discount আছে। - দুপুর ১২টা — Karim save করলেন। তাঁর কপি তৈরি হয়েছিল v1 থেকে, তাই তাতে discount নেই। ফাইলটি বসানোর সাথে সাথে Rina-র কাজ মুছে গেল — কোনো error নেই, কোনো সতর্কবার্তা নেই। একে বলে lost update.
- তিন দিন পরে। গ্রাহকেরা অভিযোগ করলেন, discount কাজ করছে না। Rina বললেন, “আমি তো লিখেছিলাম!” ফোল্ডারে এখন চারটি ফাইল; কোনটিতে কী আছে, কে কখন বদলেছেন — লেখা নেই। দুই দিন খুঁজে কাজটি আবার লিখতে হলো। কারও দোষ নয়; পদ্ধতিটাই কাজ হারানোর মতো করে বানানো।
এখন একই ঘটনা একটু বড় করে দেখি। দুজন developer ১২ বার একই ১০ লাইনের ফাইল কপি করে কাজ করলেন; প্রতিবার দুজনে একটি করে লাইন বদলালেন। প্রথম পদ্ধতিতে শেষে যিনি save করেন, তাঁর ফাইলটাই থাকে। দ্বিতীয় পদ্ধতিতে একটি version control-এর মতো নিয়ম: save-এর আগে দেখা হয়, “আপনি কপি নেওয়ার পরে ফাইলটি কি বদলেছে?” বদলালে আলাদা লাইনের পরিবর্তন মিলিয়ে দেওয়া হয়, আর একই লাইন হলে থেমে মানুষকে জিজ্ঞেস করা হয়। কোন লাইন কে বদলাবেন, তা ঠিক হয় একটি seed-যুক্ত random সংখ্যা দিয়ে, তাই প্রতিবার একই ফল আসে:
// Two developers edit a 10-line shared file in 12 rounds. Each round both copy the file,
// each changes one random line, then they save back (Rina first, then Karim).
function mulberry32(a) { return () => { a = (a + 0x6D2B79F5) | 0; let t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; }
function simulate(useVcs) {
const rnd = mulberry32(42);
let file = Array.from({ length: 10 }, (_, i) => "line" + i);
let kept = 0, lost = 0, merged = 0, conflicts = 0;
for (let round = 1; round <= 12; round++) {
const base = file.slice(); // both start from the same copy
const a = Math.floor(rnd() * 10), b = Math.floor(rnd() * 10);
const rina = base.slice(); rina[a] = "R" + round;
const karim = base.slice(); karim[b] = "K" + round;
file = rina; // Rina saves first: always fine
if (!useVcs) { // copy-overwrite: last save wins
file = karim; kept++; lost++; // Rina's edit is silently gone
} else if (a !== b) { // VCS sees the file changed since Karim's copy
file = file.slice(); file[b] = karim[b]; kept += 2; merged++; // different lines: auto-merge
} else { // same line: stop and ask a human
file = file.slice(); file[a] = "R" + round + "+K" + round; kept += 2; conflicts++;
}
}
return { kept, lost, merged, conflicts, last: file.join(" ") };
}
const f = (r) => `edits kept ${r.kept}/24, lost ${r.lost}, auto-merged ${r.merged}, conflicts ${r.conflicts}`;
console.log("copy-overwrite :", f(simulate(false)));
const v = simulate(true);
console.log("with VCS check :", f(v));
console.log("final file (VCS):", v.last);আউটপুট:
copy-overwrite : edits kept 12/24, lost 12, auto-merged 0, conflicts 0
with VCS check : edits kept 24/24, lost 0, auto-merged 11, conflicts 1
final file (VCS): K12 R8 R6 K7 K10 R12 R9+K9 R7 R11 line9
কপি করে overwrite: ২৪টি পরিবর্তনের মধ্যে ১২টিই হারিয়েছে — প্রতি দফায় Rina-র কাজ, কারণ পুরো ফাইল বসিয়ে দিলে আগের save-এর সব কিছু চলে যায়। দুজনে আলাদা লাইন বদলালেও রক্ষা নেই। Version control-এর নিয়মে: ২৪টিই টিকে আছে। ১১ দফায় দুজন আলাদা লাইন বদলেছেন, তাই নিজে থেকেই মিলে গেছে (auto-merge). একবার (৯ নম্বর দফা) দুজনেই একই লাইন বদলেছেন — তখন কোনো পক্ষকে চুপচাপ জিতিয়ে না দিয়ে একটি merge conflict জানানো হয়েছে, আর মানুষ দুটো মিলিয়ে R9+K9 লিখেছেন। এই সিমুলেশন সরল: আসল Git লাইন-ভিত্তিক three-way merge করে, যা পর্ব ১৩-এ ধাপে ধাপে দেখবেন। কিন্তু মূল কথা এখানেই: পরিবর্তন হারানো আর conflict জানানো — দুটোর পার্থক্যই version control-এর প্রথম উপহার।
২ · Version control আসলে কী দেয়
Version control (বা version control system, সংক্ষেপে VCS; অনেকে source control-ও বলেন) হলো এমন একটি ব্যবস্থা, যা ফাইলের প্রতিটি পরিবর্তন সময়ের ক্রমে রেকর্ড করে, যাতে পরে যেকোনো পুরোনো অবস্থা দেখা বা ফিরিয়ে আনা যায়, আর অনেকে নিরাপদে একসাথে কাজ করতে পারেন। মূলত কোডের জন্য তৈরি, কিন্তু যেকোনো লেখা-ভিত্তিক ফাইলে কাজ করে — বই, গবেষণাপত্র, configuration, এমনকি এই ওয়েবসাইটের পাতাও।
প্রতিটি সংরক্ষিত পরিবর্তনকে Git-এ বলে commit: project-এর একটি মুহূর্তের ছবি, সাথে লেখকের নাম, সময় আর একটি বার্তা। এই commit-গুলো যেখানে জমা থাকে, তা হলো repository (সংক্ষেপে repo). এ দুটি শব্দ দিয়েই নিচের ছয়টি সুবিধা বোঝা যায়:
📜 পূর্ণ ইতিহাস
প্রতিটি commit থেকে যায়। “গত মাসের ১০ তারিখে ফাইলটি কেমন ছিল?” — কয়েক সেকেন্ডে উত্তর। পর্ব ০৯-এ log, diff, show.
👤 কে, কখন, কেন
প্রতিটি পরিবর্তনের সাথে লেখক, সময় আর বার্তা। ভালো বার্তা “কেন” বলে দেয় — ছয় মাস পরের আপনিই এর সবচেয়ে বড় পাঠক।
who · when · why↩️ নিরাপদে ফিরে যাওয়া
ভুল পরিবর্তন বাতিল করা যায়, পুরো project বা একটি ফাইল আগের অবস্থায় ফেরানো যায়। পর্ব ১১-এ restore, reset, revert.
undo🌿 সমান্তরাল কাজ
মূল কোড না ছুঁয়ে আলাদা branch-এ নতুন feature বা পরীক্ষা; শেষে মিলিয়ে নেওয়া। পর্ব ১২ আর ১৩.
parallel work🤝 দলের কাজ
অনেকের পরিবর্তন নিয়ম মেনে মেলে; একই অংশে সংঘাত হলে লুকিয়ে না থেকে চোখে পড়ে। Review আর pull request আসবে মডিউল ৩-এ।
collaboration🛟 দোষারোপ ছাড়া উদ্ধার
কিছু ভাঙলে প্রশ্ন হয় “কোন পরিবর্তনে ভাঙল?”, “কার দোষ?” নয়। ইতিহাস থাকলে কারণ খুঁজে ঠিক করা সহজ, আর ভুল স্বীকার করাও নিরাপদ।
blame-free recoveryপর্ব ০৬-এ (Kanban আর lean) দেখেছেন, ভালো দল ভুলের পরে দোষী মানুষ নয়, দুর্বল প্রক্রিয়া খোঁজে; কাজ সহজে ফেরানো গেলে মানুষ পরীক্ষা করতেও ভয় পান না। মজার ব্যাপার, Git-এ একটি command-এর নামই git blame — প্রতিটি লাইন শেষবার কোন commit-এ বদলেছে, তা দেখায়। নামটি কঠিন শোনালেও কাজটি তদন্তের, শাস্তির নয়; পর্ব ৫৫-এ এটি আর bisect দেখবেন।
Version control শুধু “backup” নয়। Backup বলে কী ছিল; version control বলে কী বদলেছে, কে বদলেছেন, কেন, আর অন্যদের পরিবর্তনের সাথে কীভাবে মেলে। পর্ব ০১-এ (Software engineering কী) যে “টেকসই software”-এর কথা বলেছিলাম, তার প্রতিদিনের হাতিয়ার এটিই।
৩ · তিন প্রজন্ম — local, centralized আর distributed
Version control-এর ইতিহাস মোটামুটি তিনটি ধাপে ভাগ করা যায়। প্রতিটি ধাপ আগেরটির একটি বড় সীমাবদ্ধতা দূর করেছে।
ইতিহাস কোথায় থাকে — তিন ধরনের VCS
Local VCS · Centralized VCS · Distributed VCS
প্রথম প্রজন্ম — local VCS
Local VCS একটি কম্পিউটারে, সাধারণত প্রতিটি ফাইলের পাশে একটি আলাদা ইতিহাস-ফাইলে পুরোনো version রাখে। Bell Labs-এর SCCS (Marc Rochkind, ১৯৭২-এর দিকে) আর Purdue বিশ্ববিদ্যালয়ের Walter Tichy-র RCS (১৯৮২-র দিকে প্রথম প্রকাশ; Tichy-র প্রবন্ধ ১৯৮৫) এই ধারার পরিচিত নাম। RCS প্রতিটি version পুরোটা না রেখে আগের version থেকে পার্থক্যটুকু (delta) রাখত, ফলে জায়গা বাঁচত। কিন্তু সীমাবদ্ধতা স্পষ্ট: ইতিহাস এক মেশিনে, এক একটি ফাইল ধরে; দলের কাজ ভাগ করার ব্যবস্থা প্রায় নেই।
দ্বিতীয় প্রজন্ম — centralized VCS
Centralized VCS-এ পুরো ইতিহাস থাকে একটি কেন্দ্রীয় server-এ। প্রত্যেক developer server থেকে checkout করে ফাইলের একটি working copy আনেন, কাজ করেন, তারপর commit করে পরিবর্তন সরাসরি server-এ পাঠান। CVS (Dick Grune ১৯৮৬ সালে RCS-এর ওপর shell script হিসেবে শুরু করেন; পরে C-তে নতুন করে লেখা হয়) আর Subversion (SVN; CollabNet-এর উদ্যোগে ২০০০ সালে শুরু, ১.০ প্রকাশ ২০০৪-এ, এখন Apache Software Foundation-এর project) এই ধারার সবচেয়ে প্রচলিত দুটি। Perforce-এর মতো বাণিজ্যিক tool-ও মূলত centralized.
সুবিধা অনেক: সবাই একই জায়গা দেখেন, অনুমতি নিয়ন্ত্রণ সহজ (কে কোন ফোল্ডারে লিখতে পারবেন), আর ব্যবস্থাটা বোঝা সহজ। কিন্তু server-টি একটি single point of failure. Server বা network বন্ধ থাকলে commit করা যায় না, এমনকি পুরোনো ইতিহাস দেখার উপায়ও থাকে না। আর server-এর disk নষ্ট হলে, ভালো backup না থাকলে, পুরো ইতিহাস হারায় — কারণ developer-দের কাছে আছে শুধু সর্বশেষ ফাইল।
দুজনে একই ফাইল বদলাতে চাইলে — locking নাকি merging?
Centralized যুগে দুটি দর্শন ছিল, আর দুটিই আজও প্রাসঙ্গিক:
| Lock-modify-unlock | Copy-modify-merge | |
|---|---|---|
| নিয়ম | বদলানোর আগে ফাইলে তালা; তালা থাকা পর্যন্ত অন্যরা শুধু পড়তে পারেন | সবাই স্বাধীনভাবে কপিতে কাজ করেন; পরে tool মিলিয়ে দেয় |
| ভালো দিক | Conflict কখনো হয় না | কেউ অপেক্ষায় বসে থাকেন না; সমান্তরাল কাজ |
| খারাপ দিক | একজন তালা দিয়ে ছুটিতে গেলে সবাই আটকে; সমান্তরাল কাজ কম | একই অংশে দুজনে বদলালে conflict, মানুষকে মেলাতে হয় |
| কোথায় কাজের | যে ফাইল মেলানো যায় না: ছবি, ডিজাইন, ভিডিও, game-এর বড় asset | লেখা-ভিত্তিক ফাইল: কোড, documentation, configuration |
| উদাহরণ | RCS-এর ডিফল্ট; Subversion-এ ঐচ্ছিক lock; Git LFS-এর file locking | CVS, Subversion-এর ডিফল্ট; Git পুরোপুরি এই ধারার |
CVS-এর নামের “Concurrent” শব্দটিই এই বিপ্লবের ইঙ্গিত: একাধিক মানুষ একই ফাইলে একসাথে কাজ করতে পারবেন। অভিজ্ঞতায় দেখা গেল, কোডের বেশিরভাগ সমান্তরাল পরিবর্তন ফাইলের আলাদা অংশে পড়ে — ঠিক যেমন অংশ ১-এর সিমুলেটরে ১২ দফার ১১টিতে।
তৃতীয় প্রজন্ম — distributed VCS
Distributed VCS-এ প্রত্যেক developer-এর কাছে থাকে পুরো repository — প্রতিটি commit, প্রতিটি branch, পুরো ইতিহাস। শুরু হয় একটি clone দিয়ে: অন্য একটি repository-র সম্পূর্ণ কপি। তারপর commit হয় নিজের কম্পিউটারেই, network ছাড়া। দলের সাথে ভাগ করতে চাইলে push (নিজের commit পাঠানো) আর pull (অন্যদের commit আনা)। যে server-এ সবাই push করেন, সেটি প্রযুক্তিগতভাবে আরেকটি কপি মাত্র; দল মিলে ঠিক করে সেটিকেই “আসল” ধরা হবে। এমন অন্য জায়গার repository-কে Git-এ বলে remote.
এই ধারার আদি নাম কয়েকটি: GNU arch, Monotone, darcs, আর বাণিজ্যিক BitKeeper. ২০০৫ সালে প্রায় একসাথে জন্ম নেয় দুটি: Git আর Mercurial (Matt Mackall, command-এর নাম hg). দুটোর জন্মের পেছনে একই ঘটনা — অংশ ৫-এ সেই গল্প।
৪ · Server বন্ধ হলে কী হয় — একটি commit-এর দুই রকম যাত্রা
পার্থক্যটা সবচেয়ে পরিষ্কার হয় খারাপ দিনে। ধরুন অফিসে লোডশেডিং চলছে, generator-এ শুধু কম্পিউটার চলছে, internet নেই। নিচে একই কাজ দুই ব্যবস্থায় পাশাপাশি দেখুন — ওপরের দুই সারি centralized (Subversion-এর মতো), নিচের দুই সারি distributed (Git-এর মতো):
| Centralized: server | |
| Centralized: Rina-র কম্পিউটার | |
| Distributed: Rina-র repository | |
| Distributed: shared server |
- শুরু। Centralized-এ server-এ revision r1 থেকে r10, আর Rina-র কাছে শুধু r10-এর ফাইলগুলো। Distributed-এ Rina-র নিজের কম্পিউটারেই C1 থেকে C10 — পুরো ইতিহাস, server-এর মতোই।
- Rina একটি ফাইল বদলালেন। দুই ব্যবস্থাতেই পরিবর্তনটি এখনো শুধু তাঁর কাজের ফাইলে; কোথাও রেকর্ড হয়নি।
- Commit. Centralized-এ commit মানে network দিয়ে server-এ পাঠানো — server-এ r11 তৈরি হলো, অন্যরা update করলেই দেখবেন। Distributed-এ commit হলো Rina-র নিজের repository-তে (C11), মিলিসেকেন্ডে; server এখনো জানে না। ভাগ করা আলাদা ধাপ।
- Internet নেই, তিন ঘণ্টা। Centralized-এ Rina commit করতে পারছেন না; পুরোনো revision-এর log দেখতে বা দুটি revision তুলনা করতেও server লাগে। তিন ঘণ্টার কাজ রেকর্ডহীন পড়ে আছে। Distributed-এ তিনি C12, C13 commit করলেন, log আর diff দেখলেন — সবই নিজের কম্পিউটারে।
- Internet ফিরল। Centralized-এ Rina তিন ঘণ্টার সব পরিবর্তন একটি বড় commit (r12) হিসেবে পাঠালেন — ছোট ছোট ধাপের ইতিহাস হারাল। Distributed-এ তিনি push করলেন; C11, C12, C13 আলাদা আলাদা commit হিসেবেই server-এ পৌঁছাল।
- সবচেয়ে খারাপ দিন — server-এর disk নষ্ট। Centralized-এ developer-দের কাছে আছে শুধু সর্বশেষ ফাইল; backup না থাকলে পুরো ইতিহাস শেষ। Distributed-এ প্রতিটি clone একটি পূর্ণ backup; যেকোনো একটি থেকে নতুন server ভরা যায়। তবে সাবধান: যে commit কেউ push করেননি, সেটি শুধু তাঁর মেশিনেই আছে — distributed মানে নিয়মিত backup-এর দরকার ফুরিয়ে যাওয়া নয়।
একটি পুরো কর্মদিবসে কতটা পার্থক্য হয়? নিচের সিমুলেটরে সকাল ৯টা থেকে বিকেল ৫টা, ১০ মিনিটের ভাগে ভাগ করা। একটি “খারাপ দিন”: প্রতি ১০ মিনিটে ৮% সম্ভাবনায় server-এর বিভ্রাট শুরু হয়, চলে ১০ থেকে ৬০ মিনিট। তিনজন developer প্রত্যেকে প্রতি ৩০ মিনিটে একটি commit করতে চান (দিনে ১৬টি)। Centralized-এ সেই মুহূর্তে server না পেলে commit আটকে যায়; distributed-এ commit সবসময় নিজের কাছে হয়, আর server পাওয়া গেলেই না-পাঠানো সব commit push হয়:
// One workday (9:00-17:00) in 10-minute slots. The shared server has seeded outages.
// Each of 3 developers wants to commit every 30 minutes (16 times a day).
function mulberry32(a) { return () => { a = (a + 0x6D2B79F5) | 0; let t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; }
const rnd = mulberry32(2005), SLOTS = 48, up = [];
for (let s = 0; s < SLOTS; ) { // outage starts with 8% chance per slot
if (rnd() < 0.08) { const len = 1 + Math.floor(rnd() * 6); for (let k = 0; k < len && s < SLOTS; k++, s++) up.push(false); }
else { up.push(true); s++; }
}
const fmt = (s) => String(9 + Math.floor(s / 6)).padStart(2, "0") + ":" + (s % 6) + "0";
const down = up.map((u, s) => (u ? "" : fmt(s))).filter(Boolean);
console.log("server down in", down.length, "slots:", down.join(" "));
for (let dev = 0; dev < 3; dev++) {
let central = 0, blocked = 0, local = 0, pushed = 0, waiting = 0;
for (let s = dev; s < SLOTS; s += 3) { // dev's commit moments (offset 0/10/20 min)
local++; waiting++; // distributed: commit always works offline
if (up[s]) { central++; pushed += waiting; waiting = 0; } // push everything not yet shared
else blocked++; // centralized: no server, no commit
}
console.log("dev" + (dev + 1), "| centralized: committed", central, "blocked", blocked,
"| distributed: local", local, "pushed by 17:00", pushed, "waiting", waiting);
}আউটপুট:
server down in 18 slots: 09:30 09:40 09:50 10:00 10:20 10:30 10:40 10:50 12:30 12:40 13:40 13:50 14:00 14:10 14:30 14:40 14:50 15:00
dev1 | centralized: committed 9 blocked 7 | distributed: local 16 pushed by 17:00 16 waiting 0
dev2 | centralized: committed 10 blocked 6 | distributed: local 16 pushed by 17:00 16 waiting 0
dev3 | centralized: committed 11 blocked 5 | distributed: local 16 pushed by 17:00 16 waiting 0
এই seed-এ server ৪৮টি ভাগের ১৮টিতে বন্ধ — মোট ৩ ঘণ্টা, সত্যিই খারাপ একটি দিন। Centralized: তিনজনের ৪৮টি ইচ্ছার মধ্যে commit হয়েছে ৯ + ১০ + ১১ = ৩০টি, আটকে গেছে ৭ + ৬ + ৫ = ১৮টি। আটকে যাওয়া কাজ হারায় না — পরের commit-এ জুড়ে যায় — কিন্তু ছোট, অর্থবহ ধাপগুলোর ইতিহাস হারায়, আর সেই সময়ে কিছু ভুল হলে ফেরার জায়গা থাকে না। Distributed: প্রত্যেকে ১৬টি commit-ই করেছেন, আর দিনের শেষে সবগুলো push হয়ে গেছে (waiting 0), কারণ শেষ মুহূর্তগুলোতে server চালু ছিল। Seed বা 0.08 বদলে দেখুন: distributed-এ local commit সবসময় ১৬। এটি একটি মডেল; বাস্তবে server এত ঘন ঘন বন্ধ হয় না, কিন্তু ট্রেনে বা দুর্বল network-এ কাজের দিনে এই পার্থক্যই বড় হয়ে ওঠে।
| বিষয় | Centralized (SVN) | Distributed (Git) |
|---|---|---|
| পুরো ইতিহাস কোথায় | শুধু server-এ | প্রতিটি clone-এ |
| Commit-এ network লাগে? | হ্যাঁ | না; শুধু push/pull-এ লাগে |
| Log, diff-এর গতি | Server-এর ওপর নির্ভর | নিজের disk থেকে, খুব দ্রুত |
| Branch তৈরি | Server-এ ফোল্ডার কপির মতো; অনেক দল কম ব্যবহার করত | প্রায় খরচহীন; প্রতিদিনের অভ্যাস |
| অনুমতি নিয়ন্ত্রণ | ফোল্ডার ধরে সূক্ষ্ম নিয়ন্ত্রণ সহজ | সাধারণত পুরো repository ধরে; সূক্ষ্ম নিয়ম hosting platform দিয়ে |
| বিশাল binary ফাইল | তুলনামূলক সহজ (শুধু দরকারি অংশ নামানো যায়) | কঠিন; Git LFS-এর মতো সমাধান লাগে (পর্ব ১৯) |
৫ · Git-এর জন্ম — BitKeeper, Linus Torvalds আর ২০০৫
Linux kernel শুরু হয় ১৯৯১ সালে, Linus Torvalds-এর হাতে। প্রায় এক দশক ধরে kernel-এর পরিবর্তন আসত ইমেইলে পাঠানো patch (ফাইলের পার্থক্য) আর tarball (ফাইলের সংকলন) হিসেবে; Torvalds প্রকাশ্যে বলেছেন যে CVS-কে তিনি এই কাজের উপযুক্ত মনে করতেন না। ২০০২ সাল থেকে kernel-এর কাজ চলতে থাকে BitMover কোম্পানির distributed tool BitKeeper-এ, open-source project-গুলোর জন্য দেওয়া একটি বিনামূল্যের লাইসেন্সে। Free software আন্দোলনের অনেকে তখনই আপত্তি করেছিলেন, কারণ tool-টি নিজে open-source ছিল না।
২০০৫ সালের এপ্রিলের শুরুতে BitMover সেই বিনামূল্যের লাইসেন্স প্রত্যাহার করে। সাধারণভাবে বলা হয়, কারণটি ছিল Samba project-এর developer Andrew Tridgell-এর BitKeeper-এর protocol বিশ্লেষণ করে একটি বিকল্প tool লেখার চেষ্টা; দুই পক্ষের বিবরণে খুঁটিনাটি আলাদা। ফলে kernel-এর দলের হাতে হঠাৎ কোনো tool রইল না। Torvalds এপ্রিলের প্রথম সপ্তাহেই নিজে একটি tool লেখা শুরু করেন; কয়েক দিনের মধ্যে Git নিজের কোডই নিজে রাখতে পারছিল, আর জুন মাসে প্রকাশিত kernel ২.৬.১২ Git দিয়ে পরিচালিত হয়। ২০০৫-এর জুলাই থেকে Git-এর রক্ষণাবেক্ষণের দায়িত্ব নেন Junio Hamano, যিনি আজও Git-এর প্রধান maintainer; Git ১.০ প্রকাশ পায় ২০০৫-এর ডিসেম্বরে। প্রায় একই সময়ে, একই ঘটনার প্রতিক্রিয়ায়, Matt Mackall শুরু করেন Mercurial.
নামটি নিয়ে একটি রসিকতা প্রচলিত: ব্রিটিশ অপভাষায় “git” মানে মোটামুটি “একগুঁয়ে, অপ্রিয় লোক”, আর Torvalds বলেছেন তিনি নিজের নামেই project-এর নাম রাখেন — প্রথমে Linux, তারপর Git.
নকশার পাঁচটি লক্ষ্য
Scott Chacon ও Ben Straub-এর বিনামূল্যের বই Pro Git-এ Git-এর মূল লক্ষ্যগুলো এভাবে তালিকা করা আছে। প্রতিটি লক্ষ্য BitKeeper-এর অভিজ্ঞতা আর kernel-এর বিশাল আকার থেকে এসেছে:
⚡ গতি
হাজার হাজার patch দ্রুত প্রয়োগ করতে হবে। প্রায় সব কাজ নিজের disk-এ হয় বলে log, diff, commit কয়েক মিলিসেকেন্ডে।
speed🧱 সরল নকশা
ভেতরে মাত্র কয়েক ধরনের object (blob, tree, commit, tag), আর প্রতিটির নাম তার বিষয়বস্তুর hash.
simple design🌿 Non-linear development
হাজারো সমান্তরাল branch, ঘন ঘন merge — এটাই kernel-এর বাস্তবতা।
many parallel branches🌐 পুরোপুরি distributed
কোনো কেন্দ্রীয় server আবশ্যিক নয়; প্রত্যেকের কাছে পূর্ণ ইতিহাস।
fully distributed🏔️ বড় project সামলানো
Linux kernel-এর মতো বিশাল কোড আর দীর্ঘ ইতিহাস — গতি আর জায়গা দুই দিকেই দক্ষ।
large projectsআরেকটি লক্ষ্য Torvalds বারবার জোর দিয়ে বলেছেন: data-র অখণ্ডতা. প্রতিটি ফাইল আর commit-এর নাম তার বিষয়বস্তুর cryptographic hash (ঐতিহ্যগতভাবে SHA-1), তাই disk-এর একটি bit বদলে গেলেও Git টের পায়; নীরবে ইতিহাস বিকৃত করা কঠিন। SHA-1-এর দুর্বলতা জানা যাওয়ার পর Git-এ SHA-256 ভিত্তিক repository-র বিকল্প যোগ হয়েছে (Git ২.২৯ থেকে, শুরুতে পরীক্ষামূলক হিসেবে); লেখার সময়ে বেশিরভাগ repository এখনো SHA-1 ব্যবহার করে। নিরাপত্তার দিকটি পর্ব ৫৭-এ।
৬ · Snapshot বনাম delta — Git কীভাবে মনে রাখে
RCS আর Subversion-এর মতো অনেক পুরোনো tool প্রতিটি ফাইলের ইতিহাসকে ভাবে পরিবর্তনের তালিকা হিসেবে: “version ১, তারপর এই লাইনগুলো যোগ, তারপর এগুলো বাদ…”। Git ভাবে ভিন্নভাবে: প্রতিটি commit হলো পুরো project-এর একটি snapshot — সেই মুহূর্তে সব ফাইল দেখতে কেমন ছিল। “তাহলে তো প্রতিবার সব ফাইলের কপি — জায়গা ফুরিয়ে যাবে না?” না, কারণ যে ফাইল বদলায়নি, Git সেটি নতুন করে রাখে না; আগের কপির দিকে নির্দেশ করে।
বিয়েবাড়ির আয়োজনের তালিকার কথা ভাবুন। প্রতিদিন সন্ধ্যায় পুরো তালিকার একটি ছবি তুলে রাখছেন — রান্না, ডেকোরেশন, অতিথি, খরচ। কিন্তু ডেকোরেশনের পাতাটি তিন দিন ধরে বদলায়নি; তাই প্রতিদিন সেই পাতার নতুন ফটোকপি না করে লিখে রাখলেন, “ডেকোরেশন: সোমবারের পাতাটাই।” প্রতিটি দিনের ছবি পূর্ণ, অথচ খাতা মোটা হচ্ছে না। আর পাতাগুলো চেনা হচ্ছে তাদের বিষয়বস্তু দিয়ে — দুটি পাতার লেখা হুবহু এক হলে একই পাতা।
এই শেষ কৌশলটির নাম content-addressed storage: প্রতিটি ফাইলের বিষয়বস্তু থেকে একটি hash বানানো হয়, আর সেই hash-ই তার নাম। একই বিষয়বস্তু → একই hash → একবারই রাখা। নিচের প্রোগ্রাম একটি ছোট project-এর ৫টি version দুইভাবে রাখে: প্রতিবার পুরো ফোল্ডার কপি, আর hash-ভিত্তিক একটি snapshot store. Git ব্যবহার করে SHA-1 বা SHA-256; এখানে তার বদলে একটি সরল ৩২-bit hash (FNV-1a) — শেখার জন্য যথেষ্ট, নিরাপত্তার জন্য নয়। * চিহ্ন মানে নতুন object জমা হলো:
// Five versions of a tiny project: "copy the whole folder" vs a snapshot store.
// FNV-1a 32-bit stands in for Git's SHA-1/SHA-256 (a teaching hash, not secure).
function fnv1a(s) {
let h = 0x811c9dc5;
for (let i = 0; i < s.length; i++) { h ^= s.charCodeAt(i); h = Math.imul(h, 0x01000193) >>> 0; }
return h.toString(16).padStart(8, "0");
}
const logo = "LOGO".repeat(500); // a 2000-byte file that never changes
const versions = [
{ "logo.txt": logo, "README": "Shop ledger v1", "hisab.txt": "chal 1200\n" },
{ "logo.txt": logo, "README": "Shop ledger v1", "hisab.txt": "chal 1200\ndal 300\n" },
{ "logo.txt": logo, "README": "Shop ledger v2", "hisab.txt": "chal 1200\ndal 300\n" },
{ "logo.txt": logo, "README": "Shop ledger v2", "hisab.txt": "chal 1250\ndal 300\n" },
{ "logo.txt": logo, "README": "Shop ledger v1", "hisab.txt": "chal 1200\n" } // back to v1
];
const objects = new Map(); // hash -> content (each distinct content stored once)
let copyBytes = 0;
versions.forEach((files, i) => {
const snapshot = [];
for (const [name, text] of Object.entries(files)) {
copyBytes += text.length; // full-copy method: every file, every time
const id = fnv1a(text);
const isNew = !objects.has(id);
if (isNew) objects.set(id, text);
snapshot.push(name + ":" + id + (isNew ? "*" : ""));
}
console.log("v" + (i + 1), snapshot.join(" "));
});
let storeBytes = 0;
for (const text of objects.values()) storeBytes += text.length;
console.log("full copies :", copyBytes, "bytes");
console.log("snapshot store:", storeBytes, "bytes in", objects.size, "objects");
console.log("saved:", (100 * (1 - storeBytes / copyBytes)).toFixed(1) + "%");আউটপুট:
v1 logo.txt:181291f5* README:3b9e780b* hisab.txt:9809e08c*
v2 logo.txt:181291f5 README:3b9e780b hisab.txt:ab6e17ba*
v3 logo.txt:181291f5 README:3c9e799e* hisab.txt:ab6e17ba
v4 logo.txt:181291f5 README:3c9e799e hisab.txt:f30e5bb9*
v5 logo.txt:181291f5 README:3b9e780b hisab.txt:9809e08c
full copies : 10144 bytes
snapshot store: 2074 bytes in 6 objects
saved: 79.6%
প্রতিটি সারি একটি পূর্ণ snapshot — তিনটি ফাইলের নাম আর তাদের hash. কিন্তু * আছে মাত্র ৬ জায়গায়। ২০০০ byte-এর logo.txt একবারও বদলায়নি, তাই একবারই জমা হয়েছে; পাঁচটি version শুধু একই hash 181291f5-এর দিকে নির্দেশ করছে। v5-এ README আর হিসাব v1-এর অবস্থায় ফিরে গেছে, তাই তাদের hash-ও v1-এর সাথে হুবহু এক (3b9e780b, 9809e08c) — নতুন কিছুই জমা হয়নি। হিসাব: পুরো কপিতে ২০২৪ + ২০৩২ + ২০৩২ + ২০৩২ + ২০২৪ = ১০১৪৪ byte; snapshot store-এ ২০০০ + ১৪ + ১০ + ১৮ + ১৪ + ১৮ = ২০৭৪ byte, সাশ্রয় ৭৯.৬%. একটি কৌতূহল: 3b9e780b আর 3c9e799e প্রায় একই রকম দেখায়, কারণ দুটি README-তে শুধু শেষ অক্ষরটি আলাদা — সরল FNV-1a-র দুর্বলতা। SHA-1-এর মতো cryptographic hash-এ একটি অক্ষর বদলালেই পুরো hash সম্পূর্ণ অচেনা হয়ে যায়।
এটি ধারণা, পূর্ণ ছবি নয়। আসল Git প্রতিটি object zlib দিয়ে সংকুচিত করে, আর মাঝে মাঝে অনেক object একটি packfile-এ ভরে delta দিয়েও জায়গা বাঁচায়। অর্থাৎ Git-এর মডেল snapshot, কিন্তু disk-এ সংরক্ষণ আরও চতুর। ফোল্ডারের জন্য tree object আর commit-এর জন্য commit object কীভাবে এই hash-গুলো জুড়ে রাখে — পর্ব ৫২-এ (Git-এর ভেতরে) নিজের হাতে খুলে দেখবেন। Hash-এর সাধারণ ধারণা পড়তে চাইলে DSA কোর্সের Hash table পর্ব দেখুন।
৭ · Git আর GitHub এক নয় — tool, platform আর client
নতুনদের সবচেয়ে প্রচলিত বিভ্রান্তি: “আমি GitHub শিখছি” বলতে অনেকে আসলে Git বোঝান। পার্থক্যটা রান্না আর রেস্তোরাঁর মতো: Git হলো রান্নার পদ্ধতি আর চুলা, যা আপনার নিজের রান্নাঘরেই চলে; GitHub হলো একটি রেস্তোরাঁ-ভবন, যেখানে রান্না সবার সামনে রাখা যায়, অন্যরা মতামত দেন, অর্ডার নেওয়া হয়।
| Git | Hosting platform (GitHub, GitLab, Bitbucket) | |
|---|---|---|
| কী | একটি open-source version control program | Git repository রাখার অনলাইন সেবা, সাথে দলের কাজের সুবিধা |
| কোথায় চলে | আপনার কম্পিউটারে; internet ছাড়াও | কোম্পানির server-এ (কিছু platform নিজের server-এ বসানোও যায়) |
| কী দেয় | Commit, branch, merge, history, diff | Pull request, code review, issue, CI pipeline, wiki, অনুমতি, ওয়েব থেকে কোড দেখা |
| মালিক | একটি open-source সম্প্রদায় (লাইসেন্স GPLv2) | বাণিজ্যিক প্রতিষ্ঠান; নিয়ম আর দাম platform-ভেদে আলাদা |
| শুরু | ২০০৫ | GitHub ২০০৮; Bitbucket ২০০৮; GitLab ২০১১ |
একটি repository একসাথে কয়েকটি platform-এ রাখা যায়, বা কোনো platform ছাড়াই — একটি অফিসের server-এ বা USB drive-এ একটি সাধারণ Git repository দিয়েও দল চলতে পারে। GitHub ২০১৮ সালে Microsoft কিনে নেয়; Bitbucket শুরুতে Mercurial-ও সমর্থন করত, ২০২০ সালে সেই সমর্থন বন্ধ করে। Platform-এর বৈশিষ্ট্য আর দাম বদলাতে পারে; বিস্তারিত তাদের নিজের documentation-এ দেখুন। Platform-এর কাজের ধারা — fork, pull request, review — আসবে পর্ব ১৬-এ, আর remote-এর সাথে clone, fetch, pull, push পর্ব ১৪-এ।
Command line, GUI আর IDE
Git ব্যবহারের তিনটি প্রধান পথ:
- Command line: terminal-এ
gitলিখে। এটিই Git-এর পূর্ণ রূপ; সব command, সব option এখানে আছে, আর ইন্টারনেটের প্রায় সব সাহায্য এই ভাষায় লেখা। Terminal নতুন হলে Operating Systems কোর্সের Linux terminal পর্বটি কাজে আসবে। - GUI client: GitHub Desktop, Sourcetree, GitKraken, Fork-এর মতো প্রোগ্রাম, আর Git-এর সাথেই আসা
gitkওgit gui. Commit-এর গাছ চোখে দেখা আর ফাইলের কিছু অংশ বেছে commit করা এখানে সহজ। কিছু client বিনামূল্যের, কিছু শর্তসাপেক্ষ; লাইসেন্স দেখে নিন। - IDE-র ভেতরে: VS Code, IntelliJ IDEA, Android Studio, Visual Studio — সবগুলোতে Git-এর প্যানেল আছে: কোন ফাইল বদলেছে, পাশাপাশি diff, এক ক্লিকে commit.
আগে command line, তারপর বাটন। GUI আর IDE ভেতরে সাধারণত সেই একই Git command চালায়। Command line বুঝলে যেকোনো GUI বুঝবেন, আর কোনো বাটন অদ্ভুত কিছু করলে কেন করল তা ধরতে পারবেন। উল্টোটা সত্য নয়। এই কোর্সের সব উদাহরণ তাই command line-এ।
৮ · Git install আর প্রথমবারের setup
নিচের command-গুলো উদাহরণ; installer আর package-এর নাম সময়ের সাথে বদলাতে পারে, তাই সন্দেহ হলে git-scm.com-এর download পাতা দেখুন। আপনার OS বেছে নিন:
সবচেয়ে প্রচলিত পথ Git for Windows (gitforwindows.org). Installer-এর সাথে আসে git, একটি Bash terminal (Git Bash) আর কিছু Unix tool. Installer অনেক প্রশ্ন করে; শুরুতে বেশিরভাগ ডিফল্ট রাখলেই চলে, শুধু editor-এর প্রশ্নে যেটি চেনেন (যেমন VS Code বা Notepad) সেটি বেছে নিন। Windows-এর package manager winget থাকলে:
winget install --id Git.Git -e --source wingetঅনেক macOS-এ terminal-এ git --version লিখলেই Apple-এর Command Line Tools install করার প্রস্তাব আসে, যার সাথে Git থাকে। সরাসরি চাইলে প্রথম লাইন; আরও নতুন version চাইলে Homebrew দিয়ে দ্বিতীয় লাইন:
xcode-select --install
brew install gitDistribution-এর package manager দিয়ে। Ubuntu বা Debian-এ প্রথম লাইন, Fedora-য় দ্বিতীয় লাইন:
sudo apt install git
sudo dnf install gitInstall হলো কি না দেখতে একটি নতুন terminal খুলে version জিজ্ঞেস করুন। নিচের আউটপুট এই লেখার মেশিনে (Windows, Git ২.৫৩) চালিয়ে পাওয়া; Linux বা macOS-এ শেষের .windows.2 অংশ থাকবে না, আর নম্বরটি আপনার install অনুযায়ী আলাদা হবে:
$ git --version
git version 2.53.0.windows.2Setup না করলে কী হয়
নতুন install-এ প্রথম commit করতে গেলেই Git থেমে যায়, কারণ প্রতিটি commit-এ লেখকের নাম আর email লিখতে হয়। নিচে একটি সম্পূর্ণ খালি configuration দিয়ে চালানো আসল আউটপুট (মেশিনের নামটি … দিয়ে ঢাকা):
$ git commit -m "Add the shop ledger"
Author identity unknown
*** Please tell me who you are.
Run
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
to set your account's default identity.
Omit --global to set the identity only in this repository.
fatal: unable to auto-detect email address (got '…')Git নিজেই সমাধান বলে দিচ্ছে। আর init.defaultBranch ঠিক না করে নতুন repository বানালে Git ২.৫৩ একটি লম্বা পরামর্শ দেখায় (মাঝের কিছু লাইন বাদ):
$ git init hisab
hint: Using 'master' as the name for the initial branch. This default branch name
hint: will change to "main" in Git 3.0. To configure the initial branch name
hint: to use in all of your new repositories, which will suppress this warning,
hint: call:
hint:
hint: git config --global init.defaultBranch <name>
…
Initialized empty Git repository in …/hisab/.git/অর্থাৎ পুরোনো ডিফল্ট নাম master, আর Git-এর নিজের বার্তা অনুযায়ী ভবিষ্যতের Git ৩.০-তে ডিফল্ট হবে main. GitHub, GitLab-সহ বড় platform-গুলো নতুন repository-তে কয়েক বছর ধরেই main ব্যবহার করে, তাই এখনই main ঠিক করে নেওয়া সুবিধাজনক। এবার পুরো setup ধাপে ধাপে:
| Command | |
| ~/.gitconfig | |
| কেন |
- Version দেখা।
git version 2.53.0.windows.2এলে install ঠিক আছে। “command not found” বা “not recognized” এলে terminal বন্ধ করে নতুন করে খুলুন; তাতেও না হলে PATH-এ Git নেই। - নাম।
--globalমানে আপনার ব্যবহারকারী-অ্যাকাউন্টের সব repository-তে খাটবে; Git তা লেখে home ফোল্ডারের.gitconfigফাইলে। নাম উদ্ধৃতিচিহ্নের ভেতরে, কারণ নামে space থাকতে পারে। - Email. এটি প্রতিটি commit-এ স্থায়ীভাবে লেখা থাকে, আর repository প্রকাশ্য হলে সবাই দেখতে পান। ব্যক্তিগত email লুকাতে চাইলে hosting platform-গুলো একটি “no-reply” ঠিকানা দেয়; platform-এর সেটিং দেখুন। যে platform-এ কাজ করবেন, সেখানকার অ্যাকাউন্টের email দিলে commit আপনার profile-এর সাথে যুক্ত হয়।
- ডিফল্ট branch. এখন থেকে
git initকরা প্রতিটি নতুন repositorymainনামের branch দিয়ে শুরু হবে। আগের repository-গুলো বদলায় না। (এই সেটিং Git ২.২৮-এ যোগ হয়েছিল; তার আগের version-এ এটি কাজ করে না।) - Editor.
-mছাড়া commit করলে, বা merge-এর বার্তা লিখতে, Git একটি editor খোলে।code --waitহলো VS Code;--waitনা দিলে Git editor বন্ধ হওয়ার অপেক্ষা করে না। VS Code না থাকলেnanoবাnotepadদিতে পারেন। কিছু না দিলে সাধারণত Vim খোলে — বেরোতে Esc চেপে:q!. - লাইনের শেষ (শুধু Windows). Windows সাধারণত লাইনের শেষে CRLF ব্যবহার করে, Linux ও macOS শুধু LF.
trueমানে commit-এর সময় CRLF → LF, আর ফাইল বের করার সময় LF → CRLF; তাই repository-তে সবসময় LF থাকে। macOS/Linux-এ সাধারণতinputদেওয়া হয়, বা কিছুই না। দলের জন্য আরও নির্ভরযোগ্য পথ.gitattributesফাইল — পর্ব ১০-এ। - সব একসাথে দেখা।
--listশুধু পড়ে, কিছু বদলায় না। লক্ষ করুন, আউটপুটেinit.defaultbranchছোট হাতের অক্ষরে আসে — Git-এ section আর key-এর নামে বড়-ছোট হাতের পার্থক্য ধরা হয় না, তাই সে নিজের মতো ছোট হাতে দেখায়। নিচে আসল আউটপুট।
এই transcript-টি লেখার সময় আসল configuration না ছুঁয়ে একটি আলাদা পরীক্ষার ফাইলে চালানো হয়েছে (GIT_CONFIG_GLOBAL নামের environment variable দিয়ে Git-কে অন্য global ফাইল দেখানো যায়)। আপনি নিজের মেশিনে সাধারণভাবেই চালাবেন, নাম আর email নিজের দেবেন:
$ git config --global user.name "Rahim"
$ git config --global user.email "rahim@example.com"
$ git config --global init.defaultBranch main
$ git config --global core.editor "code --wait"
$ git config --global core.autocrlf true
$ git config --global --list
user.name=Rahim
user.email=rahim@example.com
init.defaultbranch=main
core.editor=code --wait
core.autocrlf=true
$ git config user.name
RahimSet করার command সফল হলে কিছুই ছাপে না; শেষ লাইনে একটি একক সেটিং পড়া হলো। এখন আগের ব্যর্থ commit আবার চেষ্টা করলে (লেখক আর সময় নির্দিষ্ট রাখা হয়েছে, তাই hash a8f8516; আপনার মেশিনে সময় আলাদা বলে hash-ও আলাদা হবে):
$ git init hisab
Initialized empty Git repository in …/hisab/.git/
$ cd hisab
$ printf 'chal 1200\ndal 300\n' > hisab.txt
$ git add hisab.txt
$ git commit -m "Add the shop ledger"
[main (root-commit) a8f8516] Add the shop ledger
1 file changed, 2 insertions(+)
create mode 100644 hisab.txtএবার কোনো hint নেই, branch-এর নাম main, আর commit হয়েছে। root-commit মানে এটি এই repository-র প্রথম commit, যার কোনো পূর্বসূরি নেই। init, add, commit আর এর পেছনের তিনটি এলাকা (working tree, staging area, repository) — পুরোটা পর্ব ০৮-এ। Config-এর তিনটি স্তর (system, global, local), কোনটি কাকে ছাপিয়ে যায়, আর repository-ভিত্তিক সেটিং — পর্ব ১০-এ।
তিনটি সাধারণ ভুল। (১) Email-এ টাইপো — পরে commit আপনার অ্যাকাউন্টে দেখাবে না, আর পুরোনো commit-এর লেখক বদলানো ঝামেলার। (২) অফিস আর ব্যক্তিগত project-এ একই email; প্রয়োজনে প্রতিটি repository-তে --global ছাড়া আলাদা email দেওয়া যায়। (৩) Home ফোল্ডার বা Desktop-এ ভুল করে git init — তখন পুরো home একটি repository হয়ে যায়। কোন ফোল্ডারে আছেন, pwd (বা Windows-এ cd) দিয়ে আগে দেখে নিন।
৯ · সাহায্য, প্রথম শব্দগুলো আর সামনের পথ
Git-এর সবচেয়ে নির্ভরযোগ্য সাহায্য তার নিজের ভেতরেই। git help <command> (বা git <command> --help) সেই command-এর পূর্ণ manual খোলে; Windows-এ সাধারণত browser-এ। শুধু option-গুলোর ছোট তালিকা চাইলে git <command> -h. আর সব command-এর তালিকা:
$ git help -a | head -14
See 'git help <command>' to read about a specific subcommand
Main Porcelain Commands
add Add file contents to the index
am Apply a series of patches from a mailbox
archive Create an archive of files from a named tree
backfill Download missing objects in a partial clone
bisect Use binary search to find the commit that introduced a bug
branch List, create, or delete branches
bundle Move objects and refs by archive
checkout Switch branches or restore working tree files
cherry-pick Apply the changes introduced by some existing commits
citool Graphical alternative to git-commit
clean Remove untracked files from the working tree“Porcelain” শব্দটি খেয়াল করুন। Git-এর ভাষায় মানুষের প্রতিদিনের ব্যবহারের command হলো porcelain (বাথরুমের চকচকে বাইরের অংশ), আর ভেতরের নিচু-স্তরের command হলো plumbing (দেয়ালের ভেতরের পাইপ)। তালিকার নিচে plumbing-ও আছে; পর্ব ৫২-এ সেগুলো ব্যবহার করবেন। git help -g দিলে আসে Git-এর ধারণা-নির্দেশিকার তালিকা (যেমন everyday, glossary). AI বা কোনো blog যে flag বলছে, তা সত্যিই আছে কি না যাচাইয়ের সবচেয়ে দ্রুত পথও এই manual.
চারটি শব্দ, যা সামনে প্রতিদিন লাগবে
📁 Repository
Project-এর ফাইল আর পুরো ইতিহাস। Git-এ ইতিহাস থাকে project ফোল্ডারের লুকানো .git ফোল্ডারে; ওটা মুছলে ইতিহাসও মুছে যায়।
📸 Commit
পুরো project-এর একটি snapshot, সাথে লেখক, সময়, বার্তা আর আগের commit-এর ঠিকানা। ছোট hash (যেমন a8f8516) দিয়ে চেনা যায়।
🌿 Branch
কাজের একটি আলাদা ধারা। ভেতরে আসলে একটি commit-এর দিকে নির্দেশক একটি নাম — তাই এত সস্তা।
পর্ব ১২–১৩🌐 Remote
অন্য কোথাও রাখা একই project-এর repository — সাধারণত hosting platform-এ। প্রচলিত নাম origin.
Git-এর তিনটি মডিউল — রোডম্যাপ
এই কোর্সে Git আসবে তিন ধাপে, প্রতিটি আগেরটির ওপর:
- মডিউল ২ — Git-এর মৌলিক (পর্ব ০৭–১৩): এই পর্বের পর প্রথম repository (০৮), history আর diff (০৯), .gitignore আর config (১০), ভুল শোধরানো (১১), branch (১২) আর merge ও conflict (১৩)। একা নিজের কম্পিউটারে আত্মবিশ্বাসের সাথে Git.
- মডিউল ৩ — Git দিয়ে দলগত কাজ (পর্ব ১৪–১৯): remote আর clone-push-pull, rebase, pull request আর fork, branching strategy (Git Flow, trunk-based), ভালো commit বার্তা, tag আর release, আর বড় repository.
- মডিউল ৯ — উন্নত Git আর automation (পর্ব ৫২–৫৮): Git-এর ভেতরের object, reflog দিয়ে উদ্ধার, merge-এর ভেতরের কৌশল, bisect আর blame, stash ও worktree-র মতো হাতিয়ার, নিরাপত্তা, আর continuous integration.
আরও গভীরে: Scott Chacon ও Ben Straub-এর Pro Git (দ্বিতীয় সংস্করণ ২০১৪) git-scm.com-এ বিনামূল্যে পড়া যায়, আর এর প্রথম অধ্যায়ই এই পর্বের বিষয়। ২০০৭ সালে Google-এ দেওয়া Linus Torvalds-এর একটি বক্তৃতা (ভিডিও আকারে সহজলভ্য) distributed ধারণার পক্ষে তাঁর নিজের যুক্তি তুলে ধরে — জোরালো ভাষায়, তাই সমালোচনামূলক মন নিয়ে শুনুন। Version control-এর সাধারণ তত্ত্বের জন্য Walter Tichy-র ১৯৮৫ সালের RCS প্রবন্ধ এখনো পড়ার মতো, আর Git-এর ভেতরের নকশা git help gitcore-tutorial-এ এবং এই কোর্সের পর্ব ৫২-এ।
পরীক্ষা ও ইন্টারভিউতে:
- Centralized আর distributed VCS-এর মূল পার্থক্য কী? — Centralized-এ পুরো ইতিহাস একটি server-এ, commit-এ server লাগে; distributed-এ প্রতিটি clone-এ পূর্ণ ইতিহাস, commit local, ভাগ করা push/pull দিয়ে।
- Git আর GitHub-এর পার্থক্য? — Git একটি version control tool; GitHub Git repository রাখার আর দলের কাজের (pull request, issue, CI) একটি hosting platform.
- Git কেন আর কে তৈরি করেন? — ২০০৫ সালে Linus Torvalds, Linux kernel-এর দল BitKeeper-এর বিনামূল্যের লাইসেন্স হারানোর পর; লক্ষ্য গতি, distributed কাজ আর বড় project.
- Git ইতিহাস snapshot হিসেবে রাখে নাকি delta হিসেবে? — ধারণাগতভাবে প্রতিটি commit পূর্ণ snapshot, না-বদলানো ফাইল একবারই জমা; disk-এ packfile-এর ভেতরে delta compression-ও ব্যবহার হয়।
- নতুন মেশিনে Git-এর প্রথম দুটি config কী? —
git config --global user.nameআরuser.email; না দিলে commit হয় না।
১০ · AI-এর যুগে — Git-এর পরামর্শ যাচাই করে নেওয়া
AI assistant এখন Git-এর প্রশ্নের প্রথম ঠিকানা হয়ে উঠছে, আর বেশিরভাগ সময় কাজের উত্তরই দেয়। কিন্তু Git এমন একটি tool, যেখানে একটি ভুল command কয়েক দিনের কাজ মুছে দিতে পারে। এই পর্বের বিষয়ে AI-এর পরিচিত ভুলগুলো:
| AI-এর ভুল | কীভাবে ধরবেন |
|---|---|
সতর্কতা ছাড়া git reset --hard বা git push --force বলে দেওয়া | যে command কিছু মুছতে বা ইতিহাস বদলাতে পারে, আগে একটি পরীক্ষার clone-এ চালান; পর্ব ১১ পড়ে নিন |
| নেই এমন flag বা config key বানানো | git help config বা git <command> -h-এ খুঁজুন; না পেলে বিশ্বাস নয় |
পুরোনো version-এর উত্তর (checkout সবকিছুতে, master ডিফল্ট) | git --version দেখে প্রশ্নে version লিখে দিন; Git ২.২৩ থেকে switch/restore আছে |
| Git আর GitHub গুলিয়ে ফেলা (platform-এর বাটনের কাজকে Git command বলা) | জিজ্ঞেস করুন: “এটা Git-এর command, নাকি platform-এর বৈশিষ্ট্য?” |
| ইতিহাসের খুঁটিনাটি বানানো (তারিখ, কে কী বলেছিলেন) | মূল উৎস, Git-এর নিজের documentation বা Pro Git দেখে মেলান |
| Token বা password সরাসরি remote URL-এ বা config-এ লিখতে বলা | কখনো নয়; credential manager বা SSH key ব্যবহার করুন (পর্ব ১৪, ৫৭) |
নিচের prompt-এ AI-কে নিজের মেশিনের তথ্য দেওয়া হয়েছে, আর প্রতিটি command-এর ঝুঁকি আলাদা করে বলতে বলা হয়েছে। Prompt-এ কখনো আসল token, password বা কোম্পানির গোপন URL দেবেন না।
AI-এর দেওয়া Git পরামর্শ হাতে পেলে — চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।
প্র ০১Linux kernel প্রায় দশ বছর কোনো version control ছাড়াই, শুধু ইমেইলের patch দিয়ে চলেছে। তাহলে version control কি সত্যিই অপরিহার্য?
প্রথমে খেয়াল করুন, “কোনো version control ছিল না” কথাটা পুরো সত্য নয়। ১৯৯১ থেকে ২০০২ পর্যন্ত kernel-এর জন্য কোনো সাধারণ VCS tool ব্যবহার হয়নি ঠিকই, কিন্তু একটি কঠোর প্রক্রিয়া ছিল। প্রতিটি পরিবর্তন আসত একটি patch হিসেবে — কোন ফাইলের কোন লাইন বদলাবে, তার নিখুঁত বিবরণ — সাথে লেখকের নাম আর ব্যাখ্যা। Patch পাঠানো হতো প্রকাশ্য mailing list-এ, সেখানে সবাই পড়তেন, মন্তব্য করতেন। বিভিন্ন অংশের দায়িত্বপ্রাপ্ত maintainer-রা patch বাছাই করে Torvalds-এর কাছে পাঠাতেন, আর তিনি নিজে প্রয়োগ করে নতুন release প্রকাশ করতেন। প্রতিটি release-এর tarball সংরক্ষিত থাকত। অর্থাৎ ইতিহাস, লেখক, কারণ, review — সবই ছিল, শুধু হাতে চালানো।
সমস্যা দেখা দিল আকারে। ২০০০-এর দশকের শুরুতে kernel-এ অবদানকারীর সংখ্যা দ্রুত বাড়ছিল, আর Torvalds নিজেই হয়ে উঠছিলেন সবচেয়ে বড় জট — patch-এর স্তূপ জমত, কিছু হারিয়েও যেত। BitKeeper গ্রহণের মূল কারণ ছিল এই জট খোলা: distributed tool হওয়ায় maintainer-রা নিজেদের মধ্যে পরিবর্তন আদান-প্রদান করতে পারতেন, Torvalds-কে প্রতিটি patch হাতে প্রয়োগ করতে হতো না।
এখান থেকে দুটি শিক্ষা। এক, version control-এর আসল মূল্য tool-এ নয়, শৃঙ্খলায়: প্রতিটি পরিবর্তন ছোট, ব্যাখ্যাসহ, পর্যালোচিত, আর ফেরানো যায় এমন। এই শৃঙ্খলা ইমেইল দিয়েও সম্ভব, যদি দলটি অসাধারণভাবে নিয়মনিষ্ঠ হয়। দুই, হাতে চালানো প্রক্রিয়া একটি আকারের পর ভেঙে পড়ে — ঠিক পর্ব ০২-এ দেখা software crisis-এর মতো। আকর্ষণীয় বিষয়, Git-এর নকশাতেই ইমেইল-patch ধারা রয়ে গেছে: git format-patch আর git am command দিয়ে commit-কে ইমেইলে পাঠানো ও প্রয়োগ করা যায়, আর kernel-এর দল আজও অনেকটা এভাবেই patch পর্যালোচনা করে।
মূল উপলব্ধি: Version control একটি শৃঙ্খলা — ছোট, ব্যাখ্যাসহ, ফেরানো যায় এমন পরিবর্তন; tool সেই শৃঙ্খলাকে সস্তা আর মাপযোগ্য করে।
প্র ০২Distributed VCS-এ সবার কাছে সমান পূর্ণ কপি থাকলে “আসল” কোড কোনটি? GitHub-এর যুগে কেন্দ্র কি আবার ফিরে আসেনি?
প্রযুক্তিগতভাবে distributed VCS-এ কোনো repository অন্যটির চেয়ে বিশেষ নয়। আপনার ল্যাপটপের clone আর দলের server-এর repository একই রকম; দুটো থেকেই commit, branch, ইতিহাস — সব পাওয়া যায়। তাহলে “আসল” কোনটি, তা ঠিক করে মানুষের চুক্তি, tool নয়। Linux kernel-এর ক্ষেত্রে সবাই মেনে নেন যে Torvalds-এর repository থেকে যা release হয়, সেটাই “mainline”. একটি কোম্পানিতে সাধারণত hosting platform-এর একটি repository-র main branch-কে আসল ধরা হয়, আর সেখান থেকেই production-এ যায়।
তাই একটি সত্যি পর্যবেক্ষণ: GitHub, GitLab আর Bitbucket-এর জনপ্রিয়তায় বাস্তবের কাজের ধারা আবার অনেকটা কেন্দ্রমুখী হয়েছে। Pull request, issue, review, CI, অনুমতি — এগুলো Git-এর অংশ নয়, platform-এর। Platform বন্ধ থাকলে আপনি local commit করতে পারবেন, ইতিহাস দেখতে পারবেন, কিন্তু review বা deploy আটকে যেতে পারে। বড় platform-এর বিভ্রাট হলে বিশ্বজুড়ে অনেক দলের কাজের গতি কমে যায় — এমন ঘটনা অতীতে একাধিকবার খবরে এসেছে।
তবু centralized VCS-এর যুগের সাথে পার্থক্য মৌলিক। এক, ইতিহাসের নিরাপত্তা: platform-এর data হারালেও প্রতিটি সক্রিয় developer-এর কাছে পূর্ণ ইতিহাস আছে। দুই, বিকল্পে যাওয়ার স্বাধীনতা: একটি platform-এর নিয়ম বা দাম পছন্দ না হলে পুরো ইতিহাসসহ অন্য platform-এ নিয়ে যাওয়া তুলনামূলক সহজ — শুধু একটি নতুন remote যোগ করে push. তবে issue আর pull request-এর আলোচনা Git-এ থাকে না, platform-এ থাকে; সেগুলো সরানো আলাদা ঝামেলা। তিন, অফলাইন কাজ: commit, branch, merge — সবই network ছাড়া।
অনেকে বলেন, আজকের বাস্তবতা হলো “distributed tool, centralized workflow” — tool-এর স্তরে ক্ষমতা বণ্টিত, কিন্তু দলের সমন্বয় একটি কেন্দ্রে। এটি দুর্বলতা নয়, একটি সচেতন বাছাই: সমন্বয়ের জন্য একটি কেন্দ্র সুবিধাজনক, কিন্তু সেই কেন্দ্র এখন আর একমাত্র ভরসা নয়।
মূল উপলব্ধি: “আসল” repository একটি সামাজিক চুক্তি; distributed tool কেন্দ্র মুছে দেয়নি, কেন্দ্রকে একমাত্র ব্যর্থতার বিন্দু হওয়া থেকে মুক্ত করেছে।
প্র ০৩Git যদি প্রতিটি commit-কে পূর্ণ snapshot হিসেবে ভাবে, তাহলে বিশাল ইতিহাসের repository-ও এত ছোট থাকে কীভাবে? Snapshot আর delta — কোনটি “ভালো”?
দুটি আলাদা প্রশ্ন গুলিয়ে যায়: ইতিহাসের মডেল কী, আর disk-এ সংরক্ষণ কীভাবে। Git-এর মডেলে প্রতিটি commit একটি পূর্ণ snapshot: কোন ফোল্ডারে কোন ফাইল, প্রতিটির বিষয়বস্তু কী। কিন্তু সংরক্ষণে তিনটি কৌশল একসাথে কাজ করে। প্রথমত, content-addressing: না-বদলানো ফাইল একবারই থাকে, যা অংশ ৬-এর প্রোগ্রামে দেখেছেন। দ্বিতীয়ত, প্রতিটি object zlib দিয়ে সংকুচিত। তৃতীয়ত, git gc বা push/fetch-এর সময় Git object-গুলোকে packfile-এ ভরে, যেখানে একই রকম দুটি object-এর একটিকে অন্যটির delta হিসেবে রাখা হয় — এবং মজার ব্যাপার, delta-র ভিত্তি সবসময় “আগের version” নয়; Git যেকোনো কাছাকাছি object বেছে নিতে পারে, প্রায়ই নতুনটিকে পূর্ণ রেখে পুরোনোটিকে delta বানায়, কারণ নতুনটিই বেশি পড়া হয়।
তাহলে মডেল হিসেবে snapshot কেন বেছে নেওয়া হলো? কারণ প্রতিদিনের প্রশ্নগুলো snapshot-এ সস্তা। “এই commit-এ project কেমন ছিল?” — সরাসরি পড়া যায়, শত শত delta জুড়ে পুনর্গঠন করতে হয় না। দুটি commit তুলনা করতে Git প্রথমে ফোল্ডারের hash মেলায়; hash এক হলে পুরো ফোল্ডারটাই বাদ — হাজার ফাইলের project-এ এটি বিশাল সাশ্রয়।
Delta-ভিত্তিক মডেলেরও যুক্তি আছে। Mercurial-এর revlog প্রতিটি ফাইলের ইতিহাস delta-র শিকলে রাখে, আর মাঝে মাঝে একটি পূর্ণ কপি, যাতে পুনর্গঠনের শিকল খুব লম্বা না হয়; একটি ফাইলের ইতিহাস পড়া এতে দক্ষ। অর্থাৎ প্রতিটি নকশা একটি প্রশ্নের জন্য অনুকূল।
এর একটি ব্যবহারিক পরিণতি মনে রাখুন: বড় binary ফাইল (ভিডিও, ডিজাইন) প্রতিবার সামান্য বদলালেও Git-এর কাছে সেটি নতুন একটি বড় object, আর তার delta প্রায়ই ভালো হয় না। ফলে repository দ্রুত ফুলে ওঠে। এজন্যই Git LFS-এর মতো সমাধান — পর্ব ১৯-এ।
মূল উপলব্ধি: Git-এর মডেল snapshot, সংরক্ষণ content-addressing + সংকোচন + delta; কোনো মডেল সর্বজনীনভাবে “ভালো” নয় — প্রশ্ন হলো কোন কাজটি সস্তা হওয়া দরকার।
প্র ০৪Git আর Mercurial একই বছরে, একই কারণে জন্ম নিয়েছিল। অনেকের মতে Mercurial শেখা সহজ ছিল। তবু Git কেন প্রায় সর্বজনীন হয়ে গেল?
২০০৫-এর পর কয়েক বছর দুটি tool প্রায় সমানে সমান ছিল। Mercurial Python-এ লেখা, command-এর নাম আর আচরণ Subversion ব্যবহারকারীদের কাছে পরিচিত লাগত, আর documentation-কে অনেকে বেশি বন্ধুসুলভ মনে করতেন। Git শুরুতে ছিল কঠিন: অদ্ভুত নাম, অনেক নিচু-স্তরের command, Windows-এ দুর্বল সমর্থন। Python, Mozilla-সহ বড় কিছু open-source project প্রথমে Mercurial বেছে নিয়েছিল (পরে দুটিই Git-এ সরে যায় বলে প্রকাশিত হয়েছে)।
পাল্লা ঘুরেছে প্রধানত প্রযুক্তির বাইরের কারণে। প্রথমত, Linux kernel-এর প্রভাব: পৃথিবীর অন্যতম বড় আর দৃশ্যমান open-source project Git ব্যবহার করছে — এটি নিজেই একটি বিজ্ঞাপন। দ্বিতীয়ত, এবং সম্ভবত সবচেয়ে বড় কারণ, GitHub (২০০৮)। GitHub repository রাখাকে সামাজিক করে তুলল — profile, star, fork, pull request. Developer-দের কাজের নমুনা দেখানোর জায়গা হয়ে উঠল, ফলে চাকরির বাজারেও Git জানা প্রত্যাশিত হলো। এটি একটি network effect: যত বেশি মানুষ Git-এ, তত বেশি tool, টিউটোরিয়াল আর চাকরি Git-এ, তত বেশি নতুন মানুষ Git শেখেন।
তৃতীয়ত, Git সময়ের সাথে নিজের দুর্বলতা কমিয়েছে: Git for Windows পরিণত হয়েছে, বার্তাগুলো বন্ধুসুলভ হয়েছে, আর Git ২.২৩-এ switch ও restore এসে অতিরিক্ত দায়িত্বে ভারী checkout-এর বোঝা কমিয়েছে। Developer সমীক্ষাগুলোতে (যেমন Stack Overflow-এর বার্ষিক জরিপ) কয়েক বছর ধরে উত্তরদাতাদের বিপুল সংখ্যাগরিষ্ঠ Git ব্যবহারের কথা জানিয়েছেন; সমীক্ষার নমুনা সব developer-এর প্রতিনিধি নয়, তবে প্রবণতাটি স্পষ্ট।
তবে Mercurial হারিয়ে যায়নি, আর তার ধারণা টিকে আছে। কিছু বড় প্রযুক্তি প্রতিষ্ঠান বিশাল monorepo-র জন্য Mercurial-এর ওপর ভিত্তি করে নিজস্ব tool বানানোর কথা প্রকাশ্যে লিখেছে (যেমন Meta-র Sapling, ২০২২ সালে open-source করা)। এখান থেকে software engineering-এর একটি বড় শিক্ষা: “সবচেয়ে ভালো” প্রযুক্তি সবসময় জেতে না; ecosystem, সম্প্রদায় আর সময়ও সমান গুরুত্বপূর্ণ।
মূল উপলব্ধি: Git-এর জয় শুধু প্রযুক্তিগত নয় — Linux kernel-এর প্রভাব, GitHub-এর network effect আর ধারাবাহিক উন্নতি মিলে; tool বাছাইয়ে ecosystem-ও একটি প্রকৌশলগত বিবেচনা।
প্র ০৫Locking (lock-modify-unlock) কি সত্যিই অতীতের জিনিস? কোন দলের জন্য আজও এটি সঠিক পছন্দ হতে পারে?
কোডের জগতে merging পুরোপুরি জিতেছে, কারণ কোড লেখা-ভিত্তিক আর লাইন ধরে মেলানো যায়; দুজন একই ফাইলের আলাদা function বদলালে tool নিজেই মেলায়। কিন্তু সব ফাইল এমন নয়। একটি Photoshop ফাইল, একটি 3D মডেল, একটি ভিডিও, একটি Excel workbook বা একটি game-এর level ফাইল — এগুলো binary; দুজনের পরিবর্তন লাইন ধরে মেলানোর কোনো অর্থপূর্ণ উপায় নেই। দুজন ডিজাইনার একই ছবিতে দুদিন কাজ করলে, merge-এর সময় একজনের পুরো কাজ ফেলে দিতে হয়। এখানে conflict-এর খরচ অনেক বেশি, আর locking-এর অপেক্ষার খরচ তুলনায় কম।
তাই locking আজও প্রাসঙ্গিক। Subversion-এ ঐচ্ছিক lock আছে, আর একটি ফাইলকে “lock না নিয়ে বদলানো যাবে না” বলে চিহ্নিত করা যায়। Git নিজে distributed বলে আসল locking দিতে পারে না — কারণ কোনো কেন্দ্রীয় কর্তৃপক্ষ নেই যে তালা ধরে রাখবে। এজন্য Git LFS-এ একটি file-locking ব্যবস্থা যোগ হয়েছে, যা একটি server-এর ওপর নির্ভর করে; অর্থাৎ locking চাইলেই একটি কেন্দ্রের দরকার পড়ে। Game তৈরির অনেক স্টুডিও বিশাল binary asset-এর জন্য Perforce-এর মতো centralized tool ব্যবহার করে বলে বহুল প্রচলিত — যদিও এটি প্রতিষ্ঠান-ভেদে আলাদা।
Locking-এর মানবিক দিকও আছে: তালা দিয়ে কেউ ছুটিতে গেলে কাজ থেমে যায়, তাই সাধারণত অ্যাডমিন জোর করে তালা ভাঙতে পারেন, আর দলের নিয়ম লেখা থাকে।
বাস্তবে অনেক দল মিশ্র পদ্ধতি নেয়: কোড Git-এ merge দিয়ে, বড় binary asset Git LFS-এ lock দিয়ে বা আলাদা asset-ব্যবস্থায়। Operating Systems-এর ভাষায় এটি optimistic বনাম pessimistic concurrency-র পুরোনো বিনিময়: conflict কম হলে আশাবাদী (merge), conflict ব্যয়বহুল হলে সতর্ক (lock). Database-এর lost update সমস্যাতেও একই দুই সমাধান দেখবেন।
মূল উপলব্ধি: Merging তখনই ভালো, যখন পরিবর্তন মেলানো যায় আর conflict সস্তা; মেলানো যায় না এমন ফাইলে locking আজও সঠিক — আর locking-এর জন্য একটি কেন্দ্র লাগে।
অনুশীলন
হিসাব, নকশা-সমালোচনা, আউটপুট অনুমান আর command-এর ধারা — প্রতিটির পূর্ণ উত্তর দেওয়া আছে।
-
জায়গার হিসাব: একটি project-এর ১০টি version রাখা হবে। এতে তিনটি ফাইল:
logo.png(৫০০ KB, কখনো বদলায় না),app.js(২০ KB, প্রতিটি version-এ বদলায়, আকার একই থাকে), আরguide.txt(৫ KB, শুধু version ৪ আর ৮-এ বদলায়)। (ক) প্রতিবার পুরো ফোল্ডার কপি করলে মোট কত KB? (খ) Content-addressed snapshot store-এ (না-বদলানো বিষয়বস্তু একবারই) কত KB, আর কতটি ফাইল-object? (গ) সাশ্রয় কত শতাংশ?(ক) প্রতিটি version = ৫০০ + ২০ + ৫ = ৫২৫ KB; ১০টিতে ৫২৫০ KB.
(খ)
logo.png-এর একটি বিষয়বস্তু: ৫০০ KB.app.js-এর ১০টি ভিন্ন বিষয়বস্তু: ১০ × ২০ = ২০০ KB.guide.txt: version ১–৩-এ একটি, ৪–৭-এ আরেকটি, ৮–১০-এ আরেকটি — ৩টি ভিন্ন বিষয়বস্তু, ৩ × ৫ = ১৫ KB. মোট ৫০০ + ২০০ + ১৫ = ৭১৫ KB, আর ফাইল-object ১ + ১০ + ৩ = ১৪টি.(গ) সাশ্রয় = ১ − ৭১৫ ÷ ৫২৫০ ≈ ১ − ০.১৩৬২ = প্রায় ৮৬.৪%. বাস্তবের Git-এ ফোল্ডার আর commit-এর জন্য ছোট tree ও commit object-ও লাগে, আর zlib সংকোচন ও packfile-এর delta মোট আকার আরও কমাতে পারে; তবে আগে থেকেই সংকুচিত PNG-এর মতো ফাইল খুব একটা ছোট হয় না।
-
একটি দলের পদ্ধতি সমালোচনা: একটি কাল্পনিক বিশ্ববিদ্যালয়ের ফলাফল পোর্টালের চারজনের দল এভাবে কাজ করে: প্রতিদিন সকালে team lead শেয়ার্ড ড্রাইভ থেকে পুরো project-এর zip সবাইকে ইমেইল করেন; সবাই কাজ করে সন্ধ্যায় বদলানো ফাইলগুলো ইমেইলে পাঠান; team lead হাতে কপি করে বসান আর ফোল্ডারের নাম দেন
portal_2026-03-14_final. কী কী ঝুঁকি দেখছেন, আর Git দিয়ে কীভাবে নতুন করে সাজাবেন?- Lost update: দুজন একই ফাইল বদলালে team lead যেটি পরে বসান, সেটিই থাকে; অন্যজনের কাজ নীরবে হারায়। Git-এ আলাদা লাইনের পরিবর্তন নিজে মেলে, একই লাইনে conflict জানায়।
- একজনের ওপর নির্ভরতা: team lead অসুস্থ হলে কাজ থেমে যায়, আর তাঁর হাতের ভুল কেউ ধরতে পারেন না। Git-এ প্রত্যেকে নিজে commit আর push করেন; review হয় pull request-এ (পর্ব ১৬)।
- “কেন” নেই: ফোল্ডারের নামে শুধু তারিখ; কে কী কেন বদলেছেন, তা জানা অসম্ভব। Git-এ প্রতিটি commit-এ লেখক, সময় আর বার্তা।
- দিনে একবার মেলানো: সমস্যা ধরা পড়ে দেরিতে, আর দিনের মাঝের ধাপগুলোর ইতিহাস নেই। Git-এ ছোট ছোট commit, দিনে কয়েকবার push.
- নিরাপত্তা: ইমেইলে কোড মানে অনিয়ন্ত্রিত কপি, আর ফলাফলের মতো সংবেদনশীল data ভুল করে চলে যেতে পারে। Git-এ অনুমতি-নিয়ন্ত্রিত remote, আর data repository-র বাইরে (পর্ব ১০-এর
.gitignore).
নতুন সাজানো: প্রত্যেকে Git install আর
user.name/user.emailsetup; একটি hosting platform-এ private repository; প্রত্যেকে clone করেন; প্রতিটি কাজ আলাদা branch-এ, ছোট commit, pull request-এ অন্তত একজনের review, তারপরmain-এ merge. Release-এর জন্য তারিখের ফোল্ডারের বদলে tag (পর্ব ১৮)। -
আউটপুট অনুমান করুন: একটি নতুন মেশিনে, যেখানে আগে কোনো Git config নেই, পরপর নিচের command-গুলো চালানো হলো (Git ২.৫৩)। শেষের তিনটি command কী ছাপবে?
git config --global user.name "Rahim" git config --global user.name "Rahim Uddin" git config --global user.email "rahim@example.com" git config --global init.defaultBranch main git config --global --list git init -q shop cd shop git branch --show-currentuser.name=Rahim Uddin user.email=rahim@example.com init.defaultbranch=main mainতিনটি জিনিস লক্ষ করার মতো। এক, দ্বিতীয়
user.nameপ্রথমটিকে প্রতিস্থাপন করেছে — একই key দুবার set করলে শেষ মানটিই থাকে, তালিকায় দুটি নাম আসে না। দুই,--list-এinit.defaultbranchছোট হাতে, কারণ Git key-এর নামে বড়-ছোট হাত আলাদা ধরে না। তিন,-q(quiet) দেওয়ায়git initকিছুই ছাপেনি, আর নতুন repository-র branchmain, কারণ আগেইinit.defaultBranchঠিক করা ছিল। এখনো কোনো commit নেই, তবু branch-এর নাম আছে। এই উত্তর এই লেখার মেশিনে একটি আলাদা পরীক্ষার config ফাইলে চালিয়ে মেলানো। -
Command-এর ধারা লিখুন: আপনি একটি নতুন Windows ল্যাপটপ পেয়েছেন। লক্ষ্য: Git আছে কি না দেখা, নাম “Karim” আর email “karim@example.com” দিয়ে পরিচয় ঠিক করা, নতুন repository যেন
mainদিয়ে শুরু হয়, লাইনের শেষ Windows-এর উপযোগী, সব সেটিং যাচাই, আরgit config-এর পূর্ণ manual খোলা। পরপর command-গুলো লিখুন, আর বলুন কোনটির পরে কোনো আউটপুট আসবে না।git --version git config --global user.name "Karim" git config --global user.email "karim@example.com" git config --global init.defaultBranch main git config --global core.autocrlf true git config --global --list git help configপ্রথমটি version ছাপে (না ছাপলে Git install বা PATH-এর সমস্যা)। মাঝের চারটি set করার command সফল হলে কিছুই ছাপে না।
--listচারটি সারি দেখাবে (user.name,user.email,init.defaultbranch,core.autocrlf), যদি আগে থেকে অন্য কিছু set করা না থাকে; Git for Windows-এর installer কিছু সেটিং system স্তরে লিখতে পারে, সেগুলো--global --list-এ আসে না। শেষেরটি Windows-এ সাধারণত browser-এ manual খোলে। চাইলে editor-এর জন্যcore.editor-ও যোগ করতে পারেন।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমVersion control-এর এই tool আর platform-গুলোকে প্রথম প্রকাশের সময় অনুযায়ী আগে থেকে পরে সাজান (▲▼ চেপে সরান)
- SCCS — Bell Labs-এর local VCS (১৯৭০-এর দশকের শুরু)
- RCS — Walter Tichy-র local VCS (১৯৮০-র দশকের শুরু)
- CVS — RCS-এর ওপর গড়া centralized VCS (১৯৮০-র দশকের মাঝামাঝি)
- Subversion — CVS-এর উত্তরসূরি centralized VCS
- Git ও Mercurial — distributed VCS
- GitHub — Git hosting platform
একটি দল Subversion-এর মতো centralized VCS ব্যবহার করে। অফিসের internet তিন ঘণ্টা বন্ধ। এই সময়ে একজন developer-এর পক্ষে কোনটি সাধারণত সম্ভব নয়?
- নিজের working copy-র ফাইল সম্পাদনা করা
- নিজের কম্পিউটারে প্রোগ্রাম চালিয়ে test করা
- পরিবর্তন commit করা আর পুরোনো revision-এর ইতিহাস দেখা
- একটি নতুন ফাইল তৈরি করা
Git আর GitHub-এর সম্পর্ক কোনটি সবচেয়ে সঠিকভাবে বর্ণনা করে?
- Git হলো GitHub-এর একটি ফিচার
- Git একটি version control tool; GitHub Git repository রাখার একটি hosting platform
- দুটো একই জিনিসের দুটি নাম
- GitHub-এ অ্যাকাউন্ট ছাড়া Git চালানো যায় না
একটি project-এর ৪টি version রাখা হবে। এতে একটি ৩০০ KB-এর ছবি (কখনো বদলায় না) আর একটি ১০ KB-এর কোড-ফাইল (প্রতিটি version-এ বদলায়)। Content-addressed snapshot store-এ (একই বিষয়বস্তু একবারই) মোট কত KB লাগবে, সংকোচন ছাড়া?
- ১২৪০ KB
- ৩১০ KB
- ৬৪০ KB
- ৩৪০ KB
git config --global init.defaultBranch main চালানোর পর কী ঘটে?
- এরপর git init দিয়ে তৈরি নতুন repository-র প্রথম branch হবে main; পুরোনো repository বদলায় না
- কম্পিউটারের সব repository-র master branch-এর নাম বদলে main হয়ে যায়
- GitHub অ্যাকাউন্টের ডিফল্ট branch বদলে যায়
- বর্তমান repository-তে main নামে নতুন একটি branch তৈরি হয়
একটি game স্টুডিওর ডিজাইনাররা বড় binary ছবি আর 3D মডেল ফাইলে কাজ করেন, যা লাইন ধরে মেলানো যায় না। দুজন একই ফাইল একসাথে বদলালে একজনের পুরো কাজ ফেলে দিতে হয়। কোন পদ্ধতি এই ফাইলগুলোর জন্য সবচেয়ে উপযুক্ত?
- Copy-modify-merge, কারণ এতে কেউ অপেক্ষা করেন না
- শেয়ার্ড ফোল্ডারে ফাইল রেখে শেষে যিনি save করেন তাঁরটা রাখা
- Lock-modify-unlock, যাতে একসময়ে একজনই ফাইলটি বদলাতে পারেন
- প্রতিদিন ইমেইলে ফাইল পাঠিয়ে হাতে মেলানো
২০০৫ সালে Git তৈরির সরাসরি কারণ কোনটি?
- GitHub-এর জন্য একটি নতুন version control দরকার ছিল
- Linux kernel-এর দল BitKeeper-এর বিনামূল্যের লাইসেন্স হারিয়েছিল
- Subversion-এর উন্নয়ন বন্ধ হয়ে গিয়েছিল
- Mercurial-এর একটি বিকল্প দরকার ছিল
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- Version control প্রতিটি পরিবর্তন লেখক, সময় আর কারণসহ রাখে; ফাইল কপি করে overwrite-এ কাজ নীরবে হারায়, VCS-এ মেলে বা conflict জানায়।
- Local → centralized (একটি server, commit-এ network লাগে) → distributed (প্রতিটি clone-এ পূর্ণ ইতিহাস, commit local, ভাগ push/pull দিয়ে)।
- Git-এর জন্ম ২০০৫, Linus Torvalds-এর হাতে, BitKeeper-এর লাইসেন্স হারানোর পর; লক্ষ্য গতি, সরল নকশা, সমান্তরাল branch, distributed আর বড় project.
- Git-এর মডেল snapshot: না-বদলানো বিষয়বস্তু একবারই, hash দিয়ে চেনা; disk-এ সংকোচন আর delta-ও আছে।
- Git ≠ GitHub. প্রথম দিনে:
user.name,user.email,init.defaultBranch main, editor, Windows-এcore.autocrlf; সন্দেহ হলেgit help.
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ০৮ · প্রথম Git repository — init, add, commit আর তিনটি এলাকাপরবর্তী পর্বপ্রথম commit থেকে শুরু, তিনটি এলাকার ছবিসহ।
- সফটওয়্যার ইঞ্জিনিয়ারিং ও Git · কোর্স হোম৭০টি পর্বপুরো কোর্সের রোডম্যাপ, Git-এর তিনটি মডিউলসহ।
- Operating Systems · Linux terminalপাশের ট্র্যাকGit-এর command line স্বচ্ছন্দে ব্যবহারের জন্য terminal-এর মৌলিক।
- System Design · Availability আর reliabilityগভীরে যানSingle point of failure আর replication — centralized বনাম distributed-এর আরেক দিক।
- DSA · Hash tableভিত্তিHash function কীভাবে কাজ করে — content-addressing-এর ভিত্তি।