恢复与 reflog
Git 很少真的丢东西。难的是把它重新找回来。
Reflog
HEAD 的每一次移动——以及每个分支的每一次移动——连同造成它的原因:检出、重置、变基、
修补、一次强制获取。从任何一条过去的记录,你都可以检出它、从它建分支,或者
硬重置到它。

这就是那个「我刚刚重置错了分支」按钮。
WIP 快照
未提交的工作是 reflog 唯一救不了的东西,所以 Gitcito 会为它拍快照:把整个工作区——
已修改、已暂存以及未跟踪的文件——通过一个一次性的索引提交出来,钉在
refs/gitcito/wip 下面。你真正的索引和贮藏列表都不会被碰到。

三种情形会拍下一张:
| 触发方式 | 何时 |
|---|---|
| 守护 | 在破坏性操作——丢弃、清理、硬重置、从某个提交恢复——之前自动拍下。默认开启;可在快照对话框里切换。 |
| 定时器 | 仓库打开期间,每 5 / 15 / 30 分钟一次。 |
| 手动 | 立即快照按钮。 |
真正要紧的是守护:工作往往就是在一次不小心的丢弃之后的那一秒永远丢失的。开着守护, 那个状态就是一张快照——打开列表,点恢复,松一口气。
选中一张快照,就能看到它捕获的文件,预览任何文件的改动,并恢复单个文件或整棵树。 恢复会把文件从快照里复制出来,盖到当前的副本上——恢复之前会先拍一张守护快照,所以 恢复本身也可以撤销。
值得知道的限制。 定时器或守护触发时若没有发现任何新内容,就什么也不记录。恢复会
覆盖并重建文件,但绝不会删除你在拍快照之后新建的文件。被忽略的文件不会被捕获。快照是
本地的隐藏引用:从不推送,不怕 git gc,保留最新的 50 张。
引导式二分查找
把提交标为好或坏,看着范围一步步收窄,最后落在第一个坏提交上。Gitcito 会跟踪还剩多少 步,所以你知道自己离答案是两个问题还是十个问题。

让一条命令来判定
范围一旦定下,让一条命令来判定就把整个搜索交给 git bisect run。Git 会检出每一个
候选提交,运行你的命令,然后读它的退出码:
| 退出码 | 含义 |
|---|---|
0 |
好——问题不在这里 |
125 |
这个测不了;跳过它 |
| 其他任何值 | 坏 |
一套测试用例本来就说这门语言,所以 npm test 通常就是全部答案。Gitcito 会把本项目
自己的脚本作为一键填入的选项提供出来,在运行时把输出流式显示出来,然后在你一个问题都
不用回答的情况下落到第一个坏提交上。

要留神的地方。 这条命令会在 git 测试的每一个提交上运行,所以一条会部署、发布, 或者往仓库外面写东西的命令,会把那件事干上好几遍。让它只做读取和报告。停止会杀掉 这次运行但保留会话,这样你可以继续手动标记;中止则彻底结束这次二分查找。
一条因为无关原因而失败的命令——比方说历史上那个时点缺少某个依赖——会把一个好提交标成
坏的,把搜索引到错误的地方去。在包装脚本里以 125 退出,就是 git 给出的解法。
残留的锁文件
git 会在它将要写入的东西旁边放一个 .lock 文件,写完就删掉。要是某个进程握着锁死
了——编辑器崩溃、git commit 期间被关掉的终端、修剪远端引用时被杀掉的 fetch——锁
就留在那儿,从此每一次写入都以同一行报错收场:
error: could not delete references: cannot lock ref 'refs/remotes/origin/x':
Unable to create '…/refs/remotes/origin/x.lock': File exists.
仓库并没有坏。只是有个文件挡道。
Gitcito 会先重试几次,因为被正在运行的 git 握着的锁通常几毫秒就放开了。要是没 放开,这次失败会弹出一个对话框,而不是一堵文字墙:磁盘上还留着的每个锁、各自多久 以前留下的,以及一个按钮——删掉它们并重跑刚才失败的操作。
年龄就是全部论据。 不到 30 秒的锁,多半属于还在干活的 git,Gitcito 拒绝删除它 ——它转而建议等一下再试。更老的会被列出来供你删除,从最老的排起,对话框也直白地说 明同意之前该确认什么:此刻没有编辑器、终端或别的 Git 客户端正在这个仓库里工作。在 活跃写入底下抽掉锁,索引就是这么被撕坏的。
扫描覆盖仓库自己的 git 目录和它的公共目录,所以关联工作树的锁也找得到。子模块会跳 过——它们属于另一个仓库,打开那个仓库来清理即可。
撤销 / 重做
大多数操作都会往撤销栈里压一条记录,所以在 git 允许的范围内,⌘Z 会回退最近 的那一次。