学习前提

先理解初始化、add与commit。

使用Git 2.35+与Bash兼容终端(Windows可用Git Bash)。每章完整代码都会创建独立临时目录;仅在练习仓库运行。git config仅修改该仓库,示例身份不是你的真实提交身份。临时目录不会自动删除,可在完成后自行清理。

本课完成后你能做什么

解释三份内容之间的差异,避免漏掉最后一次编辑。

先理解机制

工作区是编辑器看到的文件;暂存区记录下一次提交准备采用的内容;HEAD通常指向当前分支最新提交。add复制当前版本到暂存区,不是建立自动跟踪后续编辑的链接。

git diff比较工作区与暂存区,git diff --staged比较暂存区与HEAD。文件先暂存再编辑时,可以同时存在已暂存和未暂存的修改。短状态的两个位置分别描述索引和工作区变化。

一个提交最好对应可以解释、验证的一项改动。先查看差异再add明确文件,能减少把临时文件或无关修改混入提交的机会。交互式git add -p可进一步按补丁块挑选。

可运行示例

lab=$(mktemp -d)
cd "$lab"
git init -b main .
git config user.name "Honeysuck Learner"
git config user.email 'learner'@'example.invalid'
git config commit.gpgsign false
git config core.autocrlf false
printf 'Start learning\n' > notes.txt
git add notes.txt
git commit -m "Start learning notes"
printf 'Read Git basics\n' >> notes.txt
git add notes.txt
printf 'Try branching\n' >> notes.txt
git status --short
git diff -- notes.txt
git diff --staged -- notes.txt
git commit -m "Record Git reading"
git show HEAD:notes.txt
git diff -- notes.txt

推演与验证

提交只包含Start learning和Read Git basics两行,Try branching仍留在工作区差异中。commit不会自动吸收暂存后的新编辑。

常见错误与边界

git commit -a只会处理已跟踪文件的修改和删除,不包括新的未跟踪文件。不要把“提交成功”误认为所有本地文件都已记录。

动手练习

把遗留的第三行也加入一个独立提交。

参考解法与理由

检查git diff,执行git add notes.txt并提交。git show HEAD:notes.txt应有三行,git status --short为空。

深入实验:一次提交究竟读取哪份文件

下面故意让同一路径同时拥有三个版本:HEAD为one、暂存区为two、工作区为three。每一步先预测命令读取哪一份,再运行。使用Git 2.35+与Bash;代码创建独立临时仓库,仅修改仓库本地配置,完成后自行清理输出的临时路径。

lab=$(mktemp -d)
cd "$lab"
git init -q -b main
git config user.name "Honeysuck Learner"
git config user.email 'learner'@'example.invalid'
git config commit.gpgsign false
git config core.autocrlf false
printf 'one\n' > notes.txt
git add notes.txt
git commit -q -m "Seed"
printf 'two\n' > notes.txt
git add notes.txt
printf 'three\n' > notes.txt
git show HEAD:notes.txt
git show :notes.txt
cat notes.txt
git status --short
git commit -q -m "Record staged version"
git show HEAD:notes.txt
cat notes.txt
printf 'Practice directory: %s\n' "$lab"

预期观察

前三个读取依次是one、two、three,短状态为MM notes.txt。提交后HEAD内容为two,工作区仍为three。

原因、取舍与适用边界

MM的第一列是暂存区相对HEAD的变化,第二列是工作区相对暂存区的变化。git add不是订阅文件后续变化,而是记录调用时的内容。这个模型也解释了为何提交前应同时看git diff与git diff --staged:只看一边可能误以为另一个版本已经提交。若要把three包含进当前提交,先再次暂存,再决定新建提交还是在尚未共享时修改本地提交。

进阶练习

在提交前执行git restore --staged notes.txt,工作区的three会消失吗?

解法与推理

不会。默认源为HEAD,--staged只把暂存区恢复为one,工作区仍为three。若随后执行不带--staged的git restore notes.txt,它会用暂存区覆盖工作区,因此会丢弃未提交编辑;不要在真实未备份文件上试验。

进一步阅读