ملخص Git

صورة غلاف ملاحظات Git

Git:

  • ليس GITHUB
  • هو نظام مراقبة إصدارات موزع (VCS)
  • يتتبع التغييرات في مستودعات محددة (repo)
  • يساعد في إدارة الإصدارات بفعالية

مصطلحات Git

Repo:
يحتوي على ملفات المشروع عن بُعد/المحلية وسجله.
staging area:
حيث تكون الملفات جاهزة للتسجيل.
commit:
لقطة للحالة الحالية لمشروعك.
branch:
مؤشر قابل للنقل إلى التسجيل.
Clone:
نسخة مكررة من مستودع بعيد.

تنزيل Git:

Git مثبت مسبقًا في Mac و Linux

git --version # تحقق من وجود git

رابط التنزيل: https://git-scm.com/downloads

الإعدادات:

تعيين القيم:

git config set --global user.name ”idriss“
git config set --global user.email[email protected]   
git config set --global core.editor ”code“ # المحرر الافتراضي الذي سيستخدمه git لرسائل الالتزام، إلخ. (vim، nano، ...)

الحصول على القيم:

git config list # سرد جميع التكوينات
git config get user.name

حذف القيم:

git config unset user.name # حذف متغير

تحرير ملف التكوين مباشرة

git config edit --global # يفتح المحرر الافتراضي (core.editor) لتحرير ملف التكوين مباشرةً، وهو موجود في `.git/config` للتكوين المحلي، وفي `~/.gitconfig` أو `C:\\Users\\YourName\\.gitconfig` للتكوين العام.

سير عمل Git:

1. تهيئة مستودع

git init # تهيئة مستودع محلي جديد
git clone <remote-repo-url> # استنساخ مستودع بعيد موجود

سيُنشئ git مجلدًا مخفيًا باسم .git؛ سيؤدي حذفه إلى إلغاء تهيئة المستودع.

2. إجراء التغييرات

  • إنشاء الملفات: touch index.html script.js test.txt
  • تحرير الملفات: echo console.log(”hello git!“) > script.js
  • حذف الملفات: rm test.txt

3. إجراء التغييرات:

git add <file> [...<file>] # لتحديد الملفات التي سيتم إجراؤها
git add . # لإجراء جميع الملفات في المستودع الحالي

4. الالتزام بالتغييرات:

التقاط لقطة من الملفات الحالية التي تم إجراؤها

git commit -m ”message“
git log # لتتبع سجل الالتزامات

5. دفع التغييرات:

لمزامنة المستودع البعيد مع التزاماتك المحلية

git remote add origin <remote-repo-url> # أشر إلى الأصل إلى عنوان URL للمستودع البعيد، مثل الاسم المستعار حتى لا نكتب عنوان URL بالكامل في كل مرة
git push --set-upstream origin <branch> # أو:
git push -u origin <branch-name>

الفروع:

الفرع هو مؤشر قابل للتحريك إلى التزام معين في المستودع

git branch # سرد جميع الفروع المحلية
git branch -avv # سرد جميع الفروع
git branch <اسم الفرع> # إنشاء فرع
git switch -c <اسم الفرع> # إنشاء فرع والتبديل إليه
git checkout -b <اسم الفرع> # نفس ما سبق (صيغة قديمة)

الدمج

إعادة مزامنة فرعين عن طريق دمج التغييرات من أحدهما إلى الآخر.

  • الفرع الذي أنت عليه هو الفرع الذي تجلب إليه التغييرات الأخرى
git merge <اسم الفرع المستهدف>
git branch -d <اسم الفرع> # حذف فرع
  • هذا لا يحذف أي التزامات؛ إنه يحذف فقط ”تسمية“ الفرع بحيث لا يمكنك استخدامه بعد الآن. لا يزال بإمكانك استخدام جميع الالتزامات.
  • فرع الموضوع هو ما نسميه فرعًا محليًا تم إنشاؤه لموضوع واحد، مثل ميزة أو إصلاح خطأ، إلخ.
git branch -D topic1
  • حذف فرع محدد في Git بالقوة، حتى إذا كان يحتوي على تغييرات لم يتم دمجها

إعادة تعيين Git

التراجع عن التغييرات السابقة في المستودع المحلي (إعادة كتابة السجل)

أنواع إعادة التعيين:

  • soft: ينقل HEAD إلى الالتزام المستهدف ولكنه يحتفظ بجميع التغييرات المعدة -> ”جاهزة للالتزام“
  • mixed: (افتراضي) ينقل HEAD إلى الالتزام المستهدف ويلغي إعداد التغييرات -> ”تم تعديلها“
  • hard: ينقل HEAD إلى الالتزام المستهدف ويتخلص من جميع التغييرات؛ ستختفي جميع التغييرات.
git reset --soft <commit-hash> # إعادة تعيين الالتزام مع الاحتفاظ بالملفات مرحلية
git reset --mixed <commit-hash> # الافتراضي
git reset <commit-hash> # إلغاء وضع التغييرات في مرحلة التجهيز بعد الالتزام المحدد
git reset --hard <commit-hash> # تجاهل التغييرات بعد الالتزام المحدد

Git Revert:

مشابه لـ reset ولكنه يحتفظ بالسجل (لا يغير التاريخ) ويقوم بإنشاء التزام جديد.

git revert <commit-hash> [...<commit-hash>] # إعادة التزام واحد أو عدة التزامات مع التزام إعادة لكل واحد منها

خيار —no-commit يمنع الالتزام التلقائي

git revert -n <commit-hash> 
git revert <oldest-commit>^..<newest-commit> # التراجع عن مجموعة من الالتزامات
git revert --continue # بعد إصلاح تعارض الدمج (مشابه لـ rebase)

العودة بالزمن إلى الوراء

HEAD هو مؤشر إلى الحالة الحالية لمستودعك. بشكل افتراضي، يشير إلى فرع، ولكنه يمكن أن يشير أيضًا مباشرة إلى التزام في حالة منفصلة.

git switch --detach <commit-hash>

أعد إرفاق HEAD بالفرع الرئيسي. هناك خياران:

git switch - # هذا ينتقل إلى المكان الذي كنا فيه قبل ذلك، وهو في هذه الحالة الفرع الرئيسي.
git switch main # هذا ينتقل بشكل صريح إلى الفرع الرئيسي.
git checkout main # باستخدام صيغة checkout القديمة

الالتزامات المتعلقة بـ HEAD

للعودة إلى الالتزام السابق:

git switch --detach HEAD^
git switch --detach @^  # @ هو نفسه HEAD

للعودة إلى الالتزام الثالث السابق

git switch --detach HEAD^^^
git switch --detach HEAD~3

الدفع

git push <remote-alias> <remote-branch>

التتبع عن بُعد

git remote -v # سرد جميع الأجهزة البعيدة

تغيير عنوان URL البعيد

git remote set-url <remote-name> <url>

إضافة جهاز بعيد

git remote add <remote-name> <url>

تعيين فرع upstream (يربط الفرع المحلي بالفرع البعيد):

git push --set-upstream origin main
git push -u origin main              # نفس الشيء، اختصار

بعد تعيين upstream، يمكنك ببساطة تشغيل:

git push

تنظيف فروع التتبع البعيدة التي لم تعد موجودة على البعيد:

git fetch --prune
git fetch --prune <some-remote> # تقليم بعيد محدد
git fetch --prune --all # تقليم جميع البعيد

حذف فرع التتبع البعيد المحلي:

git branch -dr <remote>/<branch> # -d حذف -r بعيد

حذف الفرع من البعيد

git push <some-remote> --delete <branch-name>

حالة الملف

git status
  • غير متتبع: Git لا يعرف أي شيء عن هذا الملف ($ git add <file-name> للتجهيز أو إضافته في .gitignore لتجاهله)
  • غير معدل
  • معدل
  • مجهز: الملفات الجاهزة للتسجيل (git commit أو git restore --staged : إزالة من المرحلة والعودة إلى الحالة المعدلة)

.gitignore

ملف نصي يسرد جميع الملفات والدلائل التي يجب أن يتجاهلها Git.

الصيغة والقواعد:

  • الأسطر التي تبدأ بـ # هي تعليقات
  • البادئة ! تنفي النمط، وتعيد تضمين أي ملف مطابق تم استبعاده بواسطة نمط سابق
  • يتم دعم أحرف البدل (*، ?، [])
  • تحدد علامة / في النهاية دليلًا
  • تجعل علامة / في البداية النمط نسبيًا بالنسبة لجذر المستودع

أمثلة:

*.tmp
*.sw[op]

# ما سبق هو نفسه

*.tmp
*.swo
*.swp

تجاهل ملفات HTML التي تم إنشاؤها، باستثناء foo.html:

*.html
!foo.html

الأنماط الشائعة:

# تجاهل جميع الملفات في دليل
node_modules/

# تجاهل ملف معين في الجذر فقط
/config.local

# تجاهل النمط في أي مكان في الشجرة
**/*.log

# تجاهل جميع ملفات .txt في الدليل doc/ والدلائل الفرعية
doc/**/*.txt
قائمة GitHub لملفات .gitignore

المقارنة

يعرض الفرق بين ملفين أو التزامين.

git diff  # يقارن شجرة العمل والفهرس (منطقة التجهيز)
git diff --staged #  يقارن المرحلة مع الالتزام السابق
git diff <commit-hash> <commit-hash> # يقارن التزامين
git diff HEAD~4 HEAD~3
git diff HEAD~3^!          # نفس الشيء (^! تعني ”عملية الالتزام هذه مقابل عملية الالتزام الأصلية“)

التنسيق:

git diff -U5 # يعرض 5 أسطر من السياق حول التغييرات (الافتراضي هو 3)
git diff --name-only # يسرد فقط أسماء الملفات التي تم تغييرها

$ git diff -w #  التعامل مع عدم اتساق التنسيق
$ git diff --ignore-all-space # نفس الشيء

مقارنة ملفات محددة:

git diff -- <file> [...] # مقارنة ملفات محددة
git diff <branch-or-commit> -- <file> [...]
git diff <branch-or-commit> <branch-or-commit> -- <file> [...] # الملفات بين الالتزامات
git diff *.py # مقارنة الملفات التي تطابق نمطًا معينًا
A---B---C---D  (فرع1)
      \
        E---F---G  (فرع2)
git diff branch1...branch2 # كل ما أضافه الفرع2 منذ الانقسام == git diff B branch2

إعادة التسمية

باستخدام أوامر نظام الملفات العادية:

mv old.txt new.txt
  • لا يعلم Git أنك قمت بذلك حتى تقوم بـ git add -A (تجهيز التغييرات).
  • يرى Git ”حذف ملف“ + ”إنشاء ملف جديد“.

باستخدام أمر إعادة التسمية في Git:

git mv old.txt new.txt
  • يقوم نظام الملفات بإعادة تسمية الملف و وضعه في مرحلة إعادة التسمية في فهرس Git في خطوة واحدة.
  • يعرف Git بشكل صريح: ”تمت إعادة تسمية هذا الملف“.

إعادة تسمية الملف إلى اسمه القديم سوف يلغي التغيير:

git mv new.txt old.txt

الإزالة

git rm file.txt
  • يزيل الملف من دليل العمل ويضع الحذف في مرحلة التجهيز على الفور.

لاستعادة الملفات المحذوفة غير الملتزم بها

  1. git restore --staged file.txt ينتقل الملف من حالة التجهيز إلى حالة التعديل (لا يزال غير معروض في الدليل)
  2. git restore file.txt ينتقل الملف إلى حالة عدم التعديل (الآن تم إلغاء حذفه)

لاستعادة الملفات المحذوفة من التزام قديم

1. ابحث عن الالتزام المستهدف

git log -- <file-name> # يسرد جميع الالتزامات التي تم فيها تغيير هذا الملف

git log --name-only # إذا نسيت اسم الملف

2. استعادة الملف

git restore --source=<commit-hash> <file-name>

إعادة التأسيس

لا تقم أبدًا بإعادة تأسيس أي شيء قمت بدفعه

يسمح للمطورين بدمج التغييرات من فرع إلى آخر. يوفر سجل مشروع أنظف وأكثر خطية مقارنة بالدمج، مما يسهل تتبع التغييرات وفهم تطور قاعدة الكود.

A---B  (main)
  \
    E---F  (topic)

سيؤدي تشغيل $ git rebase main أثناء وجودك في فرع الموضوع إلى تغيير السجل ليصبح كما يلي:

A---B  (رئيسي) ---E'---F'  (موضوع)

يؤدي تشغيل $ git pull إلى ما يلي:

git fetch                 # الحصول على جميع المعلومات من الأصل
git merge origin/main    # دمج origin/main في الرئيسي

لإعادة التأسيس بدلاً من الدمج أثناء السحب:

git pull --rebase

أو تعيينه ليكون الإعداد الافتراضي:

git config set --global pull.rebase true

التعارضات في إعادة التأسيس:

لحل تعارض إعادة التأسيس:

  1. قم بتحرير الملف المتعارض وجعله صحيحًا.
  2. قم بتجهيزه. (git add .)
  3. تابع إعادة التأسيس. (git rebase --continue)

إعادة التأسيس التفاعلية

تسمح بالتعديل التفاعلي لسجل الالتزام (الضغط، التحرير، إعادة الترتيب)

git rebase -i <base>  # <base> هو الالتزام قبل النطاق الذي تريد تعديله

Git stash

حفظ التغييرات غير الملتزم بها مؤقتًا دون الالتزام بها (ميزة WIP)

git stash # دفع التغييرات إلى مكدس stash
git stash list # عرض العناصر الموجودة في stash
git stash pop # تطبيق آخر التغييرات من مكدس stash وإزالتها من المكدس.
git stash pop stash@{0} # نفس ما سبق
git stash apply <stash> # تطبيق تغييرات المخزن مع الاحتفاظ بها في المكدس
  • <stash>: على سبيل المثال، stash@1 أو —index 1
git stash drop [<stash>] # إخراج التغييرات المخزنة الأخيرة وتجاهلها إذا لم يتم تحديد أي مخزن
  • يجب عليك تجهيز الملفات التي تم تغييرها ( git add ) قبل تخزينها مؤقتًا.
  • الجزء العلوي من المكدس هو stash@{0}
  • في حالة وجود تعارض، ستظل التغييرات المخزنة مؤقتًا في المخزن المؤقت!

سجل المراجع (reflog)

يتتبع reflog الخطوات وراء كل تغيير (بما يتجاوز git log)؛ وهو مفيد عند الاستعادة من **إعادة تعيين خاطئة. **

git reflog # الحصول على هاش الالتزام المفقود
git branch <new-branch-name> <commit-hash>  # إنشاء فرع جديد من ذلك الالتزام لاستعادته

وضع التصحيح: تغييرات جزئية

يتيح لك وضع التصحيح تحديد القطع (مجموعة من التغييرات القريبة) التي سيتم العمل عليها.

تتضمن الأوامر التي تستخدم -p add وreset وstash وrestore وcommit وغيرها.

git add -p # سيسألك عن القطعة التي تريد وضعها في مرحلة التجهيز وتلك التي تريد تجاهلها
git reset -p <commit-hash> # هذه ليست إعادة تعيين صارمة أو مرنة أو مختلطة!

Cherry-Picking

Cherry-picking يعني اختيار التزام من فرع واحد وتطبيقه على فرع آخر.

git cherry-pick <commit-hash> # من الفرع الوجهة
git cherry-pick --continue # بعد حل تعارضات cherry-pick

Blame

Blame يظهر لك من قام بتغييرات معينة، حتى تعرف من تلوم!

git blame [options] <file-name>

خيارات مفيدة:

  • -L <start>,<end>: تحديد نطاق الأسطر
  • -M: اكتشاف الأسطر التي تم نقلها أو نسخها داخل نفس الملف، والإبلاغ عن المؤلف الأصلي للأسطر بدلاً من آخر مؤلف قام بنقل أو نسخ الأسطر
  • -C: اكتشاف الأسطر التي تم نقلها أو نسخها من ملفات أخرى.
  • —date=short: عرض يوم التعديل فقط دون الوقت
  • —color-lines: تبديل الألوان بين عمليات الالتزام. تخصيص اللون باستخدام git config set --global color.blame.repeatedLines <color>
  • —show-email أو -e: يعرض عنوان البريد الإلكتروني للمساهم بدلاً من اسم المستخدم

Git Alias

تُستخدم الأسماء المستعارة لتعيين الأوامر المتكررة والطويلة إلى أوامر أقصر.

git config set --global alias.<alias-name> <git-command> # تعريف اسم مستعار جديد
git config --get-regexp alias # الحصول على جميع الأسماء المستعارة الحالية

أسماء مستعارة مفيدة:

git config set --global alias.uncommit ”git reset HEAD~1“

git config set --global alias.recommit ”git commit --amend --no-edit“

git config set --global alias.editcommit ”git commit --amend“

git config set --global alias.logc ”log --oneline --graph --decorate“

تعديل الالتزامات

يتيح لك الأمر amend تعديل الالتزام الأخير. وهو مفيد في الحالات التالية:

  • تحرير أو تصحيح الأخطاء المطبعية في رسائل الالتزام
  • إضافة ملفات من الالتزام الأخير دون إنشاء التزام جديد

تعديل رسالة الالتزام:

git commit --amend # يفتح محررًا لتغيير رسالة الالتزام الأخيرة
git commit --amend -m<new-message> # يغير رسالة الالتزام الأخيرة مباشرة

إضافة ملفات إلى آخر التزام:

git add <file> # تجهيز الملف المفقود
git commit --amend --no-edit # تعديل الالتزام دون تغيير رسالة الالتزام

وضع العلامات

تُستخدم العلامات لتمييز التزامات معينة:

  • خفيفة الوزن: مجرد علامة، على سبيل المثال، v3.14.
  • مُعلّقة: علامة خفيفة + رسالة + مؤلف.

إنشاء العلامات:

git tag # سرد جميع العلامات
git tag v1.0 # إنشاء علامة خفيفة في الالتزام الحالي
git tag v1.0 <commit-hash> # تحديد التزام لوضع علامة عليه
git tag -a 1.1 -m ”رسالة العلامة“ # إنشاء علامة مع تعليق

دفع العلامات:

git push [origin] --tags # دفع جميع العلامات
git push origin tag3.14 # تحديد العلامة المراد دفعها

حذف العلامات:

git tag -d <tag-name> # حذف العلامة محليًا
git push origin -d <tag-name> # حذف من البعيد

الوحدات الفرعية

تسمح لك الوحدات الفرعية في Git بإنشاء وحدات متداخلة عن طريق وضع مستودع بعيد داخل مستودع آخر.

استنساخ مستودع مع الوحدات الفرعية:

git clone --recurse-submodules <رابط-المستودع>

إذا نسيت استخدام --recurse-submodules أثناء الاستنساخ، فاستخدم:

git submodule update --init --recursive

إنشاء وحدة فرعية:

git submodule add <remote-repo-url>

التكوين

الإعدادات الموصى بها للسماح بالتحديث التلقائي للوحدات الفرعية عند السحب والدفع

git config set --global submodule.recurse true

git config set --global push.recurseSubmodules on-demand

حذف وحدة فرعية

git submodule deinit <mysubmod>
rm -rf .git/modules/<mysubmod>
git config -f .gitmodules --remove-section submodule.<mysubmod>
git rm --cached <mysubmod>

Worktrees

تسمح لك أشجار العمل بالعمل على عدة فروع في وقت واحد دون الحاجة إلى التخزين المؤقت والتبديل بين الفروع باستمرار.

قواعد شجرة العمل:

  • لا يمكن أن تشير شجرتا عمل إلى نفس الفرع في نفس الوقت (باستثناء عند استخدام HEAD المنفصل).
  • ضع شجرة العمل كدليل شقيق لشجرة العمل الموجودة من أجل تنظيم أفضل.
  • هناك شجرة عمل رئيسية واحدة فقط تحتوي على دليل .git؛ وترتبط شجرات العمل الإضافية بها.

الأوامر

git worktree add ../<worktree-name> <branch-name> # إنشاء شجرة عمل جديدة في الدليل الأصلي بالفرع المحدد
  • إذا تم حذف <branch-name>، فسيتم استخدام الاسم الأساسي لـ <path> كاسم للفرع. إذا لم يكن هناك فرع بهذا الاسم، فسيتم إنشاء فرع جديد.
git worktree remove <مسار شجرة العمل> # يزيل شجرة العمل (يمكن تشغيله من أي مكان).
  • يمكن أن يكون <مسار شجرة العمل> أي مسار يؤدي إلى شجرة العمل، بما في ذلك . إذا تم تشغيله من داخل شجرة العمل نفسها.
git worktree list # سرد جميع أشجار العمل
  • يتم سرد شجرة العمل الرئيسية أولاً.

نصائح للمحترفين

  • لا تغير السجل إلا إذا لم تكن قد قمت بدفع التغييرات بعد! إعادة كتابة السجل المشترك تسبب مشاكل للمتعاونين.
  • Git لا يتتبع الدلائل الفارغة. الحل: أضف ملف .gitkeep (أو أي ملف) إلى الدليل حتى يتتبعه Git.
  • اتفاقية تسمية البعيد المنبع: عند إنشاء نسخة متفرعة من مستودع على GitHub، فإن الاتفاقية هي تسمية المستودع الأصلي البعيد upstream ونسختك المتفرعة origin.
  • دفع قسري أكثر أمانًا: استخدم git push --force-with-lease بدلاً من --force. لا يتم الدفع إلا إذا لم يتم تحديث الفرع البعيد منذ آخر مرة قمت فيها بالجلب (يمنع الكتابة فوق عمل الآخرين).
  • يمكنك نقل التغييرات غير الملتزم بها إلى فرع جديد باستخدام git switch -c <new-branch>
  • قواعد رسائل الالتزام: استخدم صيغة الأمر (”أضف ميزة“ وليس ”أضيفت ميزة“). ضع في اعتبارك استخدام الالتزامات التقليدية للحصول على تنسيق منظم (على سبيل المثال، feat:، fix:، docs:).
  • ملف .gitattributes هو ملف خاص يخبر Git بكيفية التعامل مع ملفات معينة في مستودعك
  *.jpg binary           # التعامل معها على أنها ثنائية
  *.sh text eol=lf      # فرض نهايات الأسطر LF
  docs/* linguist-documentation  # استبعادها من إحصائيات اللغة

المصادر

Share this post