Git Nedir? Kapsamlı Bir Teknik İnceleme
Git, yazılım geliştirme dünyasının temel taşlarından biri haline gelmiş, dağıtık bir versiyon kontrol sistemidir (DVCS). Milyonlarca geliştirici tarafından kullanılan bu araç, kod tabanındaki değişiklikleri izlemek, yönetmek ve ekipler arasında işbirliğini kolaylaştırmak için vazgeçilmez bir çözüm sunar. Linux çekirdeği geliştiricisi Linus Torvalds tarafından 2005 yılında yaratılan Git, başlangıçta Linux çekirdeğinin karmaşık ve geniş kapsamlı geliştirme sürecini yönetmek amacıyla tasarlanmıştır. Ancak zamanla, esnekliği, hızı ve güçlü özellikleri sayesinde her ölçekten yazılım projesinin standart versiyon kontrol sistemi haline gelmiştir.
Bu makalede, Git’in ne olduğunu, neden bu kadar önemli olduğunu, temel mimarisini, yaygın kullanılan komutlarını, ileri düzey özelliklerini ve yazılım geliştirme ekosistemindeki yerini detaylı bir şekilde inceleyeceğiz. Amacımız, hem yeni başlayanlar hem de deneyimli geliştiriciler için Git hakkında kapsamlı ve teknik bir rehber sunmaktır.
Versiyon Kontrol Sistemleri (VCS) Nedir?
Versiyon Kontrol Sistemleri (VCS), zaman içinde dosyalarda yapılan değişiklikleri yönetmeye yarayan sistemlerdir. Bir projenin farklı versiyonlarını kaydetme, bu versiyonlar arasında gezinme, belirli bir noktadaki değişiklikleri geri alma ve birden fazla kişinin aynı proje üzerinde eş zamanlı çalışmasını sağlama gibi temel işlevleri yerine getirirler. Yazılım geliştirme bağlamında, bu sistemler kod tabanının evrimini takip etmek, hataları bulmak ve düzeltmek için kritik öneme sahiptir.
VCS’nin Amacı ve Önemi
VCS’nin temel amacı, proje geçmişinin eksiksiz bir kaydını tutmaktır. Bu sayede:
* Değişiklik Takibi: Kimin, ne zaman ve hangi değişiklikleri yaptığını görmek mümkündür.
* Geri Alma Yeteneği: Yanlış yapılan değişiklikler kolayca geri alınabilir veya projenin önceki bir stabil durumuna dönülebilir.
* İşbirliği: Birden fazla geliştiricinin aynı anda, birbirlerinin çalışmalarını ezmeden aynı kod tabanı üzerinde çalışmasını sağlar.
* Çatışma Çözümü: İki veya daha fazla geliştiricinin aynı dosyanın aynı bölümünde yaptığı değişiklikler arasındaki çakışmaları tespit eder ve çözme mekanizmaları sunar.
* Denetlenebilirlik: Projenin geçmişi tamamen izlenebilir olduğu için, hataların kaynağını bulmak ve güvenlik açıklarını gidermek daha kolaydır.
* Yedekleme: Projenin geçmişi bir depoda saklandığı için, yerel bir arıza durumunda bile kod kaybolmaz.
Merkezi (CVCS) ve Dağıtık (DVCS) Sistemler Arasındaki Farklar
Versiyon kontrol sistemleri genel olarak iki ana kategoriye ayrılır: Merkezi Versiyon Kontrol Sistemleri (CVCS) ve Dağıtık Versiyon Kontrol Sistemleri (DVCS).
Merkezi Versiyon Kontrol Sistemleri (CVCS):
CVCS’de (örneğin Subversion – SVN, CVS), tüm projenin geçmişi ve ana kod tabanı tek bir merkezi sunucuda bulunur. Geliştiriciler, sunucudan kodun en son halini “çeker” (checkout), üzerinde çalışır ve değişikliklerini sunucuya “gönderir” (commit).
* Avantajları: Yönetimi daha basit olabilir, tüm geçmiş tek bir yerde olduğu için erişim kontrolü daha kolaydır.
* Dezavantajları:
* Tek Hata Noktası: Merkezi sunucu çökerse veya ulaşılamaz hale gelirse, tüm ekip çalışmayı durdurur ve projenin geçmişine erişim kaybolur.
* Çevrimdışı Çalışma Zorluğu: Sunucuya bağlantı olmadan commit yapılamaz veya geçmişe bakılamaz.
* Performans Sorunları: Büyük ekiplerde veya coğrafi olarak dağınık ekiplerde performans darboğazları yaşanabilir.
Dağıtık Versiyon Kontrol Sistemleri (DVCS):
Git, Mercurial gibi DVCS’lerde, her geliştiricinin kendi yerel makinesinde projenin tüm geçmişinin ve kod tabanının tam bir kopyası bulunur. Geliştiriciler, yerel depolarında değişiklikleri commit eder ve daha sonra bu değişiklikleri diğer geliştiricilerin depolarına veya ortak bir uzak depoya “iter” (push) veya “çeker” (pull).
* Avantajları:
* Yedeklilik: Her geliştiricinin yerel deposu, projenin tüm geçmişini içerdiği için, merkezi bir sunucuya bağımlılık azalır. Merkezi sunucu çökse bile, herhangi bir geliştiricinin deposundan proje kurtarılabilir.
* Çevrimdışı Çalışma: Geliştiriciler, internet bağlantısı olmadan bile commit yapabilir, geçmişi inceleyebilir ve dallanma (branching) gibi işlemleri gerçekleştirebilir.
* Hız: Çoğu işlem yerel depo üzerinde gerçekleştiği için CVCS’ye göre çok daha hızlıdır.
* Esneklik: Dallanma ve birleştirme işlemleri çok daha kolay ve verimlidir, bu da deneysel özellikler üzerinde çalışmayı veya paralel geliştirmeyi teşvik eder.
* Ölçeklenebilirlik: Büyük ve coğrafi olarak dağınık ekipler için idealdir.
Git’in Temel Felsefesi ve Mimari Yapısı
Git’in gücü, temel felsefesinden ve mimarisinden gelir. Diğer VCS’lerin aksine, Git dosyaları değişiklik setleri (delta) olarak depolamaz; bunun yerine, her commit’te projenin tam bir anlık görüntüsünü (snapshot) kaydeder.
Git Nasıl Çalışır? Anlık Görüntüler (Snapshots) ve Farklar (Diffs)
Git’in temel çalışma prensibi, dosyaların içeriğini anlık görüntüler olarak ele almasıdır. Bir git commit komutu çalıştırdığınızda, Git o anki projenin tüm dosyalarının bir “anlık görüntüsünü” alır ve bu anlık görüntünün bir referansını depolar. Eğer bir dosya değişmemişse, Git yeni bir kopyasını depolamak yerine, önceki anlık görüntüdeki aynı dosyanın referansını kullanır. Bu, disk alanından tasarruf sağlar ve Git’i inanılmaz derecede hızlı yapar.
Bir commit, sadece bir anlık görüntü referansı değildir; aynı zamanda bu anlık görüntüyü oluşturan geliştiricinin adı, e-posta adresi, commit mesajı ve bir önceki commit’e (veya birden fazla ebeveyn commit’e) işaret eden bir referans gibi meta verileri de içerir. Bu zincirleme yapı, projenin tüm tarihini bir yönlendirilmiş asiklik grafik (DAG) olarak görselleştirmemizi sağlar.
Farklar (diffs) ise Git’in çalışma prensibinin bir sonucu olarak ortaya çıkar. İki farklı anlık görüntü arasındaki farkı hesaplamak, Git için çok hızlı bir işlemdir çünkü her iki anlık görüntüdeki dosya referanslarını karşılaştırması yeterlidir.
Git’in Üç Durumu: Working Directory, Staging Area, Git Repository
Git’in anlaşılması gereken en önemli kavramlardan biri, dosyaların üç ana durumu veya alanıdır:
1. Working Directory (Çalışma Dizini): Projenizin dosyalarının yerel kopyalarının bulunduğu, üzerinde aktif olarak çalıştığınız alandır. Bu, bilgisayarınızdaki projenizin gerçek klasörüdür. Burada dosyaları düzenler, siler veya yenilerini oluşturursunuz.
2. Staging Area (Hazırlık Alanı / Index): Git’in “index” veya “hazırlık alanı” olarak adlandırdığı bu alan, bir sonraki commit’e dahil edilecek değişikliklerin kaydedildiği geçici bir alandır. git add komutuyla dosyaları çalışma dizininden hazırlık alanına alırsınız. Bu, bir commit yapmadan önce hangi değişikliklerin dahil edileceğini seçmenize olanak tanır. Örneğin, bir dosyada birden fazla değişiklik yaptıysanız ve sadece belirli bir kısmını commit etmek istiyorsanız, bunu hazırlık alanı aracılığıyla yapabilirsiniz.
3. Git Repository (Git Deposu): Bu, Git’in projenizin tüm geçmişini ve versiyonlarını depoladığı alandır. git commit komutuyla hazırlık alanındaki değişiklikler Git deposuna kalıcı olarak kaydedilir. Bu depo, .git adlı gizli bir klasör içinde bulunur ve tüm commit’leri, dallanmaları, etiketleri ve diğer Git nesnelerini içerir.
Bu üç alan arasındaki akış genellikle şu şekildedir:
* Çalışma Dizini’nde dosyaları düzenlersiniz.
* Değişikliklerin bir kısmını veya tamamını git add ile Hazırlık Alanı’na eklersiniz.
* Hazırlık Alanı’ndaki değişiklikleri git commit ile Git Deposu’na kalıcı olarak kaydedersiniz.
Git Temel Komutları ve İş Akışı
Git’i etkili bir şekilde kullanmak için bazı temel komutları ve iş akışını anlamak kritiktir.
Depo Oluşturma ve Klonlama
* git init: Mevcut bir dizini yeni bir Git deposu olarak başlatır. Bu komut, dizin içine .git adlı gizli bir alt dizin oluşturur ve bu dizin, projenizin tüm Git geçmişini ve meta verilerini saklar.
mkdir my_project
cd my_project
git init
* git clone [url]: Uzak bir Git deposunun (örneğin GitHub’da barındırılan bir depo) tam bir kopyasını yerel makinenize indirir. Bu, projenin tüm geçmişini ve tüm dallarını da içerir.
git clone https://github.com/kullaniciadi/repo_adi.git
Değişiklikleri Takip Etme ve Kaydetme
* git status: Çalışma dizininizin ve hazırlık alanınızın mevcut durumunu gösterir. Hangi dosyaların değiştirildiğini, hangilerinin hazırlanmaya (staging) hazır olduğunu ve hangilerinin takip edilmediğini (untracked) belirtir.
git status
* git add [dosya_adı]: Belirtilen dosyayı veya dosyaları çalışma dizininden hazırlık alanına ekler. Eğer . (nokta) kullanılırsa, tüm değiştirilen ve takip edilmeyen dosyaları ekler.
git add index.html
git add .
* git commit -m "[mesaj]": Hazırlık alanındaki değişiklikleri Git deposuna kalıcı olarak kaydeder. -m bayrağı, commit mesajını doğrudan komut satırında belirtmenizi sağlar. İyi bir commit mesajı, yapılan değişikliğin amacını ve içeriğini kısa ve öz bir şekilde açıklamalıdır.
git commit -m "Ana sayfa tasarımını güncelledim ve navigasyon menüsünü ekledim"
* git log: Deponun commit geçmişini gösterir. Her commit’in SHA-1 karma değeri, yazar, tarih ve commit mesajı gibi bilgilerini listeler. Çeşitli bayraklarla (örn. --oneline, --graph, --all) çıktısı özelleştirilebilir.
git log
git log --oneline --graph
* git diff: Çalışma dizinindeki değişiklikleri hazırlık alanındaki veya son commit’teki değişikliklerle karşılaştırır.
* git diff: Çalışma dizini ile hazırlık alanı arasındaki farkları gösterir.
* git diff --staged: Hazırlık alanı ile son commit arasındaki farkları gösterir.
* git diff HEAD: Çalışma dizini ile son commit arasındaki farkları gösterir.
Dallanma (Branching) ve Birleştirme (Merging)
Dallanma, Git’in en güçlü ve en çok kullanılan özelliklerinden biridir. Bir projenin ana kod tabanından ayrılıp, yeni özellikler geliştirmek veya hataları düzeltmek için izole bir ortamda çalışmayı sağlar.
* git branch: Mevcut dalları listeler. git branch [yeni_dal_adı] ile yeni bir dal oluşturulur.
git branch
git branch feature/login-page
* git checkout [dal_adı] / git switch [dal_adı]: Başka bir dala geçiş yapar. git switch daha yeni ve dallanma işlemleri için daha net bir komuttur.
git checkout feature/login-page
git switch feature/login-page
* git checkout -b [yeni_dal_adı]: Yeni bir dal oluşturur ve o dala anında geçiş yapar.
git checkout -b feature/user-profile
* git merge [kaynak_dal]: Belirtilen daldaki değişiklikleri mevcut dala birleştirir. Birleştirme işlemi genellikle iki şekilde gerçekleşir:
* Fast-forward Merge: Eğer birleştirilecek dal, mevcut daldan doğrudan türemiş ve arada başka commit’ler yoksa, Git sadece mevcut dalın işaretçisini ileri taşır.
* Three-way Merge: Eğer her iki dalda da ortak bir atadan sonra bağımsız değişiklikler yapılmışsa, Git birleştirme commit’i oluşturarak her iki dalın değişikliklerini bir araya getirir.
# feature/login-page dalındaki değişiklikleri main dalına birleştir
git switch main
git merge feature/login-page
* Çatışma Çözümü (Conflict Resolution): İki dal birleştirilirken aynı dosyanın aynı satırlarında farklı değişiklikler yapıldıysa, Git otomatik olarak birleştirme yapamaz ve bir çatışma oluşur. Bu durumda, Git çatışan dosyaları işaretler ve geliştiricinin manuel olarak hangi değişikliklerin korunacağına karar vermesini bekler. Çatışma çözüldükten sonra dosyalar git add ile hazırlanır ve git commit ile birleştirme tamamlanır.
Uzak Depolarla Çalışma (Remote Repositories)
Git’in dağıtık yapısı, uzak depolar aracılığıyla ekiplerin işbirliği yapmasını sağlar. Uzak depolar genellikle GitHub, GitLab veya Bitbucket gibi platformlarda barındırılır.
* git remote -v: Uzak depoları listeler.
git remote -v
# origin https://github.com/kullaniciadi/repo_adi.git (fetch)
# origin https://github.com/kullaniciadi/repo_adi.git (push)
* git remote add [isim] [url]: Yeni bir uzak depo ekler. Genellikle ana uzak depo için “origin” ismi kullanılır.
git remote add origin https://github.com/kullaniciadi/yeni_repo.git
* git fetch [uzak_depo_adı]: Uzak depodaki değişiklikleri yerel deponuza indirir, ancak çalışma dizininizi veya yerel dallarınızı güncellemez. Bu, değişiklikleri incelemek için güvenli bir yoldur.
git fetch origin
* git pull [uzak_depo_adı] [dal_adı]: Uzak depodaki değişiklikleri hem indirir (fetch) hem de mevcut yerel dalınıza birleştirir (merge). git pull origin main komutu, uzak depodaki main dalındaki değişiklikleri yerel main dalınıza çeker.
git pull origin main
* git push [uzak_depo_adı] [dal_adı]: Yerel deponuzdaki commit’leri uzak depoya gönderir. İlk push’ta, -u (upstream) bayrağı ile yerel dalın uzak depodaki karşılığını ayarlayabilirsiniz, böylece sonraki push’lar için sadece git push yazmak yeterli olur.
git push origin main
git push -u origin feature/new-feature
Git’in İleri Düzey Özellikleri ve Kullanım Alanları
Git, temel komutlarının ötesinde, daha karmaşık senaryolar ve daha temiz bir commit geçmişi için bir dizi ileri düzey özellik sunar.
Rebasing ve Merging Farkı
Hem git merge hem de git rebase dalları birleştirmek için kullanılır, ancak bunu farklı şekillerde yaparlar ve farklı sonuçlar doğururlar.
* Merging: Birleştirme işlemi, iki dalın ortak atası ile her bir dalın son commit’i arasındaki tüm değişiklikleri bir araya getiren yeni bir “birleştirme commit’i” oluşturur. Bu, projenin tarihini korur ve hangi birleştirmenin ne zaman yapıldığını açıkça gösterir. Ancak, sık sık birleştirme yapıldığında commit geçmişi karmaşık ve dallı bir yapıya bürünebilir.
* Rebasing: Rebasing, bir dalın commit’lerini başka bir dalın üzerine “yeniden temel almaktır”. Yani, bir dalın commit’lerini alıp, onları başka bir dalın en son commit’inden sonra yeniden uygular. Bu, commit geçmişini doğrusal ve temiz tutar, sanki tüm değişiklikler tek bir dalda sıralı olarak yapılmış gibi görünür.
Ne Zaman Ne Kullanılmalı?
* Merge: Ortak dallar (örneğin main veya develop) için genellikle merge tercih edilir, çünkü tarihçeyi değiştirmez ve işbirliği yapılan dallarda daha güvenlidir.
* Rebase: Kişisel çalışma dallarınızda (henüz uzak depoya push edilmemiş dallar) veya küçük, kısa ömürlü özellik dallarında rebase kullanmak, daha temiz bir commit geçmişi elde etmenizi sağlar. Ancak, uzak depoya push edilmiş dalları rebase etmekten kaçınılmalıdır, çünkü bu, başkalarının geçmişini değiştirir ve ciddi sorunlara yol açabilir.
Stashing
git stash: Çalışma dizininizdeki ve hazırlık alanınızdaki henüz commit edilmemiş değişiklikleri geçici olarak kaydetmenizi sağlar, böylece başka bir dala geçebilir veya acil bir iş üzerinde çalışabilirsiniz. Değişiklikler bir yığın (stack) üzerinde saklanır ve daha sonra git stash apply veya git stash pop ile geri getirilebilir.
git stash save "login page changes" # Değişiklikleri mesajla kaydet
git stash list # Kaydedilmiş stash'leri listele
git stash pop # En son stash'i uygula ve yığından kaldır
Etiketleme (Tagging)
git tag: Projenin belirli noktalarını (genellikle yayın versiyonlarını) işaretlemek için kullanılır. Etiketler, bir projenin v1.0.0 veya beta-release gibi önemli kilometre taşlarını belirtir.
* Lightweight Tag: Sadece bir isim ve bir commit’e işaret eder.
* Annotated Tag: Etiketi oluşturan kişi, tarih, etiket mesajı gibi ek meta verileri içerir ve genellikle daha resmi sürümler için kullanılır.
git tag -a v1.0.0 -m "Versiyon 1.0.0 yayınlandı"
git tag # Tüm etiketleri listele
git push origin v1.0.0 # Etiketi uzak depoya gönder
Git Hooks
Git Hooks, Git olayları (commit öncesi, push sonrası vb.) gerçekleştiğinde otomatik olarak belirli betikleri çalıştırmanıza olanak tanıyan güçlü bir özelliktir. Örneğin, pre-commit hook’u, bir commit yapılmadan önce kod stilini kontrol edebilir veya testleri çalıştırabilir. .git/hooks dizininde bulunur.
Gitignore Dosyası
.gitignore dosyası, Git’in takip etmesini istemediğiniz dosya ve dizinleri belirtmenizi sağlar. Derleme çıktıları, günlük dosyaları, IDE konfigürasyonları veya hassas bilgiler içeren dosyalar genellikle .gitignore‘a eklenir.
# Log dosyaları
*.log
Node.js bağımlılıkları
node_modules/
MacOS sistem dosyaları
.DS_Store
Alt Modüller (Submodules)
git submodule: Bir Git deposunun içine başka bir Git deposunu alt dizin olarak eklemenizi sağlar. Bu, ana projenizin bağımlılıklarını yönetmek veya birden fazla projenin ortak bir bileşeni paylaşmasını sağlamak için kullanışlıdır.
Git Kullanmanın Avantajları
Git’in yaygın olarak benimsenmesinin ardında yatan birçok önemli avantaj bulunmaktadır:
* Hız ve Performans: Git, çoğu işlemi yerel olarak gerçekleştirdiği için inanılmaz derecede hızlıdır. Commit yapmak, dallar arasında geçiş yapmak veya geçmişi incelemek saniyeler içinde tamamlanır.
* Veri Bütünlüğü ve Güvenlik: Git, her nesneyi (dosya içeriği, dizin yapısı, commit’ler) SHA-1 karma değeriyle tanımlar. Bu, verilerin değiştirilmediğini garanti eder ve projenin geçmişinin güvenli ve sağlam kalmasını sağlar.
* Dağıtık Yapı: Her geliştiricinin projenin tam bir kopyasına sahip olması, yedeklilik sağlar ve merkezi bir sunucuya olan bağımlılığı ortadan kaldırır. Çevrimdışı çalışma yeteneği, üretkenliği artırır.
* Dallanma ve Birleştirme Kolaylığı: Git’in dallanma modeli son derece hafiftir ve hızlıdır. Bu, geliştiricilerin yeni özellikler üzerinde güvenle çalışmasını, deneysel kodları test etmesini ve hataları izole bir şekilde düzeltmesini sağlar. Birleştirme işlemleri de oldukça güçlü ve esnektir.
* Açık Kaynak ve Geniş Topluluk Desteği: Git açık kaynaklıdır ve dünya çapında milyonlarca geliştirici tarafından desteklenmektedir. Bu, zengin bir dokümantasyon, birçok eğitim kaynağı ve aktif bir topluluk anlamına gelir.
* Esneklik ve Ölçeklenebilirlik: Git, küçük kişisel projelerden binlerce geliştiricinin çalıştığı büyük kurumsal projelere kadar her ölçekteki projeye uyum sağlayabilir.
Git’in Entegrasyonu ve Ekosistemi
Git, sadece bir komut satırı aracı olmaktan çok daha fazlasıdır; modern yazılım geliştirme ekosisteminin ayrılmaz bir parçasıdır.
* GitHub, GitLab, Bitbucket: Bu platformlar, Git depolarını barındırmak, ekip işbirliğini yönetmek, kod incelemeleri yapmak, hata takibi ve CI/CD (Sürekli Entegrasyon/Sürekli Teslimat) süreçlerini entegre etmek için araçlar sunar. Git’i bu platformlarla birlikte kullanarak, geliştirme süreçleri çok daha verimli hale gelir.
* IDE Entegrasyonları: Visual Studio Code, IntelliJ IDEA, Eclipse gibi modern IDE’lerin çoğu, Git ile doğrudan entegrasyon sunar. Bu entegrasyonlar, commit yapma, dallar arasında geçiş yapma, değişiklikleri görselleştirme ve çatışmaları çözme gibi işlemleri IDE içinden kolayca yapmaya olanak tanır.
* CI/CD Süreçlerindeki Rolü: Git, Sürekli Entegrasyon (CI) ve Sürekli Teslimat (CD) boru hatlarının temelini oluşturur. Geliştiriciler Git’e kodlarını push ettiklerinde, CI/CD araçları (Jenkins, GitHub Actions, GitLab CI/CD, Azure DevOps vb.) otomatik olarak testleri çalıştırabilir, kodu derleyebilir ve uygulamayı dağıtabilir. Bu, yazılımın daha hızlı, daha güvenilir ve daha sık yayınlanmasını sağlar.
Sonuç
Git, modern yazılım geliştirmenin temel bir aracıdır. Dağıtık yapısı, hızı, güvenliği ve esnekliği sayesinde, bireysel geliştiricilerden büyük kurumsal ekiplere kadar herkesin kodlarını verimli bir şekilde yönetmesini ve işbirliği yapmasını sağlar. Versiyon kontrol sistemlerinin evrimindeki en önemli adımlardan biri olan Git, yazılım projelerinin geçmişini korurken, gelecekteki gelişim için sağlam bir temel sunar.
Bu makalede ele alınan temel kavramlar ve komutlar, Git’in sunduğu geniş yetenekler yelpazesinin sadece bir başlangıcıdır. Dallanma stratejileri, cherry-picking, reflog, bisect gibi daha birçok ileri düzey özellik ve komut bulunmaktadır. Ancak, Git’in üç durumu (working directory, staging area, repository) ve temel iş akışı (add, commit, push/pull) anlaşıldığında, bu güçlü aracın potansiyelini tam olarak kullanmak için sağlam bir temel oluşturulmuş olur. Git’i öğrenmek, her yazılım geliştiricisi için vazgeçilmez bir beceridir ve kariyerlerinde önemli bir avantaj sağlar.