git - ماهو - version control شرح




git gc-aggressive git repack (4)

أنا أبحث عن طرق لتقليل حجم مستودع git . البحث يقودني إلى git gc --aggressive معظم الأحيان. لقد قرأت أيضا أن هذا ليس هو النهج المفضل.

لماذا ا؟ ماذا يجب أن أكون على دراية إذا كنت أعمل في gc --aggressive ؟

git repack -a -d --depth=250 --window=250 is over over gc --aggressive . لماذا ا؟ كيف تقلل repack من حجم المستودع؟ أيضا ، أنا لست واضحا تماما حول الأعلام - --depth و - --window .

ماذا يجب أن أختار بين gc وأعد repack ؟ متى يجب استخدام gc وأعد repack ؟


متى يجب علي استخدام gc & repack؟

كما ذكرت في " Git Garbage collection لا يبدو أنه يعمل بشكل كامل " ، فإن git gc --aggressive ليست كافية أو حتى كافية من تلقاء نفسها.
وكما أوضح أدناه ، في كثير من الأحيان لا حاجة.

سيكون المزيج الأكثر فاعلية هو إضافة git repack ، ولكن أيضًا git prune :

git gc
git repack -Ad      # kills in-pack garbage
git prune           # kills loose garbage

ملاحظة: Git 2.11 (Q4 2016) gc aggressive العمق الافتراضي gc aggressive على 50

انظر الالتزام 07e7dbf (11 أغسطس 2016) بقلم Jeff King ( peff ) .
(دمجها Junio ​​C gitster - gitster - في الالتزام 0952ca8 ، 21 سبتمبر 2016)

gc : عمق العدوانية الافتراضي إلى 50

تُستخدم عبارة " git gc --aggressive " للحد من طول سلسلة دلتا إلى 250 ، وهي طريقة عميقة جدًا لاكتساب وفورات مساحة إضافية وتضر بأداء وقت التشغيل.
تم تخفيض الحد إلى 50.

الملخص هو: الافتراضي الحالي 250 لا يوفر مساحة كبيرة ، ويتكلف وحدة المعالجة المركزية. انها ليست مفاضلة جيدة.

--aggressive علامة "- --aggressive " إلى git-gc ثلاثة أشياء:

  1. استخدام " -f " لطرد deltas الموجودة وإعادة حساب من الصفر
  2. استخدم "- نافذة = 250" لتبدو أكثر صعوبة بالنسبة للدلتا
  3. استخدم "- العمق = 250" لإنشاء سلاسل دلتا أطول

العناصر (1) و (2) هي مباريات جيدة لإعادة حزم "عدوانية".
يطلبون من repack القيام بمزيد من العمل الحسابي على أمل الحصول على حزمة أفضل. أنت تدفع التكاليف أثناء إعادة التعبئة ، والعمليات الأخرى ترى فائدة فقط.

البند (3) ليس واضحًا جدًا.
السماح بالسلاسل الأطول يعني قيودًا أقل على الدلتا ، مما يعني احتمال إيجاد سلاسل أفضل وتوفير بعض المساحة.
ولكن هذا يعني أيضًا أن العمليات التي تصل إلى دلتا يجب أن تتبع سلاسل أطول ، مما يؤثر على أدائها.
لذا فهي مفاضلة ، وليس من الواضح أن المقايضة جيدة.

(انظر الالتزام للدراسة )

يمكنك أن ترى أن وفورات وحدة المعالجة المركزية لعمليات منتظمة تتحسن ونحن خفض العمق.
ولكن يمكننا أن نرى أيضًا أن توفير المساحة ليس كبيرًا حيث يزداد العمق. توفير 5-10 ٪ بين 10 و 50 ربما يستحق مقايضة وحدة المعالجة المركزية. قد لا يكون التوفير 1٪ للذهاب من 50 إلى 100 ، أو 0.5٪ أخرى للانتقال من 100 إلى 250.

عند الحديث عن توفير وحدة المعالجة المركزية ، تعلمت " git repack " قبول خيار - --threads=<n> وتمريره إلى كائنات حزمة.

راجع الالتزام 40bcf31 (26 أبريل 2017) بقلم Junio ​​C gitster ( gitster ) .
(دمج بواسطة Junio ​​C gitster - gitster - في الالتزام 31fb6f4 ، 29 مايو 2017)

أعد حزم: --threads=<n> وقم --threads=<n> إلى pack-objects

لقد فعلنا ذلك بالفعل من أجل --window=<n> و - --depth=<n> ؛ سيساعد هذا عندما يريد المستخدم فرض - --threads=1 للاختبار استنساخه دون التعرض للتأثر بسباقات المواضيع المتعددة.


الحذر. لا تقم بتشغيل git gc --agressive مع مستودع لا تتم مزامنته مع جهاز التحكم عن بعد إذا لم يكن لديك نسخ احتياطية.

هذه العملية تعيد إنشاء deltas من نقطة الصفر ويمكن أن تؤدي إلى فقدان البيانات إذا قاطع بأمان.

بالنسبة لجهاز الكمبيوتر الخاص بي بحجم 8 جيجا بايت ، نفدت ذاكرة gc العنيفة في مستودع التخزين بسعة 1 جيجابت مع 10 كيلو بايت من العمليات الصغيرة. عندما أنهت OOM kill git عملية - تركت لي مستودعًا فارغًا تقريبًا ، ولم ينجُ إلا الشجرة العاملة وعدد قليل من الدلتا.

بالطبع ، لم تكن هذه هي النسخة الوحيدة من المستودع ، لذا فقد قمت بإعادة إنشائها وسحبت من بعيد (لا يعمل الجلب على الريبو المكسور وتم إيقافه في خطوة "حل الدلتا" عدة مرات حاولت القيام بذلك) ، ولكن إذا كانت إعادة الشراء الريبو المطور المحلي دون أجهزة التحكم عن بعد على الإطلاق - قم بنسخه أولاً.


في الوقت الحاضر ، لا يوجد فرق: git gc --aggressive تعمل git gc --aggressive وفقًا للاقتراح الذي قدمته Linus في عام 2007 ؛ انظر أدناه. اعتبارًا من الإصدار 2.11 (Q4 2016) ، يتم افتراضيات git على عمق 50. نافذة بحجم 250 جيدة لأنها تفحص قسمًا أكبر من كل كائن ، لكن العمق عند 250 يكون سيئًا لأنه يجعل كل سلسلة تشير إلى العمر القديم جدًا الكائنات ، مما يؤدي إلى إبطاء جميع عمليات git المستقبلية لاستخدام القرص بشكل هامشي.

خلفية تاريخية

اقترح لينوس (انظر أدناه للحصول على نشر قائمة git gc --aggressive الكاملة) باستخدام git gc --aggressive فقط عندما يكون لديك ، في كلماته ، "حزمة سيئة حقًا " أو "دلتا سيئة للغاية حقًا" ، ولكن "دائمًا تقريبًا ، في حالات أخرى ، إنها في الواقع أمر سيء حقًا. "قد تترك النتيجة مستودعك في حالة أسوأ من الوقت الذي بدأت فيه!

الأمر الذي يقترحه للقيام بذلك بشكل صحيح بعد استيراد "تاريخ طويل ومشترك" هو

git repack -a -d -f --depth=250 --window=250

ولكن هذا يفترض أنك قمت بالفعل بإزالة عنصر الحماية غير المرغوب فيه من سجل المستودع الخاص بك وأنك اتبعت قائمة التحقق لتقليص مستودع موجود في وثائق git filter-branch .

يمكن استخدام git-filter-branch للتخلص من مجموعة فرعية من الملفات ، عادةً مع مزيج من --index-filter و --subdirectory-filter . يتوقع الناس أن يكون المستودع الناتج أصغر من الأصل ، لكنك تحتاج إلى بضع خطوات أخرى لجعله أصغر حجمًا ، لأن Git يحاول جاهدة ألا تفقد الأشياء الخاصة بك حتى تخبره بذلك. تأكد أولاً من:

  • لقد أزلت بالفعل جميع المتغيرات من اسم ملف ، إذا تم نقل نقطة إلى نقطة طوال العمر. git log --name-only --follow --all -- filename يمكن أن تساعدك في العثور على إعادة تسمية.

  • لقد قمت بالفعل بتصفية جميع الحكام: استخدم --tag-name-filter cat -- --all عند استدعاء git filter-branch .

ثم هناك طريقتان للحصول على مستودع أصغر. الطريقة الأكثر أمانًا هي الاستنساخ ، مما يحافظ على حالتك الأصلية دون تغيير.

  • git clone file:///path/to/repo مع git clone file:///path/to/repo . لن يكون للاستنساخ الكائنات التي تمت إزالتها. انظر بوابة استنساخ. (لاحظ أن الاستنساخ باستخدام مسار عادي يؤدي فقط إلى ربط كل شيء!)

إذا كنت لا ترغب حقًا في استنساخها ، لأي سبب من الأسباب ، تحقق من النقاط التالية بدلاً من ذلك (بهذا الترتيب). هذه طريقة مدمرة للغاية ، لذلك قم بعمل نسخة احتياطية أو العودة لاستنساخها. لقد تم تحذيرك.

  • أزل المراجع الأصلية المدعومة من git-filter-branch: say

    git for-each-ref --format="%(refname)" refs/original/ |
      xargs -n 1 git update-ref -d
    
  • تنتهي صلاحية كل عمليات git reflog expire --expire=now --all .

  • تجمع البيانات المهملة جميع الكائنات غير git gc --prune=now مع git gc --prune=now (أو إذا لم يكن git gc جديدًا بما يكفي لدعم الوسيطات --prune ، استخدم git repack -ad; git prune بدلاً من ذلك).

Date: Wed, 5 Dec 2007 22:09:12 -0800 (PST)
From: Linus Torvalds <torvalds at linux-foundation dot org>
To: Daniel Berlin <dberlin at dberlin dot org>
cc: David Miller <davem at davemloft dot net>,
    ismail at pardus dot org dot tr,
    gcc at gcc dot gnu dot org,
    git at vger dot kernel dot org
Subject: Re: Git and GCC
In-Reply-To: <[email protected]>
Message-ID: <[email protected]>
References: <[email protected]>
            <[email protected]>
            <[email protected]>
            <[email protected]>
            <[email protected]>

في الخميس ، 6 ديسمبر 2007 ، كتب دانييل برلين:

في الواقع ، اتضح أن git-gc --aggressive تقوم بهذا الشيء الغبي لحزم الملفات في بعض الأحيان بغض النظر عما إذا كنت قد قمت بالتحويل من repo SVN أم لا.

إطلاقا. git --aggressive غبية في الغالب. إنها حقًا مفيدة فقط لحالة "أعرف أن لدي حزمة سيئة حقًا ، وأريد التخلص من جميع قرارات التعبئة السيئة التي قمت بها."

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

في SCMs الأخرى ، يتم إصلاح سلسلة دلتا بشكل عام. قد يكون "للأمام" أو "للخلف" ، وقد يتطور قليلاً أثناء العمل مع المستودع ، ولكنه بشكل عام سلسلة من التغييرات على ملف واحد يتم تمثيله كنوع من كيانات SCM واحدة. في CVS ، من الواضح أن الملف *,v ، والكثير من الأنظمة الأخرى تفعل أشياء متشابهة إلى حد ما.

Git يفعل أيضًا سلاسل الدلتا ، لكنه يفعلها كثيرًا "فضفاضة". لا يوجد كيان ثابت. يتم إنشاء Deltas مقابل أي إصدار عشوائي آخر ترى git أنه مرشح دلتا جيد (مع العديد من الأساليب البحثية الناجحة إلى حد ما) ، ولا توجد قواعد تجميعية ثابتة على الإطلاق.

هذا هو عموما شيء جيد جدا. إنها جيدة لأسباب مفاهيمية مختلفة (على سبيل المثال ، لا يجب على البوابة الداخلية أبدًا أن تهتم بسلسلة المراجعة بأكملها - إنها لا تفكر حقًا في الدلتا على الإطلاق) ، لكنها أيضًا رائعة لأن التخلص من قواعد دلتا غير المرنة يعني لا تواجه هذه المشكلة أية مشكلات على الإطلاق في دمج ملفين معًا ، على سبيل المثال - لا توجد ببساطة "ملفات مراجعة" تعسفية *,v لها بعض المعاني المخفية.

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

وهذا هو المكان الذي يأتي --aggressive الاسم --aggressive حقًا - --aggressive . بينما تحاول git عمومًا إعادة استخدام معلومات دلتا (لأنها فكرة جيدة ، ولا تضيع وقت وحدة المعالجة المركزية في العثور على جميع الدلتا الجيدة التي وجدناها سابقًا) ، في بعض الأحيان تريد أن تقول "دعونا نبدأ من جديد ، مع قائمة بيضاء فارغة ، وتجاهل جميع معلومات دلتا السابقة ، ومحاولة إنشاء مجموعة جديدة من دلتا".

لذلك - لا يعني --aggressive الحقيقة كونك عدوانيًا ، بل يتعلق بإهدار وقت وحدة المعالجة المركزية في إعادة اتخاذ القرار الذي اتخذناه بالفعل من قبل!

في بعض الأحيان هذا شيء جيد. بعض أدوات الاستيراد على وجه الخصوص يمكن أن تولد دلتا سيئة سيئة حقا. أي شيء يستخدم git fast-import ، على سبيل المثال ، لا يحتوي على الأرجح على تخطيط دلتا كبير ، لذلك قد يكون من المفيد القول "أريد أن أبدأ من قائمة نظيفة".

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

سأرسل تصحيحًا إلى Junio ​​لإزالة git gc --aggressive وثائق التوثيق. يمكن أن يكون مفيدًا ، لكنه مفيد بشكل عام فقط عندما تفهم حقًا ما تفعله على مستوى عميق جدًا ، وأن الوثائق لا تساعدك على القيام بذلك.

بشكل عام ، القيام git gc هو النهج الصحيح ، وأفضل من فعل git gc --aggressive . سوف تعيد استخدام الدلتا القديمة ، وعندما لا يمكن العثور على تلك الدلتا القديمة (سبب القيام GC تدريجياً في المقام الأول!) فإنها ستخلق دالات جديدة.

من ناحية أخرى ، من المؤكد أن "الاستيراد الأولي للتاريخ الطويل والمشترك" هو نقطة قد يكون من المفيد إنفاقها الكثير من الوقت في العثور على دلتا جيدة حقًا . بعد ذلك ، كل مستخدم على الإطلاق (طالما أنهم لا يستخدمون git gc --aggressive للتراجع عن ذلك!) سوف يستفيدون من هذا الحدث لمرة واحدة. لذلك ، خاصة بالنسبة للمشروعات الكبيرة ذات التاريخ الطويل ، من المحتمل أن تقوم ببعض الأعمال الإضافية ، مع إخبار كود إيجاد الدلتا بالانتشار.

لذا فإن ما يعادل git gc --aggressive - git gc --aggressive - ولكن يتم بشكل صحيح - هو القيام (بين عشية وضحاها) بشيء من هذا القبيل

git repack -a -d --depth=250 --window=250

حيث يتعلق هذا الشيء العميق بمدى عمق سلاسل الدلتا (اجعلها أطول للتاريخ القديم - إنها تستحق المساحة الإضافية) ، وشيء النافذة يتعلق بكمية نافذة الكائن التي نريد من كل مرشح دلتا أن يفحصها.

وهنا ، قد ترغب في إضافة علامة -f (وهي "إسقاط كل الدلتا القديمة" ، لأنك تحاول الآن بالفعل التأكد من أن هذه الفئة تجد بالفعل مرشحين جيدين.

ثم سيستغرق الأمر إلى الأبد ويومًا ( أي شيء "افعله بين عشية وضحاها"). لكن النتيجة النهائية هي أن كل شخص من المصب من هذا المستودع سيحصل على حزم أفضل بكثير ، دون الحاجة إلى بذل أي جهد عليه.

          Linus

ملاحظة: احذر من استخدام git gc --aggressive ، كما git gc --aggressive Git 2.22 (Q2 2019).

راجع الالتزام 0044f77 ، الالتزام daecbf2 ، الالتزام 7384504 ، الالتزام 22d4e3b ، الالتزام 080a448 ، الالتزام 54d56f5 ، الالتزام d257e0f ، الالتزام b6a8d09 (07 أبريل 2019) ، والالتزام fc559fb ، الالتزام cf9cd77 ، الالتزام b11ear6 ) .
(دمج بواسطة Junio ​​C gitster - gitster - في الالتزام ac70c53 ، 25 أبريل 2019)

مستندات gc : قلل من جدوى - --aggressive

تأتي مستندات " gc --aggressive " gc --aggressive أقل من التوصية للمستخدمين بتشغيلها بانتظام.
لقد تحدثت شخصيًا مع العديد من المستخدمين الذين أخذوا هذه المستندات كنصيحة لاستخدام هذا الخيار ، وعادةً ما يكون ذلك (غالبًا) مضيعة للوقت .

لذلك دعونا نوضح ما الذي تفعله حقًا ، ودع المستخدم يستخلص استنتاجاته الخاصة.

لنقم أيضًا بتوضيح "الآثار [...] ثابتة" لإعادة صياغة نسخة مختصرة من شرح Jeff King .

وهذا يعني أن وثائق git-gc تشمل الآن :

عدوانيا

عندما يتم توفير الخيار - --aggressive ، سيتم استدعاء git-repack بعلامة -f ، والتي بدورها سوف تمرر --no-reuse-delta إلى git-pack-objects .
سيؤدي هذا إلى التخلص من أي دلتا حالية وإعادة حسابها ، على حساب إنفاق المزيد من الوقت على إعادة التعبئة.

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

علاوة على ذلك ، فإن إمداد - --aggressive سوف يعدل - - --depth و - - خيارات --window تم تمريرها إلى git-repack .
راجع إعدادات gc.aggressiveWindow و gc.aggressiveWindow أدناه.
باستخدام حجم نافذة أكبر ، من المحتمل أن نجد المزيد من دلتا الأمثل.

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

و ( الالتزام 080a448 ):

مستندات gc : لاحظ كيف - التأثيرات --window - --depth - --depth

نظرًا لأن 07e7dbf ( gc : العمق العدواني الافتراضي إلى 50 ، 2016-08-11 ، Git v2.10.1) ، فإننا نستخدم نفس العمق بشكل مشوش إلى حد ما تحت - --aggressive كما نفعل افتراضيًا.

كما هو مذكور في هذا الالتزام المنطقي ، كان من الخطأ أن نجعل من العمق الافتراضي لـ "العدوانية" ، وبالتالي توفير مساحة على حساب أداء وقت التشغيل ، والذي عادة ما يكون عكس شخص يرغب في "gc العدواني" يريد.







version-control