跳到内容

第 0 卷 / 第 3 章 / 第 2 课

3.2 暂存区、差异和安全撤销 ​

前置知识:创建第一个 Git 仓库

预计时间:15 分钟

练习环境:继续使用上一页的临时仓库

完成标志:能先判断改动所在层,再选择 restore、amend 或 revert

第一个快照已经保存。现在修改 main.py,再问一个关键问题:“如果这次改动不想要了,你准备撤销哪一层?”Git 最容易误操作的地方,就是把所有“回退”当成同一件事。动手前先用状态和差异确认改动在哪里。

两种常用 diff ​

bash
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:某次提交本身。

未暂存:恢复工作区文件 ​

bash
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 ​

bash
printf '%s\n' 'draft' > notes.txt
git add notes.txt
git restore --staged -- notes.txt
git status --short

notes.txt 仍在工作区,只是不再属于下一次提交。

最近一次本地提交:amend ​

bash
git add notes.txt
git commit -m 'Add notes'
printf '%s\n' 'more context' >> notes.txt
git add notes.txt
git commit --amend --no-edit

amend 会创建新提交,ID 随之改变。只对尚未被别人依赖的历史这样做。个人远程分支确需更新时先协调,并优先使用 git push --force-with-lease;它仍会改写远程历史,不是普通 push 的替代品。

已共享:revert ​

bash
git revert --no-edit HEAD

revert 添加一条反向提交,保留原历史,适合共享分支。合并提交需要判断主线父提交,不能盲目套用。

git reset --hard 会同时移动引用并覆盖暂存区与工作区。本页不把它作为常规撤销工具。

.gitignore 的边界 ​

bash
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,必须备份并协调仓库使用者。

这几个忽略文件只为观察状态,不留到后面的分支实验:

bash
rm -r -- __pycache__
rm -- .env .gitignore
git status --short

确认输出为空,再继续创建分支。

→ 下一步:分支与合并

Built with VitePress | Software Systems Atlas