merge vs rebase
توجه شه که هیچ ربطی به کانفلیت ندارن اینا
- merge در مرج ابتدا باید چک آوت کنیم به برنچ مستر ، سپس بگیم مرج کن برنچ فیچر رو
اتفاقی که می افته کامل تاریخچه حفظ میشه و گراف اون ، تغییری نمی کنه و در صورت موفقیت آمیز بودن ، میگه یه کامیت باید بزنیم و به صورت دیفالت اسمش رو خودش پیشنهاد میکنه
توضیح اضافی :
$ git checkout master
$ git merge feature
این دستور برای ترکیب ۲ برنچ هست و به این صورت کار می کند که شاخه ی جدید را به شاخه اصلی وصل می کند ، در صورتی که کانفلیکت نخوریم یه کامیت جدید(“merge commit”) تولید می کند که ۲ کامیت پدر دارد. همیشه باید به شاخه اصلی برگردیم ( git checkout main ) سپس آخرین تغییرات remote را دریافت کنیم به همین منظور دستور git pull را می زنیم ( git fetch ) و در نهایت دستور مرج را میزنیم (git merge x)
- rebase
$ git checkout feature
$ git rebase master
در این روش باید در برنچ فیچر بمانیم - برخلاف مرج - سپس بعد از دستور ریبیس ، تمامی کامیت های فیچر به انتهای برنچ مستر اضافه میشه ، توجه شود معنی ریبیس یعنی همین ، شاید خیلی وقت پیش ما برنچ فیچر رو شروع کردیم و در برنچ مستر کامیت جدید تر ثبت شده باشه ولی با ریبیس به تاریخچه و ترتیب کامیت ها دقت نمی کنه ، آخرین کامیت برنچ اصلی رو بیس قرار میده و کایت های فیچر رو در ادامه قرار میده ، ولی در مرج ساده به جای این ، تاریخچه ی گراف رو حفظ می کنه و یه کامیت میسازه که اون تو توضیح می ده
ff - fast forward
این ساده ترین راه مرج کردن است و در صورتی استفاده می شود که بعد از ایجاد برنچ جدید ، برنج اصلی هیچ تغییر و کامیتی نداشته باشه و بعد از مرج ، خیلی عادی کامیت های برچ جدید ، ادامه برنچ اصلی باشند ، در این صورت حتی ( merge commit) هم تولید نمی شود نمی شود .
3-way
در این حالت هم شاخه ی جدید کامیت زده شده هم شاخه ی اصلی ، در این صورت اگر روی یک فایل مشترک تغییر باشد ، خیلی ساده یا کد برنچ اصلی یا جدید را انتخاب می کنیم و در نهایت کامیت نهایی ( merge commit ) می کنیم .
squash
در صورتی که کانفلیکتی وجود داشته باشد، به جای اینکه تمامی کامیت ها رو یکی یکی دوباره دیبیس کنیم ، می توان همون اول همه رو اسکواش کردت و در نهایت یه کامیت با تغییرات بزرگ داشت و کانفلیکت ها رو از ابین برد
git rebase -i HEAD~15
هر چند تا کامیت که در اون برنچ می خوایم رو اسکواش می کنیم
همچنین می توان امکانات بیشتری استفاده کرد ، مثلا متن کامیت ها را بهتر کرد(rework) یا بخشی از کامیت ها را حذف کرد(squash) با روش زیر :
git rebase -i master
rebase conflict step by step
اول بهتره اسکواش کنیم
git rebase -i HEAD~15
یا
git rebase -i master
توجه شود حتی اگر ۱۰ تا کامیت رو اسکواش کردیم ، باید همیشه اولین کامیت در بالا ترین جای ادیتور ، باید pick باشد
pick 3f6b6d2 Initial commit
squash d8c9e5b Add feature A
squash a1b2c3d Fix bug in feature A
squash 5f4e6a7 Improve feature A
سپس می تونیم با یکی از دستور های زیر کانفلیکت ها رو درست کنیم
git rebase develop
git pull develop
حالا باید یکی یکی کانفلیکت هارو درست کنیم ، توجه شود بهتره از vscode git lens , git graph استفاده کنیم
بعد از این که تمامی کامیت ها ( در صورت استفاده نکردن از اسکواش) رو درست کردیم ، به یه جای خیلی خطرناک میرسیم ، باید دیگه هیچ درخواستی نزنیم و تنها دستور زیر رو بزنیم :
git push origin feature --force
باید اوکی شده باشه
rebase tips
- Detached HEAD
git checkout origin/feature/finalize-promissory-note
git reset --hard HEAD
گاهی بعد از کار های بالا احتمال داره به جای اینکه دقیقن روی برنچ باشیم ، به عبارتی توی پرانتر oh-my-zsh جای برنچ ، عدد هست
در این حالت باید به جای checkout origin چکآوت کنیم بدون origin :
bad :
git checkout origin/feature/finalize-promissory-note
ok:
git checkout feature/finalize-promissory-note
current vs incoming
اگر pull ها rebase باشه در این صورت incoming ها میشن کد های من و اونایی که از develop اومدن و current میشه
git config pull.rebase
شاید هر بار برای اولین بار پول بزنیم روی یه گیت ، این متن رو ببینیم
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
توجه کنید این یه بار پرسیده میشه و میره تو کانفیگ ، برای تغییرش باید کانفیگ اون گیت رو تغییر داد
می تونیم به جای ریبیس ، اون رو مرج کنیم ، در حقیقت فرقشون رو نمی دونم ، اما من مرج زدم و کانفلیکت نداشت
بروز کردن برنچ لوکال قدیمی
زمانی که برنچ مستر یا دولوپ توی لوکالمون خیلی قدیمی باشه و بخواهیم بروز کنیم
توجه کنید در اینجا نیازی نیست کانفلیک مستر لوکال قدیمی و مستر جدید ریموت ریپازیتوری گرفته بشه ، کامل می خواهیم تغییرات اعمال بشه
یعنی نمی خواهیم همش دستور continueبزنیم
پس باید دستور زیر زده بشه
git checkout dev
git reset --hard origin/dev
MERGE VS REBASE
مرج تاریخچه را نگه می دارد در حالی که ریبیس تاریخچه را می توان تغییر داد و بازگشت و ریورت در مرج آسان تر است
اما زمانی که می خواهیم پول بزنیم همون اول می گه ریبیس رو فعال کن
git ssh
چند تا نکته داره که باید بهشون دقت کرد
~/.ssh/config
Host git.srxx.org
HostName 157.180.85.51
Port 22
ProxyCommand /usr/bin/nc -x 127.0.0.1:1080 %h %p
IdentityFile ~/.ssh/id_ed25519
~/.gitconfig
[user]
name = mo30
email = mo30.developer@gmail.com
signingkey = BF170584807AC0AC
[commit]
gpgsign = true
[url "ssh://git@git.srxx.org/"]
insteadOf = https://git.srxx.org/
- ssh
این رو باید chat gpt بگه و مرحله به مرحله جلو رفت
cherry pick
فرض کنید داشتیم روی feat کار می کردیم و یهو باید باگ فیکس کنیم ، و بدون اینکه بریم دوباره dev و برنچ hotfix بسازیم ، از برنچ feat شروع کردیم ادامه و حالا راه حل :
ابتدا باید بریم به dev سپس تنها اون کامیت ها رو بچینیم :)
core.fileMode false (chmod - permission)
گاهی فایل ها هیچ تغییری نکردن ولی توی change ها میان ، در این صورت یا پرمیشن فایل ها تغییر کرده ، ویا سیستم عامل عوض شده ، در این صورت یا باید تک تک فایل ها رو به حالت قبلی برگردونید یا این کانفیگ رو ست کرد
git config core.fileMode false
revert
با استفاده از این روش می توان تغییرات کامیت قبلی رو دو باره کپی کرد و در unstage قرار داد و زمانی استفاده می شه که یه اشتباهی کردیم و دوست داریم برگردیم کامیت قبلی
در حقیقت revert یک کامیت جدید می سازد و تغییرات رو برمی گردونه در حالی که ریست واقعا کامیت ها رو پاک می کنه
reset
git reset —soft HEAD~1 _____ با این دستور می توان آخرین کامیت رو باز کرد و تغییرات در حالت اسیج آورد ، این روش یکی از راحت ترین راه های اسکواش هست یعنی می توان چند کامیت رو تبدیل به یه کامیت کرد
git reset —hard HEAD~1 _____ با این دستور می توان کامیت را باز کرد و تغییرات رو هم حذف کرد
اگر بخواهیم فایلی که add کردیم و در stage است را دوباره unstage کنیم ، باید دستور زیر را بزنیم :
git reset HEAD <file>
اگر بخواهیمفایل را untrack کنیم :
git rm --cached <file>
نکات :
بهتره username بعد از
clean
یکی از راه های حذف فایل های untrackcاست ولی خیلی با احتیاط باید استفاده شود
-n ـــــ لیست فایل هایی که ممکن است پاک شوند
-f ــــ فورس می کنیم که پاک شوند
Git commit types
بتر است نوع های کامیت را دسته بندی کنیم ، متداول ترین انواع:
Feature افزودن ویژگی
Fix , bug fix , hot fix کدی که مشکل ایجاد کرده بود را تصحیح کنیم
Chore تغییر درچ8
submodule
به صورت دیفالت هر دایرکتوری یه .git داره و تمامی زیر پوشه ها توسط اون کنترل میشه
اما اگر بخواهیم یه ریپازیتوری رو درون یه ریپازیتوری دیگه استفاده کنیم ، از این فیچر استفاده می کنیم
git submodule add -b feature github.com/seyedmo30/salam.git folder
conventional
branch
بهتره نام های برنچ اینجوری باشه
feature/feature-name
bugfix/bug-description
hotfix/issue-description
release/version-number
history compare file
right click > git > show history
و این جا میشه دو تا commit رو select کرد و compare کرد
troubleshoot
Ambiguous object name: ‘HEAD
گاهی اشتباهی روی برنچ های اصلی مثل master , dev , stage کامیت می کنیم ، در این صورت اگر بخواهیم برنچ جدید بسازیم و به اون checkout کنیم شاید به ارور Ambiguous object name: ‘HEADبخوریم
راه حل :
شماره کامیت هم بنویسیم
git checkout -b feat/append_repository c4aa7947701f7fa6d60380fef9da7dcb7a497b4c
git flow
یه متدولوژی هست برای گیت که به صورت پیش فرض همه چیز رو به صورت یک سری از قوانین تعریف می کنه میگه بهتره چند تا برنچ ثابت داشته باشیم برای هر ریپازیتوری
- master
- hotfix
- develop
- feature
خیلی چیزا مشخصه ولی نکته ی خیلی خیلی مهم اینه که پروژه ای که چندین دولوپر داره و تغییراتش خیلی خیلی زیادن ، اگر بخواهیم یه فیچر اضافه کنیم ابتدا باید یه فیچر بسازیم و دیگه از دولوپ نه pull , push نزنیم ،
اگر این کد قراره با سرویس بیرونی مانند سرویس های میکرو سرویس یا پروایدر بیرونی کار کنه ، به هیچ وجه روی dev نباید بفرستیم هر موقع اطمینان حاصل شد اوکی هست حالا به dev مرج شه
و جمله ی پایانی ، تا زمانی که همه چی از جمله سرویس های upstream و دپندنسی ها اوکی باشه ، بعد با احتیاط باید روی dev مرج کنیم
tips
GitLens Show Line History
میشه روی تب گیت لنز توی vscode اومد و دید یه خط کد قبلا چی بوده ، احتمال داره اون خط ۱۰ تا کامیت قبل بوده