প্রকল্প সম্পর্কে

9vcs হলো 9P (Plan 9 প্রোটোকল) এর ওপর ভিত্তি করে তৈরি একটি ভার্সন কন্ট্রোল সিস্টেম, যা লেখকের Go 9p লাইব্রেরির মাধ্যমে নির্মিত। এটি এমন একটি ছোট বিশ্বস্ত দলের জন্য তৈরি যারা কোনো হোস্টিং প্ল্যাটফর্ম ছাড়াই প্রকৃত ভার্সন কন্ট্রোল ব্যবহার করতে চায়। এখানে ইতিহাস স্ন্যাপশটের পরিবর্তে কন্টেন্ট-অ্যাড্রেসড প্যাচ (content-addressed patches) হিসেবে রাখা হয়; ডিজাইনের যৌক্তিকতার জন্য README ফাইলটি PLAN.md-এর দিকে নির্দেশ করে এবং এটি কেবল ব্যবহারিক প্রয়োগের বিষয়ে সীমাবদ্ধ থাকে। এর শব্দভাণ্ডার ইচ্ছাকৃতভাবে GitHub-এর মতো করা হয়নি: এখানে clone, push, pull, fork বা pull request নেই, এবং একটি চিট শিটের মাধ্যমে সাধারণ টার্মগুলোকে 9vcs-এর সমতুল্য টার্মে ম্যাপ করা হয়েছে। প্রয়োজনীয়তা এবং ইনস্টলেশন এর একমাত্র প্রয়োজনীয়তা হলো Go 1.26.5 বা তার পরবর্তী সংস্করণ। 9vcs এবং এটি যে 9p লাইব্রেরির ওপর ভিত্তি করে তৈরি, উভয়ই বিশুদ্ধ Go ভাষায় লেখা এবং শুধুমাত্র স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার করে; এতে কোনো ডেমন, ডেটাবেস বা বাহ্যিক পরিষেবার প্রয়োজন নেই। প্রি-বিল্ট বাইনারিগুলো Releases পেজে linux/amd64, linux/arm64, darwin/arm64 এবং darwin/amd64-এর জন্য tar.gz আর্কাইভ হিসেবে প্রকাশিত হয়, যার প্রতিটির সাথে যাচাইকরণের জন্য একটি .sha256 চেকসাম থাকে; আর্কাইভটিতে বাইনারি, LICENSE এবং README থাকে। সোর্স থেকে বিল্ড করার জন্য cmd/9vcs-এর বিপরীতে একটি মাত্র go build কমান্ড প্রয়োজন। এছাড়া কিছু ইনস্টলারও উপলব্ধ রয়েছে। একক ব্যবহারকারীর কার্যপ্রবাহ (Solo workflow) একটি ডিরেক্টরিতে init চালানোর পর, status কমান্ডটি পরিবর্তিত প্রতিটি পাথের জন্য এক লাইন করে প্রিন্ট করে, যেখানে নতুন ফাইলের জন্য A, পরিবর্তিতের জন্য M, ডিলিট করা ফাইলের জন্য D এবং অমীমাংসিত কনফ্লিক্টের জন্য U ব্যবহার করা হয়; এটি কেবল যা 'ডার্টি' (dirty) তা রিপোর্ট করে, ডিফ (diff) নয়। মুভমেন্ট বা ফাইল সরানোকে রিনেম হিসেবে ট্র্যাক করা হয় না — একটি সরানো ফাইল ডিলিট এবং অ্যাড হিসেবে প্রদর্শিত হয়, যা এর অন্তর্নিহিত প্যাচ স্টোরেজের সাথে সামঞ্জস্যপূর্ণ। diff কমান্ডটি ওয়ার্কিং ট্রিতে লাইন-লেভেলের পরিবর্তন দেখায়, অন্য কোনো পয়েন্টের সাথে ডিফ করতে পারে, অথবা ওয়ার্কিং ট্রির সাথে যুক্ত না হয়ে সরাসরি দুটি পয়েন্ট তুলনা করতে পারে। log কমান্ডটি রেকর্ড করা প্যাচগুলোকে নতুন থেকে পুরানো ক্রমে লেখক, ফিঙ্গারপ্রিন্ট বা সিগনেচার স্ট্যাটাস এবং প্রভাবিত পাথসহ তালিকাভুক্ত করে। record কমান্ডটি একটি প্যাচ তৈরি করে। এখানে কোনো স্টেজিং এরিয়া বা ইনডেক্স ধাপ নেই: ওয়ার্কিং ট্রি নিজেই স্টেজিং এরিয়া হিসেবে কাজ করে এবং record কমান্ডটি বর্তমান হেডের সাথে এর ডিফ করে। ব্রাঞ্চ এবং মার্জিং branch কমান্ডটি তালিকা দেখায়, HEAD অথবা অন্য কোনো ব্রাঞ্চ বা হ্যাশ থেকে নতুন ব্রাঞ্চ তৈরি করে এবং checkout কমান্ডটি ব্রাঞ্চ পরিবর্তন করে অথবা -b ফ্ল্যাগ দিয়ে নতুন ব্রাঞ্চ তৈরি করে সুইচ করে। মার্জিং প্রকৃত প্যাচ-গ্রাফ কনফ্লিক্ট তৈরি করে — যেমন লাইন-লেভেল ফর্ক, সাইডকার ফাইলসহ বাইনারি কনফ্লিক্ট এবং মডিফাই/ডিলিট রেস — যা সাধারণ থ্রি-ওয়ে টেক্সট ডিফের চেয়ে গভীরতর। একটি ক্লিন মার্জ record কমান্ডের মাধ্যমে সম্পন্ন হয়। কনফ্লিক্টযুক্ত মার্জের ক্ষেত্রে প্রভাবিত টেক্সট ফাইলগুলোতে ইনলাইন কনফ্লিক্ট মার্কার থাকে, আর বাইনারি কনফ্লিক্টের ক্ষেত্রে পাথ এবং ছোট হ্যাশ নামে একটি সাইডকার ফাইল তৈরি হয়; ব্যবহারকারী এটি এডিট করে তারপর রেকর্ড করেন। একটি মার্জ বাতিল (abort) করা যেতে পারে, যা ওয়ার্কিং ট্রি-কে মার্জের আগের অবস্থায় ফিরিয়ে নেয় এবং মার্জ স্টেট মুছে ফেলে, তা merge কমান্ড বা apply কমান্ড যেখান থেকেই আসুক না কেন। ইগনোর প্যাটার্ন রিপো-রুট-এ থাকা .9vcsignore ফাইলটি .gitignore-এর মতো কাজ করে এবং এটি রেকর্ড ও শেয়ার করার জন্য তৈরি। প্রতি লাইনে একটি প্যাটার্ন থাকে; খালি লাইন এবং হ্যাশ কমেন্টগুলো এড়িয়ে যাওয়া হয়। স্ল্যাশ ছাড়া প্যাটার্নগুলো যেকোনো গভীরতায় ম্যাচ করে, স্ল্যাশযুক্ত প্যাটার্নগুলো রিপো রুটের সাথে যুক্ত থাকে এবং ট্রেইলিং স্ল্যাশ কেবল প্রকৃত ডিরেক্টরির ক্ষেত্রে ম্যাচ সীমাবদ্ধ করে। বিস্ময়সূচক চিহ্ন (!) দিয়ে নেগেশন এবং ডাবল-স্টার প্যাটার্ন স্পষ্টভাবে সমর্থিত নয়। ইগনোর প্যাটার্নগুলো কেবল নতুন ফাইলগুলোকে record এবং diff থেকে দূরে রাখে, এবং পরবর্তীতে কোনো প্যাটার্ন যোগ করলে আগে থেকে রেকর্ড করা ফাইল ডিলিট হিসেবে প্রদর্শিত হয় না। দলের ব্যবহার (Team usage) প্রতিটি ইনস্টলেশন প্রথমবার ব্যবহারের সময় একটি দীর্ঘস্থায়ী Ed25519 কী-পেয়ার তৈরি করে এবং identity show কমান্ডটি ফিঙ্গারপ্রিন্ট প্রিন্ট করে, যা দলের সদস্যরা একে অপরকে অথরাইজ করার জন্য আদান-প্রদান করে। যে ব্যক্তি শেয়ারড হিস্ট্রি হোস্ট করেন তিনি একটি পোর্টে serve কমান্ডটি চালান; সার্ভারটি বর্তমান রিপোর .9vcs/authorized-peers ফাইলটি পড়ে, যেখানে প্রতি সদস্যের জন্য একটি ফিঙ্গারপ্রিন্ট এবং পারমিশন লাইন থাকে। পারমিশনগুলো হলো: read (কেবল হিস্ট্রি পুল করা), propose (রিড এবং অফার এরিয়াতে সাইন করা বান্ডেল পোস্ট করা), এবং write (ব্রাঞ্চ রেফারেন্স মুভ করা সহ সবকিছু)। এখানে কোনো add-collaborator কমান্ড নেই — এটি কেবল ওই ফাইলটি এডিট করার বিষয় — এবং ফাইলটি স্টার্টআপের সময় একবার পড়া হয়, তাই পরিবর্তনের জন্য রিস্টার্ট প্রয়োজন, যা কোনো আপস করা (compromised) কী বাতিল করার সময় গুরুত্বপূর্ণ। serve কমান্ডটি কোনো ব্যাকগ্রাউন্ড ডেমন ছাড়াই ফোরগ্রাউন্ডে চলে। নেটওয়ার্ক পুশ সেই ব্রাঞ্চটি মুভ করতে অস্বীকার করে যা সার্ভিং মেশিনে বর্তমানে চেকআউট করা আছে, তাই হোস্টের উচিত অন্য একটি ব্রাঞ্চ চেকআউট রাখা অথবা সার্ভিংয়ের জন্য সংরক্ষিত ডিরেক্টরি ব্যবহার করা। একজন নতুন সদস্য init এবং import দিয়ে শুরু করেন, যেখানে পিয়ার ফিঙ্গারপ্রিন্ট, হোস্ট, পোর্ট এবং ব্রাঞ্চের নাম দিতে হয়; import কেবল ফাস্ট-ফরোয়ার্ড এবং এটি ব্রাঞ্চ এবং এর ওপর নির্ভরশীল প্রতিটি প্যাচ ও ব্লব পুল করে। reconcile হলো চলমান সিঙ্ক কমান্ড: এটি পুল করে যদি পিয়ার এগিয়ে থাকে, পুশ করে যদি লোকাল সাইড এগিয়ে থাকে, এবং প্রকৃত বৈচিত্র্য (divergence) থাকলে যা মিসিং তা ফেচ করে এবং ব্যবহারকারীকে লোকালি চেকআউট ও মার্জ করতে বলে, তার বদলে নেটওয়ার্কের মাধ্যমে সমাধান করে না। উভয় কমান্ডই স্পষ্টভাবে পিয়ার ফিঙ্গারপ্রিন্ট পিন করতে পারে, অন্যথায় তারা লোকাল trust-on-first-use স্টোর ব্যবহার করে যা নতুন অ্যাড্রেসের জন্য একবার প্রম্পট করে, পরিচিত অ্যাড্রেসগুলো নিঃশব্দে চেক করে এবং হঠাৎ ফিঙ্গারপ্রিন্ট বদলে গেলে কঠোরভাবে প্রত্যাখ্যান করে। অফলাইন বিনিময় এবং প্রস্তাব (Proposals) বান্ডেলগুলো কোনো সার্ভার ছাড়াই পরিবর্তনগুলো স্থানান্তর করে: export কমান্ডটি ইমেল, চ্যাট বা রিমুভেবল মিডিয়ার জন্য একটি সাইন করা বান্ডেল ফাইলে লেখে, এবং প্রাপক bundle show (সাইনার, মেসেজ, প্যাচ) দিয়ে এটি পরিদর্শন করেন, সিগনেচার যাচাই এবং লোকালি স্টোর করার জন্য import করেন (যা কোনো রেফারেন্স মুভ করে না), diff দিয়ে রিভিউ করেন এবং তারপর apply ও record করেন। যাদের কেবল propose পারমিশন আছে তারা offer ব্যবহার করে সরাসরি জমা দিতে পারেন, যা মেইনটেইনারের সার্ভারে একটি সাইন করা বান্ডেল পোস্ট করে; মেইনটেইনার পেন্ডিং অফারগুলোর তালিকা দেখেন, ফেচ করার জন্য একটি apply করেন, যাচাই করে লোকালি স্টোর করেন, apply দিয়ে ইন্টিগ্রেট করেন এবং কিউ থেকে সরিয়ে ফেলেন। যেহেতু অফারগুলো কেবল লাইভ সার্ভার নেমস্পেসের ভেতরে থাকে, তাই মেইনটেইনারকে তার নিজস্ব serve ইনস্ট্যান্সের সাথে কানেক্ট হতে হয় এবং authorized-peers ফাইলে তার নিজস্ব ফিঙ্গারপ্রিন্টও রাখতে হয়। 9sh এবং নেমস্পেস হ্যান্ডলিং সাধারণত রিপোটি বর্তমান ডিরেক্টরি থেকে উপরের দিকে সার্চ করে খুঁজে পাওয়া যায়, যেমনটি git-এ হয়। 9sh (একটি Plan 9 স্টাইল শেল)-এর ভেতরে, কমান্ডের নামের আগে -C ফ্ল্যাগটি দ্বিতীয় একটি পথ প্রদান করে: এটি প্রথমে 9sh নেমস্পেসের বিপরীতে পাথটি চেষ্টা করে — local-এর অধীনে একটি রিলেটিভ পাথ, অথবা একটি অ্যাবসলিউট পাথ যা 9sh-এর সাথে যুক্ত যেকোনো কিছু হতে পারে — এরপর এটি লিটারেল OS পাথে ফিরে যায়। 9sh সেশনের বাইরে এই ফ্ল্যাগটি git -C এর মতো কাজ করে। রিকভারি ডকুমেন্ট করা রিকভারি পাথগুলোর মধ্যে রয়েছে মার্জ বা apply বাতিল করা, আনকমিটেড পরিবর্তনগুলো রেকর্ড করা বা ম্যানুয়ালি মুছে ফেলা যা চেকআউট, মার্জ বা apply-কে বাধা দেয়, restore কমান্ডের মাধ্যমে নির্দিষ্ট পাথগুলোকে হেডের রেকর্ড করা অবস্থায় ফিরিয়ে আনা (যে পাথের কোনো রেকর্ড নেই তা রিমুভ করা হয়, তাই রিনেম রিভার্ট করতে উভয় পাথের নাম দিতে হয়), এবং বৈধভাবে পরিবর্তিত পিয়ার ফিঙ্গারপ্রিন্ট পুনরায় পিন করা। প্রকল্পের অবস্থা (Project status) README-তে দলের সাথে 9vcs ব্যবহার করা এবং টুলটি নিজে ডেভেলপ করার মধ্যে পার্থক্য করা হয়েছে। ডেভেলপমেন্ট ট্রাঙ্ক-বেসড ডেভেলপমেন্ট অনুসরণ করে যেখানে স্বল্পস্থায়ী ব্রাঞ্চ, একটি প্রটেক্টেড মাস্টার (যেখানে কেউ সরাসরি পুশ করে না), এবং মার্জ করার আগে বিল্ড, vet, gofmt এবং রেস-এনাবলড টেস্ট কভার করা CI থাকে; এখানে কেবল স্কোয়াশ-মার্জ এবং স্বয়ংক্রিয় ব্রাঞ্চ ডিলিট করা হয়। ভার্সনিং রিলিজের জন্য semver অনুসরণ করে, যা বর্তমানে v0.x রেঞ্জে আছে। v1.0.0-এর নিচে অন-ডিস্ক প্যাচ এবং বান্ডেল ফরম্যাটের কোনো সামঞ্জস্যতার প্রতিশ্রুতি নেই, যা মাইগ্রেশন পাথ ছাড়াই পরিবর্তিত হতে পারে; v1.0.0 থেকে রিলিজ করা ফরম্যাটের যেকোনো প্যাচ বা বান্ডেল ডিকোডযোগ্য থাকবে বলে জানানো হয়েছে, এবং ভবিষ্যতের অসামঞ্জস্যপূর্ণ পরিবর্তনগুলো রিয়েল ভার্সন ডিসপ্যাচ এবং মাইগ্রেশন টুলিংয়ের মাধ্যমে হ্যান্ডেল করা হবে। একটি চেঞ্জলগ প্রতিটি রিলিজের বৈশিষ্ট্যগুলো রেকর্ড করে।