Cross-Platform Script Line Endings

Configure .gitattributes to ensure shell scripts always use LF and batch scripts always use CRLF, preventing execution failures across operating systems.

Best Practices

Detailed Explanation

Script File Line Endings

Script files are among the most sensitive to incorrect line endings. A bash script with CRLF endings won't execute on Unix, and a batch file with LF endings may malfunction on Windows. This is one area where text=auto is not sufficient — you need explicit eol directives.

Recommended Configuration

# Unix scripts (must be LF)
*.sh     text eol=lf
*.bash   text eol=lf
*.zsh    text eol=lf
*.fish   text eol=lf
*.csh    text eol=lf
*.ksh    text eol=lf

# Makefiles (must be LF)
Makefile  text eol=lf
makefile  text eol=lf
*.mk      text eol=lf
GNUmakefile text eol=lf

# Docker (must be LF)
Dockerfile    text eol=lf
Dockerfile.*  text eol=lf
*.dockerfile  text eol=lf
docker-compose.yml text eol=lf

# CI configuration (must be LF)
.travis.yml     text eol=lf
.gitlab-ci.yml  text eol=lf
Jenkinsfile     text eol=lf

# Windows scripts (must be CRLF)
*.bat    text eol=crlf
*.cmd    text eol=crlf
*.ps1    text eol=crlf
*.psm1   text eol=crlf
*.psd1   text eol=crlf

# Git hooks (must be LF)
.husky/* text eol=lf

The Shebang Problem

When a Unix system tries to execute a script with CRLF endings, the shebang line (#!/bin/bash) is interpreted as #!/bin/bash\r. The kernel looks for an interpreter called /bin/bash\r (with a carriage return), which doesn't exist:

/bin/bash^M: bad interpreter: No such file or directory

This error is cryptic and hard to debug, especially in CI/CD pipelines where the developer doesn't have direct terminal access.

Docker and CRLF

Docker builds on Linux will fail if shell commands in the Dockerfile or entrypoint scripts have CRLF endings. A common symptom:

standard_init_linux.go: exec user process caused "no such file or directory"

Git Hooks

Git hooks (.husky/*, .git/hooks/*) are shell scripts executed by Git itself. They must have LF endings and executable permissions. The .gitattributes handles the line endings; chmod +x handles permissions.

Testing Line Endings

Verify your line endings are correct:

# Check for CRLF in a file
file script.sh
# Output: "script.sh: Bourne-Again shell script, ASCII text executable"
# vs: "script.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators"

Use Case

Any repository that contains both Unix shell scripts and Windows batch/PowerShell scripts needs explicit eol directives. This is critical for projects with CI/CD pipelines, Docker workflows, or cross-platform development teams.

Try It — .gitattributes Generator

Open full tool