Line endings, permissions, binaries
Beginner Git CLI
Why this matters
Some day a diff will show every line of a file as changed although you edited one word, or a merge request will contain a file you never touched, marked "mode changed". Both are invisible-character problems, both are harmless once understood, and both waste hours when they are not.
Line endings
Text files end each line with an invisible character. Windows historically uses two (CRLF, carriage return + line feed); macOS, Linux, and GitLab's and GitHub's web editors use one (LF). If Ben on Windows saves a file with CRLF and Ana on macOS opens it, every line differs by one invisible character, and Git reports the whole file as changed.
Git's fix is to convert on the way in and out:
core.autocrlf true(Windows): convert to LF when committing, back to CRLF when checking out. Files in the repository are always LF; files on disk look native.core.autocrlf input(macOS, Linux): convert to LF when committing, never convert on checkout.
You set this in lesson 3.3. When Git converts, it may warn:
$ git add docs/crlf.mdwarning: in the working copy of 'docs/crlf.md', CRLF will be replaced by LF the next time Git touches itThe warning is informational: the file on disk has CRLF, the committed version will have LF. Nothing is wrong; the next checkout normalizes the working copy. It becomes a problem only when a file must keep CRLF (some Windows scripts), which is what .gitattributes is for.
.gitattributes: the team's rule
core.autocrlf is personal configuration; every teammate has to set it correctly. A .gitattributes file in the repository applies to everyone, whatever their settings:
# Normalize all text files to LF in the repository; check out with the platform's native ending
* text=auto
# These must always have Windows line endings
*.bat text eol=crlf
# These are binary: never convert, never diff as text
*.png binary
*.jpg binaryIf your project has one, it wins over your core.autocrlf. If it does not, and line-ending noise appears in reviews, propose adding * text=auto in a small merge request; it is the standard fix.
File modes
Git stores one bit of permission per file: executable or not. On macOS and Linux, chmod +x on a script changes it, and the diff shows it:
$ chmod +x src/trailguide.py
$ git diffdiff --git a/src/trailguide.py b/src/trailguide.py
old mode 100644
new mode 100755100644 is a normal file, 100755 an executable. Such a change is legitimate for a script meant to be run directly, and noise when a tool or a file copy flipped the bit by accident. On Windows the bit does not exist, and Git for Windows ignores mode changes by default (core.fileMode false). If a colleague's merge request shows mode changes on files that should not have them, git update-index --chmod=-x <file> (or copying the file again) restores the mode.
Binary files
Git decides a file is binary by looking at its content: if the first few thousand bytes contain a NUL character, it is binary. Binary files are stored whole, never converted, never diffed line by line:
$ git diff --stageddiff --git a/docs/images/photo.png b/docs/images/photo.png
new file mode 100644
index 0000000..aa860ab
Binary files /dev/null and b/docs/images/photo.png differTwo consequences: reviews cannot show what changed inside, and merges cannot combine two versions (Git asks you to pick one). Mark known binary types in .gitattributes so line-ending conversion never damages them; PDFs and images corrupted by CRLF conversion are a classic problem on projects without that file.
Text files that happen to contain unusual bytes (some exports, some CSVs with a byte-order mark) may be misdetected as binary; .gitattributes can force *.csv text.
Common mistakes
- Panicking at the CRLF warning. It describes a normalization, not damage.
- "Fixing" line endings by re-saving the whole file in a different editor and committing a 400-line diff. Fix the configuration, not the file.
- Committing a mode change by accident (often after copying files from a USB drive or a download). Check
git diffforold modelines before committing. - Converting binaries. Without
binaryattributes and withautocrlfon, a PNG containing the bytes for CR and LF can be altered. Declare binaries in.gitattributes.
Try it yourself
Goal: produce the CRLF warning on purpose and see a mode change.
- In the playground, create a Windows-style file:
printf 'line1\r\nline2\r\n' > docs/crlf.md, thengit add docs/crlf.mdand read the warning (it appears withcore.autocrlf inputortrue). - Unstage and delete it:
git restore --staged docs/crlf.md && rm docs/crlf.md. - On macOS or Linux:
chmod +x src/trailguide.py, rungit diff, thenchmod -x src/trailguide.py.
Expected result: the warning names the file and says CRLF will be replaced by LF; the diff shows old mode 100644 / new mode 100755 and nothing else.
Show solution
The warning is the conversion at work: the committed version would have LF while your disk copy has CRLF. The mode diff is one line of metadata; chmod -x reverses it and git diff goes quiet. On Windows, step 3 shows nothing because file modes are not tracked there.