恢复与保护

恢复与 reflog

Git 很少真的丢东西。难的是把它重新找回来。

Reflog

HEAD 的每一次移动——以及每个分支的每一次移动——连同造成它的原因:检出、重置、变基、 修补、一次强制获取。从任何一条过去的记录,你都可以检出它、从它建分支,或者 硬重置到它。

reflog 查看器

这就是那个「我刚刚重置错了分支」按钮。

WIP 快照

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

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 会回退最近 的那一次。

另请参阅: 自那以后改了什么 · 贮藏

在 GitHub 上改进这份翻译