Git's --end-of-options Flag: What It Really Means for Developers
Git's --end-of-options flag resolves the double-dash ambiguity, but also highlights deeper issues in tool design and the Unix philosophy.
Git's command-line interface is famously powerful—and famously inconsistent. For years, developers have used the double-dash (--) to separate options from arguments. But when -- also separates revisions from paths in commands like git log, ambiguity creeps in. Enter --end-of-options, introduced in Git 2.45, to draw a clear line. This flag tells Git that everything after it is an argument, not an option. It's a pragmatic fix, but one that raises bigger questions about tool complexity and the Unix philosophy.
The Double-Dash Ambiguity Problem
Git's double-dash overload is the root cause. In most Unix tools, -- signals the end of options. But Git also uses -- to separate revisions from pathspecs in commands like git log. When a filename or branch name starts with a dash—for example, git checkout -mybranch—the traditional workaround is --. But in git log, git log -- --somefile works, while git log -- --branch becomes ambiguous: is --branch a path or a revision?
The new --end-of-options flag resolves this. For example:
git some-command --end-of-options -dodgy-filename
This ensures -dodgy-filename is treated as a name, not an option. It's a niche but welcome addition for edge cases involving unusual filenames or automated pipelines.
Community Reaction: Complexity vs. Pragmatism
The Hacker News thread (score 118, 51 comments) captures mixed feelings. One commenter wrote:
Does anyone know why git broke the long standing convention of "--" early on? Kind of a nightmare for humans to use. Remembering app-specific one-offs is kind of the worst!
Another joked:
So I should name my next branch '--' is what I'm hearing :)
The deeper critique revolves around Git's growing complexity. One user noted:
As with almost any successful system: more and more special features and edge cases get added. Git has become ridiculously complex.
And another pointed out the tension in the Unix philosophy:
The "Everything is text, do everything via text" philosophy has its advantages, and also its disadvantages.
The thread reflects a broader unease: are we piling on bandaids instead of fixing the root cause?
How to Use --end-of-options
If you write scripts that handle arbitrary input (e.g., filenames from user uploads), --end-of-options is a lifesaver. Here's how to use it:
# Without the flag – dangerous if filename starts with dash
git add -dangerous-file
# With the flag – safe
git add --end-of-options -dangerous-file
For git log, ambiguity arises when a revision name looks like a path:
# What does this mean? Revision named '--' or something else?
git log -- --
# Explicit with --end-of-options
git log --end-of-options some-revision -- some-path
The flag is particularly useful in pipelines where argument order is uncontrolled:
# Passing through user-provided refs and paths
REV="$1"
PATH="$2"
git log --end-of-options "$REV" -- "$PATH"
If you're building a Git wrapper or tool that generates Git commands, consider adding --end-of-options to avoid injection-like bugs. Also update shell aliases if you habitually use -- in risky contexts.
Downsides
It's one more thing to remember. For interactive use, most developers won't switch. The old -- works in 99% of cases. The flag is verbose and not widely known—it may fade like --literal-pathspecs.
The Bigger Picture: Tool Design Philosophy
--end-of-options is pragmatic, but it highlights a design smell: the same token used for two purposes. Adding another delimiter feels like duct tape. Tools evolve, and the Unix tradition of composable primitives works wonderfully most of the time. Edge cases (filenames with dashes, ambiguous revision ranges) are rare but painful. A dedicated flag is better than a magic incantation.
What would be better? Perhaps a syntax like git cmd --opts --revspec -- pathspec where the position of -- determines its meaning. That was suggested on HN. It's cleaner but would break backward compatibility. Git chooses to layer new flags rather than redesign—a reasonable trade-off.
For me, the real lesson is designing for humans. If a tool needs a glossary of delimiter conventions, the mental model is too complex. Git could learn from tools like ripgrep or fzf, which use clear, orthogonal flags.
Should You Care?
If you write Git scripts or tools handling arbitrary input, yes—adopt --end-of-options to future-proof your code. If you're a casual Git user typing short commands, ignore it. The root problem of Git's interface complexity remains, but this flag is a small step toward clarity—if you remember to use it.
Links: Original blog post | HN discussion | Git documentation on --end-of-options | GNU getopt conventions