تحويل الملفات صديق لنظام التحكم في الإصدارات

عندما يخزن فريق التطوير الوثائق أو الأصول التصميمية أو ملفات البيانات جنبًا إلى جنب مع شفرة المصدر، يمكن لاختيار صيغة الملف أن يُحدِّد ما إذا كان نظام التحكم في الإصدارات سهل الاستخدام أم لا. التحويل السيئ قد يضيف حجمًا كبيرًا للمستودع، يُعقّد مخرجات diff، ويجعل عمليات البناء الآلية هشة. تستعرض هذه المقالة الاعتبارات التقنية التي تُتيح لك تحويل الملفات دون التضحية بسجل نظيف وإمكانية إعادة الإنتاج التي يوفرها Git. الإرشادات مستندة إلى سير عمل واقعي وتفترض أنك تستخدم محوّل سحابي مثل convertise.app عندما تحتاج إلى تحويل سريع يراعي الخصوصية.


لماذا تتعارض التحويلات التقليدية مع Git

يتفوّق Git في تتبع تغيّر النص العادي سطرًا بسطر. أما الكائنات الثنائية (binary blobs) فتُخزن كلقطات غير شفافة؛ أي تغيير يُجبر على إعادة رفع الملف كاملًا، ما يَزيد من حجم المستودع. علاوةً على ذلك، تُنتج العديد من خطوط تحويل البيانات مخرجات غير حتمية—طوابع زمنية، GUIDs، أو بيانات وصفية مدمجة تختلف في كل تشغيل، ما يتسبب في إيجابيات كاذبة في git diff ويصعّب حل تعارضات الدمج. الجمع بين الملفات الثنائية الكبيرة وعدم الحتمية يَستنزف بسرعة الفائدة من وجود مصدر واحد للحقائق.

تُعالج سير عمل التحويل الصديق لنظام التحكم في الإصدارات ثلاث مشكلات أساسية:

  1. انتفاخ الحجم – تجنّب تخزين ميغابايتات من الأصول المُولّدة في المستودع.
  2. غموض الفروقات – الحفاظ على المخرجات بصيغة يستطيع Git إظهار فروق ذات معنى فيها.
  3. قابلية إعادة الإنتاج – ضمان أن المصدر نفسه دائمًا ينتج مخرجات متطابقة، بحيث تبقى خطوط CI حتمية.

اختيار صيغ جاهزة للتحويل مبكرًا

أكثر التدابير فعالية هو اختيار صيغة الهدف التي تتماشى مع نقاط قوة Git. إليك أكثر أزواج الصيغ شيوعًا ولماذا تُهم:

  • Markdown → HTML / PDF – Markdown نص عادي؛ HTML لا يزال نصًا، لذا يعمل diff بشكل جيد. عندما يلزم PDF، أنشئه من خط أنابيب LaTeX حتمي يُزيل الطوابع الزمنية.
  • SVG → PNG – SVG متجهي وقابل للمقارنة. حوِّله إلى PNG فقط للتوزيع النهائي؛ احتفظ بـ SVG في المستودع لتاريخ الإصدارات.
  • CSV → Parquet – احفظ CSV للمراجعة البشرية؛ استخدم خطوة تلقائية لإنتاج Parquet للتحليل. ملفات Parquet ثنائية، لذا يجب أن تُوضع في مخزن بيانات (data‑lake) وليس في المستودع.
  • مصدر التصميم (Figma، Sketch) → PNG / PDF – احتفظ بملفات المصدر الأصلية (غالبًا ما تكون ثنائية لكنها مُجمَّعة في مشروع يُتحكم فيه بالإصدار). صدرها فقط عند النشر، وخزن الصادرات في مخزن قطع منفصل.

عند حدوث تحويل ينتج ملفًا ثنائيًا (مثال: PDF مُصنَّف)، خزن المصدر (LaTeX، Markdown، SVG) في Git وتعامل مع الثنائي كقطعة مشتقة. يَحل هذا الفصل كلًا من مشكلتي الحجم والفروقات.


التحويل الحتمي: القضاء على التغيّرات المخفية

حتى إذا كان من الضروري أن يبقى ملف ثنائي داخل المستودع، يمكنك جعل عملية التحويل قابلة لإعادة الإنتاج. اتبع الخطوات التالية:

  1. إزالة الطوابع الزمنية – معظم المحوّلات تُدمج التاريخ الحالي، ما يتغيّر في كل تشغيل. استخدم سكريبت ما بعد المعالجة (exiftool -AllDates= ...) لمسحها.
  2. تطبيع ترتيب البيانات الوصفية – بعض الأدوات تكتب مداخل القاموس بترتيب غير حتمي. حدّد علمًا يفرض ترتيبًا ثابتًا إن كان المتحوّل يدعمه، أو مرّر النتيجة عبر مُسلسل ثابت (jq -S للـ JSON، xsltproc للـ XML).
  3. تثبيت إعدادات الضغط – اختر خوارزمية ضغط خالية من الفقد وحتمية (مثال: zlib مع بذرة ثابتة). تجنّب الإعدادات التي تشمل بذور عشوائية.
  4. التحكم في نهايات السطور – طبّق LF (\n) على الدوام؛ نهايات سطر Windows (\r\n) تُعطِّل الـ diffs.
  5. استخدام بيئة قابلة لإعادة الإنتاج – نفّذ التحويل داخل حاوية Docker تُثبّت جميع إصدارات المكتبات. هذا يُزيل اختلافات “يعمل على جهازي”.

بجعل خط الأنابيب التحويلي يُشبه الدالة النقية، ستحصل على قطعة مخرجة لها نفس التجزئة (hash) في كل مرة تُشغلها على نفس المصدر، ما يتيح git diff --binary موثوقًا وتخزينًا مؤقتًا (caching) سهلًا في CI.


دمج التحويل في سير عمل Git

هناك نمطان شائعان لدمج خطوات التحويل:

1. توليد عبر hook قبل الالتزام (Pre‑commit Hook)

يمكن لــ hook قبل الالتزام تشغيل المحوّل على الملفات المتدرجة قبل أن تُلتزم. يكتب الـ hook القطعة المُشتقة مرة أخرى إلى الفهرس، ما يضمن أن المستودع دائمًا يحتوي على أحدث تحويل. مثال بلغة Bash:

#!/usr/bin/env bash
# Hook قبل الالتزام: توليد ملفات PDF من Markdown
files=$(git diff --cached --name-only --diff-filter=ACM | grep '\.md$')
for f in $files; do
  out=${f%.md}.pdf
  curl -X POST -F "file=@$f" https://api.convertise.app/convert -F "target=pdf" -o "$out"
  # إزالة الطوابع الزمنية لجعل الملف حتميًا
  exiftool -AllDates= "$out" -overwrite_original
  git add "$out"
done

يُجعل الـ hook عملية التحويل آلية ويضمن أن كل التزام يحتوي على ملف ثنائي متسق.

2. قطع بناء في CI فقط (CI‑Only Build Artifacts)

عند تكون الملفات الثنائية كبيرة، غالبًا ما يكون من الأفضل توليدها على خادم CI ودفعها إلى مخزن قطع (artifact repository) مثل GitHub Packages أو Artifactory. يبقى المصدر داخل Git، وتُستورد الإصدارات الملفات المولدة من مخزن القطع. يَمنع هذا النمط انتفاخ المستودع مع الاحتفاظ بإمكانية توفير أصول جاهزة للمستهلكين النهائيين.


إدارة الملفات الثنائية الكبيرة باستخدام Git LFS

إذا اضطررت لإصدار أصول كبيرة—صور عالية الدقة، ملفات PDF مُجمَّعة لكتاب، أو معاينات نماذج ثلاثية الأبعاد—فـ Git LFS (Large File Storage) هو الحل الشائع. مفتاح النجاح هو:

  • تتبع الملفات الثنائية الضرورية فقط. احتفظ بملفات المصدر القابلة للتحويل في المستودع الرئيسي؛ يجب أن يخزن LFS الناتج النهائي.
  • فرض اتفاقية تسمية (*.pdf.lfs، *.png.lfs) حتى يعرف المطوِّرون أي ملفات تُدار عبر LFS.
  • تحديد حد للحجم في .gitattributes (مثال: *.pdf filter=lfs diff=lfs merge=lfs -text) لتجنب الالتزام غير المقصود بملفات ضخمة مباشرة.

عند الجمع مع التحويل الحتمي، يخزن Git LFS نسخة واحدة فقط لكل نسخة، وتشارك المخرجات المتطابقة عبر الفروع نفس كائن LFS، ما يُوفّر عرض النطاق الترددي.


أتمتة باستخدام hooks ما قبل الالتزام وما قبل الدفع (Pre‑commit & Pre‑push)

إلى جانب hook التوليد الأساسي، يمكنك إضافة خطوات تحقق لالتقاط الانحرافات مبكرًا:

  • التحقق من المجموع الاختباري (checksum) – بعد التحويل، احسب تجزئة SHA‑256 وقارنها بالتي مخزَّنة في ملف .checksums. إذا اختلفت، فالتحويل غير حتمي.
  • التحقق من المخطط (schema validation) – لملفات البيانات (CSV → Parquet)، استخدم مخطط JSON أو تعريف Avro لضمان توافق الأعمدة مع الأنواع المتوقعة.
  • فحص الوصولية (accessibility check) – شغّل أداة a11y تلقائية على ملفات PDF أو HTML التي تم توليدها للتأكد من أن التحويل حافظ على النص البديل (alt‑text) وهيكل العناوين.

تُنفّذ هذه الفحوص محليًا، ما يُقدّم ملاحظات فورية قبل وصول أي كود إلى المستودع المركزي.


حفظ البيانات الوصفية والأصلية (Metadata & Provenance)

حتى وإن كان الملف الثنائي غير قابل للمقارنة، يمكنك الاحتفاظ بمعلومات الأصل الحيوية في ملف جانبي. احفظ ملف JSON manifest بجوار كل قطعة مُولدة:

{
  "source": "docs/chapter1.md",
  "converter": "convertise.app",
  "timestamp": "2026-05-24T12:34:56Z",
  "options": {
    "pdfVersion": "1.7",
    "embedFonts": true
  },
  "hash": "a3f5c2..."
}

الـ manifest نص عادي، مُصدَّر بالكامل، ويمكن أن تُستعمله خطوط CI للتحقق من أن الثنائي يطابق أصله المعلن.


اختبار دقة التحويل

يتضمن سير العمل المتين اختبارات انحدار تُقارن القطع الثنائية الجديدة بقاعدة مرجعية معروفة. نظرًا لأن الفروقات الثنائية صاخبة، استعمل مزيجًا من:

  • مقارنة صورة‑صورة بحدّ تسامح (compare -metric RMSE).
  • مقارنة بنية PDF عبر diff-pdf --output-diff لتسليط الضوء على الفروقات البصرية.
  • تحقق من استخراج النص—شغّل OCR على PDF وقارن النص المستخرج بالمصدر.

أتمت هذه الفحوص في مهمة GitHub Actions تُفشل الـ PR إذا تجاوز أي انحراف الحد المسموح به.


دراسة حالة مصغرة: موقع توثيقي تقني

تحافظ فرقة برمجيات على موقع توثيق عام يُبنى بـ Hugo. تُكتب الوثائق المصدرية بـ Markdown؛ يُقدَّم الموقع أيضًا كدليل PDF قابل للتحميل. كان سير العمل الأولي يخزن ملفات PDF مباشرةً في المستودع. مع الوقت، ارتفع حجم المستودع إلى 1.5 GB، واشتكى المطورون من تعارضات الدمج في ملفات PDF.

خطوات الحل:

  1. الاحتفاظ بملفات .md فقط في المستودع.
  2. إضافة hook قبل الالتزام يستدعي convertise.app لتوليد PDF من كل ملف Markdown، يُزيل الطوابع الزمنية، ويكتب تجزئة SHA‑256 إلى ملف .md5 مرافق.
  3. ضبط Git LFS لتخزين ملفات PDF (*.pdf filter=lfs).
  4. إعداد مهمة CI تُعيد تنفيذ التحويل، تتحقق من تطابق التجزئة مع الـ .md5 الملتزم، وتنشر ملفات PDF إلى دلو S3.
  5. يسحب الموقع ملفات PDF من S3 أثناء عملية البناء.

النتيجة: انخفض حجم المستودع بنسبة 78 %، عادت الفروقات إلى أن تكون ذات معنى، وأصبح توليد PDF قابلًا للإعادة بالكامل، مما أزِل “انجراف PDF” غير المقصود بين الفروع.


ملخص لأفضل الممارسات

  • خزن الصيغ الصديقة للمصدر (Markdown، SVG، CSV) في Git؛ اعتبر الثنائيات كقطع مشتقة.
  • اجعل التحويلات حتمية عبر إزالة الطوابع الزمنية، تثبيت الضغط، واستخدام بيئات حاوية.
  • أوتوماتيكيًا: استخدم hooks ما قبل الالتزام للقطع الصغيرة أو خطوط CI للقطع الكبيرة.
  • استفد من Git LFS فقط للثنائيات الضرورية وحافظ على تسمية واضحة.
  • احفظ الأصل في ملفات JSON جانبية لضمان إمكانية التدقيق دون إغراق المستودع.
  • تحقق بانتظام عبر فحوص المجموع الاختباري، المخطط، واختبارات الانحدار البصرية.

من خلال توافق اختيارات التحويل مع نقاط قوة نظام التحكم في الإصدارات، تستطيع الفرق إبقاء مستودعاتها خفيفة، الحفاظ على تاريخ واضح، وتوفير أصول ثنائية عالية الجودة عند الحاجة. تعمل هذه الإستراتيجية على حد سواء مع المشاريع المركزية على الكود ومواقع الوثائق المحتوية على محتوى غني، وتندمج بسلاسة مع محوّلات السحابة التي تحترم الخصوصية مثل convertise.app كلما احتجت إلى تحويل موثوق حسب الطلب.