| 中文文章 | English article |
这个实验只在新建的临时 Git 仓库中执行一次 reset --hard、reflog 过期和 gc --prune=now。初始状态包含两个没有 branch 名的 commit:
main -> baseline
recoverable commit
no ref reaches it
still listed by HEAD reflog
expired commit
no ref reaches it
still listed by HEAD reflog
运行:
lab_path=$(bash setup.sh)
# 先观察还受 reflog 保护的状态
git -C "$lab_path" reflog show --oneline HEAD
git -C "$lab_path" fsck --no-reflogs --unreachable
# verify.sh 会恢复第一个 commit,并故意过期和清理第二个 commit
bash verify.sh "$lab_path"
bash cleanup.sh "$lab_path"
setup.sh 的标准输出只有临时仓库路径。它禁用系统和全局 Git 配置,为仓库设置本地身份、关闭提交和标签签名,并把 hooks 路径设为空目录。reset --hard、reflog expire 和 gc --prune=now 全部只作用于这个带实验标记的临时库。
verify.sh 会先用对象 ID、refs、HEAD reflog 和 git fsck --no-reflogs --unreachable 检查两个 commit 仍在对象库中且没有 ref 能到达它们。随后它创建 recovered branch 找回第一个 commit。最后它显式过期所有 reflog,并运行 git gc --prune=now,断言第二个 commit 已经无法用 git cat-file 解析。任何断言失败都会以非零状态退出。
运行完整自测:
bash test.sh
verify.sh 会不可逆地销毁第二个临时 commit。若要重新查看受 reflog 保护的中间状态,请重新运行 setup.sh 创建新实验库。
cleanup.sh 只删除带有本实验标记的目录,并拒绝仓库根目录、用户主目录和根目录。
This lab performs one reset --hard, reflog expiration, and gc --prune=now only inside a newly created temporary Git repository. Its initial state has two commits without a branch name:
main -> baseline
recoverable commit
no ref reaches it
still listed by HEAD reflog
expired commit
no ref reaches it
still listed by HEAD reflog
Run:
lab_path=$(bash setup.sh)
# Inspect the state that is still protected by reflog first.
git -C "$lab_path" reflog show --oneline HEAD
git -C "$lab_path" fsck --no-reflogs --unreachable
# verify.sh recovers the first commit and intentionally expires and prunes the second.
bash verify.sh "$lab_path"
bash cleanup.sh "$lab_path"
setup.sh prints only the temporary-repository path. It disables system and global Git configuration, sets a local identity, disables commit and tag signing, and points hooks to an empty directory. reset --hard, reflog expire, and gc --prune=now all operate only on this marked temporary repository.
verify.sh first asserts through object IDs, refs, the HEAD reflog, and git fsck --no-reflogs --unreachable that both commits still exist in the object database with no ref reaching them. It then creates a recovered branch for the first commit. Finally it explicitly expires every reflog and runs git gc --prune=now, asserting that the second commit no longer resolves through git cat-file. Any failed assertion exits nonzero.
Run the full self-test:
bash test.sh
verify.sh irreversibly destroys the second temporary commit. To inspect the reflog-protected intermediate state again, run setup.sh to create a new lab repository.
cleanup.sh removes only a directory marked for this lab and refuses the repository root, the user home directory, and the filesystem root.