正在阅读从递归求和到 Git 提交的实践笔记
香港天气加载中…
QWeather ↗
← Back to the notebook

从递归求和到 Git 提交的实践笔记

从注释原则和 ValueError 出发,理解暂存区、AM 状态、git add .、origin 与 upstream,并复盘为什么推送成功仍可能只上传了空文件。

注释应补充哪些信息

一次递归求和练习引出了两个问题:怎样把代码的意图说明白,以及怎样确认写好的内容真正进入了提交。两者都需要明确约定:函数有哪些有效输入,Git 的下一次提交包含哪一版内容。

判断注释有没有价值,可以问:删掉它之后,读者是否会少知道重要的意图、约束或原因?

  • 函数文档字符串说明接口约定。写清函数用途、参数要求、返回值和会抛出的异常,help() 可以展示这些说明。
  • 实现旁的注释解释原因和难点。例如递推关系、终止依据、边界条件和不直观的设计选择。
  • 省略对语法的逐句复述。# 把 n 减 1 紧挨着 n - 1,通常没有增加信息。
  • 让注释随代码一起更新。函数开始拒绝负数时,文档也要写明异常;过时的注释会误导调用者。

学习示例可以保留对基础概念的说明。随着读者熟悉语法,应把注释集中在意图、约定和推导上。

为负数输入抛出 ValueError

这里把求和函数定义在非负整数上:n == 0 返回 0,正整数按递推关系求和。负数属于约定之外的输入,应明确拒绝。如果也返回 0,调用者就无法从结果区分合法的空和与错误的参数。

raise ValueError("n 不能小于 0") 会抛出异常并离开当前函数;调用者可以捕获它,否则异常会继续向外传播。Python 官方文档将 ValueError 用于参数类型合适但值不符合要求的情形。

输入约定的行为
recursion_sum(0)返回 0
recursion_sum(5)返回 15
recursion_sum(-1)抛出 ValueError

表达式 n + recursion_sum(n - 1) 要先等递归调用返回,当前层才能完成加法。因此,“先累加 n,再递归”并不准确。

这个示例的 n: int 是类型注解;它没有额外实现运行时整数类型检查。递归版本也受解释器调用深度限制,适合用来理解执行过程。

Python
def recursion_sum(n: int) -> int:
    """递归计算从 1 到 n(含)的整数之和。

    Args:
        n: 非负整数。

    Returns:
        从 1 到 n 的整数之和;当 n 为 0 时返回 0。

    Raises:
        ValueError: 当 n 为负数时。
    """
    if n < 0:
        raise ValueError("n 不能小于 0")
    if n == 0:
        return 0

    # S(n) = n + S(n - 1),递归调用返回后再完成当前层的加法。
    return n + recursion_sum(n - 1)

工作区 暂存区 本地提交与远端仓库

编辑器里保存了文件,只能说明工作区中的文件已更新。随后还要选择提交内容、创建本地提交,再更新远端分支。

位置存放什么相关操作
工作区磁盘上正在编辑的文件编辑并保存
暂存区,也称 index准备写入下一次提交的内容git add
本地仓库提交记录和分支git commit
远端仓库通过网络同步的提交记录和分支git push

这里使用的普通 git commit -m "说明" 按暂存区创建提交;git push 再更新目标远端分支。参见 git commit 官方文档。

流程
编辑并保存文件
    ↓ git add
准备好下一次提交的内容
    ↓ git commit
形成本地提交
    ↓ git push
更新远端分支

git add 与 git add . 的范围

git add recursion_sum.py 把这个文件执行 add 时的内容放入暂存区。后续编辑不会自动更新已经暂存的版本;如果也想提交后续修改,就要再执行一次 git add。

git add . 中的点表示当前目录。它暂存当前目录及其子目录中的新增、修改和删除;在仓库根目录执行时,范围覆盖整个仓库。被忽略的未跟踪文件通常不会加入,但已被 Git 跟踪的文件仍会参与暂存,即使后来匹配了忽略规则。

只准备提交一个文件时,明确写文件名更容易控制范围;确认目录中全部改动都属于本次提交时,再使用 git add .。参见 git add 官方文档。

Bash
git status --short
git diff
git add recursion_sum.py
git diff --cached
git commit -m "Add recursive sum with input validation"

怎样读懂 AM 与前面带空格的 M

git status --short 的状态有两列。在普通文件、无合并冲突的场景中,第一列 X 比较暂存区与当前提交,第二列 Y 比较工作区与暂存区。

XY含义
AM新文件已暂存;工作区内容随后又改了,最新修改还没有暂存。
空格M已有文件在工作区被修改;暂存区没有相对当前提交的新变化。
M空格已有文件的修改已经暂存;工作区没有额外修改。
A空格新文件已经暂存,工作区与暂存区一致。

AM 表示“已暂存的新增文件又有未暂存修改”,本身不能说明暂存的是空文件。只有进一步检查暂存区或提交内容,才能知道其中具体保存了什么。参见 git status 的短格式说明。

状态示例
AM recursion_sum.py
 M recursion_sum.py
M  recursion_sum.py
A  recursion_sum.py

为什么推送成功仍然只上传了空文件

这次练习中,新建的空文件先进入了暂存区,随后写入的代码留在工作区。提交时,Git 创建了文件,却没有新增文本行:

1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 recursion_sum.py

结合当时实际检查到的暂存区内容,可以确认该提交保存的是空文件。git push 成功后,远端收到的也就是这个版本。再次推送显示 Everything up-to-date,表示所推送的分支没有新的提交需要传送;工作区里仍然可以存在未提交的修改。

当时的 M recursion_sum.py 正是在提示:代码还没有重新暂存。处理方式是把当前内容放入暂存区,确认差异,再创建新提交。重复 push 无法替代这些步骤。

检查不同层次时,可以分别使用下面的命令。

Bash
git diff                         # 工作区相对暂存区的修改
git diff --cached                # 暂存区相对当前提交的修改
git log -1 --stat                # 最近一次提交涉及哪些文件
git show HEAD:recursion_sum.py   # 当前提交里实际保存的文件内容

origin 与 upstream 分别是什么

origin 是本地为远端仓库配置的名称,通常在克隆时创建;它对应一个仓库地址。recursion-practice 是分支名。

git push --set-upstream origin recursion-practice 把这个本地分支推送到 origin,并设置它的上游跟踪关系。--set-upstream 可以缩写为 -u。在具备推送权限、远端允许创建分支的情况下,首次推送会自动创建同名远端分支,无需先在网页上手动新建分支。

账号认证决定能否访问和修改远端仓库;建立分支本身不需要新建账号。看到 has no upstream branch,应为当前分支设置上游,而不是反复执行同一条不带目标的 git push。

origin/recursion-practice 是本地记录的远端跟踪引用。git branch -vv 展示的领先或落后关系依赖这些本地记录;需要更新远端状态时先执行 git fetch origin。参见 git remote 与 git push 官方文档。

Bash
git remote -v
git remote get-url origin
git branch -vv

# 首次推送 recursion-practice,并建立上游关系
git push -u origin recursion-practice

# 后续在该分支上产生新提交后,常见的默认配置下可以直接推送
git push

把功能分支合并到 main

先在 recursion-practice 上完成暂存和提交,再把它合并到 main。下面假设远端已有 main,工作区已清理好,仓库允许直接推送主分支。

git merge recursion-practice 把指定分支合入当前分支,所以必须先切换到 main。如果 main 是功能分支的祖先,Git 可以快进合并,直接将 main 移到新的提交,不必额外产生合并提交。

如果拉取失败或合并出现冲突,应先处理报错和冲突,再继续推送。要求 Pull Request 的仓库,则在推送功能分支后创建 PR,由仓库的审查流程完成合并。参见 git merge 官方文档。

Bash
# 当前在 recursion-practice 分支,先提交本次修改
git add recursion_sum.py
git diff --cached
git commit -m "Handle negative input in recursion sum"

# 更新本地主分支,再合并功能分支
git switch main
git pull --ff-only origin main
git merge recursion-practice
git status --short --branch

# 将合并结果同步到远端 main
git push origin main

推送 main 后功能分支仍可能显示 ahead

本地两个分支可能已经指向同一个新提交,但远端两个分支仍然位于不同位置。例如:

分支或引用位置
本地 main新提交
本地 recursion-practice同一个新提交
origin/main新提交
origin/recursion-practice之前的提交

这是因为 git push origin main 更新的是远端 main。功能分支仍显示领先其上游一个提交,不影响主分支已经包含改动。是否继续同步或删除功能分支,取决于后续是否还使用它。

判断合并是否完成,应检查目标分支的提交关系和实际推送结果,并确认未提交修改是否仍留在工作区;不要只根据功能分支的 ahead 提示推断合并失败。

常见提示与操作前的检查

命令或提示应怎样理解
git pushpush命令拼写错误,应为 git push。
git status --shotr选项拼写错误,应为 --short,或使用 -s。
has no upstream branch当前分支尚未配置上游;首次推送时明确指定远端与分支。
Everything up-to-date推送目标无需更新;仍需用 git status 判断是否有未提交修改。

提交前确认 git diff --cached 中确实出现了准备提交的代码;推送前确认分支和远端;合并前确认当前位于目标分支。这三个检查分别对应“提交什么”“推到哪里”和“合入哪里”。

进一步阅读本站的 递归与逐层返回、Python 程序入口与 help(),可以把函数内部的执行过程与脚本入口连接起来。

PythonGit代码注释ValueError暂存区分支合并

整理自 2026 年 10 月 15 日的 Python 递归练习与 Git 操作讨论。

MORE IN DEVELOPMENT读懂 SSH 本地端口转发:-N、-L 与两端的 127.0.0.1