Skip to content

end_of_file_fixer: add optional git EOL-awareness to avoid pre-commit false positives/double-commit workflows #1243

@MarkVerheyen-eaton

Description

@MarkVerheyen-eaton

Summary

end_of_file_fixer currently runs before commit finalization and can flag/fix newline/EOL-related content before Git’s own normalization pipeline has fully applied (especially in environments using core.autocrlf). In practice, this can cause unnecessary hook failures and “double commit” friction.

This issue proposes an opt-in mode that makes end_of_file_fixer aware of Git EOL policy, with .gitattributes as primary source of truth.


Problem

In some setups, Git normalizes line endings during staging/commit/checkout, but end_of_file_fixer may run against working-tree state and attempt fixes earlier than necessary. Result:

  • unnecessary rewrites,
  • false-positive failures,
  • contributors having to commit twice.

Why .gitattributes must be primary (not only core.autocrlf)

core.autocrlf alone is insufficient because it is user/machine config and not path-specific policy.
.gitattributes is versioned, repo-wide, and file-pattern specific (text, -text, eol=lf, eol=crlf), so it is deterministic across contributors and CI.

Proposed precedence:

  1. Effective attributes for path (git check-attr text eol -- <file>)
  2. Fallback to repo-local core.autocrlf only when attributes are inconclusive
  3. Fallback to current behavior if Git context is unavailable

Proposal

Add an opt-in CLI mode, e.g. --respect-git-eol (name flexible), to pre_commit_hooks/end_of_file_fixer.py.

When enabled:

  • resolve effective Git EOL policy per file,
  • avoid premature fix/fail behavior for EOL normalization cases Git is expected to handle,
  • preserve existing strict behavior for real EOF violations not covered by Git normalization,
  • gracefully fallback to existing behavior when not in a git worktree / git unavailable.

Keep default behavior unchanged for backward compatibility.


Suggested CLI additions (proposal)

  • --respect-git-eol (opt-in)
  • (optional) --git-eol-strategy=off|config-only|attributes
    • off: legacy behavior
    • config-only: core.autocrlf fallback logic
    • attributes: prefer .gitattributes (recommended)

Acceptance Criteria

  1. Backward compatibility

    • With no new flag, behavior remains unchanged.
  2. Attribute precedence

    • With git-aware mode enabled, .gitattributes-derived effective policy is used before core.autocrlf.
  3. Reduced false positives

    • Hook does not require unnecessary rewrites for EOL cases Git policy is expected to normalize.
  4. Safety fallback

    • If git/attributes cannot be resolved, hook falls back to legacy behavior without crashing.
  5. Coverage

    • Tests cover:
      • eol=lf, eol=crlf, text=auto, -text
      • no attributes + varying core.autocrlf
      • binary files
      • non-git directory execution
      • Linux + Windows behavior

Repro context

Observed in workflows where contributors rely on Git line-ending normalization; hook runs pre-commit and can fail before Git normalization fully resolves effective EOL content, causing “double commit” friction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions