141

http://norbauer.com/notebooks/code/notes/git-revert-reset-a-single-file

I have found a post.

But still don't know what is the difference between

  1. git checkout <filename>

  2. git checkout -- <filename>

In what situation I should use first one and second one respectively?

1

4 Answers 4

270

The special "option" -- means "treat every argument after this point as a file name, no matter what it looks like." This is not Git-specific, it's a general Unix command line convention. Normally you use it to clarify that an argument is a file name rather than an option, e.g.

rm -f      # does nothing
rm -- -f   # deletes a file named "-f"

git checkout1 also takes -- to mean that subsequent arguments are not its optional "treeish" parameter specifying which commit you want.

So in this context it's safe to use -- always, but you need it when the file you want to revert has a name that begins with -, or is the same as the name of a branch. Some examples for branch/file disambiguation:

git checkout README     # would normally discard uncommitted changes
                        # to the _file_ "README"

git checkout master     # would normally switch the working copy to
                        # the _branch_ "master"

git checkout -- master  # discard uncommitted changes to the _file_ "master"

and option/file disambiguation:

git checkout -p -- README  # interactively discard uncommitted changes
                           # to the file "README"

git checkout -- -p README  # unconditionally discard all uncommitted
                           # changes to the files "-p" and "README"

I'm not sure what you do if you have a branch whose name begins with -. Perhaps don't do that in the first place.


1 in this mode; "checkout" can do several other things as well. I have never understood why git chose to implement "discard uncommitted changes" as a mode of the "checkout" subcommand, rather than "revert" like most other VCSes, or "reset" which I think might make more sense in git's own terms.

6
  • 14
    git checkout <name> checks out the branch <name>. git checkout -- <name> checks out the index version of the file <name>.
    – dunni
    Commented Jul 3, 2011 at 9:33
  • 3
    Thanks, unfortunately the git documentation doesn't really explain this
    – Carlton
    Commented Dec 13, 2013 at 10:57
  • 1
    Regarding "Unix convention": indeed -- as a separator between options and arguments is widely implemented. It works for any program/utility that uses POSIX getopt(3) to handle its command line options, (see man 3 getopt), shell-scripts which use getopt(1), and some programs which implement it themselves, but is not universally guaranteed to work.
    – arielf
    Commented Mar 22, 2016 at 17:56
  • 1
    Hah! I simply read an example way back when of how to discard working changes, having forgotten seeing this convention in other command-line programs, assumed that -- meant 'negate changes' a la C/C++ - and have been thinking that ever since. Mind blown! Commented Jul 19, 2016 at 13:38
  • For people like me: don't get confused by name master, he means file named master and not the branch.
    – HarsH
    Commented Aug 14, 2019 at 23:54
12

Anything following the -- is treated as a filename (not as a program argument). This is important if, for example, you have filenames which start with dashes.

1
  • 1
    This is the best answer. It is short and clear.
    – F.Tamy
    Commented May 3, 2021 at 11:34
0

The difference between git checkout <filename> and git checkout -- <filename> lies in the handling of unmerged changes.

git checkout <filename> discards the changes in the current branch and replaces the file with the version from the specified branch or commit. If you have unmerged changes in the file, this command will fail and you'll get an error message.

git checkout -- <filename> discards all changes in the file, including any unmerged changes. This is useful when you want to completely discard your local changes and start over with the version from the specified branch or commit.

In summary, git checkout <filename> is used to switch to a specific version of a file while preserving the changes that have been merged into the current branch, while git checkout -- <filename> discards all changes in a file, including unmerged changes.

0
git checkout -- filename

will replace the version of the file you have in working directory with the one you have in index(staging area).

git checkout filename

will try to checkout the branch with the same name, if it doesn't exist then it will perform same operation as git checkout -- <filename>

Not the answer you're looking for? Browse other questions tagged or ask your own question.