How to Fix Git Showing 500+ Changed Files (CRLF vs LF)

Why Git Shows 500+ Modified Files When You Changed Nothing

Why Git Shows 500+ Modified Files When You Changed Nothing

You just created a new Git branch. You haven't written a single line of code yet. But Git is screaming at you โ€” 574 modified files. What. Just. Happened. ๐Ÿ˜ญ

This happened to me recently on a Frappe project, and I almost panicked. After some digging, it turned out to be two invisible but very fixable problems: line ending differences and file ownership. Neither had anything to do with my actual code.

Let me break it all down โ€” what it is, why it happens, how to detect it, and how to fix it. No PhD required. ๐ŸŽ“

โณ Time to Complete: ~5 minutes

๐ŸŽฏ What youโ€™ll achieve / learn:

  • Understand the tricky differences between CRLF and LF line endings.
  • Discover why GitHub Desktop triggers massive false file changes in WSL.
  • Learn the quick commands to fix the 500+ changed files issue using Git configuration and .gitattributes.
  • Resolve frustrating "Permission Denied" errors when running git reset on files owned by root.

๐Ÿง  First, What Are LF and CRLF?

Every time you press Enter in a text file, your computer inserts a special invisible character to mark the end of that line. The problem is โ€” different operating systems use different characters for this. ๐Ÿ‘‡

๐Ÿ’ป OSLine EndingWhat it means
Linux / macOSLFLine Feed (\n)
WindowsCRLFCarriage Return + Line Feed (\r\n)

This goes back to the early days of computing ๐Ÿ•ฐ๏ธ, when CR (Carriage Return) literally moved the print head back to the start of a line on a typewriter, and LF (Line Feed) moved the paper up one row. Windows kept both. Linux kept only LF.

For humans reading the file, they look completely identical. But for Git โ€” which compares files character by character โ€” a file with LF endings and the exact same file with CRLF endings look completely different, even if the actual code is the same. ๐Ÿคฏ


๐Ÿ–ฅ๏ธ The Hidden Trigger: GitHub Desktop on Windows

Here's something a lot of developers don't realize โ€” the tool you use to create a branch matters.

If you're like many developers, you use GitHub Desktop on Windows for convenience (creating branches, committing, pushing) and then drop into a WSL terminal when you need more control. This is a totally reasonable workflow โ€” but it hides a nasty trap. ๐Ÿชค

When GitHub Desktop creates or checks out a branch, it uses Windows Git under the hood. And Windows Git almost always has core.autocrlf = true by default. This means the moment GitHub Desktop checks out your new branch, it silently converts every LF โ†’ CRLF across all your project files โ€” without telling you, without asking, without any warning at all.

Then you open your WSL terminal, run git status, and Linux Git looks at those same files and goes: "Excuse me, these are all different from what I expected." ๐Ÿคจ

The exact chain of events looks like this:

GitHub Desktop (Windows Git, autocrlf=true)
        โ†“ creates branch + checks out files
        โ†“ silently converts LF โ†’ CRLF on every single file
WSL Terminal (Linux Git)
        โ†“ reads same files
        โ†“ sees CRLF where it expects LF
        โ†“ reports 574 "modified" files ๐Ÿ˜ฑ

You didn't touch anything. But Git thinks you rewrote half the codebase.


๐Ÿค” So Why Does This Cause 500+ "Changed" Files?

Let's put the full picture together:

  1. ๐Ÿ“ Your project lives on a Windows drive โ€” something like /mnt/f/apps/projnewoffice in WSL.
  2. ๐ŸชŸ You use GitHub Desktop to create a new branch. It checks out all files using Windows Git, which converts LF โ†’ CRLF silently.
  3. ๐Ÿง You open WSL terminal. Linux Git reads those same files and sees CRLF endings everywhere โ€” but the Git index still expects LF.
  4. ๐Ÿ’ฅ Git compares them line by line: every single line of every file looks "changed" โ€” even though the code logic is 100% identical.

Result: 574 modified files, +53538 -53538 changes โ€” same number added and removed. That perfectly mirrored +N -N number is the dead giveaway that it's a line ending issue. No real code change ever produces that pattern. ๐Ÿ•ต๏ธ


๐Ÿ” How to Confirm It's Really CRLF (and Not Real Changes)

Before doing anything, verify the diagnosis. Run this: ๐Ÿ‘‡

git diff --ignore-space-at-eol HEAD | head -50
  • โœ… Outputs nothing โ†’ it's 100% line ending differences. Your code hasn't changed at all. Breathe. ๐Ÿ˜ฎโ€๐Ÿ’จ
  • โš ๏ธ Outputs something โ†’ there might be real changes mixed in. Look for ^M characters at the end of lines โ€” those are the visible form of \r (the CRLF culprit).

You can also run:

git diff -w HEAD | head -50

The -w flag tells Git to ignore all whitespace differences. If this also shows nothing, your working tree is perfectly clean โ€” Git is just confused about line endings. Not your fault at all. ๐Ÿ™Œ


๐Ÿ› ๏ธ Fix 1: CRLF / LF Mismatch

Step 1: Tell Git to stop converting line endings

git config core.autocrlf false
git config core.eol lf

Step 2: Re-normalize the index

git rm --cached -r .
git reset --hard HEAD

This clears Git's cached file state and re-reads everything fresh with the corrected config. Don't panic โ€” your actual files are not deleted ๐Ÿ›ก๏ธ โ€” only Git's internal index is refreshed.

Step 3: Verify โœ…

git status

You should now see either a clean working tree or only files you actually changed. Those 574 phantom changes should be gone. ๐ŸŽ‰

Step 4: Lock it permanently with .gitattributes ๐Ÿ”’

Add a .gitattributes file at the root of your repo so this never happens again โ€” for you, or anyone else on the team, on any OS:

* text=auto eol=lf
*.py text eol=lf
*.js text eol=lf
*.json text eol=lf
*.html text eol=lf
*.md text eol=lf

Then commit it:

git add .gitattributes
git commit -m "fix: enforce LF line endings via .gitattributes"

Now every developer who clones this repo gets consistent LF line endings โ€” regardless of their OS or Git client. ๐Ÿ’ช


๐Ÿ˜ค But What If git reset --hard HEAD Fails With "Permission Denied"?

This is the second trap โ€” and it caught me too. Right after the CRLF fix, I ran into this wall of errors:

error: unable to unlink old 'projnewoffice/employee_clearance/__init__.py': Permission denied
error: unable to unlink old 'projnewoffice/print_format/custom/employee_posting_clearance_report.json': Permission denied
fatal: Could not reset index file to revision 'HEAD'.

Git was trying to delete and re-write files, but it didn't have permission to touch them.

๐Ÿคท Why did this happen?

In Frappe projects (and many backend frameworks), running bench commands โ€” like scaffolding new doctypes or running migrations โ€” often requires sudo or runs as root. When bench creates new files (like __init__.py or doctype JSON files), those files end up owned by root, not by your regular user.

You can verify this with: ๐Ÿ‘‡

ls -la projnewoffice/employee_clearance/__init__.py

If you see something like:

-rw-r--r-- 1 root root 0 Apr 4 20:20 projnewoffice/employee_clearance/__init__.py

That root root is the problem. ๐Ÿšจ Your user can read the file just fine, but cannot delete or modify it โ€” and Git needs to rewrite it during reset --hard.

๐Ÿ”ง The Fix: Take ownership back

sudo chown -R $USER:$USER .

This recursively changes ownership of everything in the current directory back to your user. Then retry:

git reset --hard HEAD
git status

๐Ÿ’ก Pro tip: Stop bench before doing this

If bench is currently running, it might be holding file locks. Stop it first:

bench stop
# or if using supervisor (see: http://supervisord.org/)
sudo supervisorctl stop all

Then do the chown and reset. Much smoother. โœจ


๐Ÿ—บ๏ธ The Full Picture: Why This Perfect Storm Happens

So let's connect all the dots. You're using:

  • ๐ŸชŸ GitHub Desktop on Windows โ†’ uses Windows Git โ†’ autocrlf=true โ†’ converts LF to CRLF on branch checkout
  • ๐Ÿง WSL terminal for actual Git commands โ†’ Linux Git โ†’ expects LF โ†’ sees CRLF โ†’ reports everything as changed
  • ๐Ÿ“ Project files on a Windows drive (/mnt/f/...) โ†’ Windows and Linux filesystems handle permissions differently
  • โš™๏ธ bench commands run as root โ†’ creates files owned by root โ†’ Git can't rewrite them

Any one of these alone might be manageable. All four together? That's the perfect storm. ๐ŸŒช๏ธ

Recommendation for the long run: If you're doing serious Linux-based development in WSL, consider moving your project files to the WSL filesystem (~/projects/ or similar) instead of keeping them on /mnt/c/ or /mnt/f/. You'll dodge most of these cross-OS headaches entirely. ๐Ÿƒ


๐ŸชŸ Fixing GitHub Desktop So It Stops Causing This

Since GitHub Desktop is often the trigger, here are two ways to address it directly:

Option A: Fix the global Git config on Windows ๐Ÿ”ง

Open Git Bash or Command Prompt on Windows (not WSL) and run:

git config --global core.autocrlf false
git config --global core.eol lf

This updates the global Git config that GitHub Desktop uses. From now on, branch checkouts via GitHub Desktop won't trigger CRLF conversion. ๐ŸŽฏ

Option B: Use .gitattributes as a safety net ๐Ÿ›ก๏ธ

If you already committed .gitattributes with * text=auto eol=lf, Git will normalize line endings regardless of what tool or OS is used โ€” GitHub Desktop, WSL terminal, VS Code, anything. This is the team-safe solution because it works for every collaborator who clones the repo, not just you.

Best practice: do both. Fix your global config and commit .gitattributes. Belt and suspenders. ๐Ÿ‘–


โœ… Quick Reference: Full Fix Checklist

Copy-paste this when you're in the panic zone: ๐Ÿ˜…

# 1. Confirm it's CRLF โ€” output should be empty
git diff --ignore-space-at-eol HEAD | head -50

# 2. Fix Git config
git config core.autocrlf false
git config core.eol lf

# 3. Stop bench if running
bench stop

# 4. Fix file ownership if you get Permission Denied
sudo chown -R $USER:$USER .

# 5. Re-normalize Git index
git rm --cached -r .
git reset --hard HEAD

# 6. Verify โ€” phantom changes should be gone
git status

# 7. Lock it permanently for everyone
echo '* text=auto eol=lf' > .gitattributes
git add .gitattributes
git commit -m "fix: enforce LF line endings"

# 8. Fix GitHub Desktop's Git config (run in Git Bash / CMD on Windows, not WSL)
git config --global core.autocrlf false
git config --global core.eol lf

๐ŸŸก Bonus: Why Are My VS Code Folders Yellow Even After the Fix?

You ran git status and it says "nothing to commit, working tree clean" โœ… โ€” but VS Code's file explorer still shows some folders in that annoying dark yellow/orange color. What's going on? ๐Ÿ˜•

VS Code colorizes files and folders based on Git status:

ColorMeaning
๐ŸŸก Yellow/OrangeModified โ€” Git sees changes
๐ŸŸข GreenNew untracked file
No colorClean โ€” nothing changed

So VS Code is just visually reflecting git status. If Git was reporting phantom changes, VS Code was dutifully painting everything yellow. Now that Git is clean, VS Code just hasn't refreshed yet โ€” or it's still reading Git status through the wrong user context.

๐Ÿ”„ Quick Fix: Reload VS Code's Git view

Try any of these:

Option 1: Press Ctrl+Shift+P โ†’ type Reload Window โ†’ Enter

Option 2: Click the ๐Ÿ”„ refresh icon in the Source Control panel (the Git tab on the left sidebar)

Option 3: Close and reopen VS Code entirely

That's it โ€” the yellow folders will disappear and match what your terminal already shows. ๐ŸŽ‰

๐Ÿ”‘ The root cause of the yellow folders (pun intended)

If VS Code was opened from a root terminal session (you can tell by root@DESKTOP showing in the VS Code terminal), its Git integration runs as root too. Even if you switch users inside the terminal with su youruser, VS Code's background Git watcher is still reading status as root โ€” which can show stale or incorrect colors.

The clean long-term fix is to always open VS Code from your regular user session. In your WSL terminal as your normal user:

cd ~/f16/apps/projnewoffice
code .

This ensures VS Code, Git, and your terminal all run under the same user โ€” no more ownership mismatches, no more mystery yellow folders. ๐Ÿ™Œ


๐Ÿ’ก Key Takeaways

  • ๐Ÿ‘ป LF vs CRLF is an invisible difference that Git treats as real code changes. It's not a bug โ€” Git is doing its job correctly.
  • ๐Ÿ”ข The +N -N symmetry in your diff stats (same number added and removed) is the clearest sign it's a line ending issue.
  • ๐Ÿ•ต๏ธ git diff -w or --ignore-space-at-eol are your diagnostic tools โ€” if they show nothing, your code is fine.
  • ๐Ÿ–ฅ๏ธ GitHub Desktop uses Windows Git with autocrlf=true by default โ€” it silently converts line endings when you create or switch branches.
  • ๐Ÿ”‘ bench and similar tools often run as root, leaving files your user can't modify. sudo chown -R $USER:$USER . takes ownership back.
  • ๐Ÿ”’ .gitattributes is the permanent solution โ€” it enforces consistent line endings for the whole team, no matter the OS or Git client.
  • ๐Ÿ“ Working on a Windows-mounted drive in WSL amplifies all of these issues. Consider the native WSL filesystem for serious development.
  • ๐ŸŸก VS Code's yellow folders are just a visual reflection of git status โ€” once Git is clean, reload the window and they disappear. Always open VS Code from your regular user session, not root.

Related posts