Git
Chapters ▾ 2nd Edition

2.2 مقدمات گیت - ثبت تغییرات در مخزن

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

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

بخاطر داشته باشید که هر فایل در پوشه کاری شما می‌تواند یکی از این دو حالت را داشته باشد: Tracked (رهگیری شده) یا Untracked (دنبال نشده). فایل‌های رهگیری شده فایل‌هایی هستند که در آخرین اسنپ‌شات شما بوده‌اند؛ آن‌ها می‌توانند ویرایش‌نشده، ویرایش‌شده یا استیج‌شده داشته باشند. به طور خلاصه، فایل‌های رهگیری شده آنهایی هستند که گیت آن‌ها را می‌شناسد.

فایل‌های رهگیری نشده مابقی فایل‌ها هستند — هر فایلی در اسنپ‌شات آخر شما نبوده باشد و شما آن را add نکرده باشید. در ابتدا، هنگامی که مخزنی را کلون می‌کنید، همهٔ فایل‌ها رهگیری‌شده و دست نخورده هستند زیرا گیت همین الآن آنها را چک‌اوت کرده است و چیزی ویرایش نشده است.

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

The lifecycle of the status of your files.
نمودار 8. چرخه عمر وضعیت فایل‌های شما.

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

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

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

این بدین معنی است که پوشه کاری شما تمیز است؛ به زبان دیگر، هیچ کدام از فایل‌های رهگیری‌شده شما ویرایش نشده‌اند. علاوه بر این گیت هیچ فایل دنبال نشده‌ای نمی‌بینید، اگر می‌دید در اینجا لیست می‌شد. در آخر، این دستور به شما می‌گوید که بر روی کدام شاخه و شعبه هستید و به شما اطلاع می‌دهد که شاخه مذکور از شاخه‌ای که از سرور آمده جدا نشده است. فعلاً، آن شاخه همیشه 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 جدیدتان در حالت رهگیری‌نشده است، چون وضعیت فایل در زیر تیتر «Untracked files» خروجی است. به طوری کلی رهگیری‌نشده به این معنی است که گیت فایلی یافته است که در اسنپ‌شات (کامیت) قبلی نداشته‌اید؛ گیت آن را به اسنپ‌شات کامیت‌های بعدی اضافه نمی‌کند تا زمانی که شما صراحتاً به گیت بگویید که این کار را کند. گیت این کار را می‌کند تا شما‌ به صورت اتفاقی شروع به اضافه کردن فایل‌های اجرایی ساخته‌شده یا دیگر فایل‌هایی که نمی‌خواهید به مخزن اضافه شوند نکنید. شما می‌خواهید شروع به اضافه کردن فایل 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 وجود داشته است. ممکن است به خاطر داشته باشید که پیشتر، دستور 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]
*~

خط اول به گیت می‌گوید که هر فایلی که با .o یا .a تمام ‌می‌شود را نادیده بگیرد — فایل‌های آرشیو یا آبجکت‌هایی که ممکن است حاصل خروجی کد شما باشند. خط دوم به گیت می‌گوید که همهٔ فایل‌های که نامشان با علامت مد (~) پایان‌یافته است را نادیده بگیرد، علامتی که توسط کثیری از ویرایشگرها مانند ایمکس استفاده می‌شود تا فایل‌های موقت را علامت‌گذاری کنند. شاید حتی یک پوشهٔ log، tmp و یا pid، فایل مستنداتی که خودکار ساخته شده‌اند و سایر را هم اضافه کنید. راه‌اندازی یک فایل .gitignore برای مخزن جدیدتان پیش از اینکه کار خود را شروع کنید تمرین خوبی است چرا که نمی‌خواهید به طور اتفاقی فایل‌هایی را کامیت کنید که قصد ذخیره آنها را در مخزن گیت خود نداشته‌اید.

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

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

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

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

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

  • می‌توانید الگویی را با اضافه کردن علامت تعجب (!) برعکس کنید.

الگو‌های گلاب مانند عبارات منظم ساده شده‌ای هستند که شل‌ها از آن استفاده می‌کنند. یک ستاره (*) با یک یا چند حرف تطبیق داده می‌شود؛ [abc] هر حرفی که داخل براکت یا قلاب باشد را تطبیق می‌دهد (در این مثال a، b، یا c هستند)؛ یک علامت سوال (?) یک تک حرف را تطبیق می‌دهد؛ و براکت‌هایی که حروفی را که با خط تیره از هم جدا شده باشند ([9-0]) را محاصره کرده باشند هر حرفی که در آن مجموعه وجود داشته باشند را پیدا می‌کند (در این مورد هر عددی که بین 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 status جواب آن سؤالات را به صورت کلی، به واسطه لیست کردن نام‌های فایل‌ها خواهد داد، اما git diff جزئیات دقیق خطوط اضافه و حذف شده — انگار پچ آنرا — به شما نشان می‌دهد.

فرض کنیم که شما از دوباره فایل 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

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

$ git diff
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 --staged استفاده کنید. این دستور آخرین کامیتتان را با تغییرات استیج مقایسه می‌کند:

$ git diff --staged
diff --git a/README b/README
new file mode 100644
index 0000000..03902a1
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+My Project

خیلی مهم است که دقت کنید که git diff خودش به تنهایی تمام تغییرات ایجاد شده از آخرین کامیت را نشان نمی‌دهد — بلکه فقط تغییراتی که هنوز استیج نشده‌اند را به نمایش می‌گذارد. اگر شما تغییراتی را به استیج کنید، git diff خروجی به شما نمی‌دهد.

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

$ git add CONTRIBUTING.md
$ echo '# test line' >> 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)

    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

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

$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 643e24f..87f08c8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -119,3 +119,4 @@ at the
 ## Starter Projects

 See our [projects list](https://github.com/libgit2/libgit2/blob/development/PROJECTS.md).
+# test line

و git diff --cached برای اینکه ببینید چه چیزی را تا اینجای کار استیج کرده‌اید (--staged و --cached مترادف هستند):

$ 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 را به جای git diff اجرا کنید، می‌تواند هر کدام از این دیف‌ها را در نرم‌افزارهایی مثل emerge، vimdiff و غیره (شامل نرم‌افزارهای تجاری) ببینید. دستور git difftool --tool-help را اجرا کنید تا ببنید که چه ابزارهایی بر روی سیستم شما موجود است.

کامیت کردن تغییراتتان

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

$ git commit

انجام این کار ویرایشگرتان را باز می‌کند.

یادداشت

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

ویرایشگر متن زیر را به نمایش می‌گذارد (این مثال یک صفحه ویم است):

# 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 به صورت کامنت شده و یک خط خالی در بالای آن است. شما می‌توانید تمام این کامنت‌ها را حذف کرده و پیام خود را بنویسید، یا می‌توانید همانطور آنها رها کنید تا به شما یادآوری کنند که در حال کامیت کردن چه چیزی هستید.

یادداشت

برای یادآوری صریح‌تر مواردی که ویرایش کرده‌اید، آپشن -v را به git commit بدهید. انجام این کار همچنین دیف تغییراتتان را در ویرایشگر قرار می‌دهد تا بتوانید ببینید دقیقاً چه تغییراتی را کامیت می‌کنید.

وقتی از ادیتور خارج می‌شوید، گیت کامیت مورد نظر شما را با پیام کامیتی که نوشته‌اید (بدون کامنت‌ها و دیف‌ها) می‌سازد.

به عنوان یک روش دیگر، می‌توانید پیام کامیت خود را به صورت درون خطی همراه با دستور 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)، چه فایل‌هایی تغییر کرده‌اند و آمارهایی در کامیت جاری درباره خط‌هایی که اضافه یا حذف شده‌اند.

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

گذر از استیج

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

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
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

no changes added to commit (use "git add" and/or "git commit -a")
$ git commit -a -m 'Add new benchmarks'
[master 83e38c7] Add new benchmarks
 1 file changed, 5 insertions(+), 0 deletions(-)

دقت کنید که در این مورد دیگر لازم نیست قبل از اینکه کامیت کنید، دستور 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

no changes added to commit (use "git add" and/or "git commit -a")

سپس، اگر دستور 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 حذف آنرا تحمیل کنید. این یک امکان امنیتی برای جلوگیری از حذف تصادفی داده‌هایی است که هنوز در اسنپ‌شاتی ثبت نشده‌اند و نمی‌توانند توسط گیت بازیابی شوند.

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

$ git rm --cached README

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

$ git rm log/\*.log

به بک‌اسلش(‍\) مقابل * دقت کنید. این لازم است چراکه گیت گسترش نام‌فایل (Filename Expansion) خودش را مازاد بر گسترش نام‌فایل شل شما انجام می‌دهد. این دستور تمام فایل‌هایی که با پسوند .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 add/rm را اجرا کنید.

scroll-to-top