git - Git提取无法解决git checkout上的pathspec错误— *

标签 git git-checkout

在以前的项目中,我经常运行git checkout -- *放弃工作目录中的所有更改。


在当前的项目中,我得到以下信息:

$ git checkout -- *
error: pathspec 'node_modules' did not match any file(s) known to git.

然后,我做一个git status

$ git status
On branch <feature_branch>
Your branch is ahead of 'origin/<feature_branch>' by 2 commits.
  (use "git push" to publish your local commits)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   <relative_file_path_in_current_app_dir>

no changes added to commit (use "git add" and/or "git commit -a")

我阅读了另一个StackOverflow post,其中说git fetch可以解决此pathspec错误。我试过了,它从远程启动了一个新的功能分支:

$ git fetch
remote: Counting objects: 67, done.
remote: Compressing objects: 100% (67/67), done.
remote: Total 67 (delta 55), reused 0 (delta 0)
Unpacking objects: 100% (67/67), done.
From https://bitbucket.org/<repo_name>
   b42b31e05..e7f3858ad  <unrelated_bug_branch>       -> origin/<unrelated_bug_branch>
   36b2cd4e9..ac87583fd  develop                      -> origin/develop
   61945b8ef..22a63fd7e  <unrelated_feature_1_branch> -> origin/<unrelated_feature_branch>
   322a39980..1f8752f2c  <unrelated_feature_2_branch> -> origin/<unrelated_feature_2_branch>
 * [new branch]          <unrelated_feature_3_branch> -> origin/<unrelated_feature_3_branch>
   5fe02b8b3..a27140571  <unrelated_feature_4_branch> -> origin/<unrelated_feature_4_branch>

我再做一个git status,它与上面的#2相同。
我可以定位到特定文件,这将起作用:

$ git checkout -- <relative_file_path_in_current_app_dir>

git status现在显示我有一棵干净的工作树。


我的pathspec错误的根本原因是什么?如何解决?在此期间,我可以检出特定文件,但是我对此错误感到很好奇。

最佳答案

恐怕链接的问题Git: cannot checkout branch - error: pathspec '...' did not match any file(s) known to git是一团糟:正如您所指出的,它有很多答案,而且很少说明。同时,ElpieKay's comment有一个正确的答案:node_modules是您要让Git忽略的文件或目录,因此当您要求Git更新它时,它说:嗯?现在更新什么?

详细说明

问题的根源在于Git将太多东西塞进一个命令中。 git checkout命令可以:


根据一些现有的远程跟踪名称(例如develop)自动创建一个新分支(例如,新的分支名称(例如origin/develop));要么
检出现有分支(具有给定名称的分支,例如master);要么
检出现有的历史记录提交(例如,通过像v1.2这样的标签名,或通过原始哈希ID),从而得到Git称为分离的HEAD的信息。


所有这些动作以某种方式移动了Git的HEAD概念。特殊名称HEAD(所有大写字母,这在Linux系统上通常是必需的,而Windows用户通常可以用小写字母键入head来逃避)是Git记住您所在的分支(如果有)的方式。因此,以上三种git checkout会更改您所在的分支,或者-对于听起来很吓人但实际上在内部非常正常的1 HEAD头例来说,缺少任何分支。



例如,当您处于冲突或交互式基础时,1Git使用此分离的HEAD状态。将其用于正常开发不是一个好主意,但对于临时工作或这些内部状态到Git状态则很好。只需完成您的变基,或导致HEAD暂时脱离的任何原因,Git就会重新连接HEAD,您可以继续进行头部固定的连接。 :-)



但是git checkout可以做很多事情,根本不需要更改HEAD,这就是git checkout --的目的。在这里,Git可以:


从索引中提取一个或多个文件到您的工作树:git checkout -- filename(s),或
从特定提交中提取一个或多个文件,先将其写入索引,然后再写入工作树:git checkout commit-specifier -- filename(s)


--从文件名中分隔提交说明符,例如masterdevelop1f3a907或其他。如果文件名为--,则通常需要mastergit checkout master会将您的HEAD切换为master,而不是检出名为master的文件。有时是可选的:如果您有一个名为master的文件,但您想从develop的尖端获取副本,则编写git checkout develop master可以使Git清楚(即使它会使普通人感到困惑)。

git checkout可以做更多的事情,但让我们从这三组明显不同的操作开始:(1)将HEAD更改为不同的分支,(2)更改HEAD以在特定提交时分离, (3)根本不更改HEAD,只需从索引或特定提交中获取一个文件或多个文件即可。

Git用the git checkout documentation中的各种语法标记来表达这些不同的动作。引用它(我将引用其中包含的整个可怕的七项列表),我们看到:


git checkout [-q] [-f] [-m] [<branch>]
git checkout [-q] [-f] [-m] --detach [<branch>]
git checkout [-q] [-f] [-m] [--detach] <commit>
git checkout [-q] [-f] [-m] [[-b | -B | --orphan] <new_branch> [<start_point>]
git checkout [-f | --ours | --theirs | -m | --conflict=<style>] [<tree-ish>] [--] <paths>...
git checkout [<tree-ish>] [--] <pathspec>...
git checkout(-p | --patch)[<tree-ish>] [--] [<paths>...]


其中三个是我们在此答案中讨论的操作(其他四个是git checkout可以做的更多事情,其中​​一些可能应该是不同的Git命令)。让我们来看看它们。

按名称签出分支(或签出提交并分离HEAD)

从第一行开始:


git checkout [<branch>]


(我省略了简化选项)。这会在尖括号中显示分支名称,这意味着您应该填写一个。在方括号中也是如此,因此您可以将其省略,但是如果您将其保留,则表示“停留在当前分支”,即有点愚蠢的事情。将branch放在这样的尖括号中,将其标记为某些人所说的元变量,即您应该填写的内容,其中元变量的名称告诉您这里发生了什么事情:分支名称!

这是切换到某些现有分支,或从某些现有远程跟踪名称操作创建新分支。您提供的分支名称是要切换到或自动创建的分支名称。 Git将查找具有该名称的现有分支,如果找不到该分支,将遍历您的所有远程跟踪名称(您的origin/masterorigin/develop等),以查看这些名称之一是否可以具有origin/已删除,是您要求的名称。

(第二引号行与第一行类似,但是插入了--detach。第三行与前两行类似,但不是<branch>而是<commit>。在第二个命令行中,需要--detach ,并且在第三个字段中,它又是可选的。<commit>元变量意味着您可以使用命名提交的任何内容,而不仅仅是分支名称。这些是产生分离的HEAD的变体:他们签出提交切换分支的方法相同,但是在此过程中它们会砍掉HEAD,因此您就不在分支上。本质上,如果给git checkout一个命名为提交但不是分支名称的参数,Git只是假设您的意思是--detach。如果要在使用分支名称时分离,则必须添加--detach。这最后一步不是大多数人想要做的,但无论如何手册页都会介绍它。)

链接的问题及其答案主要是关于使用远程跟踪名称创建新分支。也就是说,他们回答了以下问题:


如果我说git checkout feature-X时出现错误,但随后我运行git fetch,然后再次执行git checkout feature-X,它就可以了。为什么?


答案是第一次运行git checkout develop时,您没有origin/feature-X,但是在git fetch完成后,您确实具有origin/feature-X。这是因为git fetch创建了它,是因为其他人在feature-X上创建了origin的时间相对较新。 git fetch让您的Git在origin调用Git,并获取其所有分支和提交的列表。您的Git加载了您尚未使用的所有新提交,并创建或更新了所有origin/*名称,现在您有了origin/feature-X

检出特定文件

倒数第二句语法行:


git checkout [<tree-ish>] [--] <pathspec>...


显示了两个元变量。第一个拼写为<tree-ish>,它是Git的简写:您可以在这里使用分支名称,提交哈希或可以用来查找树对象的任何东西。 Git有很多指定提交哈希ID的方法,这旨在覆盖所有ID,以及一些您不太可能遇到的更奇怪的极端情况。这个第一个元变量是可选的,如果您忽略它,Git将从Git的索引中检出文件(我们在这里没有真正描述它,因为它已经足够长了,我将不做详细介绍)。

第二个元变量是<pathspec>。请注意,它不是可选的!这是Git的缩写,表示文件名或*的模式,或者还有很多太长的内容无法在此处输入。 ...部分意味着您可以列出其中多个。这些路径指定了您希望Git在<tree-ish>中找到的一个或多个特定文件(您命名的提交,如果命名为一个)。

哪里出错了

当你写:

git checkout -- *


您的shell(可能是bash)会扩展*以匹配当前工作目录中的所有文件。2因此,如果您有文件READMEhellonode_modules等,那么Git看到的是:

git checkout -- README hello node_modules ...


没有<tree-ish>,因此Git在索引中查找名为READMEhellonode_modules等的文件。

如果找不到其中之一,也找不到node_modules,则Git会抱怨:


error: pathspec 'node_modules' did not match any file(s) known to git.



什么也没做。

如果改为使用.,则外壳程序将运行:

git checkout -- .


Git将.视为<pathspec>参数。这意味着“当前目录中Git已知的所有文件”,这样就可以完成您想要的操作。您还可以编写:

git checkout -- '*'


它使用引号保护*免受bash(或您正在使用的任何shell)的侵害。然后,Git将看到*,Git将展开*到“当前目录中Git已知的所有文件”。但是编写.更容易。



2请注意,在Windows上,CMD.EXE不会扩展*,而是将其传递给Git,让Git扩展*,并且永远不会发生此错误!

关于git - Git提取无法解决git checkout上的pathspec错误— *,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51749222/

相关文章:

git - 如何在没有 merge 冲突的情况下将一长串 git merge 转换为单个 rebase?

git - 如何将更改从一个分支移动到另一个分支git?

git - `git log --name-only` 显示合作者

windows - Egit 显示所有文件已更改

git - 我如何在 git 中故意分离 HEAD?

git checkout 修改后的文件没有复制粘贴完整文件路径

git - 将 Git 索引复制到临时文件夹中

git - 更新**不是**当前分支(在 Git 中)

objective-c - Xcode/git 不适用于子文件夹

git stash 错误 : git stash pop and ended up with merge conflicts