-
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
--softkullanılmışsa burada dur) -
İndeksi HEAD’in aynısı yap (eğer
--hardkullanı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 |