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:
- Komut satırı pattern'leri (git ls-files gibi)
.gitignoredosyaları (daha derin dizindeki kural üstünü ezer, aynı dosya içinde son eşleşen kural kazanır).git/info/excludecore.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/excludeveya globalcore.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.