Git'te Yerel Ignore Kuralları: .git/info/exclude ve core.excludesFile

Giriş

Ekiple birlikte büyük bir proje üzerinde çalışıyorduk. Projede herkes Claude kullanmıyordu. Ben ise pairing yaparken proje root'una sürekli bir şeyler bırakıyordum. Bir konuyu tarayıp docs olarak .md çıktısı alıyordum, geçici json dosyaları atıyordum, görseller koyuyordum. Bunların hiçbiri projeyle doğrudan ilgili değildi.

İki şey istemiyordum. Birincisi bu dosyaları .gitignore'a eklemek, çünkü .gitignore commit'lenir ve ilişkisiz bir değişiklik olarak herkese gider. İkincisi bunların file change'lerde gözükmesi, kendi yerel çalışmam yüzünden diff'i kirletmek istemiyordum.

Yani bana repoya hiç dokunmayan, sadece kendi makinemde geçerli bir ignore çözümü lazımdı. Aradım ve buldum: .git/info/exclude.

Üç yer, üç amaç

Git'te ignore kuralı yazabileceğin üç yer var, ve üçü de farklı bir işe yarıyor:

  • .gitignore: repo ile paylaşılan, commit'lenen, herkesi bağlayan kurallar.
  • .git/info/exclude: sadece senin makinen ve klonun için. Commit, push, clone edilmez, takımdaki kimse görmez.
  • core.excludesFile: git config ile işaret ettiğin bir dosya. Global (tüm repoların için, per-user) ya da tek repo için local olabilir.

Benim ihtiyacım ikincisiydi, ama üçünü de bilmek işine yarıyor.

.git/info/exclude, kişiye özel ve repoya girmez

Bu tam benim aradığım şeydi. Kurallar sadece bende kalıyor, repoya hiç dokunmuyor. Dosya zaten her repoda mevcut, ekstra bir şey yaratman gerekmiyor, sonuna satır eklemen yeterli:

echo "*.local" >> .git/info/exclude
echo "scratch/" >> .git/info/exclude

Bunu yerelde test ettim. *.local kuralını yazınca untracked note.local dosyası yoksayıldı:

git check-ignore -v note.local
# .git/info/exclude:1:*.local	note.local

En güzel tarafı, bu dosya klonlanmıyor ve push edilmiyor. Yani proje root'una attığım docs ve json dosyalarını burada tuttum, kimsenin diff'inde gözükmedi.

Önemli tuzak: zaten tracked olan dosya

Burası çok yanlış biliniyor, o yüzden ayrı yazıyorum. Eğer bir dosya zaten commit edilmişse (tracked), onu exclude'a eklemek hiçbir şey değiştirmiyor. Git tracked dosyalara ignore kurallarını uygulamaz.

Test ettim: tracked bir dosyayı exclude'a ekledim, git check-ignore -v hiçbir şey döndürmedi. Çünkü tracked dosya "ignored" sayılmıyor.

Çözüm, önce dosyayı index'ten düşürmek. Çalışma dizinindeki dosya silinmiyor, sadece git takibi bitiyor:

git rm --cached tracked.txt
# dosya diskte kalır, sadece git artık takip etmez
# bundan sonra .gitignore veya exclude kuralı devreye girer

core.excludesFile, global kişisel ignore

Bir de her repoda tekrar tekrar yazmak istemediğin şeyler var. .DS_Store, .idea/, *.swp gibi. Bunları her projede ayrı ayrı yazmak yerine bir kere merkezi tanımlayabilirsin:

git config --global core.excludesFile ~/.gitignore_global
echo "*.conf" >> ~/.gitignore_global

Yerelde denedim, *.conf kuralı app.conf'u yoksaydı:

git check-ignore -v app.conf
# ~/.gitignore_global:1:*.conf	app.conf

Global şart değil, --global olmadan git config core.excludesFile <yol> diyerek tek repo için de kullanabilirsin.

Öncelik sırası

Şimdi asıl kafa karıştıran yere geldik. Aynı dosya için birden fazla yerde kural varsa kim kazanır? Yerelde test ettim, yüksekten düşüğe sıra şöyle:

  1. Komut satırı pattern'leri (git ls-files gibi)
  2. .gitignore dosyaları (daha derin dizindeki kural üstünü ezer, aynı dosya içinde son eşleşen kural kazanır)
  3. .git/info/exclude
  4. core.excludesFile

Bunu iki negation testiyle doğruladım. .gitignore içine !note.local yazdığımda, exclude'daki *.local kuralını ezdi ve dosya yoksayılmadı. Yani .gitignore, exclude'dan önceliklidir. Sonra exclude'a !build/ yazdığımda, core.excludesFile'daki build/ kuralını ezdi. Yani exclude da core.excludesFile'dan önceliklidir.

Kısacası ortak kural (.gitignore) her zaman kişisel kurallarını ezer. Bunu akılda tutmak lazım.

Hata ayıklama: bir dosya neden yoksayılıyor?

Bir dosyanın neden ignore edildiğini (ya da edilmediğini) merak ettiğinde tek komut yetiyor:

git check-ignore -v <dosya>

-v bayrağı hangi dosyanın, hangi satırın, hangi kuralın eşleştiğini gösteriyor:

git check-ignore -v note.local
# .git/info/exclude:1:*.local	note.local

Çıktı gelmiyorsa iki ihtimal var: ya dosya ignore edilmiyor, ya da zaten tracked (tracked dosyalar bu komutta raporlanmaz).

Takım açısından: exclude mı, ortak kural mı?

Benim durumumda cevap netti. Attığım dosyalar tamamen kişiseldi, takımın umurunda değildi, o yüzden .git/info/exclude doğru seçimdi. Repoya dokunmadan kendi kirimi kendi makinemde tuttum.

Basit bir ayrım var kafamda:

  • Sadece sana özgü şeyler (IDE ayarları, kişisel scratch, pairing artıkları): .git/info/exclude veya global core.excludesFile. Repoyu kirletmez.
  • Takımca ortak muaf tutulması gereken şeyler (node_modules/, build çıktısı): commit'lenen .gitignore. Çünkü exclude paylaşılmıyor, herkesin aynı davranışı görmesi gerekir.

Kapanış

Özetle, .gitignore tek yer değil. Kişisel işler için .git/info/exclude ve core.excludesFile var, ve bunlar repoya hiç dokunmuyor. Bir daha proje root'una geçici bir dosya bırakıp da "bunu nasıl gizlerim" diye düşündüğünde, çözüm bu.

Paylaş

Yorumlar