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 اومد و دید یه خط کد قبلا چی بوده ، احتمال داره اون خط ۱۰ تا کامیت قبل بوده