git hook — commit, push oldidan avtomatik ishlar bajarish
Muammodan boshlaylik
PR ochdingiz. 2 daqiqadan keyin CI (38-dars) qizil:
- ESLint: 3 ta xato
- Prettier: 12 ta fayl formatlanmagan
- Test buzilgan —
console.logqolib ketgan
Tuzatish, push, yana kutish. Kuniga bir necha marta. Bu xatolarning hammasini commit qilish paytidayoq, lokalda, bir soniyada ushlash mumkin edi.
Git hooks — Git hodisalari (commit, push, merge) oldidan yoki keyin avtomatik ishga tushadigan skriptlar.
Hook nima?
Har bir repozitoriyda .git/hooks/ papkasi bor (5-dars):
ls .git/hooks
applypatch-msg.sample pre-commit.sample pre-push.sample
commit-msg.sample pre-rebase.sample prepare-commit-msg.sample
post-update.sample pre-merge-commit.sample ...
Bular — namunalar. .sample ni olib tashlab, faylni bajariladigan qilsangiz — hook faol bo'ladi.
Asosiy hook lar
| Hook | Qachon | Tipik foydalanish |
|---|---|---|
pre-commit |
Commit yaratilishidan oldin | Lint, formatlash, sirlarni qidirish |
commit-msg |
Xabar yozilgandan keyin | Xabar formatini tekshirish (34-dars) |
prepare-commit-msg |
Muharrir ochilishidan oldin | Xabarga branch dagi issue raqamini qo'shish |
pre-push |
Push dan oldin | Testlar |
post-merge |
Merge (va pull) dan keyin |
package-lock.json o'zgargan bo'lsa — npm install |
post-checkout |
Branch almashtirilgandan keyin | Xuddi shu |
Qoida: pre-* hook 0 dan farqli kod bilan chiqsa — Git harakatni bekor qiladi (Linux kursi, 38-dars: chiqish kodlari).
Birinchi hook — qo'lda
console.log qolgan commitlarni taqiqlash:
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
# Staging dagi JS fayllarda console.log bormi?
if git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|jsx|tsx)#39; \
| xargs -r grep -n "console\.log" ; then
echo ""
echo "❌ Commit to'xtatildi: console.log topildi (yuqorida)."
echo " Ataylab bo'lsa: git commit --no-verify"
exit 1
fi
exit 0
EOF
chmod +x .git/hooks/pre-commit
git commit -m "feat: savat"
src/savat.js:42: console.log('DEBUG', items);
❌ Commit to'xtatildi: console.log topildi (yuqorida).
git diff --cached --name-only— faqat staged fayllar--diff-filter=ACM— qo'shilgan, nusxalangan, o'zgargan (o'chirilganlar emas)xargs -r— fayl bo'lmasa grep ni ishga tushirmaslik (Linux kursi, 15-dars)
Hook har qanday tilda bo'lishi mumkin — shebang ga qarab (#!/usr/bin/env node, #!/usr/bin/env python3).
Muammo: .git/hooks commit qilinmaydi
.git/ ichidagi hech narsa repozitoriyga tushmaydi. Hook ni yozdingiz — u faqat sizda ishlaydi. Hamkasblar clone qilganda — hook yo'q.
Yechim 1: core.hooksPath
Hook larni oddiy papkada saqlash va Git ga ko'rsatish:
mkdir .githooks
mv .git/hooks/pre-commit .githooks/
git config core.hooksPath .githooks
git add .githooks && git commit -m "chore: git hook lar"
Har bir dasturchi clone dan keyin bir marta git config core.hooksPath .githooks qilishi kerak (README da yozing yoki npm skriptiga qo'shing).
Yechim 2: Husky (JavaScript loyihalari)
Eng ommabop vosita — npm install paytida hook larni avtomatik sozlaydi:
npm install -D husky
npx husky init
Bu .husky/pre-commit faylini yaratadi va package.json ga "prepare": "husky" skriptini qo'shadi — endi har bir npm install hook larni avtomatik o'rnatadi.
# .husky/pre-commit
npx lint-staged
# .husky/commit-msg
npx --no -- commitlint --edit "$1"
# .husky/pre-push
npm test
lint-staged — faqat o'zgargan fayllar
Butun loyihani har commit da lint qilish — sekin. lint-staged faqat staged fayllarni tekshiradi va avtomatik tuzatadi:
// package.json
{
"lint-staged": {
"*.{js,ts,jsx,tsx}": ["eslint --fix", "prettier --write"],
"*.{css,md,json}": "prettier --write"
}
}
npm install -D lint-staged
$ git commit -m "feat: savat"
✔ Preparing lint-staged...
✔ Running tasks for staged files...
✔ *.{js,ts,jsx,tsx} — 3 files
✔ eslint --fix
✔ prettier --write
✔ Applying modifications from tasks...
[feature/savat a1b2c3d] feat: savat
Formatlash avtomatik tuzatildi va commit ga kiritildi. Xato bo'lsa — commit to'xtaydi.
Boshqa tillar uchun
- pre-commit (Python, lekin har qanday til uchun):
.pre-commit-config.yaml - lefthook — tez, tilga bog'liq emas
- PHP — CaptainHook, GrumPHP
Foydali hook g'oyalari
# post-merge: bog'liqliklar o'zgargan bo'lsa — eslatish yoki o'rnatish
#!/bin/sh
if git diff --name-only HEAD@{1} HEAD | grep -q "package-lock.json"; then
echo "📦 package-lock.json o'zgardi — npm install bajarilmoqda..."
npm install
fi
# prepare-commit-msg: branch nomidagi issue raqamini xabarga qo'shish
#!/bin/sh
BRANCH=$(git symbolic-ref --short HEAD)
ISSUE=$(echo "$BRANCH" | grep -oE '[0-9]+' | head -1)
if [ -n "$ISSUE" ] && ! grep -q "#$ISSUE" "$1"; then
printf '\n\nRefs #%s\n' "$ISSUE" >> "$1"
fi
feature/87-qidiruv branch ida → xabar oxiriga Refs #87 (25-dars).
Hook ni chetlab o'tish
git commit --no-verify -m "..." # pre-commit va commit-msg ishlamaydi
git push --no-verify
[!WARNING] Lokal hook lar — qulaylik, xavfsizlik emas. Har kim
--no-verifyqila oladi yoki hook larni umuman o'rnatmaydi. Shuning uchun haqiqiy tekshiruvlar — CI da (38-dars) va branch protection da (23-dars). Hook — xatolarni erta va tez ushlash uchun; CI — ularnimainga o'tkazmaslik uchun. Ikkalasi ham kerak.
Hook larni tez saqlang
Sekin hook (masalan, har commit da 2 daqiqalik barcha testlar) — dasturchilarni --no-verify ga majbur qiladi. Qoida:
pre-commit— bir necha soniya: faqat staged fayllar, lint, formatlashpre-push— bir daqiqagacha: tez testlar- To'liq test to'plami — CI da
Server tomonidagi hook lar
pre-receive, update, post-receive — serverda (push qabul qiluvchi repozitoriyda) ishlaydi. Ularni chetlab o'tib bo'lmaydi. O'z Git serveringizda (49-dars) — masalan, post-receive bilan push dan keyin avtomatik deploy. GitHub da ularning o'rnini Actions va branch protection / rulesets egallaydi.
Nima uchun shunday?
Nima uchun tekshiruvlarni CI ga qo'shimcha ravishda lokal hook larda ham bajarish kerak — takrorlanish emasmi?
Takrorlanish — lekin turli vaqtda va turli narxda. Hook xatoni commit paytida ushlaydi: 2 soniya, kontekst hali boshingizda, tuzatish — darhol. CI esa uni push dan bir necha daqiqa keyin ushlaydi: siz allaqachon boshqa ishga o'tgansiz, PR qizil, reviewer kutyapti, yana bir "fix lint" commit kerak. Xatoni qanchalik erta ushlasangiz — u shunchalik arzon. Bu "shift left" tamoyili: tekshiruvlarni jarayonning boshiga — dasturchiga eng yaqin joyga — ko'chirish. CI esa xavfsizlik to'ri bo'lib qoladi: hook o'tkazib yuborgan narsa main ga baribir o'tmaydi.
Xulosa
Eslab qoling:
- Hook — Git hodisasi oldidan/keyin avtomatik skript;
.git/hooks/ pre-commit,commit-msg,pre-push— eng muhimlari; 0 dan farqli chiqish — harakat bekor.git/hookscommit qilinmaydi →core.hooksPath .githooksyoki Husky- Husky + lint-staged — faqat staged fayllarni lint va formatlash
- Husky + commitlint — Conventional Commits tekshiruvi
--no-verify— chetlab o'tish; shuning uchun haqiqiy nazorat — CI da- Hook lar tez bo'lsin: pre-commit — soniyalar
Keyingi dars
48-dars: git archive — loyihani arxivlash