平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“git提交时怎么只选部分修改?手把手教你精准暂存”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。
结合项目来看,从普通目录完成第一次本地提交同时不难,但真实开发很少一直保持“只修改一个文件,然后立即提交”的理想状态。
写一个功能时可能同时出现:
- 当前真正要提交的代码;
- 顺手修改但应单独提交的文档;
- 运行程序产生的日志;
- 只属于本机的环境设置。
这时,add 和 commit 本身同时不难,真正需判断的是:
哪些变化属于这次提交,哪些应该留在外面?
四个检查窗口
一次提交前后,能够从四个角度观察仓库:
| 想知道什么 | 命令 |
|---|---|
| 哪些路径发生了变化,分别位于哪一层 | git status --short |
| 工作区相对暂存区还有哪些具体变化 | git diff |
| 暂存区相对当前提交准备记录什么 | 实际处理时,git diff --cached,也能够采用 git diff --staged |
| 提交完成后形成了什么历史 | git log --oneline、git show |
status 先告诉我们“哪里有变化”,diff 再说明“内容怎样变化”,log 和 show 用来提交后核对已经形成的记录。
准备独立实验仓库
实际处理时,下面的初始化和第一次提交只用来建立可复现的前置状态。如果本地已有同名目录,请换一个新名字。
mkdir commit-check-lab
cd commit-check-lab
git init
git config user.name "Git Blog Lab"
git config user.email "[email protected]"
printf "login validationn" > app.txt
printf "old documentationn" > README.md
git add app.txt README.md
git commit -m "chore: initialize commit check lab"
现在仓库有一个初始提交,工作区是干净的。
先处理不应进入仓库的文件
在这个场景下,运行程序时经常产生日志,本地开发也可能需只属于个人环境的设置。先制造两个未跟踪文件:
printf "debug outputn" > debug.log
printf "local development configurationn" > .env
git status --short
输出会包含:
?? .env
?? debug.log
落到代码里,它们都是工作区中的未跟踪文件。如果直接执行 git add .,就可能把它们一起放入暂存区。
在仓库根目录新建 .gitignore:
printf "*.logn.envn" > .gitignore
git status --short
现在输出中不再显示 debug.log 和 .env,只会出现新的 .gitignore:
?? .gitignore
忽略规则本身是项目约定,应该进入版本历史:
git add .gitignore
git commit -m "chore: ignore logs and local environment files"
.gitignore 的两个边界
第一,.gitignore 主要影响尚未被跟踪的路径。文件如果已经进入提交,后来补写忽略规则不会自动停止跟踪。
若误跟踪的是普通日志或本地生成文件,能够在写好忽略规则后停止跟踪:
git rm --cached <文件>
git add .gitignore
git commit -m "chore: stop tracking generated file"
--cached 会把删除记录放入暂存区,但保留本地工作区文件。目录需配合 -r 采用。执行后应先用 git status 确认暂存内容,再提交这次规则变更。
实际处理时,第二,忽略规则不是凭据泄露后的补救工具。密钥、Token 或密码一旦进入历史,应立即轮换或作废,再根据团队流程处理仓库历史。仅仅删除文件或补写 .gitignore,不能让已经泄露的值失效。
制造一个混合修改现场
printf "check empty usernamen" >> app.txt
printf "new usage examplen" >> README.md
printf "another debug linen" >> debug.log
git status --short
输出:
M README.md
M app.txt
debug.log 仍存在于本地,但因为匹配 .gitignore,不会出现在普通状态结果中。
git status --short 在文件名前采用两个位置显示状态,能够写成:
XY 文件名
- 第一个位置
X:已经进入暂存区的变化; - 第二个位置
Y:仍在工作区、尚未暂存的变化。
当前两个文件显示为 M:第一个位置为空,第二个位置是 M,说明文件只在工作区发生了修改,还没有进入暂存区。
diff:检查具体改了什么
先检查准备作为当前功能提交的文件:
git diff -- app.txt
这里会看到新增的 check empty username。
再检查文档:
git diff -- README.md
这里会看到另一个独立意图:补充采用示例。
普通 git diff 比较工作区和暂存区,不会展示普通未跟踪文件的内容。所以,检查现场时不能只看 diff,还要先看 status;否则可能漏掉尚未跟踪、也未被忽略的文件。
只选择属于本次提交的变化
这次先提交登录校验,不把文档修改混进去:
git add app.txt
git status --short
输出:
M README.md
M app.txt
app.txt 的 M 进入左列,说明它已经被暂存;README.md 的修改仍在工作区。
提交前检查暂存区中的实际内容:
git diff --cached -- app.txt
这里只应该出现与登录校验有关的变化。确认边界正确后再提交:
git commit -m "feat: validate empty username"
从实现思路看,一次提交能够同时包含代码、测试和必要文档,关键不是“只能改一个文件”,而是这些变化能否共同表达同一个意图,同时且能够一起评审和撤销。
提交后不要立即离开
提交完成后先看状态:
git status --short
输出:
M README.md
理解这一步时,这说明功能变化已经提交,文档修改仍然安全地留在工作区。提交不会自动带走没有进入暂存区的变化。
接着查看最近历史:
git log --oneline -3
它用来更快确认最近提交的顺序和说明。
查看刚才那次提交涉及哪些文件:
git show --stat HEAD
查看提交的完整内容:
git show HEAD
HEAD 表示当前检出位置对应的提交。在通常的分支状态下,它借助当前分支定位到最新提交。
确认功能提交没有混入 README 后,再把文档作为独立提交:
git add README.md
git diff --cached -- README.md
git commit -m "docs: add usage example"
git status
最后的状态应该是干净的。
同一个文件包含两个意图怎么办
按路径执行 git add app.txt 会选择这个文件当前的全部变化。但同一个文件也可能同时包含两个不同意图。
此时能够交互式选择差异块:
git add --patch app.txt
理解这一步时,Git 会把变化分成若干块,让我们逐块决定是否暂存。没有选中的部分仍留在工作区,不会被删除。
完成后分别检查:
git diff --cached -- app.txt
git diff -- app.txt
实际处理时,第一条查看已经选入下次提交的变化,第二条查看仍留在工作区的变化。如果一个差异块内部仍然混着两个意图,能够继续拆分差异块,或者先回到编辑器整理内容。
为什么不把 commit -am 当作默认动作
git commit -am "message"
实际处理时,这个写法会在提交前自动暂存所有已跟踪文件的修改和删除,同时提交它们执行命令时的当前内容,但不会纳入普通未跟踪文件。
理解这一步时,它也会绕过“选择路径 → 检查暂存差异”的过程。如果同一个已跟踪文件在暂存后又继续修改,-a 会把后续工作区修改一起纳入提交,可能破坏原本选择好的边界。
结合项目来看,只有当所有已跟踪变化都属于同一意图,同时且已经确认过现场时,它才比较合适。
一次提交前后的稳定检查顺序
git status --short
↓
git diff
↓
排除不应跟踪的路径,选择本次相关变化
↓
git diff --cached
↓
git commit
↓
git status --short
↓
git log --oneline / git show
从实现思路看,提交之前检查选择,提交之后核对结果。暂存区不是必须机械经过的一步,而是编辑下一次历史记录的地方。
总结
结合项目来看,一次清晰的提交不是靠一句漂亮的提交说明产生的,而是从检查现场、排除无关文件、选择同一意图的变化开始。status 定位路径,diff 核对内容,暂存区确定边界,log 和 show 则帮助确认最后写入了怎样的历史。
实际处理时,总的来说,git提交适合结合实际项目边做边理解。先抓住核心思路,再逐步补上细节和边界处理,最后效果会更稳定,也更容易复用。
参考资料:
- Git 官方资料:Recording Changes to the Repository
- Git 官方资料:Viewing the Commit History
- Git 官方文档:git-status
- Git 官方文档:git-diff
- Git 官方文档:git-add
- Git 官方文档:git-commit
- Git 官方文档:git-log
- Git 官方文档:git-show
- Git 官方文档:gitignore