-
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ı
7.13 Git Araçları - Git Nesnesini Değiştirme
Git Nesnesini Değiştirme
Daha önce vurguladığımız gibi, Git’in veritabanındaki nesneleri değişmezdir, ancak Git veritabanındaki nesneleri başka nesnelerle değiştiriyormuş gibi yapmak için ilginç bir yol sunar.
replace
komutu, Git’te bir nesneyi belirtmenize ve "bu nesne her çağrıldığında, o sanki farklı bir nesneymiş gibi davran" demenize izin verir.
Bu, özellikle tüm geçmişi yeniden oluşturmak zorunda kalmadan, geçmişinizdeki bir katkıyı başka bir katkı ile değiştirmeniz gerektiğinde (ör. git filter-branch
) çok kullanışlıdır.
Örneğin, büyük bir kod geçmişiniz var ve bu geçmişi yeni geliştiriciler için kısa bir geçmiş ve veri madenciliğiyle ilgilenen kişiler için çok daha uzun ve büyük bir geçmişe bölmek istiyorsunuz. Yeni tarih çizginizdeki en erken katkıyı, eski olanın en son katkısıyla "değiştirerek" bir geçmişi diğerine ekleyebilirsiniz. Bu, genellikle onları birleştirmek için yapmanız gerektiği üzere (çünkü öncellik SHA-1’leri etkiler), yeni geçmişteki her katkıyı yeniden yazmanızı gerektirmeyeceği için güzel bir yöntemdir.
Hadi bunu deneyelim.
Mevcut bir repoyu alalım, onu biri kısa ve yeni, diğeri ise daha uzun, köklü bir proje geçmişine sahip olan iki repoya bölelim.
Ve sonra bu geçmişleri replace
kullanarak, yeni repoların SHA-1 değerlerini değiştirmeden nasıl birleştirebileceğimize bakalım.
Bunu beş katkısı olan basit bir repo üzerinde deneyelim:
$ git log --oneline
ef989d8 fifth commit
c6e1e95 fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
Bu repoyu iki tarih çizgisine bölmek istiyoruz. Bir çizgi, birinci katkıdan dördünca katkıya kadar gider (bu uzak geçmiş olacaktir). İkinci çizgide sadece dört ve beş numaralı katkılar olacaktır (bu yakın geçmiş olacaktır).
Tarihi geçmişi oluşturmak kolaydır, geçmişe bir dal ekleyebilir ve sonra bu dalı yeni bir uzak repo’nun ana dalına (master
dalına) itebiliriz.
$ git branch history c6e1e95
$ git log --oneline --decorate
ef989d8 (HEAD, master) fifth commit
c6e1e95 (history) fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
Şimdi, yeni history
dalını yeni repomuzun master
dalına itebiliriz:
$ git remote add project-history https://github.com/schacon/project-history
$ git push project-history history:master
Counting objects: 12, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (12/12), 907 bytes, done.
Total 12 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (12/12), done.
To git@github.com:schacon/project-history.git
* [new branch] history -> master
Artık, geçmişimiz yayınlandı. Şimdi geriye işin daha zor olan kısmı, yani yakın tarihli geçmişimizi kırpmak kaldı. Bir yerde örtüşme olması gerekiyor ki birindeki bir katkıyı, diğerindeki eşdeğer bir katkı ile değiştirebilelim. Bu yüzden bu geçmişi sadece dört ve beş numaralı katkılara indirgiyoruz (böylece dört numaralı katkı örtüşecektir).
$ git log --oneline --decorate
ef989d8 (HEAD, master) fifth commit
c6e1e95 (history) fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
Bu durumda, tarihçenin nasıl genişletileceği hakkında talimatları olan bir temel katkı oluşturmak faydalıdır. Böylece diğer geliştiriciler, kırpılmış geçmişin ilk katkısına ulaşırlar ve daha fazlasına ihtiyaç duyarlarsa ne yapacaklarını bilirler. Bu yüzden yapacağımız şey, talimatlar içeren bir başlangıç katkısı oluşturmak ve sonra geriye kalan katkıları (dört ve beş) bunun üzerine yeniden düzenlemektir.
Bunu yapmak için, bölme noktası olmak üzere bir nokta belirlememiz gerekiyor ki bu bizim için üçüncü katkı olacaktır: yani SHA dilinde 9c68fdc
dir.
Bu yüzden temel katkımız o ağaç üzerinde olacaktır.
Sadece bir ağaç alıp, bize öncelsiz ve yepyeni bir katkı nesnesi SHA-1’i veren commit-tree
komutunu kullanarak, temel katkımızı oluşturabiliriz.
$ echo 'get history from blah blah blah' | git commit-tree 9c68fdc^{tree}
622e88e9cbfbacfb75b5279245b9fb38dfea10cf
Not
|
|
Artık temel bir katkımız olduğuna göre, geriye kalan tarihçemizi bunun üzerine git rebase --onto
komutu ile tekrar düzenleyebiliriz.
--onto
argümanı, commit-tree
ile aldığımız SHA-1; ve üçüncü katkımız (saklamak istediğimiz ilk katkının önceli olan, 9c68fdc
) geriye dönük temel noktamız olacaktır:
$ git rebase --onto 622e88 9c68fdc
First, rewinding head to replay your work on top of it...
Applying: fourth commit
Applying: fifth commit
Artık, yeniden oluşturulabilir bir tarihçe hakkında talimatlar içeren temel katkımızı işleyip, üzerine yakın geçmişimizi yeniden yazdık. Eğer bu yeni geçmişi yeni bir projeye gönderirsek; artık insanlar o repoyu kopyaladıklarında, en son iki katkıyı ve sonra da talimatları içeren temel katkıyı göreceklerdir.
Şimdi rolleri değiştirerek, projeyi ilk kez kopyalayan ve tüm tarihçeyi isteyen birinin yerine geçelim. Bu kırpılmış repoyu kopyaladıktan sonra tarihçeyi almak için, tarihi (uzak geçmişli) repomuz için ikinci bir uzak repo ekleyip, çekmemiz lazım:
$ git clone https://github.com/schacon/project
$ cd project
$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
622e88e get history from blah blah blah
$ git remote add project-history https://github.com/schacon/project-history
$ git fetch project-history
From https://github.com/schacon/project-history
* [new branch] master -> project-history/master
Şimdi çalışma arkadaşımızın en son katkıları master
dalında ve tarihi (uzak geçmişli) katkıları project-history/master
dalında olacaktır.
$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
622e88e get history from blah blah blah
$ git log --oneline project-history/master
c6e1e95 fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
Onları birleştirmek için, sadece değiştirmek istediğiniz katkıyı ve yerine koymak istediğiniz katkıyı belirterek git replace
komutunu çağırabilirsiniz.
Burada, master
dalındaki "dördüncü" katkı, project-history/master
dalındaki "dördüncü" kattı ile değiştirmek istiyoruz.
$ git replace 81a708d c6e1e95
Şimdi, master
dalının geçmişine baktığınızda, şöyle görünmektedir:
$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
Harika, değil mi? Üst akımdaki tüm SHA-1’leri değiştirmeden, geçmişimizdeki bir katkıyı tamamen farklı bir katkı ile değiştirebildik ve tüm normal araçlar (bisect
, blame
, vb.) onlardan beklediğimiz gibi çalışacaktır.
İlginçtir ki, 81a708d
hala SHA-1 olarak görünüyor, ancak aslında onu değiştirdiğimiz c6e1e95
katkısının verilerini kullanıyor.
cat-file
gibi bir komutu çalıştırsanız bile, değiştirilmiş verileri görürsünüz:
$ git cat-file -p 81a708d
tree 7bc544cf438903b65ca9104a1e30345eee6c083d
parent 9c68fdceee073230f19ebb8b5e7fc71b479c0252
author Scott Chacon <schacon@gmail.com> 1268712581 -0700
committer Scott Chacon <schacon@gmail.com> 1268712581 -0700
fourth commit
Unutmayın ki, 81a708d
katkısının asıl önceli, burada belirtildiği gibi 9c68fdce
değil, yer tutucu katkınızdır (622e88e
).
Bir başka ilginç nokta da bu verilerin referanslarımızda tutulmasıdır:
$ git for-each-ref
e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit refs/heads/master
c6e1e95051d41771a649f3145423f8809d1a74d4 commit refs/remotes/history/master
e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit refs/remotes/origin/HEAD
e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit refs/remotes/origin/master
c6e1e95051d41771a649f3145423f8809d1a74d4 commit refs/replace/81a708dd0e167a3f691541c7a6463343bc457040
Bu, değiştirdiğimiz veriyi başkalarıyla paylaşmanın kolay olduğu anlamına gelir. Çünkü bunu sunucumuza yükleyebiliriz ve diğerleri de kolayca indirebilir. Burada ele aldığımız tarihçe aşılaması senaryosu (herkes zaten her iki tarihçeyi de indirebilecekse, onları niye ayırdık ki?) çok yardımcı olmasa da, diğer bazı durumlarda faydalı olabilir.