IlmHamroh
JavaScript Full-stack/32-qism. Professional Git va jamoada ishlash10/19-dars23 daqiqa
Mundarija (39)

Yaxshi PR tayyorlash: hajm, sarlavha, PR shabloni va self-review

Qisqacha: Yaxshi PR — reviewer uni tez va to'liq tushunadigan PR. Uch narsa hal qiladi. Hajm — kichik bo'lsin, taxminan 200–400 qatordan kam: katta PR yuzaki ko'rib chiqiladi. Sarlavha — Conventional Commits shaklida, chunki squash'dan keyin u main dagi commit xabariga aylanadi. Tavsif — PR shabloni bo'yicha: nima o'zgardi, nega, qanday tekshirildi, nimaga diqqat qilish kerak, xavf va qaytarish yo'li. Reviewer'ni chaqirishdan oldin o'z diff'ingizni o'zingiz ko'rib chiqasiz (self-review). Kanon sinov reposidagi eng katta PR +457/−54 qator edi — bitta PR'da 7 ta tuzatish; shu darsda uning narxini ko'ramiz.

Bu darsda

  • PR hajmini o'lchaysiz va katta ishni bir nechta PR'ga bo'lasiz.
  • Squash'dan keyin tarixda qoladigan sarlavha yozasiz.
  • vazifalar-api uchun PR shablonini yaratasiz va uning har bo'limini tushuntirasiz.
  • git diff --stat, --check va main..HEAD bilan self-review qilasiz.
  • Draft PR va stacked PR'larni qachon ishlatishni, squash'dan keyingi rebase --onto ni bilasiz.

Oldin bilishingiz kerak: Pull Request: yaratish, muhokama, merge, Issues, Projects va shablonlar, Interaktiv rebase, Jamoa workflow'lari, Jamoadagi yangi loyihaga kirish.

1. Nega bu kerak?

Reviewer o'rniga o'zingizni qo'ying. Ertalab sizga ikki PR keldi. Birinchisi — 40 qator, sarlavhasi fix(bron): vaqtsiz bron rad etiladi, tavsifda "nega" va "qanday tekshirdim". Siz uni 10 daqiqada o'qib, bitta aniq savol berasiz. Ikkinchisi — 19 fayl, 500 qator, sarlavhasi "tuzatishlar", tavsif bo'sh. Uni qachon ochasiz? Ehtimol, tushdan keyin. Va ehtimol, yuzaki ko'rib, "LGTM" ("menga yaxshi ko'rinadi") deysiz.

Katta PR'lar sekin merge bo'ladi va yomonroq tekshiriladi. Google'ning ochiq review qo'llanmasida ham asosiy maslahat shu: o'zgarishlarni kichik qiling — ular tezroq va sinchiklab ko'rib chiqiladi, qaytarish osonroq. Qo'llanmadagi mo'ljal: ~100 qator odatda maqbul, ~1 000 — odatda juda katta (google.github.io/eng-practices, 2026-11).

Pull Request darsida PR ochishni o'rgangansiz. Endi — PR'ni reviewer uchun tayyorlash. Hayotiy o'xshatish: pochta posilkasi. Ichida nima borligi yozilgan, sinadigan narsa alohida o'ralgan, katta yuk bir nechta qutiga bo'lingan bo'lsa — qabul qiluvchi tez tekshiradi.

2. PR hajmi

2.1 Kanon o'lchovi

Kurs sinov reposidagi PR'lar hajmi (qo'shilgan + o'chirilgan qatorlar, GitHub API'dan gh pr list bilan olindi):

Kanon sinov reposidagi PR'lar hajmi
  • #9 31 nuqsonlari511 qator
  • #17 shablonlar, ADR230 qator
  • #15 README159 qator
  • #14 CONTRIBUTING102 qator
  • #13 arxitektura101 qator
  • #12 CODEOWNERS34 qator
  • #20 sayt README8 qator

Manba: Kurs sinov reposi (github.com/Sarvarbek0704/ilmhamroh-git-sinov), gh pr list --json additions,deletions, 2026-11-04

Birinchi ustun boshqalardan ancha baland. PR #9 — 19 fayl, +457/−54. Uning tavsifida yettita raqamlangan band bor: circuit breaker, deadline, DEFAULT bo'lim, embedding prefiksi, oqim kvotasi, audit, MCP annotatsiyasi.

2.2 Biz shunday xato qildik

PR #9 da yettita mustaqil tuzatish bitta PR'ga tushdi. Oqibatlari:

  • Review'da diqqat taqsimlandi. Kanon review'idagi to'rtta qator izohi breaker, deadline, token taxmini va migratsiya qulfiga tushdi. Qolgan uch tuzatish (embedding prefiksi, audit, MCP) birorta ham izoh olmadi. Ular xatosiz bo'lishi mumkin — lekin katta PR'da reviewer diqqati aynan shunday bo'linadi.
  • Tarix yo'qoldi. Squash'dan keyin main da yettita tuzatish bitta commit: 22a1226. Agar audit tuzatishi xato bo'lib chiqsa, uni alohida git revert qilib bo'lmaydi — breaker ham qaytadi.
  • Bisect qo'pollashdi. Bisect bu commitni "aybdor" deb topsa, yetti tuzatishdan qaysi biri ekanini baribir qo'lda qidirasiz.

To'g'ri yo'l — kamida uchta PR: breaker va deadline (bir-biriga bog'liq, AI chidamliligi); DEFAULT bo'lim (migratsiya — alohida ehtiyot bilan ko'riladi); qolgan mayda tuzatishlar. Kanonni o'zgartirmadik — xato misol sifatida qoladi.

2.3 Hajmni o'lchash

Hajmni PR ochishdan oldin terminalda ko'rasiz:

bash
git diff --shortstat main...HEAD

main...HEAD (uchta nuqta) — branch main dan ajralgan nuqtadan beri sizning o'zgarishlaringiz. Biz shu buyruq chiqishini baholaydigan kichik funksiya yozdik. Chegaralar — kanon CONTRIBUTING.md dan: ≈ 200–400 qator.

js
function prHajmi(stat) {
  const qosh = Number(stat.match(/(\d+) insertion/)?.[1] ?? 0);
  const ochir = Number(stat.match(/(\d+) deletion/)?.[1] ?? 0);
  const jami = qosh + ochir;
  if (jami <= 200) return `${jami} qator — kichik`;
  if (jami <= 400) return `${jami} qator — o'rta`;
  return `${jami} qator — katta, bo'ling`;
}

console.log(prHajmi(" 4 files changed, 102 insertions(+)"));
console.log(prHajmi(
  " 4 files changed, 89 insertions(+), 70 deletions(-)"));
console.log(prHajmi(
  " 19 files changed, 457 insertions(+), 54 deletions(-)"));
console.log(prHajmi(" 1 file changed, 1 deletion(-)"));

Konsolda:

text
102 qator — kichik
159 qator — kichik
511 qator — katta, bo'ling
1 qator — kichik

Kirishlar — kanon PR #14, #15 va #9 ning haqiqiy raqamlari, --shortstat ko'rinishida. match va ?.[1] — RegExp asoslari darsidan: guruh topilmasa null, ?. xato bermaydi, ?? 0 — nol. Bitta qator ham — normal PR: imlo tuzatishi.

Raqam — qoida emas, ishora: 600 qatorlik package-lock.json review'ni og'irlashtirmaydi, 80 qatorlik xavfsizlik o'zgarishi esa sinchkov ko'riladi.

2.4 Qanday bo'lish

Katta ishni ikki xil bo'lish mumkin:

  • Qatlam bo'yicha: 1) migratsiya va ombor, 2) xizmat va testlar, 3) controller va hujjat. Har PR o'zi ishlaydi: migratsiya qo'shildi, lekin hali hech kim ishlatmaydi. Kanon CONTRIBUTING.md da aynan shu misol.
  • Mavzu bo'yicha: bir-biriga bog'liq bo'lmagan o'zgarishlar — alohida PR. PR #9 shunday bo'linishi kerak edi.

Kanonda yaxshi misol ham bor. README va hujjatlar ishi ikkiga bo'lindi: PR #14 — CONTRIBUTING, SECURITY va PR shabloni (+102); PR #15 — README qayta tuzildi va eski bo'limlar docs/qanday/ ga ko'chirildi (+89/−70). Sarlavhalarda (1/2) va (2/2) — reviewer ikkinchisi borligini biladi. PR #15 tavsifida "Review uchun" bo'limi: "Faqat ko'chirilgan bloklar: docs/qanday/*.md — eski README'dan aynan". Reviewer 48 qatorni so'zma-so'z o'qimaydi — faqat aynan ko'chirilganini tekshiradi.

Yana bir qoida: ko'chirish va o'zgartirishni aralashtirmang. Faylni boshqa papkaga ko'chirib, ichini ham tahrirlasangiz, diff'da hammasi "yangi" ko'rinadi. Avval ko'chirish (alohida commit yoki PR), keyin tahrir.

Tekshirib ko'ring: Siz vazifalar jadvaliga yangi ustun qo'shdingiz: migratsiya, Prisma sxemasi, servis, controller, testlar va OpenAPI surati — jami 620 qator. Qanday bo'lasiz?

Javob

Qatlam bo'yicha, har biri o'zi ishlaydigan qilib. 1-PR: migratsiya va sxema — ustun qo'shiladi, hech kim ishlatmaydi (Zero-downtime: expand-contract darsidagi "expand" qadami). 2-PR: servis va uning testlari. 3-PR: controller, OpenAPI surati va hujjat. Har biri 150–250 qator, har birini alohida qaytarish mumkin. Migratsiya alohida bo'lgani yaxshi: u eng xavfli qism va eng sinchkov review'ni talab qiladi.

3. Sarlavha

GitHub flow'da merge — squash (Jamoa workflow'lari). Squash commitining xabari — PR sarlavhasi va oxirida PR raqami. Kanon main tarixidan:

text
0ae90b7 docs: README qayta tuzildi, qo'llanmalar docs/qanday ga (2/2) (#15)
8fff1c5 docs: CONTRIBUTING, SECURITY va PR shabloni (1/2) (#14)
29d20db docs: arxitektura xaritasi va birinchi vazifa yo'riqnomasi (#13)

Demak sarlavha — PR yopilgandan keyin ham yashaydigan yagona matn. Conventional Commits shaklida bo'lsa, CHANGELOG vositalari uni o'qiydi.

  • Tuzatishlar — nimani? qayerda?
  • Review izohlarini tuzatdim — PR ichidagi commit uchun mos, PR uchun emas.
  • feat: README, CONTRIBUTING, breaker va audit — bitta sarlavhada to'rt mavzu = to'rtta PR.
  • fix(bron): vaqtsiz bron rad etiladi — tur, qamrov, natija.
  • docs: CONTRIBUTING, SECURITY va PR shabloni (1/2) — seriyaning qismi ekani ko'rinadi.

Sarlavhaga "va" qo'shilsa — to'xtab o'ylang: balki bu ikki PR?

4. Tavsif: PR shabloni

4.1 Kanon shabloni

Issues va shablonlar darsida «Bahor» sayti uchun oddiy shablon yozgansiz. vazifalar-api — backend, unda xavf boshqacha: migratsiya, muhit o'zgaruvchisi, API shartnomasi. Kanon shabloni .github/pull_request_template.md (aynan; uzun izoh qatorlari telefon uchun bo'lindi):

markdown
## Nima o'zgardi

<!-- 1–3 gap: nima qilindi. Sarlavha — conventional commit
shaklida: `fix(ai): …`, `feat: …`, `docs: …` -->

## Nega

<!-- Muammo yoki issue: `Closes #12` (merge bo'lganda issue
avtomatik yopiladi). Muqobil yo'llar bo'lsa — nega aynan shu. -->

## Qanday tekshirildi

- [ ] `npm run check` yashil (tip, lint, test, build)
- [ ] yangi/o'zgargan xulq uchun test bor (xato tuzatilgan
  bo'lsa — avval yiqiladigan regressiya testi)
- [ ] qo'lda: <!-- qaysi so'rov, qaysi natija
  (curl chiqishi, skrinshot) -->

## Review uchun

<!-- Qayerga diqqat qilish kerak, nima ataylab qilinmagan,
qaysi fayllar faqat ko'chirilgan. Katta PR bo'lsa — nega
bo'linmadi. -->

## Xavf va qaytarish

- [ ] migratsiya yo'q / bor (orqaga qaytarish yo'li: …)
- [ ] yangi muhit o'zgaruvchisi yo'q / bor
  (`.env.example` yangilandi)
- [ ] API shartnomasi o'zgarmadi / o'zgardi
  (`docs/openapi-snapshot.json`, mijozlarga ta'siri: …)

<!-- … --> — HTML izoh: PR sahifasida ko'rinmaydi, faqat yozayotganda maslahat beradi. Muallif uni o'z matni bilan almashtiradi.

4.2 Har bo'lim nega bor

Bo'lim Kim uchun Qaysi savolga javob
Nima o'zgardi reviewer "nimani kutib o'qiyman?"
Nega reviewer, kelajakdagi o'quvchi "bu muammo haqiqiymi, yechim to'g'rimi?"
Qanday tekshirildi reviewer "nimani qayta tekshirmasam bo'ladi?"
Review uchun reviewer "qayerga diqqat qilay?"
Xavf va qaytarish deploy qiluvchi "nima buzilishi mumkin, qanday ortga qaytaramiz?"

"Nega" — eng muhimi. Kod nima qilishini ko'rsatadi, lekin nega degan savolga javob bermaydi. Bir yildan keyin kimdir Kod arxeologiyasi usuli bilan qatorga yetib keladi, commitdan PR'ga o'tadi va sababni shu yerdan o'qiydi.

"Xavf va qaytarish" — backend'ga xos. Migratsiya bor PR'ni qaytarish oddiy git revert dan murakkab: baza allaqachon o'zgargan. Shuning uchun qaytarish yo'li oldindan yoziladi.

4.3 Yaxshi tavsif namunasi

Kanon PR #9 — katta, lekin tavsifi namunali. Undan ikki bo'lim (aynan):

markdown
## Nega

Breaker nuqsonini kiritgan commit `git bisect run` bilan topildi:
7 nomzoddan 3 qadamda — chidamlilik qo'shilgan commit (31-qism #29).
Qolganlari — 31-qism review'ida topilgan ochiq xatolar.

## Xavf va qaytarish

- [x] migratsiya bor: faqat funksiya almashtiriladi
  (`CREATE OR REPLACE`), qaytarish — 301 dagi eski ta'rif
- [x] yangi muhit o'zgaruvchisi: `AI_DEADLINE_MS` (ixtiyoriy,
  `.env.example` da)
- [x] API shartnomasi o'zgarmadi (OpenAPI surati testi o'tdi)

"Nega" da dalil bor: xato qanday topilgani. "Xavf" da har band aniq: migratsiya qanday qaytariladi, yangi o'zgaruvchi majburiy emas. Deploy qiluvchi kodni o'qimasdan qarorni shu yerdan oladi.

4.4 Biz shunday xato qildik: shablon bor, lekin ishlatilmadi

Shablon PR #14 bilan main ga tushdi. Keyingi to'rtta PR (#15, #17, #18, #19) tavsiflarini GitHub API'dan tekshirdik — hech birida "Xavf va qaytarish" bo'limi yo'q, faqat #15 da "Review uchun" bor.

Sabab — asbob. Kanon PR'larni gh pr create --body-file pr.md bilan ochdi: tavsif tayyor fayldan olindi, shablon esa umuman ochilmadi. Brauzerda "New pull request" bosilganda GitHub tavsif maydonini shablon bilan to'ldiradi (docs.github.com, sinalmagan, 2026-11). gh da esa shablonni o'zingiz berasiz: gh pr create --help ga ko'ra, -T, --template file — "boshlang'ich tavsif matni uchun shablon fayli".

Bu PR'larda faqat hujjat o'zgargan, xavf amalda nol. Lekin odat buzildi. Saboq: shablon faqat eslatadi, majburlamaydi. Majburlash kerak bo'lsa — CI'da tavsifni tekshiruvchi qadam (2-mashqdagi funksiya kabi) yoki review'da reviewer talabi.

4.5 Skrinshot va "qo'lda" bandi

UI o'zgarsa — tavsifga "oldin" va "keyin" skrinshotlari. Reviewer branch'ni yuklab, ishga tushirmasdan natijani ko'radi. Backend'da skrinshot o'rnini so'rov va javob egallaydi: curl buyrug'i va uning chiqishi, kodi bilan. Shablondagi "qo'lda:" bandi aynan shu uchun.

5. Self-review: reviewer'dan oldin o'zingiz

5.1 Nima uchun

Self-review — PR'ni boshqalarga ko'rsatishdan oldin o'z diff'ingizni reviewer ko'zi bilan o'qish. Unutilgan console.log, keraksiz fayl, yarim qolgan izoh — bularni o'zingiz topsangiz, reviewer vaqti muhim savollarga qoladi.

5.2 To'rt buyruq

Biz docs/hissa-qoshish branch'ida PR shabloni va CONTRIBUTING.md boshini qo'shib, tekshirdik:

bash
git log --oneline main..HEAD
git diff --stat main...HEAD
git diff --check main...HEAD; echo "exit $?"
text
f8ed0cc docs: CONTRIBUTING va PR shabloni (1/2)
 .github/pull_request_template.md | 23 +++++++++++++++++++++++
 CONTRIBUTING.md                  |  3 +++
 2 files changed, 26 insertions(+)
CONTRIBUTING.md:3: trailing whitespace.
+Ish oqimi: GitHub flow. 
exit 2
  1. git log --oneline main..HEAD — PR'ga qaysi commitlar kiradi. Begona commit ko'rinsa — branch noto'g'ri joydan ochilgan.
  2. git diff --stat main...HEAD — qaysi fayllar va qancha. Kutilmagan fayl (.env, dist/, rasm) — darhol ko'rinadi.
  3. git diff --check — bo'shliq xatolari. Bizda topdi: 3-qator oxirida ortiqcha bo'sh joy ("trailing whitespace"). Chiqish kodi 2 — skriptda ham ishlatsa bo'ladi. Tuzatgandan keyin — 0.
  4. git diff main...HEAD — to'liq diff. Uni boshidan oxirigacha o'qing, ayniqsa o'zingiz yozmagan joylarni: muharrir avtomatik o'zgartirgan import tartibi, formatlash.

Tarixni tartibga keltirish kerak bo'lsa ("tuzatdim", "yana tuzatdim") — Interaktiv rebase darsidagi --fixup va --autosquash. Squash merge'da bu main ga ta'sir qilmaydi, lekin reviewer PR ichidagi commitlarni o'qiydi.

5.3 Self-review ro'yxati

  • Sarlavha Conventional Commits shaklida, bitta mavzu.
  • Tavsifdagi hamma bo'lim to'ldirilgan, Closes #… bor.
  • npm run check yashil — push'dan oldin, CI'dan emas.
  • Diff'da keraksiz fayl, debug kodi, sir (kalit, parol) yo'q.
  • Yangi xulq uchun test bor; tuzatish uchun — avval yiqilgan test.
  • PR ichida o'z kodingizga qatorlik izoh: "bu yerda nega bunday" — reviewer savolidan oldin.

6. Draft PR

Pull Request darsidan bilasiz: draft — "hali tayyor emas" belgisi, uni merge qilib bo'lmaydi. Lekin qachon ishlatish kerak?

  • Yo'nalish so'rash. Ish yarmida "shu yo'l to'g'rimi?" deb so'ramoqchisiz. Draft ochib, savolni tavsifga yozasiz. Kanon ARXITEKTURA.md dagi birinchi vazifa tartibi ham shuni aytadi: "Savol tug'ilsa — PR'ni draft qilib oching va so'rang."
  • CI'ni ko'rish. Lokal sinab bo'lmagan narsa (boshqa OS, boshqa Node versiyasi) — draft PR'da CI ishlaydi.
  • Katta ishni ko'rinadigan qilish. Jamoa sizning ishingizni erta ko'radi va takrorlamaydi.

Terminalda: gh pr create --draft, tayyor bo'lgach — gh pr ready. Kanon PR'lari draft bo'lmadi: savol beradigan ikkinchi odam yo'q edi.

Draft — ruxsatnoma emas: ikki hafta draft'da yotgan PR — uzoq yashovchi branch'ning o'zi.

7. Stacked PR'lar

7.1 Muammo

Ikkinchi PR birinchisiga bog'liq. PR #15 (README) PR #14 dagi CONTRIBUTING.md ga havola qiladi. Birinchisi review'da kutyapti. Ikkinchisini kutib o'tirasizmi?

Stacked PR (qavatma-qavat PR'lar) — ikkinchi branch'ni birinchisining ustidan ochish. Kanonda #14 va #15 stack emas edi: #15 faqat #14 merge bo'lgach ochildi. Shuning uchun stack'ni biz lokal repoda sinadik.

gitGraph
  commit id: "boshlang'ich"
  branch docs/hissa-qoshish
  commit id: "(1/2) CONTRIBUTING"
  branch docs/readme
  commit id: "(2/2) README"

Diagrammada docs/readme main dan emas, docs/hissa-qoshish dan o'sgan.

7.2 Base — eng muhim tanlov

Ikkinchi PR'ni ochganda GitHub so'raydi: qaysi branch'ga? main ni tanlasangiz, reviewer ikki PR'ning hammasini ko'radi:

bash
git diff --stat main...docs/readme
git diff --stat docs/hissa-qoshish...docs/readme
text
 .github/pull_request_template.md | 23 +++++++++++++++++++++++
 CONTRIBUTING.md                  |  3 +++
 README.md                        |  2 ++
 3 files changed, 28 insertions(+)
 README.md | 2 ++
 1 file changed, 2 insertions(+)

Birinchi — base main: uch fayl, birinchi PR ham ichida. Ikkinchi — base docs/hissa-qoshish: faqat README. Stack'da ikkinchi PR'ning base'i — birinchi PR'ning branch'i (gh pr create --base docs/hissa-qoshish).

7.3 Pastki PR o'zgarsa

Review'da birinchi PR'ga tuzatish so'raldi. Uni docs/hissa-qoshish ga qo'shasiz, keyin yuqori branch'ni yangilaysiz:

bash
git switch docs/readme
git rebase docs/hissa-qoshish

Bu — oddiy rebase. Uch-to'rt qavatli stack uchun Git'da git rebase --update-refs bor: yuqori branch'ni rebase qilganda oradagi branch'larni ham suradi (Git hujjati, sinalmagan, 2026-11).

7.4 Pastki PR squash bilan merge bo'lsa — tuzoq

Eng nozik joy shu. Birinchi PR squash bilan main ga tushdi: main da yangi commit paydo bo'ldi, mazmuni pastki branch'ning hamma commitlari. Yuqori branch esa hali eski commitlar ustida. Oddiy git rebase main qilamiz:

text
CONFLICT (add/add): Merge conflict in CONTRIBUTING.md
error: could not apply b50d5b5... docs: CONTRIBUTING va PR shabloni (1/2)
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".

Chiqish qisqartirildi. Git pastki PR'ning eski commitlarini main ustiga qayta qo'ymoqchi bo'ldi. Lekin ularning mazmuni main da allaqachon bor — boshqa SHA bilan, squash shaklida. Natija — o'z kodingiz bilan konflikt.

To'g'ri yo'l — --onto: "faqat pastki branch'dan keyingi commitlarni ko'chir":

bash
git rebase --abort
git rebase --onto main docs/hissa-qoshish docs/readme
git log --oneline --graph main docs/readme
text
* eb1daf6 docs: README qayta tuzildi (2/2)
* eee8a37 docs: CONTRIBUTING va PR shabloni (1/2) (#14)
* a8427cb feat: boshlang'ich

git rebase --onto <yangi-asos> <eski-asos> <branch> — <eski-asos> dan keyingi commitlarni <yangi-asos> ustiga ko'chiradi. Bizda faqat bitta README commiti ko'chdi, konfliktsiz. Endi ikkinchi PR'ning base'ini GitHub'da main ga almashtirasiz — farq yana faqat README.

Tekshirib ko'ring: Nega squash'dan keyin oddiy git rebase main konflikt berdi, lekin merge commit bilan qo'shilganda bunday bo'lmasdi?

Javob

Merge commit pastki branch'ning o'sha commitlarini (o'sha SHA bilan) main tarixiga qo'shadi. Rebase ularni "allaqachon bor" deb taniydi va o'tkazib yuboradi. Squash esa yangi commit yaratadi — SHA boshqa. Git eski commitlarni tanimaydi va ularni yana qo'ymoqchi bo'ladi. Shuning uchun squash ishlatiladigan repoda stack'ning yuqori qavati doim --onto bilan ko'chiriladi. Pastki PR merge bo'lib, branch'i o'chirilsa, GitHub yuqori PR'ning base'ini o'zi main ga almashtiradi (hujjatga ko'ra, 2026-11; sinalmagan). Commitlarni ko'chirish esa baribir sizda.

Stack — kuchli, lekin qimmat usul. Ikki qavatdan ortiq stack'ni qo'lda yuritish qiyin; katta jamoalar buning uchun maxsus vositalardan foydalanadi (sinalmagan). Boshlang'ich qoida: avval PR'ni kichik qiling va tez merge qildiring — shunda stack kamdan-kam kerak bo'ladi.

8. PR hayoti: hammasi birga

flowchart LR
  A["branch + commit"] --> B["self-review:<br/>log, stat, check"]
  B --> C{"tayyormi?"}
  C -->|yo'q| D["draft PR:<br/>savol"]
  D --> B
  C -->|ha| E["PR: sarlavha<br/>+ shablon"]
  E --> F["review"]
  F -->|izohlar| B
  F -->|tasdiq| G["squash merge"]

Diagrammaga qarang: self-review bir marta emas — har review aylanishidan keyin yana. Review — keyingi darsning mavzusi: Code review berish va olish.

9. Loyiha qadami: PR shabloni va CONTRIBUTING.md

Endi vazifalar-api ga ikki fayl qo'shasiz. Branch — docs/hissa-qoshish. Uni Jamoa workflow'lari darsida ochgan bo'lsangiz, u eski main dan o'sgan: keyingi CODEOWNERS va arxitektura commitlari unda yo'q. Shuning uchun -c emas, -C (katta harf):

bash
git switch main
git pull
git switch -C docs/hissa-qoshish
mkdir -p .github

-c bor branch'da xato beradi — biz sinadik: fatal: a branch named 'docs/hissa-qoshish' already exists. -C esa branch bo'lmasa yaratadi, bor bo'lsa uni hozirgi main ga qayta qo'yadi (Switched to and reset branch). Bu branch'da hali commit yo'q, shuning uchun hech narsa yo'qolmaydi.

  1. .github/pull_request_template.md — «Kanon shabloni» bo'limidagi matn. GitHub uni repo ildizidagi .github/ dan oladi. Kanon sinov reposi monorepo edi (07-qism portfoliosi va vazifalar-api yonma-yon), shuning uchun shablon ikki joyga qo'yildi: ildizdagi .github/ (GitHub o'qiydi) va vazifalar-api/.github/ (loyiha alohida repo bo'lganda). Sizning repo'ngizda vazifalar-api — ildiz, bitta fayl yetadi.
  2. CONTRIBUTING.md — hozircha boshi va "Ish oqimi" bo'limi. Jamoa workflow'lari darsida va'da bergan edik: kelishuv hujjatda ham tursin. Kanon faylidan (aynan; telefon uchun qatorlar bo'lindi):
markdown
# Hissa qo'shish

Rahmat! Bu fayl — loyihaga o'zgarish kiritishning kelishilgan yo'li.
Qisqa bo'lishga harakat qildik: o'qish 5 daqiqa.

## Ish oqimi (GitHub flow)

1. **Issue** — katta ish oldidan issue oching yoki mavjudini oling
   ("men olaman" deb yozing). Kichik tuzatish (imlo, bitta qator) —
   issue'siz ham bo'ladi.
2. **Branch** — `main` dan: `git switch -c <tur>/<qisqa-nom>`.
   Tur — commit turi bilan bir xil: `feat/`, `fix/`, `docs/`,
   `test/`, `refactor/`, `chore/`.
   Misol: `fix/ai-deadline`, `docs/arxitektura`.
3. **Commit'lar** —
   [Conventional Commits](https://www.conventionalcommits.org/):
   `<tur>(<qamrov>): <nima>`. Qamrov — papka/modul: `ai`, `auth`,
   `db`, `api`. Xabar — buyruq maylida, kichik harf, nuqtasiz,
   ≤ 72 belgi. Nega — tanada. Buzuvchi o'zgarish — `feat!:` yoki
   tanada `BREAKING CHANGE:`.
   CHANGELOG va versiya shu xabarlardan hosil qilinadi — shuning
   uchun tur muhim (`fix` → patch, `feat` → minor, `!` → major).
4. **Tekshiruv** — `npm run check` (tip, lint, test, build).
   Push'dan oldin. Qizil bo'lsa — PR ochmang (draft bundan mustasno).
5. **PR** — shablonni to'ldiring. Kichik bo'lsin: ≈ 200–400 qator
   o'zgarish; kattasi — bir nechta ketma-ket PR'ga bo'linadi
   (masalan: 1) migratsiya va ombor, 2) xizmat va testlar,
   3) controller va hujjat).
6. **Review** — kamida bitta tasdiq. Izohlarga javob bering yoki
   tuzating; "hal qilindi"ni izoh egasi bosadi. Merge — **squash**
   (bitta PR = `main` da bitta commit).
7. Merge'dan keyin branch o'chiriladi.

`main` himoyalangan: to'g'ridan-to'g'ri push, force push va o'chirish
taqiqlangan — faqat PR orqali.

Bu dars mavzusi — 5-band: hajm, shablon, bo'lish usuli. 6-band — review, uning madaniyati keyingi darsda shu faylga qo'shiladi. Kanon faylida yana "Kod uslubi" va "Xato haqida xabar berish" bo'limlari bor — ular va SECURITY.md Texnik yozish: README va loyiha hujjatlari darsida.

Diqqat: Hali commit qilmang. PR shabloni, CONTRIBUTING.md va SECURITY.md — bitta mavzu ("hissa qo'shish hujjatlari"), ular Texnik yozish darsida birga commit qilinadi: docs: CONTRIBUTING, SECURITY va PR shabloni (1/2). Kanonda bu PR #14 — 4 fayl, +102 qator (monorepo'da shablon ikki joyda edi; sizda 3 fayl bo'ladi).

Hozir faqat self-review qiling: git status (ikki yangi fayl), keyin git add .github CONTRIBUTING.md va git diff --cached --check — chiqish kodi 0 bo'lsin. Nega --cached? Biz sinadik: yangi fayl uchun oddiy git diff --check jim o'tdi (exit 0) — u faqat ishchi papka bilan staging farqiga qaraydi. --cached esa staging'dagi bo'shliq xatosini topdi (exit 2).

10. Ko'p uchraydigan xatolar

10.1 "Yo'l-yo'lakay" o'zgarishlar

Xato tuzatib, yonidagi faylni ham "chiroyli" qildingiz. Diff ikki barobar oshdi. Yo'l-yo'lakay tuzatish — alohida PR.

10.2 Shablonni o'chirib tashlash

Shablon bo'limlarini "kerak emas" deb o'chirish — reviewer'ga signal: muallif o'ylamagan. Bo'lim haqiqatan tegishli bo'lmasa — o'chirmang, "yo'q" deb yozing: "migratsiya yo'q". Bu ham ma'lumot.

10.3 Noto'g'ri base

Stacked PR'ni main ga ochsangiz, reviewer ikki PR'ni birga ko'radi. Yoki teskarisi: oddiy PR adashib boshqa branch'ga ochilgan — merge bo'ladi, lekin main ga yetmaydi va Closes #… issue'ni yopmaydi (Pull Request darsidagi shart).

10.4 Squash'dan keyin rebase main konflikti

«Stacked PR'lar» bo'limidagi holat: o'z kodingiz bilan konflikt. Davosi — git rebase --abort, keyin git rebase --onto main <eski-pastki-branch>.

10.5 CI qizil, lekin "review qilib turing"

Test tuzalgach kod o'zgaradi va review qaytadan boshlanadi. Qizil bo'lsa — draft, yashil bo'lgach — "Ready for review".

11. Mashqlar

Mashqlar kurs/mashqlar/32/10-pr/ da. 2-mashq yechimi Node 24.21.0 da, 3-mashq yechimi Git 2.54.0 da tekshirilgan (biz ishga tushirdik).

1-mashq (oson): bo'shliqlarni to'ldiring

  • GitHub PR shablonini oladigan fayl — .github/
  • Branch main dan ajralgandan beri o'zgargan fayllar ro'yxati — git diff --stat main HEAD
  • Qator oxiridagi ortiqcha bo'shliqni topadigan bayroq — git diff --
  • Hali tayyor bo'lmagan PR'ni ochish — gh pr create --
  • Squash'dan keyin yuqori branch'ni ko'chirish — git rebase -- main docs/hissa-qoshish docs/readme
Yechim
  • pull_request_template.md — ildizda yoki docs/ da ham bo'lishi mumkin.
  • ... — uchta nuqta: ajralish nuqtasidan beri faqat sizning o'zgarishlaringiz.
  • check — xato bo'lsa chiqish kodi 2.
  • draft — tayyor bo'lgach gh pr ready.
  • onto — faqat eski pastki branch'dan keyingi commitlar ko'chadi.

2-mashq (o'rta): tavsif tekshiruvchisi

tavsifniTekshir(tavsif) funksiyasini yozing. U PR tavsifini (Markdown matn) oladi va kanon shablonining to'rtta majburiy bo'limini tekshiradi: "Nima o'zgardi", "Nega", "Qanday tekshirildi", "Xavf va qaytarish". Qaytaradi: yoq — umuman yo'q bo'limlar, bosh — sarlavha bor, lekin ichida faqat HTML izoh yoki bo'sh joy. Ishora: ## bilan boshlangan qator — yangi bo'lim (startsWith, Matn ichida qidirish); bo'limlar matnini Map da yig'ing (Map); izohlarni olib tashlash — replace(/<!--[\s\S]*?-->/g, "") (RegExp asoslari).

Yechim
js
const MAJBURIY = [
  "Nima o'zgardi", "Nega", "Qanday tekshirildi", "Xavf va qaytarish",
];

function tavsifniTekshir(tavsif) {
  const bolimlar = new Map();
  let joriy = null;
  for (const qator of tavsif.split("\n")) {
    if (qator.startsWith("## ")) {
      joriy = qator.slice(3).trim();
      bolimlar.set(joriy, "");
    } else if (joriy) {
      bolimlar.set(joriy, bolimlar.get(joriy) + qator + "\n");
    }
  }
  const yoq = [];
  const bosh = [];
  for (const nom of MAJBURIY) {
    if (!bolimlar.has(nom)) {
      yoq.push(nom);
      continue;
    }
    const matn = bolimlar.get(nom).replace(/<!--[\s\S]*?-->/g, "");
    if (matn.trim() === "") bosh.push(nom);
  }
  return { yoq, bosh };
}

const pr15 = [
  "## Nima o'zgardi", "README qayta tuzildi.",
  "## Nega", "README 86 qator edi.",
  "## Qanday tekshirildi", "- [x] `npm run check` yashil",
  "## Review uchun", "Faqat ko'chirilgan bloklar.",
].join("\n");
const toldirilmagan = [
  "## Nima o'zgardi", "<!-- 1–3 gap: nima qilindi.",
  "Sarlavha — conventional commit shaklida -->",
  "## Nega", "Closes #12",
  "## Qanday tekshirildi", "<!-- qaysi so'rov, qaysi natija -->",
  "## Xavf va qaytarish", "- [x] migratsiya yo'q",
].join("\n");
console.log(tavsifniTekshir(pr15));
console.log(tavsifniTekshir(toldirilmagan));

Konsolda:

text
{ yoq: [ 'Xavf va qaytarish' ], bosh: [] }
{ yoq: [], bosh: [ "Nima o'zgardi", 'Qanday tekshirildi' ] }

Birinchi kirish — kanon PR #15 tavsifining qisqartmasi: «Biz shunday xato qildik» bo'limidagi topilma avtomatik chiqdi. Ikkinchisi — shablon ochilgan, lekin to'ldirilmagan: izohlar turibdi, matn yo'q. [\s\S]*? — har qanday belgi, qatorlar orasida ham, "dangasa" (eng qisqa moslik), shuning uchun ikki qatorli izoh ham olib tashlandi. Bunday funksiyani CI qadami qilsa bo'ladi — GitHub Actions chuqur darsida ko'ramiz.

3-mashq (qiyin): stack'ni qutqarish

kurs/mashqlar/32/10-pr/stack-yarat.sh «Stacked PR'lar» bo'limidagi holatni yaratadi: pastki PR (docs/hissa-qoshish, ikki commit) squash bilan main ga tushgan, docs/readme esa eski commitlar ustida. Vazifa:

  1. docs/readme PR'iga hozir qaysi commitlar kiradi — ko'rsating.
  2. git rebase main ni sinang, natija kodini chiqaring va bekor qiling.
  3. --onto bilan to'g'ri ko'chiring va PR'da endi faqat bitta commit va bitta fayl qolganini ko'rsating.
  4. Pastki branch'ni o'chiring va qolgan branch'larni chiqaring.

Ishora: SHA'lar darsdagidek chiqishi uchun rebase'dan oldin committer'ni qotiring (GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL, GIT_COMMITTER_DATE). Squash qilingan branch git branch -d bilan o'chmaydi ("not fully merged") — -D kerak (Pull Request darsidagi tozalash).

Yechim
bash
bash stack-yarat.sh stack > /dev/null && cd stack
export GIT_COMMITTER_NAME="Aziz Karimov"
export GIT_COMMITTER_EMAIL="aziz@example.com"
export GIT_COMMITTER_DATE="2026-11-04T10:30:00+05:00"

git log --oneline main..docs/readme
git rebase -q main > /dev/null 2>&1; echo "rebase main: exit $?"
git rebase --abort
git rebase -q --onto main docs/hissa-qoshish docs/readme
git log --oneline main..docs/readme
git diff --stat main...docs/readme
git branch -q -D docs/hissa-qoshish
git branch --format='%(refname:short)'

Biz ishga tushirdik:

text
044cec5 docs: README qayta tuzildi (2/2)
3c068f3 docs: branch nomlash qoidasi
e9527f5 docs: CONTRIBUTING va PR shabloni (1/2)
rebase main: exit 1
e5bf4d5 docs: README qayta tuzildi (2/2)
 README.md | 2 ++
 1 file changed, 2 insertions(+)
docs/readme
main

Oldin PR'da uchta commit bor edi — ikkitasi allaqachon main da squash shaklida. Oddiy rebase konflikt bilan to'xtadi (exit 1). --onto dan keyin — bitta commit, bitta fayl: reviewer faqat README'ni ko'radi. main..docs/readme (ikki nuqta) — main da yo'q commitlar; main...docs/readme (uch nuqta) diff'da — ajralish nuqtasidan beri o'zgarishlar.

12. Real ishda

  • Qayerda uchraydi: deyarli har jamoada PR shabloni va "kichik PR" kelishuvi bor. Ba'zi kompaniyalar PR hajmi va review kutish vaqtini jamoa metrikasi sifatida kuzatadi.
  • Ochiq loyihalarda: begona loyihaga birinchi PR'ingiz (Open source darsida) — aynan shu darsdagi odatlar bilan qabul qilinadi yoki yopiladi.
  • Intervyu savollari: "Yaxshi PR qanday bo'ladi?", "Katta o'zgarishni qanday bo'lasiz?", "PR tavsifiga nima yozasiz?", "Stacked PR nima va squash bilan qanday ishlaydi?"

Xulosa

  • Kichik PR (≈ 200–400 qator) tezroq va sinchiklab ko'riladi; mustaqil o'zgarishlar — alohida PR. Kanon PR #9 (7 tuzatish, 511 qator) — teskari misol.
  • Sarlavha — Conventional Commits shaklida: squash'dan keyin u main dagi commit xabari.
  • PR shabloni: nima, nega, qanday tekshirildi, review uchun, xavf va qaytarish. gh pr create --body-file shablonni chetlab o'tadi — kanonda shunday bo'ldi.
  • Self-review: git log main..HEAD, git diff --stat main...HEAD, git diff --check, to'liq diff'ni o'qish.
  • Draft — erta savol uchun; stacked PR'da base — pastki branch, squash'dan keyin git rebase --onto.

Keyingi dars: Code review berish va olish — reviewer nimaga qaraydi, Conventional Comments (muammo:, taklif:, savol:), o'z PR'ingizni tasdiqlay olmaslik va muhokamalar yopilmaguncha merge yo'q.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Yaxshi PR tayyorlash: hajm, sarlavha, PR shabloni va self-review — IlmHamroh