3.2 暂存区、差异和安全撤销
前置知识:创建第一个 Git 仓库
预计时间:15 分钟
练习环境:继续使用上一页的临时仓库
完成标志:能先判断改动所在层,再选择 restore、amend 或 revert
第一个快照已经保存。现在修改 main.py,再问一个关键问题:“如果这次改动不想要了,你准备撤销哪一层?”Git 最容易误操作的地方,就是把所有“回退”当成同一件事。动手前先用状态和差异确认改动在哪里。
两种常用 diff
printf '%s\n' "print('hello, Git')" > main.py
git diff
git add main.py
git diff --staged
git commit -m 'Update greeting'git diff:工作区与暂存区。git diff --staged:暂存区与HEAD。git show HEAD:某次提交本身。
未暂存:恢复工作区文件
printf '%s\n' "print('temporary draft')" >> main.py
git diff
git restore -- main.py
git diff第一遍 diff 应显示新增的草稿行;restore 后第二遍 diff 应为空。这会用暂存区版本覆盖工作区内容。Git 从未保存过的文字通常无法恢复,运行前先读 git diff。需要保留现场时可以复制文件、建临时分支并提交,或用 git stash push -u;stash 默认不包含未跟踪文件,恢复时也可能冲突。
已暂存:只撤销 add
printf '%s\n' 'draft' > notes.txt
git add notes.txt
git restore --staged -- notes.txt
git status --shortnotes.txt 仍在工作区,只是不再属于下一次提交。
最近一次本地提交:amend
git add notes.txt
git commit -m 'Add notes'
printf '%s\n' 'more context' >> notes.txt
git add notes.txt
git commit --amend --no-editamend 会创建新提交,ID 随之改变。只对尚未被别人依赖的历史这样做。个人远程分支确需更新时先协调,并优先使用 git push --force-with-lease;它仍会改写远程历史,不是普通 push 的替代品。
已共享:revert
git revert --no-edit HEADrevert 添加一条反向提交,保留原历史,适合共享分支。合并提交需要判断主线父提交,不能盲目套用。
git reset --hard 会同时移动引用并覆盖暂存区与工作区。本页不把它作为常规撤销工具。
.gitignore 的边界
printf '%s\n' '__pycache__/' '*.pyc' '.env' > .gitignore
mkdir -p __pycache__
touch __pycache__/cache.pyc .env
git status --short忽略规则只影响未跟踪路径。已经跟踪的文件需要审查后用 git rm --cached -- path 停止跟踪,再提交变化。若密钥已提交或推送,先轮换密钥;删除工作区文件或加入 .gitignore 都不能让历史中的秘密失效。
大对象同样会留在历史中。数据集和制品通常放到专用存储;确需版本化时评估 Git LFS。用 git filter-repo 清理历史会改变提交 ID,必须备份并协调仓库使用者。
这几个忽略文件只为观察状态,不留到后面的分支实验:
rm -r -- __pycache__
rm -- .env .gitignore
git status --short确认输出为空,再继续创建分支。