PAYATHON 2026

如何安全查看其他用户不可信 Git 仓库的提交历史和 reflog?

数据阿明

可以通过 Git 传输协议获取提交,再在自己控制的新仓库中查看历史。如果环境需要较强的账户隔离,应让源仓库的 git-upload-pack 在另一个非特权账户下运行。源仓库的 reflog 不会随普通 clone 或 fetch 传输,需要另行读取或导出。

为什么不能直接添加 safe.directory?

safe.directory 表示你接受对该仓库的信任例外。它不会清理 .git/config、禁用所有 hooks,也不会把 Git 变成只读沙箱。即使命令主要用于查看信息,其行为也可能受到仓库配置的影响。

Git 官方安全说明建议,先使用 git clone --no-local 从不可信的本地仓库取得新副本,再检查其中的提交。新副本不会继承源仓库的配置和 hooks。Git 安全说明

如何获取可以审查的副本?

在自己控制的目录中执行以下命令,目标目录应尚不存在:

git clone --no-local --no-checkout \
  /home/somebodyelse/gitrepo \
  "$HOME/review-gitrepo"

git --no-pager -C "$HOME/review-gitrepo" \
  log --all --oneline --decorate

--no-local 强制使用正常的 Git 传输机制,避免本地 clone 默认采用的直接复制和硬链接优化。--no-checkout 暂不检出工作树,适合先检查提交。不要用 --shared 或直接复制整个 .git 目录来替代这一步。git-clone 文档

不过,这条普通本地 clone 命令通常仍会以你的身份启动源端 git-upload-pack。它会限制使用危险配置和 hooks,但 Git 官方也明确指出,攻击面仍然存在。因此,单用 --no-local 无法满足所有严格的账户隔离要求。Git 安全说明

如果管理员已授权你通过 sudo 以源仓库所属的普通账户运行 git-upload-pack,可以改用:

git clone --no-local --no-checkout \
  --upload-pack='sudo -u somebodyelse -- git-upload-pack' \
  /home/somebodyelse/gitrepo \
  "$HOME/review-gitrepo"

这里假定 somebodyelse 是源仓库所属的非特权账户,且系统能够找到可信的 git-upload-pack 可执行文件。不要以 root 身份提供源仓库。没有相应 sudo 权限时,可以由管理员配置 SSH 或 Git 服务,让源端进程在隔离账户下运行;添加信任例外无法达到同样的隔离效果。git-upload-pack 安全说明

如何确定对方当前检出的分支或 commit?

可以查询源仓库公开的 HEAD,并沿用上述账户隔离方式:

git ls-remote --symref \
  --upload-pack='sudo -u somebodyelse -- git-upload-pack' \
  /home/somebodyelse/gitrepo HEAD

如果输出包含 ref: refs/heads/feature HEAD,说明查询时 HEAD 指向 feature 分支;同时返回的对象 ID 表示它指向的提交。若 HEAD 处于 detached 状态,通常只会返回对象 ID。git-ls-remote 文档

这反映的是所访问仓库或 worktree 在查询时的状态。仓库之后可能发生变化,服务端也可能因配置而隐藏部分引用;查询结果无法说明工作树中未提交的改动。

如何把分支提交获取到自己的项目中?

拿到副本后,可以从自己控制的审查仓库获取分支引用。以下假定自己的项目位于 $HOME/my-project:

git -C "$HOME/my-project" fetch "$HOME/review-gitrepo" \
  'refs/remotes/origin/*:refs/remotes/colleague/*'

随后检查某个分支,例如将 feature 替换为实际分支名:

git --no-pager -C "$HOME/my-project" \
  log --oneline HEAD..refs/remotes/colleague/feature

git --no-pager -C "$HOME/my-project" \
  diff --no-ext-diff --no-textconv \
  HEAD refs/remotes/colleague/feature --

这里用 fetch 获取提交,供人工审查。若对方处于 detached HEAD,且该提交未被任何分支包含,还需要单独获取审查副本的 HEAD:

git -C "$HOME/my-project" fetch "$HOME/review-gitrepo" \
  HEAD:refs/remotes/colleague/checked-out

如何查看源仓库的 reflog?

reflog 是仓库本地引用变更的记录。clone 后运行 git reflog,看到的是新副本自己的记录,不能用它还原对方分支切换、reset 或 rebase 的过程。git-reflog 文档

如果具有文件读取权限,源仓库使用传统文件式引用存储,且 .git 是普通目录,可以把日志当作数据读取:

sed -n 'l' /home/somebodyelse/gitrepo/.git/HEAD
sed -n 'l' /home/somebodyelse/gitrepo/.git/logs/HEAD

这里的 sed 不会执行仓库配置或 hooks,显示时还会转义控制字符。logs/HEAD 包含该工作树的 HEAD 变更记录;分支自身的日志通常位于 logs/refs/heads/ 下。仓库布局说明

这些路径不适用于所有仓库。linked worktree、.git 指向文件、reftable 存储等情况需要按实际布局处理。通用做法是让仓库所属账户或隔离进程执行 git reflog show --all,再导出文本供你查看。reflog 可能已经过期或被修改,不能当作不可篡改的审计记录;其中提及的旧提交也不一定能通过普通 fetch 获取。

备注:内容仅供参考。