-
1. Başlangıç
- 1.1 Sürüm Denetimi
- 1.2 Git’in Kısa Tarihçesi
- 1.3 Git Nedir?
- 1.4 Komut Satırı
- 1.5 Git’i Yüklemek
- 1.6 Git’i İlk Defa Kurmak
- 1.7 Yardım Almak
- 1.8 Özet
-
2. Git Temelleri
-
3. Git Dalları
- 3.1 Dallar
- 3.2 Kısaca Dallandırma ve Birleştirme Temelleri
- 3.3 Dal Yönetimi
- 3.4 İş Akışı Dallandırması
- 3.5 Uzak Dallar
- 3.6 Yeniden Temelleme (rebase)
- 3.7 Özet
-
4. Bir Sunucuda Git Kurma
- 4.1 İletişim Kuralları (Protocols)
- 4.2 Bir Sunucuda Git Kurma
- 4.3 SSH Ortak Anahtarınızı Oluşturma
- 4.4 Sunucu Kurma
- 4.5 Git Cini (Daemon)
- 4.6 Akıllı HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Üçüncü Taraf Barındırma (Hosting) Seçenekleri
- 4.10 Özet
-
5. Dağıtık Git
- 5.1 Dağıtık İş Akışları
- 5.2 Projenin Gelişiminde Rol Almak
- 5.3 Bir Projeyi Yürütme
- 5.4 Özet
-
6. GitHub
- 6.1 Bir Projeye Katkıda Bulunmak
- 6.2 Proje Bakımı
- 6.3 Kurumsal Yönetim
- 6.4 GitHub’ı otomatikleştirme
- 6.5 Özet
-
7. Git Araçları
- 7.1 Düzeltme Seçimi
- 7.2 Etkileşimli İzlemleme (Staging)
- 7.3 Saklama ve Silme
- 7.4 Çalışmanızı İmzalama
- 7.5 Arama
- 7.6 Geçmişi Yeniden Yazma
- 7.7 Reset Komutunun Gizemleri
- 7.8 İleri Seviye Birleştirme
- 7.9 Rerere
- 7.10 Git’le Hata Ayıklama
- 7.11 Alt Modüller
- 7.12 Demetleme (Bundling)
- 7.13 Git Nesnesini Değiştirme
- 7.14 Kimlik Bilgisi Depolama
- 7.15 Özet
-
8. Git’i Özelleştirmek
- 8.1 Git Yapılandırması
- 8.2 Git Nitelikleri
- 8.3 Git Kancaları (Hooks)
- 8.4 Bir Örnek: Mecburi Git Politikası
- 8.5 Özet
-
9. Git ve Diğer Sistemler
- 9.1 İstemci Olarak Git
- 9.2 Git’e Geçiş
- 9.3 Özet
-
10. Dahili Git Ögeleri
- 10.1 Tesisat ve Döşeme (Plumbing ve Porcelain)
- 10.2 Git Nesneleri
- 10.3 Git Referansları
- 10.4 Packfiles
- 10.5 Refspec
- 10.6 Transfer Protokolleri
- 10.7 Bakım ve Veri Kurtarma
- 10.8 Ortam Değişkenleri
- 10.9 Özet
-
A1. Ek bölüm A: Diğer Ortamlarda Git
- A1.1 Görsel Arayüzler
- A1.2 Visual Studio ile Git
- A1.3 Visual Studio Code ile Git
- A1.4 Eclipse ile Git
- A1.5 Sublime Text ile Git
- A1.6 Bash ile Git
- A1.7 Zsh ile Git
- A1.8 PowerShell ile Git
- A1.9 Özet
-
A2. Ek bölüm B: Git’i Uygulamalarınıza Gömmek
- A2.1 Git Komut Satırı
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Ek bölüm C: Git Komutları
- A3.1 Kurulum ve Yapılandırma Komutları
- A3.2 Proje Oluşturma Komutları
- A3.3 Kısaca Poz (Snapshot) Alma
- A3.4 Dallandırma ve Birleştirme Komutları
- A3.5 Projeleri Paylaşma ve Güncelleme Komutları
- A3.6 İnceleme ve Karşılaştırma Komutları
- A3.7 Hata Ayıklama (Debugging) Komutları
- A3.8 Yamalama (Patching)
- A3.9 E-Posta Komutları
- A3.10 Harici Sistemler
- A3.11 Yönetim
- A3.12 Tesisat (Plumbing) Komutları
10.7 Dahili Git Ögeleri - Bakım ve Veri Kurtarma
Bakım ve Veri Kurtarma
Bazen veri havuzunu daha derli toplu hale getirmek, içe aktarılan bir veri havuzunu temizlemek veya kaybolan çalışmaları kurtarmak için bir miktar temizlik yapmanız gerekebilir. Bu bölümde bu senaryolardan bazıları ele alınacaktır.
Bakım
Arada sırada, Git otomatik olarak auto gc
adlı bir komut çalıştırır.
Çoğu zaman bu komut hiçbir şey yapmaz.
Ancak, fazla sayıda gevşek nesne (paket dosyasında olmayan nesneler) veya fazla sayıda paket dosyası varsa, Git tam donanımlı bir git gc
komutunu başlatır.
gc
çöp toplama (garbage collection) anlamına gelir ve bu komut birkaç şey yapar: tüm gevşek nesneleri toplayarak bunları paket dosyalarına yerleştirir, paket dosyalarını birleştirerek tek bir büyük paket dosyası haline getirir, birkaç ay öncesine dayanan ve hiçbir katkısına erişilemeyen nesneleri kaldırır.
Auto gc
'yi aşağıdaki gibi manuel olarak çalıştırabilirsiniz:
$ git gc --auto
Tekrar belirtmek gerekirse, bu genellikle hiçbir şey yapmaz.
Gerçek bir gc
komutunu çalıştırmak için yaklaşık 7.000 gevşek nesneye veya 50’den fazla paket dosyasına ihtiyacınız vardır.
Bu sınırları sırasıyla gc.auto
ve gc.autopacklimit
yapılandırma ayarları ile değiştirebilirsiniz.
gc
'nin yapacağı diğer bir şey de referanslarınızı tek bir dosyaya paketlemektir.
Diyelim ki repo şu dalları ve etiketleri içeriyor:
$ find .git/refs -type f
.git/refs/heads/experiment
.git/refs/heads/master
.git/refs/tags/v1.0
.git/refs/tags/v1.1
git gc
komutunu çalıştırırsanız, bu dosyalar artık refs
dizininde bulunmaz.
Git verimlilik açısından onları .git/packed-refs
adlı, şu şekilde gözüken bir dosyaya taşır:
$ 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 referansı güncellerseniz Git bu dosyayı düzenlemez, bunun yerine refs/heads
'e yeni bir dosya yazar.
Belirli bir referans için uygun SHA-1’i almak amacıyla Git, refs
dizininde bu referansı kontrol eder ve ardından bir yedek olarak packed-refs
dosyasını kontrol eder.
Ancak, refs
dizininde bir referans bulamazsanız, bu muhtemelen packed-refs
dosyanızdadır.
Dosyanın ^
ile başlayan son satırına dikkat edin.
Bu, doğrudan yukarıdaki etiketin açıklamalı bir etiket olduğu ve bu satırın açıklamalı etiketin işaret ettiği katkı olduğu anlamına gelir.
Veri Kurtarma
Git yolculuğunuzun bir noktasında, bir katkıyı kazara kaybedebilirsiniz. Bunu genellikle, üzerinde çalışma olan bir dalı zorla silip, sonunda dala yine ihtiyacınız olduğunu fark ettiğinizde yaşarsınız; veya bir dala sert sıfırlama yaparsınız, böylece ihtiyacınız olan bazı katkıları kaybetmiş olursunuz. Bu durum gerçekleşirse, katkıları nasıl geri alabilirsiniz?
İşte test repomdaki ana dalı bir önceki katkıya sert sıfırlayan ve sonra kaybolan katkıları kurtaran bir örnek: Önce, repomun şu anda nerede olduğunu gözden geçirelim:
$ git log --pretty=oneline
ab1afef80fac8e34258ff41fc1b867c702daa24b modified repo a bit
484a59275031909e19aadb7c92262719cfcdf19a added repo.rb
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
Şimdi, master
dalını ortadaki katkıya taşıyalım:
$ git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9
HEAD is now at 1a410ef third commit
$ git log --pretty=oneline
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
Etkili bir şekilde en üstteki iki katkıyı kaybettiniz ve bu katkılara erişilebilecek hiçbir dalınız yok. Bu katkıların SHA-1’ini bulmanız ve sonra ona işaret eden bir dal eklemeniz gerekiyor. Sorun, bu en son katkının SHA-1’ini bulmaktadır (neticede onu ezberlemediniz, değil mi)?
Genellikle, en hızlı yol git reflog
adı verilen bir araç kullanmaktır.
Çalışırken, Git HEAD’i her değiştirdiğinizde ne olduğunu sessizce kaydeder.
Her bir katkı veya dal değiştirdiğinizde reflog güncellenir.
Reflog ayrıca git update-ref
komutu tarafından da güncellenir, bu da sadece SHA-1 değerini ref dosyalarınıza yazmak yerine onu kullanmanın başka bir nedenidir (Git Referansları bölümünde ele aldığımız gibi).
Herhangi bir zamanda nerede olduğunuzu görmek için git reflog
komutunu çalıştırarak geçmişinizi görebilirsiniz:
$ git reflog
1a410ef HEAD@{0}: reset: moving to 1a410ef
ab1afef HEAD@{1}: commit: modified repo.rb a bit
484a592 HEAD@{2}: commit: added repo.rb
Burada kontrol ettiğimiz iki katkıyı görebiliriz, ancak burada pek fazla bilgi yok.
Aynı bilgiyi çok daha kullanışlı bir şekilde görmek için git log -g
komutunu çalıştırabiliriz, bu size reflog’unuz için normal bir günlük (log) çıktısı verecektir.
$ 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
modified repo.rb a bit
Görünüşe göre kaybettiğiniz katkı en alttaki katkıdır, bu yüzden onu o katkıya işaret eden yeni bir dal oluşturarak kurtarabilirsiniz.
Örneğin, o katkıya (ab1afef) işaret eden recover-branch
adında bir dal başlatabilirsiniz:
$ git branch recover-branch ab1afef
$ git log --pretty=oneline recover-branch
ab1afef80fac8e34258ff41fc1b867c702daa24b modified repo a bit
484a59275031909e19aadb7c92262719cfcdf19a added repo.rb
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
Harika – artık master
dalınızın bulunduğu yerde olan recover-branch
adında bir dalınız var, böylece ilk iki katkıya yeniden ulaşabilirsiniz.
Şimdi, varsayalım ki kaybınız reflog’da değildi (recover-branch
'i kaldırarak ve reflog’u silerek bu durumu canlandırabilirsiniz edebilirsiniz).
Şimdi, ilk iki katkı hiçbir şey tarafından ulaşılamaz durumda:
$ git branch -D recover-branch
$ rm -Rf .git/logs/
Çünkü reflog verileri .git/logs/
dizininde saklanır, hiçbir etkin reflog’unuz yoktur.
Bu noktada bu katkıyı nasıl kurtarabilirsiniz?
Bir yol, veritabanınızı bütünlük açısından kontrol eden git fsck
yardımcı programını kullanmaktır.
Onu --full
seçeneği ile çalıştırırsanız, başka bir nesne tarafından işaret edilmeyen tüm nesneleri size gösterir:
$ 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 durumda, eksik katkınızı ``dangling commit`` (sallantıdaki katkı) dizgesinden sonra görebilirsiniz. Aynı şekilde, o SHA-1’e işaret eden bir dal ekleyerek onu kurtarabilirsiniz.
Nesneleri Silmek
Git’in harika birçok özelliği olsa da, sorunlara da neden olabilen bir özelligi: git clone
komutunun projenin her dosyasının tüm sürümlerini de içermekte olan "tüm geçmişini" indirmesidir.
Bu, hepsinin kaynak kodu olduğu durumlar için sorun değildir, çünkü Git bu veriyi etkili bir şekilde sıkıştırmak için yüksek derecede optimize edilmiştir.
Ancak, projenizin geçmişinde herhangi bir noktada tek bir büyük dosya ekleyen biri olduğunda, her zaman için her klonun o büyük dosyayı indirmek zorunda kalacak olması - o dosya sonraki katkıda projeden kaldırılmış olsa bile - geçerli bir durumdur.
Çünkü geçmişten erişilebilirdir ve her zaman orada olacaktır.
Bu, Subversion veya Perforce repolarını Git’e dönüştürürken büyük bir sorun olabilir. Bu sistemlerde tüm geçmişi indirmediğiniz için, bu tür bir eklemenin bazı sonuçları vardır. Başka bir sistemden bir içe aktarma yaptıysanız veya başka bir şekilde deponuzun beklenenden çok daha büyük olduğunu görürseniz, büyük nesneleri bulup kaldırmanın bir yolunu aşağıda bulabilirsiniz.
Dikkat: Bu teknik, katkı geçmişinize zarar vericidir. Büyük bir dosyanın referansını kaldırmak için değiştirirseniz, ilk ağacınızdan itibaren her katkı nesnesini yeniden yazacaktır. Bunu, bir içe aktarmadan hemen sonra ve henüz hiç kimse çalışmaya başlamamışken yaparsanız, sorunsuzdur. Aksi takdirde, tüm katkıda bulunanlara, çalışmalarını yeni katkılara dayandırmaları gerektiğini bildirmeniz gerekir.
Bu tekniği göstermek için, test repomuza büyük bir dosya ekleyecek, bir sonraki katkıda onu kaldıracak, ardından onu bulup repodan kalıcı olarak sileceğiz. İlk olarak, geçmişinize büyük bir nesne ekleyin:
$ 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
Eyvah! Projenize devasa bir tarball eklemek istememiştiniz. Onu kaldırmak daha iyi olur:
$ git rm git.tgz
rm 'git.tgz'
$ git commit -m 'oops - removed large tarball'
[master dadf725] oops - removed large tarball
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 git.tgz
Şimdi (gc
komutuyla) veritabanınızı temizleyin ve kullandığınız alanı 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)
Kullandığınız alanı hızlı bir şekilde görmek için count-objects
komutunu çalıştırabilirsiniz:
$ 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, paket dosyalarınızın kilobayt cinsinden boyutudur, bu yüzden neredeyse 5MB kullanıyorsunuz.
Son katkıdan önce yaklaşık 2K kullanıyordunuz: açıkçası, dosyayı önceki katkıdan kaldırmak onu geçmişinizden kaldırmadı.
Bu repoyu kopyalayan herkes, bu küçük projeyi almak için 5MB’lik tümünü kopyalamak zorunda kalacak, çünkü yanlışlıkla büyük bir dosya eklediniz.
Hadi onu kaldıralım.
İlk olarak, onu bulmanız gerekiyor.
Bu durumda, zaten hangi dosyanın olduğunu biliyorsunuz.
Ancak öyle olmadığını varsayalım; bu kadar çok alanı alan dosyayı veya dosyaları nasıl tanımlarsınız?
git gc
komutunu çalıştırırsanız, tüm nesneler bir paket dosyasında bulunur; büyük nesneleri tanımlamak için git verify-pack
adlı başka bir işleme komutunu çalıştırabilir ve çıktıdaki üçüncü alana göre sıralayabilirsiniz, işte bu dosya boyutudur.
Ayrıca, yalnızca en büyük birkaç dosyaya ilgilendiğiniz için çıktıyı tail
komutuyla borudan (pipe) geçirebilirsiniz:
$ 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
Büyük nesne en alttadır: 5MB.
Bu dosyanın ne olduğunu bulmak için, kısa bir süre önce Belirli Bir Katkı Mesajı Formatını Zorunlu Hale Getirme bölümünde kullandığınız rev-list
komutunu kullanacaksınız.
rev-list
'e --objects
parametresini ilettiğinizde, tüm katkı SHA-1’leri ve bunlarla ilişkilendirilmiş dosya yollarıyla birlikte blok SHA-1’lerini listeler.
Bunu blob’un adını bulmak için kullanabilirsiniz:
$ git rev-list --objects --all | grep 82c99a3
82c99a3e86bb1267b236a4b6eff7868d97489af1 git.tgz
Şimdi, bu dosyayı geçmişinizdeki tüm ağaçlardan kaldırmanız gerekiyor. Bu dosyayı değiştiren tüm katkıları kolayca görebilirsiniz:
$ git log --oneline --branches -- git.tgz
dadf725 oops - removed large tarball
7b30847 add git tarball
7b30847
'den sonraki tüm katkıları bu dosyayı tamamen Git geçmişinizden kaldırmak için yeniden yazmalısınız.
Bunu yapmak için, Geçmişi Yeniden Yazma bölümünde kullandığınız filter-branch
komutunu kullanırsınız:
$ 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çeneği, Geçmişi Yeniden Yazma bölümünde kullanılan --tree-filter
seçeneğine benzer, ancak her seferinde diske çıkarılan dosyaları değiştiren bir komut yerine, indeksinizi veya dizin belirtmenizi sağlar.
rm dosya
gibi belirli bir dosyayı kaldırmak yerine, onu git rm --cached
ile kaldırmalısınız; bu onu dizinden değil, indeksten kaldırır.
Bunu bu şekilde yapmamızın nedeni hızdır; çünkü Git, filtrelerinizi çalıştırmadan önce her revizyonu diske çıkarmak zorunda kalmadığı için, işlem çok daha hızlı olabilir.
Aynı görevi --tree-filter
ile de gerçekleştirebilirsiniz.
git rm
'nin --ignore-unmatch
seçeneği, kaldırmaya çalıştığınız desen orada olmadığında hata vermemesini sağlar.
Son olarak, bu sorunun başladığı yere yani 7b30847
katkısından başlayarak yalnızca geçmişinizi yeniden yazmasını istersiniz, aksi takdirde işlem başlangıçtan başlayacak ve gereksiz yere daha uzun sürecektir.
Geçmişiniz artık o dosyaya bir referans içermiyor.
Yine de reflog’unuz ve filter-branch
yaptığınızda Git’in eklediği yeni bir dizi refs, hala bu dosyaya işaret ediyor; bu yüzden onları kaldırmanız ve ardından veritabanını yeniden paketlemeniz gerekiyor.
Yeniden paketlemeden önce bu eski katkılara dönük bir işaretçisi olan her şeyden kurtulmanız gerekiyor:
$ 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)
Ne kadar alan kazandığınızı görelim.
$ git count-objects -v
count: 11
size: 4904
in-pack: 15
packs: 1
size-pack: 8
prune-packable: 0
garbage: 0
size-garbage: 0
Paketlenmiş repo boyutu 8K’ya kadardır, bu da 5 MB’tan çok daha iyidir.
Boyut değerinden, büyük nesnenin hala gevşek nesnelerinizin içinde olduğunu, yani gitmediğini görebilirsiniz; ancak bir itme veya sonraki kopyalamayla (clone) aktarılmayacaktır ki önemli olan da budur.
Eğer gerçekten isterseniz`git prune` komutunu --expire
seçeneğiyle çalıştırarak nesneyi tamamen kaldırabilirsiniz:
$ 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