-
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.7 Git Araçları - Reset Komutunun Gizemleri
Reset Komutunun Gizemleri
Daha özelleşmiş araçlara geçmeden önce, Git’in reset
ve checkout
komutlarından bahsedelim.
Bu komutlar, ilk kez karşılaştığınızda Git’in en karmaşık kısımlarından ikisidir.
Bu kadar çok şey yaparlar ki, onları gerçekten anlamak ve doğru bir şekilde kullanmak umutsuz görünür.
Bu nedenle, basit bir metafor öneriyoruz.
Üç Çalışma Ağacı
Git’in üç farklı çalışma ağacının içeriğini yöneten bir içerik yöneticisi olduğunu hayal etmek, reset
ve checkout
komutlarını anlamayı kolaylaştırır.
Burada "ağaç" derken gerçekten "dosya dizinini" kastediyoruz, bir veri yapısı olan ağacı (tree) değil.
(Birkaç durumda, dizin tam olarak bir ağaç gibi davranmaz, ancak şu anda amacımız için bu şekilde düşünmek daha kolaydır.)
Git sistemi normal işleyişinde üç ağacı yönetir ve onları değiştirir:
Ağaç (Tree) | Rol |
---|---|
Uç (HEAD) |
Son katkı pozu, ardıl |
Dizin (Index) |
Önerilen katkı pozu (bir sonraki işlem için) |
Çalışma Dizini |
Kum havuzu (Sandbox) |
Uç (HEAD)
Uç, mevcut dalda işlenen son katkının referansını gösteren bir işaretçidir. Bunun anlamı, bu "uç"un işlenen bir sonraki katkının önceli olacağıdır. Genellikle "uç"u projenizin o daldaki son katkınızı işlediğiniz andaki anlık görüntüsü (poz) olarak düşünmek en basit olanıdır.
Aslında, bu pozun nasıl olduğunu görmek oldukça kolaydır. İşte, uç pozundaki her dosyanın gerçek dizin listesi ve SHA-1 kontrol toplamlarını almanın bir örneği:
$ git cat-file -p HEAD
tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
author Scott Chacon 1301511835 -0700
committer Scott Chacon 1301511835 -0700
initial commit
$ git ls-tree -r HEAD
100644 blob a906cb2a4a904a152... README
100644 blob 8f94139338f9404f2... Rakefile
040000 tree 99f1a6d12cb4b6f19... lib
Git’in düşük seviyeli işlerde kullanılan cat-file
ve ls-tree
komutları, günlük işlerde pek kullanılmayan; ancak burada neler olup bittiğini görmemize yardımcı olan, “plumbing” (boru) komutlarıdır.
İndeks (Dizin)
İndeks, beklenilen sıradaki katkı işlemidir.
Bu kavramı aynı zamanda Git’in ``İzlem Alanı`` (Staging Area) olarak da adlandırıyoruz, çünkü git commit
komutunu çalıştırdığınızda Git’in baktığı yer burasıdır.
Git, bu indeksi, çalışma dizininize en son eklenen tüm dosya içeriği listesiyle doldurur ve eklendikleri anda onların aslında neye benzediğine bakar.
Daha sonra, siz bu dosyalardan bazılarını yeniden şekillendirirsiniz ve git commit
komutu bunu yeni bir katkı için ağaca dönüştürür.
$ git ls-files -s
100644 a906cb2a4a904a152e80877d4088654daad0c859 0 README
100644 8f94139338f9404f26296befa88755fc2598c289 0 Rakefile
100644 47c6340d6459e05787f644c2447d2595f5d3a54b 0 lib/simplegit.rb
Burada yine, aslında bize dosya dizinimizin şu anda neye benzediğini gösterecek bir perde-gerisi aracı olan, git ls-files
komutunu kullanıyoruz.
İndeks teknik olarak bir ağaç yapısı değildir - aslında düzleştirilmiş bir dışavurum olarak uygulanmıştır - ancak amacımız için buna yeterince yakındır.
Çalışma Dizini
Son olarak, çalışma dizininiz (ayrıca "çalışma ağacı" olarak da adlandırılır).
Diğer iki ağaç, içeriklerini etkili ancak kullanışsız bir şekilde .git
klasörü içinde saklar.
Çalışma dizini, bunları gerçek dosyalara açar, bu da onları düzenlemenizi çok daha kolay hale getirir.
Çalışma dizinini, değişikliklerinizi (izleme alanına alıp ardından katkı olarak proje geçmişinize eklemeden önce) deneyebileceğiniz bir kum havuzu (sandbox) olarak düşünün.
$ tree
.
├── README
├── Rakefile
└── lib
└── simplegit.rb
1 directory, 3 files
İş Akışı
Git’in tipik iş akışı, bu üç ağacı manipüle ederek projenizin ardışık olarak daha gelişmiş durumlarının pozlarını kaydetmektir.
Hadi bu süreci görselleştirelim: Diyelim ki tek bir dosyanın bulunduğu yeni bir dizine giriyorsunuz.
Mavi renkte göstereceğimiz bu dosyayı v1 olarak adlandıralım.
Şimdi git init
komutunu çalıştırıyoruz: bu daha doğmamış master
dalına işaret eden bir HEAD referansı ile bir Git reposu oluşturacak.
Bu noktada, sadece çalışma dizini ağacında içerik bulunmaktadır.
Şimdi bu dosyayı katkı olarak işlemek istiyoruz, bu yüzden git add
komutunu kullanarak çalışma dizinindeki içeriği alıp indekse (izlem) kopyalarız.
Ardından git commit
komutunu çalıştırırız: bu komut dizinin içeriğini alır ve onu kalıcı bir poz olarak kaydeder, o poza işaret eden bir katkı nesnesi oluşturur ve master
'ı bu katkıya işaret edecek şekilde günceller.
git status
komutunu çalıştırırsak, henüz değişiklik yapmadığımız için, her üç ağacın da aynı olduğunu göreceğiz.
Şimdi dosyayı değiştirip, katkı olarak işlemek istiyoruz. Aynı süreci geçireceğiz; önce çalışma dizininde dosyayı değiştireceğiz. Dosyanın bu sürümüne v2 diyelim ve onu kırmızı renkle gösterelim.
Şu anda git status
komutunu çalıştırırsak, dosyayı kırmızı renkte ve ``Changes not staged for commit`` açıklamasıyla göreceğiz; çünkü bu giriş indeks ile çalışma dizini arasındaki bir farklılık olarak görünecektir.
Daha sonra bu dosya üzerinde git add
komutunu çalıştırarak, onu indekse ekliyoruz.
Bu noktada, git status
komutunu çalıştırırsak, dosyayı yeşil renkte "Yapılacak katkılar" altında göreceğiz; çünkü indeks ile uç farklıdır - yani önerilen sıradaki katkımız, işlenmiş son katkımızdan farklıdır.
Son olarak, katkılama işlemini tamamlamak için git commit
komutunu çalıştırıyoruz.
Şimdi git status
komutunu çalıştırdığımızda, tekrar tüm ağaçlar aynı olduğu için herhangi bir çıktı almayacağız.
Dallar arasında geçiş yapmak veya kopyalamak benzer bir süreçten geçer. Yeni bir dala geçiş yapmak, HEAD işaretçisini yeni dal referansını gösterecek şekilde değiştirir, indeks içeriğini o katkının pozuyla doldurur ve son olarak indeks içeriğini çalışma dizinine kopyalar.
Reset Komutunun Rolü
reset
komutu, bu bağlamda görüldüğünde daha mantıklı hale gelir.
Bu örnekleri daha iyi anlamak için, diyelim ki file.txt
dosyasını tekrar değiştirdik ve üçüncü kez katkıladık.
Şimdi geçmişimiz şöyle görünüyor:
Şimdi, reset
çağrıldığında tam olarak ne yaptığını adım adım görelim.
Basit ve öngörülebilir bir şekilde üç ağacı doğrudan manipüle eder.
Üç temel işlem yapar.
Adım 1: HEAD’i Taşı
İlk olarak, reset
'in yapacağı şey, HEAD’in işaret ettiği yeri taşımaktır.
Bu, HEAD’in kendisini değiştirmekle aynı değildir (bunu checkout
yapar); reset
, HEAD’in işaret ettiği dalı taşır.
Bu, eğer HEAD master
dalına ayarlanmışsa (yani şu anda master
dalındaysanız), git reset 9e5e6a4
komutunu çalıştırdığınızda master
'ı 9e5e6a4
noktasına getirecek demektir.
Bir katkı ile reset
'in hangi biçimini çağırırsanız çağırın, bu her zaman yapmaya çalışacağı ilk şeydir.
reset --soft
komutuyla orada duracaktır.
Şimdi o diyagrama bir kez daha göz atın ve neler olduğunun farkına varın: temel olarak son git commit
komutunu geri aldı.
git commit
komutunu çalıştırdığınızda, Git yeni bir katkı oluşturur ve HEAD’in işaret ettiği dalı oraya taşır.
reset
komutunu HEAD~
'e (HEAD’in önceli) geri alırsanız, dalı indeks veya çalışma dizininde herhangi bir değişiklik yapmadan eski konumuna geri taşırsınız.
Şimdi indeksi güncelleyebilir ve git commit
komutunu tekrar çalıştırarak git commit --amend
komutunun yaptığını başarabilirsiniz (bkz Son Katkıyı Değiştirme).
Adım 2: İndeksi Güncelleme (--mixed)
Şimdi git status
komutunu çalıştırırsanız, indeks ile yeni HEAD arasındaki farkı yeşil renkte göreceksiniz.
reset
'in yapacağı bir sonraki şey, indeksi, HEAD’in şu anda işaret ettiği pozun içeriğiyle güncellemektir.
--mixed
seçeneğini belirtirseniz, reset
işlemi bu noktada duracaktır.
Bu aynı zamanda varsayılan davranıştır, yani hiçbir seçenek belirtmezseniz (bu durumda yalnızca git reset HEAD~
), komut burada duracaktır.
Şimdi o diyagrama bir kez daha bir göz atın ve neler olduğunun farkına varın: hala son commit
işleminizi geri aldınız, ancak aynı zamanda her şey izlem alanı dışına çıktı.
Yani, tüm git add
ve git commit
komutlarınızı çalıştırmadan önceki duruma geri döndünüz.
Adım 3: Çalışma Dizinini Güncelleme (--hard)
reset
'in yapacağı üçüncü şey, çalışma dizinini indeks gibi yapmaktır.
--hard
seçeneğini kullanırsanız, bu aşamaya devam eder.
Az önce ne olduğunu bir düşünelim.
Son katkınızı, git add
ve git commit
komutlarını, ve çalışma dizininde yaptığınız tüm çalışmayı geri aldınız.
--hard
bayrağının reset
komutunu tehlikeli hale getiren tek yol olduğunu ve Git’in bir veriyi gerçekten yok edeceği çok az durumdan biri olduğunu bilmeniz çok önemlidir.
reset
'in diğer herhangi bir kullanımı oldukça kolay bir şekilde geri alınabilirken, --hard
seçeneği bunu yapamaz; çünkü çalışma dizinindeki dosyaların üzerine zorla yeniden yazar.
Bu özel durumda, Git veritabanımızda dosyanın v3 sürümüne bir katkı olarak hala sahibiz ve reflog
'umuza bakarak onu geri alabiliriz; ancak onu katkılamadan bıraksaydık, Git o dosyanın üzerine yeniden yazacaktı ve onu geri alınamaz hale getirecekti.
Özet
reset
komutu, belirli bir sırayla bu üç ağacın üzerine yazar ve siz ona durmasını söylediğinizde durur:
-
HEAD’in işaret ettiği dalı taşı (eğer
--soft
kullanılmışsa burada dur) -
İndeksi HEAD’in aynısı yap (eğer
--hard
kullanılmamışsa burada dur) -
Çalışma dizinini indeks gibi yap
Dosya Dizini ile Sıfırlama
Bu, reset
'in temel formundaki davranışını kapsar, ancak isterseniz bir dizin de belirtebilirsiniz.
Bir dizin belirtirseniz, reset
adım 1’i atlar ve geri kalan işlemleri belirli bir dosya veya dosya kümesiyle sınırlar.
Bu aslında bir bakıma mantıklıdır - HEAD sadece bir işaretçidir ve onu aynı anda bir katkının bir kısmına ve başka bir katkının başka bir kısmına doğrultamazsınız.
Ancak indeks ve çalışma dizini kısmen güncellenebilir, bu nedenle reset yoluna 2. ve 3. adımlarla devam eder.
Öyleyse, git reset file.txt
komutunu çalıştıralım.
Bu form (bir katkı SHA-1 karması, bir dal ya da --soft
veya --hard
gibi bir bayrak belirtmediğiniz için) git reset --mixed HEAD file.txt
söz diziminin kısaltmasıdır ve şunları yapar:
-
HEAD’in işaret ettiği dalı taşır (atlanır)
-
İndeksi HEAD’e benzet (burada dur)
Yani temelde file.txt
dosyasını HEAD’ten indekse kopyalar.
Bu, pratikte dosyanın izlemden çıkarılması etkisine sahiptir.
Bu komutun diyagramına bakarsak ve git add
komutunun ne yaptığını düşünürsek, tam olarak zıt olduklarını görürüz.
Bu nedenle, git status
komutunun çıktısı, bir dosyayı izlemden çıkarmak için bunu çalıştırmanızı önerir.
(Daha fazla bilgi için: İzleme Alınmış Dosyayı izlemden Çıkarmak)
Git’in "veriyi HEAD’den çek" dediğimizi varsaymasını önlemek için belirli bir katkıyı belirtebiliriz.
Yoksa, sadece git reset eb43bf file.txt
gibi bir şey çalıştırmak yeterdi.
Bununla, etkili bir şekilde (aslında tüm bu adımları geçmeden) dosyanın içeriğini çalışma dizinindeki v1'e geri döndürdük, üzerine git add
çalıştırdık, ardından tekrar v3'e geri döndürdük.
Şimdi git commit
komutunu çalıştırırsak, aslında çalışma dizinimizde hiç sahip olmadığımız halde, dosyayı tekrar v1'e geri döndüren bir değişikliği kaydedecektir.
Ayrıca, aynı git add
gibi, reset
komutu da içeriği izlemden parça parça çıkarmak için --patch
seçeneğini kabul eder.
Bu şekilde içeriği seçici olarak izlemden çıkarabilir veya geri alabilirsiniz.
Sıkıştırma (squashing)
Bu yeni keşfedilen güçle ilginç bir şeyin nasıl yapılacağına bakalım: katkıları sıkıştırmak.
Diyelim ki ``oops.``, ``WIP`` ve ``bu dosyayı unuttum`` gibi mesajlar içeren bir dizi katkınız var.
Bunları hızlı ve kolay bir şekilde tek bir işleme dönüştürmek ve gerçekten zeki görünmenizi sağlamak için reset
komutunu kullanabilirsiniz.
Sıkıştırma (Katkıları Sıkıştırmak) bunu yapmanın başka bir yoludur, ancak bu örnekte reset
'i kullanmak daha basittir.
Diyelim ki, ilk katkının bir dosyaya sahip olduğu, ikinci katkının yeni bir dosya ekleyip ilkini değiştirdiği ve üçüncü katkının ilk dosyayı yeniden değiştirdiği bir projeniz var. İkinci katkı devam eden bir çalışmaydı ve siz onu ortadan kaldırmak istiyorsunuz.
HEAD dalını daha eski bir katkıya (saklamak istediğiniz en son katkıya) geri taşımak için git reset --soft HEAD~2
komutunu çalıştırabilirsiniz:
Ve sonra tekrar "git commit" komutunu çalıştırın:
Artık itme yapabileceğiniz geçmişinizin, birinci katkının file-a.txt
dosyasının v1 sürümüne sahip olduğunu ve ikinci bir katkının hem file-a.txt
'yi v3 sürümüne değiştirdiğini hem de file-b.txt
'yi eklediğini görebilirsiniz.
Dosyanın v2 sürümüyle yapılan kayıt ise artık geçmişte yer almaz.
Check It Out
Son olarak, checkout
ve reset
arasındaki farkı merak ediyor olabilirsiniz.
Reset
gibi, checkout
da üç ağacı manipüle eder ama komuta bir dosya dizini belirtip belirtmemenize bağlı olarak biraz farklılık gösterir.
Dizinsiz
git checkout [dal]
komutunu çalıştırmak, üç ağacı da [dal]
gibi görünmesi için güncellemek açısından git reset --hard [dal]
komutunu çalıştırmakla benzerdir, ancak arada iki önemli fark vardır.
İlk olarak, reset --hard
'ın aksine, checkout
çalışma dizini güvenlidir; değiştirilmiş dosyaları silinmekten korumak için bir kontrol yapılır.
Aslında, biraz daha akıllıca davranır — çalışma dizininde basit bir birleştirme yapmaya çalışır, bu nedenle değiştirmemiş olduğunuz tüm dosyalar güncellenecektir.
Buna karşın, reset --hard
, sorgulamadan her şeyi değiştirir.
İkinci önemli fark, checkout
'un HEAD’i nasıl güncellediğidir.
Reset
komutu, HEAD’in işaret ettiği dalı taşırken, checkout
komutu, HEAD’in kendisini başka bir dala işaret etmek üzere taşır.
Örneğin, farklı katkılara işaret eden master
ve develop
dallarımız olduğunu ve şu anda develop
dalında olduğumuzu varsayalım (yani HEAD buna işaret eder).
Eğer git reset master
komutunu çalıştırırsak, develop
dalı artık master
'ın işaret ettiği aynı katkıya işaret eder.
Eğer bunun yerine git checkout master
komutunu çalıştırırsak, develop
dalı yer değiştirmez, HEAD kendisi hareket eder.
HEAD artık master
'ı işaret etmektedir.
Yani, her iki durumda da HEAD’i A katkısına taşıyoruz, ancak bunu yapma şeklimiz çok farklıdır.
Reset
komutu, HEAD’in işaret ettiği dali taşırken, checkout
komutu HEAD’i taşır.
Dizinli
checkout
komutunu çalıştırmanın diğer bir yolu, dosya yolunu belirtmek şeklinde olup, bu da reset
gibi, HEAD’i taşımaz.
Bu, belirli bir dosyayı belirli bir katkıda dizine güncelleyen, ancak aynı zamanda çalışma dizinindeki dosyayı da üzerine yazan git reset [dal] dosya
komutu gibi davranır.
Eğer reset
komutu buna izin verseydi, tam olarak git reset --hard [dal] dosya
komutuna benzer olurdu — çalışma dizini güvende olmaz ve HEAD’i taşımaz.
Ayrıca, git reset
ve git add
gibi, checkout
da dosya içeriğini parça parça geri almanıza izin vermek için --patch
seçeneğini kabul eder.
Özet
Artık reset
komutunu genel olarak anladınız ve daha rahat hissediyorsunuzdur. Ancak yine de tam olarak checkout
komutundan nasıl farklı olduğu konusunda kafanızda biraz karışıklık kalmış olabilir. Zaten farklı kullanımların tüm kurallarını ezbere bilmek de imkansızdır.
İşte hangi komutların hangi ağaçları etkilediğine dair bir hatırlatma notu.
HEAD
sütunu, komutun HEAD’in işaret ettiği referansı (dalı) taşıyıp taşımadığını belirtir; ve eğer HEAD’i taşıyorsa HEAD
, aksi takdirde REF
okunur.
"Çalışma Ağacı Güvende mi?" sütununa özellikle dikkat edin — eğer Hayır yazıyorsa, bu komutu çalıştırmadan önce bir kez daha düşünün.
HEAD | Index | Workdir | WD Safe? | |
---|---|---|---|---|
Katkı Seviyesi |
||||
|
REF |
NO |
NO |
YES |
|
REF |
YES |
NO |
YES |
|
REF |
YES |
YES |
NO |
|
HEAD |
YES |
YES |
YES |
File Level |
||||
|
NO |
YES |
NO |
YES |
|
NO |
YES |
YES |
NO |