英文:
Why does git not ignore this particular __pycache__ directory?
问题
信息
我今天提交了一个失败的提交:
git commit backend/projects/* -m "我的消息"
error: pathspec 'backend/projects/__pycache__' did not match any file(s) known to git
该提交包括对子文件夹中的文件的更改,这些子文件夹还包括它们自己的__pycache__
目录,即我有一个类似这样的目录结构:
backend/projects/__pycache__
backend/projects/my_altered_file_1.py
backend/projects/myfolder/__pycache__
backend/projects/myfolder/my_altered_file_2.py
在我的.gitignore
文件中,我有:
# Python字节编译/优化/DLL文件
__pycache__/
*.py[cod]
*$py.class
并且执行 ls -al backend/projects/__pycache__
显示该目录中只有.pyc
文件,所有这些文件都匹配.gitignore
中的*.py[cod]
语句。
执行:
git ls-files | xargs -n 1 dirname | uniq
给我一个包含git控制文件的目录列表,其中不包括有问题的__pycache__
目录,因此我知道其中没有意外地添加到git控制的内容(这会覆盖.gitignore
)。
问题
为什么提交失败,当backend/projects/__pycache__
的内容完全在.gitignore
中被忽略?
为什么在仅删除backend/projects/__pycache__
后重试后,提交成功,即使在那里还有另一个__pycache__
目录,按预期被忽略(如果它会在一个上失败,为什么不会在两个上失败)?
英文:
INFORMATION
I made a commit today that failed:
git commit backend/projects/* -m "My message"
error: pathspec 'backend/projects/__pycache__' did not match any file(s) known to git
The commit included changes to files in subfolders that ALSO include their own __pycache__
directories, ie. I have a directory structure that looks like this:
backend/projects/__pycache__
backend/projects/my_altered_file_1.py
backend/projects/myfolder/__pycache__
backend/projects/myfolder/my_altered_file_2.py
In my .gitignore
I have:
# Python byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
And doing ls -al backend/projects/__pycache__
shows nothing but .pyc
files in that directory, all of which match the *.py[cod]
statement in .gitignore
.
Doing:
git ls-files | xargs -n 1 dirname | uniq
gives me a list of the directories containing git-controlled files, which does NOT include the offending __pycache__
directory, so I know nothing in there has accidentally been added to git control previously (which would override the .gitignore
).
QUESTION(S)
Why did the commit fail, when the contents of backend/projects/__pycache
are completely .gitignore
d??
And why did retrying after deleting JUST the backend/projects/__pycache__
work fine, even though there's another __pycache__
directory in there which was ignored as expected (if it's going to fail on one, why wouldn't it fail on both)?
答案1
得分: 2
git help commit
中有一个重要细节(重点是我的):
描述
[...]
3. 通过将文件列为提交命令的参数(不使用 --interactive 或 --patch 开关),在这种情况下,提交将忽略暂存区中的更改,而是记录列出文件的当前内容(这些文件必须已知于 Git);
我不知道它被实现成这样的确切原因,我猜想,由于指定一系列的 <path>...
会使提交包括确切这些更改(忽略其他可能在暂存区的文件),所以当命令行上列出的文件或目录之一实际上不在您的提交中时,出现错误是有道理的。
正如 Richard Smith 评论所述:
当您键入 git commit backend/projects/* -m "My message"
时,扩展是由您的 shell 执行的,因此 git 实际上接收到一个命令行,其中说:
git commit backend/projects/mymod1 backend/projects/mymod2 \
backend/projects/myfile.py backend/projects/__pycache__ ...
修复方法只需命名目录:
git commit backend/projects/ -m "My message"
请注意,如果引用您的 glob 字符串,扩展将由 git 执行:
git commit "backend/projects/*" -m "My message"
这会产生其他影响:
git
将此 glob 扩展为该目录下Git 已知的文件列表,因此 backend/projects/
下的新文件将不包括在您的提交中。
然而,我建议切换到传统的 git add ...; git commit
工作流,主要是因为它允许您:
git add ...
<审查要提交的内容>
git commit
英文:
There is a fine print in git help commit
(emphasis mine):
> DESCRIPTION
> [...]
> 3. by listing files as arguments to the commit command (without --interactive or --patch switch), in which case the commit will ignore changes staged in the index, and instead record the current content of the listed files (which must already be known to Git);
I don't know the exact reason why it is implemented that way, I guess that, since specifying a sequence of <path>...
makes the commit include exactly these changes (ignoring the other possibly staged files), it makes sense to have an error when one of the files or directories listed on the command line will actually not be part of your commit.
As Richard Smith commented:
when you type git commit backend/projects/* -m "My message"
, the expansion is made by your shell, so git actually receives a command line which says :
git commit backend/projects/mymod1 backend/projects/mymod2 \
backend/projects/myfile.py backend/projects/__pycache__ ...
The fix is to simply name the directory:
git commit backend/projects/ -m "My message"
Note that if you quote your glob string, the expansion will be done by git :
git commit "backend/projects/*" -m "My message"
this has however other consequences :
git
will expand this glob to the list of files known to git under that directory, so new files under backend/projects/
would not be part of your commit.
I would recommend, however, to switch to a classical git add ...; git commit
workflow, mainly because it allows you to :
git add ...
<review what you are about to commit>
git commit
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论