在以前的项目中,我经常运行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错误的根本原因是什么?如何解决?在此期间,我可以检出特定文件,但是我对此错误感到好奇。
答案 0 :(得分:2)
恐怕链接的问题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
)自动创建一个新分支(例如,新的分支 name 例如origin/develop
);或master
);或v1.2
,或通过原始哈希ID),从而导致Git称为分离的HEAD 。所有这些操作以某种方式移动了Git的HEAD
概念。特殊名称HEAD
(所有大写字母,这在Linux系统上通常是必需的,而Windows用户通常可以通过小写键入head
来逃避)是Git记住您所在的分支的方式。因此,以上三种git checkout
会更改您在哪个分支上,或者-听起来很吓人,但实际上在内部却很正常, 1 分离了HEAD情况,没有任何分支机构。
1 Git使用此分离的HEAD状态。将其用于正常开发不是一个好主意,但对于临时工作或这些内部状态到Git状态则很好。只需完成您的变基,或者导致HEAD临时分离的任何原因,Git就会重新连接HEAD,您可以继续进行头部固定的连接。 :-)
但是git checkout
可以做很多不涉及的事情,而根本不涉及更改HEAD
,这就是git checkout --
的目的。在这里,Git可以:
git checkout -- filename(s)
,或git checkout commit-specifier -- filename(s)
。 --
从文件名中分隔提交说明符,例如master
或develop
或1f3a907
或其他名称。如果文件名为--
,{em}通常是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命令不同)。让我们来看看它们。
从第一行开始:
git checkout [
<branch>
]
(我省略了简化选项)。这会在尖括号中显示分支名称,这意味着您应该填写一个。在方括号中也是如此,因此您可以忽略它,但是如果您 do 忽略它,则表示“保持当前分支”,这是一件很愚蠢的事情。将branch
放在这样的尖括号中,将其标记为某些人所说的元变量,即您应该使用 name 填写的内容元变量告诉您什么种类会在这里:分支名称!
这是切换到某些现有分支的方法,或者根据某些现有的远程跟踪名称操作创建新的分支。您提供的分支名称是要切换到或自动创建的分支名称。 Git将查找具有该名称的现有分支,如果找不到该分支,将遍历您的所有远程跟踪名称-您的origin/master
,origin/develop
等上-查看是否其中一个 名称可以删除origin/
并成为您要求的名称。
(第二引号行与第一行类似,但是插入了--detach
。第三行与前两行类似,但是不是<branch>
,而是<commit>
。第二个命令行是--detach
,第三个是可选的。<commit>
元变量意味着您可以使用任何可以命名提交的东西,而不仅仅是分支名称。产生分离的HEAD的变体:它们以与切换分支相同的方式签出一次提交,但是它们在此过程中将HEAD砍掉,因此您位于 no 分支上。 {1}}一个命名为提交但不是分支名称的参数,Git仅假定您 meant git checkout
。如果要在使用分支名称时分离,则必须添加{ {1}}。这不是大多数人想要做的,但手册页面还是会介绍它。)
链接的问题及其答案主要是关于使用远程跟踪名称创建新分支。即,他们回答了以下问题:
如果我说
--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
的Git在origin
调用Git,并获取其所有分支和提交的列表。您的Git加载了您尚未使用的所有新提交,并创建或更新了您的所有git fetch
名称,现在您有了origin
。
倒数第二句语法行:
git checkout [
origin/*
[origin/feature-X
]<tree-ish>
显示两个元变量。第一个拼写为--
,它是Git的简写:您可以在此处使用分支名称,提交哈希或可以用来查找树对象的任何东西。 Git有很多 指定提交哈希ID的方法,这旨在涵盖所有这些ID,以及一些您不太可能遇到的更怪异的极端情况。这个第一个元变量是可选的,如果您忽略它,Git将从Git的 index 中检出文件(我们在这里没有详细描述,我不会在此赘述)已经足够长了。
第二个元变量为<pathspec>...
。请注意,这不是 可选!这是Git所说的文件名或带有<tree-ish>
的模式的缩写,或者是其他太长的内容也无法在此处使用。 {1}}部分意味着您可以列出其中多个。这些 pathspecs 命名您要Git在<pathspec>
(您命名的提交,如果您命名的提交)中找到的特定文件或文件。
写时:
*
您的shell(可能是...
)会扩展<tree-ish>
,以匹配当前工作目录中的所有文件。 2 因此,如果您有文件git checkout -- *
和bash
和*
等, Git 看到的是:
README
没有hello
,因此Git在索引中查找名为node_modules
,git checkout -- README hello node_modules ...
,<tree-ish>
等的文件。
如果没有找到 其中之一-并且找不到README
-Git会抱怨:
hello
什么也不做。
如果您改用node_modules
,则shell运行:
node_modules
并且Git将error: pathspec 'node_modules' did not match any file(s) known to git.
视为.
参数。这意味着“当前目录中Git已知的所有文件”,这样就可以完成您想要的操作。您还可以写:
git checkout -- .
使用引号来保护.
(或您正在使用的任何shell)不受<pathspec>
的侵害。然后 Git 将看到git checkout -- '*'
,而 Git 将展开*
到“当前目录中Git已知的所有文件”。但是编写bash
更容易。
2 请注意,在Windows上,CMD.EXE 不会展开*
,而是将其传递给Git,让 Git 展开*
,此错误就永远不会发生!