IlmHamroh
JavaScript Full-stack/7-qism. Git va GitHub asoslari13/36-dars21 daqiqa
Mundarija (37)

.gitattributes va qator oxirlari: CRLF va LF muammosini hal qilish

Qisqacha: Windows qator oxiriga CRLF, Linux va macOS esa LF qo'yadi. Bu farq "bitta so'z o'zgargan, lekin hamma qatorlar o'zgargan" degan diff'larni keltirib chiqaradi. Yechim — loyiha ildizidagi .gitattributes fayli: * text=auto eol=lf qatori hamma matn fayllarini repoda ham, ishchi papkada ham LF qiladi. Mavjud repoda undan keyin git add --renormalize . qilinadi. Rasmlarga binary belgisi qo'yiladi.

Bu darsda

  • LF will be replaced by CRLF ogohlantirishining sababini oxirigacha tushuntirasiz.
  • core.autocrlf ning uch qiymatini va uning kamchiligini bilasiz.
  • .gitattributes yozasiz: text=auto, eol=lf, binary, -diff, linguist-generated.
  • git ls-files --eol bilan har faylning qator oxirini tekshirasiz va git add --renormalize bilan reponi tozalaysiz.
  • .editorconfig va .gitattributes qanday birga ishlashini bilasiz.

Oldin bilishingiz kerak: Qator oxiri: CRLF va LF, .gitignore, HEAD va refs.

1. Nega bu kerak?

07-qism boshidan beri deyarli har git add da bir xil qator chiqib turibdi:

text
warning: in the working copy of 'index.html', LF will be replaced by CRLF the next time Git touches it

Birinchi repo darsida "qo'rqmang, bu ogohlantirish, keyin tartibga solamiz" degan edik. Qator oxiri darsida esa .gitattributes faylini birinchi marta ko'rgan edik va "batafsil — Git qismida" deb va'da bergandik. Bugun ikkala va'dani bajaramiz.

Ogohlantirish — muammoning faqat ko'rinadigan uchi. Asl xavf jamoada chiqadi. Qator oxiri darsidagi voqeani eslang: Ali Windows'da bitta so'zni tuzatadi, Malika esa macOS'da hamma qatorlar o'zgarganini ko'radi. Bunday diff'ni hech kim o'qiy olmaydi. Hamkasb kodingizni tekshirganda (code review — buni qism oxirida o'rganamiz) haqiqiy o'zgarish yuzlab "soxta" o'zgarish ichida yo'qoladi. Serverda esa CRLF'li skript $'\r': command not found deb yiqiladi.

Bu dars — bir martalik sozlash. To'g'ri qilsangiz, loyiha umri davomida bu mavzuga qaytmaysiz.

2. Muammoni o'z ko'zimiz bilan ko'ramiz

2.1 Tajriba

Tajribani kurs/sinov-git/ ichidagi yangi repoda qilamiz. Malika Linux'da menyu sahifasini commit qilgan deb tasavvur qilamiz — fayl LF bilan. Aziz esa Windows'da ishlaydi va uning Git'ida avtomatik almashtirish o'chirilgan: git config core.autocrlf false (bu nima ekanini keyingi bo'limda ko'ramiz).

Takrorlamoqchi bo'lsangiz, tayyorgarlik shunday. printf — echo ning aniqroq varianti, \n ni LF'ga aylantiradi (Git ichkaridan darsida ishlatgansiz):

bash
cd ~/kurs/sinov-git
mkdir qator && cd qator
git init
git config core.autocrlf false
printf '<h1>Menyu</h1>\n' > menyu.html
printf "<p>Osh — 35 000 so'm</p>\n" >> menyu.html
printf "<p>Choy — 3 000 so'm</p>\n" >> menyu.html
git add menyu.html
git commit -m "Menyu: sahifa yarat"

git config --global siz — faqat shu repo uchun (Git'ni sozlash). Har faylning qator oxirini Git'ning o'zi ko'rsatadi:

bash
git ls-files --eol
text
i/lf    w/lf    attr/                 	menyu.html

Bu buyruq — bugungi darsning asosiy asbobi. Uch ustun:

Ustun Ma'nosi
i/… Index (quti va repo) dagi nusxa: lf, crlf, mixed yoki -text (binar)
w/… Ishchi papkadagi (working tree) nusxa
attr/… .gitattributes dan kelgan qoida (hozir bo'sh)

Hozir ikkala nusxa ham LF. Aziz choy narxini 3 000 dan 4 000 ga o'zgartirdi. Uning muharriri faylni CRLF bilan saqladi. Buni ikki buyruq bilan taqlid qilamiz: sed -i — faylda almashtirish, unix2dos — Qator oxiri darsidagi dos2unix ning teskarisi, LF'ni CRLF qiladi:

bash
sed -i 's/Choy — 3 000/Choy — 4 000/' menyu.html
unix2dos -q menyu.html
file menyu.html
git diff --stat
text
menyu.html: Unicode text, UTF-8 text, with CRLF line terminators
 menyu.html | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

file buyrug'i (Qator oxiri darsidan) CRLF'ni ko'rsatdi. Bitta narx o'zgardi, Git esa "3 qator o'chdi, 3 qator qo'shildi" deyapti. Diff'ning o'zi:

text
@@ -1,3 +1,3 @@
-<h1>Menyu</h1>
-<p>Osh — 35 000 so'm</p>
-<p>Choy — 3 000 so'm</p>
+<h1>Menyu</h1>
+<p>Osh — 35 000 so'm</p>
+<p>Choy — 4 000 so'm</p>

(Diff boshidagi diff --git va index qatorlarini qisqartirdik.) Ikki qator ko'zga mutlaqo bir xil. Farq ko'rinmas belgida — \r da.

2.2 Ko'rinmas belgini ko'rish

cat -A barcha ko'rinmas belgilarni ko'rsatadi: qator oxiri — $, \r — ^M:

bash
git diff | cat -A

Natijaning oxirgi qismi (ko'rsatilgan uch qator):

text
-<h1>Menyu</h1>$
-<p>Osh M-bM-^@M-^T 35 000 so'm</p>$
-<p>Choy M-bM-^@M-^T 3 000 so'm</p>$
+<h1>Menyu</h1>^M$
+<p>Osh M-bM-^@M-^T 35 000 so'm</p>^M$
+<p>Choy M-bM-^@M-^T 4 000 so'm</p>^M$

Yangi qatorlar oxirida ^M bor. M-bM-^@M-^T — uzun tire (—) ning baytlari, cat -A harf bo'lmagan belgilarni shunday yozadi. Endi ls-files:

text
i/lf    w/crlf  attr/                 	menyu.html

Repoda LF, ishchi papkada CRLF. Git ular farqli deb hisoblaydi — va haqli.

Diff'ni o'qish uchun vaqtinchalik yo'l bor — --ignore-cr-at-eol ("qator oxiridagi CR'ga e'tibor berma"):

bash
git diff --ignore-cr-at-eol --stat
text
 menyu.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Endi faqat bitta haqiqiy o'zgarish. Lekin bu faqat ko'rish uchun: commit qilinsa, CRLF baribir repoga tushadi va Malikaning faylida hamma qatorlar o'zgaradi. Muammoni ildizidan hal qilish kerak.

Tekshirib ko'ring: git ls-files --eol natijasi i/lf w/crlf. Bu nimani anglatadi?

Javob

Repodagi (index) nusxada qator oxirlari LF, kompyuteringizdagi fayl esa CRLF. Commit qilganda nima bo'lishi sozlamaga bog'liq: almashtirish yoqilgan bo'lsa, Git CRLF'ni LF'ga aylantiradi; o'chirilgan bo'lsa — CRLF repoga tushadi.

3. core.autocrlf — eski yechim

3.1 Sizdagi qiymat

Git for Windows o'rnatuvchisi bu muammoni oldindan biladi va bitta sozlama qo'yadi. Git'ni sozlash darsida ro'yxatda ko'rgan edik. Qayerdan kelganini tekshiramiz:

bash
git config --show-origin core.autocrlf
text
file:D:/Dasturlash/Install/Git/etc/gitconfig	true

System darajasi, qiymat true. (Bizda Git D: diskda. Odatiy o'rnatishda yo'l C:/Program Files/Git/etc/gitconfig bo'ladi.)

3.2 Uch qiymat

Qiymat git add da Fayl chiqarilganda
true CRLF → LF LF → CRLF
input CRLF → LF o'zgartirmaydi
false o'zgartirmaydi o'zgartirmaydi

true — Windows uchun: repoda LF saqlanadi, sizga esa CRLF beriladi. input — macOS va Linux uchun: tasodifan kirib qolgan CRLF repoga tushmaydi. false — hech narsa qilmaydi.

Endi 07-qismdagi ogohlantirish to'liq tushunarli. Siz echo bilan LF fayl yaratdingiz. core.autocrlf=true bilan Git aytmoqda: "Repoga LF saqlayman. Lekin keyingi safar bu faylni ishchi papkaga chiqarganimda (checkout, restore, reset), CRLF bilan chiqaraman — fayl o'zgaradi, sizni ogohlantirib qo'yay". Sinovda aynan shunday bo'ldi — yangi reponing fayli Git chiqargandan keyin:

text
i/lf    w/crlf  attr/                 	a.txt

3.3 Nega bu yetarli emas?

core.autocrlf — shaxsiy sozlama. U har kimning kompyuterida alohida turadi va repo bilan birga yurmaydi:

  • Jamoaga yangi odam keldi. Git'ni boshqa usulda o'rnatgan — unda false. U CRLF commit qiladi.
  • Kimdir "bu ogohlantirishlar jonga tegdi" deb false qilib qo'ydi.
  • macOS'dagi hamkasbda umuman sozlanmagan.

Bitta odam xato qilsa — butun jamoaning diff'i buziladi. Qoida hamma uchun bir xil bo'lishi uchun u repoda turishi kerak. Bu — .gitattributes.

4. .gitattributes — qoida repoda

4.1 Fayl tuzilishi

.gitattributes — loyiha ildizida turadigan matn fayli. Unda fayllarga "atribut" (xususiyat) beriladi: bu fayl matnmi, qator oxiri qanday bo'lsin, diff ko'rsatilsinmi. Tuzilishi .gitignore ga o'xshaydi: har qatorda shablon (pattern) va atributlar.

text
shablon    atribut1 atribut2 ...

Shablonlar .gitignore dagidek: * — hamma fayl, *.png — hamma PNG, sayt/*.html — sayt ichidagi HTML'lar. Bir fayl bir necha qatorga mos kelsa — pastdagi qator ustun.

Atribut uch holatda bo'ladi:

Yozuv Holat Masalan
text yoqilgan (set) "bu matn fayl"
-text o'chirilgan (unset) "bu matn emas"
eol=lf qiymat berilgan "qator oxiri LF"

4.2 Asosiy qator: * text=auto eol=lf

Qator oxiri darsida ko'rgan qator — eng muhimi:

  • * — barcha fayllar uchun.
  • text=auto — "matnmi yoki binarmi, Git o'zi aniqlasin". Matn fayllarning qator oxirlari repoda doim LF'ga keltiriladi (normalizatsiya). Binar fayllarga tegilmaydi.
  • eol=lf — ishchi papkaga chiqarganda ham LF. Ya'ni Windows'da ham fayllaringiz LF bo'ladi.

Normalizatsiya (normalization) — hamma narsani bitta standart ko'rinishga keltirish. Bu yerda — hamma qator oxirlarini LF'ga.

Nega Windows'da ham LF? Chunki zamonaviy muharrirlar — VS Code, Notepad, WebStorm — LF fayllarni muammosiz ochadi va saqlaydi. Loyiha esa oxir-oqibat Linux serverda ishlaydi. Hamma joyda LF — eng sodda va ishonchli tanlov.

.gitattributes va core.autocrlf to'qnashsa, .gitattributes ustun: text/eol atributi bor fayllar uchun Git core.autocrlf ga qaramaydi. Shuning uchun system sozlamangizni o'zgartirish shart emas.

4.3 Istisnolar

Ba'zi fayllarga boshqa qoida kerak:

text
* text=auto eol=lf
*.bat text eol=crlf
*.png binary
  • *.bat text eol=crlf — Windows buyruq fayllari (.bat, .cmd) faqat Windows'da ishlaydi va CRLF talab qiladi. text — "bu albatta matn", eol=crlf — ishchi papkada CRLF. Repoda baribir LF saqlanadi.
  • *.png binary — "bu matn emas, ichiga umuman tegma". Rasm baytlari orasida tasodifan 13 va 10 raqamlari bo'lishi mumkin — bular CR va LF belgilarining raqamlari. Git ularni almashtirsa, rasm buziladi.

binary — aslida uch atributning qisqa yozuvi. git check-attr buni ko'rsatadi:

bash
git check-attr -a assets/images/choy.png
text
assets/images/choy.png: binary: set
assets/images/choy.png: diff: unset
assets/images/choy.png: merge: unset
assets/images/choy.png: text: unset
assets/images/choy.png: eol: lf

-text (qator oxiriga tegma), -diff (matn diff'ini ko'rsatma) va -merge (qatorma-qator birlashtirma). eol: lf qatori * qoidasidan kelgan, lekin text o'chirilgani uchun unga e'tibor berilmaydi. git check-attr — "bu faylga qaysi qoidalar ta'sir qilyapti?" degan savolning javobi.

Tekshirib ko'ring: .gitattributes da * text=auto eol=lf va undan pastda *.bat text eol=crlf yozilgan. ishga-tushir.bat fayli ishchi papkada qanday qator oxiri bilan chiqadi?

Javob

CRLF bilan. Ikkala qator ham .bat faylga mos keladi, lekin pastdagi qator ustun. Repoda esa u baribir LF saqlanadi — text atributi normalizatsiya qiladi. Sinovimizda git check-attr -a ishga-tushir.bat shunday dedi: text: set, eol: crlf.

5. Mavjud repoda yoqish: git add --renormalize

5.1 CRLF allaqachon repoda

Eng og'ir holat: kimdir core.autocrlf=false bilan CRLF fayllarni commit qilib bo'lgan. Sinov reposimizga shunday CSS va .bat fayl qo'shamiz. \r\n — aynan CRLF:

bash
printf 'body { margin: 0; }\r\n' > asosiy.css
printf 'h1 { color: green; }\r\n' >> asosiy.css
printf '@echo off\r\necho Salom\r\n' > ishga-tushir.bat
git add asosiy.css ishga-tushir.bat
git commit -m "Sinov: CSS va bat faylni CRLF bilan qo'sh"

git ls-files --eol natijasi:

text
i/crlf  w/crlf  attr/                 	asosiy.css
i/crlf  w/crlf  attr/                 	ishga-tushir.bat
i/lf    w/lf    attr/                 	menyu.html

i/crlf — CRLF repoga tushib qolgan. Endi .gitattributes yaratamiz (yuqoridagi uch qator) va qaraymiz:

bash
git ls-files --eol
text
i/crlf  w/crlf  attr/text=auto eol=lf 	asosiy.css
i/crlf  w/crlf  attr/text eol=crlf    	ishga-tushir.bat
i/lf    w/lf    attr/text=auto eol=lf 	menyu.html

attr ustuni to'ldi — qoidalar ishlayapti. Lekin i/crlf o'zgarmadi. .gitattributes faqat keyingi git add larga ta'sir qiladi. Repoda allaqachon turgan fayllarni o'zi qayta yozmaydi.

5.2 Qayta normalizatsiya

Buning uchun maxsus flag bor. Rasmiy Git hujjatidagi tartib — toza ishchi papkadan:

bash
git add --renormalize .
git status -s
text
M  asosiy.css
M  ishga-tushir.bat
?? .gitattributes

--renormalize — "kuzatilayotgan hamma fayllarni yangi qoidalar bilan qaytadan qutiga sol". Ikki fayl M bo'ldi — ularning repodagi nusxasi o'zgaradi. menyu.html ro'yxatda yo'q, u allaqachon LF edi. Tekshiramiz:

text
i/lf    w/crlf  attr/text=auto eol=lf 	asosiy.css
i/lf    w/crlf  attr/text eol=crlf    	ishga-tushir.bat
i/lf    w/lf    attr/text=auto eol=lf 	menyu.html

Quti endi hamma joyda i/lf. Hammasini alohida commit qilamiz — .gitattributes bilan birga:

bash
git add .gitattributes
git commit -m "Git: qator oxirlarini LF ga keltir"

Bizning sinovda .gitattributes ni git add --renormalize dan oldin qo'shmagan edik, shuning uchun commit ikki faylni ko'rsatdi:

text
[main 9358a82] Git: qator oxirlarini LF ga keltir
 2 files changed, 4 insertions(+), 4 deletions(-)

Nega alohida commit? Bu commit har faylning har qatorini "o'zgartiradi". Uni haqiqiy o'zgarish bilan aralashtirsangiz, diff'da haqiqiy ish yo'qoladi. Alohida, aniq nomli commit esa tarixda "bu yerda faqat qator oxirlari o'zgargan" deb turadi. Kod arxeologiyasi darsida bunday commitni git blame dan yashirishni ham o'rganamiz.

5.3 Ishchi papkani yangilash

Repo toza, lekin kompyuterdagi fayllar hali w/crlf. Git ularni keyingi safar faylga tekkanda LF bilan chiqaradi. Bitta faylni hozir yangilash uchun uni o'chirib, qayta chiqarish kifoya:

bash
rm asosiy.css
git checkout -- asosiy.css
file asosiy.css
text
asosiy.css: ASCII text

with CRLF line terminators qismi yo'q — fayl endi LF. (Bu yerda git restore asosiy.css ham xuddi shunday ishlaydi.)

Butun loyihani birdan yangilash uchun ikki buyruq bor. «Bahor»da ko'rsatamiz.

6. «Bahor»ga .gitattributes

«Bahor» reposini Birinchi repo darsi oxiridagi holatdan olamiz. Windows'dagi odatiy holat — Git fayllarni bir necha marta chiqargan (Reset darsidagi reset --hard kabi) va ular CRLF bo'lib qolgan:

text
i/lf    w/crlf  attr/                 	aloqa/index.html
i/lf    w/crlf  attr/                 	assets/css/asosiy.css
i/lf    w/crlf  attr/                 	bron/index.html
i/lf    w/crlf  attr/                 	bron/rahmat.html
i/lf    w/crlf  attr/                 	index.html
i/lf    w/crlf  attr/                 	menyu/index.html

Repo toza (i/lf) — core.autocrlf=true bunga g'amxo'rlik qilgan. Lekin muammo boshqa joyda. Menyuga echo bilan qator qo'shamiz:

bash
echo "<p>Somsa — 8 000 so'm</p>" >> menyu/index.html
git add menyu/index.html
git ls-files --eol menyu/index.html
text
warning: in the working copy of 'menyu/index.html', LF will be replaced by CRLF the next time Git touches it
i/lf    w/mixed attr/                 	menyu/index.html

w/mixed — aralash! Eski qatorlar CRLF, echo qo'shgan yangi qator LF. Bitta faylda ikki xil qator oxiri. Ogohlantirishning asl sababi mana shu.

(Bu qo'shimchani bekor qildik.) Endi «Bahor» uchun to'liq .gitattributes yozamiz. VS Code'da loyiha ildizida yangi fayl oching:

text
# Matn fayllari: repoda ham, ishchi papkada ham LF
* text=auto eol=lf

# Faqat Windows'da ishlaydigan skriptlar: CRLF
*.bat text eol=crlf
*.cmd text eol=crlf

# Rasmlar va shriftlar: ichiga tegilmasin
*.png binary
*.jpg binary
*.webp binary
*.woff2 binary

# bilan boshlangan qatorlar — izoh, .gitignore dagi kabi. Hozir «Bahor»da rasm yo'q, lekin bu qoidalar oldindan turgani yaxshi. .woff2 — veb-shrift fayli (Web shriftlar darsida ishlatgansiz).

Tartib — rasmiy hujjatdagidek:

bash
git add --renormalize .
git status -s
text
?? .gitattributes

Repo allaqachon LF edi — qayta normalizatsiya qiladigan narsa yo'q. Faqat yangi fayl. Commit qilamiz:

bash
git add .gitattributes
git commit -m "Git: qator oxirlarini .gitattributes bilan tartibla"
text
[main f54f018] Git: qator oxirlarini .gitattributes bilan tartibla
 1 file changed, 12 insertions(+)
 create mode 100644 .gitattributes

Ishchi papka hali w/crlf. Git status da buni o'zgarish deb ko'rsatmaydi — mazmun bir xil. Endi hammasini birdan LF bilan qayta chiqaramiz. Bu ikki buyruq faqat toza ishchi papkada xavfsiz:

bash
git status
git rm -r --cached -q .
git reset --hard
text
On branch main
nothing to commit, working tree clean
HEAD is now at f54f018 Git: qator oxirlarini .gitattributes bilan tartibla

Birinchisi — tekshiruv: working tree clean. git rm -r --cached -q . — hamma faylni qutidan oladi (diskdagi fayllarga tegmaydi). git reset --hard — qutini va ishchi papkani oxirgi commitdan qayta to'ldiradi. Endi fayllar yangi qoida bilan chiqdi:

bash
git ls-files --eol
text
i/lf    w/lf    attr/text=auto eol=lf 	.gitattributes
i/lf    w/lf    attr/text=auto eol=lf 	aloqa/index.html
i/lf    w/lf    attr/text=auto eol=lf 	assets/css/asosiy.css
i/lf    w/lf    attr/text=auto eol=lf 	bron/index.html
i/lf    w/lf    attr/text=auto eol=lf 	bron/rahmat.html
i/lf    w/lf    attr/text=auto eol=lf 	index.html
i/lf    w/lf    attr/text=auto eol=lf 	menyu/index.html

Hamma joyda LF. Endi o'sha somsa qatorini qayta qo'shamiz:

bash
echo "<p>Somsa — 8 000 so'm</p>" >> menyu/index.html
git add menyu/index.html
git commit -m "Menyu: somsa narxini qo'sh"
text
[main 56b3259] Menyu: somsa narxini qo'sh
 1 file changed, 1 insertion(+)

git add jim qoldi — ogohlantirish yo'q! 07-qism boshidan beri chiqib turgan qator yo'qoldi. Fayl LF, qoida LF — almashtiradigan narsa yo'q.

Diqqat: git reset --hard commit qilinmagan ishni o'chiradi (Reset darsi). Ishchi papkani yangilashdan oldin doim git status — working tree clean bo'lishi shart. Shoshilmasangiz, bu qadam umuman majburiy emas: fayllar vaqt o'tib, Git ularga tekkanda o'zi LF bo'ladi.

7. Binar fayllar va diff

7.1 binary va rasm diff'i

«Bahor»ga kichik PNG fayl qo'shdik (sinov uchun bir necha baytli) va keyin uni o'zgartirdik:

bash
git diff
git diff --stat
text
diff --git a/assets/images/choy.png b/assets/images/choy.png
index b437676..a80ba77 100644
Binary files a/assets/images/choy.png and b/assets/images/choy.png differ
 assets/images/choy.png | Bin 20 -> 20 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)

Tarjimasi: "choy.png ning binar fayllari farq qiladi". Git rasmning ichini qatorma-qator ko'rsatishga urinmaydi — ma'nosi yo'q. --stat da Bin — binar, hajmi ko'rsatiladi. git ls-files --eol da esa i/-text w/-text — "matn emas".

Git ko'pincha binar faylni binary qoidasisiz ham taniydi — ichida nol bayt bo'lsa. Lekin qoida yozish ishonchliroq: ba'zi binar fayllar "matnga o'xshab" qolishi mumkin.

7.2 -diff — matn, lekin diff'siz

Ba'zi fayllar matn, lekin ularning diff'i hech kimga kerak emas. Eng mashhur misol — package-lock.json. U npm install da avtomatik yoziladi va bitta paket yangilanganda yuzlab qator o'zgaradi. Portfolio'da:

text
package-lock.json -diff

Endi fayl o'zgarganda:

text
diff --git a/package-lock.json b/package-lock.json
index e9065a1..9cafbc5 100644
Binary files a/package-lock.json and b/package-lock.json differ

Git uni "binar" deb ko'rsatdi — lekin faqat diff'da. Qator oxirlari esa text=auto bo'yicha normalizatsiya qilinaveradi, fayl commitga tushadi. -diff faqat "bu faylning ichini diff'da ochma" degani.

Maslahat: -diff ni ehtiyot bilan ishlating. package-lock.json o'zgarishini ba'zan ko'rish kerak bo'ladi (qaysi paket versiyasi o'zgardi?). Bunday paytda git diff --text package-lock.json baribir to'liq diff'ni chiqaradi.

7.3 linguist-generated — GitHub uchun

Ba'zi atributlarni Git emas, GitHub o'qiydi. docs.github.com ga ko'ra, linguist-generated belgili fayllar:

  • Pull Request (o'zgarishingizni loyihaga qo'shishni so'raydigan GitHub sahifasi) diff'larida odatiy holatda yashiriladi;
  • repo tilini hisoblashda (sahifadagi "HTML 60%, CSS 40%" kabi statistika) hisobga olinmaydi.
text
package-lock.json linguist-generated

Bu avtomatik yaratilgan fayllar (lock fayllar, yig'ilgan kod) uchun. Pull Request'larni shu qismda o'rganamiz — o'shanda bu qatorning foydasini ko'rasiz.

8. .editorconfig bilan birga

VS Code sozlamalari darsida .editorconfig ni ko'rgan edik. Unda ham qator oxiri bor:

ini
[*]
end_of_line = lf

Ikkalasi bir ishni qilyaptimi? Yo'q, ular ikki xil joyda ishlaydi:

flowchart LR
  E[".editorconfig<br/>muharrir"] --> F["Diskdagi fayl"]
  F --> G[".gitattributes<br/>git add"]
  G --> R[("Repo: LF")]
  R --> G2[".gitattributes<br/>checkout"]
  G2 --> F

Nimaga qarang: .editorconfig — muharrirga "yangi faylni LF bilan yoz" deydi (VS Code'da kengaytma kerak). .gitattributes esa Git'ning kirish va chiqish eshigida turadi: repoga nima tushishini va diskka nima chiqishini belgilaydi. Muharrir xato qilsa, Git tuzatadi. Git'dan tashqarida (masalan, fayl nusxalanganda) esa muharrir qoidasi yordam beradi.

Yaxshi loyihada ikkalasi ham bor va ikkalasida ham LF.

9. Ko'p uchraydigan xatolar

9.1 .gitattributes yaratib, --renormalize ni unutish

Qoida yozildi, lekin repodagi eski CRLF fayllar i/crlf bo'lib qoldi. Ular keyingi safar kimdir tahrirlaganda "hamma qator o'zgargan" ko'rinishida chiqadi. .gitattributes qo'shgandan keyin — har doim git add --renormalize . va git ls-files --eol bilan tekshiruv.

9.2 Normalizatsiyani ish bilan aralashtirish

"Qator oxirlari" commitiga haqiqiy o'zgarish ham qo'shilsa, u yuzlab soxta o'zgarish ichida ko'rinmay qoladi. Normalizatsiya — alohida commit.

9.3 Rasmga binary yozmaslik

* text=auto odatda rasmni taniydi. Lekin * text (auto'siz) yozsangiz, Git hamma faylni matn deb hisoblaydi va rasm baytlarini "tuzatib" buzadi. Rasm va shriftlar uchun binary qatorini doim yozing.

9.4 Yangi ogohlantirish: CRLF will be replaced by LF

.gitattributes dan keyin teskari ogohlantirishni ko'rishingiz mumkin:

text
warning: in the working copy of 'bron.html', CRLF will be replaced by LF the next time Git touches it

Tarjimasi: "bron.html ning ishchi nusxasidagi CRLF, Git keyingi safar unga tegganda, LF bilan almashtiriladi". Bu yaxshi belgi: qoida ishlayapti. Muharriringiz faylni CRLF bilan saqlagan — repoga baribir LF tushadi. Muharrirni ham LF'ga sozlang: VS Code'ning pastki o'ng burchagidagi CRLF yozuvini bosing (Qator oxiri darsidan) yoki .editorconfig qo'shing.

9.5 core.autocrlf=false qilib "tuzatish"

Ogohlantirishdan qutulish uchun sozlamani o'chirish — noto'g'ri yo'l. Ogohlantirish yo'qoladi, lekin CRLF repoga tusha boshlaydi. To'g'ri yo'l — .gitattributes.

10. Mashqlar

1-mashq (oson): ls-files --eol ni o'qing

Sinov reposidagi .gitattributes da faqat ikki qator bor: *.html text=auto eol=lf va *.png binary. git ls-files --eol natijasi:

text
i/crlf  w/crlf  attr/                 	eski.css
i/lf    w/lf    attr/text=auto eol=lf 	index.html
i/-text w/-text attr/-text            	logo.png
i/lf    w/mixed attr/text=auto eol=lf 	menyu.html

Har qator nimani anglatadi va qaysi biri muammo?

Ishora: «Tajriba» bo'limidagi ustunlar jadvali.

Yechim
  1. eski.css — muammo: CRLF repoga tushgan va CSS uchun qoida yo'q (attr/ bo'sh). .gitattributes ga * text=auto eol=lf qatorini qo'shib, git add --renormalize . qilish kerak.
  2. index.html — ideal: repoda va diskda LF, qoida bor.
  3. logo.png — to'g'ri: binar, qator oxiriga tegilmaydi.
  4. menyu.html — muammo: repoda LF va qoida bor, lekin diskdagi faylda aralash qator oxirlari (muharrir CRLF qator qo'shgan). Faylni muharrirda LF qilib saqlash kerak — keyingi git add da repoga baribir LF tushadi.

2-mashq (o'rta): .gitattributes ni to'ldiring

Loyihada HTML, CSS, deploy.sh (Linux serverda ishlaydi), build.bat (faqat Windows) va .jpg rasmlar bor. Bo'sh joylarni to'ldiring:

text
* text= eol=
*.bat text eol=
*.jpg 

deploy.sh uchun alohida qator kerakmi? Javob: (birinchi qator uni allaqachon LF qiladi).

Ishora: «Istisnolar» bo'limi — .bat va rasmlar.

Yechim
text
* text=auto eol=lf
*.bat text eol=crlf
*.jpg binary

deploy.sh birinchi qatorga mos keladi va LF bo'ladi — Linux serverga kerakli narsa. Ko'p loyihalarda baribir *.sh text eol=lf qatori aniqlik uchun yoziladi: kimdir birinchi qatorni o'zgartirsa ham, skriptlar buzilmaydi.

3-mashq (qiyin): Malikaning shikoyati

Malika (macOS) aytdi: "Aziz har commitda butun aloqa/index.html ni o'zgartiryapti, diff'da hamma qator qizil-yashil". Aziz'ning kompyuterida git config core.autocrlf buyrug'i false deb javob berdi, git ls-files --eol aloqa/index.html esa shuni:

text
i/crlf  w/crlf  attr/                 	aloqa/index.html
  1. Muammoning sababi nima?
  2. Aziz sozlamasini true qilsa, bu yetarlimi? Nega?
  3. Butun jamoa uchun to'g'ri yechim — qaysi buyruqlar, qaysi tartibda?

Ishora: «core.autocrlf — eski yechim» va «Mavjud repoda yoqish» bo'limlari.

Yechim
  1. Aziz'da almashtirish o'chiq (false), muharriri CRLF yozadi — va CRLF repoga tushib qolgan (i/crlf). Malika faylni LF bilan saqlaganda, hamma qator "o'zgaradi" va aksincha.
  2. Yetarli emas. U faqat Aziz'ning keyingi commitlarini tuzatadi. Repodagi i/crlf o'z joyida qoladi. Keyingi yangi hamkasb yana false bilan kelishi mumkin — shaxsiy sozlama hech kimni majburlamaydi.
  3. Repoda qoida va bir martalik normalizatsiya:
bash
git status
echo '* text=auto eol=lf' > .gitattributes
git add --renormalize .
git add .gitattributes
git status -s
git commit -m "Git: qator oxirlarini .gitattributes bilan tartibla"
git ls-files --eol

Oxirida hamma qator i/lf. Endi hech kimning core.autocrlf qiymati muhim emas — qoida repo bilan birga yuradi.

4-mashq: Portfolio qadami — portfolio'ga .gitattributes

Portfolio GitHub Pages'da Linux serverda ishlaydi, sizda esa Windows. Bir martalik tartibni qilamiz.

  1. kurs/portfolio da git status — ishchi papka toza bo'lsin.
  2. git ls-files --eol — qaysi fayllar w/crlf? i/crlf bormi?
  3. Loyiha ildizida .gitattributes yarating: asosiy qator, .bat istisnosi, rasmlar uchun binary (.png, .jpg, .webp, .ico) va package-lock.json -diff.
  4. git add --renormalize ., keyin git status -s. Qaysi fayllar chiqdi?
  5. .gitattributes ni qo'shing va Git: qator oxirlarini .gitattributes bilan tartibla xabari bilan commit qiling.
  6. Ishchi papkani yangilang (git status toza bo'lsa!) va git ls-files --eol bilan tekshiring.

mashqlar repo: shu darsning 1–3-mashq javoblarini mashqlar/07/13-gitattributes/javoblar.md ga yozing va commit qiling: 07/13: .gitattributes mashqlari javoblarini qo'sh.

Yechim

.gitattributes:

text
* text=auto eol=lf
*.bat text eol=crlf
*.png binary
*.jpg binary
*.webp binary
*.ico binary
package-lock.json -diff

Buyruqlar:

bash
cd ~/kurs/portfolio
git status
git ls-files --eol
git add --renormalize .
git status -s
git add .gitattributes
git commit -m "Git: qator oxirlarini .gitattributes bilan tartibla"
git status
git rm -r --cached -q .
git reset --hard
git ls-files --eol

Biz Birinchi repo darsidagi qisqa portfolio'da sinadik. Boshida fayllar i/lf w/crlf edi, --renormalize dan keyin git status -s faqat ?? .gitattributes ni ko'rsatdi. Commit:

text
[main 086fe19] Git: qator oxirlarini .gitattributes bilan tartibla
 1 file changed, 7 insertions(+)
 create mode 100644 .gitattributes

Oxirgi git ls-files --eol dan parcha:

text
i/lf    w/lf    attr/text=auto eol=lf 	.gitattributes
i/lf    w/lf    attr/text=auto eol=lf 	.gitignore
i/lf    w/lf    attr/text=auto eol=lf 	package-lock.json
i/lf    w/lf    attr/text=auto eol=lf 	sayt/index.html
...

Agar sizda 4-qadamda M belgili fayllar chiqsa — ular CRLF bilan commit qilingan ekan, ular ham shu commitga tushadi. Bu normal. landing reposi git'ga o'tganda, unga ham xuddi shu faylni qo'shasiz.

11. Real ishda

  • Deyarli har bir jiddiy ochiq loyihada .gitattributes bor. Yangi loyiha ochganingizda .gitignore bilan birga birinchi yaratiladigan fayllardan biri. Hozir qo'shilsa — hech kim qator oxirlari haqida o'ylamaydi.
  • Docker va serverlar. Windows'da yozilgan CRLF'li .sh skript Linux serverda $'\r': command not found bilan yiqiladi. eol=lf bu xatoni butunlay yo'q qiladi. Docker'ni keyingi qismlarda o'rganasiz — o'shanda bu qator sizni qutqaradi.
  • Katta binar fayllar (videolar, dizayn fayllari) uchun .gitattributes da Git LFS qoidalari yoziladi. Git LFS — katta fayllarni repodan tashqarida saqlash usuli; uni Katta repolar darsida ko'rasiz.
  • Intervyuda "Windows va Mac'dagi dasturchilar bir loyihada ishlasa, qanday muammo chiqadi va uni qanday hal qilasiz?" — bu dars aynan shu savolga javob.

Xulosa

  • Windows — CRLF, Linux va macOS — LF; farq ko'rinmas, lekin diff'ni buzadi.
  • core.autocrlf — shaxsiy sozlama, repo bilan yurmaydi; ogohlantirish shundan chiqadi.
  • .gitattributes da * text=auto eol=lf — butun jamoa uchun bitta qoida, core.autocrlf dan ustun.
  • Mavjud repoda: .gitattributes → git add --renormalize . → alohida commit; tekshiruv — git ls-files --eol.
  • Rasmlarga binary, keraksiz diff'larga -diff, GitHub uchun linguist-generated.
  • .editorconfig muharrirni, .gitattributes Git'ni boshqaradi — ikkalasi ham LF.

Keyingi dars: Kod arxeologiyasi: blame, log -S, log -L — "bu qator nega shunday yozilgan?" degan savolga tarixdan javob topamiz.

Manbalar

  • Git hujjati: "gitattributes" (text, eol, binary, diff, normalizatsiya tartibi), "git-add" (--renormalize), "git-ls-files" (--eol), "git-config" (core.autocrlf) — git-scm.com/docs
  • GitHub Docs: "Customizing how changed files appear on GitHub" (linguist-generated) — docs.github.com
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
.gitattributes va qator oxirlari: CRLF va LF muammosini hal qilish — IlmHamroh