尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Git版本回退全指南:文件恢复、提交撤销、远端回退与reflog兜底

Git版本回退全指南:文件恢复、提交撤销、远端回退与reflog兜底 上个月帮同事收拾过一个烂摊子他把配置文件里的测试地址改成了线上地址一条git commit加git push直接甩上去等发现的时候已经是第二天早上。他第一反应是手动去改回来再提交一次结果越改越乱因为中间还夹着另外两个人的提交。这种情况其实每天在无数团队里上演涉及到的就是 git 版本回退这件看起来简单、真动手却容易翻车的事。我写这篇东西是想把 git 版本回退这条线上的东西一次讲透文件级别的恢复怎么做还没提交的错误怎么撤已经提交甚至已经推送到远端的错误怎么收场以及最坏情况下把数据从对象库里捞回来的办法。无论你是刚装完 git、连暂存区都还没搞明白的新手还是用了几年但每次回退都靠搜命令、搜完还得祈祷的老手这篇里的思路和参数选择应该都能直接用上。全文基于我自己的实际踩坑经验命令都在 Git Bash 里实跑过涉及取舍的地方我会把为什么讲清楚而不是甩一堆命令让你自己猜。1. 回退之前先把 Git 的三层结构和引用关系理清楚很多人回退出问题根本原因是没搞清数据到底待在哪一层。你敲下的每一条回退命令作用对象其实只有三种工作区的文件内容、暂存区里的索引记录、版本库里的提交对象。搞清这三者谁被改、谁没被改判断命令该不该用就是几秒钟的事。1.1 工作区、暂存区与版本库数据存在哪一层工作区就是你当前能看到、能编辑的那一堆文件。它不受 git 管理你拿记事本随便改git 不会拦你它只在执行git status或者git diff的时候拿工作区跟别的东西比一比。暂存区也叫索引是个很特殊的地方它在.git/index里存了一份文件快照的清单。平时的git add就是把工作区的内容写进这一层。很多人把暂存区理解成待提交列表其实它更像一张取景框你决定哪部分画面进到下一张照片里。版本库则是.git/objects里的一堆对象每次git commit都会生成 tree 对象和 commit 对象把它们永久钉在那个时间点上。所谓回退绝大多数时候不是把对象删掉而是把某个引用HEAD 或者分支挪到另一个提交上。对象一直都在这就是后面 reflog 能救命的原因。顺带说一个实际会踩的点你在 IDE 里看到文件变了IDE 显示的可能只是工作区跟索引的差异跟有没有提交是两回事。很多人看到 IDE 侧边栏没有变化标记就以为改动已经保存进历史了其实只是git add过而已。1.2 HEAD、分支引用与提交对象为什么回到过去不会丢数据HEAD 是一个指针正常情况下它指向某个分支名分支名又指向某个 commit。你执行提交时git 做的事情是新建一个 commit让当前分支指向它HEAD 自动跟着走。回退的本质就是让这个指针往回挪。这里有个关键认知commit 对象一旦生成除非你做垃圾回收git gc且过了宽限期否则它不会消失。指针挪走了对象还在。这带来两个特别实用的结论第一git reset --hard看起来删掉了的东西通常还能捞回来第二你以为删掉的分支只要 reflog 里还有记录就一定能恢复。还有个细节值得记住git 会同时维护ORIG_HEAD、FETCH_HEAD、MERGE_HEAD这些特殊引用。在你做了一次危险的 reset 或者 merge 之后ORIG_HEAD会记录操作前的那个提交算是一层简易保险。只不过它只保留最近一次连续做两次危险操作就容易覆盖掉所以真正靠谱的兜底还是 reflog。1.3 reset、revert、restore、checkout 的职责边界这四个命令是回退场景里最容易被混用的。它们不是同一个东西的不同写法处理的对象和产生的结果完全不同。我把日常会用到的判断整理成一张表遇到具体需求的时候按表查就行。命令主要作用对象是否改动历史典型用途git restore工作区 / 暂存区否撤销未提交的修改、撤销 addgit checkout工作区 / 索引也可切分支否老版本 git 的通用写法新版逐步被 restore/switch 取代git reset暂存区 / HEAD 指针是本地撤回提交、重排暂存内容git revertHEAD 指针新增提交否新增反向提交已推送的历史需要撤销git commit --amendHEAD 指向的提交是本地改提交信息、补漏文件判断顺序我自己的习惯是这样先问改的是文件还是提交再问这段历史有没有推给别人。改文件就走restore改提交且没推就走reset或amend改提交且已经推了就老老实实revert。这三步问完基本不会选错命令。2. 动手前的环境准备与最小配置回退操作对环境的依赖其实很低但配置不到位会让你在关键时刻看不清差异、看不懂日志判断就跟着错。花十分钟把这几件事做完后面每次回退都能少猜很多。2.1 Git 安装与首次配置三行命令搞定身份问题Windows 上最省事的做法是装 Git for Windows一路默认下一步装完自带 Git Bash。如果你习惯用图形界面TortoiseGit也就是常说的小乌龟配合 Git for Windows 一起装安装顺序是先装 Git 再装小乌龟否则小乌龟找不到 git 可执行文件。装完之后git --version能打印版本号就算通了如果提示无法将git项识别为 cmdlet、函数、脚本文件或可运行程序的名称八成是环境变量里没把 git 的 bin 目录加进去重装一遍并勾选从命令行和第三方软件使用 Git通常就解决了。身份配置这三行是必须的不配的话第一次提交会直接报错git config --global user.name 你的名字 git config --global user.email 你的邮箱 git config --global core.autocrlf true第三行在 Windows 上很关键。它控制换行符转换不配的话团队协作时会出现整个文件都变了但实际内容没变的假差异回退的时候特别容易误判。另外core.quotepath建议设成 false否则中文文件名在git status里会显示成八进制转义回退某个中文文件的时候你连文件名都复制不出来git config --global core.quotepath false git config --global core.ignorecase false2.2 让 diff 和日志更可读别名与参数优化回退之前必须看清差异看清差异就得让 diff 的输出符合你的阅读习惯。我给常用的几个配置和别名git config --global alias.lg log --color --graph --prettyformat:%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)%an%Creset --abbrev-commit git config --global alias.unstage reset HEAD -- git config --global alias.last log -1 HEAD --stat配好之后git lg一眼就能看到分支走向找哪个提交回退特别方便。git unstage file是撤销暂存的快捷写法比记完整命令省事。再说一个你可能在 IDE 日志里见过的参数串git -c diff.mnemonicprefixfalse -c core.quotepathfalse --no-optional-locks status。这是很多人打开 Visual Studio 或者 IntelliJ IDEA 之后在版本控制输出窗口里看到的调用。拆开看并不神秘diff.mnemonicprefixfalse让 diff 的路径前缀统一显示成a/、b/而不是根据操作类型变成i/、w/、c/这样 IDE 解析输出更省事人看着也更一致core.quotepathfalse就是我们上面说的中文路径问题--no-optional-locks是让 git 在执行只读命令时不要去抢索引锁避免后台 IDE 频繁扫描的时候和你的命令行操作打架。了解这几个参数的好处是当你在 IDE 里点了回退却没生效就能去输出窗口对照看真实命令是什么而不是干瞪眼。2.3 命令行、TortoiseGit 与 IDE三种入口怎么选命令行适合精确操作尤其是 reset、reflog 这类需要看清每个参数含义的场景参数写错一个字母结果天差地别。TortoiseGit 适合日常看日志、看某次提交改了哪些文件它的显示日志右键菜单能直接看到图形化的分支树找历史提交比翻命令行舒服。IDE 里的版本控制面板适合单文件级别的撤销右键一个文件选回滚很快但涉及提交级别的重排我建议还是回到命令行因为 IDE 的封装会隐藏关键参数你不知道它到底用的是--mixed还是--hard出了事不好判断。一个折中的用法是用图形工具定位到具体的 commit hash复制出来回到命令行执行回退。这样既有图形界面的直观又保留了命令行的可控性。3. 文件级恢复只坏了几个文件不用大动干戈绝大多数我搞砸了的场景其实没到提交级别只是某个文件被改坏、被删、被误加到了暂存区。这类问题处理起来最快也最不容易产生副作用因为整个过程中 HEAD 指针完全不动。3.1 工作区文件误删、改错的还原场景很典型你在编辑器里一通操作把某个文件改得面目全非ctrlz 又撤不回来了。只要这个文件的内容曾经提交过一条命令就能还原git restore file # 从暂存区恢复工作区 git restore --sourceHEAD file老版本 git 里对应的是git checkout -- file现在还能用但restore语义更清楚checkout那个--是为了防止分支名和文件名混淆的写法容易忘。这里有个细节要注意git restore file是从暂存区恢复工作区如果这个文件压根没git add过暂存区里那份就是上次提交时的样子所以结果和从 HEAD 恢复是一样的。但如果文件已经git add过暂存区里存的是你 add 时候的内容git restore file会还原到那个版本而不是最新提交。想明确指定来源就用--source。我自己常用的场景是只还原一个文件其它改动留着继续改。比如说我一个提交里改了五个文件其中两个改错了我只需要对那两个文件执行 restore其它三个照常提交互不影响。这是文件级操作的最大优势粒度足够细。3.2 把加错的文件从暂存区撤下来git add手滑把不该提交的文件加进去了比如本地调试用的配置文件、日志文件、编译产物。这时候别急着 reset只是想把文件从暂存区挪出来工作区内容一点不想动git restore --staged file # 推荐写法 git reset HEAD file # 老写法效果等价这两条命令只会把文件从暂存区移出工作区的改动原封不动保留。你可以理解成把取景框里的东西拿出来但物体本身没动。顺便提一句撤销整个暂存区的写法git restore --staged .或者git reset后面不跟路径就作用到全部。用之前先git status确认一下要撤的范围尤其是当暂存区里混着好几个不同类型改动的时候一股脑撤掉再重新 add 一遍往往比挑挑拣拣更稳。注意git reset --hard和git reset完全是两回事。前者会连工作区一起清空后者只动暂存区。手快敲错的代价是丢掉没提交的改动这种错误在没有 reflog 保护的情况下基本找不回来因为未提交内容从不进入对象库。3.3 只把某个文件退回历史某个版本有时候你要的不是撤销当前改动而是这个文件的内容回到三天前那次提交的样子。命令是git restore --sourcecommit -- file git checkout commit -- file # 等价的传统写法比如git log -- config/app.yml找到那个正常版本的 hash 是a1b2c3d那么git restore --sourcea1b2c3d -- config/app.yml就能把这个文件的内容拉回到那个版本并且自动放进工作区和暂存区。注意它只改这一个文件其它文件不受任何影响HEAD 也不会动。这条命令我常用在两个地方。一是排查问题时把配置回退到某个正常状态做对比测试二是线上出故障后只想快速把出问题的那个文件先改回去止血其它的改动后面再慢慢处理。做完之后记得 commit 一条新提交否则下次别人拉代码还是错的。如果你更想直接看历史的完整内容、手动复制几行出来用git show a1b2c3d:config/app.yml把内容打到终端就行不会动任何文件。这个只读操作在排查场景里更安全。3.4 文件早就被删了怎么从历史里翻出来有一种情况更棘手文件已经被删除而且删除的那个提交可能过了好几周你连它叫什么名字都记不太清了。这时候需要靠日志搜索git log --diff-filterD --summary # 列出所有被删除的文件 git log --diff-filterD --name-only --oneline | grep 关键词 git log --all --full-history -- **/文件名*第一行会把所有删除操作和对应的文件名列出来第二行用关键词过滤。第三行的写法稍微特殊--all让 git 在所有分支里找--full-history要求它不要因为历史简化而漏掉某些提交**/文件名这种通配写法能匹配任意目录层级下的同名文件。这几种组合我基本都试过最麻烦的情况是文件被重命名之后又删除那就得先用git log --follow -- 当前路径把改名历史还原出来再顺藤摸瓜找到删除点。找到删除前的最后一个 commit 之后用上面 3.3 的命令把它恢复出来就行。恢复出来的文件会带着删除前的内容等于一次完整的从坟墓里挖出来。4. 提交级别的回退写错信息、提交早了、提交多了到了提交这一层事情就变得复杂一些因为你要动的是历史记录本身。动历史之前必须先回答一个问题这些提交有没有推到共享分支上。答案不同方案完全不同。4.1 git commit --amend只改最近一条别越界--amend干的事情是把当前暂存区的内容合并进最近一次提交然后生成一个全新的 commit 替换掉旧的。典型用法有两个git commit --amend -m 修正后的提交信息 git add forgotten-file.txt git commit --amend --no-edit第一个是改提交信息第二个是把忘记加的文件补进上一次提交--no-edit表示信息不改。执行完之后git log里看到的还是一条提交但它的 hash 已经变了。这里最容易踩的坑是--amend只能改最近一次。有人以为可以git commit --amend去改三条之前的提交结果发现命令报错或者改错了地方。要改更早的提交就得用交互式 rebase命令是git rebase -i HEAD~3把想改的那条前面的pick改成edit或者reword。这个操作风险等级高不少涉及重排整个历史行如果这期间有别人从你的分支拉了代码冲突会很难受。还有个时间点要记牢--amend之后如果这个提交之前已经 push 过那么新的提交和远端的旧提交就分叉了直接 push 会被拒绝需要强制推送。所以我的习惯是只要这个提交在别人的机器上出现过就坚决不用--amend改用revert或者补一条新提交。4.2 git reset 的三种模式选错就是灾难git reset是回退提交的主力也是事故高发区。它有三种模式区别在于撤销 HEAD 指针这一步之外还动不动暂存区和工作区。模式HEAD 指针暂存区工作区适用场景--soft回退保留改动保留改动想重新组织提交把几个提交并成一个--mixed默认回退重置保留改动提交内容有问题想重新 add 一遍--hard回退重置重置彻底放弃这段改动回到某个干净状态我的选择逻辑是想保留全部改动重新提交用--soft想保留文件内容但重新挑选哪些进暂存区用--mixed确定这些改动一个都不要了才用--hard。举个真实例子。我曾经在一个分支上连提了三个 commit内容都是给同一个功能做的一点点调整review 的时候被要求合成一条。做法是先记下最前面那个提交的 hash或者用HEAD~3表示回退三步git reset --soft HEAD~3 git status git commit -m 完整的功能实现--soft的好处是三个 commit 的文件改动全部原样留在暂存区你直接重新提交就行不会有任何内容丢失。如果用--mixed改动会掉到工作区还得重新git add多一步如果用--hard三个提交的内容就全没了只剩 reflog 能救。再说一个参数计算上的细节。HEAD~3和HEAD^3不是一回事。~表示沿着第一父提交往上数几代^表示第几个父提交合并提交才会有多个父提交。日常回退用~n就对了HEAD~1和HEAD^等价。写HEAD~3表示回退到当前提交往前数三代的那个提交也就是丢弃包含当前在内的三个提交。4.3 回退之后想反悔ORIG_HEAD 是第一道防线reset --hard敲下去之后大脑一片空白这种体验相信不少人有。先别慌git 在大多数危险操作后都会把操作前的 HEAD 存进ORIG_HEAD。你可以这样试git reset --hard ORIG_HEAD如果刚刚那次危险操作没有被后续操作覆盖这条命令能把你直接拉回来。ORIG_HEAD的存在感很低但关键时刻真的能救命值得记一下。不过它只有一份连续做两次危险操作就会被覆盖。更可靠的兜底是git reflog这个放到第 6 节详细讲。这里先建立一个概念只要对象还在丢失的提交就找得回来reset --hard丢失的只是指针位置不是数据本身。4.4 git revert生成一条反向提交而不是抹掉历史revert和reset的思路完全相反。reset是时光倒流让历史里那条提交好像从没发生过revert是承认它发生过然后新提交一条内容相反的改动去抵消它。git revert commit git revert --no-commit commit # 只改工作区不自动提交 git revert -m 1 merge-commit # 撤销一个合并提交-m 1 表示保留第一父提交那条线最后那条撤销合并提交的写法值得单独说一下。合并提交有两个父-m 1的意思是以第一父提交通常是你合并进来的目标分支为主线把另一条线带来的改动全部抵消。这个参数不写就会报错因为 git 不知道该以哪条线为基准。撤销合并是个高级操作撤销之后再想把这条分支合并回来会遇到麻烦因为 git 会认为这个分支的改动已经被合并过了后面的合并可能什么也不做。遇到这种情况通常需要revert掉那条 revert或者用git rebase --rebase-merges重新处理比较绕。revert的最大价值在于它对共享历史友好。因为它只是新增提交不改变已有提交的 hash别人拉代码不会有任何冲突push 也不需要强制推送。凡是已经推到公共分支的提交我基本都走revert这条路哪怕它会在日志里留下撤销某某这么一条记录看起来不够干净但安全。5. 已经推送到远端之后的回退与团队协作本地怎么折腾都是自己的事一旦涉及远端回退的后果就从影响我一个人变成影响所有拉这个分支的人。这一节的重点不是命令而是判断和约定。5.1 为什么远端回退要格外小心远端分支的本质是大家约定的一个共同基准。你用reset加强制推送把远端也倒回去等于单方面改了这个约定。其他同事本地可能已经基于旧提交做了新提交他们下次 pull 的时候就会遇到分叉要么被迫处理合并冲突要么不得不放弃自己的本地修改。如果这个人不太懂 git最常见的反应是直接删掉自己的本地分支重新拉那他没推的改动就全没了。所以在我待过的团队里有个不成文的规矩主干分支和发布分支永远只允许revert不允许强制推送只有个人特性分支可以随意 reset。这个约定的好处是所有人都知道历史只会前进不会出现昨天拉的代码今天 hash 全变了这种事。5.2 强制推送前的自保动作如果确实需要改写远端历史比如个人分支上提交了一堆乱七八糟的调试信息想整理干净再推。这时候如果必须强制推送用--force-with-lease而不是--forcegit push --force-with-lease origin feature/xxx两者的区别在于--force是不管三七二十一直接覆盖远端--force-with-lease会先检查远端当前指向的提交是不是你本地记录的那个如果不是说明有别人推过东西上来就直接拒绝。这个检查能挡住绝大多数覆盖掉同事提交的事故。推送之前还有两个自保动作值得养成习惯。第一先把当前状态打个备份分支git branch backup-20240601这样即使后面操作乱套了也能从备份分支捞回来。第二把 reflog 或者当前分支的 hash 记在便签上git rev-parse HEAD就是当前提交的完整 hash。注意备份分支不要留着太久。有些团队的分支列表里堆了几十个 backup 开头的老分支既影响别人查找也容易被误推。确认没问题后及时删掉。如果远端设了分支保护强制推送会直接被服务器拒绝报错里通常有protected branch之类的字样。这不是坏事说明有人提前给你设了护栏。5.3 反悔的反悔撤销一条 revertrevert之后发现撤错了想恢复思路也是revert——把那条 revert 提交再 revert 一次。因为 revert 提交本身就是一条普通提交它记录的是把 A 的改动反向应用那么再对这条反向提交做一次 revert等于把 A 的改动又应用回来。git log --oneline -5 # 找到那条 revert 提交的 hash git revert revert-commit-hash这种方式在共享分支上是安全的因为它同样只新增提交不改历史。代价是日志会变得有点像绕口令一条撤销了撤销某某功能的提交的记录。我的做法是提交信息写清楚比如Revert Revert 调整订单超时时间并且在提交正文里说明为什么又改回来给后来看日志的人留个线索不然半年后自己都看不懂。6. 最后的兜底reflog 与悬空对象前面所有操作里最让人安心的其实不是某条命令而是 reflog 这个东西的存在。理解了它你在做任何回退操作的时候心态都会不一样因为你知道最坏情况下还有退路。6.1 reflog 到底记录了什么reflog 记录的是 HEAD 和各个分支引用每一次移动的历史。你每做一次 commit、reset、checkout、merge、rebase它都会在里面写一行包含旧 hash、新 hash、操作类型和时间。执行git reflog或者git reflog show HEAD就能看到a1b2c3d HEAD{0}: reset: moving to HEAD~2 9f8e7d6 HEAD{1}: commit: 添加订单校验 5c4b3a2 HEAD{2}: commit: 修复支付回调注意它是本地记录跟着你的仓库走不会被 push 到远端别人也看不到。默认情况下这些记录保留 90 天不可达的对象就是没有引用指向、但 reflog 里还留着的提交保留 30 天。所以昨天删的东西今天还能救是有保障的只要期间没手动跑过激进的 gc。用法非常直接找到你想回到的那一行记下 hash然后git reset --hard hash或者git checkout hash看一眼再决定。比如不小心reset --hard退过头了git reflog里通常第一行就是刚才那次 reset 操作第二行就是 reset 之前的 commit直接 reset 回去就行。6.2 误删分支、reset 过头之后的抢救路径分支被删了而且删的时候用的还是-D很多人以为彻底没了。其实分支只是一个指向 commit 的标签删标签不等于删提交只要 reflog 里还有那个分支的记录git reflog # 找到被删分支最后一次的 commit hash git branch 恢复的分支名 hash或者直接git checkout -b 新分支名 hash效果一样。关键是别在删完之后跑git gc --prunenow这类命令那会把不可达对象真的清掉。另一种常见情况是git reset --hard退太多步。处理思路和上面一样先git reflog找到退之前的位置resize 回来。如果 reflog 也找不到比如换了台机器、或者本地仓库是全新 clone 的那就只能看远端还有没有git log --all --oneline扫一遍所有分支或者到 GitLab、Gitee 这类平台的事件记录里翻一翻。6.3 用 fsck 找出悬空提交有些极端情况 reflog 里也翻不到比如引用被清理过但对象其实还躺在对象库里。这时候可以用底层命令扫一遍git fsck --lost-found git show dangling-commit-hash--lost-found会把找到的悬空对象写进.git/lost-found/目录悬空提交放在commit/子目录里。你逐个git show看看内容找到需要的那条再用git branch把它挂回一个分支上。这个操作我实际用过两次一次是同事在 rebase 出错后直接把.git里的临时引用删了一次是某个仓库做过手工修复。频率很低但知道有这条路心里踏实。它也是理解 git 存储模型最好的方式之一你亲眼看到提交对象在没有任何引用指向它的时候依然存在就能真正理解git 回退丢的是指针不是数据这句话。7. 常见报错速查与避坑清单最后把这几年遇到的高频报错和我自己总结的注意事项整理出来回退出问题时对照着看多数情况能快速定位。7.1 高频报错对照表报错信息常见原因处理方式fatal: not a git repository当前目录不在任何仓库里或者.git被删cd到正确目录或从远端重新 cloneerror: pathspec ... did not match文件名写错、路径层级不对、中文路径被转义开core.quotepathfalse用git status复制准确路径Your local changes would be overwritten目标文件有未提交改动回退会覆盖先 commit 或 stash再执行回退Updates were rejected because the remote contains work远端有你本地没有的提交先 pull --rebase或确认后再考虑强制推送fatal: refusing to merge unrelated histories两个仓库历史没有共同祖先确认情况后用--allow-unrelated-historiesdetached HEADcheckout 到了具体 commit 而不是分支想保留改动就git switch -c 新分支想放弃就切回原分支Cannot do a soft reset in the middle of a merge合并冲突未处理完就想 reset先git merge --abort或解决冲突login failed. check api token or gitlab version认证凭据问题不是回退问题重新配置凭据或使用免密方式detached HEAD这个状态特别需要提醒。你git checkout commit去看历史版本的时候HEAD 就会处于游离状态这时候提交的代码不属于任何分支切走之后就很容易找不到。如果只是看看看完直接git switch -切回原分支就行。如果想在历史版本基础上干活第一件事就是git switch -c 临时分支名给它建个分支。7.2 我踩过的坑与实操心得第一条心得是关于时机的。回退的最佳时机是刚发现错误、还没做其它操作的时候越早处理越简单。很多人发现提交错了先手忙脚乱地去改文件、又提了一条、又 rebase 了一下结果历史被搅成一团本来一条revert能解决的事情变成要花半小时理清。所以我的建议是发现错误先停手git log和git status看清楚了再动。第二条是关于人心的。回退操作里最危险的不是命令本身而是我以为我懂了。reset --hard这个命令被我列为最需要敬畏的一条每次敲之前我都会多看一眼git status确认工作区里没有我没保存的东西。养成危险命令先看一眼状态的习惯能避免大部分后悔。第三条是关于协作沟通的。如果回退涉及别人正在使用的分支先打个招呼比事后解释成本低得多。我经历过一次同事直接强推主干导致另一个人的半天工作要重新处理最后虽然数据都找回来了但浪费的时间和信任是实打实的。现在我的做法是凡是涉及公共分支的历史改动先在群里说一句我要 revert 某条提交影响范围是什么几分钟的事。第四条是关于备份的。在不确定的操作之前建一个临时分支这个动作只要三秒钟却能在最坏情况下省几个小时。我的命名习惯是bak/日期-用途做完确认没问题就删掉不留垃圾。最后一条是关于工具选择的。图形化工具在看这件事上确实强日志树、文件差异展示得比命令行清楚我能理解很多人习惯用 TortoiseGit 或者 IDE 面板。但涉及 reset、rebase、reflog 这些需要精确控制的场景还是建议回到命令行看清楚每个参数的语义。一个比较稳妥的组合是用图形工具定位和确认用命令行执行。这两者搭配起来既直观又可控是我这些年用得最顺的方式。
返回列表