الـ Git Branch، آله السفر عبر الأبعاد

السلام عليكم ورحمة الله وبركاته

وقت القراءة: ≈ 20 دقيقة (بمعدل فنجان واحد من الشاي 😊)

المقدمة

أظن أننا في المقالة السابقة git basics تحدثنا كثيرًا عن الـ 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 يمكننا أن نقول أنه من أهم مزايا الـ 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 وادمجها في المكان الذي أنا فيه حاليًا

حسنًا بعد ما تختار التعديلات التي تريدها وتقوم ببعض التعديلات الاضافية إن أردت ذلك
ثم بعد ما تقوم بحل كل التعارضات وتختار تقوم بعمل 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 يحتوي على العديد من الوظائف والمميزات منها مقدرته على

ملحوظة: الـ 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
حيث أنها تساعدنا عن إنشاء عدة نسخ من المشروع تقسم العمل ضمن الفريق

أحب أن اراجع أهم النقاط هنا:

في المقالة التالية سنتكلم الـ Remote Repository وسنشرح مفاهيم وأوامر جديدة تتعلق بهذا العالم الآخر ويمكنكم قراءتها من هنا git with remote repository