Skip to content

fix(eol): make *.ps1 canonical LF + no BOM for shebang compat#347

Merged
Chris-Wolfgang merged 1 commit into
mainfrom
fix/ps1-canonical-eol-lf
May 10, 2026
Merged

fix(eol): make *.ps1 canonical LF + no BOM for shebang compat#347
Chris-Wolfgang merged 1 commit into
mainfrom
fix/ps1-canonical-eol-lf

Conversation

@Chris-Wolfgang

Copy link
Copy Markdown
Owner

Summary

Drop the *.ps1 CRLF + UTF-8-BOM overrides in .gitattributes and .editorconfig. Required for the #!/usr/bin/env pwsh shebang at the top of every script in scripts/ to actually work as an executable on Linux/macOS.

The shebang problem

Two ways the current overrides break shebang invocation:

  1. CRLF line endings: kernel reads #!/usr/bin/env pwsh\r and tries to find an interpreter literally named pwsh\r — fails. (\r is part of the parsed interpreter path.)
  2. UTF-8 BOM: the bytes EF BB BF appear before #!, so the kernel doesn't recognize the file as a shebang script at all.

Either alone breaks ./script.ps1. Together, they make it doubly broken on non-Windows.

Why "PowerShell uses CRLF" was outdated rationale

That convention came from the Windows-PowerShell-5.1-and-earlier era when PS only ran on Windows. The current canonical sources have all standardized on LF:

  • PowerShell team's own PowerShell/PowerShell repo: LF, no BOM
  • PSScriptAnalyzer: LF, no BOM
  • Microsoft's cross-platform PS samples: LF, no BOM

Modern PowerShell 7+ (PS Core) is cross-platform and handles LF on Windows transparently.

What changes

File Before After
.gitattributes *.ps1 text eol=crlf *.ps1 text (defaults to eol=lf via the global rule)
.editorconfig [*.ps1] end_of_line = crlf, charset = utf-8-bom (both removed; defaults to LF + utf-8 no BOM)

Comments rewritten to explain the shebang rationale.

What does NOT change

  • Files in the index: already LF. The CRLF rule was aspirational policy that never matched reality (the rule was added later without renormalizing existing LF-stored files). No file content rewrites in this PR.
  • Windows users: core.autocrlf=true (Git for Windows default) still gives CRLF in working tree on checkout. Only the index/wire format is LF — which is what it's always been.
  • Indent: still 4 spaces for *.ps1.

Why this PR is so small

Today's state: index is i/lf, attr says eol=crlf, working tree on Windows is w/crlf (autocrlf). After this PR: index i/lf, attr says eol=lf, working tree w/crlf on Windows / w/lf on Linux/macOS. The only difference is the attr declaration aligning with what's already in the index.

Note about the protected-files guard

This PR touches .editorconfig (protected) — the Detect .NET Projects guard will fail it. Maintainer override required.

Follow-up

After merge, sync to the 24 affected active repos (each has the same [*.ps1] overrides). Per-repo PRs, each ~12 lines. Each will need maintainer override too — same pattern as previous fleet-wide config-touching syncs.

Test plan

  • Maintainer override + merge canonical
  • Per-repo sync PRs (24 active repos)
  • After all land: git ls-files --eol scripts/*.ps1 shows i/lf w/* attr/text eol=lf everywhere
  • Manual smoke test: chmod +x scripts/setup.ps1 && ./scripts/setup.ps1 --help works on Linux/macOS via shebang

Removes the *.ps1 CRLF + UTF-8-BOM overrides from .gitattributes and
.editorconfig. Required for the '#!/usr/bin/env pwsh' shebang line at
the top of every script under scripts/ to work as an executable on
Linux/macOS:

  - CRLF: kernel parses '#!/usr/bin/env pwsh\r' and looks for an
    interpreter literally named 'pwsh\r' — exec fails.
  - UTF-8 BOM: bytes EF BB BF appear before '#!', so the kernel
    doesn't recognize the file as a shebang script at all.

The original 'PowerShell uses CRLF for Windows compatibility'
rationale predates PowerShell 7+ (cross-platform). Modern PS Core
handles LF on Windows transparently. The PowerShell team's own
canonical repos (PowerShell/PowerShell, PSScriptAnalyzer) all use
LF + no BOM.

What changes
- .gitattributes: '*.ps1 text eol=crlf' -> '*.ps1 text' (defaults to
  eol=lf via the global '* text=auto eol=lf' rule)
- .editorconfig [*.ps1]: drop 'end_of_line = crlf' and
  'charset = utf-8-bom'; default LF + utf-8 (no BOM) applies

What does NOT change
- Files in the index: already LF (have been since day one — the
  CRLF rule was aspirational policy that never matched reality).
  No file content rewrites in this PR.
- Windows users with core.autocrlf=true: still get CRLF in their
  working tree on checkout; only the index/wire format is LF.
- Indent: still 4 spaces for *.ps1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 10, 2026 00:07
@Chris-Wolfgang Chris-Wolfgang merged commit de6e4ce into main May 10, 2026
11 checks passed
@Chris-Wolfgang Chris-Wolfgang deleted the fix/ps1-canonical-eol-lf branch May 10, 2026 00:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Aligns PowerShell script encoding/line-ending policies with cross-platform shebang execution requirements by removing CRLF and UTF-8 BOM overrides for *.ps1, so #!/usr/bin/env pwsh scripts can be executed directly on Linux/macOS.

Changes:

  • Updates .gitattributes to stop forcing *.ps1 to eol=crlf, relying on the repo’s LF normalization.
  • Updates .editorconfig to remove end_of_line = crlf and charset = utf-8-bom overrides for *.ps1.
  • Rewrites comments in both files to document the shebang rationale and cross-platform behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
.gitattributes Removes the *.ps1 CRLF override and updates documentation around PowerShell script portability.
.editorconfig Removes *.ps1 CRLF/BOM overrides so PS scripts follow the global LF + UTF-8 (no BOM) defaults.

Comment thread .gitattributes
Comment on lines +12 to +19
# PowerShell scripts: LF line endings, no BOM. Required for the
# `#!/usr/bin/env pwsh` shebang to work on Linux/macOS — the kernel
# parses CR as part of the interpreter name (looking for `pwsh\r`),
# and a UTF-8 BOM before `#!` prevents shebang recognition entirely.
# Modern PowerShell 7+ handles LF on Windows transparently; Git's
# autocrlf still gives Windows users CRLF in their working tree if
# desired without forcing CRLF into the index.
*.ps1 text

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 55fb82a — changed *.ps1 text to *.ps1 text eol=lf to match the explicit-eol convention every other entry in this file uses. Both files are now self-consistent with their own surrounding conventions.

Comment thread .editorconfig
# (CR breaks kernel exec lookup; BOM before `#!` prevents shebang recognition.)
# Modern PowerShell 7+ handles LF on Windows transparently; users with
# autocrlf=true still get CRLF in their working tree on checkout.
[*.ps1]

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 55fb82a — went with the "fix the comment" path rather than adding explicit end_of_line / charset, because every other [*.xxx] section in this file only overrides what differs from the [*] defaults. Adding explicit settings here would be inconsistent with the rest of the file's pattern. Updated the comment to accurately describe that LF + no-BOM come from the global section above (and why it matters — the shebang).

Chris-Wolfgang added a commit that referenced this pull request May 10, 2026
…comment

fix: address Copilot review on #347 (explicit eol=lf + comment honesty)
This was referenced May 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants