先给结论:不要按时间顺序回滚。正确做法是先给那次修改打一个“变更指纹”,再把此后所有变更按“是否读取过它产出的东西”分成依赖、独立、冲突三类;只有依赖项需要一并撤销或重做,独立项保留,冲突项单独判断。凭时间相近就一起回退,是这类操作里最常见的误伤来源。
以下为假设例子,用于说明判断方法,不是真实项目记录。假设某栏目页在四月把标题从“旧表述”改为“新表述”,随后两个月内又发生了三件事:五月给该页加了内链锚文本,六月把它的正文段落整段替换,七月在站点地图里调整了它的优先级。现在决定撤销四月的标题改写。问题不是“标题能不能改回去”,而是五月、六月、七月这三件事里,哪些是依赖四月结果的。
判断依据只有一条:后续变更的输入是否包含四月那次修改的产出。加内链锚文本时,如果锚文本写的是新标题里的词,那它依赖四月结果;如果锚文本本来就是页面原有品牌词,那它独立。替换正文段落时,如果新段落是为了呼应新标题而重写的,那它依赖;如果只是修正一处过时数据,那它独立。站点地图优先级与标题文本无关,属于独立项。把这三项分开之后,回滚范围立刻从“三个月全部动作”缩小到“标题本身加一处锚文本”。
多数人记录变更时写的是动作,比如“修改了标题标签”。这对回滚没用,因为动作本身不携带依赖信息。要记录的是产出物:这次修改向外部输出了哪些可被引用的字符串、结构或标识。标题改写的产出物至少包括:新的标题文本、它出现在页面上的位置、以及任何在别处复制过这段文本的地方。
打指纹的实际动作是:在撤销前,用产出物里的关键词在站内搜索一遍,包括正文、内链锚文本、结构化数据字段和模板变量。搜索结果就是候选依赖清单。这一步的结果直接决定下一步——如果搜索命中为零,可以按独立项处理,直接回滚;如果命中非零,命中的每一处都要单独看它是不是真的读取了这个产出。
证据是后续变更的原文或配置里,能找到四月那次修改产出的字符串或标识。处置方式有两种,取决于依赖是否仍然成立。如果新标题本身仍要保留,那依赖项不用动;如果标题确定要回退,依赖项必须同步改,否则会出现锚文本指向一个已不存在的表述、结构化数据与可见标题不一致这类问题。同步改的动作是:先改回标题,再逐条替换命中位置,最后重新核对一遍命中是否归零。
证据是后续变更的输入来自其他来源,比如数据修正、排版调整、外部合作方提供的素材。这类变更保留,不要因为时间上挨着就一起撤销。保留之后要做一次交叉检查:确认它引用的其他内容没有被这次回滚波及。交叉检查的结果如果发现波及,就把这一项从独立类移到冲突类。
这是最难的一类。它的输入里没有出现产出物字符串,但它的成立前提是旧标题或旧结构仍然存在。典型表现是:一段正文虽然独立撰写,但它的开头承接的是旧标题提出的问题。回滚标题后,这段正文读起来会失去指代对象。处置方式是重写衔接句,而不是撤销整段。判断冲突项的证据是通读一遍:如果去掉标题后某段话的第一句变得没有主语或没有指向,它就是冲突项。
顺序上先回滚依赖项,再回滚被依赖的那次修改,最后处理冲突项。反过来做会短暂产生断链或不一致状态,虽然通常不会造成长期问题,但会让验证阶段难以区分“回滚本身的问题”和“顺序造成的临时现象”。
验证阶段要注意一个反常现象:回滚后某些页面的抓取量或展示量出现波动,不能单独作为回滚正确或错误的证据。季节变化、搜索需求本身的涨落、数据采集口径的调整,都会产生类似波动。合理的做法是把回滚前后的数据与同期未改动页面做对照,看差异是否只出现在改动过的页面上。如果对照页面也同向变化,那这次波动更可能来自外部因素,下一步应该继续观察而不是再次改动。
如果依赖项数量多、分布散,逐条同步的成本高于保留成本,另一个成立的选择是不回滚,改为隔离:保留新标题,但把仍然引用旧表述的地方统一到新表述上。这个选择成立的条件是,新表述本身没有事实性错误,只是不如旧表述合适。隔离动作的结果是依赖清单从“需要撤销”变成“需要统一”,后续维护只需要盯住新表述一个版本。反过来,如果新表述存在事实错误或与合作方约定不符,隔离就不成立,必须走回滚路径。
两种选择的分界不在改动大小,而在产出物是否还值得被继续引用。值得引用就统一,不值得引用就回滚,并把所有读取过它的后续变更一并处理。做完这一步再去看数据,才不会把顺序问题和内容问题混在一起判断。