Git Reset vs Revert vs Rebase
نشرت: 2021-05-20في هذه المقالة ، ستتعرف على طرق مختلفة للتلاعب بالالتزامات في Git.
بصفتك مطورًا ، قد تواجه مثل هذه المواقف عدة مرات حيث كنت ترغب في التراجع عن أحد التزاماتك السابقة ولكنك لست متأكدًا من كيفية القيام بذلك. وحتى إذا كنت تعرف أوامر Git مثل إعادة التعيين ، والعودة ، وإعادة الأسس ، فأنت لست على دراية بالاختلافات بينها. لذلك دعونا نبدأ ونفهم ما هي git reset، return and rebase.
إعادة تعيين بوابة
Git reset هو أمر معقد ، ويتم استخدامه للتراجع عن التغييرات.
يمكنك التفكير في إعادة تعيين git كميزة تراجع. مع git reset ، يمكنك القفز بين عمليات التنفيذ المختلفة. توجد ثلاثة أوضاع لتشغيل أمر git reset: – soft و – mixed و –hard. بشكل افتراضي ، يستخدم الأمر git reset الوضع المختلط. في سير عمل إعادة تعيين git ، تظهر ثلاث آليات للإدارة الداخلية لـ git: HEAD ومنطقة التدريج (الفهرس) ودليل العمل .

دليل العمل هو المكان الذي تعمل فيه حاليًا ، وهو المكان الذي توجد فيه ملفاتك. باستخدام أمر git status ، يمكنك معرفة ما هي جميع الملفات / المجلدات الموجودة في دليل العمل.
منطقة التدريج (الفهرس) هي المكان الذي يتتبع فيه git جميع التغييرات في الملفات ويحفظها. تنعكس التغييرات المحفوظة في دليل .git. يمكنك استخدام الأمر git add "filename" لإضافة الملف إلى منطقة التدريج. ومثلما حدث من قبل ، عند تشغيل حالة git ، سترى الملفات الموجودة في منطقة التدريج.
يشار إلى الفرع الحالي في Git باسم HEAD. يشير إلى الالتزام الأخير ، الذي حدث في فرع السداد الحالي. يتم التعامل معها كمؤشر لأي مرجع. بمجرد تسجيل الخروج إلى فرع آخر ، ينتقل HEAD أيضًا إلى الفرع الجديد.
اسمحوا لي أن أشرح كيف تعمل إعادة تعيين git في الأوضاع الصعبة واللينة والمختلطة. يتم استخدام الوضع الثابت للانتقال إلى الالتزام المدبب ، ويتم ملء دليل العمل بملفات ذلك الالتزام ، ويتم إعادة تعيين منطقة التدريج. في إعادة الضبط الناعم ، يتم تغيير المؤشر فقط إلى الالتزام المحدد. تظل ملفات جميع الالتزامات في دليل العمل ومنطقة التدريج قبل إعادة التعيين. في الوضع المختلط (افتراضي) ، تتم إعادة تعيين كل من المؤشر ومنطقة التدريج.
Git إعادة تعيين الثابت
الغرض من git hard reset هو نقل HEAD إلى الالتزام المحدد. سيؤدي ذلك إلى إزالة جميع الالتزامات التي حدثت بعد الالتزام المحدد. سيغير هذا الأمر محفوظات الالتزام ويشير إلى الالتزام المحدد.
في هذا المثال ، سأضيف ثلاثة ملفات جديدة ، وألزمها ثم أقوم بإعادة ضبط المصنع.
كما ترون من الأمر أدناه ، في الوقت الحالي ، لا يوجد شيء للالتزام به.
$ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) nothing to commit, working tree cleanالآن ، سوف أقوم بإنشاء 3 ملفات وإضافة بعض المحتوى إليها.
$ vi file1.txt $ vi file2.txt $ vi file3.txtأضف هذه الملفات إلى المستودع الحالي.
$ git add file*عند إعادة تشغيل أمر الحالة ، فسوف يعكس الملفات الجديدة التي قمت بإنشائها للتو.
$ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: file1.txt new file: file2.txt new file: file3.txtقبل الالتزام ، دعني أوضح لك ، لدي حاليًا سجل من 3 عمليات ارتكاب في Git.
$ git log --oneline 0db602e (HEAD -> master) one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) testالآن ، سألتزم بالمستودع.
$ git commit -m 'added 3 files' [master d69950b] added 3 files 3 files changed, 3 insertions(+) create mode 100644 file1.txt create mode 100644 file2.txt create mode 100644 file3.txtإذا قمت بعمل ls-files ، فسترى أن الملفات الجديدة قد تمت إضافتها.
$ git ls-files demo dummyfile newfile file1.txt file2.txt file3.txtعندما أقوم بتشغيل أمر السجل في git ، لدي 4 التزامات ، ويشير HEAD إلى آخر التزام.
$ git log --oneline d69950b (HEAD -> master) added 3 files 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) testإذا ذهبت وحذفت file1.txt يدويًا وقمت بعمل حالة git ، فستظهر رسالة مفادها أن التغييرات لم يتم تنظيمها للالتزام.
$ git status On branch master Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits) Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) deleted: file1.txt no changes added to commit (use "git add" and/or "git commit -a")الآن ، سأقوم بتشغيل أمر إعادة التعيين الثابت.
$ git reset --hard HEAD is now at d69950b added 3 filesإذا أعدت التحقق من الحالة ، فسأجد أنه لا يوجد شيء يلزم الالتزام به ، وقد عاد الملف الذي قمت بحذفه إلى المستودع. حدث التراجع لأنه بعد حذف الملف ، لم أقم بالالتزام ، لذلك بعد إعادة التعيين الثابت ، عاد إلى الحالة السابقة.
$ git status On branch master Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits) nothing to commit, working tree cleanإذا تحققت من سجل git ، هذا هو الشكل الذي سيبدو عليه.
$ git log commit d69950b7ea406a97499e07f9b28082db9db0b387 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 19:53:31 2020 +0530 added 3 files commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 testالغرض من إعادة التعيين الثابت هو الإشارة إلى الالتزام المحدد وتحديث دليل العمل ومنطقة التدريج. اسمحوا لي أن أريكم مثالا آخر. حاليًا ، يبدو تصور التزاماتي كما يلي:

هنا ، سأقوم بتشغيل الأمر مع HEAD ^ ، مما يعني أنني أريد إعادة التعيين إلى الالتزام السابق (مرة أخرى).
$ git reset --hard HEAD^ HEAD is now at 0db602e one more commitيمكنك أن ترى أن مؤشر الرأس قد تغير الآن إلى 0db602e من d69950b.
$ git log --oneline 0db602e (HEAD -> master) one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test 
إذا قمت بفحص السجل ، فسيختفي التزام d69950b ، ويشير الرأس الآن إلى 0db602e SHA.
$ git log commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 Testإذا قمت بتشغيل ملفات ls ، فيمكنك رؤية file1.txt و file2.txt و files3.txt لم تعد موجودة في المستودع لأن هذا الالتزام وملفه تمت إزالتهما بعد إعادة التعيين الثابت.
$ git ls-files demo dummyfile newfileGit Soft Reset
وبالمثل ، سأعرض لك الآن مثالاً على إعادة تعيين ضعيف. ضع في اعتبارك ، لقد أضفت الملفات الثلاثة مرة أخرى كما هو مذكور أعلاه والتزمت بها. سيظهر سجل بوابة كما هو موضح أدناه. يمكنك أن ترى أن "إعادة الضبط الناعم" هي آخر التزام لي ، ويشير HEAD أيضًا إلى ذلك.
$ git log --oneline aa40085 (HEAD -> master) soft reset 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) testيمكن رؤية تفاصيل الالتزام في السجل باستخدام الأمر أدناه.
$ git log commit aa400858aab3927e79116941c715749780a59fc9 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 21:01:36 2020 +0530 soft reset commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 testالآن باستخدام إعادة الضبط الناعمة ، أريد التبديل إلى أحد الالتزامات القديمة باستخدام SHA 0db602e085a4d59cfa9393abac41ff5fd7afcb14

للقيام بذلك ، سوف أقوم بتشغيل الأمر أدناه. تحتاج إلى تمرير أكثر من 6 أحرف بداية من SHA ، فكلمة SHA الكاملة غير مطلوبة.
$ git reset --soft 0db602e085a4الآن عندما أقوم بتشغيل سجل git ، يمكنني رؤية إعادة تعيين HEAD إلى الالتزام الذي حددته.
$ git log commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 testلكن الاختلاف هنا هو أن ملفات الالتزام (aa400858aab3927e79116941c715749780a59fc9) حيث أضفت 3 ملفات لا تزال في دليل العمل الخاص بي. لم يتم حذفها. لهذا السبب يجب عليك استخدام إعادة ضبط بسيطة بدلاً من إعادة ضبط المصنع. لا يوجد خطر من فقدان الملفات في الوضع الناعم.
$ git ls-files demo dummyfile file1.txt file2.txt file3.txt newfileبوابة العودة
في Git ، يتم استخدام الأمر revert لإجراء عملية رجوع ، أي لعكس بعض التغييرات. إنه مشابه لأمر إعادة التعيين ، ولكن الاختلاف الوحيد هنا هو أنك تقوم بتنفيذ التزام جديد للعودة إلى التزام معين. باختصار ، من الإنصاف القول إن الأمر git revert هو التزام.
لا يحذف الأمر Git revert أي بيانات أثناء إجراء عملية الرجوع.
لنفترض أنني أقوم بإضافة 3 ملفات وإجراء عملية git الالتزام لمثال العودة.
$ git commit -m 'add 3 files again' [master 812335d] add 3 files again 3 files changed, 3 insertions(+) create mode 100644 file1.txt create mode 100644 file2.txt create mode 100644 file3.txtسيظهر السجل الالتزام الجديد.
$ git log --oneline 812335d (HEAD -> master) add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) testالآن أود العودة إلى أحد التزاماتي السابقة ، دعنا نقول - "59c86c9 التزام جديد". أود تشغيل الأمر أدناه.
$ git revert 59c86c9سيؤدي هذا إلى فتح ملف ، وستجد تفاصيل الالتزام الذي تحاول العودة إليه ، ويمكنك إعطاء اسمك الجديد هنا ، ثم حفظ الملف وإغلاقه.
Revert "new commit" This reverts commit 59c86c96a82589bad5ecba7668ad38aa684ab323. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch master # Your branch is ahead of 'origin/master' by 4 commits. # (use "git push" to publish your local commits) # # Changes to be committed: # modified: dummyfileبعد حفظ الملف وإغلاقه ، هذا هو الناتج الذي ستحصل عليه.
$ git revert 59c86c9 [master af72b7a] Revert "new commit" 1 file changed, 1 insertion(+), 1 deletion(-)الآن لإجراء التغييرات اللازمة ، على عكس إعادة التعيين ، أجرت عملية التراجع التزامًا جديدًا آخر. إذا قمت بفحص السجل مرة أخرى ، فستجد التزامًا جديدًا بسبب عملية الإرجاع.
$ git log --oneline af72b7a (HEAD -> master) Revert "new commit" 812335d add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test 
سيكون لسجل Git كل تاريخ الالتزامات. إذا كنت تريد إزالة الالتزامات من السجل ، فإن العودة ليست خيارًا جيدًا ، ولكن إذا كنت ترغب في الحفاظ على تغييرات الالتزام في السجل ، فإن الرجوع هو الأمر المناسب بدلاً من إعادة التعيين.
Git Rebase
في Git ، تعد rebase طريقة نقل أو دمج ارتباطات فرع واحد على فرع آخر. بصفتي مطورًا ، لن أقوم بإنشاء ميزاتي في الفرع الرئيسي في سيناريو العالم الحقيقي. سأعمل على الفرع الخاص بي ("فرع الميزة") ، وعندما يكون لدي بعض الالتزامات في فرع الميزات الخاص بي مع إضافة الميزة ، أود بعد ذلك نقله إلى الفرع الرئيسي.
قد يكون من الصعب أحيانًا فهم Rebase لأنها تشبه الدمج إلى حد كبير. الهدف من دمج وإعادة تأسيس كليهما هو أخذ الالتزامات من فرع الميزات الخاص بي ووضعها في فرع رئيسي أو أي فرع آخر. ضع في اعتبارك أن لدي رسمًا بيانيًا يبدو كالتالي:

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

سيعطيك هذا الأسلوب رسمًا بيانيًا نظيفًا بخط مستقيم مع جميع الالتزامات المتتالية.

إنه يجعل من السهل تتبع ما ذهب وأين يذهب. يمكنك أن تتخيل أنك إذا كنت في فريق يضم العديد من المطورين ، فإن جميع الالتزامات لا تزال متتالية. لذلك ، من السهل حقًا المتابعة حتى لو كان لديك العديد من الأشخاص الذين يعملون في نفس المشروع في نفس الوقت.
اسمحوا لي أن أريك هذا عمليا.
هكذا يبدو فرعي الرئيسي حاليًا. لديها 4 ارتباطات.
$ git log --oneline 812335d (HEAD -> master) add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) testسأقوم بتشغيل الأمر أدناه لإنشاء فرع جديد والتبديل إليه يسمى الميزة ، وسيتم إنشاء هذا الفرع من الالتزام الثاني ، أي 59c86c9
(master) $ git checkout -b feature 59c86c9 Switched to a new branch 'feature'إذا قمت بفحص السجل في فرع الميزات ، فإنه يحتوي على التزامين فقط قادمًا من الرئيسي (الخط الرئيسي).
(feature) $ git log --oneline 59c86c9 (HEAD -> feature) new commit e2f44fc (origin/master, origin/HEAD) testسوف أقوم بإنشاء الميزة 1 وألزمها بفرع الميزات.
(feature) $ vi feature1.txt (feature) $ git add . The file will have its original line endings in your working directory (feature) $ git commit -m 'feature 1' [feature c639e1b] feature 1 1 file changed, 1 insertion(+) create mode 100644 feature1.txtسوف أقوم بإنشاء ميزة أخرى ، أي الميزة 2 ، في فرع الميزة وألزمها.
(feature) $ vi feature2.txt (feature) $ git add . The file will have its original line endings in your working directory (feature) $ git commit -m 'feature 2' [feature 0f4db49] feature 2 1 file changed, 1 insertion(+) create mode 100644 feature2.txtالآن ، إذا قمت بفحص سجل فرع الميزة ، فسيكون لديه عملين جديدين ، وقد قمت بتنفيذهما أعلاه.
(feature) $ git log --oneline 0f4db49 (HEAD -> feature) feature 2 c639e1b feature 1 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) testالآن أريد إضافة هاتين الميزتين الجديدتين إلى الفرع الرئيسي. لذلك ، سأستخدم الأمر rebase. من فرع الميزات ، سأقوم بإعادة التعيين مقابل الفرع الرئيسي. ما سيفعله هذا هو أنه سيعيد تثبيت فرع الميزات الخاص بي مقابل أحدث التغييرات.
(feature) $ git rebase master Successfully rebased and updated refs/heads/feature.الآن أنا ذاهب للمضي قدمًا وتحقق من الفرع الرئيسي.
(feature) $ git checkout master Switched to branch 'master' Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits)وأخيرًا ، أعد تأسيس الفرع الرئيسي مقابل فرع الميزات الخاص بي. سيأخذ هذا الالتزامين الجديدين في فرع الميزات الخاص بي ويعيد تشغيلهما أعلى فرعي الرئيسي.
(master) $ git rebase feature Successfully rebased and updated refs/heads/master.الآن إذا تحققت من السجل في الفرع الرئيسي ، يمكنني رؤية الإلتزامين الخاصين بفرع الميزات الخاص بي تمت إضافتهما إلى الفرع الرئيسي بنجاح.
(master) $ git log --oneline 766c996 (HEAD -> master, feature) feature 2 c036a11 feature 1 812335d add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) testكان هذا كل شيء عن أوامر إعادة التعيين والعودة وإعادة تحديد القواعد في Git.
استنتاج
كان هذا كل شيء عن أوامر إعادة التعيين والعودة وإعادة تحديد القواعد في Git. آمل أن يكون هذا الدليل التفصيلي مفيدًا. الآن ، أنت تعرف كيفية اللعب مع التزاماتك حسب الحاجة باستخدام الأوامر المذكورة في المقالة.
