Git学习(2)撤销与分支操作全指南

发布时间:2026/10/29 11:03:05
Git学习(2)撤销与分支操作全指南

🔥keyipatience:个人主页

🎬作者简介:C/C++后端开发学习者

🌟专栏传送门:《c++》《linux》《c++高阶数据结构》《c++数据结构与算法》《前端学习》

⭐️patience is key in life

Git 撤销修改

情况 1:只改了文件,没有 add(修改只在工作区)

文件改坏了,还没 add,想撤销这一轮改动,恢复到最近一次 add /commit 的样子 命令:

git checkout -- ReadMe # 新版git等价推荐写法 git restore ReadMe

重点:--不能省! 如果写成git checkout ReadMe,git 会理解成【切换到名叫 ReadMe 的分支】,含义完全变了。

作用: 直接把工作区的改动抹掉,文件变回暂存区 / 版本库里保存的样子,刚才新增的内容直接消失。

风险:这个操作直接丢掉你工作区的修改,无法找回,谨慎使用!

情况 2:已经 add,但是还没有 commit(修改在暂存区)

你已经git add ReadMe,修改进到暂存区了,现在后悔,想撤出来 分两步走:

先把修改从暂存区撤回到工作区

git reset HEAD ReadMe # 等价 git reset --mixed HEAD ReadMe,--mixed是默认参数,可以省略 //底层理解HEAD:代表当前最新的 commit 版本库快照,因为还有没有commit所以回退到当前最新的commit版本就是把 暂存区(stage)清空

执行后效果:

暂存区清空文件的内容不变!改动重新回到工作区

接下来二选一:

  • 改一改,重新git add
  • 不想要了,用git checkout -- ReadMe/git restore ReadMe删掉工作区改动

情况 3:已经 add + commit(修改提交进版本库了)

已经 commit,生成一条版本记录,现在想要撤销这次提交

重要前提:这个 commit 还没有 push 推送到远程仓库!如果已经 push 到远端,不能随便用--hard回退!(后面学远程会讲)

命令:

git reset --hard HEAD^
  • HEAD^当前版本的上一个 commit
  • --hard:同时改动三处:版本库指针、暂存区、工作区执行完:HEAD 指针挪到上一个版本,暂存区清空,工作区直接变成上个版本的样子,本次 commit 写的内容本地消失。

一张汇总表

场景状态目标命令
1修改仅在工作区,未 add丢掉工作区修改git checkout -- 文件名/git restore 文件名
2已经 add,未 commit取消暂存(退回工作区)git reset HEAD 文件名
2 续取消暂存后,想彻底删掉修改丢掉工作区修改git checkout -- 文件名
3add + commit,未 push 远程回退到上一个版本,删掉本次提交git reset --hard HEAD^

文件名和HEAD系列分清楚

  • 写HEAD:撤回提交(管整条记录)
  • 写文件名:只取消 add(只管这一个文件,不碰提交)

想撤回【整个 commit 提交】

后面写:HEAD、HEAD^、一串 commit 哈希号,作用:把这一次提交给撤掉,改提交历史。这里不带文件名!管的是整条提交记录。

git reset --soft HEAD^ git reset --hard HEAD^

后面写:文件名

git reset [HEAD] file2.txt//[HEAD可以省略]

刚才git add file2.txt加到暂存区了,现在把它拿出来。不会撤销 commit,不会改动提交历史

Git 删除文件

在 git 眼里,删除文件 = 也是一种修改,需要 add /commit 记录这个删除动作

直接用 linux 的rm file5(只删工作区)

rm file5

效果:

  • 本地磁盘(工作区)file5 删掉了
  • 版本库、暂存区里还保留这个文件
  • git status提示:deleted: file5(红色,Changes not staged for commit)

问题:git 只是发现你在本地删了,但是还没有把 “删除这件事” 登记到版本库里。 现在分两条路:删错了 | 确实要删掉

情况 A:删错了!想要恢复回来

刚才只是rm file5,还没执行git rm、没 commit 用之前学过的撤销工作区修改命令:

git checkout -- file5 # 新版等价:git restore file5

从版本库把 file5 拿回来,恢复到工作区,ls 又能看到 file5 了。

情况 B:确实想要把文件从版本库删掉

git rm file5

它一次性做两件事:

  1. 删除工作区的 file5(如果还在的话)
  2. 把【删除 file5】这个动作加到暂存区

git rm≠ linux 的 rm linux rm:只动本地磁盘git 不知情

git rm:同时操作工作区 + 暂存区,告诉 git:我要删除这个文件


然后必须 commit,这个删除才正式写入版本库:

git commit -m "deleted file5"

文件已经加到暂存,想只从暂存区删掉、本地保留(不是真删文件)

git rm --cached file5
  • 本地磁盘 file5还在
  • 只把它从暂存区 / 版本追踪里移除(一般用来取消跟踪,比如误 add 了大文件和reset效果一样)

Git 分支基础

分支 = 平行宇宙

主线(master)是一条时间线;从某个提交点分出新分支,就开出一条独立时间线,分支之间互不干扰,可以在不同分支写不同代码,后面还能合并。

例子:master 主线正常开发;开新分支写新功能,写完再合并回主线。

master和HEAD

  • master指向最新提交
  • HEAD指向当前所在分支(只有一个)

master是主分支指针,指向这个分支上最新的一次提交。每commit一次,master就自动向后移动一步。HEAD是当前所在分支的标记,先指向master,再由master指向最新提交。

HEAD → master → 最新提交

Git 创建分支

git branch # 查看本地所有分支,带 * 的是当前分支 git branch dev # 新建 dev 分支(只创建,不切换过去)

执行完git branch dev之后:

  • 分支列表:dev、* master→*代表 HEAD 当前在 master
  • 去.git/refs/heads/目录下看:会多出一个dev文件
ls .git/refs/heads/ cat .git/refs/heads/*

master 和 dev 两个文件里存的 commit hash 值一模一样,说明:刚创建出来的 dev 和 master 指向同一个提交节点

git branch dev只是新增一个指针,不会复制文件、不会新建提交,非常轻量,这是 Git 分支高效的核心原因。

Git 切换分支 + 分支独立提交

切换分支命令

git checkout dev # 等价新版推荐写法:git switch dev

执行后输出:Switched to branch 'dev'

  • 查看分支:git branch,*跑到 dev 前面,代表当前分支是 dev
  • 底层验证 HEAD:
cat .git/HEAD # 输出 ref: refs/heads/dev

原理:HEAD 指针移动,指向 dev 分支

原理图变化:HEAD → dev,master 指针还停留在原来那个提交上不动。

在 dev 分支做修改并提交

vim ReadMe # 修改文件,新增一行 write aaa for new branch git add . git commit -m "modify ReadMe"

提交成功提示:[dev 274bdce] modify ReadMe

  • 这个提交只会让 dev 分支指针向前移动一步
  • master 指针原地不动,不会跟着更新

底层查看两个分支指向的 commit 哈希:

cat .git/refs/heads/dev # 拿到新的 commit id(刚提交的) cat .git/refs/heads/master # 还是原来旧的 commit id

核心:两个分支指针现在指向不同提交节点,两条分支历史开始分叉

切回 master 分支,现象:新增内容消失

git checkout master

注意:如果dev 改了文件,不 add、不 commit,切回 master,新加内容还在!

因为这个改动还没有存入 Git 的版本库,不在任何分支、不在任何提交里,它只躺在你的本地工作目录。 Git 在切换分支的时候:

  • 先检查:工作区有没有未暂存、未提交的修改
  • 如果:切换前后的两个分支,这个文件没有版本差异Git 就不会覆盖你的改动,直接把这份修改保留、带到目标分支

查看 ReadMe:刚才新增那一行不见了! 再切回去 dev:

git checkout dev

ReadMe 新增内容又回来了

为什么会这样?

  • 这次提交是在 dev 分支上做的,master 分支根本没有包含这次提交;
  • 切换到 master 时,Git 将工作区恢复成 master 指向的那个旧提交对应的文件版本;
  • 切换回 dev,Git 又把工作区换回 dev 最新提交的文件快照。

Git 合并分支(Fast-forward 快进合并)

承接前面流程:dev 分支比 master 多了一次提交,现在要把 dev 的改动合并进 master。

整套命令流程

git branch # 查看当前分支,现在在 dev git checkout master # 先切到 master,合并是【把别的分支合并到当前分支】 git merge dev # 将 dev 合并到 master

输出关键信息:

Updating 16623e1..3740dce Fast-forward ReadMe | 1 + 1 file changed, 1 insertion(+)

查看 ReadMe:master 里面也出现了 dev 新增的那一行内容。

重点规则:git merge [分支名]的含义:把指定分支合并到【你现在所在的分支】,所以合并前一定要先切到目标分支(这里是 master)。

Fast-forward(快进模式)是什么

原理图变化: 合并前:

  • master 停在旧提交点
  • dev 在 master 的正前方,顺着一条线往前走了一次提交

快进合并的时候:Git不产生新的提交记录,只是直接移动 master 指针(所以我们不好区分到底是merge让指针移动一步还是在master分支上commit一次让指针移动),让 master 指向和 dev 同一个提交节点。

所以快进合并没有生成新提交,merge 命令执行完就结束了,不用再敲git commit。

Git 删除分支

命令

git branch -d dev

d=--delete,安全删除分支。

两个硬性规则

1.不能删除当前所在的分支* 例子:现在在 dev(* dev),执行git branch -d dev

error: Cannot delete branch 'dev' checked out at 'xxx'

2.正确做法:先切到别的分支(一般切 master/main),再删

git checkout master git branch -d dev

-d安全删除的底层限制

git branch -d是安全模式:Git 会检查:这个分支的所有提交,是不是已经被别的分支合并、能访问到了。

  • 像如果:dev已经合并进 master→ 可以-d删除
  • 如果 dev 独有的提交,还没有合并进主分支,直接-d会拒绝删除,防止你丢提交!

大写-D强制删除(危险!)

git branch -D dev

-D = --delete --force

不管分支有没有合并、有没有独有的提交,直接删掉分支指针。

Git 鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在 master 分支上工作效果是一样的,但过程更安全。

即:

  • 开发新功能、改 bug:新建 dev 分支干活
  • 测试没问题,合并到主分支 master
  • 合并完成,dev 使命结束,删除它 好处:master 全程保持干净稳定,开发过程中的错误、半成品不会污染主分支