-
1. Başlanğıc
- 1.1 Versiyaya Nəzarət Haqqında
- 1.2 Git’in Qısa Hekayəsi
- 1.3 Git Nədir?
- 1.4 Əmr Sətiri
- 1.5 Git’i Quraşdırmaq
- 1.6 İlk Dəfə Git Quraşdırması
- 1.7 Kömək Almaq
- 1.8 Qısa Məzmun
-
2. Git’in Əsasları
-
3. Git’də Branch
- 3.1 Nutshell’də Branch’lar
- 3.2 Sadə Branching və Birləşdirmə
- 3.3 Branch İdarəedilməsi
- 3.4 Branching İş Axınları
- 3.5 Uzaq Branch’lar
- 3.6 Rebasing
- 3.7 Qısa Məzmun
-
4. Server’də Git
- 4.1 Protokollar
- 4.2 Serverdə Git Əldə Etmək
- 4.3 Sizin öz SSH Public Key’nizi yaratmaq
- 4.4 Server qurmaq
- 4.5 Git Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Üçüncü Tərəf Seçimləri
- 4.10 Qısa Məzmun
-
5. Paylanmış Git
-
6. GitHub
-
7. Git Alətləri
- 7.1 Reviziya Seçimi
- 7.2 Interaktiv Səhnələşdirmə
- 7.3 Stashing və Təmizləmə
- 7.4 İşinizin İmzalanması
- 7.5 Axtarış
- 7.6 Tarixi Yenidən Yazmaq
- 7.7 Reset Demystified
- 7.8 İnkişaf etmiş Birləşmə
- 7.9 Rerere
- 7.10 Git ilə Debugging
- 7.11 Alt Modullar
- 7.12 Bundling
- 7.13 Dəyişdirmək
- 7.14 Etibarlı Yaddaş
- 7.15 Qısa Məzmun
-
8. Git’i Fərdiləşdirmək
- 8.1 Git Konfiqurasiyası
- 8.2 Git Atributları
- 8.3 Git Hook’ları
- 8.4 Git-Enforced Siyasət Nümunəsi
- 8.5 Qısa Məzmun
-
9. Git və Digər Sistemlər
- 9.1 Git Müştəri kimi
- 9.2 Git’ə Miqrasiya
- 9.3 Qısa Məzmun
-
10. Git’in Daxili İşləri
- 10.1 Plumbing və Porcelain
- 10.2 Git Obyektləri
- 10.3 Git Referansları
- 10.4 Packfile’lar
- 10.5 Refspec
- 10.6 Transfer Protokolları
- 10.7 Maintenance və Məlumatların Bərpası
- 10.8 Mühit Dəyişənləri
- 10.9 Qısa Məzmun
-
A1. Appendix A: Digər Mühitlərdə Git
- A1.1 Qrafik interfeyslər
- A1.2 Visual Studio’da Git
- A1.3 Visual Studio Code’da Git
- A1.4 Eclipse’də Git
- A1.5 Sublime Text’də Git
- A1.6 Bash’da Git
- A1.7 Zsh’də Git
- A1.8 PowerShell’də Git
- A1.9 Qısa Məzmun
-
A2. Appendix B: Proqramlara Git Daxil Etmək
- A2.1 Əmr-sətri Git
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Appendix C: Git Əmrləri
- A3.1 Quraşdırma və Konfiqurasiya
- A3.2 Layihələrin Alınması və Yaradılması
- A3.3 Sadə Snapshotting
- A3.4 Branching və Birləşmə
- A3.5 Layihələrin Paylaşılması və Yenilənməsi
- A3.6 Yoxlama və Müqayisə
- A3.7 Debugging
- A3.8 Patching
- A3.9 E-poçt
- A3.10 Xarici Sistemlər
- A3.11 İdarəetmə
- A3.12 Plumbing Əmrləri
10.7 Git’in Daxili İşləri - Maintenance və Məlumatların Bərpası
Maintenance və Məlumatların Bərpası
Bəzən bəzi təmizlik işləri görməli ola bilərsiniz - deponu daha yığcam etmək, idxal olunan deponu təmizləmək və ya itirilmiş işi bərpa etmək. Bu bölmə bu ssenarilərdən bəzilərini əhatə edəcəkdir.
Maintenance
Bəzən, Git avtomatik olaraq “auto gc” adlı bir əmr işlədir.
Çox vaxt bu əmr heç bir şey etmir.
Bununla birlikdə, bir çox boş obyekt (packfile-da olmayan obyektlər) və ya çox çox paket varsa, Git tam hüquqlu bir git gc
əmrini işə salır.
“gc” zibil yığmaq deməkdir və bu əmr bir sıra şeyləri yerinə yetirir: bütün boş obyektləri toplayır və onları paketlərə yerləşdirir, paketləri bir böyük paketə birləşdirir hər hansı bir commit-dən əlçatmaz olan və bir neçə aylıq olan obyektləri silir.
Avtomatik gc-ni aşağıdakı kimi manual olaraq işə sala bilərsiniz:
$ git gc --auto
Yenə də bu tam olaraq heç bir şey etmir.
Git-in həqiqi bir gc əmrini işə salması üçün təxminən 7,000 boş obyekt və ya 50-dən çox paketiniz olmalıdır.
Bu məhdudiyyətləri sırasıyla gc.auto
və` gc.autopacklimit` konfiqurasiya parametrləri ilə dəyişdirə bilərsiniz.
gc
-nin edəcəyi başqa bir şey, istinadlarınızı bir fayla yığmaqdır.
Tutaq ki, deponuzda aşağıdakı branch-lar və etiketlər var:
$ find .git/refs -type f
.git/refs/heads/experiment
.git/refs/heads/master
.git/refs/tags/v1.0
.git/refs/tags/v1.1
Əgər siz git gc
işlədirsinizsə, artıq bu fayllar refs
qovluğunda mövcud olmayacaq.
Git bunları effektivlik naminə belə görünən .git/packed-refs
adlı bir fayla köçürəcəkdir:
$ cat .git/packed-refs
# pack-refs with: peeled fully-peeled
cac0cab538b970a37ea1e769cbbde608743bc96d refs/heads/experiment
ab1afef80fac8e34258ff41fc1b867c702daa24b refs/heads/master
cac0cab538b970a37ea1e769cbbde608743bc96d refs/tags/v1.0
9585191f37f7b0fb9444f35a9bf50de191beadc2 refs/tags/v1.1
^1a410efbd13591db07496601ebc7a059dd55cfe9
Bir istinadı yeniləsəniz, Git bu faylı redaktə etmir, əksinə refs/heads
üçün yeni bir fayl yazır.
Müəyyən bir istinad üçün uyğun SHA-1 əldə etmək üçün Git, refs
qovluğunda həmin istinadı yoxlayır və sonra packed-refs
faylını geri yük kimi yoxlayır.
Beləliklə, refs
qovluğunda bir müraciət tapa bilmirsinizsə, ehtimal ki,packed-refs
faylınızdadır.
Faylın ^
ilə başlayan son sətirinə diqqət yetirin.
Bu o deməkdir ki, birbaşa yuxarıdakı etiket izahatlı bir etiketdir və həmin sətir izlənilmiş etiketin göstərdiyi commit-dir.
Data Recovery
Git səyahətinizin bir nöqtəsində təsadüfən bir commit-i itirə bilərsiniz. Ümumiyyətlə, bu, üzərində işləyən bir branch-ı zorla sildiyiniz üçün baş verir və nəticədə branch-ı istədiyinizi ortaya qoyur; ya da bir branch-ı yenidən sıfırlayırsınız, beləliklə bir şey istədiyiniz commit-dən imtina edirsiniz. Bunun baş verdiyini düşünsək, commit-lərinizi necə geri ala bilərsiniz?
Test anbarınızdakı master
branch-ı köhnə bir commit-ə yenidən bərpa edən və sonra itirilmiş commit-ləri bərpa edən bir nümunə göstərək.
Əvvəlcə bu deponuzun harada olduğunu nəzərdən keçirək:
$ git log --pretty=oneline
ab1afef80fac8e34258ff41fc1b867c702daa24b Modify repo a bit
484a59275031909e19aadb7c92262719cfcdf19a Create repo.rb
1a410efbd13591db07496601ebc7a059dd55cfe9 Third commit
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit
İndi, master
branch-ınızı ortadakı commit-ə köçürün:
$ git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9
HEAD is now at 1a410ef Third commit
$ git log --pretty=oneline
1a410efbd13591db07496601ebc7a059dd55cfe9 Third commit
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit
Ən yaxşı iki səmərəli işi itirmisiniz - bu commit-lərin əldə edilə biləcəyi bir branch-nız yoxdur. Ən son SHA-1 əmrini tapmalı və sonra ona işarə edən bir budaq əlavə etməlisiniz. Hiylə budur: son SHA-1 commit-ni tapmaq - bu yadınızda qalan kimi deyil, düzdür?
Çox vaxt, ən sürətli yol git reflog
adlı bir vasitə istifadə etməkdir.
İşləyərkən, Git hər dəfə dəyişdirdiyiniz zaman HEAD-in nə olduğunu səssizcə qeyd edir.
Branch-ları hər dəfə işlətdiyiniz və ya dəyişdirdiyiniz zaman reflog yenilənir.
Reflog ayrıca, Git Referansları-də qeyd etdiyimiz kimi, yalnız ref fayllarınıza SHA-1 dəyərini yazmaq əvəzinə istifadə etmək üçün başqa bir səbəb olan git update-ref
əmri ilə də yenilənir.
İstədiyiniz zaman harada olduğunuzu git reflog
çalıştırarak görə bilərsiniz:
$ git reflog
1a410ef HEAD@{0}: reset: moving to 1a410ef
ab1afef HEAD@{1}: commit: Modify repo.rb a bit
484a592 HEAD@{2}: commit: Create repo.rb
Burada yoxladığımız iki işi görə bilərik, lakin burada çox məlumat yoxdur.
Eyni məlumatları daha faydalı bir şəkildə görmək üçün, git log -g
işlədə bilərik ki, bu da reflog-unuz üçün normal bir günlük output-u təmin edəcəkdir.
$ git log -g
commit 1a410efbd13591db07496601ebc7a059dd55cfe9
Reflog: HEAD@{0} (Scott Chacon <schacon@gmail.com>)
Reflog message: updating HEAD
Author: Scott Chacon <schacon@gmail.com>
Date: Fri May 22 18:22:37 2009 -0700
Third commit
commit ab1afef80fac8e34258ff41fc1b867c702daa24b
Reflog: HEAD@{1} (Scott Chacon <schacon@gmail.com>)
Reflog message: updating HEAD
Author: Scott Chacon <schacon@gmail.com>
Date: Fri May 22 18:15:24 2009 -0700
Modify repo.rb a bit
Göründüyü kimi alt commit itirdiyiniz işdir, buna görə yeni commit yaratmaqla onu bərpa edə bilərsiniz.
Məsələn, bu əməli (ab1afef) bərpa etmək üçün recover-branch
başlada bilərsiniz:
$ git branch recover-branch ab1afef
$ git log --pretty=oneline recover-branch
ab1afef80fac8e34258ff41fc1b867c702daa24b Modify repo.rb a bit
484a59275031909e19aadb7c92262719cfcdf19a Create repo.rb
1a410efbd13591db07496601ebc7a059dd55cfe9 Third commit
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit
Əla - indi recovery-branch
adlı bir branch-nız var, əvvəllər master
branch-nızın olduğu yerlərdə ilk iki iş yenidən əlçatandır.
Bundan sonra, itkinizin bir səbəbdən reflog-da olmadığını düşünək – bunu recovery-branch
-nı çıxarıb təkrar qeydini silməklə simulyasiya edə bilərsiniz.
İndi ilk iki commit-ə heç bir şey çatmır:
$ git branch -D recover-branch
$ rm -Rf .git/logs/
Reflog məlumatları .git/logs/
qovluğunda saxlanıldığından, sizdə heç bir reflog yoxdur.
Bu anda bu işi necə bərpa edə bilərsiniz?
Bir üsul, verilənlər bazanızın bütövlüyünü yoxlayan git fsck
yardım proqramından istifadə etməkdir.
Bunu --full
seçimi ilə işə salırsınızsa, başqa bir obyekt tərəfindən göstərilməyən bütün obyektləri göstərir:
$ git fsck --full
Checking object directories: 100% (256/256), done.
Checking objects: 100% (18/18), done.
dangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4
dangling commit ab1afef80fac8e34258ff41fc1b867c702daa24b
dangling tree aea790b9a58f6cf6f2804eeac9f0abbe9631e4c9
dangling blob 7108f7ecb345ee9d0084193f147cdad4d2998293
Bu vəziyyətdə, “dangling commit” sətrindən sonra itkin commit-nizi görə bilərsiniz. Eyni SHA-1-ə işarə edən bir qol əlavə edərək onu eyni şəkildə bərpa edə bilərsiniz.
Obyektlərin Silinməsi
Git haqqında çox yaxşı şey var, amma bu problemə səbəb ola biləcək bir xüsusiyyətdir, yəni, bir git clone
-un hər faylın hər versiyası da daxil olmaqla layihənin bütün tarixini yükləməsidir.
Bu əgər mənbə kodu olarsa yaxşıdır, çünki Git bu məlumatları səmərəli şəkildə sıxmaq üçün yüksək dərəcədə optimize edilmişdir.
Bununla birlikdə, layihənizin tarixinin hər hansı bir nöqtəsində kimsə tək bir nəhəng fayl əlavə etsə, bütün klonlar, sonrakı commit-lərdə layihədən çıxarılan olsa da, bütün zaman üçün bu klonu yükləmək məcburiyyətində qalacaq.
Tarixdən əlçatan olduğundan həmişə mövcud olacaq.
Subversion və ya Perforce depolarını Git-ə çevirdiyiniz zaman bu böyük bir problem ola bilər. Bu sistemlərdəki bütün tarixi yükləmədiyiniz üçün bu əlavə bir neçə nəticəyə səbəb olur. Başqa bir sistemdən idxal etmisinizsə və ya başqa bir şəkildə deponuzun lazım olduğundan daha böyük olduğunu görmünüzsə, burada böyük obyektləri necə tapa və silə biləcəyinizi görə bilərsiniz.
Xəbərdarlıq: bu texnika sizin commit tarixçəniz üçün dağıdıcıdır. O, böyük bir fayl arayışını silmək üçün dəyişdirməli olduğunuz ilk ağacdan bəri hər bir commit obyektini yenidən yazır. Bunu idxaldan dərhal sonra, kimsə işin commit üzərində qurulmasına başlamazdan əvvəl etsəniz, yaxşıdır - əks halda, bütün dəstəkçilərinizə işlərini yeni commit-lərinizə qaytarmaları lazım olduğunu bildirməlisiniz.
Nümayiş üçün test deponuza böyük bir fayl əlavə edəcək, növbəti commit-də götürüb tapacaqsınız və depodan qalıcı olaraq çıxaracaqsınız. Əvvəlcə tarixçənizə böyük bir obyekt əlavə edin:
$ curl https://www.kernel.org/pub/software/scm/git/git-2.1.0.tar.gz > git.tgz
$ git add git.tgz
$ git commit -m 'Add git tarball'
[master 7b30847] Add git tarball
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 git.tgz
Vay - layihənizə böyük bir tarball əlavə etmək istəmirdiniz. Ən yaxşısı bundan yaxa qurtarmaq üçün:
$ git rm git.tgz
rm 'git.tgz'
$ git commit -m 'Oops - remove large tarball'
[master dadf725] Oops - remove large tarball
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 git.tgz
İndi, məlumat bazanızı gc
edin və nə qədər yer istifadə etdiyinizi görün:
$ git gc
Counting objects: 17, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (13/13), done.
Writing objects: 100% (17/17), done.
Total 17 (delta 1), reused 10 (delta 0)
Nə qədər yer istifadə etdiyinizi görmək üçün count-objects
əmrini işə sala bilərsiniz:
$ git count-objects -v
count: 7
size: 32
in-pack: 17
packs: 1
size-pack: 4868
prune-packable: 0
garbage: 0
size-garbage: 0
Size-pack
girişi paketlərinizin kilobayt ölçüsündədir, buna görə demək olar ki, 5MB istifadə edirsiniz.
Son commit-dən əvvəl, 2K-a yaxın istifadə edirdiniz - açıq şəkildə, əvvəlki commit-dən faylın silinməsi tarixçənizdən silinmədi.
Hər kəs bu deponu klonladıqda, yalnız bu kiçik layihəni əldə etmək üçün bütün 5 MB-ı klonlamalı olacaq, çünki siz təsadüfən böyük bir fayl əlavə etmisiniz.
Gəlin bundan qurtulaq.
Əvvəlcə onu tapmaq lazımdır.
Bu vəziyyətdə, bunun hansı fayl olduğunu artıq bilirsiniz.
Ancaq güman etmədiniz ki; hansı fayl və ya sənədlərin bu qədər yer tutduğunu necə müəyyənləşdirərdiniz?
git gc
-i işlədirsinizsə, bütün obyektlər packfile-dadır; böyük obyektləri git verify-pack
adlı başqa bir plumbing əmrini işə salmaqla və sənəddəki fayl ölçüsü olan üçüncü sahəyə görə ayırmaqla təyin edə bilərsiniz.
Yalnız son bir neçə ən böyük sənədlə maraqlandığınız üçün onu tail
əmri ilə ötürə bilərsiniz:
$ git verify-pack -v .git/objects/pack/pack-29…69.idx \
| sort -k 3 -n \
| tail -3
dadf7258d699da2c8d89b09ef6670edb7d5f91b4 commit 229 159 12
033b4468fa6b2a9547a70d88d1bbe8bf3f9ed0d5 blob 22044 5792 4977696
82c99a3e86bb1267b236a4b6eff7868d97489af1 blob 4975916 4976258 1438
Aşağıdakı böyük obyekt: 5 MB.
Hansı fayl olduğunu tapmaq üçün qısa müddətdə Xüsusi bir Commit-Mesaj Formatının Tətbiq Edilməsi-da istifadə etdiyiniz rev-list
əmrini istifadə edəcəksiniz.
--objects
-i rev-list
-ə keçirsəniz, bütün SHA-1’ləri və bunlarla əlaqəli fayl yolları ilə blob SHA-1’ləri siyahıya alır.
Blob adınızı tapmaq üçün bundan istifadə edə bilərsiniz:
$ git rev-list --objects --all | grep 82c99a3
82c99a3e86bb1267b236a4b6eff7868d97489af1 git.tgz
İndi keçmişdəki bütün ağaclardan bu faylı silməlisiniz. Bu faylı hansı commit-in dəyişdirdiyini asanlıqla görə bilərsiniz:
$ git log --oneline --branches -- git.tgz
dadf725 Oops - remove large tarball
7b30847 Add git tarball
Bu faylı Git tarixinizdən tamamilə silmək üçün 7b30847
-dən aşağıda olan bütün commit-ləri yenidən yazmalısınız.
Bunu etmək üçün Tarixi Yenidən Yazmaq-də istifadə etdiyiniz filter-branch
-dan istifadə edirsiniz:
$ git filter-branch --index-filter \
'git rm --ignore-unmatch --cached git.tgz' -- 7b30847^..
Rewrite 7b30847d080183a1ab7d18fb202473b3096e9f34 (1/2)rm 'git.tgz'
Rewrite dadf7258d699da2c8d89b09ef6670edb7d5f91b4 (2/2)
Ref 'refs/heads/master' was rewritten
--index-filter
seçimi, Tarixi Yenidən Yazmaq-də istifadə olunan --tree-filter
seçiminə bənzəyir, yalnız diskdə qeyd edilmiş sənədləri dəyişdirən bir əmr ötürmək əvəzinə, hər dəfə quruluş sahənizi və ya indeksinizi dəyişdirirsiniz.
Müəyyən bir faylı rm file
kimi bir şeylə silmək əvəzinə, git rm --cached
ilə silməlisiniz - diskdən yox, indeksdən çıxarmalısınız.
Bunu bu şəkildə etməyinizin səbəbi sürətdir - çünki Git filterinizi işə salmadan əvvəl diskdəki hər bir düzəlişə baxmaq məcburiyyətində qalmadığı üçün proses çox daha sürətli ola bilər.
Həmin tapşırığı --tree-filter
ilə də yerinə yetirə bilərsiniz.
git rm
seçimi üçün --ignore-unmatch
seçimi, silmək istədiyiniz şablonun olmadığı təqdirdə səhv etməməsini tələb edir.
Nəhayət, filter-branch
-dan tarixinizi yalnız 7b30847
commit-indən yenidən yazmasını xahiş edirsiniz, çünki bu problemin burada başladığını bilirsiniz.
Əks təqdirdə, başlanğıcdan başlayacaq və lazımsız olaraq daha uzun çəkəcəkdir.
Tarixinizdə artıq həmin fayla istinad yoxdur.
Bununla birlikdə reflogunuz və Git-in .git/refs/original
altında filter-branch
etdiyiniz zaman əlavə etdiyi yeni bir refs dəsti hələ də mövcuddur, buna görə onları silməli və sonra verilənlər bazasını yenidən paketləməlisiniz.
Yenidən qablaşdırmadan əvvəl bu köhnə commit-lərə işarə edən bir şeydən qurtulmalısınız:
$ rm -Rf .git/refs/original
$ rm -Rf .git/logs/
$ git gc
Counting objects: 15, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (15/15), done.
Total 15 (delta 1), reused 12 (delta 0)
Gəlin nə qədər yer saxladığınıza baxaq:
$ git count-objects -v
count: 11
size: 4904
in-pack: 15
packs: 1
size-pack: 8
prune-packable: 0
garbage: 0
size-garbage: 0
Paketlənmiş depo ölçüsü 8K-a qədərdir, bu da 5MB-dən daha yaxşıdır.
Ölçü dəyərindən görə bilərsiniz ki, böyük obyekt hələ də boş obyektlərinizdədir, buna görə də getməyib; lakin vacib olan odur ki, o, push və ya sonrakı bir klon üzərinə köçürülməyəcəkdir.
Həqiqətən istəsəniz, --expire
seçimi ilə git prune
düyməsini basaraq obyekti tamamilə silə bilərsiniz:
$ git prune --expire now
$ git count-objects -v
count: 0
size: 0
in-pack: 15
packs: 1
size-pack: 8
prune-packable: 0
garbage: 0
size-garbage: 0