
最开始用SourceTree时我总觉得“重置”是个特别危险的操作生怕点一下就把几天的代码全弄没了。但后来在项目里频繁遇到“提交错了”“想回到某个历史版本看看”“想把最近几次提交合并重来”这类需求后我才发现重置其实是SourceTree里最实用、也最容易理解混乱的功能之一。今天就把我常用的两种重置恢复提交的方式完整梳理一遍顺便把Soft、Mixed、Hard三种模式的区别、适用场景、以及我踩过的坑都写出来希望能帮到刚上手SourceTree的朋友。1. 动手之前先搞懂SourceTree里的“重置”到底是什么1.1 重置与还原Revert的区别很多朋友会把“重置当前分支到此提交”和“还原提交”搞混因为从菜单上看这两个操作都在同一个右键菜单里都能让代码回到过去的某个状态。但它们的逻辑完全不同。重置Reset把当前分支的指针直接移动到目标提交等于告诉Git“我不要这之后的提交了”。操作后被重置的提交会从当前分支历史里消失但提交对象本身还在Git的对象库里只是没有分支引用它所以还有机会通过reflog找回来。还原Revert不改动历史而是生成一个“反向提交”把某个提交的改动撤销掉。比如你提交了A又提交B现在只想撤销A的改动但保留B那就用RevertGit会新建一个C提交C的内容等于“撤销A之后的结果”。用生活化类比来说重置就像是“回到过去把某段历史从时间线上抹掉”而还原则是“保留历史但写一个新的声明说之前某件事作废”。在团队协作时如果分支已经推送到远程并且别人拉取过那尽量不要用重置直接改写历史而是优先用还原否则别人的本地仓库和远程仓库会严重分叉。1.2 Soft、Mixed、Hard三种模式对比SourceTree里“重置当前分支到此提交”的对话框会弹出三种模式软合并Soft、混合合并Mixed、硬合并Hard。这个翻译其实有点容易误导本质上它们对应的是Git reset命令的三个参数--soft、--mixed、--hard。它们的核心区别在于重置后原来提交里的改动要怎么处理。模式对应参数暂存区Index工作区Working Directory典型用途软重置git reset --soft保留改动且这些改动会处于已暂存状态保留改动文件内容不变提交错了想重新整理提交混合重置git reset --mixed默认清空暂存区改动变成未暂存状态保留改动文件内容不变撤销提交且不想保留暂存状态硬重置git reset --hard清空暂存区工作区文件直接恢复到目标提交的状态所有改动丢失彻底放弃当前改动恢复到某个历史版本我刚开始用的时候对“暂存区”这个概念不太敏感。简单说暂存区就是Git里一个“准备提交的缓冲区”你修改了文件之后需要先git add把它放进暂存区然后git commit才会把暂存区里的内容提交上去。SourceTree的“暂存所有”按钮做的就是git add这件事。搞懂这三者的区别后重置就不再可怕了。只要能判断清楚自己是想保留改动还是彻底丢弃选对模式就可以放心操作。2. 两种核心重置操作实战软重置与硬重置这一章是重点。标题里的“两种重置恢复提交”我理解下来最常用的就是软重置和硬重置这两种。我分别从操作步骤、适用场景、背后原理三个角度来说。2.1 软重置Soft Reset保留改动重做提交操作步骤打开SourceTree找到左侧“提交”面板会看到当前分支的提交历史列表。在历史列表里找到你想回退到的那个目标提交。比如当前有5个提交你想撤销后3个那就右键第2个提交。选择“重置当前分支到此提交”。在弹出的对话框里模式选择“软合并Soft”点击“确定”。操作完成后你会发现分支指针已经移动到了目标提交而后面的提交记录从历史列表里“消失”了。但是被撤销的提交里的所有文件改动都还在你的工作区里而且已经自动处于“已暂存”状态。你可以直接继续修改再重新提交。适合的场景写了好几个提交结果发现这些提交的逻辑不清晰想合并成一个有意义的提交。某一次提交里不小心把密码、密钥等敏感信息提交上去了想撤销这个提交再重新提交注意如果已经推到远程这种做法一定要谨慎最好配合历史改写策略。想把一个开发周期内零碎的小提交合并成一个完整的功能提交。背后的原理软重置之所以能保留改动是因为它只移动了HEAD指针和分支引用完全没有碰暂存区和工作区。Git觉得“你只是把分支指针往回拨了一下但文件该怎样还怎样”所以那些原本已经提交的内容在重置后依然存在于暂存区中等待你决定是重新提交还是继续修改。我在项目里经常这么干开发一个功能过程中随手提交了好几次每次提交信息都写得很随意比如“fix typo”“update code”“继续调”到准备推远程之前我会用软重置回到这个功能开始前的那个提交然后重新整理成两三个语义清晰的提交。效果非常好同事看代码历史时会觉得特别清爽。2.2 硬重置Hard Reset彻底回退慎用操作步骤同样找到目标提交右键。选择“重置当前分支到此提交”。在模式里选择“硬合并Hard”确定。此时SourceTree会弹出警告大意是这个操作会丢弃工作区未提交的改动。如果你确认不需要这些改动了点确定即可。执行完后分支指针回到目标提交工作区、暂存区都会变得和目标提交完全一致。被重置掉的提交以及当时的工作区改动全部消失。适合的场景实验性代码折腾了很久发现方向错了想一键清空所有改动恢复到干净状态。本地仓库刚拉下来还没有推送到远程但已经提交了几次发现代码有问题想彻底回到远端某个版本重新开始。临时切换分支时希望工作区干干净净不保留当前未提交的改动。必须注意的坑硬重置是真正意义上的“毁尸灭迹”虽然理论上有reflog可以找回但如果你不熟悉reflog或者重置后几天才发现需要找回某些代码那时候可能真的找不回来了。所以我在执行硬重置前一定会做两步检查确认当前工作区没有需要保留的未提交改动。如果还不确定先“贮藏”Stash一下把改动存起来再重置。重置完如果后悔还可以用“贮藏”列表恢复。确认目标提交确实是你要回退到的位置。右键提交后可以先用“查看提交”看看这个提交的文件列表确保它包含你想要保留的全部状态。另外如果分支已经推送到了远程而且不是只有你一个人在用那千万不要对已推送的提交执行硬重置。因为其他人拉取后他们本地会保留旧的分支历史你一旦强制推送团队其他人的本地仓库会出现大量冲突。这种情况应该用Revert或者走代码评审流程。2.3 补充混合重置Mixed Reset有什么用虽然标题里说的是两种但我在实际使用中混合重置其实也挺常用所以稍微补充一下。混合重置对应git reset --mixed也是Git里不带参数时的默认行为。它和软重置的区别在于重置后会清空暂存区但保留工作区改动。也就是说软重置后改动已经帮你git add好了直接git commit就能生成新提交混合重置后改动还在但处于“未暂存”状态你需要自己重新决定哪些文件要加入暂存区。什么场景会用到混合重置比如你一次提交里包含了多个文件的改动但重置后你想拆成多个逻辑独立的提交。用混合重置回到某个提交然后手动把文件分批git add、分批提交就非常合适。在SourceTree里模式选择“混合合并Mixed”就行。3. 从“误操作”到“恢复提交”完整实操场景这部分我会用三个真实场景把两种重置配合起来演示。每个场景都有背景、操作步骤和最后结果跟着做一遍基本就能掌握。3.1 场景A刚提交错了想撤销并保留修改背景我在本地仓库里连续提交了三次提交信息分别是“第一部分功能”、“第二部分功能”、“临时代码”。结果发现第二次提交里包含了一个调试用的临时文件打算把第三次提交撤销掉然后把临时文件排除后再重新提交。操作步骤在SourceTree提交历史中右键第二次提交选择“重置当前分支到此提交”。模式选择“软合并Soft”。此时第三次提交的改动全部回到暂存区。我在文件状态面板里找到临时文件右键选择“取消暂存”Unstage把它挪回工作区。留下需要提交的文件点击“提交”填写新的提交信息。对于临时文件我直接删除或者单独处理后再次提交。整个过程不到一分钟而且没有丢失任何代码改动。相当于把“第三次提交”这个动作撤销了又重新做了一遍。这里有个小技巧如果你只是想改最近一次提交的提交信息不一定要用重置。可以直接点击顶部的“提交”按钮旁边的下拉箭头选择“修改上一次提交”Amend这样更简单。重置更适合要动多个提交的场景。3.2 场景B想完全丢弃最近提交背景我在本地尝试了一个新的设计方案连续写了两天代码提交了4次但最终发现方案不靠谱准备彻底放弃回到方案开始前的状态。操作步骤先确认方案开始前的那个提交通常是一个比较久远的提交。为了保险起见我先把当前所有改动“贮藏”Stash一份。万一反悔了还能找回。操作是左侧点击“贮藏”按钮给贮藏记录起个名字比如“experiment-backup”。右键那个久远的目标提交选择“重置当前分支到此提交”。模式选择“硬合并Hard”。确认提示后工作区立刻变成目标提交的状态所有试验性提交都从当前分支历史里消失。执行完后我的本地分支变得非常干净仿佛那两天什么都没发生。如果后来突然又觉得方案里某个思路可以借鉴那就用“贮藏”列表里的备份记录把对应文件恢复出来。需要特别提一句硬重置前做Stash这个操作非常有用几乎零成本却给自己留了后悔药。不要嫌麻烦多一步操作能减少很多焦虑。3.3 场景C误删分支后找回提交背景我在SourceTree里清理分支时不小心把一个本地分支删了而这个分支上还有几个未合并到主分支的提交。删分支后提交历史在主分支里看不到但我记得这个分支大概是在哪个位置拉出来的。这里其实用不到在SourceTree界面上直接操作重置但我会借助命令行和SourceTree配合来恢复。打开终端进入仓库目录输入git reflog查看本地所有HEAD移动记录。在reflog里找到被删分支最后一次指向的提交哈希。比如输出里有a1b2c3d HEAD{2}: commit: 完成xxx功能。确认这个提交后回到SourceTree点击右上角“分支”按钮在“提交”输入框中粘贴这个哈希值。勾选“从这个提交创建新分支”指定一个新的分支名点击“创建分支”。这个操作本质上等效于用重置把某个无人引用的提交“恢复”回来只不过我们不改变现有分支的指针而是新建一个分支指向它。Git的reflog机制保证了只要你没有运行git gc清理过期对象这波操作通常都能成功。4. 常见问题与排查技巧实录平时在技术群里看到很多人用SourceTree时栽在重置上这里集中写几个高频问题以及我总结的解法。4.1 重置后找不到提交reflog救命如果重置完后悔了想找回被移除的提交第一反应是打开“提交”面板翻历史结果发现找不到。因为重置后的提交不在当前分支的引用路径上SourceTree默认只展示当前分支的提交历史。这时候需要用到git reflog。reflog是Git的“引用日志”记录了当前仓库里HEAD指针的每一次移动。即使你硬重置了reflog里依然保留着之前HEAD指向的提交哈希。我一般会在终端里执行下面的命令查看git reflog输出类似a1b2c3d HEAD{0}: reset: moving to HEAD~2 e4f5g6h HEAD{1}: commit: 完成功能 j7k8l9m HEAD{2}: commit: 修改样式如果你想回到e4f5g6h这个提交可以执行git reset --hard e4f5g6h或者更稳妥地在SourceTree里从这个哈希新建一个分支把代码保护起来。注意reflog不是永久保存的Git会定期清理过期对象默认情况下90天但如果仓库做过git gc或体积很小可能更早被清掉。所以发现问题后尽早恢复。4.2 贮藏Stash与重置的配合“贮藏”是SourceTree里非常实用的功能它的作用是把当前未提交的改动先存到一个独立区域让工作区恢复干净之后再随时取回。重置和贮藏搭配使用的场景很多。比如你刚写了一堆修改但还没提交现在想看看另一个分支上的一个历史版本。如果直接切换分支SourceTree可能会提示你提交或贮藏这时候选择“贮藏”就好。还有更精细的操作方式重置之前用贮藏把当前所有未提交改动打包存起来然后执行硬重置之后再从贮藏记录里把需要的文件取回。SourceTree左侧面板有一个“贮藏”标签页里面列出了所有贮藏记录。右键某条记录可以“应用贮藏”“分支”“丢弃”等。我常用的技巧是给每条贮藏记录都起一个有辨识度的名字比如“2025-02-03-登录页样式实验”避免过几天打开看到一堆名称相同的记录根本分不清谁是谁。4.3 重置前必须注意的事项先推远程再重置团队项目千万不要随意对已推送的分支做重置。如果非要重置需要和团队成员确认并做好强制推送force push的准备。强制推送在SourceTree里是“推送到远程”对话框中的“强制覆盖”选项但这个操作非常容易引发冲突非必要不用。重置时工作区有未提交改动硬重置会直接丢弃这些改动所以一定要先确认你不需要它们了或者先贮藏起来。重置和回滚不是一回事如果你只是想让线上代码回到上一个版本建议不要用重置而是用还原Revert生成一个反向提交这样线上历史是连续的后续也能正常合并。你重置的是哪个分支在SourceTree里重置操作是作用于“当前检出的分支”的。如果你当前在主分支上右键目标提交重置那重置的是主分支。如果你当前在一个功能分支上重置的是功能分支。操作前注意左下角的分支名称。4.4 SourceTree和命令行Git的对应关系如果你之前习惯用命令行切换到SourceTree后可能会好奇这些操作对应哪些命令。我整理了一张对应表方便自己在两种方式之间切换。SourceTree操作对应的Git命令功能说明软合并重置git reset --soft 提交移动分支指针保留暂存区和工作区改动混合合并重置git reset --mixed 提交移动分支指针清空暂存区但保留工作区改动硬合并重置git reset --hard 提交移动分支指针丢弃所有改动还原提交git revert 提交生成反向提交来撤销指定提交贮藏git stash/git stash pop暂存未提交改动之后恢复SourceTree界面上把这些命令做成了图形化选项但了解了背后的命令行逻辑能帮你更准确地判断当前操作会不会影响你不想动的文件。比如你随手在SourceTree里选中某个模式如果心里不踏实可以在终端先跑一下git status看看文件状态确认后再继续。4.5 重置前如何快速确认目标提交我见过不少朋友因为选错了目标提交导致重置后丢了一部分代码。一个比较保险的确认办法是在SourceTree提交历史里右键目标提交选择“查看提交”View Commit然后看右下角的文件变更列表确认它包含了你希望保留的文件状态。特别是当提交历史比较复杂、存在合并提交时更要仔细看。比如你当前分支是从某个大版本合过来的如果你把目标提交选到了合并提交之前那重置后你的分支就会丢掉合并过来的所有改动。这个坑很隐蔽一旦踩了对项目影响还挺大。如果真的不确定可以先用软重置。因为软重置不会丢工作区改动即使选错了目标提交改动都还在顶多重新整理一下。硬重置则开弓没有回头箭一定要谨慎。5. 给新手的一个小建议我在线下和不少朋友聊过SourceTree发现一个规律越怕用重置的人越容易在误操作后陷入紧张然后到处找恢复工具。反过来把重置机制弄明白后你会觉得Git其实很宽容只要reflog还在几乎大部分误操作都能挽回。我个人的习惯是区分“实验性代码”和“正式提交”。实验性代码我会放在本地分支上频繁提交但不会推送到远程这样即使推倒重来也不影响别人。正式提交推送前我会用软重置把零碎提交整理成清晰的几个提交然后再推到远程。如果发现某个提交有问题并且已经推送了那就老老实实用Revert而不是去重置分支。还有一种情况是重置后某个文件连续出现多次冲突搞得人很烦。这种情况多半是因为你的工作区改动和重置目标提交之间产生了“交叉”需要手动解决冲突。别急着怪SourceTree这其实是Git的合并机制在保护你让你有机会决定保留哪边的内容。6. 最后再分享一个实用技巧既然标题里提到了“后续还会更新其他用处”那我再说一个和重置密切相关、但很多SourceTree用户不知道的小技巧通过“重置到远端跟踪分支”来快速同步远程状态。有时候远程分支被同事更新了你的本地分支落后很多又不想通过git pull产生合并提交希望能直接把自己的分支重置到和远程一模一样。在SourceTree提交历史里找到那个显示着“origin/分支名”的提交右键选择“重置当前分支到此提交”模式选“硬合并”。这样你的本地分支就会和远程分支保持一致非常干净。不过这个操作同样会丢掉你本地未推送的提交和未提交的改动所以执行前一定要确认你已经保留了需要的东西。如果本地有未推送的提交但只想丢弃那这个操作是最快的。如果还想保留本地提交那就别用这种方式老老实实去合并或者变基。以上就是我使用SourceTree重置功能的一些经验和踩坑记录。两种重置恢复提交的方式配合软、混合、硬三种模式基本能覆盖日常开发里绝大多数“回退”“恢复”的需求。希望这份总结对你有帮助也欢迎在使用过程中遇到问题时回来一起讨论。