Maqolalar 17 daqiqa 48 ko‘rish
Git yadrosi: plumbing buyruqlari bilan ichkaridan
Git'ning quyi darajadagi (plumbing) buyruqlari: update-index, write-tree, commit-tree, update-ref, diff-files, diff-index, ls-files --unmerged. Commit qo‘lda qanday yaratilishi, merge ichkaridan qanday ishlashi va repozitoriyni pack qilish.
Mundarija
- Nomi
- Qisqacha ishlatilishi
- Tavsif
- Git repozitoriysini yaratish
- Repozitoriyni ma’lumot bilan to‘ldirish
- Git holatini commit qilish
- O‘zgartirish kiritish
- O‘zgarishlarni tekshirish
- Versiyaga teg qo‘yish
- Repozitoriylarni nusxalash
- Yangi branch yaratish
- Ikki branchni birlashtirish
- Tashqi ishni birlashtirish
- Merge qanday ishlaydi?
- Ishingizni e’lon qilish
- Repozitoriyni pack qilish
- Boshqalar bilan ishlash
- Umumiy repozitoriy uslubi
- Ishlarni birlashtirish
- Shuningdek qarang
- Git to‘plami
- Izoh
Yuqori darajadagi buyruq kutilganidek ishlamasa, ostida nima borligini bilish yordam beradi. Bu bo‘lim git commit o‘rniga write-tree va commit-tree bilan commitni qo‘lda yasab ko‘rsatadi. Eng chuqur bo‘lim — kundalik ish uchun shart emas, lekin Git'ni tushunish uchun eng foydalisi.
Bu ma’lumotnoma, dars emas
Bu qism Git'ning rasmiy qo‘llanmasi (git help core-tutorial, Git 2.50.1) asosida
o‘zbekchaga o‘girilgan. Ketma-ket bajariladigan dars emas: kerak
bo‘lganda ochib, kerakli joyini o‘qiysiz. Git'ni noldan o‘rganmoqchi
bo‘lsangiz, avval Git va GitHub darslarini
bajaring.
Bu qo‘llanma Git’ning quyi darajadagi (plumbing) mexanizmlarini tushuntiradi. Buyruqlar asl yozilishida saqlangan.
Nomi#
gitcore-tutorial — dasturchilar uchun Git yadrosi bo‘yicha qo‘llanma.
Qisqacha ishlatilishi#
git *
Tavsif#
Bu qo‘llanma Git repozitoriysini yaratish va u bilan ishlashda Git’ning core buyruqlaridan foydalanishni tushuntiradi.
Agar Git’dan faqat versiya nazorati tizimi sifatida foydalanmoqchi bo‘lsangiz, avval gittutorial(7) yoki Git User Manual dan boshlashingiz ma’qul. Ammo Git ichki tuzilishini tushunishda quyi darajadagi vositalarni bilish foydalidir.
Git yadrosi ko‘pincha plumbing (“quvurlar”), uning ustidagi qulay foydalanuvchi interfeyslari esa porcelain (“santexnika jihozlari”) deb ataladi. Plumbing buyruqlarini tez-tez bevosita ishlatmasangiz ham, yuqori darajadagi buyruq kutilganidek ishlamasa, ular nima qilishini bilish foydali.
Hujjat dastlab yozilganda ko‘p porcelain buyruqlari shell skriptlari edi. Soddalik uchun ular plumbing buyruqlari qanday birlashtirilishini ko‘rsatishda hanuz misol sifatida ishlatiladi. Ayrim eski skriptlar manba daraxtidagi contrib/examples/ da mavjud. Hozir ular shell skripti bo‘lmasa ham, plumbing qatlamining tavsifi to‘g‘ri.
Izoh
Chuqur texnik tafsilotlar “Izoh” sifatida ajratiladi; birinchi o‘qishda ularni tashlab ketishingiz mumkin.
Git repozitoriysini yaratish#
Har bir Git repozitoriysi bo‘sh holatdan boshlanadi. Yangi loyiha uchun bo‘sh yoki Git’ga import qilinadigan mavjud ishchi katalogni tanlang:
mkdir git-tutorial
cd git-tutorial
git init
Initialized empty Git repository in .git/
Git mahalliy .git katalogini yaratadi. Undagi muhim qismlar:
-
HEAD— odatdaref: refs/heads/masterni saqlaydi va joriy branchga ramziy murojaat qiladi. Birinchi commitgacha murojaat qilinayotgan fayl mavjud bo‘lmasligi tabiiy. -
objects/— loyihaning haqiqiy ma’lumotlarini saqlovchi barcha obyektlar katalogi. -
refs/— obyektlarga murojaatlar katalogi. Uningheads/qismi branchlarga,tags/qismi teglar orqali nomlangan versiyalarga murojaatlarni saqlaydi.
master tarixiy standart branch nomidir, ammo bu faqat kelishuv: branchga istalgan nom berish mumkin. Muhimi, .git/HEAD haqiqiy joriy branchga ishora qilsin.
Obyekt 160 bitli SHA-1 xeshi bilan aniqlanadi. Obyektga murojaat uning 40 belgili o‘n oltilik ko‘rinishidir.
refsostidagi fayllar odatda shu qiymat va yakuniy yangi satrdan iborat bo‘ladi.
Repozitoriy tuzilishining chuqur tavsifi uchun gitrepository-layout(5) ga qarang.
Repozitoriyni ma’lumot bilan to‘ldirish#
Ikki oddiy fayl yarating:
echo "Hello World" >hello
echo "Silly example" >example
Ularni Git’ga yozish ikki bosqichdan iborat:
- Ishchi daraxt holati bilan index (yoki cache) ni to‘ldirish.
- Indeksni obyekt sifatida commit qilish.
Plumbing darajasida indeksni yangilash:
git update-index --add hello example
update-index tasodifiy xatolardan himoyalanish uchun yangi yozuvda --add, o‘chirishda --remove ni ochiq ko‘rsatishni talab qiladi. Buyruq fayl tarkibini obyektlar bazasiga yozib, indeksga murojaat qo‘shadi.
ls .git/objects/??/*
.git/objects/55/7db03de997c86a4a028e1ebd3a1ceb225be238
.git/objects/f2/4c74a2e500f5ee1332c86b94199f52b1d1d962
Obyekt turini va tarkibini ko‘rish:
git cat-file -t 557db03de997c86a4a028e1ebd3a1ceb225be238
blob
git cat-file blob 557db03
Hello World
557db03... obyekti hello faylining ayni paytdagi tarkibidir.
Obyektni faylning o‘zi bilan adashtirmang. Obyekt faqat muayyan tarkibni saqlaydi. Fayl keyin o‘zgarsa ham eski obyekt o‘zgarmaydi — Git obyektlari immutable, ya’ni o‘zgarmasdir.
update-index .git/index faylini ham yaratadi. Bu joriy ishchi daraxtni tavsiflaydi. Hali fayllarni commit qilmadik; faqat Git’ga ular haqida xabar berdik.
hello ni o‘zgartirib, indeksdagi holat bilan farqini ko‘ramiz:
echo "It's a new day for git" >>hello
git diff-files -p
diff --git a/hello b/hello
index 557db03..263414f 100644
--- a/hello
+++ b/hello
@@ -1 +1,2 @@
Hello World
+It's a new day for git
git diff-files indeksdagi holat bilan ishchi daraxtni solishtiradi. Uning keng ishlatiladigan qisqartmasi:
git diff
Git holatini commit qilish#
Indeksdagi fayllarni haqiqiy tree sifatida commit qilish ikki bosqichda bajariladi:
treeobyekti yaratish.- Tree va uning izohidan
commitobyekti yaratish.
git write-tree
8988da15d077d4829fc51d8544c097def6644dbb
git write-tree joriy indeksning barchasini tasvirlovchi tree obyektini yozadi; fayl nomlari, tarkibi va ruxsatlarini bir-biriga bog‘laydi.
Birinchi commitning parent’i yo‘q. commit-tree commit xabarini standart kirishdan oladi va commit obyektining nomini standart chiqishga yozadi:
tree=$(git write-tree)
commit=$(echo 'Initial commit' | git commit-tree $tree)
git update-ref HEAD $commit
Bu buyruqlar indeksdan tree, undan commit yaratadi va HEAD murojaatini yangi commitga yangilaydi. Buni loyihada qo‘lda faqat birinchi commit uchun bajarish mumkin; keyingi commitlar oldingi commitning farzandi bo‘ladi.
Amalda bu ishlarning barchasini porcelain buyrug‘i bajaradi:
git commit
O‘zgartirish kiritish#
hello indeksga kiritilgandan keyin o‘zgartirilgan edi. write-tree ishchi katalogni emas, indeksni yozgani sababli commitda eski tarkib saqlandi. Bu indeks holati, ishchi daraxt va commit qilingan tree bir xil bo‘lishi shart emasligini ko‘rsatadi.
git diff-index -p HEAD
# qisqa porcelain ko‘rinishi:
git diff HEAD
diff-files indeks bilan ishchi daraxtni, diff-index esa commit qilingan tree bilan indeks yoki ishchi daraxtni solishtiradi.
git diff-index --cached -p HEAD
--cached tree’ni faqat indeks bilan solishtirib, ishchi daraxt tarkibini e’tiborsiz qoldiradi. Hozir indeks aynan HEAD ga yozilgani uchun natija bo‘sh.
Texnik jihatdan
diff-indexdoim fayllar ro‘yxati va metama’lumotni indeksdan oladi.--cachedfaqat solishtiriladigan fayl tarkibi ishchi daraxtdan olinishi yoki olinmasligini belgilaydi. Git unga ochiq aytilmagan fayllarni qidirmaydi; kuzatiladigan fayllar ro‘yxati indeksda turadi.
Ishchi daraxtdagi o‘zgarishni commit qilish uchun avval indeksni yangilang:
git update-index hello
git diff-files -p
git diff-index -p HEAD
git diff-index --cached -p HEAD
Endi diff-files bo‘sh, chunki indeks va ishchi daraxt mos. diff-index hamda uning --cached ko‘rinishi esa HEAD dan farqni ko‘rsatadi.
Yangi commitni plumbing buyruqlari bilan yaratish:
tree=$(git write-tree)
new_commit=$(echo 'Update hello' | git commit-tree $tree -p HEAD)
git update-ref HEAD $new_commit
-p HEAD oldingi commitni yangi commitning parent’i qiladi. Oddiy ishda buning o‘rniga git commit ishlatiladi.
O‘zgarishlarni tekshirish#
git diff-tree ikkita tree yoki commit orasidagi farqni ko‘rsatadi:
git diff-tree -p HEAD^
git diff-tree -p HEAD^ HEAD
Bitta commit berilganda uning parent’i bilan solishtiriladi. -p farqni patch shaklida ko‘rsatadi.
Commit ma’lumotini tekshirish:
git cat-file commit HEAD
git show HEAD
git show commit metama’lumoti va patchni birga chiqaruvchi qulay porcelain buyrug‘idir. Tarixni ko‘rish:
git log
git log --stat
git log -p
Plumbing nuqtayi nazaridan Git tarix bo‘ylab har bir commitning parent murojaatini kuzatib yuradi.
Versiyaga teg qo‘yish#
SHA-1 nomlarini eslab qolish noqulay. Muayyan commitga tushunarli nom — teg — berish mumkin:
git tag my-first-tag HEAD
Bu .git/refs/tags/my-first-tag murojaatini yaratadi. Endi commitga teg orqali murojaat qilinadi:
git diff my-first-tag HEAD
git show my-first-tag
Oddiy (lightweight) teg bevosita obyektga murojaatdir. Izohli teg alohida tag obyekti bo‘lib, muallif, sana, xabar va ixtiyoriy kriptografik imzoni saqlaydi:
git tag -a v1.0 -m "Version 1.0"
git tag -s v1.0-signed
Batafsil ma’lumot: git-tag(1).
Repozitoriylarni nusxalash#
Git repozitoriysi barcha tarix va obyektlarni o‘z ichiga olgani sababli uni klonlash mumkin:
cd ..
git clone git-tutorial git-tutorial-copy
Klon alohida, to‘liq repozitoriy bo‘lib, asl tarixning o‘z nusxasiga ega. Git odatda asl manzilni origin nomli remote sifatida saqlaydi:
git config --get remote.origin.url
git branch -r
Mahalliy yo‘l, SSH yoki HTTP kabi qo‘llab-quvvatlanadigan transportlar orqali klonlash mumkin.
Yangi branch yaratish#
Branch shunchaki commitga siljiydigan murojaatdir:
git branch mybranch
git switch mybranch
Plumbing darajasida yangi ref yaratib, HEAD ni unga ramziy bog‘lash mumkin, ammo amalda git branch va git switch xavfsizroq hamda qulayroq.
Branchda o‘zgarish qiling:
echo "Work on my branch" >>hello
git commit -a -m "Work in mybranch"
mybranch yangi commitga siljiydi, boshqa branch esa avvalgi commitda qoladi. Branchlar o‘rtasida o‘tishda Git tree’ni indeks va ishchi katalogga chiqaradi.
git switch master
git switch mybranch
Branchlar va umumiy tarixni ko‘rish:
git show-branch
git log --all --graph --oneline
Ikki branchni birlashtirish#
Ikki branch mustaqil rivojlangach, biridagi ishni boshqasiga merge qilish mumkin:
git switch master
git merge mybranch
Agar joriy branch merge qilinayotgan branchning ajdodi bo‘lsa, fast-forward yuz beradi: yangi commit yaratilmaydi, joriy ref oldinga siljiydi.
Ikkala tomon ham o‘zgargan bo‘lsa, Git uch tomonlama merge bajaradi:
- umumiy ajdod — merge base;
- joriy branch uchi — “ours”;
- qo‘shilayotgan branch uchi — “theirs”.
Natija odatda ikki parentli merge commit bo‘ladi:
git merge -m "Merge mybranch" mybranch
Tashqi ishni birlashtirish#
Boshqa repozitoriydagi ishni olish ikki bosqichdan iborat:
git fetch <repository> <branch>
git merge FETCH_HEAD
fetch kerakli obyektlarni yuklaydi va olingan branch uchini FETCH_HEAD da qayd etadi. merge uni joriy branch bilan birlashtiradi. Ikkalasining qulay birikmasi:
git pull <repository> <branch>
Takror ishlatiladigan manzilga remote nomi beriladi:
git remote add origin <repository>
git fetch origin
git merge origin/master
# yoki
git pull origin master
fetch xavfsiz: u joriy ishchi daraxtni merge qilmaydi. Olingan o‘zgarishlarni avval tekshirish mumkin:
git log HEAD..FETCH_HEAD
git diff HEAD...FETCH_HEAD
Merge qanday ishlaydi?#
Git avval merge base’ni topadi, keyin uchta tree’ni o‘qiydi:
stage 1 — umumiy ajdod (base)
stage 2 — joriy branch (ours)
stage 3 — qo‘shilayotgan branch (theirs)
Toza birlashadigan yo‘llar indeksning stage 0 holatiga yoziladi. Konfliktli yo‘llarda indeks 1, 2 va 3-bosqich obyektlarini saqlaydi:
git ls-files --unmerged
git ls-files --stage
100644 <base-object> 1 hello
100644 <our-object> 2 hello
100644 <their-object> 3 hello
Ishchi faylda konflikt belgilari paydo bo‘ladi:
<<<<<<< HEAD
joriy branchdagi matn
=======
boshqa branchdagi matn
>>>>>>> other-branch
Faylni tahrirlab to‘g‘ri natijani qoldiring, konflikt belgilarini olib tashlang va hal qilingan faylni indeksga qo‘shing:
git add hello
git commit
git add stage 1–3 yozuvlarini bitta stage 0 yozuvi bilan almashtiradi. Merge’dan voz kechish:
git merge --abort
Konflikt vaqtida farqlarni ko‘rish uchun git diff, git diff --ours, git diff --theirs va git diff --base kabi ko‘rinishlar foydali.
Ishingizni e’lon qilish#
Boshqalar sizdan o‘zgarishlarni olishi uchun odatda alohida ochiq repozitoriy tayyorlanadi. Asosiy ish .git ostidagi shaxsiy repozitoriyda bajariladi; sifatli holatga kelgan o‘zgarishlar ochiq repozitoriyga push qilinadi.
Masofaviy kompyuterda bo‘sh repozitoriy yarating:
mkdir my-git.git
GIT_DIR=my-git.git git init
Hozirgi tavsiya etiladigan ekvivalent:
git init --bare my-git.git
Masofaviy repozitoriy tanlangan transport orqali boshqalarga ochiq bo‘lishi, yozish uchun esa sizda ruxsat bo‘lishi kerak. SSH orqali push ichkarida mahalliy git send-pack va masofaviy git-receive-pack ni bog‘laydi.
Mahalliy mashinadan yuborish:
git push <public-host>:/path/to/my-git.git master
Bu ochiq repozitoriyning master uchini va undan erishiladigan obyektlarni mahalliy repozitoriy bilan sinxronlaydi.
Eski “dumb HTTP” orqali tarqatishda
post-updatehook vagit update-server-infotalab qilinishi mumkin. Zamonaviy smart HTTP serverlarida bu odatda kerak emas.
Repozitoriyni pack qilish#
Har bir yangi Git obyekti dastlab .git/objects/??/ ostida alohida loose object sifatida saqlanadi. Bu xavfsiz va atomar yaratish uchun qulay, ammo tarmoq orqali tashish uchun samarasiz. O‘zgarmas obyektlarni bitta pack ichiga zichlash mumkin:
git repack
.git/objects/pack/ ichida o‘zaro bog‘liq ikkita fayl paydo bo‘ladi:
pack-*.pack— obyektlarning siqilgan ma’lumoti;pack-*.idx— obyektlarga tezkor murojaat qilish indeksi.
Ularni qo‘lda nusxalash zarur bo‘lsa, har doim birga nusxalang. Pack butunligini tekshirish:
git verify-pack .git/objects/pack/pack-*.idx
Pack ichida mavjud loose obyektlarni olib tashlash:
git prune-packed
Holatni tekshirish:
find .git/objects -type f
git count-objects -v
Faol loyihani vaqti-vaqti bilan repack qilish saqlash joyi va uzatishni optimallashtiradi. Amalda kundalik texnik xizmatni ko‘pincha quyidagi porcelain buyruq boshqaradi:
git gc
Boshqalar bilan ishlash#
Git to‘liq taqsimlangan tizim bo‘lsa-da, loyihani norasmiy dasturchilar iyerarxiyasi bilan tashkil qilish qulay. Git bu iyerarxiyani majburlamaydi; faqat bitta repozitoriydan olish shart emas.
Loyiha rahbari uchun tavsiya etilgan jarayon#
- Mahalliy asosiy ish repozitoriysini tayyorlang.
- Boshqalarga ochiq public repozitoriy yarating.
- Asosiy repozitoriydan public repozitoriyga push qiling.
- Public repozitoriyni repack qiling; transport mos bo‘lsa, keraksiz obyektlarni tozalang.
- O‘z o‘zgarishlaringiz, email patchlari va subsystem maintainer repozitoriylaridan merge’lar bilan ishlashda davom eting.
- Tayyor o‘zgarishlarni public repozitoriyga push qilib, e’lon qiling.
- Vaqti-vaqti bilan public repozitoriyni repack qiling va ishni davom ettiring.
Subsystem maintainer uchun jarayon#
- Loyiha rahbarining public repozitoriysini klonlang.
- O‘zingizning public repozitoriyingizni tayyorlang.
- Zarur bo‘lsa pack fayllar yoki
objects/info/alternatesorqali obyektlarni ulashing. - Asosiy ish repozitoriysidan public repozitoriyga push va repack qiling.
- O‘z ishlaringiz, email patchlari, rahbar va quyi maintainer repozitoriylaridan merge’lar bilan davom eting.
- O‘zgarishlarni public repozitoriyga push qilib, rahbaringizdan ularni pull qilishni so‘rang.
- Vaqti-vaqti bilan repack qiling.
Public repozitoriysiz individual dasturchi uchun jarayon#
- Rahbar yoki subsystem maintainer public repozitoriysini klonlang.
- O‘z branchingizda ishlang.
-
Vaqti-vaqti bilan upstream’dan faqat o‘zgarishlarni oling:
console $ git fetch origin -
Patchlardan qaysilari qabul qilinganini ko‘ring yoki qolganlarini yangi upstream ustiga ko‘chiring:
console $ git cherry origin/master $ git rebase origin/master -
Email orqali yuborish uchun patchlar tayyorlang:
console $ git format-patch origin/master
Umumiy repozitoriy uslubi#
CVS’dan kelgan foydalanuvchilarga yuqoridagi hamkorlik usuli yangi tuyulishi mumkin. Git bir nechta foydalanuvchi bevosita bitta umumiy public repozitoriyga yozadigan uslubni ham qo‘llaydi. Batafsil ma’lumot uchun gitcvs-migration(7) ga qarang.
Umumiy repozitoriy odatda guruh ruxsatlari bilan yaratiladi:
git init --bare --shared project.git
Serverdagi ruxsatlar va branch himoyasi kim push qila olishini boshqarishi kerak.
Ishlarni birlashtirish#
Bir vaqtning o‘zida bir nechta mustaqil vazifa ustida ishlashda branchlardan foydalanish qulay. Holat:
git show-branch
! [commit-fix] Fix commit message normalization.
! [diff-fix] Fix rename detection.
* [master] Release candidate #1
---
+ [diff-fix] Fix rename detection.
+ [diff-fix~1] Better common substring algorithm.
+ [commit-fix] Fix commit message normalization.
* [master] Release candidate #1
++* [diff-fix~2] Pretty-print messages.
Ikki tuzatishni ketma-ket merge qilish mumkin:
git merge -m "Merge fix in diff-fix" diff-fix
git merge -m "Merge fix in commit-fix" commit-fix
Agar o‘zgarishlar haqiqatan mustaqil bo‘lsa, bir nechta branchni birdan merge qilish — octopus merge — mumkin. Avval misoldagi ikki merge’dan oldingi holatga qaytish:
git reset --hard master~2
git merge commit-fix diff-fix
Natijada uch parentli merge commit yaratiladi:
git show-branch
! [commit-fix] Fix commit message normalization.
! [diff-fix] Fix rename detection.
* [master] Octopus merge of branches 'diff-fix' and 'commit-fix'
Octopus merge’ni shunchaki mumkin bo‘lgani uchun ishlatmang. U bir vaqtning o‘zida ikkitadan ortiq mustaqil va konfliktsiz o‘zgarishni birlashtirganda tarixni soddalashtiradi. Konflikt chiqsa, branchlar aslida mustaqil emas. Ularni ikkitadan merge qilib, konflikt qanday va nima sababli hal qilinganini commit tarixida hujjatlashtiring.
Shuningdek qarang#
gittutorial(7), gittutorial-2(7), gitcvs-migration(7), git-help(1), giteveryday(7), The Git User’s Manual.
Git to‘plami#
git(1) buyruqlar to‘plamining bir qismi.
Izoh#
- The Git User Manual:
git-htmldocs/user-manual.html - Randy Dunlap taqdimoti:
https://web.archive.org/web/20120915203609/http://www.xenotime.net/linux/mentor/linux-mentoring-2006.pdf