Difference between "git checkout -." and "git checkout -."

I am a little confused with these two options when using "git checkout"

I've always used git checkout -- .

to clear the working directory.

but today when I type git checkout - .

by mistake. I didn't find any error warning from git.

I've read the git documentation and also don't know what this option does -

. And that's hard for Google.

So please, does anyone have this?

+3


source to share


3 answers


When used, git checkout

you can use -

as shorthand for @{-1}

.
From man git-checkout

(highlighting the second paragraph):

<branch>
    Branch to checkout; if it refers to a branch (i.e., a name that, when
    prepended with "refs/heads/", is a valid ref), then that branch is checked
    out. Otherwise, if it refers to a valid commit, your HEAD becomes
    "detached" and you are no longer on any branch (see below for details).

    As a special case, the "@{-N}" syntax for the N-th last branch/commit
    checks out branches (instead of detaching). You may also specify - which is
    synonymous with "@{-1}".

      




Try this on an empty repo by creating a file on a branch master

, modifying it on another branch and using checkout -

from master:

$ git init
Initialized empty Git repository in workspace/git-test/.git/

git:(master)  $ echo a > a
git:(master*) $ git add a 
git:(master*) $ git commit
[master (root-commit) 8433343] Add a to master
 1 file changed, 1 insertion(+)
 create mode 100644 a

git:(master)  $ git checkout -b other
Switched to a new branch 'other'

git:(other)   $ echo b > a
git:(other*)  $ git add a 
git:(other*)  $ git commit
[other be2298f] Replace a by b
 1 file changed, 1 insertion(+), 1 deletion(-)

git:(other)   $ git checkout -
Switched to branch 'master'

git:(master)  $ git checkout -- . # no changes (no * next to master in the line below)
git:(master)  $ git checkout - . # checking out files from alternate branch 'other'
git:(master*) $ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   a

git:(master*) $ cat a
b

      

+7


source


UPDATE . I can reproduce this behavior now, but that is because I followed the information Mart received in their answer.

The main thing I would add: for diagnostic purposes, if you are not sure about the action of a git command, for example checkout

, use git status

and see what. Since it checkout

mainly affects the index and the working tree, you should be able to at least see what the command changed in this way.

Synopsis: You stumbled upon a less common syntax that almost certainly didn't do what you intended (and certainly can't count on what you have to do).


Original Answer



I cannot reproduce the behavior you described. In particular, if I say git checkout - .

, I get an error, a nonzero return code and no validation occurs.

-

should be interpreted as a path specification (and the error I get reflects this); another possibility would be "tree" (which means branch, tag, commit id, etc.); but is -

not a valid branch name.

So, if you have a tracked file named in your working directory -

, git will just update that file and not report any warnings / errors.

I'm not sure what you mean by "hard to google"; if you need help with a git command just run a google command (like 'git checkout`) and at least in my experience this should lead to the final git documentation for that command (which includes the command syntax which should tell you how the given argument will be interpreted).

In this case when I google the git checkout

first result is https://git-scm.com/docs/git-checkout

+4


source


As in Marth's answer (which is correct and I supported it), we start with what git checkout -

is the synonym git checkout @{-1}

that Git says: Look at my HEAD reflog and find which branch I was on before I ran git checkout branchname

and check that forking again. The general idea behind this syntax is you can:

$ git checkout feature/X
... hack for a while ...
$ git commit -m "save some temporary work"
$ git checkout bug1234
... do a quick fix or look for something ...
$ git checkout -
... now back on feature/X ...

      

Unfortunately this does not fit well with the general command format git checkout [ tree-ish ] [ -- ] path [path ...]

, which I think means:

  • If tree-ish is specified, find it as a tree (i.e., if committed, convert it to the commit source tree, if it is a tag, clear the tag until we reach the tree). Otherwise (no tree specified), extract the files from the index.
  • --

    : This part is optional and serves to separate the tree, if present, from any path arguments. We need this if we have, for example, a named file zorg

    that we want to check out from the index, but also have a named branch zorg

    . If we wrote git checkout zorg

    instead git checkout -- zorg

    , Git would try to checkout the branch.
  • path: at least one must be specified; these are the specific files to extract (from the index or from the ish tree). When retrieving files from the index, Git writes them to the work tree (not the index, because they are already in the index). However, when retrieving files from the tree, Git first writes them to the index and then to the work tree.

Thus, when we write:

git checkout -- f1 f2 f3

      

Git sees it --

as meaning "no branch and therefore not tree-like, so use an index"; so the different filenames are files to be retrieved from the index to overwrite them in the tree.

One of the reasons why we can do this - is to edit f1

, f2

and f3

to think that they were good. We then git add

released them to copy these versions into the index. Then we edited them some more ... but decided that the versions of the work tree were bad and that we want the indexed versions to return to the work tree. These index versions are not yet committed: they are only stored in the index.

(Another reason we can use git checkout -- f1 f2 f3

is that we edited them, but not git add

ed. In this case, the versions of the index were identical to the versions HEAD

... and therefore, in this case, we are "great: we can just re- extract versions HEAD

.)

Problem

Unfortunately, if we seal it like:

git checkout - f1 f2 f3

      

then Git treats it as if we had entered:

git checkout @{-1} f1 f2 f3

      

which means finding the previous branch with reflogs and then fetching files from that branch tip into the index and then into the work tree. This overwrites the versions of the indexes that we planned to restore (if, for some reason, the versions to be restored are not the same as the versions of the previous versions).

Recovery

There is a way to get versions with a single index back , but this is quite painful: run git fsck --lost-found

and then search the Git hash filenames in .git/lost-found/other

. There are probably a lot (the actual number depends on the number of dangling drops you have in your repository). Three of them - but it is not said which three without careful examination of each recovered blob file - are our three versions of the files f1

, f2

and f3

which we wanted to return.

Musings

I have often thought that there git checkout

should be at least two and possibly three or more separate commands:

  • One to checkout a branch or commit: this will have standard security checks. It would always be safe to run git checkout foo

    as it will never overwrite any files; git checkout --force foo

    will only be dangerous.
  • One to check files from the index. (Actually, there is such a command, viz git checkout-index

    . You can use that instead git checkout

    . This is the plumbing command, so it is not that user-centered and hurts more.) This might be possible as well git checkout

    , although it is a bit dangerous as it might overwrite work of a tree that simple git checkout

    does and won't. For this can be the right china china git co-index

    .
  • One to check specific files from specific commits. Since this would be written in different ways (perhaps git co-tree

    or some of them), although it is "dangerous" (overwriting existing files and / or index entries), it would be clear that we are not using the "safe" variety git checkout

    . The tree view here would not be optional, so it would be harder to make the -

    vs error --

    (which is why it should probably be a separate command from git co-index

    ).

But that's not what we have.

+2


source







All Articles