- Conventional Commits
<type>[optional scope]: <description> फ़ॉर्मैट से commit message को अर्थ देने की कोशिश करता है, लेकिन change type को आगे रखकर और scope को optional बनाकर वह वास्तविक खोजबीन के लिए ज़रूरी जानकारी को पीछे धकेल देता है
- contributor, debugger और incident responder commit log में उस code area को खोजते हैं जिसे बदलाव ने छुआ है; bug किसी भी तरह के change में आ सकता है, इसलिए scope type से ज़्यादा महत्वपूर्ण है
fix(compiler): prevent namespaced SVG <style> elements from being stripped जैसे उदाहरण में description से ही bug fix होना स्पष्ट है, और refactor(core): Update webmcp support to use document.modelContext जैसे commit fix, refactor और feature addition—तीनों पर फैल सकते हैं; इसलिए type दोहरावपूर्ण और सीमित है
- automatic CHANGELOG generation और semantic version bump का निर्णय इस वजह से भटक सकता है कि commit log और changelog के पाठक अलग होते हैं, और revert, accidental breaking changes, या बाद में breakage के समाधान के कारण नतीजे बदल सकते हैं
- scope prefix commit message बदलाव के विषय को पहले दिखाते हैं, और build/deploy conditions को title type के बजाय
git diff में बदली गई files के आधार पर तय करना बेहतर है
गलत प्राथमिकता
- Conventional Commits का लक्ष्य commit message को अर्थपूर्ण बनाना है ताकि developer और end user बदलावों को समझ सकें
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
- title line
fix, feat, chore, docs, refactor जैसे <type>, optional scope, और description से बनती है
- इसकी मूल खामी यह है कि यह change के subject यानी scope की तुलना में change category यानी type को प्राथमिकता देता है
- scope को optional रखने से commit की सबसे महत्वपूर्ण जानकारी छूट सकती है, और type को title की शुरुआत में रखकर प्राथमिकता उलट दी जाती है
scope, type से ज़्यादा महत्वपूर्ण क्यों है
- contributor commit log इसलिए पढ़ते हैं कि वे अपनी पिछली contribution के बाद हुए बदलाव, project के overall flow, और pull या rebase के दौरान ongoing work से टकरा सकने वाले commits को ढूंढ सकें
- debugger उस बदलाव को खोजते हैं जिसने उस area को छुआ हो जो सामने आए bug वाले component से जुड़ा है; bug किसी भी type के change से आ सकता है, इसलिए type की जानकारी मददगार नहीं होती
- incident responder outage के आसपास के commit log को स्कैन करके समस्या पैदा करने वाले area को ढूंढते हैं; inbound API errors में अचानक उछाल के समय
auth scope वाला commit एक मजबूत कारण-उम्मीदवार बन जाता है
- commit log पढ़ने वाले व्यक्ति के लिए अहम बात यह नहीं है कि बदलाव किस प्रकार का था, बल्कि यह है कि उसने किस area को प्रभावित किया
type की दोहरावपूर्ण और सीमित प्रकृति
automation के वादे की सीमाएँ
- git-cliff या conventional-changelog जैसे tools से commits से automatic CHANGELOG बनाना इस समस्या से जूझता है कि commit log और changelog के पाठक अलग होते हैं
- CHANGELOG user के लिए होता है और versions के बीच functional तथा business-level अंतर समझाने पर केंद्रित रहता है
- commit log developer के लिए होता है और यह समझने पर केंद्रित रहता है कि codebase समय के साथ कैसे बदला और scope के नज़रिए से उसका flow क्या रहा
- मध्यम या उससे अधिक जटिलता वाले project में एक meaningful feature अक्सर कई commits में आती है; developer के लिए implementation process उपयोगी होता है, लेकिन end user के लिए नई feature ही महत्वपूर्ण होती है
- revert commit developer के लिए commit log के flow में महत्वपूर्ण होते हैं, लेकिन end user के लिए revert किया गया change ऐसा है मानो वह बना ही नहीं
- commit type पर आधारित semantic version bump ऐसी समस्याएँ पैदा कर सकता है जहाँ breaking change revert हो जाने के बाद भी major version बढ़ जाए, या breakage बाद में पता चले तो version minor/patch के रूप में गलत बढ़े, या बाद के commits के साथ मिलकर breakage खत्म हो जाए लेकिन फिर भी उसे breaking माना जाए
- ऐसी स्थिति में rebase से history सुधारी जा सकती है, लेकिन workflow इसे रोक सकता है या तोड़ सकता है, और commit log द्वारा बताए गए flow की विश्वसनीयता घट जाती है
- अगर build/deploy process commit title type से trigger किया जाए, तो
docs: fix typos शीर्षक वाला commit authentication subsystem में vulnerability डालकर automated tools को bypass कर सकता है
- build/deploy conditions को commit title की बजाय
git diff से बदली गई files पहचानकर तय करना बेहतर है
अपनाने की समस्या और विकल्प
- Conventional Commits projects को अपना type set define करने देता है, लेकिन कई projects commitlint के default types सीधे उठा लेते हैं, जो project-विशेष की जरूरतों से मेल नहीं भी खा सकते
- Conventional Commits specification तकनीकी रूप से सिर्फ
fix और feat को define करती है और बाकी types project पर छोड़ती है
- enterprise environment में change management और audit requirements के कारण हर commit message में ticket number डालना पड़ सकता है; अगर
<scope> उसी ticket number के लिए इस्तेमाल हो जाए तो उपयोगी metadata गायब हो जाता है
- Linux, FreeBSD, Git, Go, NixOS, Node.js जैसे projects अपने project के अनुसार scope-prefix commit messages इस्तेमाल करते हैं
- Linux kernel में subsystem, Go project में package path, और microservice architecture में microservice का नाम स्वाभाविक scope बन जाता है
- scopedcommits.com commit message में scope-केंद्रित फ़ॉर्मैट की ओर लौटने और CHANGELOG generation को commit log management से अलग करने की दिशा सुझाता है
- Conventional Commits के कथित फायदे वास्तविक लाभ में नहीं बदले, और open source projects में इसकी लोकप्रियता तथा AI की default पसंद ने anti-pattern मिले-जुले commit messages के प्रसार को बढ़ाया है
1 टिप्पणियां
Lobste.rs की राय
conventional commits के खिलाफ सिर्फ सहज नापसंदगी नहीं बल्कि तर्क के साथ बात रखने वाला लेख देखकर अच्छा लगा
मुझे क्यों नापसंद है, इस पर मैंने गहराई से नहीं सोचा था, और शायद इसे LLM द्वारा जनरेट किए गए code से जोड़कर देखने लगा था। खासकर
chore:सबसे बुरा लगता है; काश Hungarian notation को फिर से ईजाद न किया जाता। इसे शुरुआत में बनना ही नहीं चाहिए थाchore:अब Angular commit style guide में भी नहीं है, और शायद उन्हें समझ आ गया कि यह बहुत अस्पष्ट है, इसलिए इसेbuild:में समाहित कर दिया गयाAngular style में रहने के दौर में भी
chore:का विवरण काफी विशिष्ट उपयोग बताता था, लेकिन कुछ open source projects में इसे सचमुच ऐसे कामों पर माहौल के हिसाब से चिपका दिया जाता है जो बस करने में उबाऊ लगते हैंमुझे conventional commits पसंद नहीं हैं, लेकिन प्रस्तावित विकल्प scope के वैकल्पिक होने की वजह को छोड़ देता है
जिन छोटे projects में स्पष्ट modules ज़्यादा नहीं होते, वहाँ “scope” की अवधारणा बहुत उपयोगी नहीं होती। एक उपयोगी प्रथा जो दोनों से छूट गई है, वह यह है कि commit title में issue या ticket number डालने से बदलाव का अतिरिक्त संदर्भ समझना आसान हो जाता है, और code review के समय यह खास तौर पर मददगार होता है। लेकिन ticket number को अनिवार्य बनाना मुझे पसंद नहीं, क्योंकि तब मामूली बदलावों के लिए भी बेकार tickets की बाढ़ आ जाती है; हाँ, अगर बदलाव किसी खास bug या task को संभाल रहा है, तो उसका उस bug या task से जुड़ना चाहिए
title line देखकर ही साफ दिखने वाले दोहराव वाले commit “type” से यह अब भी बेहतर है
अगर बदलाव किसी ticket से साफ़-साफ़ मेल खाता है, तो “ticket number” commit इस्तेमाल करें, नहीं तो कोई और तरीका। कुछ बदलाव type में अच्छे से फिट बैठते हैं लेकिन scope में कम, और कुछ इसके उलट, इसलिए scoped commits और conventional commits को मिलाकर भी इस्तेमाल किया जा सकता है
मैं कहना चाहूँगा, “अनुच्छेद के टेक्स्ट में monospace font मत इस्तेमाल करो”
फिर भी, लेख की मूल धारणा से मैं अधिकतर सहमत हूँ
commit message अच्छे न भी हों, तब भी बदलाव का दायरा समझने के लिए
git log --name-onlyयाgit log --statको अक्सर इस्तेमाल करने की सलाह दूँगाfilenames देखकर, हर commit को खोलकर देखे बिना भी क्या बदला है इसका अच्छा अंदाज़ा लग जाता है
जो तरीका मुझे सच में पसंद है, वह है PR title पर conventional commit style लागू करना
PR title को merge के बाद भी maintainer बदल सकता है, commit history को दोबारा लिखने की ज़रूरत नहीं पड़ती, और release-drafter जैसे tools के साथ इस्तेमाल करने पर GitHub releases में अर्थपूर्ण changelog को automate किया जा सकता है। यह लेखक द्वारा बताए गए stakeholders के हिसाब से सही granularity देता है, यानी feature·fix·breaking change को अलग-अलग दिखाता है, और अगली GitHub release draft के लिए उचित semver भी अपने-आप संभाल लेता है
लेख में यह बात सही कही गई है कि
parse-libजैसे component को वैकल्पिक नहीं होना चाहिए, और मैं इस बात से भी सहमत हूँ कि conventional commits को लागू करने से नए contributors हतोत्साहित हो सकते हैं। लेकिन विकल्प भी कोई खास बेहतर नहीं लगतेफिर भी, breaking change identifier
fix!(parse-lib): Don't leave sparse holes when parsing JSON arraysकाफी जानकारी देता है। यह किसी खास component की bug fix है, उस fix के साथ अपरिहार्य रूप से आया breaking change है, और minor semver bump जैसी बात भी संकेत करता है। ऐसी चीज़ PR title में इस्तेमाल की जा सकती हैमैं मानता हूँ कि commit discipline को बढ़ावा देने के तरीके के रूप में मैं conventional commits में कुछ ज़्यादा ही उलझ गया था, और अंततः यह आदत बन गई
अब यह मुझे अक्सर सीमित और मनमाना लगता है। कुछ projects में मुझे यह भी नहीं पता कि यह सच में प्रचलित तरीका है या नहीं, और मैं Linux/Go/Node style के ज्यादा करीब आ गया, जबकि अलग-अलग configuration वाले monorepo में type को जबरन गढ़ने से बेहतर
[service]: [what changed]लिखना ज़्यादा स्वाभाविक लगा। आगे मैं सख्त परंपरा में फिट होने की जगह इस आधार पर अपने निजी commit style के साथ ज़्यादा प्रयोग करना चाहता हूँ कि क्या उपयोगी लगता है, और scoped commits एक अच्छी शुरुआत जैसे लगते हैंchore(lobsters): add my 2 cents on conventionals commits [JIRA-69420]लगभग सब बातों से सहमत हूँ, लेकिन “contributors को ऐसा revisionist history दिखाना जो commit log की बताई कहानी की विश्वसनीयता घटा देता है” वाले हिस्से पर मेरी एक अलग राय है। लेखक शायद मुख्य रूप से public branches की बात कर रहा है, और public branch के लिए यह वाजिब सलाह है। लेकिन private branches पर यह लागू नहीं होना चाहिए। अंतिम बदलाव की समीक्षा करने वाले, यानी maintainer या 10 साल बाद वाला मैं, उनके लिए चीज़ें समझना आसान बनाना काफी है; उलझी हुई सोच की पूरी धारा या उससे भी बुरा
address reviewcommits का ढेर छोड़ने की ज़रूरत नहीं है“scope वैकल्पिक क्यों है?” इसका जवाब छोटे projects में बस यह है कि पूरा project ही scope होता है
मैं इस बात से सहमत हूँ कि commit का “type” इतना उपयोगी नहीं है, लेकिन scoped commits और conventional commits के बीच बहुत बड़ा अंतर भी मुझे नहीं दिखता। scoped, बस “type” हटाया हुआ conventional ही है, और fix·feat·refactor·chore जैसी श्रेणियाँ होना कोई बुरी बात नहीं है
अगर सब लोग commitlint के default values ज्यों-का-त्यों उठा रहे हैं, तो क्या बस लोगों को उसे बेहतर तरीके से संभालना नहीं सिखाया जाना चाहिए?