- Conventional Commits,
<type>[optional scope]: <description> biçimiyle commit mesajına anlam kazandırmaya çalışsa da, değişiklik türünü öne çıkarıp kapsamı isteğe bağlı bırakarak gerçek inceleme için gereken bilgiyi sona iter
- Katkıda bulunanlar, hata ayıklayanlar ve olay müdahale ekipleri commit geçmişinde değişikliğin dokunduğu kod alanını arar; hatalar her tür değişiklikte ortaya çıkabileceği için scope (kapsam), türden daha önemlidir
fix(compiler): prevent namespaced SVG <style> elements from being stripped örneğinde olduğu gibi, yalnızca açıklamadan bunun bir hata düzeltmesi olduğu anlaşılabilir; refactor(core): Update webmcp support to use document.modelContext örneğinde ise tek bir commit düzeltme, refactor ve özellik ekleme arasında kalabilir; bu yüzden type hem tekrarlayıcıdır hem de sınırlayıcıdır
- Otomatik CHANGELOG üretimi ve semantik sürüm artırımı kararı, commit geçmişi ile değişiklik günlüğünün farklı okur kitlelerine hitap etmesi nedeniyle sorunludur; revert işlemleri, kazara geriye dönük uyumluluk kırılması ve bu kırılmanın sonradan giderilmesi yüzünden sonuçlar sapabilir
- Kapsam önekli commit mesajları değişikliğin öznesini önce gösterir; build ve deploy koşullarını da başlıktaki türe göre değil,
git diff ile değişen dosyalara göre belirlemek daha iyidir
Yanlış öncelikler
- Conventional Commits, geliştiricilerin ve son kullanıcıların değişiklikleri anlayabilmesi için commit mesajlarına anlam kazandırmayı amaçlar
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
- Başlık satırı
fix, feat, chore, docs, refactor gibi bir <type>, isteğe bağlı bir scope ve bir description'dan oluşur
- Temel kusur, değişikliğin öznesi olan scope'u değil, değişiklik türü olan type'ı önceleyen yapıdır
- Scope'un isteğe bağlı olması, commit'teki en önemli bilginin eksik kalabilmesine yol açar; type'ın başlığın en başına konması da önceliği tersine çevirir
Scope neden type'dan daha önemlidir
- Katkıda bulunanlar, son katkılarından bu yana nelerin değiştiğini, projenin genel akışını ve pull ya da rebase sırasında devam eden işleriyle çakışabilecek commit'leri bulmak için commit geçmişini okur
- Hata ayıklayanlar, hatanın ortaya çıktığı bileşenle ilgili alanlara dokunan değişiklikleri arar; hatalar her tür değişiklikte çıkabildiği için type bilgisi yardımcı olmaz
- Olay müdahale ekipleri, bir kesinti sırasında commit geçmişini tarayarak soruna yol açan alanı bulmaya çalışır; gelen API hatalarının birden arttığı noktada
auth scope'lu bir commit varsa bu güçlü bir neden adayıdır
- Commit geçmişini okuyanlar için önemli olan, değişikliğin ne tür olduğu değil hangi alana dokunduğudur
Type'ın tekrarlılığı ve sınırlılığı
Otomasyon vaadinin sınırları
- git-cliff veya conventional-changelog gibi araçlarla commit'lerden otomatik CHANGELOG üretme fikrinin temel sorunu, commit geçmişi ile değişiklik günlüğünün farklı okurlara hitap etmesidir
- CHANGELOG son kullanıcıya yöneliktir ve sürümler arasındaki işlevsel ve iş açısından farkları anlamaya odaklanır
- Commit geçmişi geliştiricilere yöneliktir; kod tabanının zaman içinde nasıl değiştiğini ve scope perspektifinden akışı okumaya odaklanır
- Orta ve üzeri karmaşıklıktaki projelerde anlamlı tek bir özellik birden fazla commit ile gelebilir; geliştirici için uygulama süreci faydalıdır ama son kullanıcı için önemli olan yalnızca ortaya çıkan yeni özelliktir
- Revert commit'leri geliştiriciler için commit geçmişinin akışı açısından önemlidir; ama son kullanıcı için geri alınmış bir değişiklik, hiç yapılmamış bir değişiklikle aynıdır
- Commit type'ına dayalı semantik sürüm artırımı; geriye dönük uyumluluğu bozan bir değişiklik geri alınmış olsa bile major sürüm yükseltmek, kırılmanın ancak sonradan fark edilmesi nedeniyle minor/patch yanlış artırımı yapmak ya da sonraki commit'lerle birleşince kırılma ortadan kalksa bile hâlâ kırılma var sanmak gibi sorunlar doğurabilir
- Bu durumlarda rebase ile geçmiş düzeltilebilir; ancak workflow buna izin vermeyebilir veya bunu bozabilir ve commit geçmişinin anlattığı akışa olan güveni azaltır
- Build veya deploy süreçlerini commit başlığındaki type ile tetiklemek,
docs: fix typos başlıklı bir commit'in kimlik doğrulama alt sistemine bir zafiyet sokması gibi yollarla otomatik araçların atlatılmasına neden olabilir
- Build ve deploy koşullarını commit başlığından değil,
git diff ile değişen dosyaları belirleyerek tanımlamak daha iyidir
Uygulama sorunları ve alternatif
- Conventional Commits, proje bazında bir type kümesi tanımlamayı önerir; ancak birçok proje commitlint'in varsayılan type'larını olduğu gibi alır ve bu her projenin özelliklerine iyi uymayabilir
- Conventional Commits spesifikasyonu teknik olarak yalnızca
fix ve feat tanımlar; ek type'ları projeye bırakır
- Kurumsal ortamlarda değişiklik yönetimi ve denetim gereklilikleri nedeniyle her commit mesajına bir bilet numarası eklenmesi gerekebilir;
<scope> alanı bilet numarası için kullanılırsa yararlı metadata kaybolur
- Linux, FreeBSD, Git, Go, NixOS ve Node.js projeye uygun scope önekli commit mesajları kullanır
- Linux çekirdeğinde subsystem, Go projelerinde package path, mikroservis mimarisinde ise mikroservis adı doğal bir scope olur
- scopedcommits.com, commit mesajlarında scope merkezli biçime geri dönmeyi ve CHANGELOG üretimi ile commit geçmişi yönetimini birbirinden ayırmayı savunur
- Conventional Commits'in avantajları pratikte gerçek faydaya dönüşmedi; açık kaynak projelerdeki popülerliği ve yapay zekanın bunu varsayılan tercih olarak seçme eğilimi, anti-pattern içeren commit mesajlarının yayılmasına yol açtı
1 yorum
Lobste.rs görüşleri
conventional commits hakkında içgüdüsel bir iticilikten ziyade mantıklı bir karşı argüman sunan bir yazı görmek güzel
Neden sevmediğimi çok derin düşünmemiştim; belki de bunu LLM’in ürettiği kodla ilişkilendirmeye başlamışımdır. Özellikle
chore:en sevmediğim şey; keşke Macar gösterimini yeniden icat etmeye kalkmasak. Zaten en başta hiç var olmamalıydıchore:, artık Angular commit stil kılavuzunda da yok; sanırım fazla muğlak olduğunu fark edipbuild:içine çektilerAngular stilinde olduğu dönemde bile
chore:açıklaması oldukça belirli kullanım alanları tarif ediyordu, ama bazı açık kaynak projelerde kelimenin tam anlamıyla yapması can sıkıcı işler gibi hissedilen değişikliklere havadan ekleniyor gibi duruyorconventional commits’i sevmiyorum ama önerilen alternatif de scope’un neden isteğe bağlı olduğunu kaçırıyor gibi
Belirgin modülleri çok olmayan küçük projelerde “scope” kavramı pek kullanışlı değil. İkisinin de atladığı faydalı bir pratik olarak, commit başlığına issue ya da bilet numarası koymak değişikliğin ek bağlamını anlamayı kolaylaştırıyor ve özellikle code review sırasında yardımcı oluyor. Ama bilet numarasını zorunlu yapmak da hoşuma gitmiyor; çünkü ufak değişiklikler için işe yaramaz biletler üretiliyor. Yine de belirli bir bug ya da işi ele alan bir değişiklik, ilgili bug’a ya da işe bağlanmalı
Sadece başlık satırına bakınca bile görülebilen, gereksiz yere tekrar eden commit “type”ından yine de daha iyi
Değişiklik bir biletle net biçimde eşleşiyorsa “bilet numaralı” commit kullanılabilir, değilse başka bir yol seçilebilir. Bazı değişiklikler type’a daha iyi uyar ama scope’a daha az uyar, bazılarında da tersi geçerlidir; bu yüzden scoped commits ile conventional commits karıştırılarak da kullanılabilir
“Paragraf metninde sabit genişlikli yazı tipi kullanmayın” demek istiyorum
Yine de yazının temel önermesine büyük ölçüde katılıyorum
Commit mesajları pek iyi olmasa bile değişiklik kapsamını anlamak için sık sık
git log --name-onlyya dagit log --statkullanmayı öneririmDosya adlarına bakmak, her commit’i tek tek açmadan neyin değiştiğini anlamada epey yardımcı oluyor
Gerçekten hoşuma giden yöntem, PR başlıklarında conventional commit stilini zorunlu kılmak
PR başlıkları merge sonrasında da maintainer tarafından düzenlenebilir, commit geçmişini yeniden yazmayı gerektirmez ve release-drafter gibi araçlarla birlikte kullanıldığında GitHub release’lerinde anlamlı değişiklik günlüklerini otomatikleştirebilir. Yazarın sözünü ettiği paydaşlara uygun doğru ayrıntı düzeyini sağlar; yani özellikleri, düzeltmeleri ve breaking change’leri ayırarak gösterir ve bir sonraki GitHub release taslağı için makul bir semver artışını da otomatik işler
Yazıda,
parse-libgibi bir bileşenin isteğe bağlı olmaması gerektiği yönündeki eleştiri doğru; ayrıca conventional commits’i zorunlu kılmanın yeni katkıları caydırabileceğine de katılıyorum. Ama alternatifler de pek daha iyi görünmüyorYine de breaking change belirteci olan
fix!(parse-lib): Don't leave sparse holes when parsing JSON arraysoldukça fazla bilgi veriyor. Belirli bir bileşendeki bir bug düzeltmesi olduğunu, bu düzeltmenin kaçınılmaz olarak bir breaking change getirdiğini ve minor semver artışı gibi bir anlam taşıdığını anlatıyor. Bu tür şeyler PR başlığında kullanılabilirCommit disiplini teşvik etmenin yolu olarak conventional commits’e fazla kapıldığımı ve sonunda bunun alışkanlığa dönüştüğünü kabul ediyorum
Şimdi ise zaman zaman kısıtlayıcı ve keyfi geliyor. Bazı projelerde bunun gerçekten yerleşik pratik olup olmadığını bile bilmiyordum ve daha çok Linux/Go/Node stiline yaklaştım; çeşitli yapılandırmaları olan monorepo’larda da type’ı zorlamaktansa
[service]: [what changed]yazmak daha doğal geliyordu. Bundan sonra katı kurallara uymaya çalışmaktansa neyin faydalı göründüğüne göre kişisel commit stilimde daha fazla deneme yapmayı düşünüyorum; scoped commits de iyi bir başlangıç noktası gibi duruyorchore(lobsters): add my 2 cents on conventionals commits [JIRA-69420]Neredeyse her şeye katılıyorum ama “commit log’un anlattığı hikâyenin güvenilirliğini düşüren revizyonist bir kayıt anlayışını katkıda bulunanlara göstermek” kısmında bir noktada ayrılıyorum. Yazar galiba daha çok public branch’lerden bahsediyor; öyleyse bu makul bir tavsiye. Ama private branch’ler için geçerli olmamalı. Son değişiklikleri inceleyecek kişi, yani maintainer ya da 10 yıl sonraki ben, ne olduğunu rahat anlayabilsin yeter; tutarsız düşünce akışını ya da daha kötüsü
address reviewcommit yığınlarını bırakmaya gerek yok“Neden scope isteğe bağlı?” sorusunun cevabı, küçük projelerde aslında tüm projenin scope olması
Commit’in “type”ının çok faydalı olmadığına katılıyorum ama scoped commits ile conventional commits arasında da büyük bir fark olup olmadığından emin değilim. Scoped, sadece “type” kısmı çıkarılmış bir conventional gibi; yine de fix, feat, refactor, chore ayrımı yapılmasında bir sorun görmüyorum
Herkes commitlint’in varsayılanlarını aynen alıyorsa, belki de mesele insanların onu daha iyi kullanmasını sağlamak değil midir?