عن المشروع
9vcs هو نظام للتحكم في الإصدارات مبني على 9P، وهو بروتوكول Plan 9، عبر مكتبة Go 9p الخاصة بالمؤلف. يستهدف النظام فريقاً صغيراً موثوقاً يرغب في تحكم حقيقي في الإصدارات دون الحاجة إلى منصة استضافة. يتم الاحتفاظ بالسجل كمجموعة من الـ patches المعنونة بالمحتوى بدلاً من اللقطات (snapshots)؛ ويشير ملف README إلى ملف PLAN.md لمعرفة الأساس المنطقي للتصميم، بينما يركز هو على الاستخدام العملي. المصطلحات المستخدمة ليست مصممة على نمط GitHub: فلا يوجد clone أو push أو pull أو fork أو pull request، وتوجد ورقة غش (cheat sheet) تربط المصطلحات المعتادة بما يعادلها في 9vcs.
المتطلبات والتثبيت
المتطلب الوحيد هو Go 1.26.5 أو إصدار أحدث. كل من 9vcs ومكتبة 9p التي يعتمد عليها مكتوبان بلغة Go نقية باستخدام المكتبة القياسية فقط، دون وجود daemon أو قاعدة بيانات أو خدمات خارجية. يتم نشر الملفات الثنائية مسبقة البناء في صفحة Releases كأرشيفات tar.gz لأنظمة linux/amd64 و linux/arm64 و darwin/arm64 و darwin/amd64، مع وجود checksum من نوع .sha256 للتحقق؛ يحتوي الأرشيف على الملف الثنائي و LICENSE و README. يتم البناء من المصدر عبر أمر go build واحد ضد cmd/9vcs. وبدلاً من ذلك، تتوفر بعض أدوات التثبيت.
سير العمل الفردي
بعد تشغيل init في دليل ما، يقوم الأمر status بطباعة سطر واحد لكل مسار تم تغييره باستخدام A للملفات الجديدة، و M للمعدلة، و D للمحذوفة، و U للنزاعات غير المحلولة؛ حيث يبلغ عما هو "متسخ" (dirty) فقط، وليس الفرق (diff). لا يتم تتبع النقل كعمليات إعادة تسمية — حيث يظهر الملف المنقول كعملية حذف متبوعة بإضافة، وهو ما يتوافق مع كيفية تخزين الـ patch الأساسي له. يعرض diff التغييرات على مستوى السطر في شجرة العمل، ويمكنه إجراء diff مقابل نقطة أخرى، أو مقارنة نقطتين مباشرة دون إشراك شجرة العمل. يسرد log الـ patches المسجلة من الأحدث إلى الأقدم مع المؤلف، والبصمة أو حالة التوقيع، والمسارات المتأثرة. يقوم record بإنشاء patch. لا توجد منطقة انتظار (staging area) أو خطوة فهرسة: شجرة العمل نفسها هي منطقة الانتظار، ويقوم record بمقارنتها مع الـ head الحالي.
الفروع والدمج
يقوم branch بسرد الفروع، أو إنشائها من HEAD أو من فرع آخر أو hash، بينما يقوم checkout بالتبديل أو الإنشاء والتبديل باستخدام علم -b. ينتج عن الدمج نزاعات حقيقية في رسم بياني للـ patches — تفرعات على مستوى السطر، ونزاعات ثنائية مع ملف sidecar للمقارنة، وتضارب بين التعديل والحذف — بدلاً من مجرد diff نصي بسيط ثلاثي الاتجاهات. يتم إكمال الدمج النظيف باستخدام record. أما الدمج المتضارب فيترك علامات نزاع مضمنة في الملفات النصية المتأثرة، بينما تحصل النزاعات الثنائية على ملف sidecar مسمى حسب المسار و hash قصير للمقارنة؛ يقوم المستخدم بالتعديل ثم التسجيل. يمكن إلغاء الدمج، مما يعيد شجرة العمل تماماً إلى حالتها ما قبل الدمج ويمسح حالة الدمج، سواء كان الدمج ناتجاً عن أمر merge أو عن apply.
أنماط التجاهل
يعمل ملف .9vcsignore في جذر المستودع مثل .gitignore ويهدف إلى تسجيله ومشاركته. نمط واحد لكل سطر؛ يتم تخطي السطور الفارغة والتعليقات التي تبدأ بـ hash. الأنماط التي لا تحتوي على slash تطابق في أي عمق، والأنماط التي تحتوي على slash تكون مرتبطة بجذر المستودع، والـ slash النهائي يقصر المطابقة على دليل حقيقي. النفي باستخدام علامة التعجب وأنماط النجمة المزدوجة غير مدعومة صراحة. تحافظ أنماط التجاهل فقط على الملفات الجديدة خارج record و diff، وإضافة نمط لاحقاً لا تجعل الملف المسجل مسبقاً يظهر كمحذوف.
استخدام الفريق
ينشئ كل تثبيت زوج مفاتيح Ed25519 طويل الأمد عند الاستخدام الأول، ويطبع identity البصمة التي يتبادلها الزملاء خارج النطاق لتفويض بعضهم البعض. يقوم الشخص الذي يستضيف السجل المشترك بتشغيل serve على منفذ؛ يقرأ الخادم ملف .9vcs/authorized-peers في المستودع الحالي، سطر واحد لكل زميل يحتوي على البصمة والصلاحية، حيث تكون الصلاحيات: read (سحب السجل فقط)، propose (القراءة بالإضافة إلى نشر bundle موقع إلى منطقة العروض)، و write (كل شيء، بما في ذلك نقل مرجع الفرع). لا يوجد أمر add-collaborator — بل يتم الأمر بمجرد تحرير ذلك الملف — ويتم قراءة الملف مرة واحدة عند بدء التشغيل، لذا تتطلب التغييرات إعادة تشغيل، وهو أمر مهم عند إلغاء مفتاح قد يكون مخترقاً.
يعمل serve في المقدمة دون daemon في الخلفية. يرفض الـ push الشبكي نقل الفرع الذي تم عمل checkout له حالياً على الجهاز المضيف، لذا يجب على المضيف إبقاء فرع مختلف في حالة checkout أو استخدام دليل مخصص للاستضافة. يبدأ الزميل الجديد بـ init و import، مع تمرير بصمة النظير والمضيف والمنفذ بالإضافة إلى اسم الفرع؛ يكون import بنظام fast-forward فقط ويسحب الفرع وكل patch و blob يعتمد عليهما بشكل انتقالي. reconcile هو أمر المزامنة المستمر: يقوم بالسحب إذا كان النظير متقدماً، ويدفع إذا كان الجانب المحلي متقدماً، وفي حالة التباعد الحقيقي يجلب ما هو مفقود ويطلب من المستخدم عمل checkout والدمج محلياً بدلاً من الحل عبر الشبكة. يمكن لكلا الأمرين تثبيت بصمة النظير صراحة، وإلا فإنهما يستخدمان مخزن trust-on-first-use محلي يطلب البصمة مرة واحدة للعنوان الجديد، ويتحقق من العناوين المعروفة بصمت، ويرفض بصوت عالٍ أي بصمة تتغير فجأة.
التبادل غير المتصل والمقترحات
تنقل الـ Bundles التغييرات دون الحاجة إلى خادم يعمل: يقوم export بكتابة bundle موقع إلى ملف للبريد الإلكتروني أو الدردشة أو الوسائط القابلة للإزالة، ويقوم المستلم بفحصه باستخدام bundle show (الموقع، الرسالة، الـ patches)، ويقوم باستيراده للتحقق من التوقيع وتخزينه محلياً دون لمس أي مرجع، ثم يراجعه باستخدام diff، وبعد ذلك يقوم بتطبيقه وتسجيله. لا يقوم import أبداً بنقل مرجع بمفرده. يمكن للنظراء الذين لديهم صلاحية propose فقط التقديم مباشرة باستخدام offer، والذي ينشر bundle موقعاً إلى خادم المسؤول؛ يقوم المسؤول بسرد العروض المعلقة، وتطبيق أحدها للجلب والتحقق والتخزين محلياً، ودمجه باستخدام apply، ثم إزالته من القائمة. ولأن العروض توجد فقط داخل نطاق الخادم المباشر، يتصل المسؤول بنسخة serve الخاصة به وبالتالي يحتاج إلى بصمته الخاصة في ملف authorized-peers أيضاً.
نوافذ إلى 9sh ومعالجة namespace
عادة ما يتم حل المستودع من خلال الصعود من الدليل الحالي، مثل git. داخل 9sh، وهي shell بنمط Plan 9، يوفر العلم -C الموضوع قبل اسم الأمر مساراً ثانياً: يحاول مطابقة المسار مقابل namespace الخاص بـ 9sh أولاً — مسار نسبي تحت local، أو مسار مطلق قد يتم حله إلى أي شيء ربطه 9sh — قبل العودة إلى مسار OS حرفي. خارج جلسة 9sh، يتصرف العلم مثل git -C.
الاستعادة
تغطي مسارات الاستعادة الموثقة إلغاء merge أو apply، وتسجيل أو التخلص يدوياً من التغييرات غير الملتزم بها التي تعيق checkout أو merge أو apply، واستعادة المسارات الفردية إلى حالتها المسجلة عند head باستخدام restore (المسار الذي ليس له حالة مسجلة يتم إزالته، لذا فإن التراجع عن إعادة التسمية يعني تسمية كلا المسارين)، وإعادة تثبيت بصمة نظير تغيرت بشكل مشروع.
حالة المشروع
يميز ملف README بين استخدام 9vcs مع فريق وبين تطوير الأداة نفسها، والتي تتبع تطوير trunk-based مع فروع قصيرة العمر، و master محمي لا يدفع إليه أحد مباشرة، و CI يغطي build و vet و gofmt واختبارات race-enabled قبل الدمج، وعمليات دمج squash-only وحذف تلقائي للفروع. يتبع الإصدار semver للإصدارات، وهو حالياً في نطاق v0.x. تحت v1.0.0 لا يوجد وعد بالتوافق لتنسيق الـ patch والـ bundle على القرص، والتي قد تتغير في مكانها دون مسار هجرة؛ ومن v1.0.0 فصاعداً، يُذكر أن أي patch أو bundle تم تسجيله بتنسيق إصدار سيظل قابلاً لفك التشفير، مع معالجة التغييرات المستقبلية غير المتوافقة عبر توزيع الإصدارات وأدوات الهجرة المتاحة. يسجل changelog ما يتم شحنه في كل إصدار.
Comments
0 Rating appears after 10 ratings
Sign in to join the discussion.