Git Commit چیست و یک Commit خوب چه ویژگیهایی دارد؟
تعریف Commit بهعنوان snapshot، نقش Staging، ساختار پیام پیشنهادی Pro Git، و معیارهای Commit خوب برای Review و دیباگ — با git-commit docs.
بنیانگذار و مهندس محصول

Commit در Git یک snapshot ثبتشده از وضعیت Staging (Index) است بههمراه پیام، نویسنده، زمان و اشارهگر به والد(ها). مستندات git-commit میگوید: یک Commit جدید از محتوای فعلی Index و پیام لاگ ساخته میشود و معمولاً نوک Branch جاری را جلو میبرد. تشبیه رایج در GitHub Docs: مثل گرفتن عکس از پروژه در یک لحظه.
Commit واحد همکاری است: Review، Revert، Bisect، و Deploy به آن وابستهاند. Commit بد (درهم، بیپیام، قاطی چند موضوع) هزینهٔ همهٔ اینها را بالا میبرد. این صفحه تعریف مکانیکی و معیارهای کیفیت را جدا میکند.
پیشنیاز: دانستن Working tree و Staging از مقالات ۰۷۰ و ۰۷۲.

پاسخ کوتاه
Commit خوب سه ویژگی دارد: (۱) محتوای مرتبط و تا حد ممکن اتمی — یک منظور مشخص؛ (۲) پیام روشن که چرا را بگوید نه فقط چه فایلی؛ (۳) قابل بازبینی — آنقدر بزرگ نباشد که Reviewer رد شود. طبق بحث COMMIT INFORMATION و راهنمای پیام در مستندات، عرف رایج این است که خط اول کوتاه (حدود ۵۰ کاراکتر) خلاصه باشد، سپس خط خالی و توضیح بیشتر.
تاریخچهٔ خوب بیمهٔ آینده است: شش ماه بعد خودتان اولین خوانندهٔ این پیامها هستید.
مسیر مکانیکی: add سپس commit
Git بهصورت پیشفرض هر تغییر Working tree را Commit نمیکند. ابتدا با git add تغییرات را Stage میکنید؛ سپس commit فقط همان Stage را ثبت میکند. این دو مرحله کنترل میدهد: میتوانید بخشی از فایلها را حالا و بقیه را بعداً Commit کنید.
bash
git status git add path/to/file git commit -m "Fix login redirect for expired sessions"
گزینهٔ -a فقط فایلهای ازقبلtracked را Stage و Commit میکند؛ فایلهای untracked جدید را نمیگیرد. برای کنترل دقیق، add صریح امنتر است.
داخل یک Commit چه چیزی هست؟
- Tree: ارجاع به ساختار فایلها در آن لحظه.
- Parent: Commit قبلی (در Merge ممکن است چند والد).
- Author / Committer: هویت و زمان.
- Message: عنوان و بدنه.
شناسهٔ Commit یک hash است. تغییر محتوا یا پیام (مثلاً با amend) hash جدید میسازد؛ این همان دلیلی است که بازنویسی تاریخچهٔ Pushشده دردسر ایجاد میکند.
پیام Commit: عرف پیشنهادی
مستندات git-commit در بخش DISCUSSION پیشنهاد میکند:
- خط اول: خلاصهٔ کوتاه تغییر.
- خط خالی.
- بدنه: انگیزه، زمینه، اثرات جانبی، ارجاع به Issue.
مثال ضعیف: «fix»، «updates»، «asdf». مثال بهتر:
text
Limit password reset tokens to 15 minutes Reduce replay window after support ticket #482. Matches auth policy agreed in security review.
زبان تیم را یکدست کنید (فارسی یا انگلیسی). مهمتر از زبان، ثبات و وضوح است. بسیاری از تیمها Conventional Commits یا پیشوندهای feat/fix را قرارداد میکنند — قرارداد تیم بر سلیقهٔ فردی مقدم است.
جدول: Commit خوب در برابر Commit پرهزینه
| معیار | خوب | پرهزینه |
|---|---|---|
| اندازهٔ منظور | یک موضوع / یک Fix | UI + API + rename دیتابیس با هم |
| پیام | چرا + محدوده | «تغییرات» بدون جزئیات |
| Review | در یک نشست قابل فهم | هزاران خط بدون خلاصه |
| برگشت | Revert تمیز ممکن است | Revert نصف کار را میشکند |
| Secret | نیست | .env و کلید داخلش است |
اتمیک بودن یعنی چه؟
اتمیک بهمعنی «یک خط کد» نیست؛ یعنی یک تصمیم قابل توضیح. اگر دو Fix مستقل دارید، دو Commit بزنید تا بتوان یکی را Revert کرد بدون دیگری. اگر یک فیچر بدون مهاجرت دیتابیس ناقص است، همان Commitهای پشتسرهم مرتبط را در یک PR نگه دارید ولی باز هم پیامها را جدا و شفاف بنویسید.
WIPهای شخصی روی Branch خصوصی قابل قبولاند؛ قبل از Review، با rebase/squash طبق سیاست تیم تاریخچه را تمیز کنید — فقط وقتی میدانید Branch مشترک را بازنویسی نمیکنید.
amend، پیام خالی و دامها
- git commit --amend آخرین Commit را جایگزین میکند؛ اگر Push شده و دیگران بر پایهٔ آن کار کردهاند، خطرناک است.
- --allow-empty و پیام خالی بیشتر برای ابزارهاست؛ در کار دستی عادی از آنها پرهیز کنید.
- --no-verify Hookها را دور میزند؛ فقط با دلیل و آگاهی تیم.
- Commit کردن فایل تولیدشدهٔ بیثبات (مثل کش) نویز تاریخچه میسازد.
Commit از نگاه مدیر محصول
لازم نیست پیامها را روزانه بخوانید؛ اما اگر در بحران «چه چیزی دیروز عوض شد؟» تیم نتواند از log جواب بدهد، مشکل کیفیت Commit دارید نه کمبود جلسه. در Definition of Done میتوانید بگذارید: «پیام Commit یا خلاصهٔ PR علت تغییر را میگوید».
چکلیست قبل از زدن Commit
- git status و git diff --staged را خواندهام.
- Secret و فایلهای محلی در Stage نیستند.
- تغییر با پیام در یک جمله قابل خلاصه است.
- تست یا بررسی دستی حداقلی مرتبط را انجام دادهام.
- میدانم این Commit روی کدام Branch است.
جمعبندی
Commit عکس رسمی پروژه در یک لحظه است، نه دکمهٔ ذخیرهٔ ویرایشگر. با Staging انتخاب میکنید چه چیزی داخل عکس باشد؛ با پیام توضیح میدهید چرا آن عکس مهم است. سرمایهگذاری روی Commitهای کوچک و خوانا، Review و دیباگ را ارزان میکند.
قدم بعد: همگامسازی این Commitها با Remote از طریق Push و Pull.
اندازهٔ Commit را چطور حس کنیم؟
قاعدهٔ سرانگشتی: Reviewer باید بتواند در یک نشست متمرکز بفهمد Commit چه میکند. اگر برای توضیح به سه موضوع بیربط نیاز دارید، احتمالاً باید بشکنید. برعکس، صد Commit یکخطی بیمعنی هم نویز است — تعادل با «یک منظور» است نه با تعداد خطوط.
در UI بزرگ، Commitهای لایهلایه (مثلاً اول refactor بدون رفتار، بعد تغییر رفتار) Review را دقیقتر میکند. قاطی کردن refactor و فیچر در یک Commit باعث میشود باگ پنهان بماند.
نویسنده، Committer و زمان
مستندات commit توضیح میدهد Author و Committer میتوانند فرق داشته باشند — مثلاً وقتی کسی وصلهٔ دیگری را اعمال میکند. برای کار روزمره، تنظیم user.name/email کافی است. در محیطهای شرکتی، ایمیل سازمانی به نسبتدادن درست تغییرات کمک میکند.
بازنویسی زمان یا نویسنده بدون دلیل، ممیزی را خراب میکند. اگر از --amend یا rebase استفاده میکنید، بدانید metadata عوض میشود و hash جدید میسازید.
Hookها و کیفیت خودکار
Hookهای pre-commit و commit-msg میتوانند لنت و قالب پیام را اجباری کنند. دور زدن با --no-verify باید استثنا باشد نه عادت؛ وگرنه CI همان کار را دیرتر و گرانتر شکست میدهد. اگر Hook محلی ندارید، حداقل Checklist ذهنی قبل از Commit را جدی بگیرید.
در تیمهای توزیعشده، یکسانسازی قالب پیام هزینهٔ ابزار changelog و جستجو را کم میکند. قرارداد را کوتاه و مکتوب کنید.
نمونههای بیشتر پیام
| ضعیف | بهتر | چرا |
|---|---|---|
| fix | Fix null check on checkout total | محدوده روشن است |
| final | Remove beta banner after launch | انگیزه مشخص است |
| wip | WIP: draft payment form (do not review) | اگر مجبورید WIP بزنید، صریح بگویید |
| update deps | Bump lodash to 4.17.21 for advisory | دلیل امنیتی/نسخه |
Commit و Deploy
بهترین حالت این است که هر Deploy به یک Commit یا Tag مشخص اشاره کند. آنگاه Rollback یعنی برگشت به شناسهٔ قبلی، نه حدس فایل. این پیوند در مقالهٔ ۰۵۰ هم آمده است. Commitهای درهم، انتخاب نقطهٔ Rollback را دشوار میکنند.
اگر از Release branch استفاده میکنید، پیامها و تگها باید برای انسان غیرنویسندهٔ کد هم قابلاسکن باشند؛ چون نیمهشب ممکن است همانها خوانده شوند.
فرهنگ تیمی حول Commit
در Code Review، بهجای شرمسار کردن پیام ضعیف، نمونهٔ خوب بدهید. در آنبوردینگ، پنج پیام نمونه از مخزن خودتان را نشان دهید. اگر تاریخچه پر از «fix2» است، انتظار نداشته باشید نیروی جدید بهتر عمل کند — الگو را عوض کنید.
شاخص سلامت ساده: در git log هفتهٔ اخیر، چند درصد پیامها بدون باز کردن diff قابل فهماند؟ اگر کمتر از نصف، روی پیام و اتمیک بودن کار کنید.
Staging تکهای و کنترل دقیق
گاهی فقط بخشی از تغییرات یک فایل به Commit جاری مربوط است. git add -p (patch) امکان Stage کردن hunkها را میدهد. این مهارت سطح متوسط است ولی کیفیت تاریخچه را بالا میبرد. اگر هنوز تازهکارید، فایلها را فیزیکی جدا کنید یا تغییرات را پشتسرهم انجام دهید تا Commit قاطی نشود.
bash
git add -p
بعد از Stage، همیشه diff --staged را بخوانید. این ارزانترین Review ممکن است: Review توسط خودتان قبل از ثبت تاریخچه.
Commit خالی، Merge Commit و پیامهای خاص
Commitهای خالی (--allow-empty) گاهی برای تریگر CI یا علامتگذاری استفاده میشوند؛ در کار عادی لازم نیستند. Merge Commit پیام خودکار دارد و بخشی از تاریخچهٔ True merge است. پیامهای fixup! برای جریان autosquash پیشرفتهاند — بعد از راحتی با rebase سراغشان بروید.
امضای GPG/SSH برای Commit در بعضی پروژهها اجباری است و ثابت میکند هویت Committer با کلید شما همخوان است. اگر پروژه الزام دارد، از مستندات هاست برای فعالسازی پیروی کنید.
رابطهٔ Commit با Issue و PR
ارجاع به شمارهٔ Issue در پیام (مثلاً Fixes #123 طبق قرارداد هاست) ردیابی را خودکار میکند. در PRهای چند Commitی، پیامها باید داستان را بگویند؛ عنوان PR خلاصهٔ کل است نه جایگزین پیامهای داخلی.
اگر squash میکنید، پیام نهایی squash همان چیزی است که روی main میماند — وقت بگذارید آن را خوب بنویسید.
ضدالگوهای رایج در تیمهای عجلهدار
- یک Commit در پایان روز با همه چیز قاطی.
- پیامهای emoji-only بدون متن.
- Commit کردن کد کامنتشدهٔ زیاد بهجای حذف تمیز.
- Commit کردن artifact بیلد بهجای خروجی CI.
- عوض کردن قالب پیام هر هفته بدون سند.
درجهٔ اصلاح: در Review مؤدبانه برگردانید؛ در اسناد نمونه بگذارید؛ در Hook فقط وقتی تیم آماده است سختگیری کنید.
تمرین کیفیت پیام
ده Commit آخر مخزن فعلیتان را بخوانید. برای سه تای ضعیف، نسخهٔ بازنویسیشده بنویسید (بدون بازنویسی واقعی تاریخچه اگر مشترک است). این تمرین عضلهٔ نوشتن را میسازد بهتر از حفظ قواعد انتزاعی.
هدف نهایی: تاریخچهای که در حادثه Production، در پنج دقیقه به شما بگوید چه چیزی، چرا و توسط چه کسی وارد شده است.
Commit در حضور AI و تولید کد
وقتی بخشی از کد را مدل تولید کرده، همان را شفاف در پیام یا توصیف PR بگویید و خودتان Review کنید. Commit کردن کور خروجی مدل، بدهی فهم ایجاد میکند. Staging دقیق اینجا حیاتی است: فقط فایلهای مرتبط را Stage کنید نه کل diffهای اتفاقی ادیتور.
اندازهٔ Commit را طوری نگه دارید که بتوانید توضیح انسانی بدهید. اگر نمیتوانید بگویید چرا این بیست فایل با هم عوض شدند، هنوز آمادهٔ Commit نیستید — یا باید بشکنید یا درک کنید.
تیم میتواند در قرارداد بگذارد: هر Commit باید توسط انسان قابل دفاع باشد، حتی اگر ابزار پیشنهادش داده است. این مرز کنترل را حفظ میکند.
در کنارش، از Commit بهعنوان نقطهٔ بازگشت قبل از آزمایش بزرگ مدل استفاده کنید: یک Commit تمیز، بعد آزمایش، بعد یا Commit جدید یا برگشت. Git بیمهٔ کار با AI است.
قالب پیشنهادی تیم برای پیام — نمونهٔ قابل کپی
یک قالب ساده که بدون ابزار خاص کار میکند:
text
خلاصهٔ امری کوتاه چرا این تغییر لازم شد؟ چه ریسکی یا اثر جانبی دارد؟ ارجاع: Issue/تیکت
اجباری کردن قالب سخت در Hook فقط وقتی مفید است که تیم روی معنای آن توافق دارد. اگر قالب را بدون آموزش اجباری کنید، پیامهای بیمعنی اما «مطابق قالب» تولید میشود. اول فرهنگ، بعد اتوماسیون.
در کدبیس دو زبانه، تصمیم بگیرید پیامها فارسیاند یا انگلیسی و همان را در CONTRIBUTING بنویسید. دوگانگی بدون قاعده جستجوی تاریخچه را سخت میکند.
به Reminder: Commit خوب برای انسان نوشته میشود؛ hash برای ماشین است. وقت نوشتن پیام سرمایهگذاری در آیندهٔ دیباگ است.
از Commit تا اعتماد تیمی
اعتماد Reviewer به تاریخچه وقتی بالا میرود که پیامها قابل پیشبینی و محتوا اتمیک باشد. هر بار که یک Commit درهم Merge میشود، هزینهٔ ذهنی نسل بعدی بیشتر میشود. برعکس، تاریخچهٔ تمیز مثل مستند زنده عمل میکند و onboarding را کوتاه میکند.
اگر تیم شما الان تاریخچهٔ شلوغ دارد، لازم نیست گذشته را بازنویسی کنید؛ از Branch بعدی استاندارد را اعمال کنید. آینده را تمیز بسازید؛ وسواس پاک کردن تمام گذشته معمولاً ارزشش را ندارد و خطرناک است.
یک توافق کتبی دخطی در CONTRIBUTING دربارهٔ پیام و اندازهٔ Commit، بهتر از دهها تذکر شفاهی پراکنده است. همان را در اولین PR به تازهوارد لینک دهید.
منابع و مراجع
- 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
- GitHub Docs — About Git — https://docs.github.com/en/get-started/using-git/about-git
- Pro Git — Viewing the Commit History — https://git-scm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History
- Git Documentation hub — https://git-scm.com/docs
نویسنده
سهیل ابراهیمپور بنیانگذار FutureForge است. روی طراحی محصول، معماری و استقرار نرمافزار سفارشی کار میکند.
یادداشتهای مرتبط
اگر در انتخاب معماری یا مسیر توسعه مطمئن نیستید، میتوانید درباره پروژه صحبت کنیم.
مسئله و محدودیت را بنویسید. اگر تطابق داشته باشیم، برای گفتگو هماهنگ میکنیم.




