DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

Docker Git 上下文构建报 /.git not found

Git 上下文默认不保留 .git,忽略规则例外不能恢复它。用预定义参数保留构建所需仓库信息,或明确选择路径上下文,并限制最终产物。

同一份 Dockerfile 在本地目录构建时能读取 .git,改为 Git URL 或 GitHub Actions 的默认 Git 上下文后,COPY .git 却失败:

failed to compute cache key: "/.git" not found: not found

即使在 .dockerignore 中给 .git 加了例外,目录也可能仍然不存在。使用 Git 上下文时,BuildKit 默认不保留检出的 .git 目录;忽略规则不能恢复已经被移除的输入。

下文限定为 BuildKit 的 Git 上下文。不适用于把宿主机目录作为 . 传入的构建,也不处理另一构建阶段下载后误带入最终镜像的仓库文件。

先确认真正传给构建器的上下文

命令最后的上下文参数为 Git 仓库 URL 时,是 Git 上下文;以本地目录为参数时,是路径上下文。-f Dockerfile 只选择构建定义,不能据此判断源码来自哪里。

docker/build-push-action 默认使用 Git 上下文,通常由触发工作流的 Git 引用决定。前面添加了 checkout 步骤,并不自动改变构建动作使用的上下文。应查看构建动作的 context 输入和实际日志,而不是只看工作区里能否列出 .git。

如果构建仍从远端 Git 引用取文件,前置步骤在工作区修改的 .dockerignore 或源码也不会成为这个上下文的输入。需要这些修改时,应明确选择路径上下文;这是输入来源的选择,不能只靠调整 COPY 路径修复。

Git 上下文确实需要仓库信息时,明确保留它

在现有构建调用中增加 BUILDKIT_CONTEXT_KEEP_GIT_DIR=1。下面的仓库地址、引用和镜像标签都是占位示例,需替换为可信的实际项目:

docker buildx build \
  --build-arg BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 \
  --progress=plain \
  --load \
  -t myapp:git-check \
  'https://github.com/example/example-app.git#main'

示例用 --load 将单平台结果装入本地镜像库;已有多平台发布流程应保留原输出方式,不要为这一项配置改成单平台。项目原有 Dockerfile 路径、其他构建参数和平台选择也应保持一致。

这是 BuildKit 预定义的构建参数,不是让应用在运行时读取的环境变量。现有 GitHub Actions 构建步骤可在 with 下的 build-args 列表中加入:

build-args: |
  BUILDKIT_CONTEXT_KEEP_GIT_DIR=1

这段是合入现有步骤的配置片段,不是完整工作流。已有其他参数时追加一行,不能覆盖原列表。不要为了获取提交号,将仓库访问令牌改成普通 build argument。

保留 .git 后仍失败时,再核对上下文子目录、Dockerfile 实际工作目录以及适用的 .dockerignore 规则。如果构建上下文选在仓库的子目录,不要假设仓库根目录的一切内容都在当前输入范围内。也不要为了看到 .git,把整个忽略文件删掉。

构建需要 Git,不代表最终镜像也要携带 Git

若只是把提交号写入构建产物,可以在构建阶段使用仓库信息,再只复制发布产物。以下是说明这个边界的完整 Dockerfile 示例,要求可信 Git 上下文且没有把所需文件排除:

# syntax=docker/dockerfile:1
FROM alpine:3.22 AS revision
RUN apk add --no-cache git
WORKDIR /src
RUN --mount=target=. \
    mkdir -p /out \
    && git rev-parse HEAD > /out/revision.txt

FROM scratch
COPY --from=revision /out/revision.txt /revision.txt

将它配合前面的保留参数使用。RUN --mount=target=. 在该指令中提供上下文;输出写到挂载之外的 /out,最终阶段只复制文本文件。这个示例镜像是文件产物,不包含可启动的应用,不能用运行成功来验收它。

实际项目应保留自己的构建命令、运行基础镜像与入口,只沿用输入和产物分离的做法。不要把 .git 整体复制到最终镜像,再用后续层删除来宣称历史内容已经消失。

需要工作区文件时,切换路径上下文

如果构建必须使用 checkout 后生成或修改的文件,在现有工作流中保留正确的 checkout 步骤,并显式设置构建动作:

context: .

此时才应按工作区实际文件和 .dockerignore 核对 .git 是否可见。BUILDKIT_CONTEXT_KEEP_GIT_DIR 不能替路径上下文下载缺失的 Git 数据,也不能让被忽略的文件自动出现。

另外,保留 .git 不等于拥有完整历史。Git 上下文采用浅克隆,依赖完整历史或标签的版本计算可能仍有不同结果。这里只解决目录被默认移除;不要用 git rev-parse HEAD 成功来证明所有 git describe、历史遍历或标签规则都已满足。

验收提交号与最终内容

修改前保存原工作流、Dockerfile 与可回退镜像引用。先在允许构建的隔离环境核对 .git 相关步骤不再报缺失,并确认产出的提交号对应实际选定的 Git 引用。移动分支会继续变化,要求可追溯构建时应按项目策略使用确定的提交。

同时检查最终产物没有多出仓库历史或不需要的配置文件。如果只是为了提交号而引入了整套仓库数据,缩小复制范围后再交付。恢复原参数或上下文设置时,也要恢复配套构建定义;已经推送出去的旧镜像不会因工作流回退而自动删除。