- GitHub-शैली की PR review में अक्सर मूल बदलावों के ऊपर लगातार संशोधन commits जोड़े जाते हैं, जिससे review process और अंतिम code history आपस में गड़बड़ा जाती है
- एक अच्छी patch series ऐसी होनी चाहिए जिसे refactoring, नया API जोड़ना, और मौजूदा users का migration जैसे तार्किक रूप से अलग commits के क्रम में पढ़ा जा सके
- जब
"fix review" या "minor" जैसे commits जमा होते जाते हैं, तो बदलाव का इरादा धुंधला हो जाता है, और git blame तथा git bisect से समस्या का कारण ढूँढने की लागत बढ़ जाती है
- interdiff review में patch series का नया version जारी किया जाता है और
git range-diff main..v1 main..v2 से commit-दर-commit बदलावों का अंतर देखा जाता है
- reviewer को पूरे 500 lines फिर से पढ़ने की बजाय सिर्फ 50 lines के incremental बदलाव देखने होते हैं, और लेखक
address review जैसे शोर वाले commits के बिना अंतिम commit structure बनाए रख सकता है
कोड रिव्यू टूल और शुरुआती संदर्भ
- Gerrit Code Review एक open source code review tool है जो Git repository के साथ काम करता है, और patches submit करने, दूसरों द्वारा code review करने, तथा comments छोड़ने का workflow देता है
- code review के तरीके सिर्फ Gerrit, GitHub, Phabricator तक सीमित नहीं हैं; bug tracker में
.patch file अपलोड करना, git send-email, या किसी सहकर्मी के साथ लंबी चर्चा के बाद implementation तैयार करना भी इसमें शामिल है
- Go programming language Gerrit का उपयोग करती है, KDE और LLVM ने Phabricator का उपयोग किया, और Jujutsu ने कभी Gerrit अपनाने पर विचार किया था
- Linux kernel email-आधारित workflow को एक खास तरीके से उपयोग करता है, जबकि कई projects आसान उपयोग और कम शुरुआती लागत के कारण GitHub चुनते हैं
- मूल समस्या यह है कि सभी tools एक जैसा review model नहीं देते, और GitHub का default experience हमेशा पर्याप्त नहीं होता
एक अच्छी patch series की शर्तें
- आदर्श patch series में एक बड़े बदलाव को तार्किक चरणों में बाँटकर submit किया जाता है
- पहले संयोग से मिले code cleanup किए जाते हैं
- फिर नया API जोड़ा जाता है
- अंत में पुराने API users को नए API पर migrate किया जाता है
- हर patch का अपना स्वतंत्र कारण होना चाहिए, और क्रम से apply करने पर code का क्रमिक विकास स्पष्ट दिखना चाहिए
- ऐसी संरचना सिर्फ लेखक और reviewer के लिए ही नहीं, बल्कि बाद में
blame या bisect से बदलाव का कारण ढूँढने वाले maintainers के लिए भी फायदेमंद होती है
- वास्तविक patch size स्थिति के अनुसार बदल सकती है
- हो सकता है refactoring हो ही नहीं
- यह 100 lines का हो सकता है
- या core API change जैसा मामला हो, जहाँ सभी call sites बदलने पड़ें, तो यह 500 lines तक जा सकता है
GitHub-शैली का “diff soup” और मिश्रित history
- GitHub review comments को reflect करने के लिए मूल commits के ऊपर नए commits जोड़ने वाले flow को स्पष्ट और अप्रत्यक्ष दोनों तरह से बढ़ावा देता है
- उदाहरण में मूल 3 commits के बाद Alice और Bob की review feedback, test जोड़ना, और
"minor" implementation change वाले commits क्रम से जमा होते जाते हैं
- commit graph में केवल parent-child संबंध रहते हैं, इसलिए यह साफ नहीं होता कि review fix वाला commit मूल किस commit की किस समस्या को ठीक कर रहा था
- अगर एक
fix review commit कई मूल commits को एक साथ छू ले, तो conceptual model और जटिल हो जाता है
- यह संभव है कि हर fix commit सिर्फ एक ही feedback point को reflect करे, लेकिन तब fixup commits की संख्या बढ़ जाती है
- बड़े बदलावों के समूह और review fixes का एक ही बर्तन में मिल जाना ही “diff soup” है
git blame और git bisect का signal धुंधला होना
git blame line स्तर पर काम करता है, इसलिए यदि review reflect करने वाला commit किसी पुरानी line का छोटा हिस्सा भी बदल दे, तो उस line का स्रोत "fix alice review" जैसे commit के रूप में दिख सकता है
- असली बदलाव का कारण समझने के लिए मूल commit और review fix commits को फिर से trace करने वाली commit archaeology करनी पड़ती है
git bisect में भी यह अस्पष्ट हो सकता है कि "minor" commit ही असली कारण था, या bug नया API जुड़ने के समय से मौजूद था और बाद में सामने आया
- यदि नया API बड़ा performance improvement देता हो, तो उसे revert करना न तो उचित होगा और न ही संभव
- अगर regression कई हफ्तों बाद दिखे, तो P1 meeting जैसी आपात स्थिति में सिर्फ
"minor" commit message देखकर आगे जाँच करनी पड़ सकती है
- सिर्फ दो review rounds वाले उदाहरण में भी history जटिल हो जाती है, और open source projects की तरह कई बार review दोहराया जाए तो समस्या और बढ़ती है
GitHub UX इस flow को कैसे मजबूत करता है
- GitHub में incremental review करने के लिए ऊपर नए commits जोड़ना व्यवहारतः सबसे आसान तरीका है
- reviewer के लिए नए API की 500 lines फिर से पढ़ने से आसान
+/- 10 lines वाला "fix alice review" patch देखना होता है
- PR का diff tab default रूप से सभी commits को एक single diff में जोड़कर दिखाता है
- यह लगभग
git diff master..foo-branch देखने जैसा है
- यह उस तरीके से अच्छी तरह मेल नहीं खाता जिससे लोग बदलाव लिखते और पढ़ते हैं
- GitHub UX named branch model के हिसाब से बहुत मज़बूती से बना है, इसलिए branch के अलावा अन्य इकाइयों के बीच अंतर देखना कठिन हो जाता है
- force push के बाद PR में “Force Push” line पर मौजूद “Compare” button से diff देखा जा सकता है
- लेकिन यह सिर्फ पिछले branch head और वर्तमान branch head के बीच का पूरा diff दिखाता है
- अधिक बारीक तुलना के लिए commit ID खुद ढूँढकर URL में डालनी पड़ती है
interdiff review और git range-diff
- interdiff review में मूल 3 commits के ऊपर fix commits जोड़ने के बजाय, उन्हीं 3 commits से बनी नई version जारी की जाती है
- उदाहरण के लिए यदि
v1 patch series में Bob की टिप्पणी reflect करनी हो, तो पहले और तीसरे commit को बदलकर v2 series बनाई जाती है
- इसके बाद Alice की comments, tests जोड़ना, और
"minor" बदलाव भी उसी तरीके से reflect किए जाएँ, तब भी अंतिम परिणाम 3 commits ही रहता है
- यदि
v1 के commits A, B, C, v2 में X, Y, Z में विकसित हुए हों, तो git range-diff हर संबंधित स्थान के commits के बीच अंतर दिखाता है
git range-diff \
main..v1 \
main..v2
- यह command
v1 branch के 3 commits और v2 branch के 3 commits के बीच pairwise diff दिखाती है
- पहला commit
diff(A, X)
- दूसरा commit
diff(B, Y)
- तीसरा commit
diff(C, Z)
interdiff तरीके का व्यावहारिक असर
- जहाँ GitHub सामान्यतः
diff(main, C) या diff(main, Z) जैसा पूरा branch diff दिखाता है, वहीं interdiff commit versions के बीच का अंतर दिखाता है
- reviewer पहले से देखी हुई 500-line API change को दोबारा पढ़ने की बजाय सिर्फ बदली हुई 50 lines देख सकता है
- लेखक को history में
address review जैसे शोर वाले 30 commits जमा नहीं करने पड़ते
git blame के लिए lines को कम शोर के साथ मूल बदलाव वाले commit से जोड़ने की संभावना बढ़ जाती है
git bisect के regression को नए API commit जैसे अधिक अर्थपूर्ण unit तक सीमित करने की संभावना बढ़ जाती है
- नतीजतन, बुनियादी diagnostic tools का signal-to-noise ratio बेहतर हो जाता है
merge strategy और rebase पर नोट
- patch merge strategy की व्याख्या अभी TODO के रूप में छोड़ी गई है
- दृष्टिकोण यह है कि
git rebase तब तक ठीक है जब तक कोई और व्यक्ति उस पर commits stack करने वाली public branch की अपेक्षा न कर रहा हो
- interdiff review system छोटे और जल्दी merge होने वाले patches को प्रोत्साहित करता है
- सभी 5 commits तैयार होने तक प्रतीक्षा करना ज़रूरी नहीं
- यदि पहले 3 commits ठीक हों और पीछे के 2 को और काम चाहिए, तो सिर्फ 3 को merge किया जा सकता है
- लक्ष्य यह है कि लोग लंबी branch के बजाय main branch के आधार पर काम करें, ताकि कई remote branches के आपस में उलझकर merge होने की स्थिति कम हो
- Linux kernel जैसे projects में public branches को अन्य repositories के साथ merge किया जाता है या किसी दूसरी branch के ऊपर स्पष्ट रूप से publish किया जाता है
- Linux developers patch series बनाते और सँवारते समय
git rebase का उपयोग कर सकते हैं
- लेकिन public branch बन जाने के बाद, क्योंकि वह किसी और के tree में merge हो सकती है, वे force push नहीं करते बल्कि नए commits वाली नई branch बनाते हैं
1 टिप्पणियां
Hacker News की राय
GitHub पर मैं आम तौर पर यही flow इस्तेमाल कर रहा हूँ, लेकिन कमी यह है कि मेरे लिए काम ज़्यादा हो जाता है और सहयोगियों के लिए यह सहज नहीं होता
फिर भी reviewer सिर्फ अपने feedback से आया diff देख सकता है, और
git blameवgit bisectको खराब न करने का फायदा बना रहता हैreview feedback लागू करते समय
git commit --fixupसे commit करता हूँ, push करता हूँ, और review comment के reply में fixup commit hash छोड़ देता हूँजब PR approve होकर merge से ठीक पहले होता है, तो
git rebase --interactive origin/main --autosquashचलाकर fixup commits को मूल commits में मिला देता हूँ, फिर अंत मेंgit push --force-with-leaseकरके merge करता हूँreview खत्म होने से पहले force push करते समय सावधान रहना चाहिए. ऐसा करने पर reviewer पिछली review के बाद जोड़ा गया content नहीं देख पाएगा
मैं terminal autocomplete पर काफी निर्भर हूँ, इसलिए
git reजैसा थोड़ा सा टाइप करने पर भी लंबे command तक पहुँच जाता हूँ, लेकिन यह थोड़ा भद्दा है; अच्छा होगा अगर इस flow को support और encourage करने वाला कोई tool हो. फिर भी अगर आप GitHub से बंधे हैं, तो यह काफी ठीक हैहालांकि असल में यह अक्सर उन्हीं disciplined engineering teams में इस्तेमाल होता है जो जानबूझकर git की advanced features सीखती हैं
~/.gitconfigमें नीचे की setting डाल दें[rebase] autosquash = trueफिर उसके बाद सिर्फ
git rebase -i origin/mainसे भी fixup/squash commits अपने-आप फिर से क्रम में लग जाते हैं. छोटी setting है, लेकिन workflow काफी बेहतर हो गयायह कुछ-कुछ वैसा ही क्षेत्र है जैसे कई branches वाली commit series को rebase करते समय
--update-refsकी जरूरत होती है. इंसान को graph संबंधों को track करके commits खुद डालने और branches move करने की क्या जरूरत है? Computer graphs अच्छे से संभालते हैं, तो उन्हें ही करने देंgit absorbभी है, लेकिन वह Sapling implementation जितना robust नहीं है[1]असली problem interactive rebase है या नहीं, यह नहीं है; आम तौर पर issue खुद review tool का user experience और उससे बनती loop structure है. उदाहरण के लिए, fixup commits GitHub द्वारा base points के बीच diff दिखाने की problem solve नहीं करते, और अगर base point बड़ा हो तो review पूरी तरह बिगड़ सकती है. जैसे, जब 10 नए commits के ऊपर rebase किया गया हो
Git के अपने UX से भी शिकायतें हैं, लेकिन मूल लेख मुख्यतः GitHub के बारे में शिकायत जैसा है
[1] दोनों base algorithms का फर्क दिखाने वाला example इस GitHub issue में है: https://github.com/martinvonz/jj/issues/170
मैं 100% सहमत हूँ कि यह तरीका ideal है. GitHub का तरीका सच में भयानक है, और यह tragedy है कि इतने सारे लोगों ने उसे normal मान लिया है
पहले हम Phabricator में ऐसा करते थे, और सभी reviews को एक साथ update करने वाले command-line macro की वजह से यह कुछ हद तक manual रूप से possible था. फिर भी explicit UI हो तो और अच्छा होगा
सही है. मेरे दिमाग में असली code review style के रूप में जो था, वह यही है, GitHub वाला तरीका नहीं. अच्छा लगा कि इसका कोई नाम है
इसके अलावा, अच्छा होगा अगर review system तैयार patches को review से “बाहर” push कर सके. किसी बड़े feature पर काम करते हुए बनाया गया छोटा bug fix छोटा और independent patch होना चाहिए, और reviewer के साथ जल्दी consensus बनने की संभावना होती है
तब मैं उस patch को पूरी series से निकालकर main में cherry-pick करना, और review को नए HEAD के ऊपर rebase करना चाहूँगा. या latest patch series को main के ऊपर rebase करते हुए agreed patch को सबसे आगे reorder करके, फिर main को उस patch पर fast-forward भी किया जा सकता है
मूल बात यह है कि review का scope “जो हिस्सा अभी discussion में है” तक सीमित किया जाए, लेकिन bug fixes तैयार होते ही merge हो जाएँ
विरोध में कहा जाएगा कि “बस अलग review/PR बना दो”, लेकिन तब patchset A का patchset B पर depend करना और B merge होने के बाद main पर depend करना जैसी complexity पैदा होती है
इसमें Attention Set जैसी smart UX ideas भी भूमिका निभाती हैं. मूल रूप से यह बताता है कि “अगला action किस व्यक्ति को करना है?”, और turn-based game की तरह काम करता है. अगर आपने अभी review किया है, तो उस patch के attention set में अब आप नहीं, author होता है
इसलिए Gerrit UI में वह item मेरी queue में नीचे चला जाता है. queue के top पर वे items होते हैं जिनके attention set में मैं हूँ. स्वाभाविक रूप से काम ऐसे ही grouped हो जाता है
GitHub UX की बाकी परेशान करने वाली छोटी-मोटी problems को मैंने cover नहीं किया, लेकिन pull request list तक alternatives से खराब है. पता नहीं चलता कि कौन item किस state में है, और आखिर में सब पढ़ना पड़ता है
अगर सबसे नीचे x है, तो उसे तुरंत submit करके बाकी पर काम जारी रख सकते हैं
code review के नए approach को देखना हमेशा दिलचस्प होता है। GitHub के भी फायदे हैं, लेकिन वह परफेक्ट से बहुत दूर है
आपके बताए scenario में, तीन patches को एक-दूसरे पर dependent अलग-अलग pull request में बांटने पर विचार किया जा सकता है। GitHub इसे built-in support नहीं करता, लेकिन किसी अच्छे code review tool को pull request छोटे रखते हुए dependencies manage कर पाना चाहिए। उदाहरण के लिए patch 3 को patch 2 पर, और patch 2 को patch 1 पर dependent किया जा सकता है
tool द्वारा दी गई dependency tracking की वजह से, जरूरत पड़ने पर यह ensure किया जा सकता है कि वे सभी साथ में deploy हों
हर patch को अलग-अलग review करने से feedback ज्यादा स्पष्ट होता है और उस पर action लेना भी आसान होता है। pull request के अंदर commits को squash करके individual changes को ठीक-ठीक reflect करने वाली साफ commit history भी बनाई जा सकती है। इससे भी आगे, सही tool हो तो AI से pull request और reviews का summary बनवाकर, बिना manual effort के accurate commit message लिखना भी आसान किया जा सकता है
अच्छा code review tool rebase, merge, force push जैसे git operations से प्रभावित नहीं होना चाहिए। पीछे चाहे जितने भी complex git operations हो रहे हों, reviewer को last review के बाद के changes ही दिखने चाहिए। तब वे बड़े diff को फिर से review किए बिना नए content पर focus कर सकते हैं, और review history commit history से अलग साफ-सुथरी बनी रहती है
मुझे जिज्ञासा है कि इस तरह pull request को बांटकर और उनकी mutual dependencies track करके जरूरत पूरी होगी या नहीं
सचमुच यह वही workflow है जिसे support करने के लिए git design किया गया था, और GitHub में pull request आने के बाद से लगातार उठती रही पुरानी आलोचना का core point भी यही है
मुझे हैरानी है कि यह idea, calendar देखकर कहूं तो, 15 साल से ज्यादा समय तक “mailing list के पुराने लोगों” का तरीका कहकर कमतर आंका जाता रहा, और अब जाकर trendy development culture में ऊपर क्यों आया है
मुझे लगता था कि कई software developers ने अपने सबसे ज्यादा इस्तेमाल होने वाले tools में से एक को ठीक से सीखने से लंबे समय तक इनकार किया, इसलिए वे जानबूझकर खराब workflow चुन रहे हैं। इसलिए जब company को git पर ले जाया, तो ऐसे tools और flows चुने और बनाए। खैर, IBM खरीदने पर किसी को निकाला तो नहीं जाता
अगर external contributor repository fork इस्तेमाल करता है, तो तीनों PR क्रमशः A, A+B, A+B+C को progressively include करेंगे। तब आखिरी दो PRs में वह code भी diff में फिर से देखना पड़ेगा जिसे दूसरे PR में पहले ही review किया जा चुका है, जिससे review मुश्किल हो जाता है
हर commit independently review किया जा सकता है। commits के बीच dependency tracking भी संभव है। AI built-in न होना भी अच्छी बात है। PR के उलट commits के बीच interdiff भी देखा जा सकता है
commits Git की basic building blocks हैं। बस commits का इस्तेमाल करें
मुझे जिज्ञासा है कि GitContext fixup, rebase, reordering जैसी operations से गुजर चुके commits को कैसे track करता है
इस article का लेखक मैं हूं। कुछ भी पूछिए
साथ ही, पता नहीं यह rules के खिलाफ है या नहीं, लेकिन हाल ही में मुझे नई job की जरूरत पड़ गई है। मुझे developer tools और मुश्किल problems पर काम करना पसंद है। अगर आपको यह article पसंद आया हो, या आप अपनी dev team की productivity बढ़ाना चाहते हों, या मेरे शानदार और कभी-कभी eclectic taste को experience और enjoy करना चाहते हों, तो मेरे profile में email है
गंभीरता से कहूं तो resume impressive है। उम्मीद है आपको अच्छी और जल्दी जगह मिल जाए। मेरे बहुत हालिया job-search experience के हिसाब से current hiring market बुरी तरह बीमार है। आप जितने ज्यादा senior और experienced होते हैं, पागलपन भरी interview/HR practices और बिना explanation वाले rejections आत्मा को उतना ही ज्यादा चोट पहुंचाते हैं
एक दोस्त ने नीचे के links भेजे थे
https://danluu.com/hiring-lemons/
https://danluu.com/programmer-moneyball/
https://danluu.com/algorithms-interviews/
शुभकामनाएं
एक बात जिसे अभी cover नहीं किया गया है, वह यह है कि diff soup की वजह से लोग fixup commits का “noise” हटाने के लिए squash merge strategy को prefer कर सकते हैं। इससे शुरुआत के अच्छे atomic 3 commits भी साथ में फेंक दिए जाते हैं
interdiff review style में शुरुआती 3 commits बचे रहते हैं, और उन्हें individual रूप से शामिल करना है या squash करना है, यह पूरी तरह उसी commit और उसकी असली atomicity पर तय किया जा सकता है
GitHub के pain को कम करने के लिए external services भी हैं, और वे stacked diff support देती हैं, लेकिन काफी महंगी लगती हैं। खासकर self-hosted Gerrit से compare करें तो और भी। जिज्ञासा है कि आपने ऐसे tools भी देखे हैं या नहीं
मुझे याद है कि पहले MR series pattern काफी आसानी से set up कर लिया था। 3 MRs को merge करने पर हर MR के लिए single squash commit वाले 3 merge commits बने थे। यह MR की commit history से independent था
trade-off यह है कि review के दौरान अगर आगे वाली series branch बदलती है, तो पीछे वाली series branch में फिर से merge करना पड़ता है
फिर भी review के दौरान लोग commit history को अपनी इच्छा से manage कर सकते हैं। आखिरकार squash होना है, इसलिए फर्क नहीं पड़ता
हालांकि यह किए हुए काफी समय हो गया है, और आजकल GitHub में बंधा हुआ हूं, इसलिए शायद मैं इसे गुलाबी यादों से देख रहा हूं
Review Board [https://www.reviewboard.org] ने 2006 में ही interdiff बना दिया था। सच कहूं तो हो सकता है वह शब्द मैंने ही गढ़ा हो, या स्वतंत्र रूप से उसी तक पहुंचा होऊं
यह आज भी product और code review प्रक्रिया का मेरा सबसे पसंदीदा हिस्सा है, और यह उन features में से एक है जिसकी कमी लोगों को GitHub जैसी चीजों पर जाते समय सबसे ज्यादा महसूस होती है
fix-it commits कभी भी मुझे सही विकल्प नहीं लगे
पहला, वे यह नहीं बताते कि upstream बदलाव commit series में कैसे reflected हुए
दूसरा, वे अस्थायी रूप से ही सही, commit graph को बिगाड़ देते हैं और review को मुश्किल बनाते हैं। जो व्यक्ति review को लगातार follow कर रहा था, उसने fix-it commit जिस code को ठीक कर रहा है उसे पहले ही पढ़ा हो सकता है, लेकिन कोई नया व्यक्ति उस code की मंशा या structure के बारे में खराब पहली छाप लेकर शुरू कर सकता है
तीसरा, हर कोई Git या कई commits संभाल सकने वाला version control system इस्तेमाल नहीं करता। game development में Perforce, और chip manufacturers में Keysight SOS जैसे specialized version control systems अक्सर इस्तेमाल होते हैं। ऐसी जगहों पर fix-it commit खुद कोई विकल्प नहीं होता
सही interdiff support वाला code review system हो तो एक reviewer शुरुआत में publish की गई review request से लेकर सभी updates को follow करते हुए सिर्फ बदली हुई चीजें देख सकता है, और दूसरा reviewer सीधे latest पूरे बदलाव में जा सकता है, fix-it series की चिंता किए बिना। और यह version control system से स्वतंत्र रूप से संभव है
ठीक से बनाया जाए तो यह कई commits वाले बदलावों के साथ भी coexist कर सकता है
उदाहरण के लिए, review में मदद के लिए किसी छोटे project को API handler, frontend UI, और documentation के कई commits में बांटा गया हो, और commits इतने closely related हों कि उन्हें एक ही review request के रूप में डालना उचित लगे। अगर वे आपस में कम related हों, तो dependency chain के रूप में कई review requests बनाना ideal होगा
review feedback के आधार पर उन commits में से किसी एक या सभी में बदलावों की एक series बनाई जा सकती है। जब लोग updates review करें, तो अच्छा होगा कि वे fix-it commit और उस बदलाव को संबंधित original change से दिमाग में map करने के बजाय देख सकें कि हर हिस्सा कैसे evolve हुआ
इसलिए interdiff सचमुच शानदार है। चाहे बहुत सारे छोटे commits हों या बड़ा commit, single-commit review request हो या multi-commit—इसे और ज्यादा लोगों को इस्तेमाल करना चाहिए
2013 के आसपास Glasgow Haskell Compiler, मजाक में कहे जाने वाले “bug reporter में .patch file पढ़ना” तरीके से Phabricator इस्तेमाल करने पर shift हुआ। इसकी कुछ वजहें थीं, लेकिन उस समय वजह stacked diff नहीं था। वजह यह थी कि GitHub review के लिए इतना खराब था कि उसमें side-by-side diff तक नहीं था। सिर्फ इसी वजह से वह पूरी तरह विकल्प से बाहर था, और दूसरी वजहें भी थीं
लेकिन code review tool पर team को shift कराना मेरे लिए पहली बार नहीं था। 2009 में मेरी पहली job Houston के एक कमरे में बैठी बहुत छोटी और करीबी engineers की team में थी, और मुझे लगा कि अगर कोई मेरा code review करे और मैं उनका लिखा पढ़ूं, तो codebase को बेहतर समझ सकूंगा
इसलिए join करने के पहले कुछ महीनों में मैंने manager को काफी मनाकर ReviewBoard install करवाया, और सबको वह सचमुच पसंद आया
यानी RB को धन्यवाद। आज भी कभी-कभी उसे अच्छी याद के रूप में याद करता हूं। उसी की वजह से code review मेरे career का लगभग पहले दिन से ही बहुत बड़ा हिस्सा रहा, और आज भी मुझे लगता है कि मैं इसे और ज्यादा कर सकता हूं
कुल मिलाकर, code review-first और rebase-focused Gerrit जैसे systems में code review करना कहीं ज्यादा आसान लगा
सबसे अच्छी बातों में से एक यह है कि कई patches stack करने की capability default रूप से support होती है, जिससे लोग छोटे और review करने में आसान patches बनाते हैं
GitHub का code review किसी खराब बाद में जोड़े गए feature जैसा लगता है। forum thread जैसा दिखने वाला space-wasting UI, rebase के आगे tracking न कर पाना, वगैरह
ऐसी “big picture” लेकिन technical discussions बहुत बार issue tracker में हो जाती हैं। लेकिन इन्हें कहां रखना चाहिए, यह भी समझ नहीं आता। यह stack बहुत temporary है और अगले push में पूरी तरह बदल सकता है
ऐसी रणनीति की वकालत करते हुए मैंने कई बार सुना है, लेकिन मैं आश्वस्त नहीं हुआ। जिन ज्यादातर प्रोजेक्ट्स पर मैं काम करता हूँ, उनमें feature branch को एक ही commit में squash करके merge किया जाता है, और branch history हटा दी जाती है
लेखक ने जो मामला बताया है, अगर वैसा हो तो मैं refactoring, नया API, और update को बस 3 commits बना दूँगा
मेरे लिए जो चीज़ पक्के तौर पर अच्छी practice रही है, वह है लंबे समय तक रहने वाली branches से बचना। ऐसे multi-step commit scenarios आम तौर पर वहीं से पैदा होते हैं। यानी कोई कई दिनों, कभी-कभी कई हफ्तों तक किसी feature पर काम करता है और फिर उसे एक साथ फेंक देना चाहता है
मैं रोज़, या दिन में कई बार भी, main में लाना कहीं ज़्यादा पसंद करता हूँ। इसका एक तरीका feature flags इस्तेमाल करना है, ताकि progress में चल रहे commits भी बिना समस्या के शामिल हो सकें। अगर system ठीक से configure हो, तो फायदा यह भी है कि development और staging environments में इसे चालू करके test किया जा सकता है। यह blue/green deployment से भी बस एक कदम दूर है
मैं बड़े commits को आसानी से review करने का तरीका नहीं चाहता। मैं चाहता हूँ कि team छोटी changes जल्दी और बार-बार commit करने के लिए मजबूर हो। मैं समझता हूँ कि हर कोई इससे सहमत नहीं होगा
इसकी एक वजह यह है कि GitHub के PR के उलट, stack के सिर्फ कुछ हिस्से apply किए जा सकते हैं। लेख के उदाहरण में, अगर “छोटी refactoring” diff तैयार है, तो “नया API” और “API users migration” diffs को साथ में apply किए बिना उसे पहले डाला जा सकता है
अगर branch की बजाय commit-centric रखा जाए, तो लंबे समय तक रहने वाली branch की तुलना में कुल commits छोटे हो जाते हैं
इससे
git blameऔरgit bisectव्यवहार में बेकार हो जाते हैंअगर regression हो, तो
git bisectउसे एक single patch तक narrow down कर सकता है। इसलिए किसी feature के लिए git history में 8000 lines का एक patch होने से बेहतर है कि 160 lines के 50 patches होंअगर code की कोई एक line संदिग्ध लगे, तो मैं चाहता हूँ कि
git blameया लगातार चलाए गएgit blamecommands मुझे 8000-line commit की बजाय detailed commit message वाले 160-line commit तक ले जाएँमूल commits का order भी preserve होना चाहिए। कुछ साल बाद सिर्फ individual commit messages को क्रम में पढ़ना भी original design समझने में बहुत मददगार हो सकता है। बेशक, original patchset dependency order में arranged होना चाहिए, हर stage पर compile होना चाहिए, वगैरह—यानी feature implementation के ऊपर एक अलग development stage चाहिए। code को logical stages में present किया जाना चाहिए
दिलचस्प। workplace में हम PRs का इस्तेमाल वैसे करते हैं जैसे लेखक commits का इस्तेमाल करते हैं, और अंत में सच में squash-and-merge करते हैं
लेकिन इस तरीके में जब भी आगे वाले PR को बदला जाता है, तो पीछे वाले PRs को rebase करना पड़ता है। यह काफी झंझट भरा है, “force-push मना है” rule से भी टकराता है, engineers को सीखने में समय लगता है, और GitHub UI में मौजूदा code review comments को तोड़ने की tendency रखता है। फिर भी दो-तीन PR तक तो यह किसी तरह काम कर जाता है
हमारे flow में commits काम की इकाई से ज़्यादा save points जैसे हैं
हम stash भी काफी इस्तेमाल करते हैं और Emacs का undo-tree-mode भी काफी इस्तेमाल करते हैं। तब source code history track करने के चार तरीके हो जाते हैं, जो सुनने में duplicate लगते हैं, लेकिन असल में ठीक-ठाक चल जाते हैं
Git में इसे handle करने की usability काफी खराब है। Phabricator बेहतर था, लेकिन फिर भी अनावश्यक रूप से कठिन था। शायद कोई नया version control tool commits और branches से higher-level concepts को first-class support दे सके, और शायद उससे इस्तेमाल करना और भी खराब हो जाए
क्या Git से बेहतर tool हो तो अच्छा होगा? बिल्कुल, मैं भी कम खामियों वाला और अधिक user-friendly tool चाहता हूँ। लेकिन workaround के तौर पर commits को commits की तरह treat करके देखें? खुद ही अपने लिए मुश्किल क्यों बनानी
मुझे आश्चर्य है कि लोगों को PR वाले चश्मे से देखने की आदत डालने में GitHub की कितनी जिम्मेदारी है
jj,sapling,mercurialको देखना अच्छा होगाblog post अच्छी थी, और यह देखकर अच्छा लगा कि कुछ लोग सचमुच सोच रहे हैं कि code review कैसे काम करना चाहिए
मैंने अलग-अलग trade-offs वाले चार code review systems काफी इस्तेमाल किए हैं: Critique(Google internal), Gerrit(Google में इस्तेमाल किया, लेकिन बाहरी जैसा ही), GitHub, और मेरा बनाया CodeApprove
Critique बहुत आगे था, लेकिन यह इसलिए संभव था क्योंकि वह Google के monorepo, अपने version control system, और custom lint/test tools के साथ पूरी तरह tuned था। CodeApprove को उसके फायदे अधिकतम रूप से GitHub में लाने के लिए design किया गया था, लेकिन व्यवहार में उसके करीब पहुँचना मुश्किल है
reviewer experience के लिहाज से Gerrit दूसरा सबसे अच्छा था, लेकिन author के रूप में मुझे वह हमेशा नापसंद रहा। सही तरीके से करने की तुलना में गलत करने के तरीके ज़्यादा लगते थे, और UI भी खास सुंदर नहीं है
GitHub authors के लिए बहुत friendly है और हमारे सोचने के तरीके के हिसाब से काम करता है। code लिखो, feedback लो, फिर और code लिखो। PR के अंत में squash and merge करने पर लेखक ने जो history problem कही, वह नहीं रहती
लेकिन reviewers या team के लिए यह उतना friendly नहीं है। incremental diff highlight नहीं होता, diff और conversation अलग tabs में होते हैं, और force push व rebase history को नष्ट कर देते हैं। comments “outdated” होकर गायब हो जाते हैं, diff window के बाहर files पर comments नहीं कर सकते, बड़ी files default से छिप जाती हैं—ऐसी कई समस्याएँ हैं। साफ है कि GitHub को इसकी खास परवाह नहीं है, और शायद उन्हें कुछ ऐसा पता हो जो मुझे नहीं पता
आखिरकार सबसे निराशाजनक बात यह है कि बहुत-सी teams version control platform में built-in code review tool को बस स्वीकार कर लेती हैं। यह laptop में default आया IDE ज्यों का त्यों इस्तेमाल करने जैसा है। आज बहुत बेहतर options मौजूद हैं। CodeApprove के अलावा मुझे GitContext, Reviewable, Graphite पसंद हैं, और इनके अलावा भी मैं कम से कम छह शानदार options बता सकता हूँ। defaults को यूँ ही accept नहीं करना चाहिए
reviewers और maintainers contributors की तुलना में कहीं अधिक दुर्लभ होते हैं। मेरे हिसाब से workflow और UI को review throughput के लिए optimize करना चाहिए
बताए गए बाकी तीन tools मैंने इस्तेमाल नहीं किए हैं, इसलिए मेरा दावा general observation है