Mundarija (36)
- Bu darsda
- 1. Nega bu kerak?
- 2. Muammo: sir tarixda
- 2.1 O'quv repo
- 2.2 Joriy fayllarda — toza
- 2.3 Tarixda — to'rt commit
- 3. Tartib: avval kalit, keyin tarix
- 4. git filter-repo
- 4.1 O'rnatish
- 4.2 Birinchi urinish: ishchi repo'da
- 4.3 To'g'ri yo'l: yangi --mirror klon
- 4.4 Natija: yangi tarix
- 4.5 Nega origin o'chirildi
- 4.6 --sensitive-data-removal rejimi
- 5. Majburiy push va uning oqibatlari
- 5.1 Markazga yuborish
- 5.2 Jasur: to'g'ri yo'l
- 5.3 Nodira: odatdagi git pull
- 5.4 Boshqa yon ta'sirlar
- 6. GitHub tomoni
- 7. Kichikroq qayta yozishlar
- 8. Loyiha qadami: vazifalar-api tarixini tekshirish
- 9. Ko'p uchraydigan xatolar
- 9.1 "does not look like a fresh clone"
- 9.2 'filter-repo' is not a git command
- 9.3 Tozalandi, lekin sir yana paydo bo'ldi
- 9.4 fatal: Need to specify how to reconcile divergent branches
- 9.5 Faqat main tozalandi
- 9.6 Tozaladim, endi kalit xavfsiz
- 10. Mashqlar
- 1-mashq (oson): bo'shliqlarni to'ldiring
- 2-mashq (o'rta): --replace-text ni JavaScript'da
- 3-mashq (qiyin): to'liq tozalash
- 11. Real ishda
- Xulosa
- Manbalar
Tarixni qayta yozish va sirlarni tozalash: git filter-repo, majburiy push va push protection
Qisqacha: Sir bir marta commit qilinsa, keyingi commitda o'chirilsa ham tarixda qoladi —
git log -Suni bir soniyada topadi. Birinchi qadam doim rotatsiya: eski kalitni bekor qilib, yangisini berish. Tarixni tozalash — ikkinchi, ixtiyoriy qadam:git filter-repofaylni (--invert-paths --path .env) yoki matnni (--replace-text) butun tarixdan olib tashlaydi, lekin sirga tegmagan commitlardan keyingi hamma hash'ni o'zgartiradi. Keyin majburiy push va har bir hamkasbning klonini tozalash kerak. Kurs tajribasida bitta eski klondan qilingan oddiygit pullvagit pushtozalangan sirni markaziy repo'ga qaytarib qo'ydi.
Bu darsda
- Sir tarixda qanday "yashashini" o'z repo'ngizda ko'rasiz:
git grepvagit log -Sfarqi. git filter-repobilan faylni va matnni butun tarixdan olib tashlaysiz.- Nega filter-repo "yangi klon" talab qilishini va
originni o'chirishini tushunasiz. - Majburiy push (force push) dan keyin hamkasblar nima qilishi kerakligini ko'rasiz — to'g'ri va noto'g'ri yo'l bilan.
- GitHub tomonidagi himoyani bilasiz: push protection, secret scanning va GitHub Support.
Oldin bilishingiz kerak: Sirlarni boshqarish, Kod arxeologiyasi: blame, log -S, log -L, Interaktiv rebase, Ajralgan tarix: pull --rebase va force-with-lease, Reflog.
1. Nega bu kerak?
Sirlarni boshqarish darsida qoidani yozgan edik: sir sizib chiqsa, avval rotatsiya, keyin (ixtiyoriy) tozalash. O'sha darsda birinchi qismni bajardik. Bugun ikkinchisi — tozalash.
Nega "ixtiyoriy"? Chunki bekor qilingan kalit endi hech narsani ochmaydi. Uni tarixda qoldirish xavfsiz, faqat chiroyli emas. Lekin tozalash shart bo'ladigan holatlar ham bor:
- Almashtirib bo'lmaydigan ma'lumot. Mijozlar ro'yxati, shaxsiy ma'lumot, pasport skani. Uni "rotatsiya" qilib bo'lmaydi.
- Hujjat yoki qonun talabi. Ma'lumot repo'dan butunlay yo'qolishi kerak.
- Katta fayl. 200 MB video tasodifan commitga tushgan. Har klonda u yuklanadi (bu haqda keyingi darsda).
- Ochiq repo. Kalit bekor qilingan bo'lsa ham, uning formati va joylashuvi hujumchiga "bu jamoa sirni qayerda saqlaydi" degan ma'lumot beradi.
Hayotiy o'xshatish: kitobning bitta sahifasiga telefon raqamingizni yozib qo'ydingiz. Kitob 50 nusxada chop etilgan. Siz o'z nusxangizdagi sahifani yirtasiz — lekin qolgan 49 nusxa allaqachon tarqalgan. Eng to'g'ri ish — raqamni almashtirish. Sahifani yirtish esa qo'shimcha chora: yangi chop etiladigan nusxalarda raqam bo'lmaydi.
Git'da ham shunday. Tarixni "qayta chop etish" mumkin, lekin eski nusxalar — hamkasblarning klonlari, fork'lar, CI keshlari — sizning nazoratingizda emas.
2. Muammo: sir tarixda
2.1 O'quv repo
«Bahor» choyxonasining Telegram boti. Repo'ni kurs/mashqlar/32/05-tozalash/sir-repo-yarat.sh skripti yaratadi: bash sir-repo-yarat.sh bot, keyin cd bot. Muallif va sanalar qotirilgan — SHA'lar sizda ham darsdagidek chiqadi. Sir — ataylab yasalgan qiymat: SOXTA-BAHOR-SIRI-0000-faqat-lokal. U hech qaysi xizmatning kalit formatiga o'xshamaydi.
Tarix:
git log --onelineTerminalda:
8d0b325 (HEAD -> main) docs: ish vaqti
b536195 fix: token env'dan o'qiladi
b51df01 feat: konfig moduli
112cb66 fix: .env ni git'dan chiqarish
f4ca674 feat: sozlamalar
09785db feat: bot boshlang'ichIkki xato bor. Birinchisi: f4ca674 da .env fayli commit qilingan, keyin 112cb66 da kuzatuvdan chiqarilgan. Ikkinchisi: b51df01 da kalit to'g'ridan konfig.js ga yozilgan, b536195 da process.env ga almashtirilgan. Ikkala holatda ham "tuzatish" commiti bor.
2.2 Joriy fayllarda — toza
git grep -c "SOXTA-BAHOR-SIRI-0000-faqat-lokal"
echo "exit $?"exit 1git grep faqat joriy holatni qidiradi. Hech narsa topilmadi, chiqish kodi 1. Shu yerda ko'pchilik "tuzatildi" deb to'xtaydi.
2.3 Tarixda — to'rt commit
Kod arxeologiyasi darsidagi git log -S — "shu matn qo'shilgan yoki olib tashlangan commitlar":
git log --all -S"SOXTA-BAHOR-SIRI-0000-faqat-lokal" --oneline
git show HEAD~4:.envTerminalda:
b536195 fix: token env'dan o'qiladi
b51df01 feat: konfig moduli
112cb66 fix: .env ni git'dan chiqarish
f4ca674 feat: sozlamalar
PORT=3000
BOT_TOKEN=SOXTA-BAHOR-SIRI-0000-faqat-lokalTo'rt commit: ikkitasi sirni qo'shgan, ikkitasi olib tashlagan. git show HEAD~4:.env — to'rt commit oldingi .env ning to'liq mazmuni. Repo'ni klonlagan har kishi shu ikki buyruqni yozishi yetarli.
Tekshirib ko'ring: Nega "tuzatish" commitlari (
112cb66,b536195) hamlog -Sro'yxatida bor, axir ular sirni olib tashlagan-ku?
Javob
-S matnning soni o'zgargan commitlarni topadi: qo'shilgan ham, olib tashlangan ham. Olib tashlagan commitning diff'ida sir - qatorida to'liq turibdi. Ya'ni "tuzatish" commiti sirni o'zi ham ko'rsatadi.
3. Tartib: avval kalit, keyin tarix
Tozalashni boshlashdan oldin to'liq rejaga qaraymiz. Bu ketma-ketlik GitHub hujjatidagi "Removing sensitive data from a repository" sahifasiga mos:
flowchart TD
A["Sir sizdi"] --> B["1. Rotatsiya:<br/>eski kalit bekor"]
B --> C{"Tarixni<br/>tozalash shartmi?"}
C -- "yo'q" --> Z["Tugadi:<br/>kalit endi ishlamaydi"]
C -- "ha" --> D["2. Yangi klonda<br/>git filter-repo"]
D --> E["3. Tekshirish:<br/>git log -S bo'sh"]
E --> F["4. Majburiy push<br/>--force --mirror"]
F --> G["5. Hamkasblar:<br/>qayta klon yoki rebase"]
G --> H["6. GitHub Support:<br/>PR havolalari, kesh"]Ikki narsaga e'tibor bering. Birinchi: rotatsiya tozalashdan oldin. Tozalash soatlab, hamkasblarni kutish bilan kunlab davom etadi. Shu vaqt ichida kalit ishlab turmasin. Ikkinchi: tozalash bitta buyruq emas, olti qadamlik jarayon. Eng qiyini 5-qadam — boshqa odamlar.
4. git filter-repo
4.1 O'rnatish
git filter-repo — Git loyihasi tavsiya qiladigan tarixni qayta yozish vositasi. Eski git filter-branch ning hujjatida ham "uning o'rniga filter-repo ishlating" deb yozilgan. U Git bilan birga kelmaydi — Python 3 da yozilgan alohida skript:
pip install git-filter-repo
git filter-repo --versionO'rnatilmagan bo'lsa, Git uni tanimaydi:
git: 'filter-repo' is not a git command. See 'git --help'."filter-repo — Git buyrug'i emas". Git git X ni ko'rsa, PATH'dan git-X dasturini qidiradi. pip aynan shunday nomli faylni o'rnatadi. Kurs tajribasida versiya — 2.47.0 (pip), Git 2.54.0.
4.2 Birinchi urinish: ishchi repo'da
Avval markaziy repo kerak — GitHub o'rnida lokal "bare" repo (Remote darsidagidek). Unga push qilamiz va ikki hamkasb — Nodira va Jasur — klon oladi:
git init -q --bare -b main ../markaz.git
git remote add origin ../markaz.git
git push -q -u origin main
git clone -q ../markaz.git ../nodira
git clone -q ../markaz.git ../jasurEndi o'z ishchi repo'mizda .env ni butun tarixdan olib tashlashga urinamiz:
git filter-repo --invert-paths --path .envBiz ishga tushirdik:
Aborting: Refusing to destructively overwrite repo history since
this does not look like a fresh clone.
(expected at most one entry in the reflog for HEAD)
Note: when cloning local repositories, you need to pass
--no-local to git clone to avoid this issue.
Please operate on a fresh clone instead. If you want to proceed
anyway, use --force."To'xtatildi: bu yangi klonga o'xshamagani uchun tarixni buzib qayta yozishni rad etaman (HEAD reflog'ida ko'pi bilan bitta yozuv kutilgan edi). Iltimos, yangi klonda ishlang." Chiqish kodi 1.
Bu — xato emas, himoya. filter-repo qaytarib bo'lmaydigan ish qiladi. U "foydalanuvchida zaxira bormi?" degan savolga bilvosita javob izlaydi: yangi klon bo'lsa, asl nusxa serverda turibdi. Ishchi repo'da esa push qilinmagan commit, stash, branch bo'lishi mumkin — ular yo'qolsa, qaytarib bo'lmaydi. Reflog'dagi bir nechta yozuv (Reflog darsi) — "bu repo'da ish qilingan" degan belgi.
--force bu tekshiruvni o'chiradi. filter-repo hujjati ochiq yozadi: har doim --force yozishga o'rganib qolish — "juda yomon g'oya". Kurs tajribasida biz --force ni faqat bir martalik sinov repo'sida ishlatdik.
4.3 To'g'ri yo'l: yangi --mirror klon
cd ..
git clone -q --mirror markaz.git tozalash.git
cd tozalash.git--mirror — "ko'zgu" klon: ishchi papkasiz (bare), hamma ref'lar bilan — branch'lar, tag'lar, boshqa ref'lar. Tozalash uchun aynan shu kerak: sir faqat main da emas, boshqa branch yoki tag'da ham bo'lishi mumkin.
Endi ikki vazifa bir buyruqda. Fayl — --invert-paths --path .env: ".env dan boshqa hamma narsani qoldir". Matn — --replace-text <fayl>: har qatorda bitta almashtirish qoidasi.
echo "SOXTA-BAHOR-SIRI-0000-faqat-lokal==>***OLIB-TASHLANDI***" \
> ../almashtir.txt
git filter-repo --invert-paths --path .env \
--replace-text ../almashtir.txtBiz ishga tushirdik (yo'l qisqartirildi):
NOTICE: Removing 'origin' remote; see 'Why is my origin removed?'
in the manual if you want to push back there.
(was …/markaz.git)
Parsed 6 commits
New history written in 0.45 seconds; now repacking/cleaning...
Repacking your repo and cleaning out old unneeded objects
Completely finished after 1.26 seconds.Oltita commit 1.3 soniyada qayta yozildi. Chiqishning birinchi qatoriga keyinroq qaytamiz.
Almashtirish fayli formati (filter-repo hujjatidan):
| Qator | Ma'nosi |
|---|---|
matn |
aniq matn, o'rniga ***REMOVED*** |
matn==>yangi |
aniq matn, o'rniga yangi |
regex:naqsh==>yangi |
muntazam ifoda |
glob:naqsh==>yangi |
* va ? shabloni |
4.4 Natija: yangi tarix
git log --oneline main
git log --all -S"SOXTA-BAHOR-SIRI-0000-faqat-lokal" --oneline
git show main~2:konfig.jsTerminalda:
84aecd1 (HEAD -> main) docs: ish vaqti
0d20272 fix: token env'dan o'qiladi
586fae7 feat: konfig moduli
235b65f fix: .env ni git'dan chiqarish
ae30c80 feat: sozlamalar
09785db feat: bot boshlang'ich
export const token = '***OLIB-TASHLANDI***';log -S bo'sh qaytdi — sir tarixda yo'q. konfig.js ning eski versiyasida sir o'rnida belgi turibdi. Commit xabarlari, mualliflar, sanalar — o'zgarmadi.
Lekin hash'larga qarang. filter-repo eski va yangi hash'lar xaritasini filter-repo/commit-map fayliga yozadi (qisqartirib, tartiblab ko'rsatdik):
old new
09785db09785db
112cb66235b65f
8d0b32584aecd1
b51df01586fae7
b5361950d20272
f4ca674ae30c80Faqat birinchi commit — 09785db — o'zgarmadi. Qolgan beshtasi yangi hash oldi. Nega?
Git ichkaridan darsini eslang: commit hash'i uning butun mazmunidan hisoblanadi — daraxt (fayllar), ota-commit hash'i, muallif, xabar. f4ca674 ning daraxtidan .env olib tashlandi — daraxt o'zgardi, demak hash o'zgardi. Undan keyingi 112cb66 ning daraxti o'zgarmagan bo'lishi mumkin edi, lekin uning ota-commit hash'i o'zgardi — demak uning hash'i ham o'zgaradi. Zanjir oxirigacha shunday ketadi. Birinchi commitda sir yo'q edi va uning otasi yo'q — u tegilmadi.
Qoida: sir tarixning qayerida birinchi marta paydo bo'lsa, undan keyingi hamma commit yangi bo'ladi. Sir uch yil oldin commit qilingan bo'lsa — uch yillik tarix qayta yoziladi. Bu qoida imzosiz commitlar uchun; imzolangan repoda butun tarix yangilanadi («Boshqa yon ta'sirlar» bo'limi).
4.5 Nega origin o'chirildi
Chiqishning birinchi qatori: "'origin' remote olib tashlanmoqda". Tekshiramiz — git remote bo'sh.
filter-repo hujjatida "Why is my origin removed?" bo'limi bor. Sabab: yangi tarixni eski tarix ustiga tasodifan push qilib yubormaslik. Oddiy git push rad etiladi, lekin chalg'igan dasturchi git pull qilib, eski va yangi tarixni birlashtirib yuborishi mumkin — keyingi bo'limda aynan shuni ko'ramiz. Hujjat yangi tarixni yangi repo'ga push qilishni tavsiya qiladi. Eski joyga qaytarish kerak bo'lsa, remote'ni qo'lda qo'shasiz.
4.6 --sensitive-data-removal rejimi
filter-repo 2.47 da sir tozalash uchun maxsus bayroq qo'shildi. GitHub hujjati hozir aynan uni tavsiya qiladi. Xuddi shu repo'ning yangi --mirror klonida:
git filter-repo --sensitive-data-removal --invert-paths \
--path .env --replace-text ../almashtir.txtBiz ishga tushirdik (boshi va oxiri):
You rewrote 5 (of 6) commits.
NOTE: First Changed Commit(s) is/are:
f4ca674c58524823aeac0664aa95ba8045df32bc
NOTE: LFS object orphaning not checked (LFS not in use)
...
NEXT STEPS FOR YOUR SENSITIVE DATA REMOVAL:
...
* Force push the rewritten history to the server:
git push --force --mirror origin
* Contact the server admins for additional steps they need to take; the
First Changed Commit(s) may come in handy here.
* Have other colleagues with a clone either discard their clone and reclone
OR follow the detailed steps in the manual to repeatedly rebase and
purge the sensitive data from their copy. Again, the First Changed
Commit(s) may come in handy.Uch farq:
- "First Changed Commit" — birinchi o'zgargan commit:
f4ca674, sir paydo bo'lgan joy. Server administratoriga va hamkasblarga aynan shu hash kerak: "shu commitdan keyingi hamma narsa yangi". origino'chirilmaydi — bu rejimda maqsad aynan eski joyga qaytarish.git remote—origin.- Keyingi qadamlar ro'yxati — «Tartib: avval kalit, keyin tarix» bo'limidagi diagrammaning o'zi, vositaning tilida.
Sir tozalashda shu rejimni ishlating. Oddiy rejim — tarixni boshqa maqsadda qayta yozish uchun (papkani alohida repo'ga ajratish, katta faylni olib tashlash).
5. Majburiy push va uning oqibatlari
5.1 Markazga yuborish
Oddiy rejimdagi tozalash.git ga qaytamiz va origin ni qo'lda qo'shamiz:
git remote add origin ../markaz.git
git push origin mainTo ../markaz.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to '../markaz.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again."Rad etildi: remote'da sizda yo'q ish bor." Ajralgan tarix darsidagi holat: markazdagi 8d0b325 yangi tarixda yo'q. Git git pull ni maslahat beradi — va aynan shu maslahat bu yerda halokatli: pull eski tarixni (sir bilan) qaytarib olib keladi. Bizga almashtirish kerak:
git push --force origin mainTo ../markaz.git
+ 8d0b325...84aecd1 main -> main (forced update)+ va "forced update" — eski 8d0b325 o'rniga yangi 84aecd1. Haqiqiy GitHub repo'da bunga ruleset to'sqinlik qiladi (Branch himoyasi darsidagi "Block force pushes"). Tozalash paytida uni vaqtincha o'chirish kerak bo'ladi — GitHub hujjati ham buni yon ta'sirlar ro'yxatida aytadi. Sir tozalashda butun repo uchun git push --force --mirror origin ishlatiladi: barcha branch va tag'lar bir martada. GitHub'da bu buyruq refs/pull/... ref'larida rad oladi — hujjatga ko'ra ular faqat o'qish uchun. Bu kutilgan holat: ularni GitHub Support hal qiladi («GitHub tomoni» bo'limi).
Diqqat: Odatiy ishda
--forceemas,--force-with-leaseishlating (Ajralgan tarix darsi). Tozalash — kamdan-kam holat: siz markazdagi tarixni ataylab butunlay almashtiryapsiz va bundan oldin jamoani ogohlantirgansiz.
5.2 Jasur: to'g'ri yo'l
Jasur tozalashdan oldin klon olgan va ustida bitta commit qilgan (feat: narx fayli), hali push qilmagan. Jamoa chatida "tarix qayta yozildi, birinchi o'zgargan commit f4ca674" degan xabarni o'qidi. U merge qilmaydi — o'z commitlarini yangi tarix ustiga ko'chiradi:
git fetch -q
git rebase --onto origin/main 'origin/main@{1}' main
git log --oneline -3Terminalda:
Successfully rebased and updated refs/heads/main.
b225906 (HEAD -> main) feat: narx fayli
84aecd1 (origin/main, origin/HEAD) docs: ish vaqti
0d20272 fix: token env'dan o'qiladirebase --onto A B main — "B dan keyingi main commitlarini A ustiga qayta ter". origin/main@{1} — fetch'dan oldingi origin/main holati, ya'ni eski 8d0b325 (Reflog darsidagi @{1} sintaksisi). Demak, faqat Jasurning o'z commiti ko'chdi. Eski tarix uning main idan chiqib ketdi: git log -S endi 0 ta commit ko'rsatadi. Push oddiy, --force siz o'tdi:
To ../markaz.git
84aecd1..b225906 main -> mainO'z commiti bo'lmasa, yo'l yanada oddiy: eski klonni o'chirib, qayta git clone.
5.3 Nodira: odatdagi git pull
Nodira chatni o'qimadi. U ham bitta commit qildi (feat: menyu moduli) va odatdagidek git pull yozdi:
From ../markaz
+ 8d0b325...b225906 main -> origin/main (forced update)
hint: You have divergent branches and need to specify how to reconcile them.
...
fatal: Need to specify how to reconcile divergent branches.Git 2.54 sozlanmagan pull da ajralgan tarixni o'zi hal qilmaydi — "qanday birlashtirishni ko'rsating" deb to'xtaydi (chiqish kodi 128). forced update so'zi — birinchi ogohlantirish: kimdir tarixni almashtirgan. Lekin Nodira hint'dagi variantlardan birini tanlaydi:
git pull --no-rebase
git push origin mainMerge made by the 'ort' strategy.
To ../markaz.git
b225906..b098b2c main -> mainMerge muvaffaqiyatli, push ham — chunki merge commiti yangi tarixni o'z ichiga oladi, ya'ni bu oddiy fast-forward. Hech qanday himoya ishlamadi. Markazda nima bo'ldi?
SIR="SOXTA-BAHOR-SIRI-0000-faqat-lokal"
git -C ../markaz.git log --all -S"$SIR" --oneline
git -C ../markaz.git log --oneline --graph mainBiz ishga tushirdik:
b536195 fix: token env'dan o'qiladi
b51df01 feat: konfig moduli
112cb66 fix: .env ni git'dan chiqarish
f4ca674 feat: sozlamalar
* b098b2c (HEAD -> main) Merge branch 'main' of ../markaz
|\
| * b225906 feat: narx fayli
| * 84aecd1 docs: ish vaqti
| * 0d20272 fix: token env'dan o'qiladi
| * 586fae7 feat: konfig moduli
| * 235b65f fix: .env ni git'dan chiqarish
| * ae30c80 feat: sozlamalar
* | 1e69225 feat: menyu moduli
* | 8d0b325 docs: ish vaqti
* | b536195 fix: token env'dan o'qiladi
* | b51df01 feat: konfig moduli
* | 112cb66 fix: .env ni git'dan chiqarish
* | f4ca674 feat: sozlamalar
|/
* 09785db feat: bot boshlang'ichSir qaytdi. Butun tozalash bekor bo'ldi. Bundan ham yomoni: tarixda har commit endi ikki nusxada — eski va yangi, bir xil xabar bilan. Rasmda:
gitGraph
commit id: "09785db"
branch eski
commit id: "f4ca674 (sir)"
commit id: "b51df01 (sir)"
commit id: "8d0b325"
commit id: "1e69225 menyu"
checkout main
commit id: "ae30c80"
commit id: "586fae7"
commit id: "84aecd1"
commit id: "b225906 narx"
merge eski id: "b098b2c merge"GitHub hujjati bu xavfni "recontamination" (qayta ifloslanish) deb ataydi: eski klonlardan biri push qilsa, "sir qaytadi". Shuning uchun tozalash — texnik emas, jamoaviy jarayon: hamma ogohlantiriladi, hamma qayta klon yoki rebase qiladi, va shundan keyingina ish davom etadi.
Tekshirib ko'ring: Nodira
git pull --rebaseni tanlaganida nima bo'lardi?
Javob
Ko'pincha to'g'ri ishlaydi, lekin kafolat emas. Biz ikkala holatni sinadik. Odatdagi klonda Git reflog'dan eski origin/main ni topdi ("fork-point") va faqat Nodiraning commitini ko'chirdi:
Successfully rebased and updated refs/heads/main.
commitlar: 7, sir: 0Keyin eski origin/main ref'i yo'q klonda sinadik (masalan, boshqa remote nomi bilan ishlagan yoki ref'ni o'chirgan hamkasb). Git eski commitlarni ham "Nodiraniki" deb terishga urindi va birinchisidayoq to'xtadi:
Could not apply f4ca674... # feat: sozlamalarf4ca674 — sir paydo bo'lgan commit. Konfliktni "yechib" davom etsa, sir qaytadi. Shuning uchun Jasurdagi aniq rebase --onto yoki qayta klon — ishonchli yo'l. Push'dan oldin git log -S"<sir>" bilan tekshirish — majburiy.
5.4 Boshqa yon ta'sirlar
GitHub hujjatidagi "Side effects of rewriting history" ro'yxatidan (2026-11-04 da o'qildi):
- Hash'lar o'zgaradi — commit havolalari (issue'larda, CHANGELOG'da, chatda) endi mavjud bo'lmagan commitga olib boradi.
- Imzolar yo'qoladi — filter-repo commit va tag imzolarini olib tashlaydi, sir paydo bo'lishidan oldingi commitlarnikini ham. Commit imzolash darsidagi
GbelgisiNga aylanadi. - PR'lar — yopilgan PR'larning diff'i ko'rinmay qoladi, ochiq PR'larda izohlar yo'qolishi mumkin; hujjat avval ochiq PR'larni yopish yoki merge qilishni tavsiya qiladi.
- Hamkasblarning ishi — tozalashdan oldin push qilinmagan ishlar rebase talab qiladi.
Imzo bandini o'zimiz tekshirdik. Uch commitli repo, hammasi SSH kaliti bilan imzolangan, ikkinchisida sir fayli bor (sir.txt). Yangi klonda git filter-repo --invert-paths --path sir.txt, keyin git log --format='%h %G? %s'. Qarang: belgi va hash'lar qanday o'zgardi.
=== oldin
f4bf238 G docs: ish vaqti
561b497 G feat: sozlamalar
d17e7a0 G feat: boshlang'ich
=== filter-repo'dan keyin
c3d26d9 N docs: ish vaqti
1c0a1ed N feat: boshlang'ich
tag ichida imzo: 0Nima bo'ldi? Hamma imzo ketdi (G → N), tagdagi imzo ham. Muhimi — sirga tegmagan birinchi commit ham yangi hash oldi (d17e7a0 → 1c0a1ed). Imzo commit matnining bir qismi edi; u olib tashlangach, matn o'zgardi. Demak, imzolangan repoda «Natija: yangi tarix» bo'limidagi "birinchi commit tegilmadi" qoidasi ishlamaydi — butun tarix yangi bo'ladi. (Hash'lar sizda boshqa chiqadi: sinovda kalit har safar yangi yaratiladi.) Tozalashdan keyin yangi commitlarni odatdagidek imzolaysiz; eski tarix imzosiz qoladi.
6. GitHub tomoni
Lokal tarixni tozaladingiz va majburiy push qildingiz. GitHub'da sir hali ham qolishi mumkin (docs.github.com, sinalmagan, 2026-11):
- PR havolalari. Har PR uchun GitHub
refs/pull/N/headni saqlaydi. Ularni siz o'chira olmaysiz. - Kesh ko'rinishlar. Commit sahifasi URL bo'yicha ochilib turishi mumkin.
- Fork'lar. Ular boshqa odamlarniki — GitHub ularni tozalamaydi va egalarining kontaktini bermaydi.
Birinchi ikkisi uchun GitHub Support ga murojaat qilinadi — --sensitive-data-removal chiqishidagi "First Changed Commit" aynan shu murojaatda kerak. Support faqat rotatsiya bilan hal bo'lmaydigan sezgir ma'lumot uchun yordam beradi.
Eng yaxshisi — sir umuman push qilinmasin. GitHub'ning ikki himoyasi bor:
- Secret scanning — repo'dagi ma'lum formatdagi kalitlarni (GitHub tokenlari, bulut kalitlari va h.k.) qidiradi va ogohlantiradi.
- Push protection — push paytida ma'lum formatdagi sirni ko'rsa, push'ni rad etadi. Shaxsiy akkauntlar uchun ochiq repo'larga push'da sukut bo'yicha yoqilgan. Rad etilganda batafsil xabar chiqadi. Yozish huquqi bor odam uni sabab ko'rsatib chetlab o'tishi mumkin: "It's used in tests", "It's a false positive", "I'll fix it later". Repo darajasida push protection yoqilgan bo'lsa, chetlab o'tish ogohlantirish (alert) yaratadi, audit jurnaliga yoziladi va repo egalariga xat boradi. Faqat foydalanuvchi darajasidagi himoyada bunday ogohlantirish yaratilmaydi (hujjat, 2026-11-04).
Biz push protection'ni sinamadik: kursning sinov reposiga hech qanday sir yuborilmadi. Bizning SOXTA-… qiymatimiz hech qaysi ma'lum formatga mos emas — push protection uni tanimagan bo'lardi. Bu muhim saboq: himoya faqat taniladigan formatlarni ushlaydi. O'zingiz o'ylab topgan parol yoki baza manzili .env bilan ketsa — hech kim to'xtatmaydi. Sirlarni boshqarish darsidagi pre-commit skaner va .gitignore — birinchi qatordagi himoya.
7. Kichikroq qayta yozishlar
Hamma "tarixni qayta yozish" filter-repo emas. Push qilinmagan commitlar uchun Interaktiv rebase darsidagi vositalar yetarli: commit --amend, rebase -i, commit --fixup + --autosquash. Ular ham hash'larni o'zgartiradi — lekin hech kimda eski nusxa yo'q, shuning uchun xavfsiz.
Kanon tajribasida (IlmHamroh, 2026-11) bir foydali usul sinaldi: --autosquash ni muharrir ochmasdan ishlatish. GIT_SEQUENCE_EDITOR=: — Git rebase ro'yxatini ochadigan "muharrir" o'rniga hech narsa qilmaydigan : buyrug'ini ishlatadi, ya'ni ro'yxat o'zgarishsiz qabul qilinadi:
git commit --fixup HEAD~1
GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash HEAD~4Kanon chiqishi — oldin va keyin:
027f720 fixup! feat: f fayl
6e76fdd feat: g fayl
04ed8c8 feat: f fayl
19b1bc2 feat: konfig
--- autosquash'dan keyin:
67bd6d0 feat: g fayl
972f05e feat: f fayl
19b1bc2 feat: konfigfixup! commiti feat: f fayl ga qo'shildi. Skriptlarda va CI'da muharrir yo'q — bu usul shunday joylar uchun.
BFG Repo-Cleaner — filter-repo'ga muqobil vosita. U Scala'da yozilgan va Java (JRE 11+) ostida java -jar bilan ishlaydi: bfg --delete-files .env, bfg --replace-text. U ko'p eski qo'llanmalarda uchraydi. Kanon filter-repo'ni ishlatdi, BFG sinalmagan. GitHub hujjatining joriy versiyasi BFG'ni tilga olmaydi — faqat filter-repo'ni tavsiya qiladi.
8. Loyiha qadami: vazifalar-api tarixini tekshirish
Bu dars — tajriba darsi: vazifalar-api kodi o'zgarmaydi va commit yo'q. Bizning loyihada tozalash kerak emas — va buni isbotlash kerak.
Kanon tajribasida (IlmHamroh, 2026-11) xuddi shu jarayon vazifalar-api bilan bir xil tuzilishdagi alohida sinov repo'sida bajarildi: .env commiti, git filter-repo --invert-paths --path .env — 1.06 s, sirga tegmagan birinchi commit hash'i o'zgarmadi, origin o'chirildi. Eski klonda esa sir 2 joyda qoldi. Xulosa o'sha: tarixni tozalash kalitni almashtirmaydi.
Kursning sinov reposiga har push'dan oldin kanon tarixni ma'lum sir naqshlariga tekshirdi. O'z repo'ngizda ham qiling:
git log --all -p | grep -c -E \
'ghp_|github_pat_|sk-|AIza|AKIA|PRIVATE KEY|xox[bpa]-'Naqshlar: GitHub tokenlari (ghp_, github_pat_), ko'p AI xizmatlari kaliti (sk-), Google (AIza), AWS (AKIA), maxfiy kalit fayli, Slack (xox…). Kanon shu naqshlar bilan har push'dan oldin tekshirdi — haqiqiy moslik 0. Sizda 0 dan katta bo'lsa — har mos qatorni ko'rib chiqing: ba'zan bu naqshning o'zi yozilgan skript bo'ladi. Haqiqiy kalit bo'lsa — avval rotatsiya, keyin shu dars.
Va bitta odat: .env.example — repo'da, .env — .gitignore da. Bu loyihada Sirlarni boshqarish darsidan beri shunday.
9. Ko'p uchraydigan xatolar
9.1 "does not look like a fresh clone"
filter-repo ishchi repo'da ishga tushirildi. Davosi: git clone --mirror (yoki lokal yo'l uchun git clone --no-local) bilan yangi klon va o'sha yerda ishlash. --force ni odat qilmang.
9.2 'filter-repo' is not a git command
Vosita o'rnatilmagan yoki pip papkasi PATH'da yo'q. pip install git-filter-repo, keyin terminalni qayta oching. Windows'da py -m pip install git-filter-repo ham ishlaydi.
9.3 Tozalandi, lekin sir yana paydo bo'ldi
Eski klondan pull + push («Nodira: odatdagi git pull» bo'limi). Davosi: tozalashdan oldin jamoani ogohlantiring, keyin har klonni qayta oling. Push'dan oldin git log --all -S"<sir>" — 0.
9.4 fatal: Need to specify how to reconcile divergent branches
pull paytida forced update ko'rdingizmi? Hint'dagi variantni o'ylamay tanlamang — avval jamoadan so'rang, tarix qayta yozilganmi.
9.5 Faqat main tozalandi
Oddiy klonda filter-repo faqat lokal branch'larni ko'radi. Sir eski feature branch yoki tag'da qoladi. Davosi: --mirror klon va push --force --mirror.
9.6 Tozaladim, endi kalit xavfsiz
Yo'q. Klonlar, fork'lar, CI loglari, botlar allaqachon nusxa olgan bo'lishi mumkin. Rotatsiya qilinmagan kalit — sizib chiqqan kalit.
10. Mashqlar
Mashqlar kurs/mashqlar/32/05-tozalash/ da. 2-mashq yechimi Node 24.21.0 da, 3-mashq yechimi Git 2.54.0 va git-filter-repo 2.47.0 da tekshirilgan (biz ishga tushirdik).
1-mashq (oson): bo'shliqlarni to'ldiring
- Sir sizib chiqqanda birinchi qadam —
- Faqat joriy fayllarda qidiradigan buyruq —
git - filter-repo'da faylni tarixdan olib tashlash:
--path .envva --replace-textda==>yozilmasa, sir o'rniga qo'yiladigan matn —- Barcha branch va tag'larni bir martada almashtiradigan push —
git push --force
Yechim
- rotatsiya — eski kalit bekor qilinadi; tozalash — keyin.
- grep — tarix uchun
git log -S. - --invert-paths — "shu yo'ldan boshqasini qoldir".
- ***REMOVED*** — filter-repo sukuti.
- --mirror —
--mirrorklon bilan juft.
2-mashq (o'rta): --replace-text ni JavaScript'da
filter-repo almashtirish faylini o'qiydigan qoidalarniOqi(fayl) va qoidalarni matnga qo'llaydigan tozala(matn, qoidalar) funksiyalarini yozing. Format — «To'g'ri yo'l: yangi --mirror klon» bo'limidagi jadval: oddiy matn, ==> bilan almashtirish, regex: prefiksi (glob: shart emas). ==> bo'lmasa — ***REMOVED***. Bo'sh qatorlarni tashlab keting. Ishora: indexOf("==>") va slice (Satr metodlari); hamma moslikni almashtirish uchun replaceAll (replaceAll) va g bayroqli RegExp.
Yechim
function qoidalarniOqi(fayl) {
return fayl
.split("\n")
.filter((q) => q.trim() !== "")
.map((q) => {
const i = q.indexOf("==>");
const naqsh = i === -1 ? q : q.slice(0, i);
const orniga = i === -1 ? "***REMOVED***" : q.slice(i + 3);
if (naqsh.startsWith("regex:")) {
return { re: new RegExp(naqsh.slice(6), "g"), orniga };
}
return { matn: naqsh, orniga };
});
}
function tozala(matn, qoidalar) {
let natija = matn;
for (const q of qoidalar) {
natija = q.re
? natija.replace(q.re, q.orniga)
: natija.replaceAll(q.matn, q.orniga);
}
return natija;
}
const qoidalar = qoidalarniOqi([
"SOXTA-BAHOR-SIRI-0000",
"parol123==>[PAROL]",
"regex:BOT_TOKEN=\\S+==>BOT_TOKEN=***",
].join("\n"));
console.log(tozala("const k = 'SOXTA-BAHOR-SIRI-0000';", qoidalar));
console.log(tozala("DB_PAROL=parol123", qoidalar));
console.log(tozala("BOT_TOKEN=abc.def\nPORT=3000", qoidalar));Konsolda:
const k = '***REMOVED***';
DB_PAROL=[PAROL]
BOT_TOKEN=***
PORT=3000Uchala qoida turi ishladi. Uchinchi misolda muntazam ifoda faqat BOT_TOKEN= qatorini almashtirdi — \S+ bo'sh joy yoki qator oxirigacha. Regex qoidasi kuchli, lekin xavfli: juda keng naqsh (regex:.*) butun fayllarni buzadi. filter-repo'ning o'zi Python muntazam ifodalarini ishlatadi — sintaksis deyarli bir xil, lekin almashtirishdagi guruh havolasi \1 (JavaScript'da $1).
3-mashq (qiyin): to'liq tozalash
sir-repo-yarat.sh bilan bot repo'sini yarating, "markaz" sifatida bare repo oching va unga push qiling. Keyin «Tartib: avval kalit, keyin tarix» bo'limidagi 2–4 qadamlarni bajaring: --mirror klon, --sensitive-data-removal bilan .env va sir matnini olib tashlash, push --force --mirror. Oxirida markazdan yangi klon oling va isbotlang: commitlar soni o'zgarmagan, sir ham, .env ham tarixda yo'q, konfig.js ning eski versiyasida sir o'rnida belgi.
Ishora: .env tarixini git log --all --oneline -- .env ko'rsatadi; wc -l qatorlarni sanaydi. filter-repo chiqishi uzun — > /dev/null 2>&1 bilan yashiring va natijani o'zingiz tekshiring.
Yechim
bash sir-repo-yarat.sh bot
git init -q --bare -b main markaz.git
git -C bot push -q ../markaz.git main
git clone -q --mirror markaz.git tozalash.git
cat > qoidalar.txt <<'EOF'
SOXTA-BAHOR-SIRI-0000-faqat-lokal
EOF
cd tozalash.git
git filter-repo --sensitive-data-removal --invert-paths \
--path .env --replace-text ../qoidalar.txt > /dev/null 2>&1
git push -q --force --mirror origin
cd ..
git clone -q markaz.git tekshir && cd tekshir
SIR="SOXTA-BAHOR-SIRI-0000-faqat-lokal"
echo "commitlar: $(git rev-list --count HEAD)"
echo "sir tarixda: $(git log --all -S"$SIR" --oneline | wc -l)"
echo ".env tarixda: $(git log --all --oneline -- .env | wc -l)"
git show HEAD~2:konfig.js
git log --onelineBiz ishga tushirdik:
commitlar: 6
sir tarixda: 0
.env tarixda: 0
export const token = '***REMOVED***';
446886c docs: ish vaqti
e6c970a fix: token env'dan o'qiladi
e24c16b feat: konfig moduli
235b65f fix: .env ni git'dan chiqarish
ae30c80 feat: sozlamalar
09785db feat: bot boshlang'ichHash'larni dars bilan solishtiring: 235b65f va ae30c80 — darsdagidek, chunki .env bilan bog'liq o'zgarish bir xil. Keyingi uchta commit esa boshqacha (e24c16b, darsda 586fae7): bu safar sir o'rniga ***REMOVED*** yozildi, darsda ***OLIB-TASHLANDI***. Bitta belgining farqi ham butun zanjirni o'zgartiradi. Tekshiruv yangi klonda qilinganiga e'tibor bering: tozalash joyidagi repo emas, markazdagi holat muhim.
11. Real ishda
- Qayerda uchraydi: "ochiq repo'ga kalit tushdi" — har yili minglab holatlar; botlar ochiq repo'larni bir necha daqiqada skanerlaydi. Jamoada tozalash odatda xavfsizlik hodisasi (incident) sifatida yuritiladi: kim, qachon, qaysi kalit, rotatsiya vaqti.
- Boshqa maqsadlar: filter-repo bilan papkani alohida repo'ga ajratish (
--subdirectory-filter), katta fayllarni olib tashlash, muallif emailini ommaviy almashtirish (--mailmap) — sir bo'lmasa ham tarix qayta yoziladi va bu darsdagi hamma oqibat amal qiladi. - Intervyu savollari: "Repo'ga parol tushib qoldi — qadamlaringiz?", "Nega
git rmyetarli emas?", "Tarixni qayta yozgandan keyin hamkasblar nima qilishi kerak?"
Xulosa
git grep— joriy fayllar,git log -S— butun tarix. Sir "tuzatish" commitida ham to'liq ko'rinadi.- Tartib: rotatsiya → yangi klonda filter-repo → tekshirish → majburiy push → hamkasblar → GitHub Support.
git filter-repo --invert-paths --path <fayl>— faylni,--replace-text— matnni olib tashlaydi; sir uchun--sensitive-data-removal.- filter-repo yangi klon talab qiladi va oddiy rejimda
originni o'chiradi — bu himoya. - Sir paydo bo'lgan commitdan keyingi hamma hash o'zgaradi; imzolar yo'qoladi.
- Bitta eski klondan
pull+pushsirni qaytaradi; to'g'ri yo'l — qayta klon yokirebase --onto. - Push protection faqat taniladigan formatlarni ushlaydi; o'ylab topilgan sirni
.gitignoreva skaner himoya qiladi.
Keyingi dars: Katta repolar: Git LFS, shallow clone va sparse-checkout — tarixda 30 versiyali video bo'lsa, klonni qanday tezlashtirish mumkin: --depth 1, --filter=blob:none, sparse-checkout va Git LFS.
Manbalar
- git-filter-repo hujjati (
--replace-text, fresh clone tekshiruvi, "Why is my origin removed?"): https://github.com/newren/git-filter-repo/blob/main/Documentation/git-filter-repo.txt - GitHub Docs — Removing sensitive data from a repository: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository
- GitHub Docs — About push protection: https://docs.github.com/en/code-security/secret-scanning/introduction/about-push-protection
- GitHub Docs — About secret scanning: https://docs.github.com/en/code-security/secret-scanning/introduction/about-secret-scanning (2026-11-04 da o'qildi)
- Git hujjati — git-filter-branch (filter-repo tavsiyasi): https://git-scm.com/docs/git-filter-branch (Git 2.54 bilan kelgan hujjatda tekshirildi)
- Git hujjati — git-rebase (
--onto,--autosquash): https://git-scm.com/docs/git-rebase - BFG Repo-Cleaner: https://rtyley.github.io/bfg-repo-cleaner/ (vosita sinalmagan; sahifa 2026-11-04 da o'qildi)
- Kanon tajribasi (IlmHamroh, 2026-11-04): Git 2.54.0, git-filter-repo 2.47.0 (pip), Windows 11. «Bahor» bot repo'si, markaz va ikki hamkasb klonlari,
--sensitive-data-removal, sir qaytgan merge, imzolangan repoda filter-repo va mashq yechimlari — biz ishga tushirdik (2026-11-04); fixup/autosquash va 1.06 s o'lchovi — kanon tajribasi.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!