3、Git进阶操作:文件撤销、版本回退、删除文件、移动文件、忽略文件

好,咱们继续往前走。上一章我们把Git的基本操作捋了一遍,add、commit、push这些你应该已经玩熟了。但说实话,日常开发中真正让你头疼的,往往是那些「哎呀手滑了」、「完了改错了」、「这个文件不该提交」的瞬间。

这一章,我就带你把这些「后悔药」吃明白。说白了,Git的进阶操作就是教你如何优雅地犯错,再优雅地收场。

本章核心:学会在Git中撤销、回退、删除、移动和忽略文件,掌握这些操作后,你基本能应对90%的日常场景。

Git进阶操作知识体系 Git进阶操作 文件撤销 版本回退 删除文件 移动文件 忽略文件 (.gitignore) git checkout git restore git reset git revert git rm git mv 重命名 *.log / node_modules

3.1 文件撤销:把改错的东西变回去

先聊聊文件撤销。这可能是你用得最频繁的操作之一。你想想看,写代码哪有不手滑的?

我个人习惯把撤销分成两种情况:还没add的已经add的。这两种的处理方式完全不同。

3.1.1 撤销工作区的修改(还没add)

假设你改了一个文件,改到一半发现方向错了。这时候文件还在工作区,没执行过git add。怎么办?

# 撤销单个文件的修改
git checkout -- filename

# 或者用新版Git的推荐写法
git restore filename

嗯,这里要注意。git checkout -- filename这个命令,会把文件恢复到最近一次git commit时的状态。你做的所有修改都会丢失,所以用之前一定要确认——你真的不想要这些改动了。

⚠️ 警告:git checkout -- 会直接覆盖文件,无法撤销。如果你只是不确定要不要改,建议先 git stash 暂存起来,给自己留条后路。

3.1.2 撤销暂存区的修改(已经add了)

如果你已经git add了,但还没commit,这时候想撤销怎么办?

# 把文件从暂存区移回工作区
git reset HEAD filename

# 新版Git写法
git restore --staged filename

这个操作只是把文件「请出」暂存区,文件内容不会丢失。它还在工作区里等着你重新考虑。

我曾经有一次在项目上线前,不小心把一个调试用的配置文件给add了。还好及时发现,用git reset HEAD把它撤了回来。你想想看,要是那个文件被commit甚至push上去,后果不堪设想。

3.2 版本回退:坐时光机回到过去

版本回退,说白了就是让整个项目回到某个历史状态。这个功能在Git里做得非常优雅。

3.2.1 查看历史版本

回退之前,你得先知道有哪些版本可以回。用git log查看提交历史:

# 查看简洁版历史
git log --oneline

# 查看带图形的历史
git log --oneline --graph --all

输出大概长这样:

a1b2c3d (HEAD -> main) 修复登录bug
e4f5g6h 新增用户注册功能
i7j8k9l 初始化项目

每个commit前面那串字符(比如a1b2c3d)就是版本号。记住它,回退就靠它了。

3.2.2 两种回退方式:reset 和 revert

这里有个重要的概念区分。我刚开始用Git时也搞混过,所以特意拿出来讲。

操作 命令 特点 适用场景
硬回退 git reset --hard HEAD~1 直接删除历史,回退后的commit会消失 本地分支,还没push
软回退 git reset --soft HEAD~1 保留修改内容,只移动HEAD指针 想重新commit
安全回退 git revert HEAD 生成一个新的commit来抵消旧commit 已经push到远程的分支
# 回退到上一个版本(硬回退)
git reset --hard HEAD~1

# 回退到指定版本
git reset --hard a1b2c3d

# 安全回退(生成新commit)
git revert HEAD

💡 我的建议:如果分支已经push到远程了,千万别用 git reset --hard 然后强行push。团队其他人会恨你的。用 git revert 更体面。

为什么会这样?因为git reset会改写历史,而git revert是在历史后面追加。你想想看,如果别人已经基于你的commit做了开发,你突然把历史删了,他那边会乱成一锅粥。

3.3 删除文件:不只是删掉那么简单

删除文件看起来简单,但在Git里,你得告诉它「我是故意删的」。

3.3.1 用 git rm 删除

# 删除文件并自动记录到暂存区
git rm filename

# 删除整个目录
git rm -r directory/

这个命令做了两件事:一是从磁盘上删除文件,二是把这次删除操作记录到暂存区。下次commit时,Git就知道这个文件被移除了。

如果你只是手动在文件管理器里删了文件,Git会检测到「未跟踪的变化」。这时候你需要:

# 手动删除后,告诉Git确认删除
git rm filename

# 或者用 add 命令也能识别删除
git add -u

3.3.2 只从Git中删除,保留本地文件

有时候你不想让Git继续跟踪某个文件,但文件本身还想留着用。比如一些配置文件,你提交过一次示例后,后续不想再跟踪它的变化。

# 从Git中移除跟踪,但保留本地文件
git rm --cached filename

这个操作很实用。我记得有一次,项目里有个config.local.js文件,每个人本地配置都不一样。我把它提交过一次作为模板,然后用git rm --cached取消跟踪,再添加到.gitignore里。这样大家各自改自己的,互不影响。

3.4 移动文件:改名改位置

移动文件在Git里其实是个组合操作——先复制再删除。但Git贴心地提供了git mv命令,一步到位。

# 重命名文件
git mv oldname.txt newname.txt

# 移动文件到其他目录
git mv file.txt src/utils/

这个命令等价于:

mv oldname.txt newname.txt
git rm oldname.txt
git add newname.txt

我个人习惯直接用git mv,省事。但如果你用IDE的重命名功能,IDE会自动处理好这些,你只需要记得git add一下就行。

注意:Git跟踪的是文件内容,不是文件名。所以即使你改了文件名,Git也能通过内容相似度识别出「这是同一个文件」。用 git log --follow filename 可以查看文件的重命名历史。

3.5 忽略文件:.gitignore 的正确用法

最后聊聊忽略文件。这个太重要了,几乎每个项目都要用。

你肯定不想把node_modules.env、编译产物这些文件提交到Git仓库里。这时候就需要.gitignore文件出场了。

3.5.1 .gitignore 的基本规则

# 忽略所有 .log 文件
*.log

# 但保留 important.log
!important.log

# 忽略 node_modules 目录
node_modules/

# 忽略 build 目录下的所有内容
build/

# 忽略以 temp 开头的文件
temp*

# 忽略 .env 文件(常见于环境配置)
.env

规则其实很简单:

  • * 匹配任意多个字符
  • ? 匹配单个字符
  • ! 取反,表示不忽略
  • / 在末尾表示目录

3.5.2 全局忽略配置

有些文件是跟具体项目无关的,比如.DS_Store(macOS的目录配置文件)、Thumbs.db(Windows的缩略图缓存)。这些可以配置到全局忽略中:

# 设置全局 .gitignore
git config --global core.excludesfile ~/.gitignore_global

然后在~/.gitignore_global里写上:

.DS_Store
Thumbs.db
*.swp
*.swo

💡 避坑指南:我曾经遇到过一个问题——明明在 .gitignore 里写了忽略规则,但文件还是被跟踪了。后来发现,是因为这个文件之前已经被 git add 过。.gitignore 只对「未跟踪」的文件有效。如果文件已经被跟踪,你需要先用 git rm --cached 取消跟踪。

3.5.3 检查忽略规则是否生效

# 查看哪些文件会被忽略
git status --ignored

# 检查某个文件是否被忽略
git check-ignore -v filename

这两个命令在排查问题时特别有用。有时候规则写复杂了,自己都搞不清到底忽略了哪些文件。

小结一下

这一章的内容其实就围绕一个核心思想:Git给了你犯错的权利,也给了你改正的机会。文件撤销让你能反悔未提交的修改,版本回退让你能回到过去,删除和移动文件让你能整理项目结构,忽略文件让你能保持仓库干净。

这些操作单独看都不难,但组合起来就能应对绝大多数日常场景。你只要记住:git restore管撤销,git reset管本地回退,git revert管远程回退,.gitignore管眼不见心不烦。

嗯,差不多就这些。下一章我们会聊分支操作——那才是Git真正强大的地方。


公众号:蓝海资料掘金营,微信deep3321