在.git/refs/remotes/origin中显示__pycache__

xzabzqsa  于 2022-11-27  发布在  Git
关注(0)|答案(2)|浏览(139)

我遇到了一个Azure DevOps管道停止工作的问题,原来是因为有一个“坏了”的ref .git/refs/remotes/origin/feature/__pycache__/app.cpython-310.pyc(显然一开始就不应该存在)。所以我登录到服务器,删除了那个__pycache__目录,管道又开始按预期工作了。
现在,我试着在我的本地上切换分支,我得到了同样的错误:

$ git fetch --all --prune
Fetching origin
error: cannot lock ref 'refs/remotes/origin/feature/__pycache__/app.cpython-310.pyc': unable to resolve reference 'refs/remotes/origin/feature/__pycache__/app.cpython-310.pyc': reference broken
error: could not remove reference refs/remotes/origin/feature/__pycache__/app.cpython-310.pyc

我很困惑这是怎么来的。有人见过吗?这是潜在的一个问题,有人意外地创建了一个新的分支,如git checkout -b feature/__pycache__/app.cpython-310.pyc?其他东西?

dgsult0t

dgsult0t1#

我对这一切是怎么来的感到很困惑。
Git在key-value database中存储名称-分支名称、标记名称、远程跟踪名称等,其中的全名,例如refs/heads/main,是键,值是一个哈希ID。好吧,但这有什么关系呢?嗯,目前这个键-值数据库的实际 * 实现 * 相当低级:

  • 有时,名称-值对由名为.git/packed-refsfile 中的一行(可能添加了一个辅助行)组成;
  • 有时,该值存储在纯文本文件中(未添加辅助行),该文件存储在.git/refs内的 * 目录 * 中,目录名由引用的组成部分组成(省略冗余的refs/)。

有时它什至在两个位置,虽然这意味着“未打包”的文件引用覆盖了打包的文件,因为它被认为是较新的。
因此,这意味着如果一个名为feature/foo的分支存在,那么.git/refs/heads/feature/可能存在,也可能不存在!
好吧,但那又怎样?如果这个目录确实存在,你运行一个Python程序,Python会加载一个名为app.py的文件,并将其字节编译为.pyc文件(并且您使用的是Python3),*python字节编译器 * 可能会 * 将.pyc文件 * 写入名为__pycache__/app.cpython-310.pyc的文件。1 Python将使用此字节-编译的文件来加载和运行东西。
但是一旦 Python 完成了这个操作,Git 就会认为.git/refs/heads/feature/__pycache__/app.cpython-310.pyc是一个有效的ref,因此会有一个名为feature/__pycache__/app.cpython-310.pyc的分支。
远程跟踪名称也会发生同样的情况:唯一的区别是,这个目录的开始是.git/refs/remotes/origin/feature/。在这两种情况下,Git都认为这个名字是有效的,但其值--哈希ID--是假的。这就是为什么无法“锁定”“损坏”的引用。2
那么,真实的的问题是:是什么原因导致运行中的Python程序将__pycache__文件放到Git仓库的子目录中?__pycache__目录的位置应该与加载的.py文件的位置相同,这意味着有人在Git仓库内部的.git/refs/目录中写入了app.py文件,这将是坏的(程序不应该做这样的事情:它们应该在专用临时目录或X1 M18 N1 X或类似目录中生成它们的临时文件)。
除了指向What is pycache?If Python is interpreted, what are .pyc files?,我必须离开这个谜在这一点上未解决,因为我不知道是什么创建了这个app.py文件摆在首位。
1如果打开了字节代码优化,编译后的文件可能以.pyo结尾。2 Python 2将这些文件写入.py文件的旁边,而不是__pycache__目录中。中间的cpython-310部分表示您使用的是CPython 3.10版;在Python的某些(较旧的)版本中不会出现这种版本号插入。
2在这种情况下,“锁定”ref的操作包括创建一个文件,该文件的名称以.lock结尾,其他方面与完整ref文件名相同。该文件将用于保存新值,并且将使用原子rename操作将文件交换到适当位置以更新和解锁ref。所有这些都严重依赖于POSIX文件语义,这是不应该将.git存储库放入云管理软件文件夹的众多原因之一,因为云管理软件文件夹不遵守POSIX文件语义。

izkcnapc

izkcnapc2#

我想我应该更新一个答案:
我有一个验证提交的脚本,测试文件是否编译和做各种各样的事情。这个脚本显然是在.git目录上迭代,并试图编译一个(可能是名字不好的)refs/heads/feature/app.py分支。通过删除__pycache__目录并确保验证脚本跳过.git目录来修复:)

相关问题