Meaning of Git checkout double dashes – Dev

The best answers to the question “Meaning of Git checkout double dashes” in the category Dev.

QUESTION:

What is the meaning of the double dashes before the file name in this git command?

git checkout --ours -- path/to/file.txt
git checkout --theirs -- path/to/file.txt

Are they mandatory? Is it equivalent to

git checkout --ours path/to/file.txt
git checkout --theirs path/to/file.txt

ANSWER:

The double dash “–” means “end of command line flags” i.e. it tells the preceding command not to try to parse what comes after command line options.

ANSWER:

Suppose I have a file named path/to/file.txt in my Git repository, and I want to revert changes on it.

git checkout path/to/file.txt

Now suppose that the file is named master

git checkout master

Whoops! That changed branches instead. The -- separates the tree you want to check out from the files you want to check out.

git checkout -- master

It also helps us if some freako added a file named -f to our repository:

git checkout -f      # wrong
git checkout -- -f   # right

This is documented in git-checkout: Argument Disambiguation.

ANSWER:

Note that you would not need, since Git 2.5 (Q2 2015) a ‘--‘ if your argument includes wildcard (*)

An heuristic to help the “git <cmd> <revs> <pathspec>” command line convention to catch mistyped paths is to make sure all the non-rev parameters in the later part of the command line are names of the files in the working tree, but that means “git grep $str -- \*.c” must always be disambiguated with “--“, because nobody sane will create a file whose name literally is asterisk-dot-see.

Git 2.5 looses the heuristic to declare that with a wildcard string the user likely meant to give us a pathspec.

git checkout 'a*'
# same as
git checkout -- 'a*'

See commit 28fcc0b (02 May 2015) by Duy Nguyen (nguyenlocduy).
(Merged by Junio C Hamano — gitster — in commit 949d167, 19 May 2015)

pathspec: avoid the need of “--” when wildcard is used

When “--” is lacking from the command line and a command can take both revs and paths, the idea is if an argument can be seen as both an extended SHA-1 and a path, then “--” is required or git refuses to continue.
It’s currently implemented as:

  • (1) if an argument is rev, then it must not exist in worktree
  • (2) else, it must exist in worktree
  • (3) else, “--” is required.

These rules work for literal paths, but when non-literal pathspec is involved, it almost always requires the user to add “--” because it fails (2) and (1) is really rarely met (take “*.c” for example, (1) is met if there is a ref named “*.c“).

This patch modifies the rules a bit by considering any valid (*) wildcard pathspec “exist in worktree”.
The rules become:

  • (1) if an arg is a rev, then it must either exist in worktree or not be a valid wildcard pathspec.
  • (2) else, it either exists in worktree or is a wildcard pathspec
  • (3) else, “--” is required.

With the new rules, “--” is not needed most of the time when wildcard pathspec is involved.


With Git 2.26 (Q1 2020), the disambiguation logic to tell revisions and pathspec apart has been tweaked so that backslash-escaped glob special characters do not count in the “wildcards are pathspec” rule.

See commit 39e21c6 (25 Jan 2020) by Jeff King (peff).
(Merged by Junio C Hamano — gitster — in commit 341f8a6, 12 Feb 2020)

verify_filename(): handle backslashes in “wildcards are pathspecs” rule

Reported-by: David Burström
Signed-off-by: Jeff King

Commit 28fcc0b71a (pathspec: avoid the need of “--” when wildcard is used, 2015-05-02) allowed:

git rev-parse '*.c'

without the double-dash.

But the rule it uses to check for wildcards actually looks for any glob special.
This is overly liberal, as it means that a pattern that doesn’t actually do any wildcard matching, like “a\b“, will be considered a pathspec.

If you do have such a file on disk, that’s presumably what you wanted.
But if you don’t, the results are confusing: rather than say “there's no such path a\b“, we’ll quietly accept it as a pathspec which very likely matches nothing (or at least not what you intended).
Likewise, looking for path “a\*b” doesn’t expand the search at all; it would only find a single entry, “a*b“.

This commit switches the rule to trigger only when glob metacharacters would expand the search, meaning both of those cases will now report an error (you can still disambiguate using “--“, of course; we’re just tightening the DWIM heuristic).

(DWIM: Do What I Mean)

Note that we didn’t test the original feature in 28fcc0b71a at all.
So this patch not only tests for these corner cases, but also adds a regression test for the existing behavior.