Windows vs macOS dev environment
Windows vs macOS dev environment
Even with the same language and the same code, the basics like paths, line endings, shells, and permissions shift once the operating system changes. Linux falls on the macOS side of this split (both are Unix-flavored).
1. About the two operating systems
Windows is a GUI operating system Microsoft released in 1985. It carved out its own path with NTFS, cmd.exe, PowerShell, and WSL2. macOS started as Mac OS X in 2001 — a custom GUI on top of Unix-flavored BSD. The differences between them surface whenever the same code has to run in both places.
2. Path separators
- Windows — traditionally backslash (
\).C:\Users\name\project. - macOS · Linux — slash (
/)./Users/name/project.
Even so, the Windows API itself accepts slashes. C:/Users/name works in most Win32 calls. cmd.exe sometimes treats slashes as option introducers (dir /w), so be careful. PowerShell accepts both broadly.
Language standard libraries usually abstract the OS-specific separator. Python's pathlib, Node's path.join, Java's Paths.get. Using these is more portable than hard-coding \\.
3. Line endings
- Windows — CRLF (
\r\n, 0x0D 0x0A). A relic of DOS-era teletype convention. - macOS (modern) · Linux — LF (
\n, 0x0A). - macOS Classic (OS 9 and earlier) — CR (
\r). Rarely seen today.
Git handles this difference through core.autocrlf and .gitattributes.
| Setting | Behavior |
|---|---|
true (recommended Windows default) |
LF→CRLF on checkout, CRLF→LF on commit. |
input (recommended on macOS · Linux) |
CRLF→LF on commit, checkout untouched. |
false |
No conversion. |
Declaring * text=auto or per-file eol=lf in .gitattributes is the safer SSOT.
4. File permission models
Unix (macOS · Linux) — mode bits express r/w/x for user/group/other. chmod 755 · chmod +x. Executable is its own bit.
Windows (NTFS) — ACL (Access Control List). Permissions are granted per ACE at finer granularity for users and groups. Whether a file is executable comes from the extension (.exe · .bat · .ps1) and the execution policy — there is no separate executable bit.
Git tracks the Unix executable bit (100755 vs 100644). On Windows chmod +x carries little meaning, so use git update-index --chmod=+x to set the bit directly.
5. Package managers
| OS | Main manager | Traits |
|---|---|---|
| macOS | Homebrew | The de facto standard. brew install. |
| macOS | MacPorts | An older alternative. Builds dependencies in its own isolated tree. |
| Windows | winget | Microsoft's official one. Bundled by default since Windows 10 1809+. |
| Windows | Chocolatey | The oldest and largest catalog. |
| Windows | Scoop | Installs into the user directory, no admin rights needed. |
Linux varies by distro: apt (Debian/Ubuntu), dnf (Fedora/RHEL), pacman (Arch).
6. Default shells
- macOS — zsh by default since 10.15 Catalina (2019). Before that, bash (Apple switched to zsh to avoid GPLv3).
- Windows — PowerShell (modern), cmd.exe (legacy). Windows Terminal is the default host.
- Linux — varies by distro, but bash is common, with dash sometimes wired into
/bin/sh.
7. Case-sensitive file systems
- macOS APFS — case-insensitive, case-preserving by default.
Foo.txtandfoo.txtare the same file. - Linux ext4 — case-sensitive. Two different files.
- Windows NTFS — case-insensitive by default. Since Windows 10 1803+ there is a per-directory case-sensitivity option.
Git tracks file names with case. Code that runs fine on macOS or Windows but fails on Linux CI with import errors is most often this difference.
8. Where WSL2 fits
WSL2 (Windows Subsystem for Linux 2) virtualizes a real Linux kernel on top of Windows. Available since 2019, it runs on a lightweight Hyper-V VM.
- File system — Linux side is ext4, Windows side is NTFS. Cross-side I/O is slow, so keep project files on one side (usually inside WSL at
~/). - Shell · tools — real bash, real
apt. Docker Desktop also uses the WSL2 backend. - VS Code — the Remote-WSL extension makes editing and debugging from Windows seamless.
It is the most integrated option when a Windows user wants a Unix environment.
9. The same task in two notations
| Task | macOS (zsh/bash) | Windows (PowerShell) |
|---|---|---|
| Set env var | export FOO=bar |
$env:FOO = "bar" |
| Read env var | echo $FOO |
echo $env:FOO |
| Home directory | ~ |
~ or $HOME |
| Chain on success | a && b |
a; if ($?) { b } (5.1) / a && b (7+) |
| Grant exec permission | chmod +x script.sh |
(NTFS ACL · execution policy) |
10. Common pitfalls
A .sh script gets converted to CRLF on Windows checkout and fails with a ^M error — declaring *.sh text eol=lf in .gitattributes blocks it.
An import that worked on macOS fails on Linux CI — file name case difference.
After changing PATH on Windows, a forgotten shell restart leaves the new command unfound.
Permission and speed issues when working with Windows files inside WSL through /mnt/c/....
Closing thoughts
Most OS-related accidents land on four spots: line endings, paths, permissions, and shells. A single .gitattributes line of * text=auto eol=lf plus the path abstractions in language standard libraries plus a set of OS-equivalent shell scripts forms the standard shape.
Next
- shells-overview
- bash-and-sh
Microsoft Learn — Naming Files · git-scm gitattributes · Apple zsh as default · WSL 2 docs · Homebrew · winget for reference.