-
1. شروع به کار (getting started)
-
2. مقدمات گیت (git basics chapter)
- 2.1 گرفتن یک مخزن گیت (Getting a Git Repository)
- 2.2 ثبت تغییرات در مخزن (Recording Changes to the Repository)
- 2.3 مشاهده تاریخچه کامیتها (Viewing the Commit History)
- 2.4 بازگرداندن تغییرات (Undoing Things)
- 2.5 کار کردن با ریموت ها (Working with Remotes)
- 2.6 تگ کردن (Tagging)
- 2.7 نام مستعار گیت (Git Aliases)
- 2.8 خلاصه (summary)
-
3. انشعابگیری در گیت (Git Branching)
-
4. گیت روی سرور (Git on the server)
- 4.1 پروتکلها (The Protocols)
- 4.2 راهاندازی گیت روی یک سرور (Getting Git on a Server)
- 4.3 ایجاد کلید عمومی SSH شما (Generating Your SSH Public Key)
- 4.4 نصب و راهاندازی سرور (Setting up server)
- 4.5 سرویسدهنده گیت (Git Daemon)
- 4.6 HTTP هوشمند (Smart HTTP)
- 4.7 گیتوب (GitWeb)
- 4.8 گیتلب (GitLab)
- 4.9 گزینههای میزبانی شخص ثالث (Third Party Hosted Options)
- 4.10 خلاصه (Summary)
-
5. گیت توزیعشده (Distributed git)
-
6. GitHub (گیت هاب)
-
7. ابزارهای گیت (Git Tools)
- 7.1 انتخاب بازبینی (Revision Selection)
- 7.2 مرحلهبندی تعاملی (Interactive Staging)
- 7.3 ذخیره موقت و پاکسازی (Stashing and Cleaning)
- 7.4 Signing Your Work (امضای کارهای شما)
- 7.5 جستجو (Searching)
- 7.6 بازنویسی تاریخچه (Rewriting History)
- 7.7 بازنشانی به زبان ساده (Reset Demystified)
- 7.8 ادغام پیشرفته (Advanced Merging)
- 7.9 بازاستفاده خودکار از حل تضادها (Rerere)
- 7.10 اشکالزدایی با گیت (Debugging with Git)
- 7.11 سابماژول ها (Submodules)
- 7.12 بستهبندی (Bundling)
- 7.13 جایگزینی (Replace)
- 7.14 ذخیرهسازی اطلاعات ورود (Credential Storage)
- 7.15 خلاصه (Summary)
-
8. سفارشیسازی Git (Customizing Git)
-
9. گیت و سیستمهای دیگر (Git and Other Systems)
-
10. (Git Internals)
- 10.1 ابزارها و دستورات سطح پایین (Plumbing and Porcelain)
- 10.2 اشیا گیت (Git Objects)
- 10.3 مراجع گیت (Git References)
- 10.4 فایلهای بسته (Packfiles)
- 10.5 نگاشت (The Refspec)
- 10.6 پروتکلهای انتقال (Transfer Protocols)
- 10.7 نگهداری و بازیابی دادهها (Maintenance and Data Recovery)
- 10.8 متغیرهای محیطی (Environment Variables)
- 10.9 (Summary)
-
A1. پیوست A: گیت در محیطهای دیگر (Git in Other Environments)
- A1.1 رابط های گرافیکی (Graphical Interfaces)
- A1.2 Git در ویژوال استودیو (Git in Visual Studio)
- A1.3 Git در Visual Studio Code (Git in Visual Studio Code)
- A1.4 Git در IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine (Git in IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine)
- A1.5 Git در Sublime Text (Git in Sublime Text)
- A1.6 گیت در بش (Git in Bash)
- A1.7 Git در Zsh (Git in Zsh)
- A1.8 Git در PowerShell (Git in PowerShell)
- A1.9 خلاصه (Summary)
-
A2. پیوست B: گنجاندن گیت در برنامههای شما (Embedding Git in your Applications)
-
A3. پیوست C: دستورات گیت (Git Commands)
- A3.1 تنظیم و پیکربندی (Setup and Config)
- A3.2 گرفتن و ایجاد پروژهها (Getting and Creating Projects)
- A3.3 نمونهبرداری پایهای (Basic Snapshotting)
- A3.4 انشعابگیری و ادغام (Branching and Merging)
- A3.5 بهاشتراکگذاری و بهروزرسانی پروژهها (Sharing and Updating Projects)
- A3.6 بازرسی و مقایسه (Inspection and Comparison)
- A3.7 عیبیابی (Debugging)
- A3.8 اعمال تغییرات به صورت پچ (Patching)
- A3.9 ایمیل (Email)
- A3.10 سیستمهای خارجی (External Systems)
- A3.11 مدیریت (Administration)
- A3.12 دستورات سطح پایین گیت (Plumbing Commands)
5.3 گیت توزیعشده (Distributed git) - نگهداری یک پروژه (Maintaining a Project)
نگهداری یک پروژه (Maintaining a Project)
علاوه بر دانستن نحوه مشارکت مؤثر در یک پروژه، احتمالاً باید بدانید چگونه آن را نگهداری کنید.
این کار میتواند شامل پذیرش و اعمال اصلاحاتی باشد که از طریق format-patch
ایجاد شده و به شما ایمیل شدهاند، یا ادغام تغییرات در شاخههای راه دور برای مخازنی که به عنوان ریموت به پروژه خود اضافه کردهاید.
چه شما مسئول نگهداری یک مخزن رسمی باشید و چه بخواهید با تأیید یا تصویب اصلاحات کمک کنید، باید بدانید چگونه کار را به گونهای بپذیرید که برای سایر مشارکتکنندگان واضح باشد و در درازمدت برای شما پایدار بماند.
کار در شاخههای موضوعی (Working in Topic Branches)
وقتی قصد دارید کاری جدید را ادغام کنید، معمولاً بهتر است آن را در یک شاخه موضوعی امتحان کنید — شاخهای موقتی که به طور خاص برای آزمایش آن کار جدید ایجاد میشود.
به این ترتیب، میتوانید به راحتی یک اصلاحیه را به صورت جداگانه تنظیم کنید و اگر کار نمیکند آن را کنار بگذارید تا وقتی که وقت داشته باشید دوباره به آن برگردید.
اگر نام سادهای برای شاخه بر اساس موضوع کاری که میخواهید امتحان کنید انتخاب کنید، مانند ruby_client
یا چیزی مشابه که توصیفی باشد، به راحتی میتوانید آن را به خاطر بسپارید اگر مجبور شوید برای مدتی آن را رها کنید و بعداً برگردید.
نگهدارنده پروژه Git معمولاً این شاخهها را نیز با نامگذاری فضا (namespace) مشخص میکند — مثلاً sc/ruby_client
که در آن sc
مخفف نام شخصی است که کار را ارائه داده است.
همانطور که به یاد دارید، میتوانید شاخه را بر اساس شاخه master
خود اینگونه ایجاد کنید:
$ git branch sc/ruby_client master
یا اگر میخواهید بلافاصله به آن سوئیچ کنید، میتوانید از گزینه checkout -b
استفاده کنید:
$ git checkout -b sc/ruby_client master
حالا آمادهاید که کار ارسالی را که دریافت کردهاید به این شاخه موضوعی اضافه کنید و تصمیم بگیرید که آیا میخواهید آن را به شاخههای بلندمدت خود ادغام کنید یا خیر.
اعمال اصلاحات از طریق ایمیل (Applying Patches from Email)
اگر اصلاحیهای از طریق ایمیل دریافت کردید که باید آن را در پروژه خود ادغام کنید، لازم است ابتدا آن اصلاحیه را در شاخه موضوعی خود اعمال کنید تا آن را ارزیابی نمایید.
دو روش برای اعمال اصلاحیه ایمیلی وجود دارد: با git apply
یا با git am
.
اعمال یک پچ با apply
(Applying a Patch with apply
)
اگر اصلاحیه را از کسی دریافت کردید که آن را با git diff
یا نسخهای از دستور یونیکس diff
ایجاد کرده است (که توصیه نمیشود؛ بخش بعدی را ببینید)، میتوانید آن را با فرمان git apply
اعمال کنید.
فرض کنیم اصلاحیه را در مسیر /tmp/patch-ruby-client.patch
ذخیره کردهاید، میتوانید به این صورت اعمالش کنید:
$ git apply /tmp/patch-ruby-client.patch
این کار فایلها را در دایرکتوری کاری شما تغییر میدهد.
این تقریباً مشابه اجرای دستور patch -p1
برای اعمال اصلاحیه است، با این تفاوت که git apply
محتاطتر است و تطابقهای مبهم کمتری را میپذیرد.
همچنین اگر افزودن، حذف یا تغییر نام فایلها در فرمت git diff
توصیف شده باشد، آن را مدیریت میکند، کاری که patch
انجام نمیدهد.
در نهایت، git apply
یک مدل "همه را اعمال کن یا همه را لغو کن" است، یعنی یا همه اصلاحات اعمال میشوند یا هیچکدام، در حالی که patch
ممکن است اصلاحات را به صورت ناقص اعمال کند و دایرکتوری کاری شما را در وضعیت نامناسبی قرار دهد.
در مجموع، git apply
بسیار محافظهکارانهتر از patch
است.
این فرمان برای شما کامیت ایجاد نمیکند — بعد از اجرای آن باید تغییرات را به صورت دستی استیج و کامیت کنید.
همچنین میتوانید از git apply
استفاده کنید تا ببینید آیا اصلاحیه به صورت تمیز اعمال میشود یا خیر، قبل از اینکه واقعاً آن را اعمال کنید — میتوانید با گزینه --check
این کار را انجام دهید:
$ git apply --check 0001-see-if-this-helps-the-gem.patch
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
اگر خروجیای نداشت، یعنی اصلاحیه باید بهخوبی اعمال شود. این فرمان همچنین در صورت شکست بررسی، با کد خطای غیر صفر خارج میشود، بنابراین میتوانید آن را در اسکریپتها به کار ببرید.
اعمال پچ با am
(Applying a Patch with am
)
اگر مشارکتکننده از کاربران گیت باشد و به اندازه کافی حرفهای باشد که از فرمان format-patch
برای تولید پچ خود استفاده کند، کار شما آسانتر خواهد بود چون پچ شامل اطلاعات نویسنده و پیام کامیت برای شما است.
اگر میتوانید، مشارکتکنندگان خود را تشویق کنید تا به جای استفاده از diff
، برای تولید پچها از format-patch
استفاده کنند.
شما معمولاً فقط برای پچهای قدیمی و موارد مشابه نیاز دارید از git apply
استفاده کنید.
برای اعمال پچی که با format-patch
تولید شده است، از git am
استفاده میکنید (نام فرمان am
به این دلیل است که برای «اعمال مجموعهای از پچها از یک صندوق پستی» به کار میرود).
از نظر فنی، git am
برای خواندن فایل mbox طراحی شده است، که یک فرمت ساده و متنی برای ذخیرهسازی یک یا چند ایمیل در یک فایل متنی است.
این فرمت چیزی شبیه به این است:
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] Add limit to log function
Limit log functionality to the first 20
این ابتدای خروجی فرمان git format-patch
است که در بخش قبل دیدید؛ همچنین نمایانگر یک فرمت ایمیل معتبر mbox است.
اگر کسی پچ را به درستی از طریق git send-email
برای شما ایمیل کرده باشد و شما آن را در قالب mbox دانلود کنید، میتوانید به git am
اشاره کنید که آن فایل mbox را بخواند و شروع به اعمال همه پچهای موجود در آن کند.
اگر از یک کلاینت ایمیل استفاده میکنید که میتواند چند ایمیل را در قالب mbox ذخیره کند، میتوانید کل سری پچها را در یک فایل ذخیره کرده و سپس با git am
آنها را یکییکی اعمال کنید.
با این حال، اگر کسی فایل پچی که با git format-patch
تولید شده را در یک سیستم تیکتینگ یا مشابه آن بارگذاری کرده باشد، میتوانید آن فایل را به صورت محلی ذخیره کرده و سپس آن فایل ذخیره شده روی دیسک را به git am
بدهید تا اعمال شود:
$ git am 0001-limit-log-function.patch
Applying: Add limit to log function
میبینید که پچ بهصورت تمیز اعمال شده و به طور خودکار کامیت جدیدی برای شما ساخته است.
اطلاعات نویسنده از سربرگهای From
و Date
ایمیل گرفته شده و پیام کامیت نیز از Subject
و متن ایمیل (قبل از پچ) استخراج میشود.
برای مثال، اگر این پچ از نمونه mbox بالا اعمال شده باشد، کامیت تولید شده چیزی شبیه به این خواهد بود:
$ git log --pretty=fuller -1
commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Author: Jessica Smith <jessica@example.com>
AuthorDate: Sun Apr 6 10:17:23 2008 -0700
Commit: Scott Chacon <schacon@gmail.com>
CommitDate: Thu Apr 9 09:19:06 2009 -0700
Add limit to log function
Limit log functionality to the first 20
اطلاعات Commit
فردی را نشان میدهد که پچ را اعمال کرده و زمان اعمال آن را،
اطلاعات Author
فردی را که پچ را در اصل ایجاد کرده و زمان ایجاد آن را نشان میدهد.
اما ممکن است پچ بهصورت تمیز اعمال نشود.
شاید شاخه اصلی شما خیلی از شاخهای که پچ بر اساس آن ساخته شده فاصله گرفته باشد، یا پچ به پچ دیگری وابسته باشد که هنوز آن را اعمال نکردهاید.
در این صورت، فرآیند git am
شکست میخورد و از شما میپرسد که چه کاری میخواهید انجام دهید:
$ git am 0001-see-if-this-helps-the-gem.patch
Applying: See if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Patch failed at 0001.
When you have resolved this problem run "git am --resolved".
If you would prefer to skip this patch, instead run "git am --skip".
To restore the original branch and stop patching run "git am --abort".
این فرمان، مارکرهای تداخل را در فایلهای دارای مشکل قرار میدهد، مشابه زمانی که در یک عملیات ادغام یا بازپایهگذاری (rebase) به تداخل برخورد میکنید.
شما این مشکل را به همان روش حل میکنید — فایل را ویرایش کرده و تداخل را برطرف میکنید، فایل جدید را استیج میکنید، و سپس دستور git am --resolved
را اجرا میکنید تا به پچ بعدی بروید:
$ (fix the file)
$ git add ticgit.gemspec
$ git am --resolved
Applying: See if this helps the gem
اگر میخواهید گیت کمی هوشمندانهتر تلاش کند تا تداخل را حل کند، میتوانید گزینه -3
را به آن بدهید که باعث میشود گیت یک ادغام سهطرفه انجام دهد.
این گزینه به طور پیشفرض فعال نیست چون در صورتی که کامیتی که پچ گفته بر اساس آن ساخته شده در مخزن شما نباشد، کار نمیکند.
اگر آن کامیت را دارید — یعنی اگر پچ بر اساس یک کامیت عمومی ساخته شده — گزینه -3
معمولاً در اعمال پچهای دارای تداخل هوشمندانهتر عمل میکند:
$ git am -3 0001-see-if-this-helps-the-gem.patch
Applying: See if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.
در این حالت، بدون گزینه -3
پچ به عنوان تداخل در نظر گرفته میشد.
اما چون گزینه -3
استفاده شده، پچ بهصورت تمیز اعمال شده است.
اگر تعدادی پچ از یک فایل mbox اعمال میکنید، میتوانید فرمان am
را در حالت تعاملی (interactive) اجرا کنید که در هر پچ متوقف شده و از شما میپرسد آیا میخواهید آن را اعمال کنید یا خیر:
$ git am -3 -i mbox
Commit Body is:
--------------------------
See if this helps the gem
--------------------------
Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all
این حالت برای زمانی که چند پچ ذخیره شده دارید مفید است، چون میتوانید ابتدا پچ را ببینید اگر یادآوری نمیکنید چیست، یا اگر قبلاً آن را اعمال کردهاید، از اعمال دوباره آن صرفنظر کنید.
وقتی همه پچهای مربوط به موضوع شما اعمال و کامیت شدند، میتوانید تصمیم بگیرید که آیا و چگونه آنها را در شاخهای با عمر طولانیتر ادغام کنید.
بررسی شاخههای ریموت (Checking Out Remote Branches)
اگر مشارکت شما از طرف یک کاربر گیت باشد که مخزن خودش را راهاندازی کرده، تعدادی تغییر را در آن پوش کرده و سپس URL مخزن و نام شاخه ریموتی که تغییرات در آن هستند را برای شما ارسال کرده است، میتوانید آن را به عنوان یک ریموت اضافه کرده و ادغامها را به صورت محلی انجام دهید.
برای مثال، اگر جسیکا ایمیلی برای شما بفرستد و بگوید که یک ویژگی عالی جدید در شاخه ruby-client
مخزن خودش دارد، میتوانید با اضافه کردن ریموت و چکاوت آن شاخه به صورت محلی آن را تست کنید:
$ git remote add jessica https://github.com/jessica/myproject.git
$ git fetch jessica
$ git checkout -b rubyclient jessica/ruby-client
اگر او بعداً دوباره برای شما ایمیل بزند و شاخهای دیگر با ویژگی دیگری عالی ارسال کند، میتوانید مستقیماً با استفاده از `fetch` و سپس `checkout` آن را دریافت کنید چون قبلاً تنظیم ریموت را انجام دادهاید.
این روش بیشتر وقتی مفید است که شما به طور مداوم با یک نفر کار میکنید. اگر کسی فقط گهگاه یک پچ ارسال میکند، پذیرش آن از طریق ایمیل ممکن است کمتر وقتگیر باشد تا اینکه از همه بخواهید سرور خود را راهاندازی کنند و به طور مداوم ریموتها را اضافه و حذف کنید تا چند پچ دریافت کنید. همچنین احتمالاً نمیخواهید صدها ریموت داشته باشید که هر کدام فقط مربوط به کسی باشد که یک یا دو پچ ارسال کرده است. با این حال، اسکریپتها و سرویسهای میزبانی شده میتوانند این کار را آسانتر کنند — این بستگی زیادی به نحوه توسعه شما و توسعهدهندگان شما دارد.
مزیت دیگر این روش این است که تاریخچه کامیتها را نیز به دست میآورید.
اگرچه ممکن است با مشکلات ادغام منطقی روبرو شوید، اما میدانید که کار آنها بر اساس کجای تاریخچه شماست؛ ادغام سهطرفه مناسب به طور پیشفرض انجام میشود و نیازی نیست که گزینه -3
را بدهید و امیدوار باشید پچ بر اساس یک کامیت عمومی تولید شده که به آن دسترسی دارید.
اگر با فردی به طور مداوم کار نمیکنید ولی همچنان میخواهید به این شکل از او pull کنید، میتوانید آدرس URL مخزن ریموت را به دستور git pull
بدهید.
این کار یک بار pull انجام میدهد و URL را به عنوان ریموت ذخیره نمیکند:
$ git pull https://github.com/onetimeguy/project
From https://github.com/onetimeguy/project
* branch HEAD -> FETCH_HEAD
Merge made by the 'recursive' strategy.
تشخیص تغییرات ایجاد شده (Determining What Is Introduced)
حالا شما یک شاخه موضوعی دارید که کارهای ارسالی را شامل میشود. در این مرحله میتوانید تصمیم بگیرید که با آن چه کاری انجام دهید. این بخش چند دستور را مرور میکند تا ببینید چگونه میتوانید دقیقاً بررسی کنید چه چیزی را قرار است با ادغام این شاخه به شاخه اصلی خود وارد کنید.
معمولاً مفید است که تمام کامیتهایی که در این شاخه هستند ولی در شاخه master
شما نیستند را بررسی کنید.
میتوانید با افزودن گزینه --not
قبل از نام شاخه، کامیتهای موجود در شاخه master
را حذف کنید.
این کار همان کاری را انجام میدهد که فرمت master..contrib
که قبلاً استفاده کردیم انجام میداد.
برای مثال، اگر همکارتان دو پچ برای شما فرستاده و شما شاخهای به نام contrib
ساخته و آنها را روی آن اعمال کردهاید، میتوانید این دستور را اجرا کنید:
$ git log contrib --not master
commit 5b6235bd297351589efc4d73316f0a68d484f118
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Oct 24 09:53:59 2008 -0700
See if this helps the gem
commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
Author: Scott Chacon <schacon@gmail.com>
Date: Mon Oct 22 19:38:36 2008 -0700
Update gemspec to hopefully work better
برای دیدن تغییراتی که هر کامیت معرفی میکند، به یاد داشته باشید که میتوانید گزینه -p
را به git log
بدهید تا تفاوتهای مربوط به هر کامیت به خروجی اضافه شود.
برای دیدن تفاوت کامل اینکه اگر این شاخه موضوعی را با شاخهای دیگر ادغام کنید چه اتفاقی میافتد، ممکن است مجبور شوید از یک ترفند عجیب استفاده کنید تا نتایج صحیح را بگیرید. ممکن است فکر کنید این دستور را اجرا کنید:
$ git diff master
این دستور یک diff به شما میدهد ولی ممکن است گمراهکننده باشد.
اگر شاخه master
شما از زمان ایجاد شاخه موضوعی پیش رفته باشد، نتایج به نظر عجیب میرسند.
این به این دلیل است که گیت مستقیماً اسنپشات آخرین کامیت شاخه موضوعی را با اسنپشات آخرین کامیت شاخه master
مقایسه میکند.
برای مثال، اگر شما در شاخه master
یک خط به فایلی اضافه کرده باشید، مقایسه مستقیم اسنپشاتها باعث میشود شاخه موضوعی به نظر برسد که آن خط را حذف میکند.
اگر master
یک جد مستقیم شاخه موضوعی شما باشد، این مشکل نیست؛ اما اگر دو تاریخچه متفاوت شده باشند، diff طوری به نظر میرسد که شما دارید همه چیز جدید شاخه موضوعی را اضافه میکنید و همه چیز منحصر به فرد شاخه master
را حذف میکنید.
آنچه واقعاً میخواهید ببینید، تغییراتی است که به شاخه موضوعی اضافه شده است — کاری که اگر این شاخه را با master
ادغام کنید وارد میکنید.
این کار را با این روش انجام میدهید که گیت آخرین کامیت شاخه موضوعی شما را با اولین جد مشترک آن با شاخه master
مقایسه کند.
از نظر فنی، میتوانید با یافتن صریح جد مشترک و سپس اجرای diff روی آن این کار را انجام دهید:
$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db
یا به صورت خلاصهتر:
$ git diff $(git merge-base contrib master)
با این حال، هیچکدام از این روشها خیلی راحت نیستند، پس گیت یک میانبر دیگر برای انجام همین کار ارائه میدهد: نحو سهنقطهای.
در زمینه دستور git diff
، میتوانید سه نقطه بعد از نام شاخه دیگر قرار دهید تا diff بین آخرین کامیت شاخهای که روی آن هستید و جد مشترک آن با شاخه دیگر گرفته شود:
$ git diff master...contrib
این دستور فقط کاری که شاخه موضوعی شما پس از جد مشترکش با master
انجام داده را نشان میدهد.
این نحو بسیار مفیدی است که باید به خاطر بسپارید.
ادغام کارهای ارسالی (Integrating Contributed Work)
وقتی همه کارهای شاخه موضوعی شما آماده ادغام به شاخه اصلیتر شدند، سوال این است که چگونه این کار را انجام دهید. علاوه بر این، چه روش کاری کلی را میخواهید برای مدیریت پروژه خود استفاده کنید؟ شما چندین گزینه دارید، پس چند مورد از آنها را بررسی میکنیم.
روشهای ادغام (Merging Workflows)
یکی از روشهای پایهای کار این است که تمام تغییرات را مستقیماً در شاخهی master
خود ادغام کنید.
در این حالت، شاخهی master
شما عمدتاً شامل کد پایدار است.
وقتی کاری در یک شاخهی موضوعی انجام دادهاید که فکر میکنید تمام شده است، یا کاری که شخص دیگری انجام داده و شما بررسی کردهاید، آن را به شاخهی master خود ادغام میکنید، سپس آن شاخهی موضوعی که تازه ادغام شده را حذف میکنید و این روند را تکرار میکنید.
برای مثال، اگر مخزنی داشته باشیم که کار در دو شاخه به نامهای ruby_client
و php_client
انجام شده و وضعیت آن مانند History with several topic branches باشد، و ابتدا ruby_client
سپس php_client
را ادغام کنیم، تاریخچهی شما به شکل After a topic branch merge خواهد بود.


این احتمالاً سادهترین روش کاری است، اما ممکن است در پروژههای بزرگتر یا پایدارتر که میخواهید واقعاً مراقب تغییراتی باشید که وارد میکنید، مشکلساز شود.
اگر پروژهی مهمتری دارید، ممکن است بخواهید از چرخهی ادغام دو مرحلهای استفاده کنید.
در این حالت، دو شاخهی بلندمدت دارید، master
و develop
، که در آن تعیین شده است فقط وقتی نسخهی بسیار پایداری منتشر میشود، master
بهروزرسانی شود و تمام کدهای جدید در شاخهی develop
ادغام شوند.
شما هر دو شاخه را به طور منظم به مخزن عمومی ارسال میکنید.
هر بار که شاخهی موضوعی جدیدی برای ادغام دارید (Before a topic branch merge)، آن را به develop
ادغام میکنید (After a topic branch merge). سپس، وقتی یک نسخه منتشر میکنید، شاخهی master
را به محل شاخهی develop
که حالا پایدار است، بهصورت fast-forward میبرید (After a project release).



به این ترتیب، وقتی افراد مخزن پروژهی شما را کلون میکنند، میتوانند یا شاخهی master
را چکاوت کنند تا آخرین نسخهی پایدار را بسازند و بهراحتی بهروز بمانند، یا شاخهی develop
را که محتویات پیشرفتهتر و جدیدتری دارد، بررسی کنند.
شما میتوانید این مفهوم را با داشتن یک شاخهی integrate
که تمام کارها در آنجا ادغام میشود، گسترش دهید.
سپس وقتی کد روی آن شاخه پایدار و تستها را پاس کرد، آن را به شاخهی develop
ادغام میکنید؛ و وقتی آن شاخه برای مدتی پایدار بود، شاخهی master
خود را fast-forward میکنید.
روندهای کاری ادغام بزرگ (Large-Merging Workflows)
پروژهی Git چهار شاخهی بلندمدت دارد: master
، next
، و seen
(قبلاً "pu" به معنای بهروزرسانیهای پیشنهادی) برای کارهای جدید، و maint
برای پشتیبانی و نگهداری.
وقتی کار جدیدی توسط مشارکتکنندگان ارائه میشود، در شاخههای موضوعی در مخزن نگهدارنده جمعآوری میشود، مشابه آنچه شرح داده شد (نگاه کنید به Managing a complex series of parallel contributed topic branches).
در این مرحله، موضوعها ارزیابی میشوند تا مشخص شود آیا امن و آمادهی استفاده هستند یا نیاز به کار بیشتری دارند.
اگر امن باشند، به شاخهی next
ادغام میشوند و آن شاخه به مخزن عمومی ارسال میشود تا همه بتوانند موضوعها را به صورت یکپارچه امتحان کنند.

اگر موضوعها هنوز نیاز به کار دارند، به شاخهی seen
ادغام میشوند.
وقتی مشخص شود کاملاً پایدار هستند، موضوعها دوباره به master
ادغام میشوند.
شاخههای next
و seen
سپس از روی master
بازسازی میشوند.
این یعنی شاخهی master
تقریباً همیشه جلو میرود، next
گاهی بازبیس میشود و seen
حتی بیشتر بازبیس میشود.

وقتی شاخهی موضوعی نهایتاً به master
ادغام شد، از مخزن حذف میشود.
پروژهی Git همچنین یک شاخهی maint
دارد که از آخرین نسخه فورک شده تا در صورت نیاز به انتشار نگهداری، اصلاحات به عقب منتقل شوند.
بنابراین، وقتی مخزن Git را کلون میکنید، چهار شاخه دارید که میتوانید برای ارزیابی پروژه در مراحل مختلف توسعه آنها را بررسی کنید، بسته به اینکه چقدر پیشرفته بودن برایتان مهم است یا چگونه میخواهید مشارکت کنید؛ و نگهدارنده هم یک گردشکار ساختاریافته دارد تا به آنها در بررسی مشارکتهای جدید کمک کند.
گردشکار پروژهی Git تخصصی است.
برای درک دقیقتر میتوانید راهنمای نگهدارندهی Git را در
Git Maintainer’s guide.
مطالعه کنید
روندهای کاری بازپایهگذاری و انتخاب گزینشی (Rebasing and Cherry-Picking Workflows)
نگهدارندگان دیگر ترجیح میدهند کارهای ارائه شده را روی شاخهی master
خود بازبیس یا چریپیک کنند، به جای ادغام مستقیم، تا تاریخچهای تقریباً خطی داشته باشند.
وقتی کاری در شاخهی موضوعی دارید و تصمیم گرفتهاید آن را ادغام کنید، به آن شاخه میروید و فرمان بازبیس را اجرا میکنید تا تغییرات را روی شاخهی فعلی master
(یا develop
و غیره) بازسازی کنید.
اگر این کار خوب پیش رفت، میتوانید شاخهی master
را fast-forward کنید و تاریخچهی پروژه به صورت خطی باقی میماند.
راه دیگر انتقال کار انجامشده از یک شاخه به شاخهی دیگر، چریپیک کردن است. چریپیک در Git مانند بازبیس برای یک کامیت است. این عمل پچ معرفی شده در یک کامیت را گرفته و سعی میکند روی شاخهای که هماکنون روی آن هستید دوباره اعمال کند. این روش زمانی مفید است که چند کامیت در شاخهی موضوعی دارید ولی میخواهید فقط یکی از آنها را ادغام کنید، یا وقتی فقط یک کامیت در شاخهی موضوعی دارید و ترجیح میدهید به جای بازبیس، آن را چریپیک کنید. برای مثال، فرض کنید پروژهای دارید که به این شکل است:

اگر میخواهید کامیت e43a6
را به شاخهی master
خود وارد کنید، میتوانید این دستور را اجرا کنید:
$ git cherry-pick e43a6
Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index fails."
3 files changed, 17 insertions(+), 3 deletions(-)
این دستور همان تغییر اعمال شده در e43a6
را وارد میکند، اما یک مقدار جدید SHA-1 برای کامیت دریافت خواهید کرد، چون تاریخ اعمال آن متفاوت است.
اکنون تاریخچهی شما به این شکل خواهد بود:

حالا میتوانید شاخه موضوعی خود را حذف کنید و کامیتهایی که نمیخواستید وارد شوند را کنار بگذارید.
بازاستفاده خودکار از حل تضادها (Rerere)
اگر زیاد عملیات ادغام (merge) و بازپایهگذاری (rebase) انجام میدهید یا شاخهی موضوعی بلندمدتی را نگهداری میکنید، گیت ویژگیای به نام “rerere” دارد که میتواند به شما کمک کند.
Rerere مخفف “reuse recorded resolution” است — روشی برای کوتاهکردن فرآیند حل تعارضات به صورت دستی. وقتی rerere فعال باشد، گیت مجموعهای از تصاویر قبل و بعد از ادغامهای موفق را نگه میدارد، و اگر متوجه شود تعارضی مشابه تعارضی که قبلاً حل کردهاید رخ داده، به جای اینکه دوباره از شما بخواهد آن را حل کنید، بهطور خودکار همان حل قبلی را به کار میبرد.
این ویژگی دو بخش دارد: یک تنظیم پیکربندی و یک دستور.
تنظیم پیکربندی rerere.enabled
است، که به اندازهای مفید است که بهتر است در تنظیمات سراسری (global) قرار بگیرد:
$ git config --global rerere.enabled true
از این پس هر بار که ادغامی انجام دهید و تعارضها را حل کنید، این حل تعارض در حافظه کش ذخیره میشود تا در آینده در صورت نیاز دوباره استفاده شود.
اگر لازم باشد، میتوانید با استفاده از دستور git rerere
با کش rerere تعامل داشته باشید.
وقتی این دستور به تنهایی اجرا شود، گیت پایگاه داده حل تعارضهای خود را بررسی میکند و سعی میکند با تعارضهای فعلی مطابقت پیدا کند و آنها را حل کند (اگر rerere.enabled
روی true
تنظیم شده باشد این کار به صورت خودکار انجام میشود).
همچنین زیردستورات مختلفی وجود دارد تا ببینید چه مواردی ثبت خواهد شد، حل تعارض خاصی را از کش پاک کنید و یا کل کش را خالی نمایید.
ما در بخش بازاستفاده خودکار از حل تضادها (Rerere) به جزئیات بیشتری درباره rerere خواهیم پرداخت.
برچسبگذاری نسخههای خود (Tagging Your Releases)
وقتی تصمیم میگیرید یک نسخه منتشر کنید، احتمالاً میخواهید یک برچسب (tag) اختصاص دهید تا بتوانید آن نسخه را در هر زمانی در آینده دوباره ایجاد کنید. میتوانید برچسب جدیدی ایجاد کنید، همانطور که در مقدمات گیت (git basics chapter) توضیح داده شده است. اگر تصمیم دارید برچسب را به عنوان نگهدارنده امضا کنید، برچسبگذاری ممکن است چیزی شبیه به این باشد:
$ git tag -s v1.5 -m 'my signed 1.5 tag'
You need a passphrase to unlock the secret key for
user: "Scott Chacon <schacon@gmail.com>"
1024-bit DSA key, ID F721C45A, created 2009-02-09
اگر برچسبهای خود را امضا کنید، ممکن است با مشکل توزیع کلید عمومی PGP که برای امضای برچسبها استفاده میشود مواجه شوید.
نگهدارنده پروژه گیت این مشکل را با قرار دادن کلید عمومی خود به صورت یک blob در مخزن و سپس اضافه کردن یک برچسب که مستقیماً به آن محتوا اشاره میکند، حل کرده است.
برای این کار، میتوانید کلیدی که میخواهید را با اجرای دستور gpg --list-keys
پیدا کنید:
$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub 1024D/F721C45A 2009-02-09 [expires: 2010-02-09]
uid Scott Chacon <schacon@gmail.com>
sub 2048g/45D02282 2009-02-09 [expires: 2010-02-09]
سپس میتوانید کلید را با صادر کردن آن و عبور دادن خروجی از طریق git hash-object
مستقیماً در پایگاه داده گیت وارد کنید، که یک blob جدید با این محتویات در گیت مینویسد و مقدار SHA-1 آن blob را به شما برمیگرداند:
$ gpg -a --export F721C45A | git hash-object -w --stdin
659ef797d181633c87ec71ac3f9ba29fe5775b92
حالا که محتویات کلید شما در گیت است، میتوانید برچسبی بسازید که مستقیماً به آن اشاره کند با مشخص کردن مقدار SHA-1 جدیدی که دستور hash-object
به شما داده است:
$ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92
اگر دستور git push --tags
را اجرا کنید، برچسب maintainer-pgp-pub
با همه به اشتراک گذاشته خواهد شد.
اگر کسی بخواهد برچسبی را تأیید کند، میتواند کلید PGP شما را با استخراج مستقیم blob از پایگاه داده و وارد کردن آن در GPG به صورت مستقیم وارد کند:
$ git show maintainer-pgp-pub | gpg --import
آنها میتوانند از آن کلید برای تأیید تمام برچسبهای امضا شده شما استفاده کنند.
همچنین، اگر دستورالعملهایی در پیام برچسب درج کنید، اجرای git show <tag>
به کاربر نهایی اجازه میدهد دستورالعملهای خاصتری درباره تأیید برچسب دریافت کند.
تولید شماره ساخت (Generating a Build Number)
چون گیت شمارههایی که به صورت پیوسته افزایش یابند مانند 'v123' یا معادل آن برای هر کامیت ندارد، اگر بخواهید نامی قابل خواندن برای انسان همراه با کامیت داشته باشید، میتوانید دستور git describe
را روی آن کامیت اجرا کنید.
در پاسخ، گیت رشتهای تولید میکند که شامل نام آخرین برچسبی است که قبل از آن کامیت وجود داشته، به همراه تعداد کامیتهایی که از آن برچسب گذشته است، و در نهایت بخشی از مقدار SHA-1 کامیتی که توصیف میشود (با پیشوند حرف "g" که مخفف Git است):
$ git describe master
v1.6.2-rc1-20-g8c5b85c
به این ترتیب، میتوانید یک تصویر فوری (snapshot) یا نسخهای بسازید و آن را به گونهای نامگذاری کنید که برای دیگران قابل فهم باشد. در واقع، اگر گیت را از کد منبعی که از مخزن گیت کلون شده بسازید، دستور `git --version` چیزی شبیه به این به شما میدهد. اگر شما یک کامیت را که مستقیماً تگ زدهاید توضیح دهید، فقط نام تگ را نشان میدهد.
به طور پیشفرض، دستور git describe
به تگهای حاشیهنویسی شده (annotated tags) نیاز دارد (تگهایی که با فلگهای -a
یا -s
ساخته شدهاند)؛ اگر میخواهید از تگهای سبکوزن (lightweight tags) یا غیرحاشیهنویسی شده نیز استفاده کنید، گزینه --tags
را به دستور اضافه کنید.
شما همچنین میتوانید این رشته را به عنوان هدف دستور git checkout
یا git show
استفاده کنید، اگرچه این روش به مقدار کوتاهشده SHA-1 در انتها وابسته است، پس ممکن است همیشه معتبر نباشد.
برای مثال، هسته لینوکس اخیراً تعداد کاراکترهای SHA-1 را از ۸ به ۱۰ افزایش داده است تا یکتایی اشیاء SHA-1 را تضمین کند، بنابراین نامهای خروجی قدیمی git describe
نامعتبر شدهاند.
آمادهسازی نسخه انتشار (Preparing a Release)
حالا میخواهید نسخهای منتشر کنید.
یکی از کارهایی که میخواهید انجام دهید، ایجاد یک آرشیو از آخرین تصویر فوری کدتان برای آن دسته از افراد است که از گیت استفاده نمیکنند.
دستور این کار git archive
است:
$ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz
$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz
اگر کسی آن فایل tar را باز کند، آخرین تصویر پروژه شما را در دایرکتوریای به نام project
دریافت میکند.
شما همچنین میتوانید به روشی مشابه یک آرشیو zip ایجاد کنید، اما با افزودن گزینه --format=zip
به دستور git archive
:
$ git archive master --prefix='project/' --format=zip > `git describe master`.zip
اکنون شما یک فایل tar و یک آرشیو zip زیبا از نسخه پروژهتان دارید که میتوانید آن را در وبسایت خود بارگذاری کنید یا برای دیگران ایمیل کنید.
گزارش کوتاه (The Shortlog)
وقت آن است که به فهرست ایمیل افرادی که میخواهند بدانند در پروژه شما چه خبر است اطلاع دهید.
یک روش خوب برای به دست آوردن سریع نوعی گزارش تغییرات (changelog) از آنچه از آخرین انتشار یا ایمیل شما به پروژه اضافه شده، استفاده از دستور git shortlog
است.
این دستور خلاصهای از تمام کامیتها در بازهای که به آن میدهید ارائه میدهد؛ برای مثال، دستور زیر خلاصهای از تمام کامیتها از زمان آخرین انتشار شما، اگر آخرین انتشار شما با نام v1.0.1
بوده باشد، به شما میدهد:
$ git shortlog --no-merges master --not v1.0.1
Chris Wanstrath (6):
Add support for annotated tags to Grit::Tag
Add packed-refs annotated tag support.
Add Grit::Commit#to_patch
Update version and History.txt
Remove stray `puts`
Make ls_tree ignore nils
Tom Preston-Werner (4):
fix dates in history
dynamic version method
Version bump to 1.0.2
Regenerated gemspec for version 1.0.2
شما یک خلاصه مرتب و تمیز از تمام کامیتها از v1.0.1
به بعد، به تفکیک نویسنده، دریافت میکنید که میتوانید آن را به فهرست ایمیل خود ارسال کنید.