小叶用AI做了一个查询校园自习地点的网页。同学选择一栋楼,页面列出符合条件的地点和开放时间;没有匹配地点时,会提示换一个条件。第一版外观普通,这几项行为已经检查过,小叶准备继续改善手机上的显示。

AI很快把列表换成了卡片。小叶打开页面,看到卡片排列整齐,就接着请它更正一处地点的关闭时间。原来的资料写晚上九点,现在得到的新资料明确为晚上十点。等两项修改都做完,小叶再次选择一个没有自习地点的楼栋,页面却空在那里,没有任何提示。

他记得以前有这句话,却说不清在哪一轮修改里丢了。项目旁边还有“查询页最终版”“查询页最终版2”和“查询页新”,其中一份能显示提示,关闭时间却还是九点。现在的困难不是完全没有东西可用,而是不知道哪些部分可以放心保留、哪些应该退回,以及怎样把它们重新组成当前需要的网页。

这一讲讨论的版本管理,就是对文件随时间发生的变化进行记录、比较和组织。它让小叶可以指明“我要查看卡片改版之前的页面”,也可以判断“这次只撤掉卡片改版,后来更正的开放时间仍要保留”。AI修改得越快,辨认这些状态的作用越明显:一次对话里看起来连续的“继续优化”,落在文件里可能已经是几种不同的方案。

以下地点、时间和项目经历均为虚构教学案例。查询页只在小叶本地制作和试用,开放时间不对应真实校园。文中的Git小实验只操作少量文本文件,用来观察版本记录的行为,不是已经实现并测试了整个查询系统。

一、先能指出“哪一个状态”,才谈得上恢复

假如小叶把当前目录完整复制一份,注明“手机卡片改版前”,它确实可以帮助他找回当时的文件。这个办法在初次尝试时就有价值:至少下一次修改失败,不必只靠记忆让AI重新写。问题通常出现在副本越来越多以后。哪些文件后来又被补改过,哪个副本包含时间更正,目录名与内容是否还相符,都需要额外辨认。

版本控制工具把这类记录系统地组织起来。我们用Git作具体例子:把需要管理的项目放进一个仓库,再通过一次次提交记录文件状态。仓库既包含版本历史,也与当前操作的文件相联系。提交可以理解为给纳入记录的那套文件拍一张可查找的快照,同时记录说明及其与先前提交的关系。Pro Git:版本控制的用途介绍了恢复和比较历史文件的基本作用。

快照这个比喻有一个需要落到实物上的地方:它不是只记住屏幕上显示的页面,而是记录被纳入提交的文件内容。页面代码、地点数据、显示配置可能一起构成一个能工作的版本。只保存网页截图,可以回忆外观;只保存AI说“已经修复”的对话,可以知道它声称做了什么;两者都不能代替当时实际运行的那套文件。

为了看清开篇的变化,先假定小叶已经分别记录了下面三个提交。V0、V1、V2是本讲为了阅读方便取的教学标签,实际Git提交有自己的标识。

教学版本 这次发生的变化 页面中的无匹配提示 那处地点的关闭时间
V0 记录已经检查的基础查询页 有 21:00
V1 改用手机卡片布局,误删提示 无 21:00
V2 更正地点数据,未修改页面代码 无 22:00

V2中的时间是目前已经确认应采用的资料。小叶如果把全部文件换回V0,提示会回来,时间也会一起退回旧值。这里恢复失败的原因并不是旧版不能用,而是“以前可用”与“现在全部适用”不是同一件事。版本管理先提供准确的历史材料,采用哪些历史材料仍要依据当前需求。

提交标识帮助我们避免凭“最新”“上一个”猜测对象。相同标识应指向同一个提交;分支名则可能随着后续提交继续前进。小叶记下“今天看过main”仍可能不够,因为明天main已经包含新修改。需要复查某次结果时,具体提交标识比一个不断移动的名字更能说明检查对象。

记录版本也不要求每次都证明整个项目完美。小叶可以保存一个尚未做完的试验,以便稍后继续。但“已经记录”“已检查某几项行为”“可以供同学使用”是三种不同状态。把试验提交写成“卡片布局尝试,空结果提示待补”,比把它叫“最终稳定版”更能帮助后来的人正确使用这份记录。

二、一个能恢复的版本,究竟应该包含什么

小叶的查询页至少有两类文件。一类决定页面怎样筛选和显示;另一类提供地点与开放时间。假设页面代码约定读取数据里的close_time字段,地点数据也使用这个字段名,两者配合后才能把关闭时间显示出来。只有页面代码的历史,未必足以重新得到原先的查询结果。

因此,确定版本范围时,应从“怎样重新得到这项行为”反推需要的材料。页面代码、与它配套的数据格式、必要配置、用于检查的示例,通常都值得一起考虑。若页面运行时会调用AI解释查询结果,提示和模型配置也是影响当前行为的材料。若AI只是帮助写过页面代码,保存生成时的提示主要便于日后复查过程和继续修改;已有代码能否运行,要看代码实际依赖什么。材料放在聊天里还是文件里,也关系到以后能否找到与这次工作对应的那份内容。

这并不要求把电脑上的一切都塞进同一个仓库。查询页运行后生成的临时缓存,重新运行就能产生;本机安装的软件本体,也不适合靠不停复制进项目来管理。更有帮助的是区分:哪些是自己维护的源材料,哪些是能够重建的产物,哪些由外部系统提供。对外部依赖,保存可用的版本说明与取得方式;对不可随意复制的数据,保留合适的引用或受控副本安排。

Git会区分已经纳入跟踪的文件和未跟踪文件。新建一份地点表后,它出现在目录里,不表示已经进入历史。小叶本机能够读取它,所以页面看似正常;同学只取到提交里的文件,缺少这份表,运行结果就可能不同。“我这台电脑能打开”因而不能独自证明仓库中的版本已经完整。

另有一些文件会被设置为忽略,例如缓存目录。忽略规则常写在.gitignore文件里,帮助日常操作避开不准备纳入版本的材料。但忽略规则不负责删除已经进入历史的内容,已经被跟踪的文件也不会因为新加一条忽略规则而自动停止跟踪。这是Git官方文档明确区分的范围。Git:gitignore

把这个范围放回小叶的工作:假如正式地点表从一开始就未纳入跟踪,又被误当成临时输出忽略了,代码虽然每次都有提交,时间更正仍可能只留在电脑上。恢复时找不到十点这个值,是因为这份更正没有进入所依赖的版本记录。应该调整记录范围,或建立明确的数据版本安排。

还有一种情况值得分开理解。网页实际连接着一份持续变化的在线地点数据库,代码仓库只存连接方式。提交代码只能说明当时的程序,不能自动保存数据库在那一刻的全部内容。此时“恢复程序版本”和“恢复数据状态”需要分别安排。先说清正在恢复哪个对象,才能判断手头的历史是否够用。

三、保存文件、准备提交与真正提交,发生在不同位置

使用编辑器时按下保存,文件进入磁盘,小叶重新打开它还能看到修改。Git则还要回答另一个问题:下一次历史记录里准备放入什么。为此,它在当前文件与已有历史之间提供了暂存区。暂存区可以理解为下一次提交的内容准备区;将文件暂存,就是把此时选定的内容放到这份准备中。Pro Git:记录文件变化

这三个位置分别是工作目录、暂存区和已经提交的历史。工作目录是小叶眼下编辑、运行时使用的文件;暂存区决定普通提交将记录的内容;提交完成后,这套被选定的状态进入历史。理解它们,主要是为了知道自己看见、检查和保存的是否为同一份内容。

做一个很小的文字实验。另开一个教学仓库,用display.txt中的一行文字代替真正的页面提示。已有提交写着No matching places,意思是没有匹配地点。小叶先把它改为No places并暂存;随后觉得还应给用户一个行动建议,又在编辑器里把同一行改成Try another filter,意思是换一个筛选条件试试,但这次没有重新暂存。

此刻三个位置的内容如下。这是同一文件在同一时刻的三种状态,不是三个不同文件。

位置 已经处在这个位置的提示文字
上一次提交 No matching places
暂存区 No places
当前工作目录 Try another filter

如果这时进行普通提交,进入历史的是暂存区中的No places。当前文件里的第三种文字仍留在工作目录,作为尚未提交的后续修改。暂存不是持续同步开关:小叶后来又改过文件,先前放入暂存区的内容不会自动跟着变化。

这也解释了一类很让人困惑的现象。小叶刚刚运行页面,看到自己满意的新提示,然后提交并把提交标识交给同学;同学取得对应版本,却只看到较早的提示。可能两人的运行方式完全相同,差别只在于小叶检查的是工作目录,实际提交的仍是更早暂存的内容。对照这三个位置,比反复让AI“检查为什么我的电脑正常”更快缩小问题。

在命令行中,下面这些操作分别用于查看状态、比较未暂存修改、比较待提交修改。它们都是查看操作,不会把某种内容自动变成正确版本。

可复制模板
git status --short
git diff -- display.txt
git diff --staged -- display.txt

在刚才的实验里,普通diff看到的是“没有地点”变成“换个条件试试”;带--staged的比较看到的是原提示变成较短提示。两处差异都真实,只是比较的两端不同。官方命令说明也把工作目录对暂存区、暂存区对提交分别列出。Git:diff的比较对象

小叶若决定记录第三种文字,应重新暂存这份文件,再检查待提交差异,最后提交。图形界面通常也能完成选择变更、查看差异和提交这些动作。先看懂文件怎样进入记录,比记住某个按钮的位置更重要;界面换了,这个判断仍然适用。

独立本地仓库中的实际实验得到了同样结果:先暂存第二种文字、再保存第三种文字,随后普通提交记录了第二种,工作文件仍保留第三种。两份内容各自在哪里,可以通过状态和差异查看清楚。

四、差异让“AI改好了”变成可以检查的具体变化

差异比较把两个状态之间增加、删除或改写的内容显示出来。小叶提出“把列表改成适合手机的卡片”,AI报告完成,这只表达了目标及其自述。打开差异后,他才能进一步看到:哪些文件变了,旧的空结果处理是否被删掉,数据读取方式有没有一起变化。

例如,页面原来在查询结果为空时显示提示,改版后只剩“把每个结果画成卡片”的部分。正常有地点时,两种页面都能显示内容;当结果为空,没有卡片可画,页面就空白了。差异指出被删的处理,已有失败场景说明这项删除会造成什么,两种证据配合后才能判断是否应该恢复。

逐行差异也有它不直接回答的问题。一次修改增加了很多行,并不一定风险更大;统一整理缩进会使差异看起来很长,却未必改变行为。相反,把一个条件判断中的比较方式改掉,可能只有一处文字变化,却会影响整类结果。小叶阅读差异时,需要追问变化怎样影响功能,而不是单按行数决定是否接受。

如果AI同时重新排版整个文件并改动查询逻辑,真正影响行为的几处变化会被许多格式变化包围。可以把纯格式整理与行为修改分开,让每次比较更容易围绕一个问题展开。这项安排的价值在于减少辨认成本,而不是规定项目永远不能进行大改版。

比较之前,还要说明自己想查哪段变化。V0对V1可以帮助小叶查卡片改版动了什么;V1对V2主要显示地点资料更正;V0对V2显示两轮累计变化。如果他想定位提示为何消失,却只看后一轮时间更正,比较本身即使完全准确,也没有包含造成问题的那一段。

我们常把“看了差异”说得很简单,实际有效的信息是“看了哪两个状态之间、哪些文件的差异”。尤其让AI帮忙审查时,给它明确的起点和终点,才能避免它只解释当前代码,而没有检查你真正关心的修改。它给出的判断仍需要落到具体文件和行为上,小叶可以据此继续核对。

差异也能帮助保留有价值的新内容。发现无匹配提示丢失以后,小叶如果只想着“退回之前”,很容易连十点关闭的资料一起换掉。看清V1和V2分别改了什么,才知道问题与后来的更正并没有必须捆在一起。这为下一步选择恢复办法提供了材料。

五、一次提交尽量围绕一件说得清的事

既然可以选择哪些变化进入一次提交,小叶就需要决定怎样划分。较实用的标准是:这些变化是否共同完成一个能够解释、检查和必要时撤销的意图。一次提交可以包含多个文件,也可以只有一处修改;关键是它们为什么应该一起被理解。

地点数据增加一个新字段,页面增加读取和显示它的功能,这两部分可以共同构成一次变化。要把这项新功能作为完成结果提供,两部分需要配套进入版本;只先加好数据字段,旧页面可能仍照常工作,却还没有新增的显示能力。相反,卡片布局和与布局无关的关闭时间更正可以分开,之后出现问题时,读历史的人就能分别判断两件事。

这种围绕一个完整意图的提交,有时被称为原子提交。这里借用“原子”是强调把相互依赖的变化作为一个有意义的整体,不是要求一次只能改一行或一个文件。它为理解和调整提供边界,也不会自动保证提交里的实现正确。

看看两个提交说明。“优化”只告诉人动过东西;“无匹配地点时恢复换条件提示”则指出受影响情景和希望得到的行为。后者仍需要查看文件和检查结果,但它让小叶以后搜索历史时有了入口。他想找提示第一次消失或恢复的位置,不必逐个猜“优化1”“优化2”分别做了什么。

提交说明写得具体,也不等于把一整份报告塞进标题。简单变化可以用一句说明完成。涉及重要取舍时,再补充为何采用这种做法、尚有哪些未解决条件。更完整的需求、使用说明和决策文档可以放在相应位置,后续章节会继续讨论它们;这里需要的是让历史记录的每一步有可辨认的意图。

AI一轮改动可能跨越多个意图。这时小叶不必按照对话轮数机械提交:一条消息可以产生几项独立变化,几轮讨论也可能才完成同一项功能。先查看改动的关系,再决定记录成一份还是几份,更符合实际工作。如果文件中的变化交织得难以分开,也可以先保存当前试验,再请AI在明确起点上分别实现,而不是假装已经形成几个互不依赖的改动。

过度拆分同样会制造困难。假如页面读取新字段必须依赖地点表同步更名,将它们拆成两个不配套的“完成版”,并不能让恢复更容易。小叶需要的是能解释的中间状态。尚未完整的工作当然可以留下记录,只要其用途和未完成情况清楚,不把这些记录直接当成可交付成果。

六、分支把试验留在一条能追溯的路上

开篇是连续提交的情景。现在另从V0设想一种工作安排:小叶准备尝试卡片布局,同时又收到已经确认的关闭时间更正。他希望先把正确资料补进日常使用版本,布局试验则继续进行,不让尚未检查的页面影响这份基础版本。

分支可以帮助组织这样的两条发展路线。Git中的分支有一个名字,指向这条线当前的提交;后续沿这条线提交时,它通常继续指向新的末端。创建一个试验分支并不要求把所有历史重新抄写一份,两个分支可以从相同提交开始,之后分别积累变化。

小叶把日常整合的分支叫main,试验分支叫cards。这两个名字只是项目里的命名选择,不自带质量保证。此时可以让main保留基础页面并更正时间,在cards中尝试卡片布局。两边来自同一份V0,因此日后有条件比较各自究竟增加了什么。

从共同起点分别修改,再形成一个合并结果
图 S10-01|从共同起点分别修改,再形成一个合并结果

图中的箭头表示提交的先后与来源关系,不表示电脑自动把所有改动同时放进当前文件。下方的布局试验在合并前,还不包含上方后来做的时间更正;上方的主线也没有自动得到卡片布局。是否将它们组合,是接下来要完成的工作。

如果只使用一个工作目录,切换分支时,Git会按目标分支更新相应的工作文件。小叶可能看到卡片变回列表,这不等于卡片试验被删除,而是当前查看和运行的文件换到另一条线。理解“当前在哪条分支、文件对应什么提交”,可以避免把正常切换误认为AI撤销了自己的工作。

尚未提交的修改则需要另作考虑。有些修改能够跟着切换保留,有些切换会因覆盖风险被工具阻止,分支并没有给全部未提交工作自动分好抽屉。实际切换前先看状态,把需要保留的修改记入相应提交,或另存为一份可确认取回的独立副本,再进行切换。仅在编辑器里保存当前文件,不会因此多出这样的记录或副本。这样小叶才能清楚知道,切换后眼前哪些内容应当出现,原来的工作又在哪里。

两名AI助手并行工作时,这个问题尤其具体。如果它们直接修改同一个工作目录,一个保存文件的动作可能覆盖另一个刚改过的内容。只在任务描述里说“你负责A、它负责B”,并没有自动产生文件隔离。可以安排各自使用独立工作副本和对应分支,再汇合变化;工作材料是否真正分开,要由实际目录和工具设置确认。

即使文件工作副本分开,外部共享的数据库或服务也可能仍是同一个。分支主要管理代码和相关文件的版本路线,不会自动为所有外部系统复制独立环境。对于本讲这个只在本地读取教学地点表的例子,先管好文件就能解决相当一部分问题;涉及外部共享对象时,再检查相应范围。

七、合并是在当前条件下组合两份变化

两条路线都积累了可考虑采用的内容后,合并负责把它们接起来。Git通常会结合两边的状态和共同来源,判断各自相对起点改了什么。这样就有机会既保留主线的时间更正,也采用试验线的卡片布局,而不是拿一个目录简单覆盖另一个目录。共同来源、自动合并与冲突的基本关系可参照Pro Git:分支与合并。

在最容易理解的情形里,两边分别修改独立文件:main只改地点表的关闭时间,cards只改页面布局,而且两者读取数据的约定保持一致。文件变化可以顺利组合,小叶随后检查新页面能否读到十点这个值,也检查空结果等行为。这里“合并完成”先表示文件层面的组合已经完成,功能是否符合要求要看组合后的实际结果。

若两边把同一处提示改成了不同文字,工具可能无法自动决定应该保留哪个,于是报告合并冲突,把需要处理的位置交给人。这个冲突不是说两个分支全部失效,而是说明某些变化尚未形成明确的合并结果。小叶需要理解两边的目的,再选择一方、组合含义,或写出更合适的第三种表达。

例如,一边把提示改成“这栋楼没有可用地点”,另一边改成“请更换筛选条件”。如果当前筛选还包含开放时段,第一句话可能过早断言整栋楼没有地点。解决冲突时,小叶应根据实际筛选范围决定提示,而不是认为后改的文字天然正确。版本历史提供两边为什么改的线索,最终表达仍服务于用户当前看到的结果。

让AI处理冲突也适用同样的判断。只要求“把冲突标记去掉”,它可能保留一边、删除另一边,文件重新变得整齐,却丢掉其中一个意图。更完整的处理是给它两项变化各自要解决的问题,要求说明合并后怎样保留这些需要,再查看结果和相应检查。冲突标记消失,只是处理过程中的一个可见变化。

更隐蔽的情况是工具没有报告冲突,行为却不配套。另设一个情景:主线把地点表的字段从close_time改成closing_time,并同步修改已有页面的读取代码;试验线则新增一个页面文件,仍按旧字段读取自己分支中的地点表。主线修改的两个文件与试验线新增的文件不同,文本可能顺利合并,但组合后的新页面取不到关闭时间。文件虽然合在一起了,新增页面使用的字段约定却没有跟上主线的变化。

即使两条分支此前都已在各自配套的材料中检查过相关显示,这些结果也不能代替组合后的检查。小叶要确认的是当前合并版本中的页面、数据和配置一起工作时有什么行为。主线数据更名以后,试验线带来的新页面还要与它对齐,才能共同完成查询。

独立Git文本实验中,两条分支分别改一个文件后再合并,实际结果保留了双方的文字变化。这对应本节前面各改独立文件的组合情形;查询页采用组合后的文件时,还应查看数据怎样被各个页面读取,并检查相关显示。

八、恢复旧文件与撤销某次修改,解决的问题不同

回到开篇已经连续形成V0、V1、V2的情景。V1删掉提示,V2更正时间。小叶现在不想再试新布局,只想先得到提示正常、关闭时间为十点的查询页。可以从两个方向考虑:从已知旧状态取回所需文件,或者反向处理造成问题的那次修改。

第一种是恢复指定文件的内容。假定V1只修改页面文件,V2只修改地点表,页面与地点表之间的字段约定一直没有变化,那么用V0的页面替换当前页面,就有条件恢复原布局和提示,同时保留当前地点表的十点。这里选择的是“取回旧页面”,没有要求把整个项目换回旧状态。

Git的restore可以指定内容来源和需要恢复的文件。为了把动作看得具体,再用一个独立文本实验模拟这三轮历史:baseline是事先标记好的基础提交,display.txt代替页面显示内容,地点表单独保存。从V2对应的干净工作状态开始,没有尚未记录的修改,下面命令把显示文件在基础提交中的内容放回工作目录。

可复制模板
git restore --source baseline --worktree -- display.txt
git diff -- display.txt

第二行用于查看这次恢复相对暂存内容造成的差异。在这个实验的干净起点上,暂存内容与当时最新提交一致,因此可以看到基础显示内容怎样替换当前显示内容。其他文件没有因为这条命令被要求一起恢复,地点表仍保持十点。指定来源、作用位置与文件范围,是理解这项操作的要点。Git:restore

恢复后的文件还只是当前工作内容。小叶检查它与新数据配合是否符合要求,再把这项恢复作为一个新提交记录下来。这样历史里仍保留V1和V2发生过什么,也多出一份明确的恢复结果。若实际工作中还有需要保留的未提交修改,应像切换前一样,先将其记入提交或留下独立副本,再恢复所选文件;否则这些修改可能被旧内容覆盖,单靠已有历史找不回来。

第二种是撤销某次提交带来的变化。Git的revert会尝试反向应用所选提交的改动,并通常以一个新提交记录结果。它保留先前历史,不是把整个项目瞬间送回那个提交之前。小叶如果选中的是V1的卡片改版,后面独立完成的地点时间更正有机会继续保留。Git:revert

另一条实验路线同样从V2开始:V1只改显示文件,V2只改地点表,撤销V1确实恢复了基础显示内容并保留十点。实际操作使用的是V1的真实提交标识。假如在V2状态选择撤销“当前最新提交”,反而会撤掉V2的时间更正,提示问题仍然没有解决。因此,“撤销哪一次”比记住“撤销”这个动作本身更关键。

两种办法在这个简单例子中可以得到相同文件内容,不代表它们在所有项目里效果一样。恢复旧文件会取回那个文件在指定状态中的内容,后来放进同一文件的其他好改动也可能被一起覆盖;撤销提交则针对那次变化反向处理,可能因为后续修改而发生冲突,也可能影响依赖这次变化的新功能。都需要看当前文件和变化关系。

如果后来又在页面里增加了读屏提示,整份恢复V0页面会连这项新增内容一起丢掉。小叶此时可能更适合只修回无匹配处理,保留读屏支持;或者仔细处理撤销时的相关变化。历史为他提供正确旧行为的参照,不强迫他只能在“全旧”和“全新”之间二选一。

九、恢复之后,要知道自己检查的是哪一份结果

找回文件只是恢复过程的一部分。小叶还要确认这套文件能满足当前需要:无匹配时出现恰当提示,那处地点关闭时间显示十点,其他原有筛选仍正常。之所以逐项指出这些行为,是因为它们分别对应开篇的损坏、后来必须保留的更正和可能受页面恢复影响的旧功能。

假如小叶检查完恢复结果,AI又顺手整理页面代码,而这项整理尚未复查,那么后一个提交不能直接继承“刚才那版已经检查”的结论。改变可能没有影响行为,也可能有;应该根据实际差异判断需要复查什么。检查记录带上具体版本,就是为了让这种关系能被追踪。

同样,检查时使用了某份地点表,交给同学的版本却遗漏它,检查与交付也发生了偏离。可以在一个新的工作副本里取得准备交付的提交,按规定取得必要数据并运行一次相关流程。这样比较容易发现本机额外文件、未记录设置或旧缓存一直替项目补着缺口。

新的工作副本主要帮助检查:记录中的材料是否足以组成这次工作。它仍可能使用相同的错误示例,或连接同一份已经变化的外部数据,所以结果的正确性还要按相应要求核对。比起始终在原目录里反复刷新页面,这次检查多回答的是有没有依赖本机额外材料的问题。

涉及部署时,还要再看运行对象。小叶电脑里的文件恢复了,服务器上的页面未必已经更新;即使重新部署,用户浏览器也可能还在使用旧资源。实际需要确认供用户使用的那个入口呈现什么。版本标识可以帮助关联文件、构建和部署,真正的恢复结果要落到当前用户能使用的行为上。

这里也能看出版本管理与上一讲测试的配合。测试说明某份材料在某些条件下表现如何,版本记录帮助我们找到那份材料及其变化。前者没有明确对象,结果容易张冠李戴;后者没有行为检查,历史再整齐也可能只是整齐地保存了多个错误状态。

十、历史存在,不代表所有东西都已经可以找回

小叶把文件提交到本机仓库后,通常可以在没有网络的情况下查看和继续记录本地历史。这对AI任务中途断网很有帮助:已经保存在本地的提交并不会因为聊天中断就消失。但如果唯一的电脑磁盘损坏,本地历史与工作文件可能一起丢失。版本历史解决变化的记录,另一处可靠副本则帮助应对存储位置本身失效。

把远程仓库设在另一台设备或可靠服务上,可以为共享和保存版本历史提供另一处位置。把本地提交发送过去,常称为推送;本地提交成功并不表示推送也已完成。如果小叶只在电脑里提交,另一台机器取得远程仓库时仍可能拿不到最近的记录。能否恢复最新工作,要查看另一处实际保存到了哪里。Git所说的远程仓库也可以位于同一台电脑,因此仅有“远程”这个名称,并不证明已经有了应对本机损坏的副本。Pro Git:远程仓库与推送

也不应把远程仓库当成整个电脑的自动备份。未跟踪的地点资料、本机专用设置、外部数据库以及不属于推送范围的内容,未必随提交一起到达。版本管理和备份可以配合:需要跟随代码变化的材料保持清楚的版本关系,重要但由其他系统管理的数据采用相应备份和恢复方式。判断依据是文件和数据的实际去向。

有了另一处副本,还可以做一次小范围恢复演练:从那里取得指定提交,把必要环境和材料准备好,运行当前关心的流程。演练发现少了地点表,就补充数据保存安排;发现缺少某个依赖版本,就明确可取得的环境。演练的作用是把“应该能恢复”推进到“这一种恢复路径确实走过”,并暴露路径缺口。

环境之所以重要,是因为相同源文件可能调用不同版本的软件库、不同配置或外部服务。记录依赖版本、安装方式和必要配置,可以减少恢复时的猜测。即使这些都记下来了,外部服务能否继续提供原接口、授权是否仍有效,也可能影响实际可用性。应按项目的依赖程度安排,简单本地页面与依赖多个在线服务的工具,所需准备不会完全一样。

如果查询页接入AI,让模型根据开放时间回答同学的问题,恢复同一份提示与程序,也不保证模型再次生成逐字相同的回答。版本记录保存的是可控制、已记录的输入和设置;模型服务及生成过程还可能有其他变化。对于关键观察,可以保存当时的输入、实际输出和相关设置,便于解释那一次结果;重新运行时仍需按当前要求检查。

这不妨碍版本管理发挥作用。它把原来混在一起的疑问拆得更清楚:是代码变了、数据变了、配置变了,还是在同样已知材料下运行行为出现差异。小叶不用把每次异常都当作无法追踪的偶然,也不会因为找到了旧提示,就误以为整个外部环境已经跟着恢复。

十一、带着明确的恢复目标,回到小叶的查询页

现在可以具体处理开篇的问题。当前资料已经确认关闭时间为十点,这项更正需要保留;卡片改版删掉无匹配提示,已经有失败场景;基础版有对应处理。小叶先辨认并保留当前文件和已有历史,查看V0到V1及V1到V2的差异,确认这两轮变化各自涉及什么。

沿用第八节的文件分工和字段相容条件,并假定当前没有其他未记录修改。若小叶愿意暂时回到原布局,可以从V0取回页面,保留V2的地点表。这样得到的新组合明确服务于眼前目标:提示恢复,时间不退回九点。若他希望保留卡片,则应以旧的空结果处理为参照修复当前页面,不能直接把整个旧页面换回来却又声称卡片仍在。

进一步假定小叶采用了前一种安排,并已经在恢复后的文件上检查了无匹配提示、十点显示和原有筛选,三项都符合这次要求。他就可以把结果记为新的恢复提交,说明恢复了基础页面并保留新资料。这个版本的可用依据来自实际检查的行为;提交记录则让这些检查能够对应到一套确定文件。

卡片尝试仍留在历史里,之后可以从明确起点继续研究。小叶不需要因为一次改版失败就删除整个尝试,也不必为了保住尝试而让同学继续面对已知的空白页面。版本记录使两件事可以分别安排:当前采用哪份结果,未来从哪里继续改进。

再让AI工作时,他可以交代具体起点、要改善的情景和应保留的行为,让修改在可辨认的工作位置进行。完成后先看差异,再检查相关行为,最后记录确认采用的状态。这样,一句“继续优化”就逐渐成为能够检查和调整的过程:我们知道从哪里出发,增加了什么,发现问题后又能选择合适的材料继续前进。

练习与参考分析

练习一:检查过的文字,为什么没有进入提交

小叶把一个提示文件从“没有结果”改成“请重新选择”,并将其暂存。之后又改成“请放宽筛选条件”,保存文件并检查了页面,随后直接进行普通提交,没有再次暂存。提交中应是哪句话?刚才的页面检查可以直接证明这个提交的提示已经检查过吗?

**参考分析:**普通提交记录暂存区中的“请重新选择”。工作目录里的“请放宽筛选条件”仍是后续未提交修改。小叶检查的是后一状态,不能把它直接记为对前一状态的检查。如果希望记录刚才检查的内容,应重新暂存并查看待提交差异,确认对应文件及其他必要变化正确进入这次提交。这里的关键不是保存按钮失效,而是磁盘保存与历史记录选择发生在不同位置。

练习二:旧页面回来以后,为什么时间又错了

基础提交中的页面和地点表都已记录,地点表写21:00。后来一次独立提交只把地点表更正为22:00,再后来一次提交损坏了页面提示。小叶把全部文件换回基础提交,提示正常了,时间也显示21:00。他说“恢复已经成功,因为页面不再空白”。这个判断缺少什么?怎样考虑更合适的办法?

**参考分析:**如果当前目标包括保留已确认的22:00,只恢复提示并未完成全部要求。应查看损坏页面的那次修改、当前页面是否还有需要保留的新内容,以及旧页面能否读取现有数据。条件允许时,可以只恢复页面而保留新地点表,或针对损坏提交做撤销,再检查组合后的行为。题目把时间更正放在页面损坏之前,但对象判断没有变:应保留什么由当前需求决定,不能仅凭“基础版曾经正常”整体退回。

练习三:没有冲突提示,是否可以立即交付

两条分支分别进行修改。主线把地点表中的字段名更改,并同步修改已有页面的读取代码;试验线新增另一个页面文件,仍按旧字段读取其分支中的数据。Git自动合并成功,保留了主线的新数据、更新后的已有页面,以及试验线新增的页面。两条分支各自在自己的配套材料中也曾检查通过。小叶还需要查看什么?

**参考分析:**自动合并只说明工具形成了文件结果,不说明页面与数据的约定一致。应查看合并后的页面实际读取哪个字段、数据实际提供哪个字段,并把它们一起运行检查。两条分支原先各自配套,不表示合并后的新组合仍配套。修复时要将相关读取和数据约定对齐,再检查受影响功能;不能为了让界面不报错,就用一个无依据的默认关闭时间掩盖读取失败。

练习四:仓库有了备份,资料是否也有了

小叶已经把全部本地提交推送到另一个可靠存储位置。但实际使用的地点表一直是未跟踪文件,没有进入提交,也没有其他副本。电脑损坏后,他取得远程仓库。仅凭这些信息,能否认为最新地点表一定可以恢复?

**参考分析:**不能。远程保存的是被发送过去的版本记录,题面明确地点表不在其中,且没有其他副本。不能把“全部提交”扩大成“全部工作材料”。程序可能恢复,地点资料仍缺失。这个问题需要在事前明确数据的版本或备份安排,并在恢复演练中核实资料能否取得;如果数据本来能从可靠来源重新取得,也应验证这种路径,而题面并未给出这项条件。

练习五:两名AI助手是否已经互不干扰

小叶给两个AI助手分配了不同任务,也为任务取了两个分支名,但它们实际编辑的是同一个工作目录。一个助手切换分支后继续修改,另一个仍按照原先看到的文件保存结果。是否可以仅凭任务和分支名不同,判断它们不会相互覆盖?

**参考分析:**不能。同一个工作目录中的当前文件是双方实际读写的对象,名字不同没有自动提供独立副本。应先明确各助手的工作位置和当前版本,采用真正分开的工作副本及对应分支,或顺序安排修改,再对各自结果进行汇合检查。如果任务还会访问同一外部数据库,也要另外检查共享范围;文件分开只解决其中一部分对象的隔离。

练习六:恢复旧文件还是修复当前文件

V0页面包含无匹配提示。V1改版时删掉提示。V2又在同一个页面文件里增加了已经确认需要保留的读屏说明。当前目标是同时拥有无匹配提示和读屏说明。直接从V0恢复整个页面,是否满足目标?是否能断言撤销V1一定更好?

**参考分析:**整份恢复V0会丢掉后来增加的读屏说明,因而不能直接满足两个要求。可以比较V0、V1、V2中相关处理,考虑在当前文件上补回缺失提示,保留读屏说明。撤销V1也值得考察,但题面没有说明V2与V1的结构依赖,不能保证反向改动一定顺利或不会影响读屏行为。应检查具体差异和当前文件,形成兼顾两项要求的新结果,再验证两种情景。历史提供参照,选择恢复办法仍取决于现在要保留的关系。