چطور و چگونه دیگر از Git نترسیم - قسمت 2

دسته بندی: آموزش
زمان مطالعه: 7 دقیقه
۱۱ دی ۱۳۹۷

در این مطلب میخوام قسمت دوم مطلب چگونه دیگر از Git نترسیم رو ادامه بدم و شما رو بیشتر با Git و جزئیات اون آشنا کنم.

در مطلب قبل working directory و Object store رو رو توضیح دادم و در این مطلب index و بقیه چیزایی که مونده رو بهتون توضیح میدم.

index

این مورد هسته Git هست و به اون Staging area هم گفته میشه. index یک mapping از فایلها به object هایی که در object store هستند رو ذخیره‌سازی میکنه و با استفاده از اون میفهمه که کدام فایل مربوط به کدام object می‌باشد. اینجا هست که commit خودش رو نشون میده. خب برای فهم بیشتر Commit هم بهتره که با استفاده از مثال اون رو توضیح بدیم.

مثلا فرض کنید میخوایم فایل helloworld رو commit کنیم. برای اینکار بصورت زیر عمل میکنیم:

$ git commit -m "Add helloworld"

[master (root-commit) a39b9fd] Add helloworld
 1 file changed, 1 insertion(+)
 create mode 100644 helloworld

همونطور که میبینید با پیام Add helloworld این فایل رو commit کردیم. حالا اگر دوباره محتویات دایرکتوری .git رو با استفاده از دستور tree ببینیم، خروجی بصورت زیر خواهد بود:

$ tree .git/

.git/
├── COMMIT_EDITMSG
├── HEAD
├── config
├── description
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   ├── prepare-commit-msg.sample
│   └── update.sample
├── index
├── info
│   └── exclude
├── logs
│   ├── HEAD
│   └── refs
│       └── heads
│           └── master
├── objects
│   ├── a0
│   │   └── 423896973644771497bdc03eb99d5281615b51
│   ├── a3
│   │   └── 9b9fdd624c35eee08a36077f411e009da68c2f
│   ├── fb
│   │   └── 26ca0289762a454db2ef783c322fedfc566d38
│   ├── info
│   └── pack
└── refs
    ├── heads
    │   └── master
    └── tags
14 directories, 22 files

همونطور که میبینید با این commit چند فایل به این دایرکتوری اضافه شده است. 2 مورد به Object store اضافه شده و اطلاعاتی نیز به logs و refs اضافه شدند که هنوز اطلاعاتی در مورد اونا بهتون ندادم و در ادامه با اونا آشنا میشید.

حالا میخوایم با استفاده از دستور cat-file که در مطلب قبل توضیح دادم، محتویات object‌های ساخته شده جدید رو از حالت فشرده خارج کرده و مشاهده کنیم و ببینیم که چه اطلاعاتی در اونا قرار داده شده است. object اول بصورت زیر هست:

$ git cat-file a39b9fdd624c35eee08a36077f411e009da68c2f -p

tree fb26ca0289762a454db2ef783c322fedfc566d38
author = <=> 1537700068 +0100
committer = <=> 1537700068 +0100

Add helloworld

همونطور که میبینید این object اطلاعاتی در مورد commit رو در اختیار ما قرار میده که این commit چه موقع و توسط چه کسی انجام شده و چه کاری رو انجام داده است. همونطور که میبینید به fb26ca0289762a454db2ef783c322fedfc566d38 اشاره شده است. این object در واقع همون مسیر به فایل اصلی هست و اگر اطلاعات اون رو با استفاده از cat-file مشاهده کنیم، بصورت زیر خواهد بود:

$ git cat-file fb26ca0289762a454db2ef783c322fedfc566d38 -p

100644 blob a0423896973644771497bdc03eb99d5281615b51 helloworld

همونطور که میبینید این object به فایل یا blob با نام helloworld و شماره object اون اشاره میکنه. اگر شما اطلاعاتی در مورد سیستم Unix داشته باشید، موارد بالا برای شما به خوبی قابل فهم خواهند بود.

در Git هر چیزی یا tree (دایرکتوری) یا blob (فایل) هست و با هر commit، گیت اطلاعات مربوط به tree رو نیز ذخیره‌سازی میکنه تا بدونه که در اون تاریخی که commit انجام شده، ساختار working directory به چه شکلی بوده است که اگر ما خواستیم یه زمانی به عقب برگردیم، Git بتونه این کار رو برای ما انجام بده.

حالا وقتشه که در مورد Branch یا شاخه‌ها صحبت کنیم. همونطور که در بالا دیدید زمانی که یک commit رو انجام دادیم، اطلاعات دیگه‌ای نیز به دایرکتوری .git اضافه شد. مسیر چیزی که اضافه شده بود، .git/refs/heads/master هست. حالا اگر با استفاده از دستور cat، محتویات اون رو مشاهده کنیم، بصورت زیر هست:

$ cat .git/refs/heads/master

a39b9fdd624c35eee08a36077f411e009da68c2f

میبینید که hash مربوط به یکی از object‌ها در اون قرار گرفته است. یک branch در Git یک اشاره‌گر بسیار سبک و متحرک هست که به یکی از Commit‌ها اشاره میکنه. اسم شاخه پیش‌فرضی که در گیت وجود داره master هست.

همونطور که در دستور cat هم دیدید این branch به object با شماره a39b9fdd624c35eee08a36077f411e009da68c2f اشاره کرده که مربوط به commit مورد نظر است. پس اگر قبلا تصور میکردید که با ساختن یک branch یک کپی از کل فایلها گرفته میشه و دیگه تاثیری بر روی هم ندارند، اشتباه فکر میکردید و در واقع این commit‌ها هستند که همه چیز رو مدیریت میکنند و branch‌ها فقط به یکی از اونا اشاره میکنند.

برای فهم بیشتر فرض کنید که میخوام یک شاخه جدید با نام the-ending رو به وجود بیارم. برای اینکار بصورت زیر عمل میکنیم:

$ git branch the-ending



$ git branch

* master
  the-ending

با استفاده از دستور اول branch مورد نظر رو ساخته و با استفاده از دستور git branch هم همه شاخه‌های موجود رو لیست کردیم. با اینکار یک مورد جدید به مسیر .git/refs/heads/ اضافه میشه و میتونین با استفاده از cat میتونین اطلاعات اون رو مشاهده کنید:

$ cat .git/refs/heads/the-ending

a39b9fdd624c35eee08a36077f411e009da68c2f

همونطور که میبینید همانند شاخه master، این شاخه هم به همون commit اشاره کرده است.

فایل byeworld رو یادتون هست؟ این فایل هنوز هم untracked هست و به شاخه‌ای که در اون هستید وابسته نیست و در working directory باقی میمونه. خب با استفاده از دستور git checkout به شاخه the-ending میرم و دستور git branch رو مجددا اجرا میکنم. بصورت زیر:

$ git checkout the-ending
Switched to branch 'the-ending'


$ git branch
  master
* the-ending

همونطور که میبینید در کنار اسم شاخه the-ending یک ستاره قرار داده شده و به معنای اینه که در حال حاضر در این شاخه قرار داریم. با تغییر دادن شاخه Git در پشت صحنه همه فایلهای مربوط به اون commit که این شاخه به اون اشاره میکنه، در working directory قرار میگیرن. هم اکنون چون هر 2 شاخه به یک commit اشاره میکنند، پس محتوای working directory همانند هم خواهد بود و فرقی با هم نخواهند داشت.

حالا یک فایل byeworld رو نیز commit میکنم. بنظرتون ساختار دایرکتوری .git به چه صورت خواهد شد؟

$ tree .git/

.git/
├── COMMIT_EDITMSG
├── HEAD
├── config
├── description
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   ├── prepare-commit-msg.sample
│   └── update.sample
├── index
├── info
│   └── exclude
├── logs
│   ├── HEAD
│   └── refs
│       └── heads
│           ├── master
│           └── the-ending
├── objects
│   ├── 0b
│   │   └── 17be9dbc34c5a5fbb0b94d57680968efd035ca
│   ├── a0
│   │   └── 423896973644771497bdc03eb99d5281615b51
│   ├── a3
│   │   └── 9b9fdd624c35eee08a36077f411e009da68c2f
│   ├── b3
│   │   └── 00387d818adbbd6e7cc14945fdf4c895de6376
│   ├── d1
│   │   └── 8affe001488123b496ceb34d8b13b120ab4cb6
│   ├── fb
│   │   └── 26ca0289762a454db2ef783c322fedfc566d38
│   ├── info
│   └── pack
└── refs
    ├── heads
    │   ├── master
    │   └── the-ending
    └── tags

17 directories, 27 files

همونطور که میبینید 3 object جدید به وجود اومدن. یکی از این object‌ها برای اضافه شدن فایل و 2 تا از اونا مربوط به commit هستند. این object‌ها شامل موارد زیر هستند:

  • اطلاعات مربوط به commit
  • محتوای مربوط به فایل اضافه شده
  • اطلاعات مربوط به دایرکتوری و tree

آخرین چیزی که باید بدونیم اینه که هر commit با commit قبلی چطوری ارتباط برقرار میکنه و چطوری git متوجه میشه که ترتیب commit‌ها به چه صورت هست. برای اینکار مجددا از دستور cat-file استفاده میکنیم:

$ git cat-file 0b17be9dbc34c5a5fbb0b94d57680968efd035ca -p
100644 blob d18affe001488123b496ceb34d8b13b120ab4cb6 byeworld
100644 blob a0423896973644771497bdc03eb99d5281615b51 helloworld



$ git cat-file b300387d818adbbd6e7cc14945fdf4c895de6376 -p
tree 0b17be9dbc34c5a5fbb0b94d57680968efd035ca
parent a39b9fdd624c35eee08a36077f411e009da68c2f
author = <=> 1537770989 +0100
committer = <=> 1537770989 +0100
add byeworld




$ git cat-file d18affe001488123b496ceb34d8b13b120ab4cb6 -p
Bye world!




$ cat .git/refs/heads/the-ending 
b300387d818adbbd6e7cc14945fdf4c895de6376

همونطور که میبینید در دستور دوم که مربوط به b300387d818adbbd6e7cc14945fdf4c895de6376 هست، اطلاعات مربوط به پدر یا parent اون قرار داده شده و گفته شده که پدر این commit چه commit ای هست. پس همونطور که میبینید گیت با استفاده از linked list کار خودشو انجام میده و پروژه شما رو مدیریت میکنه.

همونطور که میبینید شاخه the-ending به b300387d818adbbd6e7cc14945fdf4c895de6376 اشاره میکنه در حالی که شاخه master هنوز هم به a39b9fdd624c35eee08a36077f411e009da68c2f اشاره میکنه و هیچ ربطی به هم ندارند.

چه امتیازی به این مقاله می دید؟
نویسنده محمد اسفندیاری
بسیار به طراحی وب علاقمندم و به سرعت در حال یادگیری تمام مباحث پیشرفته هستم و دوست دارم که به دیگران هم یاد بدهم.
ارسال دیدگاه
خوشحال میشیم دیدگاه و یا تجربیات خودتون رو با ما در میون بذارید :

 

نظرات کاربران

امید امامی

دقیق، مختصر و مفید بود.سپاس فراوان

Roohollah Taeb

مطلب خیلی خوبی بود. ممنون

محمد اسفندیاری

موفق باشید دوست عزیز