Skip to content

03 · 日常改代码与提交

一天里用得最多的一层:把工作区的改动,有选择地变成一次 commit。

git status

作用: 显示当前分支、与上游的 ahead/behind、工作区与暂存区差异、未跟踪文件、进行中的 merge/rebase。

改动范围: 只读。

典型场景: 每次 add / commit / 切分支之前先看一眼;冲突中看还剩哪些文件没解决。

常用写法:

bash
git status
git status -sb          # 短格式,适合配 alias.st
git status --untracked-files=all

不要这样用: 看都不看就 git add .commit。密钥、调试打印、本地配置很容易混进去。

做错了怎么办: 这条命令不会做错。输出看不懂时,对照 00 章三区图

git add

作用: 把工作区改动写入暂存区,为下一次 commit 做准备。

改动范围: 暂存区。工作区文件不动。

典型场景:

  • 只提交其中一个文件,其它半成品留着。
  • 一个文件里既有功能又有调试,用 -p 一块一块挑。
  • 批量暂存已跟踪文件的修改,但不把新的未跟踪垃圾加进去。

常用写法:

bash
git add src/login.ts
git add -p                  # 交互挑选 hunk
git add -u                  # 已跟踪文件的修改和删除,不含新文件
git add .                   # 当前目录往下所有改动(受 .gitignore 约束)

不要这样用: git add . 之前不看 status;在仓库根目录把 .env、大二进制、IDE 文件一起加进去。

做错了怎么办: 多暂存了,撤出暂存区、保留工作区改动:

bash
git restore --staged src/login.ts
# 旧写法:git reset HEAD src/login.ts

git commit

作用: 把暂存区拍成一次新的 commit,移动当前分支指针和 HEAD。

改动范围: 本地历史。不自动推远程。

典型场景: 完成一个可审查的小步骤:修一个 bug、加一个函数、改一处文案。

常用写法:

bash
git commit -m "fix: 拒绝空密码登录"
git commit                    # 打开编辑器写更长说明
git commit -am "fix: ..."     # 把已跟踪文件的改动一并 add 再 commit;新文件不会被加进去

好的说明:写「做了什么、为什么」,不写「改了点东西」。团队若有 Conventional Commits,跟着用 feat: / fix: / chore:

不要这样用:

  • git commit -a 漏掉刚新建的文件还以为提交全了。
  • git commit --amend 去改已经 push 且别人可能基于它开发的提交。

git commit --amend(改最后一次提交)

作用: 用「当前暂存区 + 新的提交说明」替换最新一次 commit(SHA 会变)。

改动范围: 改写本地历史(最新一颗)。

典型场景(仅限该提交尚未 push,或你确定只有自己在用这条分支):

  • 说明写错了。
  • add 了一个文件。
bash
git add 漏掉的文件
git commit --amend --no-edit     # 只补文件,不改说明
git commit --amend -m "新的说明" # 改说明

不要这样用: main 上已经 push 的提交拿去 amend,再 push --force。同事的历史会分叉。

做错了怎么办: amend 之前的那颗 commit 还在 reflog:

bash
git reflog -10
git reset --soft HEAD@{1}        # 回到 amend 前,改动仍在暂存区

详见 急救手册 · 提交说明写错 / 漏文件

git restore

作用: 从指定来源恢复文件到工作区和/或暂存区。专门负责「文件」,不负责「切分支」。

改动范围: 工作区和/或暂存区。默认不移动 HEAD。

典型场景:

  • 这个文件改砸了,回到最后一次提交。
  • 暂存多了,撤出暂存但代码留着。
  • 对比其它分支上的同名文件,把某文件换成那边的版本。

常用写法:

bash
# 丢弃工作区改动,回到 HEAD(暂存区不受影响)
git restore src/login.ts

# 撤出暂存区,工作区保留
git restore --staged src/login.ts

# 暂存区和工作区都回到 HEAD(等价于丢掉该文件未提交的全部改动)
git restore --source=HEAD --staged --worktree src/login.ts

# 把某文件恢复成 main 上的样子
git restore --source=main src/login.ts

旧写法对照:

现在以前
git restore 文件git checkout -- 文件
git restore --staged 文件git reset HEAD 文件

不要这样用: 对未 add 过的新文件执行 restore 期望「找回刚才删的内容」——未跟踪文件不在 Git 里。想清未跟踪文件用 clean,那是删除不是恢复。

做错了怎么办:

  • 只是 --staged:工作区还在,再 add 回去。
  • 已经 restore 丢掉工作区:若曾经 add 过,blob 可能还能用 git fsck --lost-found 碰运气,见 急救手册。从未 add 的,看编辑器 Local History / 回收站。

git rm

作用: 从工作区和暂存区删除文件,下次 commit 会记录删除。

改动范围: 工作区 + 暂存区。

典型场景: 这个源文件确定不要了;或者只要停止跟踪(--cached)。

常用写法:

bash
git rm src/obsolete.ts
git rm -r docs/old/
git rm --cached secrets.env      # 停止跟踪,磁盘文件留下

不要这样用:git rm 和资源管理器删除混着用,又不 status,最后一次提交里漏删或误删。

做错了怎么办: 还没 commit:

bash
git restore --staged --worktree src/obsolete.ts

已经 commit 但未 push:git reset --soft HEAD~1 或再把文件从上一提交检出。已 push:再提交一次把文件加回来,或 revert 那次删除提交。

git mv

作用: 重命名或移动已跟踪文件,并一次性放进暂存区。

改动范围: 工作区 + 暂存区。

典型场景: 文件改名、目录调整。等价于「重命名 + git add 旧路径和新路径」,Git 之后靠相似度检测把它显示成 rename。

bash
git mv src/login.ts src/auth/login.ts
git commit -m "refactor: 移动登录模块"

直接在资源管理器改名也可以,再用 git add -A,效果类似。git mv 只是少一步。

做错了怎么办:git mv 回去,或 git restore --staged --worktree 后手动改回。

git clean · 危险

作用: 删除未跟踪文件(和可选的目录)。不动已跟踪文件。

改动范围: 工作区里 Git 不认识的文件。删了 Git 救不回。

典型场景: 构建产物、误生成的大文件、跑测试留下的垃圾。想要一个「和最新提交一模一样的工作区」。

常用写法(务必先演练):

bash
git clean -n            # dry-run:只打印会删什么
git clean -nd           # 连将要删的目录一起预览
git clean -fd           # 真删:未跟踪文件 + 目录
git clean -fdx          # 连被 ignore 的也删(node_modules 等会没)

不要这样用: 不看 -n-fd / -fdx。新建了半天还没 add 的源文件会一起消失。

做错了怎么办: Git 无能为力。立刻去:

  1. 编辑器的 Local History / Timeline
  2. 系统回收站
  3. 云盘或备份

预防:不确定的先 git addgit stash -u 再 clean。完整说明见 急救手册 · clean

一条建议工作流

bash
git status -sb
git diff                    # 看没暂存的
git add -p
git diff --staged           # 看即将提交的
git commit -m "..."
git status -sb              # 确认干净或只剩有意留下的改动

需要和远程同步时再去 07 章。想扔掉「已经 commit 但还没 push 的几笔」,用 06 章的 reset,不要在这里 clean


上一章:02 · 创建与克隆 · 下一章:04 · 查看状态、差异与历史