Git Commit چیست؟ Snapshot، پیام و واحد برگشتپذیر تاریخچه
Commit بهعنوان شیء snapshot با والد و پیام؛ معیار اتمی بودن، پیام از دید Pro Git و git-commit، و هزینهٔ Commit بد برای Review و Deploy.
بنیانگذار و مهندس محصول

Commit فقط «ذخیره» نیست. طبق مستندات git-commit، یک Commit جدید از محتوای فعلی Index و یک پیام لاگ ساخته میشود و معمولاً نوک Branch جاری را جلو میبرد. GitHub Docs تشبیه عکس لحظهای از پروژه را بهکار میبرد؛ Pro Git تأکید میکند مدل Git مبتنی بر snapshot است نه زنجیرهٔ صرف patch. واحدی که Review، Revert، Bisect و Deploy به آن قفل میشوند همین شیء است.
مقالهٔ ۰۷۴ تعریف اولیه داد؛ اینجا زاویهٔ عمیقتر است: داخل شیء Commit چه میگذرد، اتمی بودن یعنی چه مسئلهای را حل میکند، پیام چگونه هزینهٔ آینده را کم میکند، و چه محدودیتهایی amend و بازنویسی دارند.

پاسخ کوتاه
Commit یک شیء در دیتابیس Git است که به یک tree (وضعیت فایلها) اشاره میکند، یک یا چند والد دارد، نویسنده/زمان دارد، و پیام انسانی همراهش است. شناسهاش hash محتواست؛ تغییر پیام یا محتوا hash جدید میسازد. Commit خوب یک منظور روشن، پیام «چرا»-محور، و اندازهای دارد که بازبینیپذیر باشد.
شش ماه بعد، اولین خوانندهٔ پیام Commit خودتان هستید — تاریخچه بیمه است نه خاطره.
مکانیک: از Index تا شیء Commit
چرخهٔ پایه:
bash
git status git add -p git commit -m "Explain the reason, not only the file list" git log -1 --oneline
داخل هر Commit تقریباً این فرادادهها هستند:
- Tree: ریشهٔ ساختار فایل در آن لحظه (با اشتراک blobهای تکراری).
- Parent: Commit قبلی؛ Merge میتواند چند والد داشته باشد.
- Author و Committer: ممکن است فرق کنند (مثلاً پس از rebase یا patch).
- Message: عنوان و بدنه.
چون شناسایی content-addressable است، «همان Commit» یعنی همان hash. بازنویسی تاریخچهٔ Pushشده با force برای همتیمیها هزینه دارد — مگر قرارداد صریح Branch خصوصی.
اتمیک بودن: مسئله، نه شعار
اتمیک بهمعنی یک خط کد نیست؛ یعنی یک تصمیم قابل توضیح و قابل برگشت. اگر UI و مهاجرت دیتابیس را در یک Commit قاطی کنید، Revert یکی بدون دیگری سخت میشود. اگر دو باگ مستقل را با هم ببندید، bisect سیگنال را گلآلود میکند.
- یک منظور = یک Commit (یا زنجیرهٔ مرتبط در یک PR با پیامهای جدا).
- WIP روی Branch شخصی مجاز است؛ قبل از Merge به main بهتر است تاریخچه خوانا شود (squash یا rebase تعاملی با احتیاط).
- اندازهٔ خط مهم است اما «منظور» مهمتر از تعداد فایل.
پیام Commit از دید مستندات
بخش DISCUSSION در git-commit پیشنهاد میکند: خط اول خلاصهٔ کوتاه، سپس خط خالی، سپس بدنه با انگیزه و زمینه. عرف حدود ۵۰ کاراکتر برای موضوع در بسیاری از تیمها رایج است؛ مهمتر از عدد، خوانایی در git log --oneline است.
text
Restrict password-reset tokens to 15 minutes Shorten replay window after incident review. Aligns with auth policy in SECURITY.md.
ضعیف: fix، updates، asdf، «تغییرات». قوی: مشکل، محدودیت، و ارجاع به Issue/Incident. زبان تیم (فارسی یا انگلیسی) را یکدست کنید؛ Conventional Commits قرارداد اختیاری است نه قانون Git.
جدول: Commit ارزان در برابر Commit پرهزینه
| معیار | ارزان برای آینده | پرهزینه |
|---|---|---|
| منظور | یک تصمیم روشن | چند موضوع قاطی |
| پیام | چرا + محدوده | فهرست مبهم فایلها |
| Review | در یک نشست قابل فهم | هزاران خط بدون خلاصه |
| Revert | تمیز ممکن است | نیمهٔ سیستم میشکند |
| Secret | نیست | کلید داخل تاریخچه |
| Hash پایدار | پس از Push عوض نمیشود | amend مکرر روی main مشترک |
Amend، پیام اشتباه، و تاریخچهٔ عمومی
git commit --amend آخرین Commit را جایگزین میکند (hash جدید). روی Commitی که هنوز Push نشده یا روی Branch کاملاً خصوصی معمولاً امن است. روی main مشترک که دیگران از آن Pull کردهاند، بازنویسی باعث واگرایی دردناک میشود. قانون عملی: عمومی شد → بهجای amend، Commit اصلاحی جدید یا revert.
Commit و Deploy / CI
پایپلاینها معمولاً به hash قفل میشوند. Commit شلخته یعنی Artifact مبهم. پیام خوب در Release Note و bisect زمان قطعی شدن رگرسیون را کم میکند. Tag روی Commit مشخص نسخهٔ انتشار را ثابت میکند — نه «آخرین فایل روی لپتاپ».
اشتباههای رایج
- یک Commit هفتگی غولپیکر بهجای واحدهای بازبینیپذیر.
- Commit کردن فایل تولیدشده یا dependency بدون نیاز.
- خالی گذاشتن پیام یا تکیه به پیام پیشفرض Merge بدون توضیح.
- Amend بعد از Push بدون هماهنگی.
- فرض اینکه تعداد Commit زیاد = حرفهای؛ کیفیت پیام و منظور مهم است.
Commit بهعنوان قرارداد اجتماعی تیم
علاوه بر مکانیک، Commit واحد اعتماد است: Reviewer روی آن کامنت میگذارد، CI روی hash سبز/قرمز میشود، و Incident Response میپرسد کدام Commit به Production رفت. اگر پیامها بیمعنی باشند، این قرارداد اجتماعی میشکند حتی اگر Git از نظر فنی سالم باشد.
تیمهای بالغ اغلب در راهنمای CONTRIBUTING مینویسند: زبان پیام، اشاره به Issue، و ممنوعیت Commit شامل Secret. این قواعد مکمل git-commit هستند نه جایگزین.
نمونهٔ گردش با پیام چندخطی
bash
git commit -m "$(cat <<'EOF' Fail closed when payment provider times out Timeouts previously returned HTTP 200 with empty body, which caused clients to mark orders as paid. See incident-2026-03-12 and issue #918. EOF )"
بدنه به «چرا» و اثر کاربر اشاره میکند؛ خط اول برای log --oneline کافی است. این سبک با مستندات DISCUSSION در git-commit همراستاست.
Bisect و ارزش Commit اتمی
git bisect روی تاریخچهای که هر Commit یک تغییر مفهومی دارد سریع به Commit مقصر میرسد. اگر هر Commit ترکیبی از refactor و فیچر و فرمت باشد، bisect شما را به «این Commit همهچیز را عوض کرد» میرساند بدون سیگنال مفید. اتمی بودن سرمایهگذاری روی روز حادثه است.
Empty commit و Commitهای سیاستی
گاهی تیمها Commit خالی با --allow-empty برای تریگر CI میزنند. مجاز است ولی بهتر است علت در پیام باشد. Commitهای «فقط برای سبز کردن» را با اصلاح تست واقعی اشتباه نگیرید.
نویسنده، Committer و هویت
user.name و user.email هویت تاریخچه را میسازند. روی ماشین مشترک یا تصویر CI، تنظیم اشتباه نویسنده را غلط ثبت میکند. Signed commits لایهٔ اضافه برای اثبات کلید است؛ وقتی Branch protection آن را بخواهد، پیام بدون امضا Merge نمیشود.
bash
git config user.name "Your Name" git config user.email "you@example.com" git log -1 --format=fuller
اندازهٔ PR و اندازهٔ Commit؛ دو مقیاس
میتوانید روی Branch ده Commit اتمی داشته باشید و یک PR واحد بسازید. میتوانید یک Commit واحد هم داشته باشید. مقیاس Commit برای تاریخچه و bisect است؛ مقیاس PR برای Review انسانی. هر دو را قاطی نکنید: PR بزرگ با یک Commit غولپیکر هم Review را سخت میکند هم تاریخچه را.
اگر سیاست squash روی Merge باشد، Commitهای میانی روی main فشرده میشوند ولی در صفحهٔ PR برای Review باقی میمانند. باز هم نوشتن پیام خوب در طول کار، Review را بهتر میکند.
Hookها و کیفیت Commit
pre-commit و commit-msg میتوانند lint یا الگوی پیام را اجباری کنند. مفیدند اگر سریع و قابلفهم باشند؛ اگر ده دقیقه طول بکشند، افراد --no-verify میزنند و فرهنگ دور زدن شکل میگیرد. Hook مکمل آموزش است نه جایگزین.
bash
# مثال مفهومی — ابزارها بسته به زبان فرق دارند # pre-commit run --all-files
سوالات متداول
چند Commit در روز طبیعی است؟
به جریان کار بستگی دارد. معیار بازبینیپذیری است نه سهمیه. روی Branch فیچر میتوانید زیاد Commit کنید و قبل از Merge منظم کنید اگر تیم اجازه دهد.
آیا هر Commit باید تست سبز داشته باشد؟
ایدهآل برای main بله؛ روی Branch شخصی گاهی Commit میانی قرمز است. سیاست تیم را صریح کنید.
Signed commit لازم است؟
در بسیاری سازمانها برای اثبات هویت و Branch protection مفید است؛ جزو تعریف پایهٔ Commit نیست ولی لایهٔ اعتماد اضافه میکند.
خلاصه
Commit snapshot ثبتشده از Index است با هویت، والد و پیام. ارزشش در اتمی بودن، پیام چرا-محور، و پایداری hash پس از انتشار است. Commit بد هزینهٔ Review، دیباگ و Rollback را بالا میبرد؛ Commit خوب همان واحدی است که تیم روی آن توافق میکند «این تغییر وارد شد».
بعدی: Branch را بهعنوان اشارهگر متحرک بشناسید (۲۰۵) تا بفهمید Commitها چطور خطوط موازی میسازند.
منابع و مراجع
- git-commit documentation — https://git-scm.com/docs/git-commit
- Pro Git — Recording Changes to the Repository — https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository
- Pro Git — What is Git? (snapshots) — https://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F
- GitHub Docs — About Git — https://docs.github.com/en/get-started/using-git/about-git
- GitHub Docs — Commit changes to your project — https://docs.github.com/en/github/committing-changes-to-your-project
نویسنده
سهیل ابراهیمپور بنیانگذار FutureForge است. روی طراحی محصول، معماری و استقرار نرمافزار سفارشی کار میکند.
یادداشتهای مرتبط
اگر در انتخاب معماری یا مسیر توسعه مطمئن نیستید، میتوانید درباره پروژه صحبت کنیم.
مسئله و محدودیت را بنویسید. اگر تطابق داشته باشیم، برای گفتگو هماهنگ میکنیم.




