بیشتر اوقات برای آوردنِ تغییراتِ تویِ remote repository به local repository باید از دستورِ fetch همراه با merge استفاده کنیم. (fetch + merge)

البته دستوری به اسمِ pull رو داریم که دو دستورِ بالا رو یکی می‌کنه.

Pulling

در تصویرِ زیر، در ابتدا local repo و remote repo در وضعیتِ یکسانی قرار دارن و در هر دو repo فقط یک کامیت هست.

تو لوکال ریپو یه کامیتِ جدیدی رو می‌سازیم. و در ریموت ریپو نیز کامیتِ جدید دیگری رو می‌سازیم. حالا زمانی که از دستورِ git pull استفاده می‌کنیم گیت کامیتِ C رو از ریموت ریپو دانلود می‌کنه و اون رو در لوکال ریپو جا می‌کنه.

دقت کنید که Origin/Master حالا به کامیتِ C اشاره می‌کنه. و حالا مسیرِ branchهامون از هم جدا هست. در این حالت، گیت از three-way merged استفاده می‌کنه تا تغییراتِ تویِ کامیتِ C (تغییراتِ remote) رو با master branchمون یکی کنه و در نتیجه یه merge commit رو خواهیم داشت. (کامیتِ M در تصویر)

برخی افراد merge commit رو نمی‌پسندن چون این کامیت‌ها history رو آلوده می‌کنن. روشِ جایگزینی که داریم استفاده از rebasing هستش.

اگه آپشنِ rebasing در دستورِ git pull استفاده کنیم گیت کامیتِ B رو rebase خواهد کرد و baseش رو از کامیتِ A به کامیتِ C تغییر خواهد داد. و این یعنی دوباره، علاوه بر تغییراتی که از remote روی local اعمال شد تغییراتِ دیگه‌ای نیز علاوه بر اون، با rebase کردنِ کامیتِ B اعمال شد. حالا یه تاریخچه‌ی خطی داریم.

و سالهاست که بر سر این قضیه بحث‌هاست. برخی عاشقِ rebasing هستن و برخی merge commit رو ترجیح می‌دن.

Pulling

سناریویِ بالا رو در عمل ببینیم. کامیتِ جدیدی رو در remote repo می‌سازیم. حالا برمی‌گردیم به ترمینال و local repoمون. در اینجا هم کامیتِ جدیدی رو می‌سازیم.

حالا به logمون نگاه کنیم.

* 77f23f4 (HEAD -> master) Add file1
* 012ff85 (origin/master, origin/HEAD) Update README.md
* fb3b343 Initial commit

با توجه به خروجیِ بالا، Master branch یه کامیت جلوتر از origin/master branch هستش. ولی در این لحظه‌ای که لاگ بالا رو می‌بینیم از کامیتی که در گیت‌هاب ساخته شده، خبری نداریم.

حالا، اگه دستورِ git pull رو اجرا کنیم، گیت کامیتِ جدید رو از remote repo دانلود خواهد کرد و سپس، three-way merge رو اجرا خواهد کرد تا تغییرات رو به master branch بیاره.

git pull

با اجرای دستورِ بالا ادیتورِ پیشفرض اجرا خواهد شد تا پیامِ merge commit رو ببینیم و ویرایشش کنیم.

دوباره لاگ رو یه نگاه می‌کنیم.

* f8dd46e (HEAD -> master) Merge branch 'master' of https://github.com/codewithmosh/Mars into master
|\
| * f11b0d0 (origin/master, origin/HEAD) Update README.md
* | 77f23f4 Add file1
|/
* 012ff85 Update README.md
* fb3b343 Initial commit

کامیتِ‌ f8dd46e همون merge commitمونه که تغییراتِ کامیت‌هایِ f11b0d0 و 77f23f4 رو یکی کرده. همانطور که می‌بینید نتیجه‌ی کار non-linear history هستش. می‌تونیم از re-basing استفاده کنیم تا یه linear history داشته باشیم. ولی قبلش آخرین کامیت (f8dd46e) رو undo می‌کنیم تا به آخرین وضعیتِ قبلی برسیم.

git reset --hard HEAD~1

دوباره به لاگ نگاه کنیم.

* efe2257 (HEAD -> master) Add file1
| * f11b0d0 (origin/master, origin/HEAD) Update README.md
|/
* 012ff85 Update README.md
* fb3b343 Initial commit

حالا می‌تونیم دستورِ git pull —-rebase رو اجرا کنیم تا تغییراتِ localمون رو replay کنیم. دوباره یه نگاهی به لاگ بندازیم.

* 478ac2a (HEAD -> master) Add file1
* f11b0d0 (origin/master, origin/HEAD) Update README.md
* 012ff85 Update README.md
* fb3b343 Initial commit

حالا یه simple linear history داریم و کامیتِ لوکال‌مون بالاتر از کامیتی هست که در گیت‌هاب ساخته بودیم.