IlmHamroh
JavaScript Full-stack/32-qism. Professional Git va jamoada ishlash3/19-dars20 daqiqa
Mundarija (32)

Jamoa workflow'lari: GitHub flow, trunk-based va git-flow

Qisqacha: Workflow — jamoaning branch bilan ishlash kelishuvi: qayerdan branch ochiladi, u qancha yashaydi, qayerga qo'shiladi va reliz qanday chiqadi. GitHub flow — main doim tayyor, har ish qisqa branch va PR orqali. Trunk-based — branch'lar soatlab yashaydi, tayyor bo'lmagan ish feature flag ortida main ga tushadi. Git-flow — main + develop va release/hotfix branch'lari, versiyalangan relizlar uchun. Kanon tajribasida bir xil 3 ta o'zgarish trunk-based'da 5 commit va 0 merge commit, git-flow'da 11 commit va 6 merge commit qoldirdi. Ko'p veb jamoalar uchun boshlang'ich tanlov — GitHub flow.

Bu darsda

  • Uch workflow'ning qoidalarini va ular qoldiradigan tarixni solishtirasiz.
  • GitHub flow'ni kurs sinov reposidagi haqiqiy PR'lar misolida ko'rasiz: ruleset rad etishlari bilan.
  • Trunk-based'da --ff-only va rebase bilan chiziqli tarix qurasiz.
  • Git-flow'da release va hotfix branch'lari qanday ishlashini va narxini tushuntirasiz.
  • Branch nomlash kelishuvini yozasiz va tekshirasiz.

Oldin bilishingiz kerak: Pull Request: yaratish, muhokama, merge, Branch himoyasi va rulesets, Rebase: tarixni chiziqlash, Feature flag'lar backend'da.

1. Nega bu kerak?

Tasavvur qiling: vazifalar-api ustida endi besh kishi ishlaydi. Aziz main ga to'g'ridan push qiladi. Nodira bir haftalik branch ochgan, u main dan 40 commit orqada. Sardor develop degan branch yaratib, hammani unga merge qilishga undayapti. Reliz kuni hech kim bilmaydi: qaysi branch'dan chiqaramiz?

Muammo Git'da emas — kelishuvda. Git hamma usulga ruxsat beradi. Jamoaga esa umumiy qoidalar kerak:

  • Yangi ish qayerdan boshlanadi?
  • Branch qancha yashaydi?
  • U qayerga va qanday qo'shiladi (merge, squash, rebase)?
  • Reliz qayerdan va qachon chiqadi? Shoshilinch tuzatish (hotfix) qanday o'tadi?

Bu savollarga javoblar to'plami workflow (ish oqimi) deyiladi.

Hayotiy o'xshatish: chorraha. Svetofor bo'lmasa ham mashinalar o'tadi, lekin sekin va avariya bilan. Kichik ko'chada "o'ngdagi o'tadi" qoidasi yetadi, katta chorrahada — svetofor va burilish yo'laklari kerak. Workflow ham shunday: jamoa va reliz ritmiga mos bo'lsin. Ortiqcha murakkab qoidalar kichik jamoani sekinlashtiradi.

2. GitHub flow

2.1 Qoidalar

GitHub flow — eng sodda va eng keng tarqalgan workflow. GitHub hujjatidagi oltita qadam (docs.github.com, "GitHub flow", 2026-11-04 da o'qildi):

  1. main dan yangi branch oching, nomi nima qilinayotganini aytsin.
  2. Branch'da o'zgartiring, commit qiling va uni GitHub'ga yuboring.
  3. Pull Request oching: tavsif yozing va hamkasblardan fikr so'rang.
  4. Review (kod ko'rib chiqish) izohlariga yangi commitlar bilan javob bering.
  5. PR tasdiqlangach — main ga merge.
  6. Branch'ni o'chiring.

Bu qadamlar ortida bitta tamoyil turadi: main doim ishlaydigan holatda, uni istalgan payt deploy qilsa bo'ladi. Hujjatda bu so'zma-so'z yozilmagan, lekin oqim shunga qurilgan: o'zgarish main ga faqat review'dan keyin tushadi.

gitGraph
  commit id: "import"
  branch fix/31-nuqsonlari
  commit id: "breaker"
  checkout main
  commit id: "#9 squash"
  branch chore/reliz-4.0.1
  commit id: "4.0.1"
  checkout main
  commit id: "#11 squash"

Diagrammaga qarang. Har branch qisqa: bitta ish, bitta PR. Merge'dan keyin main da bitta commit paydo bo'ladi (squash — PR'ning hamma commitlari bittaga siqiladi). Branch'lar main ga qaytmaydi — ular o'chiriladi.

2.2 Kanon tajribasi: sinov reposidagi 10 ta PR

Kurs sinov reposida (github.com/Sarvarbek0704/ilmhamroh-git-sinov) 32-qism davomidagi har o'zgarish GitHub flow bilan o'tdi: 10 ta PR, hammasi squash bilan. Avval main himoyalandi — ruleset (Branch himoyasi va rulesets darsi). Kanon uni gh api orqali JSON fayldan yaratdi (bitta uzun qator telefon uchun bo'lindi, mazmun aynan):

json
{
  "name": "main himoyasi",
  "target": "branch",
  "enforcement": "active",
  "conditions": {
    "ref_name": { "include": ["~DEFAULT_BRANCH"], "exclude": [] }
  },
  "bypass_actors": [],
  "rules": [
    { "type": "deletion" },
    { "type": "non_fast_forward" },
    { "type": "required_linear_history" },
    { "type": "pull_request", "parameters": {
        "required_approving_review_count": 0,
        "dismiss_stale_reviews_on_push": true,
        "require_code_owner_review": false,
        "require_last_push_approval": false,
        "required_review_thread_resolution": true,
        "allowed_merge_methods": ["squash"] } }
  ]
}

Qoidalarni o'qiymiz:

  • deletion, non_fast_forward — main ni o'chirish va force push taqiqlangan.
  • required_linear_history — main da merge commit bo'lmaydi, tarix chiziqli.
  • pull_request — faqat PR orqali; required_review_thread_resolution — hamma muhokamalar yopilmaguncha merge yo'q; allowed_merge_methods — faqat squash.
  • required_approving_review_count: 0 — tasdiq soni nol. Bu bitta odamli sinov reposining cheklovi: GitHub o'z PR'ingizni tasdiqlashga ruxsat bermaydi (pastda isbot). Jamoada kamida 1 tasdiq va CODEOWNERS review qo'yiladi (Git va monorepo darsida).

Ruleset ishlayaptimi? Kanon main ga to'g'ridan push qildi. Chiqishda repo manzili login/vazifalar-api ga almashtirildi:

text
remote: error: GH013: Repository rule violations found for refs/heads/main.        
remote: Review all repository rules at https://github.com/login/vazifalar-api/rules?ref=refs%2Fheads%2Fmain        
remote: 
remote: - Changes must be made through a pull request.        
remote: 
To https://github.com/login/vazifalar-api.git
 ! [remote rejected] main -> main (push declined due to repository rule violations)
error: failed to push some refs to 'https://github.com/login/vazifalar-api.git'

"O'zgarishlar pull request orqali kiritilishi kerak." GitHub flow'ning birinchi qoidasi endi faqat kelishuv emas — server uni majburlaydi.

2.3 Bitta PR'ning hayoti

Birinchi PR — Bisect darsidagi 31-qism nuqsonlari. Kanon buyruqlari (repo nomi almashtirildi):

bash
git switch -c fix/31-nuqsonlari
# ... commit (Bisect darsidagi tuzatish)
git push -u origin fix/31-nuqsonlari
T="fix(ai): har modelga alohida circuit breaker"
T+=" va umumiy deadline; 31-qism nuqsonlari"
gh pr create --base main --head fix/31-nuqsonlari \
  --title "$T" --body-file pr.md

Keyin review keldi: kodning aniq qatorlariga to'rtta izoh (savol:, taklif:, maqtov:) — ularni Code review darsida batafsil o'qiymiz. Endi ikki haqiqiy rad etish.

O'z PR'ini tasdiqlash:

bash
gh pr review 9 --approve -b "LGTM"
text
failed to create review: GraphQL: Review Can not approve your own pull request (addPullRequestReview)

"O'z pull request'ingizni tasdiqlay olmaysiz." Shuning uchun sinov reposida tasdiq soni 0 — aks holda bitta odam hech narsani merge qila olmasdi.

Ochiq muhokama bilan merge:

bash
gh pr merge 9 --squash
text
X Pull request login/vazifalar-api#9 is not mergeable: the base branch policy prohibits the merge.
To have the pull request merged after all the requirements have been met, add the `--auto` flag.
To use administrator privileges to immediately merge the pull request, add the `--admin` flag.

"PR merge qilinmaydi: asosiy branch siyosati taqiqlaydi." Ikki savol hali javobsiz edi. Muallif javob yozdi, taklifni alohida issue'ga chiqardi, keyin to'rtta muhokama yopildi va merge o'tdi:

text
{"commit":"22a1226","mergedAt":"2026-11-03T19:21:42Z","state":"MERGED"}

E'tibor bering: chiqishdagi ikkinchi maslahat — --admin bilan qoidani chetlab o'tish. Bu imkoniyat bor, lekin "muhokama yopilmaguncha merge yo'q" qoidasi aynan shunday shoshilishga qarshi yozilgan.

2.4 Natija: chiziqli main

10 ta PR'dan keyin main tarixi (gh api dan, oxirgi 12 commit):

text
7f8f2d4 docs(sayt): README — sinov repo izohi va reja yangilandi (#20)
a9550ae docs: vazifalar-api uchun MIT LICENSE va hissa litsenziyasi (#19)
ca2a135 docs: takrorlanuvchi vazifalar — talab hujjati (#18)
f12ef28 docs: issue shablonlari, ADR va muloqot qoidalari (#17)
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)
8ec1500 chore(repo): CODEOWNERS va CI path filtri; actions @v7 (#12)
6e0d3e9 chore(release): 4.0.1 — CHANGELOG.md; fix(mcp): server versiyasi package.json dan (#11)
22a1226 fix(ai): har modelga alohida circuit breaker va umumiy deadline; 31-qism nuqsonlari (#9)
9c395ca feat(vazifalar-api): 31-qism yakuni (v4.0.0) — kurs loyihasi sinov repoga
c70c84c LICENSE: MIT litsenziyasini qo'sh

Har qator — bitta PR, oxirida raqami. Merge commit yo'q, har commit Conventional Commits formatida. Bunday tarix bilan Bisect ham, CHANGELOG ham oson ishlaydi. PR ichidagi oraliq commitlar ("tuzatdim", "review izohi") main ga tushmadi — squash ularni siqdi.

Narxi ham bor. Squash'dan keyin PR ichidagi tafsilotli tarix main da yo'q — u faqat GitHub'dagi PR sahifasida qoladi. Katta PR bitta katta commitga aylanadi: bisect uni bo'la olmaydi. Shuning uchun GitHub flow kichik PR'larni talab qiladi (Yaxshi PR tayyorlash darsi).

Diqqat: GitHub ba'zan xato qaytaradi, lekin amalni bajaradi. Kanon jarayonida yangi branch'ning birinchi push'i ikki marta remote rejected … (Internal Server Error) oldi — qayta push o'tdi. gh pr merge bir marta 502 Bad Gateway qaytardi, lekin keyingi qatorda #12 MERGED turdi. Qoida: xato kelsa, darhol qaytarmang — avval holatni tekshiring (gh pr view, git ls-remote).

2.5 Kimga mos

GitHub flow — bitta versiya ishlaydigan joyda mos: veb ilova, API, SaaS. Foydalanuvchida eski versiya qolmaydi, hamma doim oxirgisini oladi. vazifalar-api — aynan shunday. Talabi: avtomatik tekshiruvlar (CI) va tez review. CI bo'lmasa, "main doim ishlaydi" degan va'da faqat umid bo'lib qoladi.

Kanonda sinalmaganlar: required status checks (PR'ni CI yashil bo'lmaguncha to'sish) va merge queue — sinov reposida Actions o'chiq edi. Ular haqida GitHub Actions chuqur darsida.

Tekshirib ko'ring: Ruleset'da required_linear_history yoqilgan, allowed_merge_methods da esa merge ham bor. Kimdir PR'ni oddiy "Create a merge commit" bilan qo'shmoqchi. Nima bo'ladi?

Javob

Merge commit chiziqli tarixni buzadi, shuning uchun required_linear_history uni rad etadi. Ikki qoida bir-biriga zid — sozlamada faqat squash va rebase qoldirilishi kerak. Kanon ruleset'ida aynan shunday: faqat squash. Bu xabarni Branch himoyasi darsida ko'rgansiz: "Merge commits are not allowed on this repository."

3. Trunk-based development

3.1 Qoidalar

Trunk (tana) — asosiy branch, odatda main. Trunk-based development — hamma o'z ishini tez-tez, kamida kuniga bir marta trunk'ga qo'shadi. Sayt buni shunday yozadi: "all team members commit to trunk at least once every 24 hours". Ya'ni "jamoaning har a'zosi kamida 24 soatda bir marta trunk'ga commit qiladi" (trunkbaseddevelopment.com, 2026-11-04 da o'qildi). Asosiy qoidalar:

  • branch'lar qisqa umrli — soatlar, ko'pi bilan bir-ikki kun (sayt aniq muddat yozmaydi, bu son 24 soatlik qoidadan kelib chiqadi); kichik jamoada to'g'ridan trunk'ga commit ham bo'ladi;
  • tayyor bo'lmagan xususiyat ham trunk'ga tushadi — feature flag ortida, o'chiq holda (Feature flag'lar backend'da);
  • reliz — trunk'dan, istalgan payt; kerak bo'lsa reliz branch'i ham trunk'dan ochiladi, lekin unga kod yozilmaydi.

Asosiy g'oya: birlashtirishni kechiktirmaslik. Branch qancha uzoq yashasa, main bilan farqi shuncha katta, konflikt shuncha og'ir. Trunk-based'da konflikt kichik — chunki farq bir kunlik.

3.2 Kanon tajribasi

Kanon bir xil uchta o'zgarishni (2 ta feat + 1 ta fix) ikki workflow'da yozdi. Trunk-based'da qisqa branch'lar --ff-only bilan qo'shildi va darhol o'chirildi:

bash
git switch -c qidiruv-filtr
# ... commit: feat: qidiruvga filtr (bayroq ortida, o'chiq)
git switch main
git merge --ff-only qidiruv-filtr
git branch -d qidiruv-filtr

--ff-only — faqat fast-forward (Merge darsi): main oldinga suriladi, merge commit yaratilmaydi. Agar main orada o'zgargan bo'lsa, buyruq rad etadi — avval rebase kerak. Natijaviy tarix (kanon chiqishi):

text
* bf02850 (HEAD -> main, tag: v1.1.0) feat: filtr bayrog'i 10% foydalanuvchiga
* bbdecf4 feat: filtr UI (bayroq ortida)
* b74c2fa fix: sana formati
* fda4f88 feat: qidiruvga filtr (bayroq ortida, o'chiq)
* 8b48306 feat: boshlang'ich
branch'lar: 1 (faqat main)

Bitta chiziq. Commit xabarlariga qarang: filtr ikki bosqichda, "bayroq ortida" qo'shildi — foydalanuvchi uni ko'rmaydi. Faqat oxirgi commit bayroqni 10% foydalanuvchiga ochadi. Kod tayyor bo'lmasdan trunk'da yashaydi, lekin hech kimni buzmaydi. Bu — 31-qismdagi foizli rollout.

3.3 Narxi

  • CI shart. Hamma kuniga bir necha marta main ga qo'shsa, har qo'shishda testlar yurishi kerak. Aks holda main tez-tez buziladi.
  • Feature flag intizomi. Flag'lar to'planib qoladi. Eskirgan flag — o'lik kod. Ularni o'chirish rejasi bo'lsin.
  • Review tezligi. PR bir kun kutib qolsa, "qisqa umr" buziladi. Ba'zi jamoalar juft dasturlash (pair programming) bilan review'ni almashtiradi.

4. Git-flow

4.1 Qoidalar

Git-flow — 2010 yil 5 yanvarda Vincent Driessen taklif qilgan model (nvie.com, 2026-11-04 da o'qildi). Unda ikki doimiy branch bor:

  • main — faqat relizlar, har merge'ga tag;
  • develop — keyingi reliz uchun yig'ilayotgan ish.

Va uch xil vaqtinchalik branch:

  • feature/* — develop dan ochiladi, develop ga qaytadi;
  • release/* — reliz tayyorlash (versiya raqami, oxirgi tuzatishlar): develop dan ochiladi, ham main ga, ham develop ga merge qilinadi;
  • hotfix/* — prodakshndagi shoshilinch xato: main dan ochiladi, yana ikki joyga merge.

Hamma merge'lar --no-ff bilan — har branch tarixda alohida "qavariq" bo'lib ko'rinsin.

gitGraph
  commit id: "v1.0.0"
  branch develop
  branch feature/qidiruv
  commit id: "qidiruv"
  checkout develop
  merge feature/qidiruv
  branch release/1.1.0
  commit id: "versiya 1.1.0"
  checkout main
  merge release/1.1.0 tag: "v1.1.0"
  checkout develop
  merge release/1.1.0

Diagramma ataylab soddalashtirildi: bitta feature va reliz. Hotfix ham xuddi reliz kabi ikki joyga qo'shiladi.

4.2 Kanon tajribasi

Xuddi o'sha uchta o'zgarish git-flow bilan: ikkita feature/*, bitta release/1.1.0, bitta hotfix/1.1.1. Grafda Merge branch qatorlarini va chapdagi parallel chiziqlarni sanang. Kanon chiqishi:

text
*   4d8f501 (HEAD -> develop) Merge branch 'hotfix/1.1.1' into develop
|\  
* \   8b56a77 Merge branch 'release/1.1.0' into develop
|\ \  
| | | *   d4b3536 (tag: v1.1.1, main) Merge branch 'hotfix/1.1.1'
| | | |\  
| | | |/  
| | |/|   
| | * | 6ed377e fix: eksportda bo'sh qator
| | |/  
| | *   649b864 (tag: v1.1.0) Merge branch 'release/1.1.0'
| | |\  
| | |/  
| |/|   
| * | 16badfb chore: versiya 1.1.0
|/ /  
* |   885ab15 Merge branch 'feature/eksport' into develop
|\ \  
| * | 743ae2b feat: CSV eksport
|/ /  
* |   4bb4f00 Merge branch 'feature/qidiruv' into develop
|\ \  
| |/  
|/|   
| * 3c8b819 feat: qidiruv
|/  
* 8a368eb (tag: v1.0.0) feat: boshlang'ich
merge commit'lar: 6; doimiy branch'lar: develop main 

Grafni pastdan yuqoriga o'qing. Ikki feature develop ga qo'shildi. Reliz branch'ida versiya raqami o'zgardi va u main ga (v1.1.0 tagi) va develop ga qo'shildi. Keyin prodakshnda xato topildi: hotfix main dan ochildi, tuzatildi va yana ikki joyga qo'shildi (v1.1.1).

4.3 Narxi va qachon mos

Bir xil ish uchun 11 commit va 6 merge commit — trunk-based'da 5 va 0:

Bir xil 3 o'zgarish: commitlar soni
  • trunk-based: commit5 ta
  • trunk-based: merge commit0 ta
  • git-flow: commit11 ta
  • git-flow: merge commit6 ta

Manba: IlmHamroh kanon tajribasi, 2026-11-04: Git 2.54.0, bir xil 2 feat + 1 fix; git-flow — 2 feature, 1 release, 1 hotfix branch

Qo'shimcha commitlar o'z-o'zidan yomon emas. Muammo boshqa joyda:

  • Ikki joyga merge. Hotfix main ga qo'shilib, develop ga unutilsa — keyingi relizda xato qaytadi. Bu git-flow'ning eng ko'p uchraydigan nosozligi.
  • Uzun branch'lar. develop va reliz branch'lari kunlab, haftalab yashaydi — konfliktlar kattalashadi.
  • Bisect va o'qish qiyin. Grafni ko'rdingiz: oddiy tarixni tushunish uchun chiziqlarni kuzatish kerak.

Git-flow qachon o'zini oqlaydi? Bir vaqtda bir nechta versiya qo'llab-quvvatlanganda: mobil ilova (do'kondagi 3.2 va tayyorlanayotgan 3.3), desktop dastur, kutubxonaning eski major versiyasi. Modelning muallifi 2020 yil 5 martda maqolasiga "Note of reflection" (mulohaza) qo'shgan. Unda doimiy yetkaziladigan veb ilovalar uchun GitHub flow kabi soddaroq usulni tavsiya qiladi. Git-flow esa aniq versiyalanadigan yoki bir nechta versiyasi qo'llab-quvvatlanadigan dasturga mos, deydi. Yakuniy gapi: "panaceas don't exist" — "hamma dardga davo yo'q, o'z sharoitingizga qarang".

Tekshirib ko'ring: Git-flow'da hotfix faqat main ga merge qilindi, develop ga — yo'q. Keyingi reliz develop dan chiqadi. Nima bo'ladi va buni qanday tekshirish mumkin?

Javob

Keyingi reliz develop dan tayyorlanadi, unda tuzatish yo'q — xato prodakshnga qaytadi. Tekshirish: git branch --contains <hotfix-commit> — commit qaysi branch'larda borligini ko'rsatadi. Ro'yxatda develop bo'lmasa — hotfix unutilgan. Reliz oldidan bunday tekshiruvni avtomatlashtirish mumkin.

5. Taqqoslash

GitHub flow Trunk-based Git-flow
Doimiy branch'lar main main main, develop
Branch umri kunlar soatlar haftalar
Tayyor bo'lmagan ish branch'da kutadi flag ortida main da develop da
Reliz har merge yoki tag istalgan payt release/* orqali

Uchala workflow'ni aralashtirish ham mumkin. Ko'p jamoalar GitHub flow'ni trunk-based ruhida ishlatadi: PR'lar kichik, kuniga bir necha marta merge, tayyor bo'lmagan ish flag ortida. Ba'zi jamoalar faqat release/* ni qo'shadi — qo'llab-quvvatlanadigan eski versiya uchun.

6. Branch nomlash

Workflow'ning kichik, lekin muhim qismi — nomlar. Branch nima darsidan boshlab kursda prefikslar ishlatiladi: feature/, fix/, chore/. Kanon sinov reposidagi branch'lar ham shunday edi: fix/31-nuqsonlari, chore/reliz-4.0.1, chore/codeowners, docs/readme, docs/litsenziya.

Yaxshi nom uchta narsani aytadi: tur (prefiks), mazmun (qisqa, kichik harf, chiziqcha bilan) va ixtiyoriy issue raqami (fix/42-sana-formati). Kelishuvni kod bilan tekshirish mumkin:

js
const NAQSH =
  /^(feature|fix|chore|docs|release|hotfix)\/[a-z0-9][a-z0-9.-]*$/;

function branchNomiTogrimi(nom) {
  return NAQSH.test(nom);
}

const nomlar = [
  "fix/31-nuqsonlari", "chore/reliz-4.0.1", "docs/readme",
  "Aziz-branch", "feature/Yangi Filtr", "hotfix/4.0.2",
];
for (const nom of nomlar) {
  console.log(nom.padEnd(20), branchNomiTogrimi(nom));
}

Konsolda:

text
fix/31-nuqsonlari    true
chore/reliz-4.0.1    true
docs/readme          true
Aziz-branch          false
feature/Yangi Filtr  false
hotfix/4.0.2         true

Aziz-branch — prefiks yo'q va nom ishni emas, odamni aytadi. feature/Yangi Filtr — bosh harf va bo'sh joy: terminalda qo'shtirnoqsiz yozib bo'lmaydi. Shunday tekshiruvni ruleset ham qila oladi: ruleset yaratishda "Restrictions" bo'limidagi "Restrict branch names" qoidasi (docs.github.com, "Creating rulesets for a repository", sinalmagan, 2026-11).

7. Loyiha qadami: vazifalar-api uchun GitHub flow

Bu dars — tajriba darsi: loyiha kodi o'zgarmaydi va commit yo'q. Lekin workflow tanlanadi. vazifalar-api uchun kanon GitHub flow ni tanladi:

  • API — bitta versiya ishlaydigan veb xizmat; eski versiyalar qo'llab-quvvatlanmaydi.
  • Repo'da Branch himoyasi darsidagi ruleset bor: faqat PR, chiziqli tarix, squash.
  • Reliz — tag va CHANGELOG (CHANGELOG va reliz avtomatikasi).
  • Tayyor bo'lmagan xususiyat — 31-qismda qurilgan flag'lar ortida.

O'z repo'ngizda keyingi ishni shu tartibda boshlang:

bash
git switch main
git pull
git switch -c docs/hissa-qoshish

Bu branch hozircha mashq uchun: Yaxshi PR tayyorlash darsida uni main ning o'sha paytdagi holatidan qayta boshlaymiz. Nomi esa bejiz emas: 32-qismning jamoa darslarida (CONTRIBUTING.md, PR shabloni) aynan shunday branch'lar ochiladi. Workflow qoidalari esa keyinroq Yaxshi PR tayyorlash darsida CONTRIBUTING.md ga yoziladi — kelishuv faqat boshda emas, hujjatda ham tursin.

8. Ko'p uchraydigan xatolar

8.1 GH013 — to'g'ridan push

Ruleset main ni himoya qiladi: "Changes must be made through a pull request." Davosi: commitni branch'ga ko'chiring (Branch himoyasi darsidagi retsept) va PR oching. --force yechim emas — u ham taqiqlangan.

8.2 Fast-forward bo'lmadi

Trunk-based'da ikkinchi branch'ni --ff-only bilan qo'shmoqchi bo'lsangiz, main esa orada oldinga ketgan bo'lsa, biz shu chiqishni oldik:

text
hint: Diverging branches can't be fast-forwarded, you need to either:
hint:
hint: 	git merge --no-ff
hint:
hint: or:
hint:
hint: 	git rebase
hint:
hint: Disable this message with "git config set advice.diverging false"
fatal: Not possible to fast-forward, aborting.

"Ajralgan branch'larni fast-forward qilib bo'lmaydi: yo merge commit, yo rebase." Trunk-based'da tanlov — rebase: branch'ni main ustiga ko'chirasiz va yana --ff-only. Buni 3-mashqda qilasiz.

8.3 Uzoq yashovchi branch

Branch bir hafta yashadi, main 40 commit oldinga ketdi, PR'da 15 ta konflikt. Davosi — oldini olish: ishni kichik qismlarga bo'ling, har kuni main ni branch'ga olib turing (git rebase main), tayyor bo'lmaganini flag ortida qo'shing.

8.4 "Can not approve your own pull request"

Bitta odamli repoda tasdiq talabi qo'ysangiz, hech narsani merge qila olmaysiz. Jamoada bu to'g'ri xulq — o'z kodini o'zi tasdiqlamaydi.

8.5 Hotfix bir joyga

Git-flow'da hotfix develop ga qo'shilmadi. Davosi: git branch --contains <commit> bilan tekshirish va har hotfix'ni ikki merge bilan yopish.

9. Mashqlar

Mashqlar kurs/mashqlar/32/03-workflow/ 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

  • Git-flow'da keyingi reliz uchun ish yig'iladigan doimiy branch —
  • Prodakshndagi shoshilinch xato uchun git-flow branch'i prefiksi —
  • Merge commit yaratmay, faqat main ni oldinga suradigan bayroq — git merge --
  • Trunk-based'da tayyor bo'lmagan xususiyat nima ortida yashaydi? —
  • Kanon ruleset'ida ruxsat etilgan yagona merge usuli —
Yechim
  • develop — main esa faqat relizlar.
  • hotfix — main dan ochiladi va ikki joyga qo'shiladi.
  • ff-only — main ajralgan bo'lsa, rad etadi.
  • feature flag — kod main da, lekin foydalanuvchiga o'chiq.
  • squash — PR bitta commitga siqiladi, tarix chiziqli qoladi.

2-mashq (o'rta): eski branch'larni topish

Trunk-based'da branch ko'pi bilan 2 kun yashashi kerak. eskiBranchlar(branchlar, bugun, chegaraKun) funksiyasini yozing. branchlar — { nom, ochilgan } obyektlari (ochilgan — ISO sana satri). Funksiya chegaradan uzoq yashagan branch'larni "nom: N kun" ko'rinishida, eng eskisidan boshlab qaytarsin. main hisobga olinmasin. Ishora: ikki sana farqi millisekundda — new Date(a) - new Date(b); kun — 86_400_000 ms (Date asoslari); butun kun uchun Math.floor.

Yechim
js
const KUN = 86_400_000;

function eskiBranchlar(branchlar, bugun, chegaraKun) {
  return branchlar
    .filter((b) => b.nom !== "main")
    .map((b) => ({
      nom: b.nom,
      kun: Math.floor((new Date(bugun) - new Date(b.ochilgan)) / KUN),
    }))
    .filter((b) => b.kun > chegaraKun)
    .sort((a, b) => b.kun - a.kun)
    .map((b) => `${b.nom}: ${b.kun} kun`);
}

const branchlar = [
  { nom: "main", ochilgan: "2026-09-30T10:00:00+05:00" },
  { nom: "fix/sana", ochilgan: "2026-11-03T15:00:00+05:00" },
  { nom: "feature/eksport", ochilgan: "2026-10-21T09:00:00+05:00" },
  { nom: "feature/filtr", ochilgan: "2026-11-01T09:00:00+05:00" },
];
console.log(eskiBranchlar(branchlar, "2026-11-04T12:00:00+05:00", 2));

Konsolda:

text
[ 'feature/eksport: 14 kun', 'feature/filtr: 3 kun' ]

fix/sana bir kunga ham to'lmagan — normal. feature/filtr uch kunlik — chegaradan o'tdi, uni kichik qismlarga bo'lish yoki flag ortida qo'shish vaqti keldi. feature/eksport ikki hafta yashagan — bunday branch'ning PR'i katta konflikt bilan keladi. Haqiqiy repoda sana git log -1 --format=%cI <branch> dan olinadi.

3-mashq (qiyin): ikki dasturchi, bitta trunk

kurs/mashqlar/32/03-workflow/trunk-yarat.sh repo yaratadi: main da bitta commit, undan ikkita qisqa branch — feature/filtr (Aziz) va fix/sana (Nodira). Vazifa: ikkalasini main ga faqat fast-forward bilan qo'shing, merge commit bo'lmasin, oxirida faqat main qolsin.

  1. bash trunk-yarat.sh trunk va cd trunk.
  2. feature/filtr ni --ff-only bilan qo'shing.
  3. fix/sana ni ham shunday qo'shishga urining — nima bo'ladi?
  4. Muammoni rebase bilan yeching va qayta qo'shing.
  5. Ikkala branch'ni o'chiring, git log --graph va merge commitlar sonini ko'rsating.

Ishora: Rebase darsi — git rebase main branch'ni main ustiga ko'chiradi. SHA'lar darsdagidek chiqishi uchun rebase'dan oldin committer'ni qotiring: export GIT_COMMITTER_NAME="Nodira Rahimova" GIT_COMMITTER_EMAIL="nodira@example.com" GIT_COMMITTER_DATE="2026-11-02T11:00:00+05:00".

Yechim
bash
bash trunk-yarat.sh trunk && cd trunk
export GIT_COMMITTER_NAME="Nodira Rahimova"
export GIT_COMMITTER_EMAIL="nodira@example.com"
export GIT_COMMITTER_DATE="2026-11-02T11:00:00+05:00"

git merge -q --ff-only feature/filtr
git merge --ff-only fix/sana
git switch -q fix/sana
git rebase -q main
git switch -q main
git merge -q --ff-only fix/sana
git branch -q -d feature/filtr fix/sana
git log --graph --format='%h %an: %s'
echo "merge commitlar: $(git rev-list --merges --count HEAD)"
echo "branch'lar: $(git branch --format='%(refname:short)')"

Biz ishga tushirdik (trunk-yarat.sh chiqishi yozilmagan):

text
hint: Diverging branches can't be fast-forwarded, you need to either:
hint:
hint: 	git merge --no-ff
hint:
hint: or:
hint:
hint: 	git rebase
hint:
hint: Disable this message with "git config set advice.diverging false"
fatal: Not possible to fast-forward, aborting.
* ff24e9e Nodira Rahimova: fix: sana formati
* 460a757 Aziz Karimov: feat: qidiruvga filtr (bayroq ortida, o'chiq)
* 3ab7b6b Aziz Karimov: feat: boshlang'ich
merge commitlar: 0
branch'lar: main

Birinchi qo'shish o'tdi — main oldinga surildi. Ikkinchisi rad etildi: fix/sana eski main dan ochilgan, endi ikki tarix ajralgan. Rebase Nodira commitini yangi main ustiga ko'chirdi (yangi SHA, chunki ota-commit o'zgardi) va --ff-only o'tdi. Natija — uchta commit bir chiziqda, merge commit 0. Bu — trunk-based'ning kichik nusxasi. GitHub'da "Rebase and merge" yoki squash tugmasi xuddi shu ishni server tomonida qiladi.

10. Real ishda

  • Qayerda uchraydi: startap va SaaS jamoalarining ko'pi — GitHub flow yoki trunk-based. Git-flow — mobil ilovalar, desktop dasturlar, bir nechta versiyani qo'llab-quvvatlaydigan kutubxonalar.
  • DORA (DevOps Research and Assessment — jamoalar dasturni qanchalik tez va barqaror yetkazishini yillar davomida o'lchaydigan tadqiqot dasturi). Uning sahifasiga ko'ra, 2016–2017 ma'lumotlarida trunk-based amaliyotiga amal qilgan jamoalar yetkazish tezligi va barqarorligida yuqoriroq natija ko'rsatgan. Tavsiyalari aniq: repo'da uchtadan ko'p bo'lmagan faol branch, branch'larni kamida kuniga bir marta trunk'ga qo'shish (dora.dev, 2026-11-04 da o'qildi).
  • Intervyu savollari: "Jamoangizda qanday branching strategiyasi bor va nega?", "Git-flow va trunk-based farqi?", "Hotfix qanday o'tadi?", "Uzoq yashovchi branch'lar muammosini qanday hal qilasiz?"

Xulosa

  • Workflow — branch'lar bo'yicha jamoaviy kelishuv: qayerdan, qancha, qayerga, reliz qanday.
  • GitHub flow: main doim tayyor, har ish — qisqa branch va PR; ruleset uni server darajasida majburlaydi.
  • Trunk-based: branch'lar soatlab yashaydi, tayyor bo'lmagan ish feature flag ortida; CI shart.
  • Git-flow: main + develop, release/hotfix ikki joyga merge; bir nechta versiya qo'llab-quvvatlansa o'zini oqlaydi.
  • Kanon: bir xil 3 o'zgarish — trunk-based 5 commit / 0 merge, git-flow 11 / 6; sinov reposida 10 PR, chiziqli main.
  • Branch nomi: tur/qisqa-mazmun, kichik harf, chiziqcha.

Keyingi dars: Commit imzolash va Verified belgisi — user.email ni istalgan kishi yozishi mumkin; SSH imzo bilan commit muallifi haqiqatan siz ekaningizni isbotlaymiz.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Jamoa workflow'lari: GitHub flow, trunk-based va git-flow — IlmHamroh