Takip et

Git’in Kalbine Yolculuk: Nasıl Çalışır ve .git Klasörünün Rolü

Git’in Kalbine Yolculuk: Nasıl Çalışır ve.

Git’in Kalbine Yolculuk: Nasıl Çalışır ve .git Klasörünün Rolü

Git, modern yazılım geliştirmenin vazgeçilmez bir parçası haline gelmiş, dağıtık bir sürüm kontrol sistemidir. Milyonlarca geliştiricinin projelerini yönetmek, işbirliği yapmak ve değişiklikleri takip etmek için kullandığı bu güçlü aracın sihrini anlamak, çoğu zaman yüzeysel komut bilgisiyle sınırlı kalır. Ancak Git’in gerçek gücü ve esnekliği, perde arkasında, yani her Git deposunun kalbinde yer alan .git klasörünün derinliklerinde yatar. Bu makalede, Git’in iç işleyişine dalacak, .git klasörünün gizemini çözecek ve Git’in verileri nasıl sakladığını, değişiklikleri nasıl takip ettiğini ve dallanma gibi karmaşık operasyonları nasıl gerçekleştirdiğini adım adım inceleyeceğiz.

Git Nedir ve Neden Önemlidir?

Git, Linus Torvalds tarafından 2005 yılında Linux çekirdeği geliştirme sürecini yönetmek için oluşturulmuş, ücretsiz ve açık kaynaklı bir dağıtık sürüm kontrol sistemidir (DVCS). Projelerdeki değişiklikleri izlemek, farklı sürümler arasında geçiş yapmak ve birden fazla kişinin aynı proje üzerinde eş zamanlı çalışmasını sağlamak amacıyla tasarlanmıştır.

Sürüm Kontrol Sistemleri ve Git’in Yeri

Sürüm kontrol sistemleri (VCS), zaman içindeki dosya ve dizin değişikliklerini yönetmek için kullanılan yazılımlardır. Merkezi (SVN, CVS) ve dağıtık (Git, Mercurial) olmak üzere iki ana kategoriye ayrılırlar. Git, dağıtık yapısıyla öne çıkar; her geliştirici, projenin tüm geçmişini içeren tam bir kopyasına (depo) sahiptir. Bu, çevrimdışı çalışmaya olanak tanır ve merkezi bir sunucunun çökmesi durumunda veri kaybı riskini minimize eder.

Dağıtık Yapının Avantajları

Git’in dağıtık mimarisi, birçok avantaj sunar:

  • Çevrimdışı Çalışma: Her geliştirici kendi yerel deposuna sahip olduğu için internet bağlantısı olmadan bile commit yapabilir, branch oluşturabilir ve merge işlemleri gerçekleştirebilir.
  • Yüksek Performans: Çoğu işlem yerel olarak gerçekleştirildiği için çok hızlıdır.
  • Veri Güvenliği: Projenin tam geçmişi birden fazla yerde yedeklendiği için veri kaybı riski düşüktür.
  • Esneklik: Farklı iş akışlarını destekler ve karmaşık dallanma stratejileri için idealdir.

Temel Git Kavramları: Repository, Commit, Branch

Git’i anlamak için bazı temel kavramları bilmek gerekir:

  • Repository (Depo): Projenizin tüm dosyalarını, revizyon geçmişini ve Git’in meta verilerini içeren ana dizindir. Her depo, kök dizininde bir .git klasörü barındırır.
  • Commit: Projenin belirli bir anındaki anlık görüntüsünü (snapshot) temsil eden bir kayıttır. Her commit, bir SHA-1 hash’i ile benzersiz şekilde tanımlanır ve yazar, tarih, mesaj gibi meta veriler içerir.
  • Branch (Dal): Geliştirme akışının birbirinden bağımsız olarak ilerlemesini sağlayan işaretçilerdir. Yeni özellikler geliştirmek veya hataları düzeltmek için ana kod tabanından ayrılmanıza olanak tanır.

.git Klasörü: Git’in Beyni

Bir Git deposunun kalbi ve beyni, projenin kök dizininde yer alan .git klasörüdür. Bu klasör, projenizin tüm sürüm geçmişini, yapılandırma ayarlarını, nesne veritabanını ve Git’in çalışması için gerekli tüm meta verileri barındırır. Çalışma dizininizdeki dosyaların kendisi Git deposunun bir parçası değildir; sadece .git klasöründeki verilerle ilişkilidir.

.git Klasörünün Yapısı ve Ana Bileşenleri

Bir .git klasörünün temel yapısı şöyledir:


.git/
├── HEAD
├── config
├── description
├── hooks/
├── info/
│   └── exclude
├── objects/
│   ├── info/
│   └── pack/
└── refs/
    ├── heads/
    └── tags/


Bu yapının her bir bileşeni, Git'in farklı bir yönünü yönetir.

HEAD Dosyası: Mevcut Konumunuz

HEAD dosyası, o an üzerinde çalıştığınız dalı veya commit'i gösteren bir referanstır. Genellikle bir dalı işaret eder (örneğin, ref: refs/heads/main). Bir dal üzerinde çalışırken, HEAD o dalın en son commit'ini gösterir. Detached HEAD durumunda ise doğrudan bir commit'i işaret eder.

config Dosyası: Proje Ayarları

config dosyası, depoya özel yapılandırma ayarlarını içerir. Bu ayarlar, kullanıcı adınız ve e-posta adresinizden, uzak depoların URL'lerine, merge stratejilerine kadar çeşitli bilgileri barındırabilir. Örneğin:


[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
[remote "origin"]
    url = https://github.com/kullanici/repo.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
    remote = origin
    merge = refs/heads/main

description ve info/exclude Dosyaları

* description: Bu dosya, gitweb gibi araçlar tarafından deponun kısa bir açıklaması olarak kullanılır. Genellikle tek bir satır içerir.
* info/exclude: Bu dosya, .gitignore dosyasına benzer şekilde, Git tarafından takip edilmemesi gereken dosyaları belirtir. Ancak .gitignore'dan farklı olarak, bu dosya deponun bir parçası değildir ve başkalarıyla paylaşılmaz. Yerel olarak göz ardı edilecek dosyalar için kullanılır.

Nesne Veritabanı: Git'in Temeli (objects Klasörü)

.git/objects klasörü, Git'in tüm verilerini depoladığı ana yerdir. Git, projenizin her bir dosyasını, dizin yapısını ve commit geçmişini "nesneler" olarak saklar. Bu nesneler, SHA-1 hash'leri ile adlandırılır ve içeriklerine göre sıkıştırılır. Git'in temelinde yatan içerik adreslenebilirliği prensibi burada devreye girer: bir nesnenin içeriği değişirse, SHA-1 hash'i de değişir ve bu yeni bir nesne olarak kaydedilir.

Git Nesne Tipleri: Blob, Tree, Commit, Tag

Git'in dört ana nesne tipi vardır:

  1. Blob (Binary Large Object): Çalışma dizininizdeki dosyaların içeriğini temsil eder. Her dosya sürümü, bir blob nesnesi olarak saklanır.
  2. Tree (Ağaç): Bir dizin yapısını temsil eder. Dizin içindeki dosyaların (blob'lar) ve alt dizinlerin (diğer tree'ler) SHA-1 hash'lerini ve dosya/dizin adlarını içerir.
  3. Commit (Taahhüt): Projenin belirli bir anındaki anlık görüntüsünü temsil eder. Bir commit nesnesi, yazar, tarih, mesaj, işaret ettiği tree nesnesinin SHA-1'i ve önceki commit'lerin (parent commit'ler) SHA-1'lerini içerir.
  4. Tag (Etiket): Belirli bir commit'i işaretlemek için kullanılır, genellikle önemli sürümleri (v1.0, v2.0 gibi) işaretlemek için kullanılır. İki tür tag vardır: hafif (lightweight) ve açıklamalı (annotated). Açıklamalı tag'ler kendi başlarına bir nesnedir ve yazar, tarih, mesaj gibi meta veriler içerir.

Nesnelerin Saklanma Biçimi: SHA-1 ve Sıkıştırma

Her Git nesnesi, içeriğinin SHA-1 hash'i ile adlandırılır. Bu hash'in ilk iki karakteri, nesnenin içinde bulunduğu alt dizinin adını oluşturur, geri kalan 38 karakter ise dosya adıdır. Örneğin, d670460b4b4aece13fd2022b07e296e492c30765 hash'ine sahip bir nesne, .git/objects/d6/70460b4b4aece13fd2022b07e296e492c30765 yolunda bulunur. Nesneler, disk alanından tasarruf etmek için zlib kullanılarak sıkıştırılır.

git cat-file ile Nesneleri İnceleme

git cat-file komutu, Git nesnelerinin içeriğini ve türünü incelemek için kullanılır.

  • Bir nesnenin türünü görmek için: git cat-file -t
  • Bir nesnenin içeriğini görmek için: git cat-file -p

Örneğin, bir commit'in içeriğini görmek için:


$ git cat-file -p 87e9c...
tree 72a8c...
parent 1b2f0...
author John Doe  1678886400 +0300
committer John Doe  1678886400 +0300

Initial commit

Referanslar ve Dallanma (refs Klasörü)

Git'in dallanma (branching) ve etiketleme (tagging) yetenekleri, .git/refs klasöründe tutulan referanslar sayesinde mümkün olur. Referanslar, belirli commit'lere işaret eden basit dosyalardır.

Branch'ler: refs/heads

refs/heads klasörü, yerel dallarınızın her birini temsil eden dosyaları içerir. Her dosyanın adı bir dalın adıdır (örneğin, main, feature-x), içeriği ise o dalın işaret ettiği en son commit'in SHA-1 hash'idir.


.git/refs/
├── heads/
│   ├── main  (içeriği: 87e9c... - main dalının son commit'i)
│   └── feature-x (içeriği: a1b2c... - feature-x dalının son commit'i)
└── tags/


Bir dalda yeni bir commit yaptığınızda, ilgili dosyadaki SHA-1 hash'i otomatik olarak güncellenir.

Tag'ler: refs/tags

refs/tags klasörü, projenizdeki etiketleri (tag'leri) içerir. Tıpkı dallar gibi, etiket dosyaları da işaret ettikleri commit'in SHA-1 hash'ini barındırır. Açıklamalı tag'ler ise doğrudan bir commit'i değil, kendi tag nesnelerini işaret eder.

Uzak Referanslar: refs/remotes

Uzak depolarla etkileşim kurduğunuzda, Git bu uzak depolardaki dalları izlemek için refs/remotes klasörünü kullanır. Örneğin, origin adlı bir uzak deponuz varsa, refs/remotes/origin/main dosyası, origin deposundaki main dalının en son commit'ini gösterir. Bu, yerel ve uzak dalları birbirinden ayırmanıza ve git fetch gibi komutlarla uzak depodaki değişiklikleri takip etmenize olanak tanır.

Dizin ve Çalışma Alanı Yönetimi (index, logs, hooks Klasörleri)

.git klasörü, sadece geçmişi değil, aynı zamanda mevcut çalışma durumunuzu ve gelecekteki otomasyonları yönetmek için de çeşitli bileşenler barındırır.

index (Staging Area): Değişikliklerin Hazırlanması

.git/index dosyası, "staging area" veya "cache" olarak da bilinen Git dizinini temsil eder. Bu dosya, bir sonraki commit'e dahil edilecek değişikliklerin bir listesini tutar. git add komutu, çalışma dizininizdeki dosyaların anlık görüntülerini alır ve bu bilgiyi index dosyasına yazar. git commit komutu ise bu index dosyasındaki anlık görüntüyü kullanarak yeni bir commit oluşturur. index dosyası, ikili (binary) bir formatta saklanır ve dosya yolları, modları ve blob nesnelerinin SHA-1 hash'lerini içerir.

logs Klasörü: Referans Geçmişi

logs klasörü, Git'in her bir referansın (dallar, HEAD) geçmişini tuttuğu yerdir. Örneğin, logs/HEAD dosyası, HEAD'in hangi commit'leri işaret ettiğini gösteren bir geçmiş kaydıdır. logs/refs/heads/main ise main dalının hangi commit'lere işaret ettiğinin geçmişini tutar. Bu dosyalar, git reflog komutu tarafından kullanılır ve bir dalın veya HEAD'in hareket geçmişini görmenizi sağlar, bu da yanlışlıkla yapılan değişiklikleri geri almak için çok faydalıdır.

hooks Klasörü: Otomasyon ve Özel Komutlar

.git/hooks klasörü, Git olayları (commit öncesi, push sonrası vb.) tetiklendiğinde otomatik olarak çalışan betikleri barındırır. Bu betikler, kod kalitesini kontrol etmek, testleri çalıştırmak veya belirli bir formatı zorlamak gibi görevler için kullanılabilir. Varsayılan olarak, bu klasörde örnek betikler bulunur (örneğin, pre-commit.sample). Kendi betiklerinizi oluşturmak için .sample uzantısını kaldırmanız ve betiği çalıştırılabilir hale getirmeniz yeterlidir.


.git/hooks/
├── applypatch-msg.sample
├── pre-commit.sample
├── post-commit.sample
└── ...

Git İş Akışı ve .git Klasörü İlişkisi

Git komutları, .git klasöründeki çeşitli dosyaları ve dizinleri manipüle ederek çalışır. Bu ilişkiyi anlamak, Git'in nasıl çalıştığına dair daha derin bir kavrayış sağlar.

git init ve .git Klasörünün Oluşumu

Bir dizini Git deposu haline getiren git init komutu, o dizin içinde boş bir .git klasörü oluşturur. Bu klasör, yukarıda bahsedilen temel dizinleri (objects, refs, hooks vb.) ve dosyaları (HEAD, config) varsayılan halleriyle oluşturur. Bu andan itibaren, Git bu klasörü kullanarak projenizin geçmişini yönetmeye başlar.

git add, git commit ve Nesne Veritabanı

* git add : Çalışma dizininizdeki bir dosyanın içeriğini okur, SHA-1 hash'ini hesaplar, bu içeriği bir blob nesnesi olarak .git/objects klasörüne yazar ve bu blob'un SHA-1'ini .git/index dosyasına ekler.
* git commit -m "Mesaj": .git/index dosyasındaki bilgileri kullanarak bir tree nesnesi oluşturur. Bu tree nesnesi, o anki dizin yapınızın anlık görüntüsüdür. Ardından, bu tree nesnesine, önceki commit'lere (HEAD'in işaret ettiği commit), yazar/tarih bilgilerine ve commit mesajına referans veren yeni bir commit nesnesi oluşturur ve bunu da .git/objects klasörüne yazar. Son olarak, HEAD'in işaret ettiği dalın referansını (örneğin, refs/heads/main) bu yeni commit'in SHA-1'i ile günceller.

git branch, git merge ve Referans Yönetimi

* git branch : HEAD'in işaret ettiği commit'i referans alarak, refs/heads/ adında yeni bir dosya oluşturur ve içine HEAD'in işaret ettiği commit'in SHA-1'ini yazar.
* git merge : Bir dalı mevcut dala birleştirdiğinizde, Git her iki dalın geçmişini analiz eder, ortak atayı bulur ve gerekli birleştirme işlemlerini yapar. Sonuç olarak, yeni bir commit (merge commit) oluşturulur. Bu commit, birleştirilen dalların her ikisini de parent olarak işaret eder ve bu yeni commit'in SHA-1'i mevcut dalın referansına yazılır. Bu işlem sırasında yeni blob ve tree nesneleri de .git/objects klasörüne eklenebilir.

Sonuç

Git'in .git klasörünün iç yapısını anlamak, sadece "Git nasıl çalışır?" sorusuna yanıt vermekle kalmaz, aynı zamanda Git ile ilgili sorunları giderme, daha karmaşık iş akışları tasarlama ve hatta kendi Git araçlarınızı geliştirme konusunda size eşsiz bir avantaj sağlar. Git'in her şeyi bir nesne veritabanında saklaması, referanslarla bu nesnelere işaret etmesi ve indeks aracılığıyla değişiklikleri yönetmesi, onun hem performanslı hem de esnek olmasının temel nedenidir. Bu derinlemesine bakış, Git'in sadece bir komut satırı aracı olmadığını, aynı zamanda içerik adreslenebilirliği ve yönlü döngüsel olmayan grafikler (DAG) gibi güçlü bilgisayar bilimleri prensipleri üzerine inşa edilmiş sofistike bir sistem olduğunu göstermektedir.

SSS (Sık Sorulan Sorular)

.git klasörünü silersem ne olur?

.git klasörünü silmek, projenizin tüm Git geçmişini, dallarını, etiketlerini ve yapılandırma ayarlarını kalıcı olarak siler. Projeniz artık bir Git deposu olmaktan çıkar ve sürüm kontrolü altında olmaz. Bu işlem geri alınamaz.

.git klasörü neden bu kadar büyük?

.git klasörünün boyutu, projenizin geçmişindeki dosya sayısı, boyutu ve değişiklik sıklığına bağlıdır. Her commit, yeni blob ve tree nesneleri oluşturabilir. Özellikle büyük ikili dosyalar (resimler, videolar) sık sık değiştirilirse, .git klasörü hızla büyüyebilir. git gc (garbage collect) komutu, kullanılmayan nesneleri temizleyerek ve nesneleri "pack file" adı verilen daha verimli bir formatta birleştirerek klasör boyutunu optimize etmeye yardımcı olabilir.

.git klasörünü başka bir yere taşıyabilir miyim?

Hayır, .git klasörü, projenizin kök dizininde olmak zorundadır. Git, bu klasörün konumuna göre projenizin bir depo olup olmadığını anlar ve işlemlerini gerçekleştirir. Ancak, "bare repository" (çıplak depo) adı verilen bir konsept vardır ki bu, çalışma dizini olmayan, sadece .git klasörünün içeriğini barındıran bir depodur. Bu genellikle merkezi sunucularda kullanılır.

Git'i daha iyi anlamak için nereden başlamalıyım?

Git'i daha iyi anlamak için öncelikle temel komutları (git add, git commit, git push, git pull, git branch, git merge) pratik yaparak öğrenmelisiniz. Ardından, bu makalede bahsedilen .git klasörünün iç yapısını inceleyerek ve git cat-file, git reflog gibi daha ileri komutları kullanarak Git'in perde arkasında neler olduğunu keşfedebilirsiniz. Pro Git kitabı ve resmi Git belgeleri de harika kaynaklardır.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Gönder

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
Mobil sürümden çık