【Git基础】03——Git 撤销与回退:改错了怎么办
基础篇01: 【Git 基础】01——代码是怎么被追踪的基础篇02: 【Git基础】02——分支在不破坏主线的情况下做实验 写代码总会手滑。改了半天发现方向错了或者 commit 信息写错了甚至把不该提交的东西提交上去了这些都是日常。Git 的撤销体系看起来命令很多但核心其实只有一句话先判断改动在哪一层再选择对应的撤销工具。只要这点清楚Git 的“后悔药”其实非常好用。引言 先建立一张地图Git 追踪改动分三层工作区Working Directory你正在编辑的文件暂存区Staging Area执行git add之后提交历史Commit History执行git commit之后撤销操作的方向本质就是沿着这条链向后退。 三层结构图工作区、暂存区、提交历史依次排列撤销操作是沿着这条链往回走的过程。一、场景一还没 add直接丢弃工作区改动 你改了一个文件还没add现在想把它恢复到上次提交的状态gitrestore README.md 这条命令会丢弃工作区的改动文件直接回到最近一次 commit 的版本。注意这个操作是不可逆的因为工作区的修改没有进入Git历史。 旧版 Git 用的是git checkout -- README.md效果一样只是语义不够清晰。现在推荐统一用git restore。二、场景二已经add但还没 commitgit add之后反悔了想把文件从暂存区拿回来gitrestore--stagedREADME.md 加了--staged就是针对暂存区操作。执行后文件回到已修改但未暂存的状态工作区的改动还在只是不再准备提交了。 如果想一步到位既撤销暂存又丢弃工作区修改推荐分两步gitrestore--stagedREADME.mdgitrestore README.md意图清晰比命令短更重要。三、场景三已 commit怎么办这里是 Git 新手最容易混乱的地方 这里要区分两种情况这个 commit有没有推送到远程。3.1 没推送可以用git resetgit reset会移动HEAD指针改写提交历史。 有三种模式模式改动去向--soft回到暂存区默认mixed回到工作区--hard直接丢弃(1) commit - 暂存区gitreset--softHEAD~1(2) commit - 工作区gitreset HEAD~1(3) commit 直接删除gitreset--hardHEAD~1 三个模式的区别在于改动去哪里--soft退回暂存区默认--mixed退回工作区--hard直接扔掉。--hard用之前要想清楚它是真正的删除按钮改动没有备份找回来非常麻烦。3.2 已推送必须用git revert 一旦 commit 推送到了远程绝对不要用git reset。原因很简单远程已经有这个commit的记录你本地改写历史之后推送会被拒绝就算强推成功协作的同事拉代码时会遭遇历史冲突现场一片混乱。 正确做法是git revertgitrevert HEAD 它不会删除commit而是会生成一个新的 commit内容是把目标 commit 的改动反向应用一遍。历史链条不动安全可追溯。提交历史A → B → C需要撤销 C revert 后A → B → C → CC 是 C 的逆操作reset直接把 HEAD 往回挪C 从历史中消失本地没问题但如果这个 commit 已经推送到远程别人的历史里还有 C强推会导致冲突。而revert则是在 C 后面追加一个反向 commit C’历史只增不删对协作者完全透明这就是为什么已推送的 commit 必须用 revert。 代价是历史会多一条记录但这正是团队协作里应有的透明度。四、git stash保存现场去干别的 有一种场景 reset 和 revert 都处理不了你改到一半突然需要切分支处理紧急 bug。改动还没到能提交的程度但直接切分支又可能出现冲突或者把改动带过去。 这时候可以用git stashgitstash 它会把当前工作区和暂存区的改动打包藏起来让你的工作目录回到干净状态。处理完紧急任务切回原来的分支再把现场恢复出来gitstash poppop会把最近一次 stash 的内容恢复并从 stash 列表里移除。如果想保留记录用git stash apply代替。 有时候同时有几个 stash可以用git stash list查看git stash pop stash{1}指定恢复哪一个。五、决策表碰到问题查这里当前状态目标命令工作区有改动未 add丢弃改动git restore file已 add未 commit撤销暂存git restore --staged file已 commit未推送撤销 commitgit reset HEAD~1已 commit已推送撤销 commitgit revert commit改到一半要切分支临时保存现场git stash/git stash pop 撤销体系的核心逻辑就是一句话改动走到哪一层用对应层的工具往回退已经共享出去的历史只能用新 commit 来修正不能改写。