- Gradle टीम Git-compatible VCS Jujutsu(jj) को रोज़मर्रा के development में अपनाना चाहती थी, लेकिन Windows के लिए
gradlew.bat में line ending handling की वजह से अपनाने को टाल दिया
- मुख्य समस्या यह है कि
jj .gitattributes के per-file EOL rules नहीं पढ़ पाता, इसलिए *.bat text eol=crlf लागू नहीं कर सकता
- Git
gradlew.bat को repository में LF के रूप में normalize करता है और working directory में CRLF के रूप में checkout करता है, लेकिन jj इसे change मानकर लगातार phantom modification बनाता रहता है
gradlew.bat को CRLF के साथ ही commit करके और *.bat -text में बदलकर workaround किया जा सकता है, लेकिन अगर editor इसे LF में बदल दे तो Git अपने आप recover नहीं करेगा, जिससे Windows execution stability डगमगा सकती है
- Gradle टीम फिलहाल कई working directories चलाने के लिए
git worktree इस्तेमाल करेगी, और jj में eol support implement होने पर फिर से कोशिश करने की योजना है
अपनाने में असली अड़चन: gradlew.bat और .gitattributes
- Jujutsu(
jj) Git backend इस्तेमाल करते समय commits और files को Git में store करता है और मौजूदा Git repositories के साथ काम करने वाला Git-compatible version control system है
jj staging area को हटा देता है और working copy को लगातार update होने वाले वास्तविक commit के रूप में दर्शाता है
- commit edit या reorder करने के बाद यह बाद के commits को अपने आप rebase करता है, conflicts को काम रोकने के बजाय history में रखा जा सकता है, और operation log से वापस भी लौटा जा सकता है
- Gradle engineer की
git को jj से replace करने की कोशिश jj के model की वजह से नहीं, बल्कि Gradle project के disk पर रखे जाने के तरीके की एक छोटी detail पर अटक गई
Windows पर gradlew.bat को CRLF चाहिए
- सामान्य Gradle repository में Gradle Wrapper के साथ
gradlew.bat शामिल होता है
gradlew.bat label और goto का इस्तेमाल करता है, और cmd.exe सिर्फ LF line endings वाली batch file को गलत तरीके से process कर सकता है
- Windows पर भरोसेमंद तरीके से चलाने के लिए
gradlew.bat का CRLF के रूप में checkout होना ज़रूरी है
- Gradle project इस requirement को
.gitattributes से enforce करता है
*.bat text eol=crlf
- Git में यह behavior standard flow है
- file index में normalized form में store होती है
eol=crlf attribute checkout के समय working copy में CRLF materialize करता है
- edits दोबारा save होने पर फिर normalize हो जाते हैं
jj में .gitattributes support न होने से बनने वाला phantom diff
jj .gitattributes नहीं पढ़ता, इसलिए per-file line ending rules apply नहीं कर सकता
- संबंधित feature पुराने issue jj-vcs/jj#53 में track हो रहा है, और कम-से-कम
eol attribute support पर चर्चा चल रही है
- अभी
jj में उपलब्ध साधन केवल global setting working-copy.eol-conversion है
- Git के
core.autocrlf की तरह यह सभी files पर एक साथ apply होता है
- केवल
.bat files को अलग से specify नहीं किया जा सकता
- colocated repo में समस्या तुरंत दिखती है
- Git
gradlew.bat को LF के रूप में store करता है और CRLF के रूप में checkout करता है
jj उस attribute का सम्मान नहीं करता, इसलिए disk पर मौजूद CRLF को Git के LF blob की तुलना में change के रूप में record करता है
- प्रभावित Gradle projects में
gradlew.bat में लगातार fake changes बनते हैं
- यह समस्या सिर्फ Gradle टीम का case नहीं है
- एक user ने छह अंकों की संख्या जितनी files में phantom changes आने के कारण
jj इस्तेमाल करना छोड़ दिया
सुझाए गए workarounds और सीमाएँ
jj के author ने issue में non-colocated workspace को एक रास्ते के रूप में suggest किया
- उदाहरण: Git working copy के बाहर
jj git init --git-repo=<path> इस्तेमाल करना
- Gradle engineer के मुताबिक यह तरीका भी समस्या हल नहीं करता
- जब
jj stored LF blob से gradlew.bat materialize करेगा, तो disk पर LF आएगा
- LF
gradlew.bat Windows पर execute नहीं होता
- global setting
working-copy.eol-conversion = input-output से CRLF force किया जा सकता है
- लेकिन यह checkout के समय सभी text files को CRLF में फिर से लिख देता है, इसलिए अलग समस्या बन जाता है
चलने वाला लेकिन कमजोर समाधान
- वास्तव में काम करने वाला तरीका है
gradlew.bat को repository में CRLF के साथ ही commit करना और normalization बंद करना
- rule इस तरह बदलता है
- मौजूदा:
*.bat text eol=crlf
- बदला हुआ:
*.bat -text
- ऐसा करने पर Git और
jj storage tree और working copy दोनों में CRLF पर सहमत हो जाते हैं
- conversion खत्म हो जाता है
- phantom diff भी गायब हो जाता है
- Windows execution भी बनी रहती है
- इसके बदले
*.bat -text, text eol=crlf से मिलने वाली automatic recovery छोड़ देता है
- पहले गलती से LF आ भी जाए तो commit के समय चुपचाप फिर normalize हो जाता था
- अब LF वैसे ही रह जाएगा और
gradlew.bat Windows पर चुपचाप टूट सकता है
- यह conversion केवल एक बार करना होता है, और गलत edits आम तौर पर review में पकड़े जा सकते हैं
- फिर भी Gradle टीम ने माना कि पूरे ecosystem को इस assumption पर दांव पर लगाना मुश्किल है कि सभी Gradle projects सीधे CRLF commit करेंगे और कोई editor इसे चुपचाप नहीं बदलेगा
फिलहाल जारी रहने वाला विकल्प: git worktree
jj का workspace एक repository share करने वाली कई working directories देता है, ताकि लंबी CI runs या in-progress changes अगला काम न रोकें
- Gradle टीम पहले से ही
git worktree से इसी जरूरत को पर्याप्त रूप से संभाल रही है
git worktree add ../gradle-feature-x feature-x
git worktree add ../gradle-hotfix hotfix-7.6
- यह तरीका दो checkouts और एक object store इस्तेमाल करता है
- stash या दूसरे clone के बिना भी parallel work और लंबे समय तक maintained
main checkout साथ-साथ चलाए जा सकते हैं
- Gradle टीम इस pattern को कई सालों से इस्तेमाल कर रही है
jj पर दोबारा विचार की संभावना
- यह case Gradle project में
jj खुद के बारे में अंतिम फैसला नहीं है
jj का operation log अकेला भी गहराई से review करने लायक है
eol support को हल हो सकने वाली समस्या माना जा रहा है, और issue में gix-filter के जरिए implementation पर चर्चा भी है
- वह support आने पर Gradle टीम फिर से कोशिश करने की योजना रखती है
- तब तक
gradlew.bat की वजह से Git बना रहेगा, और git worktree जरूरी भूमिका निभाएगा
1 टिप्पणियां
Lobste.rs की रायें
मुझे लगता है कि Git की
autocrlfsetting और उसके बाद की.gitattributessetting शुरू से ही गलती थीं और आगे भी रहेंगीversion control system को repository के अंदर मौजूद file को disk पर मौजूद file से अलग तरह से store नहीं करना चाहिए
अगर file format enforce करना है, तो यह linter, commit hook, merge hook का काम है, version control system की भूमिका नहीं
core.{eol, safecrlf, autocrlf}को deprecated कर देना चाहिएline ending conversion सिर्फ Windows की वजह से जोड़ा गया था, ␍-only Git से पहले ही मर चुका था, और Windows को छोड़कर सब ␊-only पर settle हो गए थे
अब असल में ␍␊ की चिंता करने वाली मुख्य चीज शायद batch files ही होंगी
सभी languages ␍␊ support करने की कोशिश करती हैं, लेकिन अब लगभग कोई भी इसे require या generate नहीं करता
अगर Notepad आज भी ␍␊ को default के रूप में इस्तेमाल करता है या सिर्फ वही support करता है, तो Notepad इस्तेमाल करने वाले को उसके नतीजे झेलने चाहिए
Windows compatibility में ज्यादा दिलचस्प क्षेत्र file mode है
Git ने Unix modes अपनाए थे और उनके निशान बचे हुए हैं, इसलिए Windows पर काम करते समय कभी-कभी अनचाहे mode errors पैदा हो जाते हैं
अगर tools इतने अच्छे हो जाएं कि checkout करते समय अपने-आप spaces इस्तेमाल करें, या किसी के जोर देकर चाहने वाले अजीब तरह से specific spaces की संख्या के हिसाब से format कर दें, तो tabs और spaces की बहस बंद हो सकती है
और आगे बढ़कर यह भी कहा जा सकता है कि version control system को raw text के बजाय abstract syntax tree (AST) store करना चाहिए
अभी इसे मनवाना मुश्किल होगा, लेकिन कोई दूसरी timeline या भविष्य imagine किया जा सकता है जहां यह तरीका बहुत natural लगे
समझ नहीं आता कि
.batfile को Windows के अलावा कहां execute किया जाएगायह भी सवाल है कि थोड़ा भी अलग behavior कहां desirable होगा
मैं इस दलील से सहमत नहीं हूं कि file को जरूरी line ending format में ही commit नहीं करना चाहिए
मुख्य बात यह लगती है कि “कोई line endings खराब करके commit कर सकता है, code review पास हो सकता है और टूटी हुई script आ सकती है”
यह सब सही है, लेकिन इसी लिए तो CI lint check होते हैं, है ना?
उस file में non-CRLF line endings scan करें और मिलते ही CI fail कर दें, तो line endings खराब करने वाला change pull request stage पार नहीं कर पाएगा
“बस CI जोड़ दो” वाला जवाब काफी नहीं है
संबंधित project किसी relatively beginner द्वारा बनाया गया Minecraft mod भी हो सकता है, और उनमें से कोई भी
gradle.batको तोड़कर भी notice न करेमेरी भी जिम्मेदारी है क्योंकि मैंने beginners के लिए CLI Git से कहीं बेहतर बताते हुए jj को alternative के तौर पर promote किया है
क्या
gradlew.batसेgradlew.ps1पर जाना, यानीcmd.exe/batch file से PowerShell पर जाना, एक option हो सकता है?अब MAYBE यह मान सकते हैं कि Windows install base के 90% के पास sufficiently recent PowerShell है
लेकिन default execution permission बढ़ानी पड़ने के cases अब भी हैं, और corporate environments में यह locked down भी हो सकता है
पता नहीं आपने PowerShell कितना इस्तेमाल किया है, लेकिन यह “bash है, तो
.shfile चला दो” जैसा feel नहीं थाWindows versions के हिसाब से feature set अलग था, जैसे
kshऔरbash4की तुलना कर रहे हों