-
1. شروع به کار
- 1.1 دربارهٔ کنترل نسخه
- 1.2 تاریخچهٔ کوتاهی از گیت
- 1.3 گیت چیست؟
- 1.4 خط فرمان
- 1.5 نصب گیت
- 1.6 اولین راهاندازی گیت
- 1.7 کمک گرفتن
- 1.8 خلاصه
-
2. مقدمات گیت
- 2.1 دستیابی به یک مخزن گیت
- 2.2 ثبت تغییرات در مخزن
- 2.3 دیدن تاریخچهٔ کامیتها
- 2.4 بازگردانی کارها
- 2.5 کار با ریموتها
- 2.6 برچسبگذاری
- 2.7 نامهای مستعار در گیت
- 2.8 خلاصه
-
3. شاخهسازی در گیت
- 3.1 شاخهها در یک کلمه
- 3.2 شاخهسازی و ادغام مقدماتی
- 3.3 مدیریت شاخه
- 3.4 روند کاری شاخهسازی
- 3.5 شاخههای ریموت
- 3.6 ریبیسکردن
- 3.7 خلاصه
-
4. گیت روی سرور
- 4.1 پروتکلها
- 4.2 راهاندازی گیت در سرور
- 4.3 ساختن کلید عمومی SSH
- 4.4 نصب و راهاندازی سرور
- 4.5 دیمن گیت
- 4.6 HTTP هوشمند
- 4.7 گیتوب
- 4.8 گیتلب
- 4.9 گزینههای شخصی ثالث میزبانی شده
- 4.10 خلاصه
-
5. گیت توزیعشده
- 5.1 روندهای کاری توزیعشده
- 5.2 مشارکت در یک پروژه
- 5.3 نگهداری یک پروژه
- 5.4 خلاصه
-
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. Customizing Git
- 8.1 Git Configuration
- 8.2 Git Attributes
- 8.3 Git Hooks
- 8.4 An Example Git-Enforced Policy
- 8.5 Summary
-
9. Git and Other Systems
- 9.1 Git as a Client
- 9.2 Migrating to Git
- 9.3 Summary
-
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 in Visual Studio
- A1.3 Git in Visual Studio Code
- A1.4 Git in Eclipse
- A1.5 Git in IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine
- A1.6 Git in Sublime Text
- A1.7 Git in Bash
- A1.8 Git in Zsh
- A1.9 Git in PowerShell
- A1.10 Summary
-
A2. پیوست B: Embedding Git in your Applications
- A2.1 Command-line Git
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
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 گیت توزیعشده - نگهداری یک پروژه
نگهداری یک پروژه
علاوه بر دانستن چگونگی مشارکت مؤثر در یک پروژه، شما احتمالاً میبایست بدانید که چگونه یک پروژه را نگهداری (Maintain) کنید.
این فعل میتواند شامل قبول و اعمال پچهای تولید شده توسط format-patch
و پیچهای ایمیلشده به شما یا یکپارچهسازی تغییرات در برنچهای ریموت برای مخازنی که به عنوان ریموت به پروژهتان اضافه کردهاید باشد.
در صورتی که یک مخزن استاندارد را نگهداری میکنید یا میخواهید با تأیید و احراز پچها کمک کنید، لازم است بدانید که چگونه به واضحترین روش ممکن در نظر دیگر مشارکتکنندگان کار را قبول کنید که
که در دراز مدت نیز قابل مدیریت باشد.
کار در شاخههای موضوعی
وقتی به یکپارچهسازی کار جدید فکر میکنید، به طور کل امتحان کردنش روی یک برنچ موضوعی راه خوبی است — یک برنچ موقت مختص به امتحان آن کار جدید.
بدین طریق ویرایش پچهای جدید به طور مستقل آسان است و در صورت کار نکردن میتوانید آنها را تا زمان ثانوی معلق کنید.
اگر یک نام ساده برنچ بر اساس کاری که در حال امتحان آن هستید انتخاب کنید، مثلاً ruby_client
یا چیزی با محتوای مشابه، در صورتی که بخواهید آنرا ترک کنید و بعداً به آن بازگردید، میتوانید به سادگی آنرا به خاطر بسپارید.
نگهدارندهٔ پروژهٔ گیت سعی در این دارد که این برنچها را در فضانامهای مختلف هم قرار دهد — مانند sc/ruby_clinet
که sc
آن مخفف نام شخصی است که در کار همکاری داشته است.
همانطور که به خاطر دارید، میتوانید از master
به این صورت برنچ بسازید:
$ git branch sc/ruby_client master
یا اگر ترجیح میدهید به طور آنی به آن انتقال پیدا کنید، میتوانید از آپشن checkout -b
استفاده کنید:
$ git checkout -b sc/ruby_client master
حال آمادهاید که کاری که در برنچ موضوعی دریافت کردهاید را اضافه کنید و به این فکر کنید که میخواهید آنرا در برنچهای اصلیتر ادغام کنید:
اعمال وصله از ایمیل
اگر یک پچ از ایمیل دریافت کردهاید، لازم است آنرا در برنچ موضوعی خود تعبیه و یکپارچهسازی کنید تا بتوانید آنرا ارزیابی کنید.
دو راه برای اعمال یک پچ ایمیل شده وجود دارد: با git apply
یا با git am
.
اعمال وصله با apply
اگر پچی دریافت کردهاید که با git diff
یا مدلی از دستور یونیکس diff
تولید شده است (اگرچه توصیه نمیشود؛ بخش بعد را ببینید)، میتوانید آنرا با دستور git apply
اعمال کنید.
با فرض اینکه پچ را در /tmp/patch-ruby-client.patch
ذخیره کردهاید، میتوانید آنرا اینگونه اعمال کنید:
$ git apply /tmp/patch-ruby-client.patch
این دستور فایلهای درون پوشهٔ کاری شما را ویرایش میکند.
تقریباً معادل اجرای دستور patch -p
برای اعمال پچ است، هرچند کمی شکاکتر است و تطابیق فازی کمتری را به نسبت دستور پچ قبول میکند.
همچنین این دستور توانایی اضافه، پاککردن و تغییر نام فایلها را هم دارد اگر در قالب git diff
شرح داده شود در حالی که patch
این تواناییها را ندارد.
در آخر git applly
یک «همه را اعمال کن یا همه را لغو کن» است که یا همه چیز یا هیچچیزی را اعمال نمیکند؛ در patch
میتوان به صورت جزئی پچفایلها را اعمال کرد که پوشهٔ کاری را به وضعی عجیب در میآورد.
git apply
به طور کل بسیار بیشتر از patch
محافظ کارانه است.
کامیت جدیدی برای شما نمیسازد — پس از اجرای آن باید تغییرات را به طور دستی استیج و کامیت کنید.
شما همچنین میتوانید از git apply
استفاده کنید تا ببینید که آیا قبل از اعمال واقعی پچ، پچ امکان اعمال شدن به صورت تمیز را دارد — میتوانید 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
اگر مشارکتکننده یک کاربر گیت است و به اندازهای ماهر بود که از دستور format-patch
برای ساختن پچ خود استفاده کند، آنگاه کار شما آسانتر است چرا که این پچ شامل اطلاعات نویسنده و متن کامیت هم میباشد.
اگر میتوانید، مشارکتکنندگانتان را تشویق کنید تا با استفاده از format-patch
به جای diff
برایتان پچ بسازند.
بهتر است از git apply
فقط برای پچهای سنتی مانند قبل استفاده کنید.
برای اعمال پچی که با format-patch
ساخته شده، از git am
استفاده میکنید (این دستور am
نامیده شده بخاطر اینکه برای «اعمال یک سری پچ از صندوق مــیلها یا ایمیلها» (from a mailbox) به کار میرود).
از لحاظ فنی git am
ساخته شده تا از یک فایل mbox محتویات را بخواند، که به طور ساده یک قالب متن-خالی (Plain-Text) برای ذخیرهٔ یک یا چند پیغام ایمیل در یک فایل متنی است.
این فایل چیزی شبیه این است:
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
شما میتوانید ملاحظه کنید که به تمیزی اعمال شد و به طور خودکار کامیت جدید را برای شما ساخت. اطلاعات نویسنده از هدرهای بخش فرستده و تاریخ ایمیل رونوشت و پیغام کامیت از موضوع و بدنهٔ (قبل از خود پچ) ایمیل گرفته میشود.
به طور مثال اگر پچ مثال 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".
این دستور علامتهای تداخل را در هر فایلی که با آن مشکل دارد میگذارد، بسیار شبیه به عملیات مرج یا ریبیس تداخل دار.
شما این مشکل را به روش بسیار مشابهی حل میکنید — برای حل تداخل فایل را ویرایش میکند، فایل جدید را استیج کرده و بعد 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
را در حالت تعاملی اجرا کنید که با هر پچی که پیدا میکند میایستد و از شما میپرسد که آیا میخواهید آنرا اعمال کنید:
$ 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
اگر چند پچ ذخیره شده دارید این مفید است، چراکه اگر به خاطر نمیآورید که چیست میتوانید ابتدا پچ را ببینید و یا اگر از قبل اعمال کردهاید آنرا اعمال نکنید.
وقتی تمام پچهای موضوع خود را اعمال و به برنچ خود کامیت کردید میتوانید انتخاب کنید که آیا میخواهید تغییرات را به برنچ قدیمیتر خود اعمال کنید و اگر میخواهید چگونه این کار انجام شود.
چکاوت کردن برنچهای ریموت
اگر مشارکت شما از یک کاربر گیت آمده که مخزن خود را دارد و تعدادی تغییرات به آن اعمال کرده و سپس برای شما URL مخزن و نام برنچ ریموتی که تغییرات در آن قرار دارند را ارسال کرده است، میتوانید آنها را به عنوان یک ریموت اضافه و به طور محلی مرج کنید.
به طور مثال اگر جسیکا برای شما ایمیلی با این مضمون میفرست که ویژگی عالی در برنچ ruby-client
مخزن خودش دارد، شما میتوانید آنرا با اضافه کردن ریموت و چکاوت کردن آن برنچ به طور محلی امتحان کنید:
$ git remote add jessica git://github.com/jessica/myproject.git
$ git fetch jessica
$ git checkout -b rubyclient jessica/ruby-client
اگر بعداً او دوباره به شما ایمیلی زد و برنچ دیگری که شامل ویژگی عالی دیگر بود را اضافه کرده بود، شما به طور مستقیم میتوانید فچ و چکاوت کنید چرا که از قبل ریموت را اضافه کردهاید.
این ویژگی بخصوص زمانی مفید است که شما به طور مادام با یک فرد کار میکنید. اگر شخصی فقط یک پچ دارد و فقط هر از گاهی مشارکت میکند، ممکن است قبول کردن تغییرات از طریق ایمیل آسانتر باشد چرا که هرکسی میتواند سرور خود را راهاندازی کند و شما را وادار کند که ریموت اضافه و حذف کنید تا بتوانید پچها را دریافت کنید. همچنین احتمال اینکه بخواهید صدها ریموت داشته باشید، هر ریموت برای یک نفر که فقط قرار است یک یا دو پچ را اضافه کرده باشد کم است. هرچند اسکریپتها و سرویسهای میزبانی شده ممکن است که این را کمی آسانتر کنند — تا حد زیادی بستگی به چگونگی توسعهدادن شما و همکارانتان دارد.
از دیگر مزایای این روش این است که شما میتوانید تاریخچهٔ کامیتها را هم بگیرید.
اگرچه ممکن است مشکلات مشروع مرجی داشته باشید، که میدانید که کار آنها بر اساس چه نقطهای از تاریخچهٔ شماست؛ یک مرج سه طرفه مناسب پیشفرض است، جای اینکه مجبور باشید یک -3
ارائه کنید و به این امیدوار
باشید که پچ از کامیت عمومی آمده باشد که شما به آن دسترسی دارید.
اگر به طور دائم با فردی کار نمیکنید اما باز هم میخواهید از این طریق پول کنید، میتوانید URL مخزن ریموت را به دستور git 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.
تشخیص تغییرات معرفی شده
حال شما یک برنچ موضوعی که شامل کار مشارکتشده است دارید. در این نقطه میتوانید تصمیم بگیرید میخواهید که با آن چکار کنید. این بخش تعدادی دستور را بازبینی میکند تا بتوانید ببینید چگونه میتوانید از آنها برای بررسی دقیق اتفاقاتی که در صورت مرج کردن به برنچ اصلی رخ میدهد استفاده کنید.
معمولاً گرفتن یک بازبینی از تمام کامیتهایی که در این برنچ میباشند اما در برنچ master
نیستند کار مفیدی است.
میتوانید دربارهٔ کامیتهایی که در برنچ master
هستند، با اضافه کردن آپشن --not
قبل از نام برنچ، استثنا قائل شوید.
این همان کاری را میکند که قالب 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
بدهید و دستور در انتهای هر کامیت دیف آنرا هم اضافه میکند.
برای دیدن دیف کامل اتفاقاتی که میتوانست در صورت مرج برنچ موضوعی با master
بیافتد، میتوانید از یک ترفند عجیب استفاده کنید که خروجی درست را میدهد.
ممکن است گمان کنید که باید این را اجرا کنید:
$ git diff master
این دستور به شما یک دیف میدهد، اما ممکن است گمراه کننده باشد.
اگر برنچ master
از زمانی که برنچ موضوعی را از آن ساختهاید جلو رفته است، خروجی ظاهراً غریبی خواهید گرفت.
این اتفاق به این دلیل میافتد که گیت به طور مستقیم اسنپشات آخرین کامیت برنچ موضوعی که روی آن هستید و آخرین کامیت برنچ master
را با یکدیگر مقایسه میکند.
به فرض مثال اگر یک خط به یک فایل روی برنچ master
اضافه کرده باشید، یک مقایسهٔ مستقیم اسنپشاتها اینگونه نمایش میدهد که انگار برنچ موضوعی میخواهد آن خط را حذف کند.
اگر master
والد مستقیم برنچ موضوعی شما است، این مسئله مشکل نیست؛
اما اگر دو تاریخچه دو شاخه شده باشند، دیف به گونهای نمایش میدهد که انگار در حال اضافه کردن محتوای جدید به برنچ موضوعی هستید و هر چیزی که مختص به برنچ master
است را پاک میکنید.
به جای این، چیزی که واقعاً میخواهید ببینید تغییراتی است که به برنچ موضوعی اضافه شده است — کاری که در صورت مرج برنچ با master
معرفی میشود.
شما این کار را با واداری گیت به مقایسهٔ آخرین کامیت برنچ موضوعیتان با اولین والد مشترکی که با برنچ master
دارد انجام میدهید.
از لحاظ فنی میتوانید با تشخیص صریح والد مشترک و سپس اجرای دیف با آن والد این کار را به انجام برسانید:
$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db
یا به طور مختصرتر:
$ git diff $(git merge-base contrib master)
هرچند هیچکدام از این دو خیلی عرف نیست، بنابراین گیت مختصری برای انجام همین کار ارائه میکند: سینتکس سه نقطه.
در متن دستور git diff
میتوانید سه نقطه بعد از برنچ دیگری بگذارید تا یک diff
بین آخرین کامیت برنچی که روی آن هستید و والد مشترکش با برنچ دیگری بگیرید:
$ git diff master...contrib
این دستور فقط کاری که این برنچ موضوعی فعلی از آخرین والد مشترکش با master
معرفی کرده را نشان میدهد.
این سینتکس بسیار مفیدی برای به خاطر سپردن است.
تعبیه و یکپارچهسازی کار مشارکتشده
هنگامی که تمام کار در برنچ موضوعی آماده است تا یکپارچهسازی به یک برنچ اصلیتر است، سؤال این میشود که چگونه میتوان این کار را کرد. علاوه بر آن میخواهید از چه روند کاری کلی برای نگهداری پروژه خود استفاده کنید؟ شما تعدادی انتخاب دارید، ما چندی از آنها را بررسی میکنیم.
ادغام روندهای کاری
یک روند کاری ساده این است که تمام کار را مستقیماً با master
مرج کنید.
در این سناریو شما یک برنچ master
دارید که شامل کد باثبات شماست.
وقتی که کاری در برنچ موضوعی دارید که فکر میکنید کامل است یا کاری از کسی دیگر دارید که به شما داده شده و شما آنرا تأیید کردهاید،
آنرا با برنچ مستر مرج، آن برنچ تازه مرج شدهٔ موضوعی را پاک و این فرآیند را تکرار میکنید.
مثلاً اگر مخزنی داریم که در آن دو برنچ کار شده با نامهای ruby_client
و php_client
داریم که شبیه تاریخچه با تعدادی برنچ موضوعی. است و ruby_client
و سپس php_client
را مرج کنیم، تاریخچهٔ شما شبیه بعد مرج یک برنچ موضوعی. خواهد شد.
![History with several topic branches.](png/merging-workflows-1.png)
![After a topic branch merge.](png/merging-workflows-2.png)
این احتمالاً سادهترین روند کاری است، اما اگر با پروژههای بزرگتر یا باثباتتر سروکار دارید و میخواهید به آنچه ارائه میکنید محتاط باشید، میتواند مشکلساز باشد.
اگر پروژهٔ مهمتری دارید، ممکن است بخواهید از یک چرخهٔ مرج دوفازی استفاده کنید.
در این سناریو شما دو برنچ با قدمت دارید، master
و develop
که master
فقط موقعی بروزرسانی میشود که یک نسخه خیلی باثبات تهیه شده و همهٔ کدهای جدید در برنچ develop
تعبیه میشوند.
عموماً شما هردوی این برنچها را به مخزن عمومی پوش میکنید.
هر بار که برنچ موضوعی جدیدی برای مرج کردن دارید (قبل از مرج یک برنچ موضوعی.)، آنرا به develop
مرج میکنید (بعد مرج یک برنچ موضوعی.)؛
سپس هنگامی که یک تگ انتشار داشتید، master
را به هرجایی که برنچ موقتاً باثبات develop
هست fast-forward میکنید (بعد از یک انتشار از پروژه.).
![Before a topic branch merge.](png/merging-workflows-3.png)
![After a topic branch merge.](png/merging-workflows-4.png)
![After a topic branch release.](png/merging-workflows-5.png)
از این طریق هنگامی که مخزن پروژهٔ شما را کلون میکنند، یا master
را برای ساختن آخرین نسخهٔ باثبات چکاوت میکنند و آنرا به روز نگه میدارند و یا برنچ develop
را چکاوت میکنند که
شامل محتوای بروز بیشتری است.
همچنین می توانید با داشتن یک برنچ integrate
که در آن تمام کارها مرجشده است این مفهوم را گسترش دهید.
پس از این هنگامی که کدبیس شما روی آن برنچ باثبات است و تستها را میگذراند، میتوانید آنرا در برنچ develop
بریزید؛ و وقتی که برای مدتی باثبات جلوه کرد برنچ master
خود را fast-forward کنید.
روند کاری ادغام-بزرگ
پروژهٔ گیت چهار برنچ باقدمت دارد: master
، next
، و pu
(Proposed Updates، بروزرسانی پیشنهادی) برای کارهای جدید و maint
(Maintenance Backports، بکپورتهای نگهداری).
وقتی کار جدید توسط مشارکتکنندگان معرفی میشود، درون برنچ موضوعی در مخزن نگهدارنده، مشابه چیزی که توصیف کردیم، جمعآوری میشود (مدیریت مجموعهای پیچیده از برنچهای موضوعی موازی مشارکتشده. را ببینید).
در این نقطه موضوعات در پی دریافتن اینکه آیا برای استفاده آماده و امن هستند و یا احتیاج است بیشتر روی آنها کار شود ارزیابی میشوند.
اگر امن بودند به next
مرج میشوند و آن برنچ پوش میشود تا همه بتوانند موضوعاتی که با هم یکپارچهسازی شدهاند را امتحان کنند.
![Managing a complex series of parallel contributed topic branches.](png/large-merges-1.png)
اگر موضوعات هنوز احتیاج به کار دارند، بهجای next
در pu
مرج میشوند.
وقتی تعیین شد که کاملاً باثبات هستند، موضوعات در master
بازادغام میشوند.
برنچهای next
و pu
پس از آن از master
بازسازی میشوند.
این به آن معناست که master
تقریباً همیشه رو به جلو حرکت میکند، next
هر از گاهی ریبیس میشود و pu
حتی بیشتر ریبیس میشود:
![Merging contributed topic branches into long-term integration branches.](png/large-merges-2.png)
هنگامی که یک برنچ موضوعی بالآخره به master
مرج شده، از مخزن حذف میشود.
پروژهٔ گیت علاوه بر این یک برنچ maint
دارد که از آخرین انتشار فورک میشود تا پچهای بکپورت را ارائه کند، در حالتی که انتشار نگهدارندهای لازم باشد.
بنابراین وقتی مخزن گیت را کلون میکنید چهار برنچ دارید که میتوانید برای ارزیابی پروژه در مراحل مختلف توسعه، با توجه به اینکه چقدر میخواهید بروز باشید یا چگونه میخواهید مشارکت کنید، چکاوت کنید؛
و نگهدارنده یک روند کاری ساختاریافته برای کمک به تیمار مشارکتهای جدید دارد.
روند کاری پروژهٔ گیت تخصصیشده است.
برای درک بهتر این موضوع میتوانید به راهنمای نگهدارندهٔ گیت مراجعه کنید.
روند کاری ریبیس و چری-پیک
دیگر نگهدارندهها ترجیح میدهند که کار مشارکتشده را بجای مرج به نوک برنچ master
خود ریبیس یا چری-پیک کنند تا بیشتر تاریخچه را خطی نگهدارند.
هنگامی که کار خود را در یک برنچ موضوعی دارید و تصمیم گرفتهاید که آنرا یکپارچه کنید، به آن برنچ میروید و دستور ریبیس را برای بازسازی تغییرات روی نوک برنچ master
(یا develop
و امثالهم) اعمال میکنید.
اگر درست کار کرد، میتوانید برنچ master
خود را fast-forward کنید و به یک تاریخچهٔ خطی برخواهید خورد.
راه دیگر انتقال کار ارائه شده از یک برنچ به برنچ دیگر چری-پیک کردن آن است. یک چری-پیک (دستچینی) مانند ریبیس برای یک کامیت واحد است. این عملیات پچی که در یک کامیت ارائه شده را میگیرید و سعی میکنید که آنرا روی برنچی که در حال حاضر روی آن هستید بازاعمال کند. اگر تعدادی کامیت روی یک برنچ موضوعی دارید و فقط میخواهید یکی از آنها را اعمال کنید یا اگر یک کامیت روی یک برنچ موضوعی دارید و ترجیح میدهید که بجای ریبیس آنرا دستچین کنید، این دستور مفید است. به طور مثال، فرض کنید که پروژهای شبیه این دارید:
![Example history before a cherry-pick.](png/rebasing-1.png)
اگر میخواهید تغییرات کامیت 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 جدید خواهید گرفت چرا که تاریخ اعمال شدن آن متفاوت است.
حال تاریخچهٔ شما شبیه به این است:
![History after cherry-picking a commit on a topic branch.](png/rebasing-2.png)
حال میتوانید برنچ موضوعی را پاک کنید و کامیتهایی را که نمیخواستید پول کنید پاک کنید.
ررره
اگر کلی ریبیس و مرج انجام میدهید و یک برنچ موضوعی باقدمت را نگهداری میکنید، گیت قابلیتی با نام «rerere» دارد که به شما کمک میکند.
ررره مخفف «Reuse Recorded Resolution» — راهی برای مخفف کردن حل کردن دستی تداخلات — است. هنگامی که ررره فعال است، گیت مجموعهای از ایمیجهای پیش و پس از مرج موفق را نگه میدارد و پس از این اگر متوجه شد که تداخلی دقیقاً مشابه چیزی که سابقاً حل کردهاید وجود دارد، بدون اینکه سر شما را درد بیاورد، خودش از راهحل سابق شما استفاده میکند.
این ویژگی با دو بخش میآید: گزینه تنظیمات و یک دستور.
گزینهٔ تنظیمات آن rerere.enabled
است و آنقدر کاربرد دارد که آنرا در تنظیمات جهانی خود قرار دهید:
$ git config --global rerere.enabled true
حال هرگاه که مرجی که تداخلی را حل میکند انجام دهید، برای روز مبادا حلال آن در کش ذخیره میشود.
اگر لازم است میتوانید با کش ررره به وسیلهٔ دستور git rerere
تعامل داشته باشید.
هنگامی که تنها اجرا شود، گیت پایگاه دادهٔ حلالهایش را چک میکند و سعی میکند تطبیقی با هر تداخل مرج فعلی پیدا کرده و آن را حل کند
(اگرچه اگر rerere.enabled
روی true
تنظیم شده باشد این کار به طور خودکار انجام میشود).
همچنین زیردستوراتی برای مشاهدهٔ آنچه که ذخیره خواهد شد، پاک کردن حلالهای خاص از کش و پاک کردن کل کش وجود دارد.
ررره را با جزئیات بیشتر در Rerere مورد بررسی قرار میدهیم.
برچسب زدن انتشاراتتان
هنگامی که تصمیم گرفتید نسخهٔ انتشاری تهیه کنید، احتمالاً خواهید خواست که تگ متناسبی برای اینکه بتوانید آن انتشار را در آینده بازسازی کنید اعمال کنید. شما میتوانید مطابق آنچه که در مقدمات گیت توصیف شد تگ جدیدی ایجاد کنید. اگر به عنوان نگهدارنده تصمیم گرفتهاید که تگی را امضا کنید، تگ کردنتان ممکن است شبیه به این باشد:
$ 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 عمومی مورد استفاده در تگها را نیز داشته باشید.
نگهدارندههای پروژه گیت این مشکل را با اضافه کردن کلید عمومی خود به عنوان یک بلاب به مخزن و سپس اضافه کردن تگی که مستقیماً به آن محتوا اشاره میکند حل کردهاند.
برای انجام این کار میتوانید با اجرای 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
وارد کنید، که یک بلاب جدید با آن محتوا در گیت میسازد و به شما SHA-1 بلاب را میدهد.
$ 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 شما از پایگاهداده و وارد کردن مستقیم آن به GPG این کار را انجام دهد:
$ git show maintainer-pgp-pub | gpg --import
همچنین افراد میتوانند که از آن کلید برای تأیید صحت تمام تگهایی که شما امضا کردهاید استفاده کنند.
همچنین اگر دستورالعملهایی را در پیغام تگ اضافه کنید، git show <tag>
به کاربر نهایی دستورات دقیقتر دربارهٔ تأیید صحت تگ را نشان میدهد.
ساختن یک شمارهٔ بیلد
از آنجایی که گیت شمارههای افزایشی یکنواختی مانند v123 یا معادل آنرا ندارد تا به هر کامیت اعمال کند، اگر میخواهید یک نام خوانا با یک کامیت ارائه شود میتوانید git describe
را روی آن کامیت اجرا کنید.
در جواب گیت رشتهای محتوی نام جدیدترین تگهایی که پیش از آن کامیت معرفی شدهاند میسازد که به همراه شمارهٔ کامیت از زمان آن تگ و در آخر بخشی از مقدار SHA-1 کامیت توصیفشده میباشد (با پیشوند «g» به معنی گیت):
$ git describe master
v1.6.2-rc1-20-g8c5b85c
از این طریق میتوانید یک اسنپشات یا بیلد صادر کنید و آنرا با نامی قابل فهم برای مردم نامگذاری کنید.
فیالواقع اگر گیت را از سورس کد کلون شده از مخزن گیت بسازید git --version
به شما چیزی را مشابه با همین نشان میدهد.
اگر کامیتی را توصیف (describe) میکنید که به طور مستقیم تگ کردهاید، صرفاً به شما نام تگ را میدهد.
به طور پیشفرض دستور git describe
به تگهای توصیفشده احتیاج دارد (تگهایی که با فلگهای -a
یا -s
ساخته شدهاند)؛
اگر میخواهید از مزیتهای تگهای سبک (توصیف نشده) هم استفاده کنید، آپشن --tags
را نیز به دستور اضافه کنید.
همچنین میتوانید از این رشته برای دستور git checkout
یا git show
استفاده کنید، هرچند وابسته به مقدار SHA-1 مختصر در آخر خروجی است که ممکن است همیشه کارا نماند.
به طور مثال هستهٔ لینوکس از ۸ به ۱۰ حرف پرید تا از یکتا بودن آبجکتهای SHA-1 مطمئن باشد، بنابراین نامهای خروجیهای قدیمی git describe
نامعتبر شدند.
آمادهسازی یک انتشار
حال میخواهید یک بیلد را منتشر کنید.
یکی از چیزهایی که میخواهید انجام دهید ساختن آرشیوی از آخرین اسنپشاتهای کدتان برای آن دسته از بیچارگانی است که از گیت استفاده نمیکنند.
دستور این کار git archive
است:
$ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz
$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz
اگر شخصی آن تاربال را باز کند، آخرین اسنپشات پروژه شما را زیر یک پوشهٔ project
نام پیدا میکند.
همچنین شما میتوانید یک آرشیو زیپشده را به شکل مشابهی بسازید، اما با فرستادن آپشن --format=zip
به git archive
:
$ git archive master --prefix='project/' --format=zip > `git describe master`.zip
حال میتوانید یک زیپ و تاربال زیبا از انتشار پروژهٔ خود داشته باشید تا بتوانید آنرا روی وبسایت خود آپلود کرده یا به دیگران ایمیل کنید.
شورتلاگ
وقت این است که به لیست ایمیل افرادی که میخواهند بدانند چه اتفاقی در پروژه افتاده ایمیل بزنید.
یک راه مفید سریع برای گرفتن نوعی لاگ تغییراتی که زمان آخرین انتشار یا ایمیل به پروژه شما اضافه شده استفاده از دستور 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 به بعد با دستهبندی بر اساس نویسنده، میگیرید.