Meaning of Git checkout double dashes
Asked Answered
F

3

330

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
Fractocumulus answered 10/11, 2012 at 11:4 Comment(6)
It's a shell expression. See unix.stackexchange.com/questions/11376/…Rabbit
@iltempo: It's slightly different for Git. For Git, it separates the tree from the paths, in cases where trees and paths might look the same.Assemblage
Also documented in https://mcmap.net/q/11419/-deleting-a-badly-named-git-branchOe
Duplicate of Difference between "git checkout <filename>" and "git checkout -- <filename>"Stash
It is a duplicate, but this duplicate is at least googleable by the query 'git double dash'.Residentiary
Adding just one word to timmcliu's post to clarify his or her meaning: 'The double dash "--" means "end of command line flags" i.e. it tells the preceding command not to try to parse what comes after as command line options.'Psychoanalysis
A
460

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.

Assemblage answered 10/11, 2012 at 11:9 Comment(11)
This is true for many bash commands, not just git commands, yes?Colmar
@NHDaly: Yes, it is true. However, a terminology note: "Bash" only has a few commands (maybe 20 or so), most commands are separate programs from Bash. It is actually part of the POSIX standard that -- can be used to separate options from other arguments, so you will see it on commands like cp and mv (which are not part of Bash).Assemblage
Any idea why this syntax is not properly described in the checkout command documentation?Honolulu
@TanguyP: Looks like it's described at the top of git-scm.com/docs/git-checkout to me.Assemblage
@DietrichEpp In several places, it's listed like a possible parameter to the checkout command, but nowhere does the documentation explain what it does or why it's used...which is what ultimately brought me here.Tetchy
@chris: It is actually in the docs. In the synopsis: git checkout [-p|--patch] [<tree-ish>] [--] [<paths>…​] The [--] means that -- can be used, optionally, to separate the tree from the paths.Assemblage
@DietrichEpp Correct, but having read the syntax (and the examples) before coming to Stack Overflow, I still did not understand why one would or would not want to use --. As someone who does not come from a linux background, it's not obvious what that does. To me, it appeared to be a syntax specific to git, with no description of its functional purpose. I think it would be better to have a short description like the other options, or at least a link to a linux man page.Tetchy
@chris: You can always refer to the "man-pages" man page, which explains the conventions for the "synopsis" section. Anything in the synopsis which isn't given a meaning is typically just part of the command syntax, like --. man7.org/linux/man-pages/man7/man-pages.7.htmlAssemblage
@Colmar only the last part, about disambiguating between options and positional arguments that happen to start with a - is true, in general. Using -- to disambiguate between different types of positional arguments (eg: "tree-ish" and "paths" in the case of git-checkout) is pretty odd. I've never heard of anything other than git that does this.Curfew
IMO this problem only exists because checking out files and branches are separate commands.Montiel
Indeed, there's similarity between git and bash.Socioeconomic
A
131

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.

Airlie answered 5/3, 2015 at 17:4 Comment(1)
For clarity, in git it means more than this, as it also means the argument after the -- cannot be a branch name, and by implication the argument before -- cannot be a file path.Gastight
O
1

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.

Oe answered 13/2, 2020 at 17:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.