-
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ı
3.6 Git Dalları - Yeniden Temelleme (rebase)
Yeniden Temelleme (rebase)
Git’te, bir dalın değişikliklerini diğerine birleştirmenin iki ana yolu vardır: merge
(birleştirme) ve rebase
(yeniden temelleme). Bu bölümde, yeniden temellemenin ne olduğunu, nasıl yapıldığını, neden oldukça etkili bir araç olduğunu ve hangi durumlarda kullanmak istemeyeceğinizi öğreneceksiniz.
Kısaca Yeniden Temelleme
Eğer önceki örneğe, Birleştirme başlıklı bölüme geri dönerseniz, işinizi dallandırdığınızı ve iki farklı dalda katkı işlediğinizi görebilirsiniz.
Dalları birleştirmenin en kolay yolu, zaten ele aldığımız gibi merge
komutudur.
Bu komut, iki dalın (C3
ve C4
) ve bunların en son ortak öncelinin (C2
) son pozlarını üçyönlü birleştirerek, yeni bir poz (ve katkı) oluşturur.
Ancak, başka bir yol daha vardır: C4
ile tanıtılan değişikliğin yamasını alabilir ve bunu C3
'ün üzerine yeniden uygulayabilirsiniz.
Git’te buna yeniden temelleme (rebasing) denir.
rebase
komutu ile bir dalda işlenmiş tüm değişiklikleri alabilir ve bunları farklı bir dala aktararak bir temel olarak kullanabilirsiniz.
Bu örnekte, experiment
dalına geçer ve ardından onu şu şekilde master
dalına aktarabilirsiniz:
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
Bu işlem, iki dalın (üzerinde bulunduğunuz dal ve yeniden temellediğiniz dal) ortak önceline gitmesiyle başlar. Ardından, üzerinde bulunduğunuz dalın her katkısının getirdiği farkı alır ve bu farkları geçici dosyalara kaydeder. Mevcut dalı, üzerine yeniden temelleme yaptığınız dalın katkıları ile aynı katkıya sıfırlar ve son olarak her değişikliği sırayla uygular.
C4
'teki değişikliği C3
üzerine temellemeBu noktada, master
dalına geri dönebilir ve bir ileri-sarma birleştirmesi (fast-forward merge) yapabilirsiniz.
$ git checkout master
$ git merge experiment
Şu anda, C4'
tarafından işaret edilen poz, the merge example örneğinde C5
tarafından işaret edilen poz ile tam olarak aynıdır.
Birleştirme çıktısında fark yoktur, ancak yeniden temelleme daha temiz bir geçmiş sunar.
Eğer git log
komutuyla temellenmiş bir dalın günlüğünü incelerseniz, doğrusal bir geçmiş görürsünüz.
Başlangıçta eşzamanlı gerçekleşmiş olsa bile, tüm işin sırayla gerçekleştiği izlenimini verir.
Çoğu zaman bunu, katkılarınızın temiz bir şekilde bir uzak dala uygulanmasını sağlamak için yaparsınız, belki de bir süre üzerinde çalıştığınız ancak sürdürmediğiniz bir projede.
Bu durumda, işinizi bir dalda yapar ve yamalarınızı ana projeye göndermeye hazır olduğunuzda işinizi origin/master
üzerine yeniden temellersiniz.
Bu şekilde, bakım yapan kişinin herhangi bir birleştirme çalışması yapmasına gerek kalmaz - sadece bir ileri-sarma veya temiz bir uygulama yapması yeterlidir.
Unutmayın ki, bu işlem sonunda elde ettiğiniz poz, ister bir yeniden temelleme işlemi için alınmış son temelleme katkısı, isterse birleştirme işlemi sonrası elde ettiğiniz son birleştirme katkısı olsun, aynı pozdur - farklı olan sadece tarihtir. "Yeniden Temelleme" değişiklikleri tanımlandıkları sırayla bir iş çizgisinden başka bir iş çizgisine aktarırken, "birleşim" uç noktaları alır ve bunları birleştirir.
Daha Detaylıca Yeniden Temelleme
Yeniden temelleme işlemi için hedef aldığınız dal dışında bir dala da temellemenizi uygulayabilirsiniz.
Mesela Bir tematik daldan ayrılan başka bir tematik dalın geçmişi şeklindeki bir tarihçeyi ele alalım:
Projeye sunucu tarafı işlevselliği eklemek için server
adında tematik bir dal oluşturdunuz ve bir katkı işlediniz.
Ardından, istemci tarafındaki değişiklikleri yapmak için bu daldan ayrılıp client
dalında birkaç katkı işlediniz.
Son olarak, sunucu dalına geri dönüp birkaç katkı daha işlediniz.
Diyelim ki, bir sürüm için kullanıcı tarafındaki değişiklikleri ana dalınıza birleştirmeye karar verdiniz, ancak sunucu tarafındaki değişiklikleri daha fazla test edilene kadar bekletmek istiyorsunuz.
Bu durumda, sunucu tarafında olmayıp (C8
and C9
) kullanıcı tarafında olan değişiklikleri alabilir ve onları git rebase
komutunun --onto
seçeneğini kullanarak master
dalınıza yeniden temelleyebilirsiniz:
$ git rebase --onto master server client
Bu temel olarak şunu ifade eder: "client
dalını al, bu dalın server
dalından ayrıldığından bu yana yapılan yamaları belirle ve bu yamaları client
dalında, sanki doğrudan master
dalından temellenmiş gibi yeniden temelle."
Biraz karmaşık gibi görünebilir, ancak sonuç oldukça etkileyicidir.
Artık master
dalınızı ileri sarabilirsiniz (bkz. master
dalını client
dalındaki değişiklikleri içerecek şekilde ileri sarmak):
$ git checkout master
$ git merge client
master
dalını client
dalındaki değişiklikleri içerecek şekilde ileri sarmakDiyelim ki sunucu dalını da eklemeye karar verdiniz.
git rebase <temel-dalı> <tema-dalı>
komutunu çalıştırarak, öncesinde dalınızı değiştirmeden, sunucu dalını master
dalına tekrar temelleyebilirsiniz.
Bu komut, ilgili tema dalına (burada server
) geçiş yapar ve onu ana dal üzerine (burada master
) yeniden temeller.
$ git rebase master server
Bu, server
dalını master
dalının üzerine yeniden temelleme diyagramında gösterildiği gibi server
çalışmanızı master
çalışmanızın üzerine yeniden temeller.
server
dalını master
dalının üzerine yeniden temellemeArdından, ana dalınıza (master
) ileri sarabilirsiniz:
$ git checkout master
$ git merge server
Tüm çalışmalar birleştirildiği için artık client
ve server
dallarını silebilirsiniz, çünkü bu sürecin tüm geçmişi zaten Nihai katkı geçmişi şeklinde görünecektir:
$ git branch -d client
$ git branch -d server
Yeniden Temellemenin Riskleri
Yeniden temelleme getirdiği kolaylıkların yanında malesef bazı dezavantajları da içerir. Bu riskleri tek cümlede özetlemek mümkündür:
Repo dışında var olan ve üzerine çalışılmış olabilecek katkıları yeniden temellemeyin.
Eğer bu kılavuzu takip ederseniz, sorun yaşamazsınız. Ama anlatacağımız yönergelere uymazsanız, insanlar sizi sevmeyecek; dostlarınız ve aileniz tarafından hor görüleceksiniz.
Birşeyleri yeniden temellediğinizde, mevcut katkıları terk ediyor ve benzer ancak farklı olan yeni katkılar oluşturuyorsunuz.
Eğer katkılarınızı bir yere iterseniz ve başkaları bunları çekip), üzerine çalışma yaparsa, ve daha sonra bu katkıları git rebase
ile değiştirip tekrar iterseniz, çalışma arkadaşlarınız kendi çalışmalarını tekrar birleştirmek zorunda kalacak ve onların çalışmalarını kendi projenize çekmeye çalıştığınızda bir karışıklık ortaya çıkacaktır.
Herkese açık bir şekilde yayımladığınız çalışmayı yeniden temellemenin nasıl sorunlara yol açabileceğine dair bir örneğe bakalım. Merkezi bir sunucudan bir repo kopyaladığınızı ve ardından biraz çalışma yaptığınızı düşünelim. katkı geçmişiniz şu şekilde görünüyor:
Şimdi, başka biri birleştirme içeren bazı çalışmalar yapar ve bu çalışmayı merkezi sunucuya iter. Siz bunu çeker ve yeni uzak dalı kendi çalışmanıza birleştirirsiniz, geçmişiniz şöyle görünebilir:
Ardından, birleştirilmiş çalışmayı iten kişi, bunun yerine, geriye gidip çalışmaya yeniden temellemeye karar verir.
Bunun için git push --force
kullanarak sunucudaki geçmişin üzerine yazar.
Siz de bu sunucudan çekerseniz, yeni katkıları getirirsiniz.
Şimdi her ikiniz de çıkmazdasınız.
Eğer bir git pull
yaparsanız, her iki geçmiş çizgisini de içeren birleştirme katkısı oluşturursunuz ve repo şu şekilde görünecektir:
Eğer geçmişiniz bu şekilde göründüğünde bir git log
komutu çalıştırırsanız; aynı yazar, tarih ve mesajı taşıyan iki katkı göreceksiniz ki bu da kafa karıştırıcı olacaktır.
Dahası, eğer bu geçmişi tekrar sunucuya iterseniz, tüm bu yeniden temellenmiş katkıları merkezi sunucuya tekrar eklemiş olursunuz ki bu insanların kafasını daha da karıştırabilir.
Diğer geliştiricinin (en başta yeniden temelleme yaptığı için), C4
ve C6
'nın geçmişte olmasını istemediğini varsayabiliriz.
Yeniden Temelleme Yaparken Dikkat Edilmesi Gerekenler
Eğer kendinizi böyle bir durumda bulunursanız, Git size yardımcı olabilecek bazı ek özellikler sunar. Eğer takımınızdaki birisi, yeniden temellediğiniz bir işin üzerine yazan değişiklikleri zorla iterse (force push), karşılaşacağınız gerçek sorun hangi kodun size ait olduğu ve hangisinin üzerine yeniden yazılan olduğunu bulmaktır.
Git, katkının SHA-1 sağlamasına ek olarak, yalnızca katkı ile tanıtılan yamaya dayalı bir sağlama da hesaplar. Buna ``patch-id`` denir.
Eğer üzerine yeniden yazılan işi çekerseniz ve bu işi meslektaşınızın yeni katkıları üzerine yeniden temellerseniz; Git genellikle sizin çalışmanızın hangisi olduğunu başarılı bir şekilde bulabilir ve bunları yeni dalın üzerine uygulayabilir.
Örneğin, önceki senaryoda, Birisi çalışmanıza temellediğiniz katkıları terkedip, yeniden temellenmiş katkıları iter noktasındayken birleştirme yerine git rebase teamone/master
komutunu çalıştırırsak, Git şunları yapacaktır:
-
Dalımıza özgü işleri belirle (C2, C3, C4, C6, C7)
-
Hangilerinin birleştirme katkısı olmadığını belirle (C2, C3, C4)
-
Hangilerinin hedef dalda üzerine yeniden yazılmadığını belirle (C4, C4' ile aynı yama olduğu için sadece C2 ve C3)
-
Tüm bu katkıları
teamone/master
'ın üstüne uygula
Bu durumda, Aynı çalışmayı tekrar yeni bir birleştirme katkısına dahil edersiniz görüntüsündeki sonuç yerine, daha ziyade Zorla itilmiş yeniden temelleme (force-push rebase) üzerine temelleme benzeri bir sonuç elde ederiz.
Bu sadece meslektaşınızın yaptığı C4 ve C4' katkılarının neredeyse tamamen aynı yama olması durumunda çalışır. Aksi takdirde, yeniden temelleme bunun bir kopya olduğunu anlayamaz ve başka bir C4 benzeri yama ekler (değişiklikler zaten en azından bir dereceye kadar mevcut olacağı için, bu muhtemelen düzgün bir şekilde uygulanamaz).
Bunu normal bir git pull
yerine git pull --rebase
komutunu çalıştırarak daha da basitleştirebilirsiniz.
Veya bu durumda bir git fetch
ve ardından git rebase teamone/master
komutu kullanarak manuel olarak da gerçekleştirebilirsiniz.
Eğer git pull
kullanıyorsanız ve --rebase
varsayılan olsun istiyorsanız, git config --global pull.rebase true
gibi bir komutla pull.rebase
yapılandırmasını ayarlayabilirsiniz.
Eğer sadece kendi bilgisayarınızdan hiç ayrılmamış katkıları yeniden temelliyorsanız, sorun yaşamazsınız. Eğer itilmiş ancak kimsenin bunlardan temellemediği katkıları yeniden temelliyorsanız, yine sorun yaşamazsınız. Ancak eğer zaten herkese açık bir şekilde itilmiş ve birileri bu katkılardan temelleme yapmışsa, o zaman sıkıntılı bir durumla karşılaşabilir ve takım arkadaşlarınızın tepkisini çekebilirsiniz.
Eğer siz veya bir meslektaşınız bunu gerekli görürse, bu sıkıntıyı biraz daha basitleştirmeye çalışmak için, herkesin git pull --rebase
komutunu çalıştırmayı bildiğinden emin olun.
Yeniden Temelleme ve Birleştirme
Yeniden temelleme ve birleştirmeyi öğrendiğinize göre hangisinin daha iyi olduğunu merak ediyor olabilirsiniz. Bunu yanıtlayabilmek için biraz geriye gitmek ve geçmişin ne anlama geldiğini konuşmak gerekiyor.
Bu konudaki bir bakış açısı, repo katkı geçmişinin aslında nelerin gerçekleştiğinin bir kaydı olduğudur. Bu oynanmaması gereken, çok değerli ve tarihi bir belgedir. Bu açıdan bakıldığında, katkı geçmişini değiştirmek neredeyse şirktir. Çünkü tarihi tahrif ederek, gerçekte neler olduğu hakkında yalan söylemiş olursunuz. Yani karışık bir dizi birleştirme katkısı varsa ne olmuş ki? İşte öyle olduysa bile repo bunu gelecek nesiller için korumalıdır.
Karşıt bakış açısı, katkı geçmişinin projenizin nasıl yapıldığını anlatan bir hikaye olduğudur. Bir kitabın ilk taslağını yayımlamazsınız ve yazılımınızı nasıl sürdüreceğiniz konusundaki kılavuz, dikkatli bir düzenlemeyi hak eder. Bu görüştekiler "yeniden temelleme" ve "dal filtreleme" gibi araçları kullanarak hikayeyi gelecekteki okuyucular için en iyi şekilde anlatan kişilerdir.
Şimdi, birleştirmenin mi yoksa yeniden temellemenin mi daha iyi olduğu sorusuna gelince: bunun o kadar da basit bir soru olmadığını anladığınızı ümidediyorum. Git geçmişinizle ilgili birçok şey yapmanıza izin veren güçlü bir araçtır, ancak her ekip ve her proje de farklıdır. Her iki işlemin de nasıl çalıştığını bildiğinize göre, hangisinin sizin özel durumunuz için en iyi olduğuna siz karar vereceksiniz.
Genel olarak, her iki yaklaşımdan da en iyi şekilde faydalanmanın yolu, henüz paylaşmadığınız yerel değişiklikleri itmeden önce yeniden temelleme yaparak geçmişi temizlemektir, ancak herhangi bir sunucuya ittiğiniz bir şeyi asla yeniden temelleme yapmamaktır.