Chapters ▾ 2nd Edition

8.3 Customizing Git (سفارشی‌سازی Git) - Git Hooks (هوک‌های گیت)

Git Hooks (هوک‌های گیت)

مانند بسیاری از سیستم‌های کنترل نسخه دیگر، Git این امکان را دارد که هنگام وقوع اقدامات مهم، اسکریپت‌های سفارشی را اجرا کند. این hookها به دو دسته تقسیم می‌شوند: سمت کلاینت (client-side) و سمت سرور (server-side). Hookهای سمت کلاینت توسط عملیاتی مانند commit و merge فعال می‌شوند، در حالی که hookهای سمت سرور هنگام انجام عملیات شبکه‌ای مانند دریافت pushها اجرا می‌شوند. شما می‌توانید از این hookها برای اهداف گوناگونی استفاده کنید.

Installing a Hook (نصب یک هوک)

تمام hookها در زیر‌پوشه‌ای به نام hooks در دایرکتوری Git ذخیره می‌شوند. در اکثر پروژه‌ها، این مسیر برابر است با .git/hooks. وقتی یک ریپازیتوری جدید را با git init مقداردهی اولیه می‌کنید، Git دایرکتوری hooks را با مجموعه‌ای از اسکریپت‌های نمونه پر می‌کند؛ بسیاری از این اسکریپت‌ها به خودی خود مفید هستند، و همچنین نحوه‌ی دریافت ورودی‌ها توسط هر اسکریپت را مستند کرده‌اند. تمام مثال‌ها به‌صورت shell script نوشته شده‌اند (با کمی کد Perl)، اما هر اسکریپت اجرایی با نام مناسب کار خواهد کرد — می‌توانید آن‌ها را با Ruby، Python یا هر زبان دیگری که با آن آشنایی دارید بنویسید.

اگر می‌خواهید از اسکریپت‌های آماده استفاده کنید، باید آن‌ها را تغییر نام دهید؛ زیرا همه‌ی فایل‌ها پسوند .sample دارند.

برای فعال‌سازی یک اسکریپت hook، کافیست یک فایل اجرایی (بدون پسوند) با نام مناسب در زیرپوشه hooks از دایرکتوری .git قرار دهید. از آن لحظه به بعد، Git در زمان مناسب آن اسکریپت را اجرا خواهد کرد.

در ادامه، بیشتر نام‌های رایج و کلیدی hookها را بررسی خواهیم کرد.

Client-Side Hooks (هوک‌های سمت کلاینت)

تعداد زیادی hook سمت کلاینت وجود دارد. در این بخش، آن‌ها را به سه دسته تقسیم می‌کنیم:

hookهای مربوط به فرآیند commit
اسکریپت‌های مرتبط با گردش‌کار ایمیل (email workflow)
و سایر موارد متفرقه

هر دسته نقش خاصی در خودکارسازی یا کنترل دقیق‌تر عملیات در Git دارد.

یادداشت

نکته‌ی مهم این است که hookهای سمت کلاینت هنگام clone کردن یک ریپازیتوری کپی نمی‌شوند. اگر هدف شما از این اسکریپت‌ها اعمال یک سیاست یا محدودیت خاص است، بهتر است این کار را در سمت سرور انجام دهید. برای این منظور، می‌توانید به مثال موجود در بخش An Example Git-Enforced Policy (یک مثال از سیاست‌های تحمیلی گیت) مراجعه کنید، که نحوه‌ی پیاده‌سازی یک سیاست کنترل‌شده توسط Git را در سمت سرور توضیح می‌دهد.

Committing-Workflow Hooks (هوک‌های جریان کاری کامیت)

چهار هوک اول مربوط به فرآیند کامیت کردن هستند.

هوک pre-commit اولین هوکی است که اجرا می‌شود، پیش از آن‌که حتی پیام کامیت را بنویسید. از آن برای بررسی اسنپ‌شاتی که قرار است کامیت شود استفاده می‌شود — برای اینکه مطمئن شوید چیزی را فراموش نکرده‌اید، تست‌ها به‌درستی اجرا می‌شوند، یا هر بررسی دلخواه دیگری روی کد انجام شده است. اگر اجرای این هوک با وضعیت غیر صفر (non-zero) تمام شود، فرآیند کامیت لغو می‌شود. البته می‌توانید با استفاده از git commit --no-verify از آن عبور کنید. با این هوک می‌توانید کارهایی مثل بررسی استایل کد (مثلاً اجرای lint یا ابزار مشابه)، بررسی وجود فاصله‌ی اضافی در انتهای خطوط (که هوک پیش‌فرض همین کار را انجام می‌دهد)، یا بررسی مستندات مناسب برای متدهای جدید را انجام دهید.

هوک prepare-commit-msg قبل از باز شدن ادیتور پیام کامیت اجرا می‌شود، اما بعد از تولید پیام پیش‌فرض. این امکان را می‌دهد که پیش از آن‌که نویسنده پیام را ببیند، آن را ویرایش کنید. این هوک چند پارامتر دریافت می‌کند: مسیر فایلی که تا اینجا پیام کامیت در آن نوشته شده، نوع کامیت، و اگر کامیت از نوع «اصلاح‌شده» (amended) باشد، SHA-1 آن کامیت. این هوک معمولاً برای کامیت‌های عادی کاربرد زیادی ندارد؛ بلکه بیشتر در مواردی مفید است که پیام پیش‌فرض کامیت به‌صورت خودکار تولید می‌شود — مثل کامیت‌های حاصل از مرج، اسکواش، یا اصلاح. می‌توانید از این هوک همراه با یک تمپلیت پیام کامیت استفاده کنید تا اطلاعات موردنظر را به‌صورت برنامه‌نویسی‌شده درج کنید.

هوک commit-msg یک پارامتر دریافت می‌کند: مسیر فایلی موقت که پیام کامیت نوشته‌شده توسط توسعه‌دهنده در آن قرار دارد. اگر این اسکریپت با وضعیت غیر صفر خاتمه یابد، Git فرآیند کامیت را متوقف می‌کند. پس می‌توان از آن برای اعتبارسنجی وضعیت پروژه یا بررسی فرمت پیام کامیت پیش از انجام کامیت استفاده کرد. در انتهای این فصل، مثالی از کاربرد این هوک برای بررسی تطابق پیام کامیت با یک الگوی خاص خواهیم دید.

پس از تکمیل کامل فرآیند کامیت، هوک post-commit اجرا می‌شود. این هوک هیچ پارامتری دریافت نمی‌کند، اما به‌راحتی می‌توانید آخرین کامیت را با اجرای git log -1 HEAD به‌دست آورید. معمولاً از این اسکریپت برای کارهایی مثل ارسال نوتیفیکیشن یا موارد مشابه استفاده می‌شود.

Email Workflow Hooks (هوک‌های جریان کاری ایمیل)

می‌توانید سه هوک سمت کلاینت برای یک گردش‌کار مبتنی بر ایمیل تنظیم کنید. تمام این هوک‌ها توسط دستور git am فراخوانی می‌شوند، بنابراین اگر در روند کاری‌تان از این دستور استفاده نمی‌کنید، می‌توانید با خیال راحت به بخش بعدی بروید. اگر وصله‌ها (patch) را از طریق ایمیل و با استفاده از git format-patch دریافت می‌کنید، بعضی از این هوک‌ها ممکن است برایتان مفید باشند.

اولین هوکی که اجرا می‌شود، applypatch-msg است. این هوک یک آرگومان دریافت می‌کند: نام فایل موقتی که پیام کامیت پیشنهادی در آن قرار دارد. اگر این اسکریپت با وضعیت غیر صفر (non-zero) خارج شود، Git عملیات وصله را متوقف می‌کند. می‌توانید از این هوک برای اطمینان از قالب مناسب پیام کامیت استفاده کنید، یا اینکه با ویرایش پیام در همان فایل، آن را به شکل دلخواه نرمال‌سازی کنید.

هوک بعدی که هنگام اعمال وصله از طریق git am اجرا می‌شود، pre-applypatch است. نکته‌ای که ممکن است کمی گیج‌کننده باشد این است که این هوک بعد از اعمال وصله ولی پیش از ایجاد کامیت اجرا می‌شود، بنابراین می‌توانید از آن برای بررسی اسنپ‌شات قبل از ثبت نهایی استفاده کنید. می‌توانید تست‌ها را اجرا کنید یا به هر شکل دیگری شاخه‌ی کاری را بررسی کنید. اگر چیزی کم باشد یا تست‌ها رد شوند، با خروجی غیر صفر، اسکریپت git am را بدون اعمال کامیت متوقف می‌کند.

آخرین هوکی که در فرآیند git am اجرا می‌شود، post-applypatch است، که بعد از انجام کامیت اجرا می‌شود. می‌توانید از آن برای اطلاع‌رسانی به گروه یا نویسنده‌ی وصله‌ای که دریافت کرده‌اید استفاده کنید که این وصله دریافت و اعمال شده است. توجه داشته باشید که این اسکریپت نمی‌تواند فرآیند اعمال وصله را متوقف کند.

Other Client Hooks (سایر هوک‌های کلاینت)

هوک pre-rebase قبل از آنکه چیزی را ریبیس (rebase) کنید، اجرا می‌شود و می‌تواند فرآیند را با خروجی غیر صفر متوقف کند. از این هوک می‌توانید برای جلوگیری از ریبیس کردن کامیت‌هایی که قبلاً به ریموت پوش شده‌اند استفاده کنید. مثال هوک pre-rebase که توسط Git نصب می‌شود همین کار را انجام می‌دهد، هرچند که ممکن است فرضیاتی داشته باشد که با روند کاری شما هم‌خوانی نداشته باشد.

هوک post-rewrite توسط دستوراتی که کامیت‌ها را تغییر می‌دهند اجرا می‌شود، مانند git commit --amend و git rebase (اما نه git filter-branch). این هوک یک پارامتر دریافت می‌کند که مشخص می‌کند کدام دستور تغییر را ایجاد کرده است، و همچنین فهرستی از تغییرات را از طریق stdin دریافت می‌کند. این هوک بسیاری از کاربردهای مشابه هوک‌های post-checkout و post-merge را دارد.

پس از اجرای موفقیت‌آمیز دستور git checkout، هوک post-checkout اجرا می‌شود. می‌توانید از این هوک برای تنظیم مناسب دایرکتوری کاری‌تان برای محیط پروژه استفاده کنید. این ممکن است شامل جابجایی فایل‌های باینری بزرگ که نمی‌خواهید تحت کنترل نسخه باشند، تولید خودکار مستندات، یا کارهای مشابه باشد.

هوک post-merge پس از اجرای موفقیت‌آمیز دستور merge اجرا می‌شود. می‌توانید از این هوک برای بازیابی داده‌ها در دایرکتوری کاری استفاده کنید که Git قادر به پیگیری آن‌ها نیست، مانند داده‌های دسترسی (permissions). این هوک همچنین می‌تواند وجود فایل‌های خارجی که تحت کنترل Git نیستند را اعتبارسنجی کرده و در صورتی که نیاز باشد آن‌ها را هنگام تغییر دایرکتوری کاری کپی کند.

هوک pre-push هنگام اجرای دستور git push اجرا می‌شود، پس از آنکه رفرنس‌های ریموت به‌روزرسانی شده‌اند، اما قبل از انتقال هر شیء. این هوک نام و موقعیت ریموت را به‌عنوان پارامتر دریافت می‌کند، و فهرستی از رفرنس‌های به‌روزرسانی‌شده از طریق stdin دریافت می‌کند. می‌توانید از آن برای اعتبارسنجی مجموعه‌ای از به‌روزرسانی‌های رفرنس پیش از انجام پوش استفاده کنید (خروجی غیر صفر باعث توقف فرآیند پوش می‌شود).

Git به‌طور دوره‌ای عملیات جمع‌آوری زباله (garbage collection) را به‌عنوان بخشی از عملکرد معمول خود انجام می‌دهد، با فراخوانی دستور git gc --auto. هوک pre-auto-gc درست قبل از انجام جمع‌آوری زباله اجرا می‌شود و می‌توان از آن برای اطلاع‌رسانی به شما در مورد وقوع این عملیات یا برای متوقف کردن جمع‌آوری در صورت عدم مناسب بودن زمان استفاده کرد.

Server-Side Hooks (هوک‌های سمت سرور)

علاوه بر هوک‌های سمت کلاینت، به‌عنوان یک مدیر سیستم می‌توانید از چند هوک مهم سمت سرور برای اعمال هر نوع سیاستی که می‌خواهید برای پروژه‌تان استفاده کنید. این اسکریپت‌ها قبل و بعد از پوش به سرور اجرا می‌شوند. هوک‌های پیشین (pre-hooks) در هر زمانی می‌توانند با خروجی غیر صفر (non-zero) پوش را رد کنند و همچنین پیام خطا را به کلاینت ارسال کنند. شما می‌توانید یک سیاست پوش با هر پیچیدگی که می‌خواهید تنظیم کنید.

pre-receive

اولین اسکریپت که هنگام پردازش یک پوش از سمت کلاینت اجرا می‌شود، pre-receive است. این اسکریپت فهرستی از رفرنس‌هایی که در حال پوش شدن هستند را از طریق stdin دریافت می‌کند؛ اگر با خروجی غیر صفر (non-zero) تمام شود، هیچ‌کدام از آن‌ها پذیرفته نمی‌شوند. می‌توانید از این هوک برای کارهایی مانند اطمینان از اینکه هیچ‌کدام از رفرنس‌های به‌روزرسانی‌شده غیر-فست‌فورواد (non-fast-forwards) نباشند، یا برای اعمال کنترل دسترسی به تمامی رفرنس‌ها و فایل‌هایی که با پوش تغییر می‌کنند، استفاده کنید.

update

اسکریپت update شباهت زیادی به اسکریپت pre-receive دارد، با این تفاوت که برای هر برنچی که پُشر (pusher) در تلاش است تا به‌روزرسانی کند، یکبار اجرا می‌شود. اگر پُشر در تلاش باشد که به چندین برنچ پوش کند، pre-receive تنها یکبار اجرا می‌شود، در حالی که update برای هر برنچی که قصد پوش آن را دارد، یکبار اجرا می‌شود. این اسکریپت به‌جای خواندن از stdin، سه پارامتر دریافت می‌کند: نام رفرنس (برنچ)، SHA-1 که آن رفرنس قبل از پوش به آن اشاره می‌کرد، و SHA-1 که کاربر در تلاش است آن را پوش کند. اگر اسکریپت update با خروجی غیر صفر (non-zero) تمام شود، تنها همان رفرنس رد می‌شود؛ رفرنس‌های دیگر همچنان می‌توانند به‌روزرسانی شوند.

post-receive

هوک post-receive پس از اتمام کامل فرآیند اجرا می‌شود و می‌توان از آن برای به‌روزرسانی خدمات دیگر یا اطلاع‌رسانی به کاربران استفاده کرد. این اسکریپت همان داده‌های stdin را که pre-receive دریافت می‌کند، می‌گیرد. مثال‌هایی از این استفاده‌ها شامل ارسال ایمیل به یک فهرست، اطلاع‌رسانی به سرور یکپارچه‌سازی مداوم (CI)، یا به‌روزرسانی سیستم پیگیری تیکت‌ها است – حتی می‌توانید پیام‌های کامیت را تجزیه کرده و بررسی کنید که آیا تیکتی باید باز، ویرایش یا بسته شود. این اسکریپت نمی‌تواند فرآیند پوش را متوقف کند، اما کلاینت تا زمانی که اسکریپت کامل شود از سرور جدا نمی‌شود، بنابراین اگر قصد دارید کاری انجام دهید که زمان زیادی می‌برد، باید مراقب باشید.

scroll-to-top