مقدمه

شروع به کار

درباره نسخه کنترل

سیستم‌های کنترل نسخه محلی

سیستم‌های کنترل نسخه متمرکز

سیستم‌های کنترل نسخه توزیع شده

تاریخچه کوتاهی از گیت

گیت چیست؟

snapshot,هیچ فرقی ندارد

تقریبا هر عملیت به صورت محلی انجام می‌شود

گیت دارای یکپارچگی است

گیت به طور کلی فقط داده‌ها را اضافه می‌کند

سه حالت

خط فرمان

نصب گیت

نصب بر روی لینوکس

نصب بر روی macOS

نصب بر روی ویندوز

نصب از منبع

راه‌اندازی اولیه گیت

هویت شما

ویرایشگر شما

نام برنچ پیش فرض شما

بررسی تنظیمات شما

دریافت کمک

خلاصه

مبانی گیت

اگر تنها یک فصل را برای شروع کار با گیت بخواهید، این فصل بهترین انتخاب است. در این فصل، تمام دستورهای پایه‌ای که برای انجام اکثر کارهایی که در آینده با گیت انجام می‌دهید، نیاز دارید، پوشش داده می‌شود. در پایان این فصل، باید بتوانید یک مخزن را پیکربندی و راه‌اندازی کنید، ردیابی فایل‌ها را آغاز و متوقف کنید، و تغییرات را مرحله‌بندی و ثبت کنید. همچنین به شما خواهیم آموخت که چگونه گیت را تنظیم کنید تا برخی فایل‌ها و الگوهای خاص را نادیده بگیرد، چطور به‌راحتی اشتباهات خود را اصلاح کنید، چگونه تاریخچه پروژه‌تان را مرور کرده و تغییرات بین نسخه‌ها را مشاهده کنید، و چگونه از مخازن راه دور اطلاعات را بارگذاری و دریافت کنید.

ایجاد یک مخزن گیت

شما معمولاً یک مخزن گیت را به یکی از دو روش زیر به دست می‌اورید:

۱. می‌توانید یک دایرکتوری محلی که در حال حاضر تحت کنترل نسخه نیست را به مخزن گیت تبدیل کنید.

۲. می‌توانید یک مخزن گیت موجود را از جای دیگر کلون کنید.

در هر دوحالت، شما در نهایت یک مخزن گیت بر روی دستگاه محلی خود خواهید داشت که اماده کار است.

نصب یک مخزن در یک دایرکتوری موجود

اگر دایرکتوری پروژه‌ای دارید که در حال حاضر تحت کنترل نسخه نیست و می‌خواهید با گیت آن را مدیریت کنید، ابتدا باید به دایرکتوری پروژه بروید. این کار بسته به سیستم‌عامل شما کمی متفاوت است:

برای لینوکس:

$ cd /home/user/my_project

برای macOS:

$ cd /Users/user/my_project

برای ویندوز:

$ cd C:/Users/user/my_project

سپس تایپ کنید:

$ git init

این دستور یک دایرکتور فرعی به نام گیت ایجاد می‌کند. که شامل تمام فابل‌های لازم برای مخزن شما است- که به آن اسکلت مخزن گیت گفته می‌شود. در این مرحله، هبچ‌ چیزی در پروژه شماهنوز تحت ردیابی نیست. برای اطلاعات بیشتر در مورد فایل‌های موجود در دایرکتوری گیت که تازه ایجاد کرده‌اید به مستندات git internals مراجعه کنید.

اگر می‌خواهید فایل‌های موجود را تحت کنترل نسخه قرار دهید(نه یک دایرکتوری خالی) باید این فایل‌ها را ردیابی کرده و یک کامیت اولیه انجام دهید. می‌توانید این کار را با چند دستور git add انجام دهید که فایل‌های مورد نظر شما را مشخص می‌کند و سپس یک دستور git commit صادر کنید:

$ git add *.c
$ git add LICENSE
$ git commit -m 'نسخه اولیه پروژه'

در ادامه، در مورد عملکرد این دستورات بیشتر توضیح خواهیم داد. در این مرحله، شما یک مخزن گیت دارید که شما فایل‌های تحت ردیابی و یک کامیت اولیه است.

کلون کردن یک مخزن موجود

اگر می‌خواهید یک نسخه از یک مخزن گیت موجود به دست آوررید-برای مثال، پروژه‌ای که تمایل دارید در آن مشارکت کنید- دستوری که نیاز دارید git clone است. اگر با سیستم‌های کنترل نسخه دیگری مانند subversion آشنا باشید، متوجه خواهید شد که دستور "clone" به جای "checkout" استفاده می‌شود. این تفاوت مهمی؛ زیرا به جای دریافت تنها یک نسخه کاری، گیت تقریبا تمام داده‌هایی که سرور دارد به طور کامل دریافت می‌کند. به طور پیش‌فرض، هر نسخه از هر فایل از تاریخجه پروژه با اجرای دستور git clone دانلود می‌شود. در واقع، اگر دیسک سرور شما اسیب ببیند، معمولاً می‌توانید از هر یک از کلون‌های موجود در کلاینت‌ها برای بازگرداندن سرور به وضعیت قبلی استفاده کنید(شاید برخی از hookهای سمت سرور را از دست بدهید، اما تمت داده‌های نسخه بندی‌شده در آنجا خواهند بود- برای جزیئات بیشتر به بخش "getting git on a server" مراجعه کنید).

برای کلون کردن یک مخزن، از دستور زیر استفاده کنید:

$ git clone <url>

به‌عنوان مثال، اگر می‌خواهید کتابخانه‌ای به نام libgit2 را کلون کنید، می‌توانید به شکل زیر این کار را انجام دهید:

$ git clone https://github.com/libgit2/libgit2

این دستور یک دایرکتوری به نام libgit2 ایجاد می‌کند، یک دایرکتوری گیت درون آن راه‌اندازی می‌کند، تمام داده‌های مربوط به آن مخزن را دانلود کرده و یک نسخه‌کاری از اخرین نسخه را بررسی می‌کند. اگر به دایرکتوری جدید libgit2 که تازه ایجاد شده بروید، فایل‌های پروژه را خواهید دید که اماده کار یا استفاده هستند.

اگر می‌خواهید مخزن را در دایرکتوری‌ای با نامی غیر از libgit2 کلون کنید، می‌توانید نام دایرکتوری جدید را به عنوان یک آرگومان اضافی مشخص کنید:

$ git clone https://github.com/libgit2/libgit2 mylibgit

این دستور همان عملکرد دستور قبلی را دارد، اما دایرکتوری هدف به نام mylibgit خواهد بود.

گیت پروتکل‌های انتقالی مختلفی را ارائه می‌دهد. مثال قبلی از پروتکل http استفاده می‌کند، اما ممکن است پروتکل‌های //:git یا user@server:path/to/repo.git (که از پروتکل SSH استفاده می‌کند)را نیز ببینید. بخش "getting git on a server" تمامی گزینه‌های موجود برای دسترس به مخزن گیت را معرفی کرده و مزایا و معایب هر یک را بررسی می‌کند.

ثبت تغییرات در مخزن

در این مرحله، شما باید یک مخزن گیت واقعی بر روی دستگاه محلی خود داشته باشید و یک نسخه کاری از تمام فایل‌های آن در دسترس شما باشد. معمولا می‌خواهید شروع به ایجاد تغییرات کنید و هر باز که پروژه به حالتی می‌رسد که می‌خواهید ثبت کنید، یک snapshot از‌ آن تغییرات در مخزن خود ذخیره کنید.

به یاد داشته باشید که هر فایل در دایرکتوری کاری شما می‌تواند در یکی از دو حالت زیر باشد: ردیابی شده یا ردیابی نشده.

فایل‌های ردیابی شده: این فایل شامل فایل‌هایی است که در اخرین snapshot وجود داشته‌اند و همچنین هر فایل جدیدی که در مرحله بندی قرار گرفته است. این فایل‌ها می‌توانند بدون تغییر، تغییریافته یا ردیابی شده فایل‌هایی هستند که گیت از آن‌ها آگاه است.

فایل‌های ردیابی نشده: این فایل‌ها شامل هر فایل دیگری در دایرکتوری کاری شما هستند که در اخرین snapshot وجود نداشته و در ناحیه مرحله‌بندی قرار ندارند. هنگامی که شما یک مخزن را کلون می‌کنید، تمام فایل‌ها به طور پیش فرض ردیابی شده و بدون تغییرات خواهند بود، زیرا گیت فقط آن‌ها را بررسی کرده و شما هنوز چیزی ویرایش نکرده‌اید.

زمانی که شما فایل‌ها را ویرایش می‌کنید، گیت آن‌ها را به عنوان تغییر یافته شناسایی می‌کند، زیرا از آخرین کامیت شما تتغییر کرده اند. در حین کار، شما به‌طور انتخابی این فایل‌های تغییر یافته را مرحله بندی کرده و سپس تمام تغییرات مرحله بندی شده را کامیت می‌کنید و این چرخه تکرار می‌شود. alt text شکل 8. چرخه حیات وضعیت فایل های شما

بررسی وضعیت فایل‌های شما

ابزار اصلی که برای تعیین وضعیت فایل‌ها استفاده می‌کنید، دستور git status است. اگر این دستور را بلافاصله پس از کلون کردن مخزن اجرا کنید، باید چیزی شبیه به این مشاهده کنید:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean

این به این معناست که دایرکتوری کاری شما تمیز است؛ به عبارت دیگر، هیچ یک از فایل‌های ردیابی شده شما تغییر نکرده‌اند. گیت همچنین هیچ فایل ردیابی نشده‌ای نمی‌بیند. وگرنه آن‌ها در اینجا فهرست می‌شدند. در نهایت، در این دستور به شما می‌گوید که در کدام برنچ هستید و اطلاع می‌دهد که این برنچ از برنچ مشابه روی سرور انحرافی ندارد. در حال حاضر، این برنچ همیشه master است که پیش فرض است؛ شما در حال حاضر نگران این موضوع نباید باشید. در بخش "git branching" به طور مفصل به برنچ‌ها و ارجاعات پرداخته خواهد شد.

گیت هاب در میانه‌ی سال ۲۰۲۰ نام پیش فرض برنچ را از master به main تغییر داد و سایر میزبان‌های گیت نیز از این تغییر پیروی کردند. بنابراین ممکن است در برخی از مخازن تازه‌ساخته، نام پیش فرض main برنچ main باشد و نه master. همچنین، نام پیش فرض برنچ قابل تغییر است،بنابراین ممکن است با نام‌های دیگری برای برنچ پیش فرض مواجه شوید. با این حال، خود گیت هنوز master را به عنوان نام پیش فرض استفاده می‌کند، بنابراین ما هم از آن در کتاب استفاده خواهیم کرد.

فرض کنید یک فایل جدید به پروژه‌تان اضافه می‌کنید، مثلا یک فایل README ساده. اگر این فایل قبلاً وجود نداشته باشد و شما دستور git status را اجرا کنید، فایل ردیابی نشده خود را به شکل زیر مشاهده خواهید کرد:

$ echo 'My Project' > README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
(use "git add <file>..." to include in what will be committed)

 README
nothing added to commit but untracked files present (use "git add" to track)

شما می‌بینید که فایل README جدید شما ردیابی نشده است، زیرا تحت عنوان فایل‌های ردیابی نشده در خروجی وضعیت شما قرار دارد. ردیابی نشده به طور کلی ببه این معناست که گیت یک فایل را می‌بیند که در‌ snapshot قبلی(کامیت) وجود نداشته و هنوز مرحله بندی نشده است؛ گیت تا زمان که به طور صریح به آن نگویید، آن فایل را در snapshot های کامیت شما شامل نخواهد کرد. این کر را انجام می‌دهد تا شما به طور تصادفی فایل‌های باینری تولیده شده یا سایر فایل‌هایی را که نمی‌خواستید اضافه کنید، به کامیت ها اضافه نکنید. حالا شما می‌خواهید فایل README را ردیابی کنید، پس بیایید شروع به ردیابی این فایل کنیم.

ردیابی فایل‌های جدید

برای شروع ردیابی یک فایل جدید، از دستور git add استفاده می‌کنید. برای ردیابی فایل README، می‌توانید دستور زیر را اجرا کنید:

$ git add README

اگر دوباره دستور git status را اجرا کنید، می‌بینید که فایل README شما اکنون ردیابی شده و ادامه کامیت است:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)

 new file: README

شما می‌توانید تشخیص دهید که این فایل در حالت مرحله بندی است، زیرا تحت عنوان "changes to be committed" قرار دارد. اگر در این مرحله کامیت کنید، نسخه فایل در زمان اجرای git add در snapshot تاریخی بعدی ذخیره خواهد شد.

شاید به یاد داشته باشید که وقتی قبلاً دستور git init را اجرا کردید، سپس دستور git add <files> را نیز اجرا کردید- این برای شروع ردیابی فایل‌ها در دایرکتوری شما بود. دستور git addمی‌تواند یک مسیر برای یک فایل یا دایرکتوری بگیرد؛ اگر مسیر یک دایرکتوری باشد، این دستور به طور بازگشتی تمام فایل‌های آن دایرکتوری را اضافه می‌کند.

مرحله‌بندی فایل‌های تغییریافته

حال بیایید یک فایل ردیابی شده قبلی را تغییر دهیم. اگر فایلی به نام CONTRIBUTING.md را تغییر دهید و سپس دستور git status را دوباره اجرا کنید، خروجی چیزی شبیه به این خواهد بود:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

 new file: README

Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

 modified: CONTRIBUTING.md

فایل CONTRIBUTING.md تحت عنوان "changes not staged for commit" قرار دارد - این به این معناست که فایل ردیابی شده‌ای در دایرکتوری کاری تغییر یافته اما هنوز مرحله بندی نشده است. برای مرحله بندی آن، از دستور git addاستفاده می‌کنید.

دستور git add چندمنظوره است - شما از آن برای شروع ردیابی فایل‌های جدید، مرحله بندی فایل‌ها و همچنین سایر کارها مانند علامت‌گذاری فایل‌های درگیر در ادغام به عنوان حل شده استفاده می‌کنید. می تواند مفید باشد که به آن به عنوان "اضافه کردن دقیقا همین محتوا به کامیت بعدی" فکر کنید تا "اضافه کردن این فایل به پروژه". بیایید اکنون git add را برای مرحله بندی اول CONTRIBUTING.md اجرا کنیم و سپس دوباره git status را اجرا کنیم:

$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

new file: README
modified: CONTRIBUTING.md

هر دو فایل اکنون مرحله بندی شده‌اند و به کامیت بعدی شما وارد خواهند شد. حال فرض کنید یک تغییر کوچک دیگر در CONTRIBUTING.md می‌خواهید انجام دهید قبل از اینکه آن را کامیت کنید. فایل را باز کرده و تغییر مورد نظر را اعمال کنید، و آماده کامیت هستید. اما بیایید یک بار دیگر git status را اجرا کنیم:

$ vim CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

 new file: README
modified: CONTRIBUTING.md

Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

 modified: CONTRIBUTING.md

چرا CONTRIBUTING.md هم به عنوان مرحله بندی شده و هم به عنوان ردیابی نشده فهرست شده است؟ این به این دلیل است که گیت فایلی را دقیقا به همان صورتی که شما دستور git add را اجرا کردید، مرحله بندی می‌کند. اگر اکنون کامیت کنید، نسخه CONTRIBUTING.md که به کامیت خواهد رفت همان نسخه‌ای است که آخرین بار دستور git add را اجرا کردید، نه نسخه‌ای که در دایرکتوری کاری شما هنگام اجرای git commit وجود دارد.

اگر پس از اجرای git add فایلی را تغییر دهید، باید دوباره git add را اجرا کنید تا آخرین نسخه فایل را مرحله بندی کنید:

$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

 new file: README
modified: CONTRIBUTING.md

وضعیت کوتاه

در حالی که خروجی git status بسیار جامع است، اما ممکن است کمی طولانی به نظر برسد. گیت همچنین یک فلگ وضعیت کوتاه دارد تا بتوانید تغییرات خود را به صورت فشرده‌تری مشاهده کنید. اگر دستور git status -s یا git status --short را اجرا کنید، خروجی بسیار ساده‌تری دریافت خواهید کرد:

$ git status -s
M  README
MM Rakefile
A  lib/git.rb
M  lib/simplegit.rb
?? LICENSE.txt

فایل‌های جدید که ردیابی نمی‌شوند، دارای "؟؟" در کنارشان هستند. فایل‌های جدیدی که به مرحله آماده سازی اضافه شده‌اند، علامت A دارند، و فایل‌های تغییر یافته با نام M نمایش داده می‌شوند. خروجی شامل دو ستون است - ستون سمت چپ وضعیت مرحله آماده سازی و ستون سمت راست وضعیت دایرکتوری کاری را نشان می‌دهد.

به عنوان مثال، در این خروجی، فایل README در دایرکتوری کاری تغییر یافته اما هنوز آماده سازی نشده است، در حالی که فایل lib/simplegit.rb تغییر یافته و آماده سازی شده است. فایل rakefile تغییر یافته، بنابراین تغییراتی در آن وجود دارد که هم آماده سازی شده و هم ردیابی نشده است.

نادیده گرفتن فایل‌ها

اغلب، شما با دسته‌ای از فایل‌ها روبه‌رو می‌شوید که نمی‌خواهید گیت به طور خودکار آن‌ها را اضافه یا حتی به عنوان فایل‌های ردیابی نشده نشان دهد. این فایل‌ها معمولاً فایل‌های تولید شده به صورت خودکار هستند، مانند فایل‌های لاگ یا فایل‌های تولید شده توسط سیستم ساخت شما. در این موارد، می‌توانید فایلی به نام .gitignore ایجاد کنید که الگوهایی برای نادیده گرفتن آن‌ها فهرست می‌کند.

به عنوان مثال، یک فایل .gitignore به صورت زیر است:

$ cat .gitignore
*.[oa]
*~

خط اول به گیت می‌گوید که هر فایلی که با a. یا o. پایان می‌یابد - فایل‌های شی و ارشیو که ممکن است نتیجه ساخت کد شما باشند - نادیده گرفته شود. خط دوم به گیت می‌گوید که تام فایل‌هایی که نامشان با (~) پایان می‌یابد، نادیده گرفته شوند؛ این علامت در بسیاری از ویرایشگرهای متن مانند emacs برای علامت‌گذاری فایل‌های موقت استفاده می‌شود.

شما همچنین می‌توانید در دایرکتوری مانند log, tmp یا pid را اضافه کنید؛ مستندات تولید شده به طور خودکار؛و غیره. به همین ترتیب تنظیم یک فایل .gitignore برای مخزن جدیدتان قبل از شروع کار عموماً ایده خوبی است تا به طور تصادفی فایل‌هایی را که واقعا نمی‌خواهید در مخزن گیت شما وجود داشته باشند، کامیت نکنید.

قوانین الگوها در فایل .gitignore

قوانین مربوط به الگوهایی که می‌توانید در فایل gitignore. قرار دهید به شرح زیر است:

خطوط خالی یا خطوطی که با # شروع می‌شوند، نادیده گرفته می‌شوند.

الگوهای glob استاندارد کار می‌کنند و به صورت بازگشتنی در سراسر دایرکتوری کاری اعمال می‌شوند.

می‌توانید الگوها را با یک اسلش(/) شروع کنید تا از بازگشت جلوگیری کنید.

می‌تونید الگوها را با یک اسلش(/) پایان دهید تا یک دایرکتوری تشخیص داده شود.

می‌توانید با شروع الگو با علامت تعجب (!) آن را نفی کنید.


الگوهای glob شبیه به عبارات منظم ساده هستند و که شل‌ها از آن‌ها استفاده می‌کنند. به عنوان مثال:

یک ستاره(*) صفر یا بیشتر کاراکتر را تطبیق می‌دهد.

ا[abc] هر کاراکتری را که داخل براکت‌ها است تطبیق می‌دهد. (در این مورد a,b یا c)

براکت‌های حاوی کاراکترها که با خط تیره جدا شده‌اند ([0-9])هر کاراکتری بین آن‌ها است تطبیق می‌دهد(در این مورد از ۰ تا ۹).

همچنین می‌توانید از دو ستاره برای تطبیق دایرکتوری‌های تو در تو استفاده کنید؛ a//z دایرکتوری‌های a/z,a/b/z,a/b/c/z و غیره را تطبیق می‌دهد.

مثال‌های دیگر از‌ gitignore.

# ignore all .a files
*.a

# but do track lib.a, even though you're ignoring .a files above
!lib.a

# only ignore the TODO file in the current directory, not subdir/TODO
/TODO

# ignore all files in any directory named build
build/

# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt

# ignore all .pdf files in the doc/ directory and any of its subdirectories
doc//*.pdf

گیت هاب فهرست نسبتاً جامع و خوب از مثال‌های gitignore. برای ده‌ها پروژه و زبان را در ادرس https://github.com/github/gitignore نگهداری می‌کند که می‌توانید برای پروژه‌تان به عنوان نقطه شروع از‌ آن استفاده کنید.

در حالت ساده، یک مخزن ممکن است یک فایل gitignore. در دایرکتوری ریشه‌اش داشته باشد که به صورت بازگشتی به کل مخزن اعمال می‌شود. با این حال، همچنین ممکن است فایل‌های gitignore. اضافی در دایرکتوری‌های زیرمجموعه وجود داشته باشد. قوانین در این فایل‌های gitignore. تو در تو تنها به فایل‌های زیر دایرکتوری که در آن قرار دارند، اعمال می‌شوند. به عنوان مثال، مخزن منبع هسته لینوکس ۲۰۶ فایل gitignore. دارد.

جزیئات بیشتر درباره فایل‌های gitignore. در محدوده این کتاب نیست؛ برای اطلاعات بیشتر به man gitignore. مراجعه کنید.

مشاهده‌ تغییرات مرحله‌بندی شده و مرحله بندی نشده

اگر خروجی دستور git status برای شما خیلی مبهم است و می‌خواهید دقیقا بدانید چه تغییراتی ایجاد کرده‌ایدد، می‌توانید از دستور git diff استفاده کنید. این دستور به شما کمک می‌کند تا دقیقاً خطوطی که اضافه حذف شده‌اند را مشاهده کنید. معمولاً از git diff برای پاسخ به دو سوال زیر استفاده می‌شود:

۱. چه تغییراتی ایجاد کرده‌ام اما هنوز مرحله‌بندی نکرده‌ام؟

۲. چه تغییراتی را مرحله‌بندی کرده‌ام که قرار است کامیت کنم؟

مشاهده تغییرات مرحله‌بندی‌نشده

برای دیدن تغییراتی که هنوز مرحله‌بندی‌ نشده اند، کافی است دستور git diff را بدون آرگومان‌های اضافی اجرا کنید:

$ git diff

خروجی به شما تغییرات ایجاد شده در فایل‌هایی که هنوز مرحله‌بندی نکرده‌اید را نمایش می‌دهد.

مشاهده تغییرت مرحله‌بندی شده

اگر می‌خواهید تغییراتی که مرحله‌بندی کرده‌اید و قرار است در کامیت بعدی قرار بگیرند را مشاهده کنید، می‌توانید از دستور git diff --staged استفاده کنید:

$ git diff --staged 

این دستور تغییرات مرحله‌بندی شده را با آخرین کامیت مقایسه می‌کند

مثال‌های عملی

فرض کنید شما فایل README را ویرایش و مرحله‌بندی کرده‌اید و سپس فایل CONTRIBUTING.md را ویرایش کرده‌اید بدون اینکه آن را مرحله‌بندی کنید. با اجرای git status ،خروجی به شکل زیر خواهد بود:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

 modified: README

Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

 modified: CONTRIBUTING.md

اکنون برای دیدن تغییرات فایل CONTRIBUTING.md که هنوز مرحله بندی نشده‌اند، از دستور git diff استفاده می‌کنید:

$ git diff

خروجی نشان می‌دهد که چه خطوطی اضافه شده یا تغییر یافته است.

مشاهده تغییرات پس از مرحله‌بندی

اگر فایل CONTRIBUTING.md را مرحله‌بندی کنید و سپس آن را ویرایش کنید، می‌توانید از git diff برای مشاهده تغییرات مرحله‌بندی شده و غیر مرحله‌بندی شده استفاده کنید. به عنوان مثال:

$ git add CONTRIBUTING.md
$ echo '# test line' >> CONTRIBUTING.md
$ git status

خروجی نشان می‌دهد که تغییرات جدیدی وجود دارد که هنوز مرحله‌بندی نشده‌اند.

سپس با استفاده از git diff می‌توانید تغییرات غیر مرحله‌بندی شده را مشاهد کنید:

$ git diff

این روش به شما این امکان را می‌دهد که به طور دقیق تغییرات ایجاد شده را پیگیری کنید و اطمینان حاصل کنید که همه چیز قبل از کامیت آماده است.

ویرایش تغییرات با استفاده از git diff --cached

برای مشاهده تغییراتی که تاکنون مرحله‌بندی کرده‌اید، می‌توانید از دستور git diff --cached (یا --staged که معادل آن است) استفاده کنید:

$ git diff --cached
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
Please include a nice description of your changes when you submit your PR;
if we have to read the whole diff to figure out why you're contributing
in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your patch is
+longer than a dozen lines.

If you are starting to work on a particular area, feel free to submit a PR
that highlights your work in progress (and note in the PR title that it's

استفاده از ابزارهای خارجی برای نمایش تغییرات

در ادامه کتاب، ما با استفاده از دستور git diff در روش‌های مختلف خواهیم پرداخت. اگر ترجیح می‌دهید از یک برنامه نمایش تفاوت گرافیکی یا خارجی استفاده کنید، می‌توانید به جای دستور git diff از git difftool استفاده کنید. این دستور به شما این امکان را می‌دهد که تغییرات را در نرم‌افزارهایی مانند emerge, vimdiff و سایر برنامه‌ها(شامل محصولات تجاری) مشاهده کنید. برای مشاهده گزینه‌های موجود در سیستم خود، می‌توانید دستور زیر را اجرا کنید:

$ git difftool --tool-help

ثبت تغییرات شما

حالا که مرحله آماده‌‌سازی شما به شکلی که می‌خواهید تنظیم شده، می‌توانید تغییرات خود را ثبت کنید. به یاد داشته باشید که هر چیزی که هنوز مرحله بندی نشده - هر فایلی که ایجاد یا ویرایش کرده‌اید و پس از ویرایش دستور git addرا اجرا نکرده‌اید - وارد این کامیت نمی‌شود. به عنوان فایل‌های ویرایش شده رو دیسک شما باقی می‌مانند. فرض کنید اخرین باری که دستور git status را اجرا کردید، دیدید که همه چیز مرحله‌بندی شده و بنابراین آماده‌اید تغییرات خود را ثبت کنید. ساده‌ترین راه برای ثit بت این است که:

$ git commit

با این کار ویرایشگر مورد نظر شما باز می‌شود. این ویرایشگر توسط متغیر محیطی EDITOR شل شما تنظیم می‌شود - معمولاً vim یا emacs، اگر چه می‌توانید آن را با استفاده از دستور git config --global core.editor به هر جیزی که می‌خواهید پیکربندی کنید. همینظور که در getting started دیدید.

ویرایشگر متنی چیزی شبیه به این را به شما نشان می‌دهد:

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with 'origin/master'.
#
# Changes to be committed:
#  new file: README
#  modified: CONTRIBUTING.md
#
~
~
~
".git/COMMIT_EDITMSG" 9L, 283C

شما می‌توانید مشاهده کنید که پیام ثبت پیش فرض شامل اخرین خروجی دستور git status است که به صورت کامنت نوشته شده و یک خط خالی در بالای آن وجود دارد. می‌توانید این کامنت را حذف کرده پ پیام ثبت خود را بنویسید یا اینکه آن‌ها را برای یادآوری تغییراتی که در حال ثبت هستید، حفظ کنید.

برای یادآوری صریح‌تر از تغییرات خود، می‌توانید گزینه - را به git commit اضافه کنید این کار همچنین تغییرات شما را در ویرایشگر نشان می‌دهد تا دقیقا ببینید چه تغییراتی را ثبت کرده می‌کنید.

زمانی که از ویرایشگر خارج می‌شوید، گیت کامیت شما را با آن پیام ثبت می‌کند‌(با حذف کامنت‌ها و تفاوت‌ها).

به طور جایگزین، می‌توانید پیام ثبت خود را به صورت خطی با استفاده از فلگ -m مشخص کنید:

$ git commit -m "Story 182: fix benchmarks for speed"

در این صورت خواهید دید که کامیت شما ایجاد شده و خروجی زیر را نشان می‌دهد:

[master 463dc4f] Story 182: fix benchmarks for speed
2 files changed, 2 insertions(+)
create mode 100644 README

حالا شما اولین کامیت خود را ایجاد کرده اید! می‌توانید ببینید که کامیت اطلاعاتی درباره خود دارد: کدام برنچ ثبت شده(master)،چه بررسی SHA-1 برای کامیت وجود دارد (463dc4f)، چه تعداد فایل تغییر کرده و آمار مربوط کامیت که چه خطوطی اضافه یا حذف شده است.

به یاد داشته باشید که کامیت وضعیت فعلی شما را که در مرحله آماده‌سازی تنظیم کرده‌اید، ضبط می‌کند. هر چیزی که مرحله بندی نکردید هنوز به عنوان ویرایش شده باقی‌مانده است؛ می‌توانید یک کامیت دیگر برای اضافه کردن آن به تاریخچه‌تان انجام دهید. هر بار که ثبت می‌کنید، یک snapshot از پروژه خود را کامیت می‌:نید می‌توانید بعداً به آن بازگردید یا مقایسه کنید.

عبور از مرحله آماده سازی

اگرچه مرحله آماده‌سازی می‌تواند بسیار مفید باشد، گاهی اوقات کمی پیچیده‌تر از آن چیزی است که در جریان کار خود نیاز دارید. اگر بخواهید از منطقه مرحله‌بندی عبور کنید گیت یک میانبر ساده ارائه می‌دهد. با افزودن گزینه -a به دستور git commit ، گیت به‌طور خودکار هر فایلی که قبلاً پیگیری شده را قبل از ثبت، مرحله‌بندی می‌کند و شما می‌توانید بخش git add را نادیده بگیرید:

$ git commit -a -m 'Add new benchmarks'

در این حالت نیازی نیست قبل از ثبت، دستور git add را برای فایل CONTRIBUTING.md اجرا کنید. این به این دلیل است که فلگ -a شامل تمام فایل‌های تغییر کرده است. این کار راحت است، اما احتیاط کنید؛ گاهی اوقات این فلگ ممکن است باعث شود تغییرات ناخواسته‌ای را شامل کنید.

حذف فایل ها

برای حذف یک فایل از گیت، باید آن را از فایل‌های بررسی شده‌تان حذف کنید (به‌عبارت دقیق‌تر، آن را از منطقه مرحله آماده سازی خود حذف کنید) و سپس ثبت کنید. دستور git rm این کار را انجام می‌دهد و همچنین فایل را از دایرکتوری کاری شما حذف می‌کند تا در دور بعدی به‌عنوان یک فایل بدون بررسی نشان داده نشود. اگر فقط فایل را از دایرکتوری کاری خود حذف کنید، در بخش "Changes not staged for commit" (یعنی بخش unstaged) خروجی git statusشما نشان داده می‌شود:

$ rm PROJECTS.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

deleted: PROJECTS.md

سپس، اگر git rmرا اجرا کنید، حذف فایل را مرحله‌بندی می‌کند:

$ git rm PROJECTS.md
rm 'PROJECTS.md'
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

deleted: PROJECTS.md

بار بعد که ثبت کنید، فایل حذف و دیگر پیگیری نخواهد شد. اگر فایل را تغییر داده‌اید یا قبلاً آن را به منطقه مرحله‌بندی اضافه کرده‌اید، باید با گزینه -f حذف را به‌صورت اجباری انجام دهید. این یک ویژگی ایمنی است تا از حذف تصادفی داده‌هایی که هنوز در یک عکس‌العمل ثبت نشده‌اند و نمی‌توانند از گیت بازیابی شوند، جلوگیری کند.

مفهوم مفید دیگری که ممکن است بخواهید انجام دهید، نگه‌داشتن فایل در درخت کاری (working tree) خود، اما حذف آن از ناحیه‌ی مرحله بندی. به عبارت دیگر، ممکن است بخواهید فایل را روی هارد خود نگه‌دارید اما دیگر گیت آن را ردیابی نکند. این کار به‌خصوص زمانی مفید است که فراموش کرده‌اید چیزی را به فایل .gitignore اضافه کنید و به‌طور تصادفی آن را مرحله بندی کرده‌اید، مانند یک فایل لاگ بزرگ یا مجموعه‌ای از فایل‌های کامپایل شده با پسوند .a. برای انجام این کار، از گزینه --cached استفاده کنید:

$ git rm --cached README

شما می‌توانید فایل‌ها، دایرکتوری‌ها و الگوهای فایل‌گلوب را به دستور git rm پاس دهید. به این معنی که می‌توانید کارهایی مانند زیر را انجام دهید:

$ git rm log/*.log

به backslash در جلوی * توجه کنید. این کار ضروری است زیرا گیت علاوه بر گسترش نام فایل توسط شل شما، خود نیز گسترش نام فایل را انجام می‌دهد. این دستور تمام فایل‌هایی که پسوند .log در دایرکتوری log/ دارند را حذف می‌کند. یا می‌توانید کاری مشابه این انجام دهید:

$ git rm *~

این دستور تمام فایل‌هایی که نامشان با ~ به پایان می‌رسد را حذف می‌کند.

جا‌به‌جایی فایل ها

برخلاف بسیاری از سیستم‌های کنترل نسخه (VCS)، گیت به‌طور صریح حرکت فایل‌ها را ردیابی نمی‌کند. اگر فایلی را در گیت تغییر نام دهید، هیچ متاداده‌ای در گیت ذخیره نمی‌شود که به آن بگوید فایل تغییر نام داده شده است. با این حال، گیت در شناسایی این موضوع پس از واقعیت هوشمند است — که در ادامه به تشخیص حرکت فایل‌ها خواهیم پرداخت.

بنابراین، کمی گیج‌کننده است که گیت یک دستور mv دارد. اگر می‌خواهید فایلی را در گیت تغییر نام دهید، می‌توانید چیزی شبیه به این اجرا کنید:

$ git mv file_from file_to

و این به‌خوبی کار می‌کند. در واقع، اگر چیزی شبیه به این را اجرا کنید و وضعیت را بررسی کنید، خواهید دید که گیت آن را به‌عنوان یک فایل تغییر نام داده شده در نظر می‌گیرد:

$ git mv README.md README
$ git status

خروجی:

On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

 renamed: README.md -> README

با این حال، این معادل اجرای چیزی شبیه به این است:

$ mv README.md README
$ git rm README.md
$ git add README

گیت به‌طور ضمنی متوجه می‌شود که این یک تغییر نام است، بنابراین فرقی نمی‌کند که فایل را به این روش تغییر نام دهید یا با دستور mv. تنها تفاوت واقعی این است که git mv یک دستور است که به جای سه دستور دیگر، به‌صورت یکجا اجرا می‌شود — که یک عملکرد راحتی است. مهم‌تر اینکه، می‌توانید از هر ابزاری که دوست دارید برای تغییر نام یک فایل استفاده کنید و بعداً، قبل از کامیت، به اضافه کردن و حذف آن بپردازید.

مشاهده تاریخچه کامیت‌ها

پس از ایجاد چندین کامیت یا کلون کردن یک مخزن با تاریخچه موجود، احتمالاً می‌خواهید به تاریخچه نگاه کنید. ابزار اصلی برای این کار، دستور git log است.

این مثال‌ها از یک پروژه ساده به نام "simplegit" استفاده می‌کنند. برای دریافت پروژه، فرمان زیر را اجرا کنید:

$ git clone https://github.com/schacon/simplegit-progit

زمانی که دستور git log را در این پروژه اجرا کنید، خروجی مشابه زیر را دریافت می‌کنید:

$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700

 Change version number

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 16:40:33 2008 -0700

 Remove unnecessary test

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 10:31:28 2008 -0700

 Initial commit

به طور پیش فرض، بدون هیچ آرگومانی، git log کامیت‌های موجود در آن مخزن را به ترتیب معکوس زمانی نمایش می‌دهد؛ یعنی جدیدترین کامییت‌ها ابتدا نمایش داده می‌شوند. همان طور که می‌بینید، این دستور هر کامیت را با هش SHA-1، نام و ایمیل نویسنده، تاریخ و پیام کامیت فهرست می‌کند.

گزینه‌ها و تنوع زیادی برای دستور git log وجود دارد که به شما کمک می‌کند دقیقا آنچه را که به دنبال آن هستید پیدا کنید. یکی از گزینه‌های مفید، -p یا --patch است که تفاوت‌ها(خروجی patch)ایجاد شده در هر کامیت را نمایش می‌دهد. همچنین می‌توانید تعداد ورودی‌های لاگ نمایش داده شده را محدود کنید، مثلا با استفاده از -2 که فقط دو ورودی آخر را نشان می‌دهد.

$ git log -p -2
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700

 Change version number

diff --git a/Rakefile b/Rakefile
index a874b73..8f94139 100644
--- a/Rakefile
+++ b/Rakefile
@@ -5,7 +5,7 @@ require 'rake/gempackagetask'
spec = Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.name = "simplegit"
- s.version = "0.1.0"
+ s.version = "0.1.1"
s.author = "Scott Chacon"
s.email = "schacon@gee-mail.com"
s.summary = "A simple gem for using Git in Ruby code."

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 16:40:33 2008 -0700

 Remove unnecessary test

diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index a0a60ae..47c6340 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -18,8 +18,3 @@ class SimpleGit
    end

end
-
-if $0 == __FILE__
- git = SimpleGit.new
- puts git.show
-end

این گزینه همان اطلاعات را نمایش می‌دهد، اما با تفاوت‌های که به‌طور مستقیم پس از هر ورودی قرار دارد. این امر برای باز بینی کد یا مرور سریع آنچه در طول یک سری کامیت‌هایی که یک همکار اضافه کرده، بسییار مفید است. همچنین می‌توانید از مجموعه‌ای از گزینه‌های خلاصه‌سازی با دستور git log استفاده کنید. به عنوان مثال، اگر بخواهید آمار مختصری از هر کامیت مشاهده کنید، می‌توانید از گزینه --stat استفاده کنید:

    $ git log --stat
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700

 Change version number

 Rakefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 16:40:33 2008 -0700

 Remove unnecessary test

 lib/simplegit.rb | 5 -----
1 file changed, 5 deletions(-)

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 10:31:28 2008 -0700

 Initial commit

 README | 6 ++++++
Rakefile | 23 +++++++++++++++++++++++
lib/simplegit.rb | 25 +++++++++++++++++++++++++
3 files changed, 54 insertions(+)

همان طور که مشاهده می‌کنید، گزینه --stat زیر هر ورودی کامیت، فهرستی از فایل‌های اصلاح شده، حذف شده در آن فایل‌ها را چاپ می‌کند. همچنین، خلاصه‌ای از اطلاعات را در انتها ارائه می‌دهد.

گزینه دیگری که واقعاً مفید است، --pretty است. این گزینه خروجی لاگ را به فرمت‌های دیگری غیر از فرمت پیش فرض تغییر می‌دهد. چندین مقدار پیش ساخته برای این گزینه در دسترس است. مقدار one live برای این گزینه هر کامیت را در یک خط نمایش می‌دهد که برای مرور تعداد زیادی کامیت بسیار کاربردی است. علاوه بر این، مقادیر short و full و fuller خروجی را تقریبا در همان فرمت اما با اطلاعات کمتر یا بیشتر، به ترتیب، نشان می‌دهند:

    $ git log --pretty=oneline
ca82a6dff817ec66f44342007202690a93763949 Change version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Remove unnecessary test
a11bef06a3f659402fe7563abf99ad00de2209e6 Initial commit

گزینه format در git log به شما این امکان را می‌دهد که فرمت خروجی لاگ را به دلخواه خود تعیین کنید. این ویژگی به خصوص زمانی مفید است که می‌خواهید خروجی را برای پردازش ماشین تولید کنید؛ زیرا با تعیین صریح فرمت، اطمینان دارید که خروجی با به روزرسانی‌های گیت تغییر نخواهد کرد. این امر باعث می‌شود که بتوانید به راحتی خروجی را در برنامه‌ها یا اسکریپت‌های خود استفاده کنید و از ثبات آن مطمئن باشید.

$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 6 years ago : Change version number
085bb3b - Scott Chacon, 6 years ago : Remove unnecessary test
a11bef0 - Scott Chacon, 6 years ago : Initial commit

دستور git log --pretty=format گزینه‌های مختلفی برای فرمت کردن خروجی لاگ‌های گیت ارائه می‌دهد.

جدول۱. دستور‌های مفید برای git log --pretty=format

SpecifierDescription
%HCommit hash
%hAbbreviated commit hash
%TTree hash
%tAbbreviated tree hash
%PParent hashes
%pAbbreviated parent hashes
%anAuthor name
%aeAuthor email
%adAuthor date (format respects the --date=option)
%arAuthor date, relative
%cnCommitter name
%ceCommitter email
%cdCommitter date
%crCommitter date, relative
%sSubject

شاید برایتان جالب باشد که تفاوت بین نویسنده و کامیت‌کننده چیست. نویسنده کسی است که به‌طور اولیه اثر را نوشته، در حالی که کامیت‌کننده شخصی است که آخرین بار کار را اعمال کرده است. بنابراین، اگر شما یک پچ به یک پروژه ارسال کنید و یکی از اضای اصلی آن پچ را اعمال کند، هم شما و هم آن عضو اعتبار دریافت می‌کند - شما به عنوان نویسنده و آن عضو به کامیت کننده. در مورد این تفاوت بیشتر در بخش گیت توزیع شده بحث خواهیم کرد.

مقادیر گزینه‌های oneline و format به ویژه با گزینه دیگری از لاگ به نام --graph بسیار مفید هستند. این گزینه یک تمودار ASCII کوچک و زیبا اضافه می‌کند که تاریخچه برنچ و ادغام‌های شما را نشان می‌دهد.

    $ git log --pretty=format:"%h %s" --graph
* 2d3acf9 Ignore errors from SIGCHLD on trap* 5e3ee11 Merge branch 'master' of https://github.com/dustin/grit.git
|\
| * 420eac9 Add method for getting the current branch
* | 30e367c Timeout code and tests
* | 5a09431 Add timeout protection to grit
* | e1193f8 Support for heads with slashes in them
|/
* d6016bc Require time for xmlschema
* 11d191e Merge branch 'defunkt' into local

این نوع خروجی با ادامه مباحث مربوط به برنچ‌سازی و ادغام در فصل بعد جالب‌تر خواهد شد.

این‌ها تنها برخی از گزینه‌های ساده برای فرمت‌دهی خروجی در git log هستند و گزینه‌های بیشتری نیز وجود دارد. بخش "گزینه های رایج برای git log " شامل گزینه‌هایی است که تاکنون بررسی کرده‌ایم و همچنین برخی دیگر از گزینه‌های رایج فرمت‌دهی که ممکن است مفید باشند، به همراه توضیحاتی درباره نحوه تغییر خروجی دستور لاگ است.

جدول 2. گزینه های رایج برای git log

OptionDescription
-pShow the patch introduced with each commit.
--statShow statistics for files modified in each commit.
--shortstatDisplay only the changed/insertions/deletions line from the --stat command.
--name-onlyShow the list of files modified after the commit information.
--name-statusShow the list of files affected with added/modified/deleted information.
--abbrev-commitShow only the first few characters of the SHA-1 checksum instead of all 40.
--relative-dateDisplay the date in a relative format (e.g., "2 weeks ago") instead of the full date format.
--graphDisplay an ASCII graph of the branch and merge history beside the log output.
--prettyShow commits in an alternate format. Option values include oneline, short, full, fuller, and format.
--onelineShorthand for --pretty=oneline --abbrev-commit used together.