Skip to content

Conversation

@silentip404
Copy link

@silentip404 silentip404 commented Nov 10, 2025

Reasons for making this change

The current Icon\r pattern in macOS.gitignore has a reliability issue: the invisible carriage return (CR) character is silently corrupted by editors' default behavior, causing the rule to fail even when developers believe they haven't modified the file.

Core Problem: Silent Line-Ending Conversion

The literal \r character in the .gitignore file is automatically processed by modern editors during save operations, even when file content is ultimately unchanged.

Actual corruption observed (real git diff output):

diff --git a/Global/macOS.gitignore b/Global/macOS.gitignore
--- a/Global/macOS.gitignore
+++ b/Global/macOS.gitignore
@@ -3,7 +3,8 @@
 __MACOSX/
 .AppleDouble
 .LSOverride
-Icon[^M]
+Icon[
+]

What happened:

  • Original rule: Icon followed by carriage return (displayed as ^M in some environments)
  • After corruption: CR is replaced by LF (\n), splitting the pattern into two lines
  • Result: Pattern becomes Icon[ + new line ], completely broken
  • macOS Icon\r files are no longer matched and start appearing in git status

Precise Reproduction Steps (Verified)

Test Environment:

  • Editor: VS Code (without EditorConfig enabled)
  • File: Global/macOS.gitignore

Reproduction Steps:

  1. Open .gitignore file containing the Icon\r rule
  2. Modify other content in the file (e.g., add a comment line)
  3. Save the file (Ctrl+S / Cmd+S)
  4. Undo the modification (Ctrl+Z / Cmd+Z), reverting to original state
  5. Save the file again
  6. Check changes with git diff

Expected Result:

  • File content has been reverted, there should be no diff

Actual Result:

  • The diff above appears: Icon\r is split into two lines
  • Git shows the file as modified, even though the developer made no intentional changes

Analysis:

  • VS Code silently converted \r\n during the first save
  • Even though the developer undid all content changes, the line-ending conversion persisted
  • This is VS Code's default line-ending normalization behavior
  • Developers cannot perceive this change from the editor interface (requires checking git diff)

Why This Is a Serious Problem

High stealth:

  • Developers believe they "didn't modify the file" (content was indeed reverted)
  • Git shows the file as changed (line endings were converted)
  • Difficult to diagnose that the \r character caused the issue

Wide impact:

  • Once someone opens and edits this file with VS Code
  • The rule becomes permanently broken
  • Other macOS users' Icon files start appearing in version control

No error indication:

  • No warnings that the gitignore rule is corrupted
  • File appears "normal" (no visual anomalies in the editor)

Solution: Use Character Class Pattern

Replace Icon\r with Icon[^!-~] (Icon followed by any non-printable character):

Technical Rationale:

  • [^!-~] matches all characters outside the ASCII printable range (33-126)
  • Includes all control characters: CR(13), LF(10), TAB(9), etc. (ASCII 0-32)
  • Includes DEL character (ASCII 127)

Why This Works:

  • Completely immune to line-ending processing: Character class syntax [^!-~] contains only printable characters and won't be modified by editors' line-ending normalization
  • Won't be split into multiple lines: Entire pattern is single-line printable text
  • Stable and reliable: Pattern remains unchanged regardless of how many times you save/undo
  • Visible: Clear in code reviews and diffs, no invisible characters
  • Functionally equivalent: Covers all real macOS Icon files (Icon\r)

Backward Compatibility:

  • ✅ 100% matches all legitimate macOS Icon\r files
  • ⚠️ Theoretically matches Icon + any control character combinations
    • Practical impact: negligible. macOS Finder only creates Icon\r files
    • If files with other control characters exist, they are abnormally named and should be ignored anyway
  • ✅ Won't false-match normal files:
    • Icon.png, IconSet, Icon!, Icon123 etc. are explicitly excluded
    • ! (ASCII 33) to ~ (ASCII 126) defines the printable character range boundary

Why Character Class Is the Best Solution

Comparison of possible approaches:

Approach Viable Issue
Keep Icon\r Cannot resist editor line-ending normalization, will be silently corrupted
Use Icon[\r] The \r inside brackets is still a literal byte, will be converted the same way
Use Icon? Would false-match Icon1, Icona and other normal files
Use Icon* Would match all Icon-prefixed files
Use Icon[^!-~] Pure printable character syntax, immune to line-ending processing; precise function; stable after undo

Links to documentation supporting these rule changes

N/A - This change fixes an editor compatibility issue discovered through testing. The pattern syntax is standard gitignore format documented in the Git documentation.

If this is a new template

N/A - This PR modifies an existing template (Global/macOS.gitignore), not adding a new one.

Merge and Approval Steps

  • Confirm that you've read the contribution guidelines and ensured your PR aligns
  • Ensure CI is passing
  • Get a review and Approval from one of the maintainers

Replace invisible CR with character class Icon[^!-~]

The literal CR character is frequently corrupted by:
- Text editors auto-trimming invisible chars
- Formatting tools (editorconfig) normalizing line endings
- Copy/paste operations losing special characters
- IDE auto-formatting and linting tools

Character class pattern is collaboration-safe and functionally identical.
@silentip404 silentip404 requested a review from a team as a code owner November 10, 2025 14:45
@silentip404 silentip404 marked this pull request as draft November 10, 2025 14:53
@silentip404 silentip404 marked this pull request as ready for review November 10, 2025 14:59
@silentip404 silentip404 marked this pull request as draft November 10, 2025 18:30
@silentip404
Copy link
Author

======================================  
  Icon[^!-~] Full Validation Test  
======================================  

📝 Creating test files...  

✓ Creating control character files (should be ignored):  
  - Icon\r (CR-13) ← target file  
  - Icon\t (TAB-9)  
  - Icon\n (LF-10)  
  - Icon\f (FF-12)  
  - Icon\x1B (ESC-27)  
  - Icon space (SP-32)  
  - Icon\x7F (DEL-127)  

✓ Creating printable character files (should not be ignored):  
  - Icon! (boundary-33)  
  - Icon" (34)  
  - Icon# (35)  
  - Icon$ (36)  
  - Icon~ (boundary-126)  
  - Icon.png  
  - Icon.svg  
  - Icon.ico  
  - Icon.icns  
  - Icona  
  - Icon1  
  - Icon123  
  - IconSet  
  - Icon_old  
  - Icon-new  
  - Icon.backup  
  - MyIcon  
  - icon.png (lowercase)  

✓ Creating multi-character test files:  
  - Icon\r\r (double carriage return)  
  - Icon\r\n (Windows line ending)  

📋 File list (with byte display):  
Icon\t  
Icon\n  
Icon\f  
Icon\r  
Icon\r\n  
Icon\r\r  
Icon\033  
Icon   
Icon!  
Icon\"  
Icon#  
Icon$  
Icon-new  
Icon.backup  
Icon.icns  
Icon.ico  
Icon.png  
Icon.svg  
Icon1  
Icon123  
IconSet  
Icon_old  
Icona  
Icon~  
Icon\177  
MyIcon  

🔍 Inspecting byte code of Icon\r:  
00000000: 4963 6f6e 0d                             Icon.  

======================================  
  Begin testing gitignore rule  
======================================  

[Test 1] Files that should be ignored (control characters):  
--------------------------------------  
  ✅ Icon\r (CR-13) correctly ignored  
  ✅ Icon\t (TAB-9) correctly ignored  
  ✅ Icon\n (LF-10) correctly ignored  
  ✅ Icon\f (FF-12) correctly ignored  
  ✅ Icon\x1B (ESC-27) correctly ignored  
  ✅ Icon space (SP-32) correctly ignored  
  ✅ Icon\x7F (DEL-127) correctly ignored  

[Test 2] Files that should not be ignored (printable characters):  
--------------------------------------  
  ✅ Icon! (boundary-33) not ignored  
  ✅ Icon" (34) not ignored  
  ✅ Icon# (35) not ignored  
  ✅ Icon~ (boundary-126) not ignored  
  ✅ Icon.png not ignored  
  ✅ Icon.svg not ignored  
  ✅ Icona not ignored  
  ✅ Icon1 not ignored  
  ✅ Icon123 not ignored  
  ✅ IconSet not ignored  
  ✅ Icon_old not ignored  
  ✅ Icon-new not ignored  
  ✅ MyIcon not ignored  
  ✅ icon.png (lowercase) not ignored  

[Test 3] Multi-character boundary cases:  
--------------------------------------  
  ✅ Icon\r\r (should not match) not ignored  
  ✅ Icon\r\n (should not match) not ignored  

[Test 4] git check-ignore -v detailed check:  
--------------------------------------  
.gitignore:1:Icon[^!-~] "Icon\r"  

======================================  
  Test summary  
======================================  
✅ All tests passed! Icon[^!-~] rule works as expected  

Validation summary:  
  ✓ Icon\r (macOS Icon file) correctly ignored  
  ✓ All control character files ignored  
  ✓ All normal files unaffected  
  ✓ Boundary characters (!, ~) handled correctly  

@silentip404 silentip404 marked this pull request as ready for review November 10, 2025 19:27
@doriangurazdowski0-prog
Copy link

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