هل هناك فرق بين "إعادة تعيين GIT -Hard Hard" و "Git Checkout Hash"؟
-
23-09-2019 - |
سؤال
بينما reset
و checkout
لديك استخدامات مختلفة معظم الوقت ، لا أستطيع أن أرى الفرق بين هذين.
من المحتمل أن يكون هناك واحد أو لا أحد كان سيزعج إضافة أ --hard
خيار للقيام بشيء أساسي checkout
يمكن القيام به.
ربما هناك فرق هو الطريقة التي سترى بها التاريخ؟
المحلول
يتم نقل هذه الإجابة في الغالب من إجابتي إلى سؤال سابق: إعادة تعيين git باللغة الإنجليزية العادية.
الإثنان مختلفان جدا. إنها تؤدي إلى نفس الحالة لمؤشرك وشجرة العمل ، لكن التاريخ الناتج والفرع الحالي ليسا متماثلين.
لنفترض أن تاريخك يبدو هكذا ، حيث تم فحص الفرع الرئيسي حاليًا:
- A - B - C (HEAD, master)
وأنت تركض git reset --hard B
. ستحصل على هذا:
- A - B (HEAD, master) # - C is still here, but there's no
# branch pointing to it anymore
ستحصل بالفعل على هذا التأثير إذا كنت تستخدم --mixed
أو --soft
أيضًا - الفرق الوحيد هو ما يحدث لشجرة عملك والفهرس. في ال --hard
الحالة ، تطابق شجرة العمل والفهرس B
.
الآن ، افترض أنك ستشغل git checkout B
في حين أن. ستحصل على هذا:
- A - B (HEAD) - C (master)
لقد انتهى بك الأمر في حالة رأس منفصلة. HEAD
, ، شجرة العمل ، فهرس كل مطابقة B
, ، كما هو الحال مع إعادة التعيين الصلب ، ولكن تم ترك الفرع الرئيسي وراءه C
. إذا قمت بالتزام جديد D
في هذه المرحلة ، ستحصل على هذا ، وهو ربما ليس ما تريده:
- A - B - C (master)
\
D (HEAD)
لذلك ، يمكنك استخدام الخروج ، حسنًا ، تحقق من هذا الالتزام. يمكنك أن تملأ معها ، تفعل ما تريد ، لكنك تركت فرعك وراءك. إذا كنت تريد نقل الفرع أيضًا ، فأنت تستخدم إعادة التعيين.
نصائح أخرى
إذا لم تساعدك الوثائق المقدمة بـ GIT ، فقم بإلقاء نظرة على مرجع GIT المرئي بقلم مارك لوداتو.
على وجه الخصوص إذا كنت تقارن git checkout <non-branch>
مع git reset --hard <non-branch>
(Hotlinked):
(مصدر: github.com)
لاحظ أنه في حالة git reset --hard master~3
أنت تترك وراءها جزءًا من DAG of Revisions - بعض الالتزامات لا يتم الرجوع إليها من قبل أي فرع. تلك محمية (بشكل افتراضي) 30 يومًا ريتش; ؛ سيتم تقليمهم في النهاية (إزالته).
git-reset hash
يحدد مرجع الفرع إلى التجزئة المحددة ، ويتحقق منه اختياريًا ،--hard
.
git-checkout hash
يضع شجرة العمل على التجزئة المعطاة ؛ وما لم يكن التجزئة اسم فرع ، فسوف ينتهي به الأمر برأس منفصل.
في النهاية ، يتعامل Git مع 3 أشياء:
working tree (your code)
-------------------------------------------------------------------------
index/staging-area
-------------------------------------------------------------------------
repository (bunch of commits, trees, branch names, etc)
git-checkout
بشكل افتراضي ، فقط يقوم بتحديث الفهرس والشجرة العاملة ، ويمكنه تحديث شيء ما في المستودع اختياريًا (مع -b
اختيار)
git-reset
بشكل افتراضي ، فقط يقوم بتحديث المستودع والفهرس ، واختياري شجرة العمل (مع --hard
اختيار)
يمكنك التفكير في المستودع مثل هذا:
HEAD -> master
refs:
master -> sha_of_commit_X
dev -> sha_of_commit_Y
objects: (addressed by sha1)
sha_of_commit_X, sha_of_commit_Y, sha_of_commit_Z, sha_of_commit_A ....
git-reset
يعالج ما يشير إليه المراجع الفرع.
لنفترض أن تاريخك يبدو هكذا:
T--S--R--Q [master][dev]
/
A--B--C--D--E--F--G [topic1]
\
Z--Y--X--W [topic2][topic3]
ضع في اعتبارك أن الفروع هي مجرد أسماء تتقدم تلقائيًا عند الالتزام.
لذلك لديك الفروع التالية:
master -> Q
dev -> Q
topic1 -> G
topic2 -> W
topic3 -> W
وفرعك الحالي topic2
, ، أي ، يشير الرأس إلى Topic2.
HEAD -> topic2
ثم، git reset X
سوف يعيد تعيين الاسم topic2
للإشارة إلى x ؛ بمعنى أنه إذا قمت بالتزام P on Branch Topic2 ، فستبدو الأمور هكذا:
T--S--R--Q [master][dev]
/
A--B--C--D--E--F--G [topic1]
\
Z--Y--X--W [topic3]
\
P [topic2]