هناك حاجة لبعض الحيل في بعض الأحيان عند العمل مع بوابة

أريد مشاركة الوصفات لحل بعض المشاكل التي تنشأ أحيانًا عند العمل مع git ، والتي "ليست واضحة تمامًا".


في البداية اعتقدت أن تتراكم المزيد من هذه الوصفات ، ولكن كل شيء له وقته. أعتقد أنه إذا كان هناك أي فائدة ، فمن الممكن شيئًا فشيئًا ...


لذا ...


فروع الاندماج القديمة مع ألم بسيط


الديباجة. هناك فرع master ( master ) ، يلتزم بنشاط الميزات والإصلاحات الجديدة ؛ هناك فرع متوازي feature ، أبحر فيه المطورون لفترة من الوقت في السكينة الخاصة بهم ، ثم اكتشفوا فجأة أنهم لم يكونوا مع السيد لمدة شهر الآن ، وكان الدمج "على الجبهة" (وجها لوجه) غير بسيط.


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


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


المؤامرة. حقيقة أنه في البوابة يمكنك تعديل آخر التزام بالمفتاح - --amend يعرفه --amend . الحيلة هي أن هذا "الالتزام الأخير" يمكن أن يكون موجودًا في أي مكان ويحتوي على أي شيء. على سبيل المثال ، لا يمكن أن يكون مجرد "الالتزام الأخير بالفرع الخطي" ، حيث نسوا تصحيح الخطأ المطبعي ، ولكن أيضًا التزام الدمج من الدمج المعتاد أو "الأخطبوط". --amend فقط --amend التغييرات المقترحة و "تضمين" الالتزام المتغير في الشجرة ، كما لو أنه ظهر بالفعل نتيجة دمج صادق وحل النزاعات. في جوهرها ، git merge و git commit --amend يسمح git commit --amend بفصل "مكان git commit --amend تمامًا ("هذا الالتزام في الشجرة سيكون هنا") ومحتويات الالتزام نفسه.


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


  1. "حبة مكان". من السهل القيام بذلك عن طريق وضع استراتيجية اندماج لن تطرح أسئلة غير ضرورية حول حل النزاع.


     git checkout feature git merge master -s ours 

  2. أوه نعم. كان من الضروري قبل الدمج إنشاء فرع "نسخ احتياطي" من رأس الميزة. بعد كل شيء ، لم يتم دمج أي شيء حقًا ... ولكن فليكن هذه هي الفقرة الثانية ، وليس الفقرة 0. بشكل عام ، ننتقل إلى الميزة غير المدمجة ، والآن ندمج بصدق. بأي شكل من الأشكال ، على الرغم من أي "الاختراق القذرة". طريقي الشخصي هو النظر إلى الفرع الرئيسي من لحظة الدمج الأخير وتقييم عمليات ارتكاب المشاكل المحتملة (على سبيل المثال: تصحيح خطأ مطبعي في مكان واحد - وليس مشكلة واحدة. على نطاق واسع (العديد من الملفات) قاموا بإعادة تسمية كيان - مشكلة واحدة ، وما إلى ذلك). من ارتكاب المشكلات ، ننشئ فروعًا جديدة (أقوم ببراعة - master1 ، master2 ، master3 ، وما إلى ذلك). ثم نقوم بدمج فرع تلو الآخر ، وننتقل من النزاعات القديمة إلى الجديدة والصحيحة (التي عادة ما تكون بديهية مع هذا النهج). اقتراح طرق أخرى (أنا لست ساحرًا ؛ أنا أتعلم فقط ؛ سأكون سعيدًا بالتعليقات البناءة!). في النهاية ، إنفاق (ربما) بضع ساعات على العمليات الروتينية البحتة (والتي يمكن أن يعهد بها إلى صغار ، لأنه ببساطة لا توجد تعارضات معقدة مع هذا النهج) ، نحصل على الحالة النهائية للرمز: تم نقل جميع الابتكارات / إصلاحات المعالج إلى فرع الميزة بنجاح ، وجميع الاختبارات ذات الصلة مشى على هذا الرمز ، إلخ. يجب الالتزام برمز ناجح.


  3. إعادة كتابة "قصة نجاح". يجري على الالتزام ، حيث "يتم كل شيء" ، قم بتشغيل ما يلي:



 git tag mp git checkout mp git reset feature git checkout feature git tag -d mp 

(I decipher: باستخدام علامة (mp - دمج نقطة) ، ننتقل إلى حالة HEAD المنفصلة ، ومن هناك يتم إعادة تعيينها إلى رأس فرعنا ، حيث في البداية تم إنشاء "حصة خارج" من خلال عملية دمج احتيالية. لم تعد العلامة مطلوبة ، لذلك نحذفها). نحن الآن على التزام دمج "محض" الأصلي ؛ في نفس الوقت في نسخة العمل لدينا الملفات "الصحيحة" ، حيث يوجد كل ما تحتاجه. الآن تحتاج إلى إضافة جميع الملفات التي تم تغييرها إلى الفهرس ، وإلقاء نظرة خاصة على الملفات غير المرحلية (سيكون هناك جميع الملفات الجديدة التي ظهرت في الفرع الرئيسي). نضيف كل ما نحتاجه من هناك أيضًا.


أخيرًا ، عندما يكون كل شيء جاهزًا ، ندخل التزامنا الصحيح في المكان المحجوز:


 git commit --amend 

مرحى! كل شيء يعمل! يمكنك دفع فرع عرضيًا إلى مستودع عام ، ولن يعرف أحد أنك قضيت نصف يوم من العمل في هذا الدمج.


التحديث: طريقة أكثر إيجازا


بعد ثلاثة أشهر من هذا المنشور ، مقالة " كيف ولماذا سرقة الأشجار في بوابة " من قبل capslocky


استنادًا إلى دوافعها ، من الممكن تحقيق نفس الهدف بالضبط بطريقة أقصر وبدون آليات مساعدة: لا حاجة إلى "نشر مساحة" ، والنظر في الملفات غير المرحلية بعد إعادة التعيين وإجراء التعديل ؛ يمكنك إنشاء التزام دمج مباشر مع المحتوى المطلوب في خطوة واحدة.


نبدأ على الفور بالاندماج باستخدام أي من الطرق المتاحة (كما في الفقرة 2 أعلاه). لا تزال القصة المتوسطة والمتسللة غير ذات صلة. وبعد ذلك ، بدلاً من المطالبة 3 ، مع استبدال التزام الدمج ، نقوم بعمل دمج مصطنع ، كما هو الحال في المقالة:


 git tag mp git checkout feature git merge --ff $(git commit-tree mp^{tree} -m "merged branch 'master' into 'feature'" -p feature -p master) git tag -d mp 

كل السحر هنا يتم في خطوة واحدة بواسطة الأمر الثالث (بوابة الالتزام - شجرة).


حدد جزءًا من الملف ، مع الاحتفاظ بالسجل


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


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


المؤامرة. مع بعض تأثيرات الحواف المزعجة قليلاً ، يمكن القيام بذلك. من أجل التعريف ، هناك ملف file.txt ، أرغب في تسليط الضوء على جزء منه في file2.txt . (وما زلت تحتفظ بالقصة ، نعم). تشغيل هذا المقتطف:


 f=file.txt; f1=file1.txt; f2=file2.txt cp $f $f2 git add $f2 git mv $f $f1 git commit -m"split $f step 1, converted to $f1 and $f2" 

نتيجة لذلك ، نحصل على ملفات file1.txt و file2.txt . كلاهما لهما نفس القصة بالضبط (حقيقي ؛ مثل الملف الأصلي). نعم ، كان يجب إعادة تسمية file.txt الأصلي ؛ هذا هو تأثير حافة "مزعج قليلاً". لسوء الحظ ، لم أجد طريقة لحفظ القصة ، ولكن من أجل عدم إعادة تسمية الملف المصدر (إذا كان بإمكان أي شخص ، أخبرني!). ومع ذلك ، فإن git سوف تتحمل كل شيء. الآن لا أحد يزعج إعادة تسمية الملف مرة أخرى في التزام منفصل:


 git mv $f1 $f git commit -m"split finish, rename $f1 to $f" 

الآن file2.txt سيعرض المذهب نفس تاريخ سطر الملف الأصلي. الشيء الرئيسي هو عدم دمج هاتين الجريمتين معًا (وإلا سيختفي كل السحر ؛ لقد جربته!). ولكن في الوقت نفسه ، لا أحد يزعج تحرير الملفات مباشرة في عملية الفصل ؛ ليس من الضروري القيام بذلك في وقت لاحق مع عمليات منفصلة. ونعم ، يمكنك تحديد العديد من الملفات دفعة واحدة!


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


تحديث: زوج من الوصفات من Lissov


فصل جزء مستودع التاريخ


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


هام! يجب أن تتم جميع الحركات باستخدام git mv ، وإلا فقد يفقد التاريخ التاريخ.


نقوم بتنفيذ:


 git filter-branch --prune-empty --subdirectory-filter "{directory}" [branch] 

{الدليل} هو المجلد الذي سيتم فصله. ونتيجة لذلك ، نحصل على المجلد جنبًا إلى جنب مع السجل الكامل للالتزامات فقط ، أي في كل التزام ، يتم عرض الملفات من هذا المجلد فقط. وبطبيعة الحال ، سيكون جزءًا من عمليات التنفيذ فارغًا ، ويزيلهم -prune-blank.
الآن قم بتغيير الأصل:


 git remote set-url origin {another_repository_url}` git checkout move_from_Repo_1 

إذا كان المستودع الثاني نظيفًا ، يمكنك الذهاب مباشرة لإتقان. حسنًا ، ادفع:


 git push -u move_from_Repo_1 

مقتطف كامل (للنسخ واللصق بسهولة):


 directory="directory_to_extract"; newurl="another_repository_url" git filter-branch --prune-empty --subdirectory-filter "$directory" git remote set-url origin "$newurl" git checkout move_from_Repo_1 git push -u move_from_Repo_1 

ادمج مستودعين معًا


لنفترض أنك فعلت شيئًا أعلى بمرتين وحصلت على move_from_Repo_1 move_from_Repo_2 في كل من move_from_Repo_1 و move_from_Repo_2 ، وفي كل ملف قمت بنقل الملفات باستخدام git mv إلى المكان الذي يجب أن تكون فيه بعد الدمج. الآن يبقى للسيطرة على:


 br1="move_from_Repo_1"; br2="move_from_Repo_2" git checkout master git merge origin/$br1 --allow-unrelated-histories git merge origin/$br2 --allow-unrelated-histories git push 

الحيلة بأكملها في --السماح - لا علاقة لها - التاريخ. ونتيجة لذلك ، نحصل على مستودع واحد يحتوي على سجل كامل لجميع التغييرات.

Source: https://habr.com/ru/post/ar424045/


All Articles