“git checkout - 。”和“git checkout - ”之间的区别。

时间:2017-05-16 12:07:06

标签: git

使用“git checkout”时,我对这两个选项感到有点困惑

我总是使用git checkout -- .清除我的工作目录。

但今天我错误地输入了git checkout - .。我发现没有来自git的错误警报。

我已经阅读了git文档,也不知道这个-选项的作用。这很难谷歌。

所以,请有人对此有任何想法吗?

3 个答案:

答案 0 :(得分:7)

使用git checkout时,您可以使用-作为@{-1}的简写。
来自man git-checkout(强调第二段):

<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}".

通过在分支master中创建文件,在另一个分支中修改它,并使用master中的checkout -来尝试在空的仓库中执行此操作:

$ 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

答案 1 :(得分:4)

更新 - 我现在可以重现这种行为,但那是因为我遵循了Marth在答案中提供的信息。

我要补充的主要内容是:出于诊断目的,如果你不确定像checkout这样的git命令的效果,请使用git status并查看它是什么。由于checkout主要影响索引和工作树,因此您应该能够至少看到命令以这种方式改变了什么。

总结是你偶然发现了一种不那么常见的语法,几乎肯定没有按照你的意图行事(当然也不能指望做你想做的事情)。

原始回答

我无法重现您描述的行为。具体来说,如果我说git checkout - .我收到错误,非0返回代码,并且没有签出。

-应该被解释为路径规范(我得到的错误反映了这一点);另一种可能性是“tree-ish”(意思是分支,标签,提交ID等);但-不是有效的分支名称。

因此,如果您的工作目录中碰巧有一个名为-的跟踪文件,git将只刷新该文件并报告没有警告/错误。

我不确定你对“难以谷歌”的意思;如果你需要git命令的帮助,只需谷歌命令(例如'git checkout`),至少根据我的经验,这应该导致该命令的权威git文档(包括命令语法,它应该告诉你如何解释给定的参数。)

在这种情况下,当我谷歌git checkout时,第一个结果是https://git-scm.com/docs/git-checkout

答案 2 :(得分:2)

Marth's answer中一样(这是正确的,而且我已经赞成它),我们从git checkout -git checkout @{-1}的同义词的概念开始,它告诉Git: 看看我的HEAD reflog并在我运行 git checkout branchname 之前找到我所在的分支,并再次检查该分支。这种语法背后的一般思路是你可以这样做:

$ 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 ...

不幸的是,这与一般的git checkout [ tree-ish ] [ -- ] path [path ...]命令格式结合得很差,正如我所知,这意味着:

  • 如果指定了 tree-ish ,请将其查找为树(即,如果它提交,则将其转换为提交的源树;如果它&#39 ; sa标签,剥离标签,直到我们到达树木)。否则(未指定 tree-ish ),从索引中提取文件。
  • --:此部分是可选的,用于将 tree-ish (如果存在)与任何路径参数分开。如果我们有一个名为zorg的文件,我们想从索引中提取,但还有一个名为zorg的分支,我们需要这个。如果我们写了git checkout zorg而不是git checkout -- zorg,Git会尝试检查分支。
  • 路径:必须至少指定一个;这些是要提取的特定文件(来自索引,或来自 tree-ish )。从索引中提取文件时,Git将它们写入工作树(而不是索引,因为它们已经索引中)。但是,从 tree-ish 中提取文件时,Git会先将它们写入索引,然后再将其写入工作树。

因此,当我们写:

git checkout -- f1 f2 f3

Git将--视为含义&#34;没有分支,因此没有树,因此请使用索引&#34 ;;因此,各种文件名是从索引中提取的文件,用于覆盖工作树中的内容。

我们可能会这样做的一个原因是我们已经编辑了f1f2f3,并认为它们很好。然后我们git add编辑它们以将这些版本复制到索引中。然后我们对它们进行了一些编辑......但是我们认为工作树版本很糟糕,我们希望 index 版本回到工作树中。这些索引版本尚未提交任何提交:它们仅存储在 索引中。

(我们可能使用git checkout -- f1 f2 f3的另一个原因是我们编辑了它们但 git add编辑它们。在这种情况下,索引版本与{{{ 1}}版本...因此在这个的情况下我们很好:我们可以重新提取HEAD版本。)

问题

不幸的是,如果我们将其拼写为:

HEAD

然后Git将其视为我们输入的内容:

git checkout - f1 f2 f3

表示通过reflog查找上一个分支,然后将该分支提示中的文件提取到索引中,然后再导入工作树。 这会覆盖我们打算恢复的索引版本(除非这些&#34;旨在恢复&#34;版本与之前的分支版本相匹配)。

恢复

有一种方法可以恢复索引中的唯一版本,但这非常痛苦:运行git checkout @{-1} f1 f2 f3 ,然后搜索Git写入{的哈希命名文件{1}}。可能有很多(实际数量取决于存储库中存在的悬空blob的数量)。其中三个 - 但没有告诉哪个三个没有仔细检查每个恢复的blob文件 - 我们的三个版本的文件git fsck --lost-found.git/lost-found/other和{{1我们想要回来的。

沉思

我经常认为f1应该至少有两个,可能是三个或更多个单独的命令:

  • 一个检查分支或提交:这个将进行标准安全检查。运行f2总是安全的,因为它永远不会覆盖任何文件;只有f3会有危险。
  • 一个用于检出索引中的文件。 (实际上,这样的命令,即git checkout。你可以使用它代替git checkout foo。它是一个管道命令,所以它不是面向用户,更难以使用。)这个可能也许也是git checkout --force foo,虽然它有点危险,因为它可以覆盖工作树工作,这是{{ {1}}做了,不做。前端瓷器git checkout-index可能是正确的名称。
  • 一个用于检查特定提交中的特定文件。由于这将拼写不同(可能git checkout或某些此类),即使它是危险的&#34; (覆盖现有文件和/或索引条目),很明显我们不会使用&#34; safe&#34;各种git checkout tree-ish 在这里是可选的,因此更难以犯git checkout vs git co-index错误(这就是为什么它可能应该是git co-tree)的单独命令。

但这不是我们所拥有的。