كيف يمكنني التعافي/إعادة التزامن بعد أن يدفع شخص ما إلى إعادة ضبط أو إعادة تعيين إلى فرع منشور؟
-
28-09-2019 - |
سؤال
لقد سمعنا جميعًا أنه لا ينبغي لأحد أن ينشر العمل ، وأنه خطير ، وما إلى ذلك. ومع ذلك ، لم أر أي وصفات منشورة لكيفية التعامل مع الموقف في حالة Rebase هو نشرت.
الآن ، لاحظ أن هذا أمر ممكن حقًا إذا لم يتم استنساخ المستودع إلا من قبل مجموعة معروفة (ويفضل أن تكون صغيرة) من الأشخاص ، بحيث يمكن لأي شخص يدفع Rebase أو إعادة تعيينه إخطار الجميع بأنهم سيحتاجون إلى الاهتمام في المرة القادمة أحضر(!).
سيعمل أحد الحلول الواضحة التي رأيتها إذا لم يكن لديك أي علاقة محلية foo
ويتم تربيتها:
git fetch
git checkout foo
git reset --hard origin/foo
هذا سوف يرمي ببساطة الحالة المحلية foo
لصالح تاريخها حسب المستودع البعيد.
ولكن كيف يمكن للمرء أن يتعامل مع الموقف إذا ارتكب المرء تغييرات محلية كبيرة على هذا الفرع؟
المحلول
العودة إلى التزامن بعد دفع Rebase ليس معقدًا في معظم الحالات.
git checkout foo
git branch old-foo origin/foo # BEFORE fetching!!
git fetch
git rebase --onto origin/foo old-foo foo
git branch -D old-foo
بمعنى آخر. أولاً ، قمت بإعداد إشارة مرجعية للمكان الذي كان فيه الفرع البعيد في الأصل ، ثم يمكنك استخدام ذلك لإعادة تشغيل الالتزامات المحلية الخاصة بك من تلك النقطة فصاعدًا على الفرع البعيد المُعاد للبرد.
إن إعادة التثبيت مثل العنف: إذا لم يحل مشكلتك ، فأنت بحاجة فقط إلى المزيد منها. ☺
يمكنك القيام بذلك دون إشارة مرجعية بالطبع ، إذا بحثت عن إعادة البيئة قبل origin/foo
ارتكب معرف ، واستخدم ذلك.
هذه هي أيضًا الطريقة التي تتعامل بها مع الموقف الذي نسيت أن تصنع إشارة مرجعية قبل جلب. لا شيء ضائع - تحتاج فقط إلى التحقق
git reflog show origin/foo | awk '
PRINT_NEXT==1 { print $1; exit }
/fetch: forced-update/ { PRINT_NEXT=1 }'
هذا سيطبع معرف الالتزام الذي origin/foo
أشارت قبل الجلب الأخير الذي غير تاريخها.
يمكنك بعد ذلك ببساطة
git rebase --onto origin/foo ارتكاب $ foo
نصائح أخرى
أود أن أقول التعافي من Rebase في المنبع يغطي قسم من صفحة Git-Rebase Man إلى حد كبير كل هذا.
لا يختلف الأمر حقًا عن التعافي من Rebase الخاص بك - أنت تحرك فرعًا واحدًا ، و Rebase جميع الفروع التي كانت في تاريخها في موقعها الجديد.
بدءًا من GIT 1.9/2.0 Q1 2014 ، لن تضطر إلى وضع علامة على أصل فرعك السابق قبل إعادة صياغته على فرع المنبع المعاد كتابته ، كما هو موضح في أرسطو Pagaltzis'س إجابه:
نرى الالتزام 07d406b و ارتكاب D96855F :
بعد العمل على
topic
فرع تم إنشاؤه معgit checkout -b topic origin/master
, ، تاريخ فرع التتبع عن بُعدorigin/master
ربما تم إعادة بناء وإعادة بنائها ، مما يؤدي إلى تاريخ من هذا الشكل:
o---B1
/
---o---o---B2--o---o---o---B (origin/master)
\
B3
\
Derived (topic)
أين
origin/master
تستخدم للإشارة في الالتزاماتB3
,B2
,B1
والآن يشير فيB
, ، وخاصتكtopic
بدأ الفرع فوقه عندماorigin/master
كان فيB3
.يستخدم هذا الوضع مجموعة من
origin/master
لايجادB3
كنقطة شوكة ، بحيثtopic
يمكن أن يتم تربيتها فوق التحديثorigin/master
بواسطة:
$ fork_point=$(git merge-base --fork-point origin/master topic)
$ git rebase --onto origin/master $fork_point topic
لهذا السبب git merge-base
الأوامر له خيار جديد:
--fork-point::
ابحث عن النقطة التي يؤدي فيها الفرع (أو أي تاريخ يؤدي إلى
<commit>
) متشوق من فرع آخر (أو أي مرجع)<ref>
.
هذا لا يبحث فقط عن الجد المشترك بين الاثنين ، ولكن يأخذ أيضا في الاعتبار ريبوج<ref>
لمعرفة ما إذا كان التاريخ يؤدي إلى<commit>
متشوق من تجسد سابق للفرع<ref>
.
ال "
git pull --rebase
"يحسب الأمر نقطة الشوكة للفرع الذي يتم إعادة إدخاله باستخدام إدخالات lefg of the"base
"فرع (عادةً فرع تتبع عن بُعد) ، كان عمل الفرع يعتمد على ، من أجل التعامل مع الحالة التي تم فيها إعادة بناء فرع" القاعدة "وإعادة بنائها.
على سبيل المثال ، إذا كان التاريخ يبدو وكأنه:
- الطرف الحالي من "
base
"الفرع فيB
, ، لكن الجلب في وقت سابق لاحظ أن طرفه كان يستخدمB3
وثمB2
وثمB1
قبل الوصول إلى الالتزام الحالي ، و- يعتمد الفرع الذي يجري تربيته فوق أحدث "قاعدة" على الالتزام
B3
,يحاول أن يجد
B3
عن طريق المرور من خلال إخراج ""git rev-list --reflog base
" (بمعنى آخرB
,B1
,B2
,B3
) حتى يجد التزامًا يمثل سلف النصيحة الحالية "Derived (topic)
".داخليا لدينا
get_merge_bases_many()
يمكن أن يحسب هذا مع واحد.
نريد قاعدة دمج بينDerived
ودمج وهمية من شأنه أن ينتج عنه دمج جميع النصائح التاريخية لـ "base (origin/master)
".
عند وجود مثل هذا الالتزام ، يجب أن نحصل على نتيجة واحدة ، والتي تتطابق تمامًا مع أحد إدخالات القبيحة ""base
".
ستضيف GIT 2.1 (Q3 2014) جعل هذه الميزة أكثر قوة لذلك: انظر ارتكاب 1E0DACD بواسطة جون حفظ (johnkeeping
)
تعامل بشكل صحيح مع السيناريو حيث لدينا الطوبولوجيا التالية:
C --- D --- E <- dev
/
B <- master@{1}
/
o --- B' --- C* --- D* <- master
أين:
B'
هو نسخة ثابتة منB
هذا ليس متطرفًا معB
;C*
وD*
هي patch-pantical لC
وD
على التوالي والصراع للنصوص إذا تم تطبيقه بالترتيب الخاطئ ؛E
يعتمد على النصD
.
النتيجة الصحيحة ل git rebase master dev
هل هذا B
تم تحديده على أنه نقطة شوكة dev
و master
, ، لهذا السبب C
, D
, E
هي الالتزامات التي يجب إعادة تشغيلها master
; ؛ لكن C
و D
تصحيح مع C*
و D*
وهكذا يمكن إسقاطها ، بحيث تكون النتيجة النهائية هي:
o --- B' --- C* --- D* --- E <- dev
إذا لم يتم تحديد نقطة الشوكة ، فعند اختيار B
على فرع يحتوي B'
ينتج عنه تعارض وإذا لم يتم تحديد الالتزامات المتطورة بشكل صحيح ثم الاختيار C
على فرع يحتوي D
(أو مكافئ D*
) النتائج في الصراع.