为什么git不会忽略这个特定的__pycache__目录?

huangapple go评论57阅读模式
英文:

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 .gitignored??

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 &lt;path&gt;... 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 &quot;My message&quot;, 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 &quot;My message&quot;

Note that if you quote your glob string, the expansion will be done by git :

git commit &quot;backend/projects/*&quot; -m &quot;My message&quot;

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 ...
&lt;review what you are about to commit&gt;
git commit

huangapple
  • 本文由 发表于 2023年6月8日 15:44:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76429643.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定