AgentDepthAgent 工程学习指南
输入概念或问题,检索正文和待编写目录。
第一次学习?从 L0 总览开始 →

Git、命令行与版本控制:知道自己保存和提交了哪一版

我的学习 →

正在读取学习记录…

Git 用“提交”记录项目在某一时刻的版本。你可以先保存一个能运行的 Python 文件,修改并检查差异,再把这次修改提交;以后仍能找到修改前的版本。这里先让你在一个全新目录里完成这条正常路径。

先想象一个发货台:手里正在整理的材料是工作区,放到打包台上的那份是暂存区,封好并贴上编号的包裹是提交。材料还可以继续改,台上和包裹里保留的是各自放进去时的样子。Git 就这样把“正在改”“准备保存”和“已经保存”分开,帮助我们找回修改前的版本。

动手前在终端运行 git --version,确认 Git 已安装,然后新建一个练习目录。

1. 命令执行前,先看自己站在哪里

1.1 安装与确认

Git 是一个需要安装的软件,不是 Windows 自带命令,也不是 GitHub 网站的别名。在 PowerShell 输入 git --version;若能看到 git version 2...,先使用现有安装,不为这里重复重装。

若没有 Git 命令,从 Git 官网下载适合机器架构的安装程序。安装时保留命令行集成选项;完成后重新打开 PowerShell 检查版本。组织管理的电脑先确认安装许可,安装程序从官网下载。

macOS可在终端运行 git --version 并按系统提示安装命令行工具;Linux按发行版包管理方式安装。平台差异见 Pro Git 安装说明。下面的 Git 命令可在 Windows PowerShell 或 macOS 终端中执行。

1.2 建一个只放练习文件的目录

用资源管理器或 Finder 创建空文件夹 agentdepth-git-manual。在终端输入 cd ,Windows 用户粘贴带引号的完整路径,macOS 用户可以把文件夹拖入终端,再按回车。

终端中的当前目录决定命令从哪里查找文件。先执行下面的命令,确认位置、文件清单和 Git 版本:

Bash
pwd
ls
git --version

路径含空格时要加引号。把git init运行在错误的大目录,会把不相关文件纳入同一个仓库范围。在新建的独立练习目录中初始化,仓库范围就清楚了。

还有一项习惯:看退出码与输出。某条命令失败后,后面一串命令不一定会自动停止。逐条运行命令,读完输出再继续下一步,出错时就能找到对应操作。

1.3 初始化并设置本仓库身份

确认目录后逐行执行:

Bash
git init --initial-branch=main
git rev-parse --show-toplevel
git config --local user.name "Learning Example"
git config --local user.email "learning@example.invalid"
git config --local commit.gpgsign false
git status

第二条应显示你刚创建的教学目录;若不是,立即停止检查位置。init 创建保存版本信息的 .git 目录,main 是初始分支名。最后应显示当前在main分支,还没有提交。

--local 只设置这个仓库,不修改所有项目。这里使用虚构的教学身份,并关闭本仓库的提交签名以减少初学配置;正式项目使用自己的作者信息和团队签名要求。作者名和邮箱是提交记录里的署名,不是登录密码,也不会让你自动登录远端服务。

2. 工作区、暂存区和仓库

工作区是你正在编辑的文件。暂存区也叫 index,决定下一次提交记录哪些修改。提交保存文件树、父提交和说明;HEAD 通常指向当前分支的最新提交。

可以把暂存区想成发货前的打包台:编辑器里是你手上的材料,add 把选中的材料放到打包台,commit 把台上的内容封成一个有编号的包裹。封包前又修改手上的材料,已经放上打包台的那份不会跟着变。下面用三个数字亲眼看看。

git add task.txt 把此刻的内容放入暂存区。之后继续编辑,新的内容留在工作区,直到再次执行 add。git commit 记录的是暂存区里的那一份。

暂存让你可以把同一批编辑分成有意义的提交,例如先记录修正参数类型,再记录更改展示样式。在提交之前,你可以通过它选择这次要记录哪些修改。Pro Git的记录变更章节解释了文件状态与暂存流程。

3. 一个最容易猜错的实验

3.1 手动做出第一版

先用文本编辑器在教学目录保存 task.txt,内容只有一行 limit=2。这个文件让我们看清每次编辑、暂存和提交时内容如何变化。

Bash
git status --short
git add task.txt
git diff --cached
git commit -m "Add task limit"
git show HEAD:task.txt

首次status应出现 ?? task.txt,表示尚未跟踪。add后文件进入暂存区;cached diff里能看到新增的 limit=2。commit保存这一版;最后一条应显示 limit=2。-m 后面的文字是提交说明,不是文件名。若出现作者信息或签名错误,回到第1节检查本仓库配置,不反复提交碰运气。

如果看到 LF will be replaced by CRLF,这是换行符转换警告,不等于提交失败;LF与CRLF是文本换行的不同表示。先看命令是否成功、diff是否符合预期,不为这里随意修改所有仓库的全局换行配置。若log或diff进入可滚动的分页界面,按 q 返回终端。

3.2 暂存第三条规则,再编辑第四条

用编辑器把文件内容改为 limit=3 并保存,执行 git add task.txt。现在再把文件改成 limit=4 并保存,但暂时不要再次add。接着执行:

Bash
git diff
git diff --cached
git show HEAD:task.txt
观察位置此时的内容刚才哪一步改变了它
编辑器中的文件limit=4第二次编辑并保存
暂存区limit=3第一次编辑后执行add
HEAD提交limit=2第一次commit

这张表就是整个实验的关键。编辑器的保存按钮只改变工作区;add选择将哪个内容提交;commit才建立版本记录。现在执行 git commit -m "Raise committed limit to three",再执行 git show HEAD:task.txt,输出应为 limit=3,但编辑器仍然显示4。

第二次提交前:HEAD为2、暂存区为3、工作区为4;箭头标出git add与git commit的方向
图1:第二次提交前的三个版本。add 更新暂存内容,commit 把暂存内容保存为新版本。

若你的提交里是4,先检查是否在第二次编辑后又执行了add,或使用了自动暂存的IDE按钮。提交内容来自当时的暂存区,重新 add 就会更新它。

可选:用脚本自动复现,并查看完整输出

3.3 用脚本复现同一过程

你已经手动观察过状态,下面的脚本用于复现和保存结果。它会创建另一个教学仓库,不继续修改上面的手动仓库;两者的提交ID不同是正常的。

先预测:文件最初是limit=2,第一次提交后,改成3并add,然后又改成4,此时直接commit。新提交里会是3还是4?

答案是3。4只在工作区,暂存区仍然是3。不要急着背答案,下面用真实Git操作验证。

复制下方完整代码,保存为 git_lab.py,放到一个专门的学习目录:

保存为 git_lab.py:

Python
"""在脚本旁创建练习仓库,观察提交前后文件和版本的变化。"""
import json
import os
from pathlib import Path
import subprocess
import tempfile

def run_lab():
    # 新建独立练习目录,后续 Git 命令都在这个目录执行。
    root = Path(tempfile.mkdtemp(prefix='git-practice-', dir=os.environ.get('AGENTDEPTH_LAB_DIR', str(Path(__file__).resolve().parent))))
    env = os.environ.copy()
    for name in list(env):
        if name.startswith('GIT_'):
            env.pop(name)
    def git(*args):
        return subprocess.check_output(['git', '-c', 'user.name=Learning Example', '-c', 'user.email=learning@example.invalid', '-c', 'commit.gpgsign=false', '-c', 'core.autocrlf=false', '-c', 'core.hooksPath=/dev/null', *args], cwd=root, env=env, text=True, encoding='utf-8', stderr=subprocess.STDOUT).strip()
    git('init', '--initial-branch=main')
    (root / 'task.txt').write_text('limit=2\n', encoding='utf-8')
    git('add', 'task.txt')
    git('commit', '-m', 'Add task limit')
    first = git('rev-parse', '--short', 'HEAD')
    (root / 'task.txt').write_text('limit=3\n', encoding='utf-8')
    git('add', 'task.txt')
    (root / 'task.txt').write_text('limit=4\n', encoding='utf-8')
    before = {'status': git('status', '--short'), 'staged': git('diff', '--cached'), 'unstaged': git('diff')}
    git('commit', '-m', 'Raise committed limit to three')
    result = {'repo_path': str(root.resolve()), 'first_commit': first, 'before_commit': before, 'committed': git('show', 'HEAD:task.txt'), 'working_file': (root / 'task.txt').read_text().strip(), 'after_status': git('status', '--short'), 'remote': git('remote')}
    assert result['committed'] == 'limit=3'
    assert result['working_file'] == 'limit=4'
    assert result['after_status'] == 'M task.txt'
    assert result['remote'] == ''
    return result

if __name__ == '__main__':
    print(json.dumps(run_lab(), ensure_ascii=False, indent=2))

这次在另一个文件夹 agentdepth-git-script 保存代码。用 cd 进入该文件夹,运行 ls git_lab.py 确认文件存在,再执行下面的命令。后面第8节会切回手动仓库。

Bash
python -X utf8 git_lab.py

脚本在同目录创建 git-practice-... 子目录,在里面写入 task.txt 并创建两次本地提交。每次运行使用新目录,原来的手动仓库保持不变。

脚本使用命令级教学身份,learning@example.invalid不是你的身份。不要把它复制成正式项目的作者配置。初学者可以先借此完成实验,正式使用时按自己的账户要求配置本地作者信息。

看三个版本

真实Git实验展示暂存limit为3、工作区为4,新提交保存3且工作区仍有修改
图2:真实本地Git操作输出的实验结果页。短提交ID与机器运行有关,不要求你的ID与截图相同。

输出中的repo_path是本次新建仓库的完整路径。复制它,替换下面示例路径(不要原样照抄),然后继续观察:

Bash
cd "你的学习目录/git-practice-本次生成的名称"
git status --short
git diff
git diff --cached
git show HEAD:task.txt
git log --oneline -2

实验在第二次提交后已经结束,所以此时cached diff为空,普通diff显示3到4的变化。截图里的before_commit记录的是提交前,因此两个diff都有内容。比较时要确认观察的时间点,不能拿提交后的状态去否定提交前的记录。

命令比较或展示什么第二次提交前的结果
git diff工作区相对暂存区的变化3变4
git diff --cached暂存区相对HEAD的变化2变3
git show HEAD:task.txt当前提交中的文件仍为2
git status --short简短状态同一个文件可同时暂存又修改

简短状态的两列分别表示index与工作区相应状态。脚本打印时做了首尾空白整理,因此不要依靠JSON输出里前导空格的缺失解释两列;在仓库里直接运行status观察。具体diff范围以官方git-diff说明为准。

4. 三条观察命令

继续使用手动目录。第二次提交后,git show HEAD:task.txt 显示3,git diff 显示3到4,git diff --cached 为空:你刚把暂存区的3提交了,还没有把工作区的4再次暂存。以后分不清保存了哪版,就用这三条命令定位。

5. 学习项目怎样提交才有用

第一次记录“实验骨架与基线测试”,第二次记录“拒绝布尔条数”,第三次记录“增加超时用例”,比一次提交全部实验、图片和随机笔记更容易查原因。提交信息应说明改变了什么,必要时说明为什么;不要只写“update”。

在提交前,先跑受影响的测试,再看 diff,再 add 明确文件,最后检查 cached diff。测试通过不代表提交范围正确:你可能测试了工作区 4,却提交了暂存区 3。

若要证明某次实验对应某版代码,记录提交ID并检查工作区是否还有未提交修改。存在未提交变化时,仅写HEAD不能完整定位当时源码;还要保留差异或将相关修改单独提交。模型输出、依赖环境和外部数据也会影响复现,Git提交号并不能单独锁定所有这些因素。

6. 本地提交、远端与备份

commit 发生在本地,push 才把相应对象和引用更新送到远端。即使没有 remote,也能在本地创建提交历史。Git 是版本控制工具,GitHub 是一种托管协作服务。

没有推送过的本地提交会随磁盘损坏而丢失,远端也不一定保存未提交文件。版本控制不替代完整备份。对学习内容,可以保留远端代码和另外的素材备份;不要把私人运行记录或密钥混进公共仓库。

分支可以理解为指向提交的可移动引用,不是自动复制一套独立依赖环境。切换分支后,Python虚拟环境不会自动变成该分支要求的依赖版本。后面的可复现环境章节会把代码版本与环境版本一起管理。

7. 哪些文件不应该随手提交

常见需要排除的包括.venv/、缓存目录、私人.env、带身份信息的运行记录。可以提供不含秘密的.env.example说明变量名称,但不要把真实值填进去。

TXT
.venv/
__pycache__/
.env

gitignore主要影响未跟踪文件,不能把已经提交的密钥从历史里抹掉。如果秘密已经公开,应先撤销或轮换秘密,再处理历史和协作者副本;单纯追加一条ignore不够。gitignore官方说明明确区分已跟踪与未跟踪文件。

图片和实验输出也需要考虑大小与维护。应保存能支持结论的脱敏证据,不是无限堆每次运行日志。图源比只有一张位图更方便修订,但第三方素材许可仍需单独检查。

8. 改错了,先诊断再恢复

Git 错误可能停在工作区、暂存区或提交历史;先用 status 和对应 diff 定位,再选择不同恢复动作
图 3:从左到右是编辑、暂存、提交三个位置。想保留编辑但取消暂存时看中栏;已共享的错误提交看右栏。图中的命令是判断线索,不要在未知仓库直接照抄恢复操作。

先用 git status --short 确认当前仓库和状态,再从图中选择对应的一栏操作。下面的命令只在刚创建的练习仓库中运行。

8.1 只取消暂存,不删除编辑

在第3节的手动仓库里,文件应仍为4,HEAD为3。先确认当前位置;做过可选自动实验的读者需要切回手动目录:

Bash
cd "你的agentdepth-git-manual完整路径"
git rev-parse --show-toplevel
git status --short
git show HEAD:task.txt

确认根目录是手动目录,HEAD显示 limit=3,编辑器中的文件仍是4。如果不符合,先核对第3节的执行情况,不要在另一个仓库继续猜。符合时再依次执行:

Bash
git add task.txt
git restore --staged task.txt
git diff --cached
git diff

第二条把暂存区中的这个文件恢复到HEAD版本,不改工作区。结果应是cached diff为空、普通diff仍显示3到4。这里的 --staged 很重要,不能随意去掉;不带它的恢复操作可能覆盖工作区编辑。具体语义见 git restore 文档。

接下来执行 git add task.txt 与 git commit -m "Record limit four",再用 git status --short 确认没有未提交修改。只有这一步干净了,才继续下面的分支演示。

8.2 在分支上尝试修改

执行 git switch -c trial-limit 创建并切换到新分支。在编辑器把文件改为 limit=5,保存,然后执行:

Bash
git add task.txt
git commit -m "Try limit five"
git switch main
git show HEAD:task.txt
git switch trial-limit
git show HEAD:task.txt

回main时应看到4,回trial-limit时应看到5。切换分支会更新工作区,编辑器可能提示文件在磁盘上改变;重新加载后查看,不要用尚未保存的旧内容覆盖它。这里先保证干净再切换,是为了不把未提交修改和分支变化混在一起。分支不是独立虚拟环境,也不会复制整台电脑。git switch 文档说明了切换与新建分支的行为。

8.3 用新提交撤销已经提交的效果

仍在trial-limit,确认最近一次提交是 Try limit five、工作区干净,再运行:

Bash
git revert --no-edit HEAD
git show HEAD:task.txt
git log --oneline -3

结果应回到4,但历史里仍能看到尝试5的提交,以及新增加的撤销提交。revert 新增一条反向修改,原来的操作仍保留在历史里。遇到冲突时,根据 Git 提示处理冲突文件,再检查结果。见 git revert 文档。

运行 git show HEAD:task.txt 应得到4,再核对日志新增的 Revert 提交。文件回到了4,历史却完整保留了“尝试5”和“撤销5”两个动作。

这个命令只在这里明确状态的教学仓库使用,不在未知仓库照抄 HEAD。如果输出和预期不同,先停止并看status和log,不重复执行revert来猜结果。

8.4 回到一般项目时先判断状态

先运行status、普通diff和cached diff,判断错误在哪个位置:只在工作区、已经暂存、还是已经提交。不同位置的恢复命令不同,不能上来就用reset --hard。

如果只是暂存了不该提交的文件,调整暂存范围即可,不必丢弃工作区内容。如果错误已进入共享提交,先与协作者商量用新提交撤销,不要私自重写历史。

遇到合并冲突也不要直接选择“全保留我的”。冲突标记表示Git无法自动合并文本,解决的是两边意图如何兼容;删掉标记后仍需运行测试。未来AI帮你处理冲突时,你也需要检查结果,不把工具退出0当业务正确。

9. 练习与验收

课后练习展开习题收起习题
题1:add以后继续编辑,再commit会包含最新编辑吗?

不会自动包含。提交读取暂存内容,最新编辑仍可能只在工作区。再次add才更新暂存内容;提交前用cached diff确认。

题2:测试了工作区,记录HEAD就足以复现实验吗?

不一定。工作区可能有未提交变化,依赖与输入也可能不同。应记录代码版本、差异状态、环境和数据,不能用一个提交号替代全部证据。

题3:把.env加入gitignore能清除已经泄漏的密钥吗?

不能。已经跟踪或提交的内容不因ignore消失,更不会撤销秘密本身。需要轮换秘密并处理历史和传播范围。

用三位置对照做一次实践:回到第 3 节,停在 HEAD=2、暂存区=3、工作区=4,分别运行 git diff 和 git diff --cached:前者比较“3→4”,后者比较“2→3”。说清下一次提交保存哪个版本,再看提交结果。接着重做第 8 节的恢复实验,观察 restore --staged 保留编辑、revert 新增提交的区别。

如果你已经跟到第8节,手动仓库的 main 分支应提交了4,trial-limit 分支还包含“尝试5”和“撤销5”的历史;不要再执行一次提交4的命令。只在自己的教学仓库检查现状:

Bash
cd "你的agentdepth-git-manual完整路径"
git rev-parse --show-toplevel
git status --short
git switch main
git show HEAD:task.txt
git log --oneline -3

先确认根目录确实是你第1节新建的教学目录、工作区没有未保存的修改,再切换分支。git show 应输出 limit=4;git status --short 在没有额外编辑时为空。若想重新截取“2、3、4同时存在”的证据,请在另一个全新空目录重做第3节,不要倒退或清空当前仓库。

讨论:一次提交是否越小越好?如果一个改动必须同时修改实现和测试才能表达完整意图,拆得过碎也会让历史难懂。判断标准是提交是否可解释、可检查,而不是行数越少越好。

4 道练习 · 客观题规则评分 · 其余题目待批改

正在读取本地记录…

不调用模型,不执行代码。简答、代码和场景题仅保存答案并展示自查标准,不生成评分、徽章或认证。输入内容不会自动保存,请点击提交;不要填写个人信息或密钥。

练习 1 / 4 · v1.0.0

选择题 · commit 记录哪一份?

文件先改成 3 并 add,再改成 4,随后 commit。提交中通常是哪一版?

对应知识点:L0-git

选择一个答案
练习 2 / 4 · v1.0.0

简答题 · 提交号为什么不够复现?

你记录了 HEAD 提交号,但工作区还有未提交修改。要让别人复现实验,还应保留什么?

对应知识点:L0-git

练习 3 / 4 · v1.0.0

代码题 · 设计一次安全提交前检查

写出提交前命令顺序,要求发现工作区差异、暂存范围和测试结果,并避免提交 .env。

对应知识点:L0-git

练习 4 / 4 · v1.0.0

场景题 · 错误提交已经共享

一个错误提交已经推送并被同事使用。请比较追加撤销提交与重写历史的风险,并给出选择条件。

对应知识点:L0-git

10. 回顾:编辑、暂存、提交

回顾三件事:

  • git add 把当前内容放入暂存区,git commit 保存暂存区的版本。暂存后又编辑,工作区和下一次提交的内容就可能不同。
  • 暂存数字3后把文件改成4,第二次提交仍记录3;revert 用新提交撤销旧提交的效果。
  • 查状态用 status,查未暂存差异用 diff,查准备提交的差异用 diff --cached。

命令语义可查 git add 与 git revert。

开源资料先读Pro Git的基础章节,再查Git源码仓库相关命令文档。下一篇是Docker与可复现环境:保留了代码版本,为什么换台机器还可能跑不起来?

参考资料

以下 Git 官方资料介绍暂存、差异比较、忽略文件和撤销操作,可按需要查阅。

读者问题原始资料文中对应位置
暂存后又编辑,commit 保存哪版?Pro Git:记录变更 · git commit第2—4节的三位置实验
普通 diff 与 cached diff 比较什么?git diff第4节差异表
ignore 能否移除已跟踪内容?gitignore第7节秘密风险
如何取消暂存、切换分支、反向撤销提交?git restore · git switch · git revert第8节,仅限教学仓库

读图1时对应三个位置,读图2时对应提交前后两个时间点。记住这两组区别,add、commit 和 diff 的方向就清楚了。

图片查看器
100%

文章配图 · 按 Esc 关闭