الـ Git Branch، آله السفر عبر الأبعاد
السلام عليكم ورحمة الله وبركاته
الفهرس
المقدمة
أظن أننا في المقالة السابقة أساسيات Git تحدثنا كثيرًا عن الـ branch
و main
لكن لا نفهم حقيقتهم بشكل جيد، لذا تاليًا سنتعمق في هذا العالم
لذا يمكنني أن أقول أننا الآن وصلنا لأهم المزايا التي يقدمها الـ Git
وهي فكرة الـ branch
لقد ذكرنا سابقًا أن Git
ينشيء سلسلة من الـ snapshot
وهي النسخ التي تسجل في الـ Local Repository
وهي ما نراه عندما ننفذ git log
فكل commit
ما هو إلا snapshot
أي نسخة من المشروع بها التعديلات التي حصلت في هذا الـ commit
دعونا نستخدم git log
ونرى حالة المشروع التي لدينا من المقالة السابقة
> git log --oneline
290f0eb (HEAD -> main) add article 3
9ebb273 add article 2
0035199 edit article 1
be7a504 delete xyz article again
cbbc411 add xyz article again
937637d delete xyz article
c2d77c1 add xyz article
6dc050b edit article 1
4032898 add new article to the blog
ستلاحظ شيء مهم وهو HEAD -> main
حسنًا الـ Git
عندما يبدأ عمله في ينشيء branch
من المشروع الخاص بنا وهذا الفرع هو الذي يضم سلسلة من الـ commit
و Git
تلقائيًا ينشيء فرع افتراضي ويسميه main
وقديمًا كان يسمى master
والفرع main
هو الذي يحتفظ بكافة الـ commit
التي ننشئها، فكل commit
رأيناه في الـ git log
تابع للـ main
والـ HEAD
كما عرفنا فهو مجرد مؤشر يشاور على commit
ما وغالبا ما يؤشر على آخر commit
حصل في الـ branch
لكن يمكننا تعديل مكانه ونجعله يشاور على commit
آخر كما فعلنا سابقًا
وأظنك لاحظت أنه كلما نقوم بعمل git status
يقول لك On branch main
بمعنى هذه حالة الملفات في الفرع main
ما هو الـ branch ؟
- الـ
branch
هو سلسلة من الـcommit
تكون متجمعة فيه وتنتمي إلى فرع معين - وعندما نقوم بعمل
git init
لاول مرة لمشروعنا يبدأGit
بعمل فرع فارغ يدعىmain
لا يحتوي على أيcommit
بعد - وهذا الـ
main
هو اسم الفرع الافتراضي للمشروع وكلما قمنا بعملcommit
يتم ضمه في الـmain
- مع أول
commit
يتم وضه في الـmain
يتم إنشاء الـHEAD
لأول مرة ليشاور عليه - يمكننا إنشاء أكثر من
branch
في المشروع الواحد من اجل التنظيم والاختبار وسنرى ذلك لاحقًا
الـ Branch
يمكننا أن نقول أنه من أهم مزايا الـ Git
لأنه يسمح لنا بعمل أكثر من نسخة للمشروع وكل نسخة في branch
مختلف
ويمكننا تقسيم العمل ضمن الفريق حيث يمكن لكل عضو العمل على نسخته من المشروع في فرع مختلف بشكل مستقل عن باقي الفريق
وفي المشاريع الكبيرة يكون الفرع الافتراضي والأساسي هو الـ main
أو master
قديمًا
وغالبًا ما يكون هو الفرع الذي يحتوي على النسخة المستقرة من المشروع الخاص بالـ Production
لذا لا يفضل على الاطلاق أن تقوم بعمل commit
بشكل مباشر في الـ main
بل ستجد أنه يفضل دائمًا عندما يتم العمل على إضافة جديدة او تعديل جديد او تصليح مشكلة يتم عمل نسخة من المشروع في branch
مستقل عن الـ main
وليكن اسمه development
ثم تقوم بعمل ما تريده فيه كاختبار التعديلات ومراجعتها
ثم عندما تشعر أن نسخة المشروع التي في الـ development
اصبحت مستقرة وتم اختبارها جيدًا وجاهزة للـ Production
يمكنك أن تدمجه في النهاية إلى الفرع الرئيسي main
يمكنك أن تنشيء عدة فروع مثل experiment
أو testing
و development
الأمر عائد إليك في كيفية تنظيم مشروعك واختباره وتنظيم العمل بين فريقك
اذ كان لديك فرق مختلفة فيمكن لكل فريق ان يكون له نسخته من المشروع في فرع معين من اجل ان يختبروا وينظموا العمل ما بينهم وبين اعضاء الفريق الواحد
ويمكن لكل عضو داخل الفريق الواحد ان يكون له فرع خاص به وفي النهاية يقوم بدمج تعديلاته في الفرع الكبير الخاص بفريقه
وهكذا من الافكار والاقتراحات والاساليب التي يمكنك ان تفعلها مع ميزة الـ Branch
في الـ Git
git branch
لنرى كل الـ branch
التي لدينا في المشروع نقوم بكتابة git branch -v
> git branch -v
* main 290f0eb add article 3
هنا يعرض لنا جميع الـ branch
التي لدينا في المشروع و -v
يعرض لك آخر commit
فيه والرسالة التوضيحية الخاصة بالـ commit
وعلامة *
تدل الـ HEAD
والفرع الذي نقف فيه حاليا ونحن حاليًا على main
حاليًا نحن لدينا فقط الـ main
في المشروع وسنرى مثالًا عمليًا على كيفية إنشاء اكثر من فرع وكيفية التعامل معها
الآن لننشيء branch
جديد نكتب git branch
ثم اسم الفرع
> git branch feature
أولًا، لنرى كل الـ branch
التي لدينا في المشروع
> git branch -v
feature 290f0eb add article 3
* main 290f0eb add article 3
لاحظ أنه الآن اصبح لدينا فرع جديد وهو feature
وعلامة *
كما قلنا فهي تدل على مكان الـ HEAD
وتدل على الفرع الذي نقف فيه حاليًا
ونحن حاليًا على main
وستلاحظ ان كلا من الـ main
و feature
لديهم نفس الـ commit
وهذا يدل أن feature
أشتق من الـ main
بالفعل
git switch branch-name
الآن نريد نحرك الـ HEAD
من الـ main
إلى الـ feature
ماذا نفعل ؟
ببساطة لدينا أمر متخصص لهذا وهو git switch
وتستطيع استخدام git checkout
لكن يفضل استخدام git switch
لتحريك الـ HEAD
بين الفروع
أي حال سنقوم بتنفيذ git switch feature
لنحرك الـ HEAD
من الـ main
إلى feature
> git switch feature
Switched to branch 'feature'
لنتأكد باستخدام git branch -v
> git branch -v
* feature 21c55c9 edit the content in file 1
main 21c55c9 edit the content in file 1
سترى أن *
على feature
لذا تأكدنا أن الـ HEAD
تحرك إلى الـ feature
فعًلا
عمل commit في الفرع الجديد feature
دعونا الآن نقوم بإضافة تعديل ما وليكن إنشاء ملف جديد وليكن اسمه article_4.txt
ثم نقوم بعمل git status
> git status
On branch feature
Untracked files:
(use "git add <file>..." to include in what will be committed)
article_4.txt
nothing added to commit but untracked files present (use "git add" to track)
لاحظ انه كتب لنا On branch feature
وقال لنا ان هناك ملف جديد Untracked
لذا سنقوم بعمل git add
لكي يقوم Git
بعمل tracked
له وأيضًا يضعه في الـ Staging
> git add article_4.txt
> git status
On branch feature
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: article_4.txt
الآن نقوم بعمل commit
مع رسالة جميلة
> git commit -m "add article number 4 to the blog"
[feature 123bdca] add article number 4 to the blog
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 article_4.txt
الآن لنشاهد كيف يبدو الـ git log
الخاص بنا
> git log --oneline
123bdca (HEAD -> feature) add article number 4 to the blog
290f0eb (main) add article 3
9ebb273 add article 2
0035199 edit article 1
be7a504 delete xyz article again
cbbc411 add xyz article again
937637d delete xyz article
c2d77c1 add xyz article
6dc050b edit article 1
4032898 add new article to the blog
أنظر الآن الـ feature
اصبح يقف على الـ commit
الجديد والـ main
مازال على القديم ولم يتأثر بأي شيء
لأن ما نقوم به في feature
يكون منفصل تماما عن الـ main
ولاحظ أن الـ HEAD
أصبح في الـ feature
ويشير على الـ commit
الذي فيه وليس الذي في الـ main
دعني أريك شيء سيبهرك قليلًا
> ls
article_1.txt article_2.txt article_3.txt article_4.txt
هذه هي المقالات التي في الـ feature
من ضمنهم المقالة الجديدة article_4.txt
التي أنشأناها للتو
الآن سننتقل إلى الـ main
> git switch main
Switched to branch 'main'
ونرى المقالات التي فيه
> ls
article_1.txt article_2.txt article_3.txt
سترى أن المقالة الرابعة article_4.txt
التي اضفناها ليست موجودة في الـ main
لاننا اضفناها في feature
وليس في الـ main
لانه كما قلنا ان التعديلات في الفرع الواحدة تكون مستقلة تمامًا عن باقي الفروع
git merge
لنفترض أننا قمنا بعمل تعديلات كثيرة في الـ feature
وتم اختبارها جيدًا واصبح مستقرًا وجاهز لوضع التعديلات التي فيه وندمجها في الـ main
هنا سنستخدم git merge
لدمج التعديلات، حاليًا الأمور بسيطة لذا سنقوم بعمل git switch main
ونحن حاليًا على الـ main
بالفعل
> git branch -v
feature 123bdca add article number 4 to the blog
* main 290f0eb add article 3
الـ HEAD
يقف على الـ main
الآن لدمج التعديلات من الـ feature
إليه نقول له git merge feature
> git merge feature
Updating 290f0eb..123bdca
Fast-forward
article_4.txt | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 article_4.txt
الآن كل التعديلات التي كانت في الـ feature
اصبحت متواجدها في الـ main
لاحظ انه كتب لنا أن عملية الدمج هذه نوعها Fast-forward
وهو نوع من انواع الدمج
يقوم فقط بتحريك الـ main
ويجعله يساوي الـ commit
الذي يقف عليه الـ feature
دون أن يقوم بعمل أي commit
جديد
> git branch -v
feature 123bdca add article number 4 to the blog
* main 123bdca add article number 4 to the blog
لاحظ كيف أن الـ main
اصبح لديه نفس الـ commit
التي كانت عند feature
أي git merge
قامت فقط بتحريك الـ main
وجعلته مساويًا للـ feature
دون أن تنشيء أي commit
جديد
لنتأكد من هذا عن طريق الـ git log
الخاص بنا
> git log --oneline
123bdca (HEAD -> main, feature) add article number 4 to the blog
290f0eb add article 3
9ebb273 add article 2
0035199 edit article 1
be7a504 delete xyz article again
cbbc411 add xyz article again
937637d delete xyz article
c2d77c1 add xyz article
6dc050b edit article 1
4032898 add new article to the blog
كما ترى الـ main
تحركت من الـ 290f0eb
إلى 123bdca
وهذا هو الـ fast forward merge
وهو ابسط الأنواع
هو يحدث بسبب أنه لم يتم إنشاء أي commit
جديد في الـ main
بعد إنشاءنا للـ feature
لكن اذا تم إنشاء commit
جديد في الـ main
والـ feature
لا يعرف عنه شيء هنا لا يتم تطبيق الـ fast forward merge
بطلب منك أن تقوم بعمل commit
جديد تمامًا يضم محتوى الدمج، وقد يحدث مشكلة شائعة وهي الـ Merge Conflict
مثال تطبيقي على مشكلة الـ Merge Conflict
لكن بالطبع يوجد انواع اخرى تجعل عملية الـ merge
معقدة قليلًا
لأنه غالبًا تحدث مشكلة شائعة جدًا تسمى merge conflict
وهي تحدث عندما تكون على سبيل المثال في الـ feature
وقمت بتعديل ملف article_1.txt
عملت commit
ثم رجعت على الـ main
وقمت أيضًا بتعديل نفس الملف article_1.txt
وعملت commit
الآن هناك تعديلات حصلت في الـ main
، والـ feature
لا يعلم عنها شيء والعكس كذلك، وقد تكون هذه التعديلات تتعارض مع بعضها البعض وهذا وارد وشائع جدًا جدًا في أي فريق عمل
وعندما تحاول دمج التعديلات الموجودة في الـ feature
والـ main
ستظهر مشكلة التعارض
بالتالي الـ Git
يحتار ولا يعرف أي من التعديلات يختار هل يختار التي على الـ feature
أم التي على الـ main
هنا تحدث الـ merge conflict
وتتطلب تدخل يدوي من اعضاء الفريق ليختاروا بشكل يدوي التعديلات الذي يريدونها
لنجرب الأمر بشكل عملي
> git switch feature
Switched to branch 'feature'
ثم نقوم بعمل تعديل ما على الملف article_4.txt
> git status
On branch feature
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: article_4.txt
no changes added to commit (use "git add" and/or "git commit -a")
الآن لنقم بعمل git add
ثم git commit
> git add article_4.txt
> git commit -m "update article 4 in feature"
[feature 21d665c] update article 4 in feature
1 file changed, 1 insertion(+)
الآن سنحصل لنرى الـ git log
> git log --oneline
21d665c (HEAD -> feature) update article 4 in feature
123bdca (main) add article number 4 to the blog
290f0eb add article 3
9ebb273 add article 2
0035199 edit article 1
be7a504 delete xyz article again
cbbc411 add xyz article again
937637d delete xyz article
c2d77c1 add xyz article
6dc050b edit article 1
4032898 add new article to the blog
الآن لننتقل إلى الـ main
ونقوم بتعديل نفس الملف
> git switch main
Switched to branch 'main'
نقوم بتعديل نفس الملف article_4.txt
> git status
On branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: article_4.txt
no changes added to commit (use "git add" and/or "git commit -a")
نقوم بعمل git add
ثم git commit
> git add article_4.txt
> git commit -m "update article 4 in main"
[main 6bde1e0] update article 4 in main
1 file changed, 1 insertion(+)
الآن الـ main
حصل فيها تعديلات والـ feature
لا يعرف عنها شيء والعكس صحيح
وعندما نقوم بدمج feature
على main
الـ Git
سيلاحظ أن الـ main
بها commit
ليس موجودًا في الـ feature
وأيضًا فوق هذا هناك تعديلات في الـ main
تتعارض مع التعديلات التي على feature
وهنا سيحدث الـ merge conflict
لكن انتبه لو كان الـ main
اضيف له تعديلات جديدة ليست موجودة في feature
لكنها لا تتعارض مع أي شيء داخله ولا مع التعديلات التي قام بها فلن يحدث أي merge conflict
عند الدمج
لكن في كلتا الحاليتين سيطلب منك القيام بعمل commit
جديد من اجل الـ merge
لنرى الـ git log
> git log --oneline --graph --all
* 6bde1e0 (HEAD -> main) update article 4 in main # <--- edit same file as in feature
| * 21d665c (feature) update article 4 in feature # <--- edit same file as in main
|/
* 123bdca add article number 4 to the blog
* 290f0eb add article 3
* ...
* ...
* 4032898 add new article to the blog
لاحظ أن هناك فرعين مختلفين يخرجان من نفس الـ commit
الـ 123bdca
الآن لنحاول القيام بعمل git merge feature
ونرى ما الذي سيحدث
> git merge feature
Auto-merging article_4.txt
CONFLICT (content): Merge conflict in article_4.txt
Automatic merge failed; fix conflicts and then commit the result.
ستلاحظ أن عملية الدمج لم تكتمل وحصل الـ Merge Conflict
الذي تحدثنا عنه
ستلاحظ أنه يخبرك بأن تحل المشكلة بنفسك بشكل يدوي وتقوم بعمل commit
بعد انتهائك
حتى أن ذهبت لتتفقد ماذا يقول لك git status
> git status
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: article_4.txt
no changes added to commit (use "git add" and/or "git commit -a")
ستجده يكرر لك نفس الأمور وأن عليك حل المشكلة ثم تقوم بعمل git add
ثم git commit
وان كنت تريد التراجع عن عملية الـ merge
فقط قم بعمل git merge --abort
الآن سنضطر لفتح الملف article_4.txt
الذي به التناقض
ستجد أن الملف تم التعديل عليه من قبل Git
وستجده يقسم لك الملف والتعديلات ويقول لك أن هذه التعديلات من feature
و هذه التعديلات من main
وأنه محتار لذا أنت الذي ستختار وتقبل اي تعديل من الاثنين
عندما تفتح الملف ستجد الاجزاء التي بها التعديلات المتعارضة بهذا الشكل
<<<<<<< HEAD
update article 4 in main
=======
update article 4 in feature
>>>>>>> feature
وكما قلنا فإن Git
هو من قام بتعديل الملف بهذا الشكل
ليعرض لك ويقسم لك الاجزاء المختلفة التي تحتاج تدخل يدوي منك
ستجد أن القسم الذي في الأعلى هي التعديلات التي في الـ HEAD
أي المكان الذي أنت فيه الآن وهو الـ main
والقسم الذي في الأسفل هي التعديلات التي كانت في الـ feature
وقد تلاحظ أن القسم الذي في الأعلى يطلق عليه Current Change
لانها التعديلات التي في الـ HEAD
المكان الذي أنت فيه حاليًا
والقسم الذي في الأسفل يطلق عليه Incoming Change
لانها التعديلات التي تحاول أن تدمجها في الـ HEAD
والقادمة من الـ feature
لاننها نفذنا git merge feature
والتي تعني أحضر التعديلات التي في الـ feature
وادمجها في المكان الذي أنا فيه حاليًا وهو الـ main
في هذه الحالة
حسنًا بعد ما تختار التعديلات التي تريدها وتقوم ببعض التعديلات الاضافية إن أردت ذلك
ثم بعد ما تقوم بحل كل التعارضات وتختار تقوم بعمل git add
ثم git commit
> git add article_4.txt
الآن لنرى git status
ماذا سيقول لنا عند هذه النقطة
> git status
On branch main
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: article_4.txt
كما ترى يقول لكم ان عملية الدمج شارفت على الانتهاء ولا يوجد أي ملف يحتوي على أي تعارض
تبقى فقط أن تقوم بعمل git commit
لتنتهي عملية الدمج وتضع التعديلات التي نتجت عن عملية الدمج في commit
جديد
> git commit -m "merge feature into main, and fix the merge conflict"
[main 55395bb] merge feature into main, and fix the merge conflict
الآن لننظر إلى شكل الـ git log
كيف اصبح
> git log --oneline --graph --all
* 55395bb (HEAD -> main) merge feature into main, and fix the merge conflict
|\
| * 21d665c (feature) update article 4 in feature
* | 6bde1e0 update article 4 in main
|/
* 123bdca add article number 4 to the blog
* 290f0eb add article 3
* ...
* ...
* 4032898 add new article to the blog
الآن كما تلاحظ لقد تم دمج التعديلات الموجودة في feature
و main
في commit
جديد والذي يقف عليه الـ HEAD
حاليًا
لاحظ أيضًا كيف أن الـ main
و feature
اشتقوا من commit
مشترك وهو 123bdca
ثم قام main
بعمل commit
جديد وهو 6bde1e0
وقام feature
بعمل commit
جديد وهو 21d665c
الآن عندما نريد أن ندمج feature
على الـ main
فهنا لا يمكن تنفيذ الـ fast forward merge
فلا يمكن جعل الـ feature
يؤشر على الـ commit
الخاص بالـ main
ببساطة لان كلاهما لديه تعديلات و commit
ليست عند الآخر
فهنا نحن مضطرين بإنشاء commit
جديد تمامًا يضم التغيرات المختلفة في كلاهما بغض النظر عن ان كانت فيها تعارض ام لا
لذا تم دمجهما في commit
جديد وهو 55395bb
كما رأيت
وهذا النوع من الدمج يسمى three way merge
git rebase branch-name
الـ rebase
يحتوي على العديد من الوظائف والمميزات منها مقدرته على
- نقل كل الـ
commit
من فرع معين إلى فرع آخر - إعادة ترتيب الـ
commit
بحيث أنه يستطيع استبدال وتغيرcommit
معcommit
آخر - ويمكنه حذف
commit
قديم من المشروع ليصبح كأنه لم يكن موجودًا من قبل
ملحوظة
: الـgit rebase
تأثيراته تعدل وتغير في الـLocal Repository
بشكل مباشر
لذا كن حذرًا جدًا جدًا جدًا في استخدامه لانه كما ترى فأنه يغير ويستبدل ويعدل ويحذفcommit
بشكل مباشر
حسنًا لنرى كيف يبدو شكل الـ git log
الذي لدينا
> git log --all --oneline --graph
* 43831b9 (HEAD -> main) edit article 3
* 403dff2 edit article 2
* 5395b85 edit article 1 again
| * 457df97 (feature) add article 7
| * eca79bc add article 6
| * 333ef33 add article 5
|/
* 123bdca add article number 4 to the blog
* 290f0eb add article 3
* ...
* ...
* 4032898 add new article to the blog
لاحظ هنا أن الـ main
و feature
يخرجان من commit
مشترك وهو 123bdca
وكل واحد قام بإنشاء عدة commit
مختلفة عن الآخر
اذا قمنا بعمل git merge
فسوف يقوم بعمل commit
جديد ويضم التعديلات التي في الفرعين feature
و main
مثل ما رأينا
لكن في حالة rebase
فسوف يقوم بنقل كل الـ commit
من فرع معين إلى فرع آخر
بمعنى لو قلنا اننا نريد عمل rebase
من feature
إلى main
فسوف ينقل كل الـ commit
التي انشأناها في feature
ويضمها إلى main
كما لو كأننا لم ننشيء feature
من الأساس وكأننا انشأنا الـ commit
داخل الـ main
من البداية
لنرى هذا بشكل عملي، نحن الآن في الـ main
وسنقوم بعمل rebase
للـ feature
> git rebase feature
Successfully rebased and updated refs/heads/main.
الآن كل الـ commit التي كانت في feature
أصبحت كأنها تم انشاءها في الـ main
من البداية
> git log --all --oneline --graph
* 05ba00e (HEAD -> main) edit article 3
* 1d3b069 edit article 2
* 40c0158 edit article 1 again
* 457df97 (feature) add article 7 # the commit moved to main branch
* eca79bc add article 6 # the commit moved to main branch
* 333ef33 add article 5 # the commit moved to main branch
* 123bdca add article number 4 to the blog
* 290f0eb add article 3
* ...
* ...
* 4032898 add new article to the blog
لاحظ هنا أن الفرع feature
و main
دمجوا مع بعض ليصبحوا فرع واحد
ولاحظ أنه كما قلنا فإن كل الـ commit
الموجود في الفرع feature
تم نقلها ودمجها كما هي
ستلاحظ أيضًا أن git rebase
قام بتعديل اماكن بعض الـ commit
أو استبدالها وتغيرها
لكي يقوم بدمج كل شيء بسلاسة كما رأيت
لذا انتبه عندما تستخدمه لأن تأثيراته تعدل وتغير في الـ Local Repository
بشكل مباشر
لانه كما ترى فأنه يغير ويستبدل ويعدل ويحذف commit
بشكل مباشر
حل الـ merge conflict أثناء عملية الـ rebase
حسنًا ماذا يحدث عندما يكون هناك merge conflict
؟ كيف سيتعامل git rebase
مع هذه الحالة ؟
> git log --all --oneline --graph
* 2224b49 (HEAD, main) edit article 1 again
* 6bde1e0 update article 4 in main # <--- edit article 4 in main
| * ed3c633 (feature) add article 7
| * ed26c57 add article 6
| * d169f4a add article 5
| * 21d665c update article 4 in feature # <--- edit article 4 in feature
|/
* 123bdca add article number 4 to the blog
* 290f0eb add article 3
* ...
* ...
* 4032898 add new article to the blog
هنا سنفترض أن هناك commit
في feature
يتعارض commit
مع main
كما ترى
الآن سنقوم بعمل git rebase feature
> git rebase feature
Auto-merging article_4.txt
CONFLICT (content): Merge conflict in article_4.txt
error: could not apply 6bde1e0... update article 4 in main
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 6bde1e0... update article 4 in main
كما ترى أن rebase
قام بتحذيرنا بأن هناك تعارض أي حصل merge conflict
ويخبرنا ببعض التعليمات مثل أن عليك حل المشكلة يدويًا
وعند انتهائنا نقوم بعمل git add
للملفات التي قمت بحل التعارض التي بها ثم استكمال عملية الـ rebase
بتنفيذ git rebase --continue
أو يمكنك التراجع عن عملية الـ rebase
والعودة للحالة التي كنت عليها فقم بتنفيذ git rebase --abort
لنرى شكل الـ git log
الآن
> git log --all --oneline --graph
* 2224b49 (main) edit article 1 again
* 6bde1e0 update article 4 in main
| * ed3c633 (HEAD, feature) add article 7
| * ed26c57 add article 6
| * d169f4a add article 5
| * 21d665c update article 4 in feature
|/
* 123bdca add article number 4 to the blog
* 290f0eb add article 3
* ...
* ...
* 4032898 add new article to the blog
سترى أنه بالفعل لا شيء حدث حتى الآن لان عملية الـ rebase لم تنتهي بعد
ستلاحظ شيء وهو الـ HEAD
تغير وأصبح يشاور على feature
وهذا بسبب أنه في وسط عملية الـ rebase
وعندما تفقد الـ feature
وجد أن هناك تعارض لذا هو منتظر هناك لغاية من تقوم بحل الـ merge conflict
ثم تستكمل عملية الـ rebase
الآن لنرى ماذا يقول لك الـ git status
> git status
interactive rebase in progress; onto ed3c633
Last command done (1 command done):
pick 6bde1e0 update article 4 in main
Next command to do (1 remaining command):
pick 2224b49 edit article 1 again
(use "git rebase --edit-todo" to view and edit)
You are currently rebasing branch 'main' on 'ed3c633'.
(fix conflicts and then run "git rebase --continue")
(use "git rebase --skip" to skip this patch)
(use "git rebase --abort" to check out the original branch)
Unmerged paths:
(use "git restore --staged <file>..." to unstage)
(use "git add <file>..." to mark resolution)
both modified: article_4.txt
فستراه يقول لك نفس الشيء، بأنك الآن في وسط عملية rebase
لم تنتهي منها بعد
ويوجد merge conflict
تحتاج لتدخل منك لحله ثم تنفيذ git rebase --continue
لاستكمال العملية
أو يمكنك التراجع بتنفيذ git rebase --abort
وإن أردت التخلص من الـ commit
الذي به التعارض يمكنك تنفيذ git rebase --skip
ومعناه أن الـ HEAD
حاليًا يشير على feature
ووجد أن هناك commit
الـ main
يتعارض مع ما هو موجود في feature
لذا ب تنفيذ git rebase --skip
فهو سيحذ ويتخلص من الـ commit
الذي في الـ main
ويبقى على التعديلات التي في feature
كما هي
لأن الـ HEAD
موجود في الـ feature
اثناء عملية الـ rebase
والتعارض بالنسبة له أتى من الـ main
لذا --skip
تتخلص من هذا التعارض الذي أتي من الـ main
وتحذف الـ commit
الخاص بالـ main
كأنه لم يكن موجود
سنقوم بهذا يدويًا وسنفتح الملف article_4.txt
الذي فيه التعارض ونحاول ان نختار ونعدل
<<<<<<< HEAD
update article 4 in feature
=======
update article 4 in main
>>>>>>> 6bde1e0 (update article 4 in main)
وكما عرفنا فإن Git
سيعرض لك ويقسم لك الاجزاء المختلفة التي تحتاج تدخل يدوي منك
ستجد أن القسم الذي في الأعلى تمثل الـ HEAD
وكما عرفنا فهو الآن في الـ feature
حاليًا
والقسم الذي في الأسفل ستكون بالطبع التعديلات القادمة من الـ main
التي تسبب التعارض من وجه نظر الـ HEAD
حسنًا بعد ما تختار التعديلات التي تريدها وتقوم ببعض التعديلات الاضافية إن أردت ذلك
ثم بعد ما تقوم بحل كل التعارضات وتختار تقوم بعمل git add
ثم git commit
> git add article_4.txt
الآن لنرى git status
ماذا سيقول لنا عند هذه النقطة
> git status
interactive rebase in progress; onto ed3c633
Last command done (1 command done):
pick 6bde1e0 update article 4 in main
Next command to do (1 remaining command):
pick 2224b49 edit article 1 again
(use "git rebase --edit-todo" to view and edit)
You are currently rebasing branch 'main' on 'ed3c633'.
(all conflicts fixed: run "git rebase --continue")
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: article_4.txt
كما ترى يقول لنا أننا مازلنا في منتصف عملية الـ rebase
ولا يوجد أي ملف يحتوي على أي تعارض، تبقى فقط أن تقوم بعمل git commit
لتنتهي عملية الدمج وتضع التعديلات التي نتجت عن عملية الدمج في commit
جديد
ثم نقوم بتنفيذ git rebase --continue
لاستكمال وانهاء عملية الـ rebase
> git commit -m "fix merge conflict during rebase"
[detached HEAD 7d7ddae] fix merge conflict during rebase
1 file changed, 4 insertions(+)
الآن لننظر إلى شكل الـ git log
كيف اصبح
> git log --all --oneline --graph
* 7d7ddae (HEAD) fix merge conflict during rebase
* ed3c633 (feature) add article 7
* ed26c57 add article 6
* d169f4a add article 5
* 21d665c update article 4 in feature
| * 2224b49 (main) edit article 1 again
| * 6bde1e0 update article 4 in main
|/
* 123bdca add article number 4 to the blog
* 290f0eb add article 3
* ...
* ...
* 4032898 add new article to the blog
الآن تم انشاء commit
جديد يضم نتيجة حل الـ merge conflict
وأخيرًا لننهي عملية الـ rebase
بتنفيذ git rebase --continue
> git rebase --continue
Successfully rebased and updated refs/heads/main.
الآن لنرى الـ git log
> git log --all --oneline --graph
* d480bc6 (HEAD -> main) edit article 1 again
* 7d7ddae fix merge conflict during rebase
* ed3c633 (feature) add article 7
* ed26c57 add article 6
* d169f4a add article 5
* 21d665c update article 4 in feature
* 123bdca add article number 4 to the blog
* 290f0eb add article 3
* ...
* ...
* 4032898 add new article to the blog
سترى أن عملية الـ rebase
تم بنجاح وما كان في الـ feature
تم ضمه إلى الـ main
وتم حل أي merge conflict
خاتمة
الآن أصبح لديك معرفة جيدة عن مفهوم الـ Branch
في الـ Git
حيث أنها تساعدنا عن إنشاء عدة نسخ من المشروع تقسم العمل ضمن الفريق
أحب أن اراجع أهم النقاط هنا:
- استخدام الأمر
git branch
لإضافةbranch
جديد - استخدام الأمر
git switch
للتنقل ما بين الـbranch
المختلفة - استخدام الأمر
git merge
لدمج الفروع مع بعضها - التعامل مع مشكلة الـ
merge conflict
في المقالة التالية سنتكلم الـ Remote Repository
وسنشرح مفاهيم وأوامر جديدة تتعلق بهذا العالم الآخر
ويمكنكم قراءتها من هنا الـ Git Remotes، وما علاقة الـ GitHub بالـ Git ؟