在以前的项目中,我经常运行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)
。--
从文件名中分隔提交说明符,例如master
或develop
或1f3a907
或其他。如果文件名为--
,则通常需要master
:git 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/master
,origin/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因此,如果您有文件README
,hello
和node_modules
等,那么Git看到的是:git checkout -- README hello node_modules ...
没有
<tree-ish>
,因此Git在索引中查找名为README
,hello
,node_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/