第 08 章

Git 与 GitHub:给代码加上版本与备份

用快照的方式理解 Git,分清仓库、暂存、提交、推送、拉取与克隆,完成从安装、认证到把本地项目推上 GitHub 的全过程,并用 .gitignore 挡住虚拟环境与密钥。

Git and GitHub: Version History and a Remote Backup

Understand Git as snapshots, tell repository, staging, commit, push, pull and clone apart, go from installation and authentication to pushing a local project to GitHub, and keep virtual environments and secrets out with .gitignore.

首发于 2025.10.21中 / EN
系统课程gitgithubversion-controlworkflow
语言
字号
目录
篇内目录

这一章在讲什么

写代码绕不开两个问题:改坏了怎么退回去,以及怎样把代码交给别人。Git 解决前者,GitHub 解决后者。这一章只讲日常会用到的部分——大约占全部 Git 功能的 80%–90%——剩下的查速查表即可。

这一章对应长视频第 8 章,时间范围 4:10:04–4:44:33。

时间轴

时间内容
4:10:04Git 与 GitHub 分别是什么
4:12:33版本控制要解决的问题与核心概念
4:13:57仓库、暂存、提交、推送、拉取、克隆
4:15:29检查与安装 Git
4:16:52最小工作流:init → add → commit → push
4:18:50创建 GitHub 账号与配置身份
4:20:30认证:GitHub CLI 与 SSH
4:22:40克隆别人的仓库
4:28:20创建仓库与 .gitignore
4:32:37把本地项目推到 GitHub(完整命令)
4:36:36日常循环:status → add → commit → push
4:38:08VS Code 图形界面操作

没有版本控制时会发生什么

课程先复现了一个所有人都经历过的场景:代码改坏了,于是复制一份备份,命名为 final.py;再改坏,就有了 final_v2.py、final_actually_final.py。文件名越来越长,却没人记得哪一版能用。

Git 解决的就是这件事。它给代码拍快照,每次快照记录改了什么、谁改的、什么时候改的、为什么改。比如周一按原价计算,周二客户要求加 25% 加价,周三又要求回到 20%——有 Git 时,回到周一的版本只是一次切换。

改动一个数字当然可以手动改回来;但一个大项目突然跑不通时,「回到上一个能跑的版本」就变成了救命功能。

六个词,先记住

  • 仓库(repository):被 Git 跟踪的项目。
  • 暂存(staging):挑选这次要保存的改动,像装箱前先挑货。
  • 提交(commit):真正拍下快照,并附一句说明。
  • 推送(push):把提交上传到 GitHub。
  • 拉取(pull):把别人推送的改动下载回来。
  • 克隆(clone):把 GitHub 上的仓库整个下载到本地。

课程的说法很直白:Git 的词汇听起来专业,本质就是保存文件、上传、下载,只是每一步都有自己的名字。

另外要分清 Git 和 GitHub:Git 是装在你电脑上的版本控制工具,GitHub 是托管仓库的网站。不用 GitHub 也能用 Git,但没有 GitHub 就很难分享与协作。

安装与配置

先检查是否已经安装:

git --version

有版本号就跳过安装。Windows 从 git-scm.com 下载安装包;macOS 可以用 Homebrew 装,也可以让系统在首次运行时安装 Xcode Command Line Tools。

装好后设置身份(只需一次):

git config --global user.name "Your Name"
git config --global user.email "you@example.com"

这两项会写进每一次提交,别人看历史时能看到是谁改的。名字和邮箱建议与 GitHub 账号一致。

认证:让本地能推送到 GitHub

本地 Git 需要知道「你是 GitHub 上的哪个账号」。课程推荐用 GitHub CLI,因为它把认证流程包成了几条命令。

macOS 用 brew install gh,Windows 从 cli.github.com 下载安装包。然后:

gh auth login

按提示选择 GitHub.com、协议(推荐 SSH),在浏览器里完成授权,把终端显示的一次性代码贴进去即可。这一步只需要做一次。

另外两种方式是 HTTPS token 与 SSH key,也能用,但配置步骤更多。课程的建议是先把 CLI 跑通。

克隆别人的仓库

看到想跑的示例代码时,先进入准备存放项目的文件夹,然后:

git clone https://github.com/openai/openai-quickstart-python.git

终端里可以在目标文件夹右键选择「新建终端」,省去 cd 的麻烦。克隆完成后,整个仓库连同提交历史都在本地。

想在 VS Code 里直接打开这个项目,可以用 code 命令:

code .

第一次使用前需要在命令面板(Ctrl+Shift+P / Cmd+Shift+P)里执行一次 Shell Command: Install 'code' command in PATH。

.gitignore:有些文件不该进仓库

把项目推到 GitHub 之前,必须排除不该上传的文件。最典型的是虚拟环境:课程里那个 .venv 有 270 MB,里面是一整套 Python 解释器和依赖,传上去既慢又没意义——别人用 requirements.txt 或 pyproject.toml 就能重建。

在项目根目录新建 .gitignore:

.venv/
__pycache__/
.env
.DS_Store
*.pyc

规则是:环境、缓存、密钥、系统文件一律不跟踪。.env 一定要在里面,否则密钥会被推上 GitHub。

把本地项目推到 GitHub

先在 GitHub 网页上点「New repository」,填名字、选可见性。课程特别提醒:默认选 private,只有确实要公开时才选 public;需要协作时可以在 private 仓库里邀请成员。

然后在项目目录里依次执行:

git init
git add .
git commit -m "initial commit"
git branch -M main
git remote add origin https://github.com/<user>/<repo>.git
git push -u origin main

逐条解释:

  • git init 在当前目录创建仓库,生成隐藏的 .git/ 文件夹,所有历史都存在里面。
  • git add . 把当前所有改动放进暂存区;. 表示全部。不想全部提交时才逐个指定文件。
  • git commit -m "..." 拍下快照并写说明。
  • git branch -M main 把默认分支改名为 main,这是现在的通用约定。
  • git remote add origin <url> 把本地仓库与 GitHub 上的仓库关联起来,origin 是远程的默认名字。
  • git push -u origin main 推送,并用 -u 记住这条默认路径,以后直接 git push 即可。

第一次操作步骤很多,但其中 80%–90% 是一次性的。装好、认证好、关联好之后,日常只剩下四步。

日常循环

git status
git add .
git commit -m "add grand total to report"
git push

git status 先看有哪些改动(未跟踪、已修改、已暂存),再决定提交什么。提交之后在 GitHub 上能看到这次改动具体修改了哪些行,「改坏了就回退」的能力就是从这里来的。

VS Code 图形界面

课程自己日常使用的是 VS Code 的源代码管理面板:

  • 左侧图标显示改动数量;
  • 输入提交信息,点「提交」等价于 git commit -m;
  • 点「提交并推送」(Commit & Push)一步完成提交与上传;
  • 第一次推送时如果没有远程,界面会提示「发布分支」(Publish Branch),按向导选择 public/private 即可创建仓库并关联。

还有一个便利:在一个空文件夹里初始化仓库、写一个 README、点提交并推送,VS Code 会引导你创建对应的 GitHub 仓库,不用先去网页操作。

安装 GitHub Copilot 后,提交信息还可以让 AI 根据改动自动生成——课程坦言「写提交信息大概是开发者最难的事情之一」。

本章结论

  • Git 给代码拍快照;GitHub 托管这些快照并与他人协作。
  • 六个核心词:仓库、暂存、提交、推送、拉取、克隆。
  • 一次性配置:安装、user.name/user.email、gh auth login。
  • 推送到 GitHub 的五条命令:init、add、commit、branch -M main、remote add + push -u。
  • 日常只需 status → add → commit → push,或用 VS Code 面板点两下。
  • .gitignore 必须排除虚拟环境、缓存与 .env。
  • 仓库默认设为 private,需要分享时再单独处理。

理解检验

1. Git 和 GitHub 有什么区别?只用其中一个可以吗?

参考答案:Git 是本地运行的版本控制程序,负责记录提交、管理分支与历史;GitHub 是托管 Git 仓库的在线服务,负责备份、分享与协作。只用 Git 完全可以:所有提交都存在本机,可以在本地回退、分支、合并,但换电脑或与别人协作时没有统一的远程副本。只用 GitHub 则不行,因为推送与拉取都要通过本地 Git 完成。

2. git add 和 git commit 各自做了什么?为什么需要两步?

参考答案:git add 把选中的改动放进暂存区,决定「这次提交包含哪些文件、哪些改动」;git commit 把暂存区的内容固化成一次快照,并记录提交信息、作者与时间。分两步是为了能精确控制提交内容:例如你同时改了三个文件,但只想提交其中两个相关的改动,就先 add 那两个再 commit,历史会更清晰。git add . 是「全部加入」的快捷方式。

3. 为什么 .venv/ 和 .env 必须写进 .gitignore?

参考答案:.venv/ 是虚拟环境,里面有几十到几百 MB 的解释器与依赖副本,而且换一台机器、换一个 Python 版本就无法复用;这些依赖应当通过 requirements.txt 或 pyproject.toml 重建,而不是存进仓库。.env 保存 API key、数据库密码等密钥,一旦推送到 GitHub,尤其是公开仓库,任何能看到仓库的人都能拿到,可能造成数据泄露或费用损失。把 .env 加入 .gitignore,密钥就只留在本地。

4. git push -u origin main 里的 -u 有什么用?

参考答案:-u(--set-upstream)把本地 main 分支与远程 origin/main 关联起来,并把这个关联记下来。之后在 main 分支上直接执行 git push 或 git pull,Git 就知道该和哪个远程分支同步,不需要每次写全 origin main。第一次推送时设置一次即可。

5. 你在本地提交了几次,但忘了先 git remote add origin。现在执行 git push 会怎样?应该怎么补救?

参考答案:会提示没有配置远程仓库(类似 fatal: No configured push destination)。已经提交的历史不会丢失。补上远程地址后再推送即可:

git remote add origin https://github.com/<user>/<repo>.git
git push -u origin main

如果推送时提示远程已有内容(例如创建仓库时勾选了 README),需要先 git pull --rebase origin main 把远程的提交合并进来,再推送。

6. 你在周一提交了一个版本,周三把代码改坏了。怎样回到周一的状态?回到之后,改坏的那次提交还在吗?

参考答案:可以用 git log 找到周一的提交哈希,再执行 git checkout <hash> 查看当时的代码,或者用 git revert 生成一个反向提交来撤销改动。如果只是想让工作区回到某次提交的状态而不改写历史,git checkout <hash> -- . 或 git restore 都可以。改坏的那次提交仍然在历史里:Git 的提交不会被普通操作删除,这正是不用再复制 final_v2.py 的原因——任何时候都能找回。只有 git reset --hard 这类会移动分支指针的操作才会让提交从当前历史中「消失」,但对象仍会在本地保留一段时间。

与前后章的关系

上一章用类把代码组织起来,这一章给代码加上版本与远程备份。下一章处理项目的另外两件「日常装备」:用 .env 把密钥从代码里分离出来,用 Ruff 统一代码风格,再用 uv 替代 pip 管理依赖。三章合起来,构成一个可以直接拿去交付的项目骨架。

What this chapter covers

Writing code raises two questions: how do you get back to a working version after breaking something, and how do you hand the code to someone else. Git answers the first; GitHub answers the second. This chapter covers the part used every day — roughly 80–90% of what you need — and leaves the rest to a cheat sheet.

This is chapter 8 of the long course, covering 4:10:04–4:44:33.

Timeline

TimeTopic
4:10:04What Git and GitHub each are
4:12:33The problem version control solves, and the core concepts
4:13:57Repository, staging, commit, push, pull, clone
4:15:29Checking for and installing Git
4:16:52The minimal loop: init → add → commit → push
4:18:50Creating a GitHub account and configuring identity
4:20:30Authentication: GitHub CLI and SSH
4:22:40Cloning someone else's repository
4:28:20Creating a repository and a .gitignore
4:32:37Pushing a local project to GitHub, command by command
4:36:36The daily loop: status → add → commit → push
4:38:08The VS Code graphical interface

Life without version control

The lecture recreates a scene almost everyone recognises: the code breaks, so you copy it and call the copy final.py; it breaks again, so you get final_v2.py, then final_actually_final.py. The names grow longer and nobody remembers which one still works.

Git solves this. It takes snapshots of the code, and each snapshot records what changed, who changed it, when, and why. If Monday's price was 20%, Tuesday's client asked for a 25% markup, and Wednesday's asked to go back to 20%, returning to Monday is a single step with Git.

Changing one digit by hand is easy; recovering a large project that suddenly stops running is where this becomes essential.

Six words to know

  • Repository: a project tracked by Git.
  • Staging: choosing which changes go into this commit, like picking items before sealing a box.
  • Commit: actually taking the snapshot, with a message.
  • Push: uploading commits to GitHub.
  • Pull: downloading changes someone else pushed.
  • Clone: downloading an entire repository to your machine.

The lecture puts it plainly: the vocabulary sounds technical, but underneath it is saving files, uploading and downloading — each with its own name.

Also keep Git and GitHub apart: Git is the version-control program on your computer; GitHub is a website that hosts repositories. Git works without GitHub, but sharing and collaboration are much harder.

Install and configure

First check whether Git is already present:

git --version

If you see a version number, skip the install. On Windows, download the installer from git-scm.com; on macOS, use Homebrew or let the system install the Xcode Command Line Tools on first use.

Then set your identity once:

git config --global user.name "Your Name"
git config --global user.email "you@example.com"

These values are written into every commit, so anyone reading the history can see who made the change. Use the same name and email as your GitHub account.

Authentication: letting your machine push

Local Git needs to know which GitHub account it belongs to. The lecture recommends the GitHub CLI, which wraps authentication into a few commands.

On macOS install with brew install gh; on Windows download the installer from cli.github.com. Then:

gh auth login

Choose GitHub.com, pick a protocol (SSH is recommended), authorise in the browser and paste the one-time code the terminal shows. This is a one-time setup.

HTTPS tokens and SSH keys work too, but require more configuration. The advice is to get the CLI working first.

Cloning someone else's repository

When you find example code you want to run, open a terminal in the folder where you keep projects and run:

git clone https://github.com/openai/openai-quickstart-python.git

On both macOS and Windows you can right-click a folder and choose "Open in Terminal" or "New Terminal at Folder" to avoid cd. After cloning, the entire repository and its commit history are local.

To open the project in VS Code from the terminal:

code .

The first time, run Shell Command: Install 'code' command in PATH from the command palette (Ctrl+Shift+P / Cmd+Shift+P).

.gitignore: files that should never be pushed

Before pushing, exclude files that do not belong in the repository. The clearest case is the virtual environment: the one in the lecture is 270 MB of interpreters and dependencies. Uploading it is slow and pointless — anyone can rebuild it from requirements.txt or pyproject.toml.

Create .gitignore at the project root:

.venv/
__pycache__/
.env
.DS_Store
*.pyc

The rule: environments, caches, secrets and system files are never tracked. .env must be listed, or your keys will end up on GitHub.

Pushing a local project to GitHub

On GitHub, click "New repository", choose a name and visibility. The lecture stresses: default to private, switch to public only when you genuinely want the world to see it; collaborators can be invited to a private repository.

Then, in the project folder:

git init
git add .
git commit -m "initial commit"
git branch -M main
git remote add origin https://github.com/<user>/<repo>.git
git push -u origin main

Line by line:

  • git init creates the repository, including the hidden .git/ folder that holds all history.
  • git add . stages every current change; . means "everything". Name files individually only when you want a partial commit.
  • git commit -m "..." takes the snapshot and records the message.
  • git branch -M main renames the default branch to main, the current convention.
  • git remote add origin <url> links the local repository to the GitHub one; origin is the conventional name for that remote.
  • git push -u origin main uploads and, with -u, remembers the default so later pushes are just git push.

The first run looks like a lot, but 80–90% of it is one-time setup. Once installed, authenticated and linked, daily work is four steps.

The daily loop

git status
git add .
git commit -m "add grand total to report"
git push

git status shows what changed (untracked, modified, staged) so you can decide what to commit. After pushing, GitHub shows exactly which lines changed — that is where the ability to roll back comes from.

The VS Code interface

The lecture's own daily workflow uses the Source Control panel:

  • the icon shows how many changes exist;
  • type a message and click Commit, equivalent to git commit -m;
  • "Commit & Push" does both in one click;
  • the first time, if no remote exists, the panel offers "Publish Branch" and walks you through creating a public or private repository.

There is a shortcut worth knowing: initialise a repository in an empty folder, add a README, and click Commit & Push; VS Code will offer to create the matching GitHub repository without visiting the website first.

With GitHub Copilot installed, commit messages can be generated from the diff — the lecture admits that writing commit messages is one of the harder parts of being a developer.

Takeaways

  • Git snapshots your code; GitHub hosts those snapshots and enables collaboration.
  • Six core words: repository, staging, commit, push, pull, clone.
  • One-time setup: install, user.name/user.email, gh auth login.
  • Five commands push a project: init, add, commit, branch -M main, remote add plus push -u.
  • Daily work is status → add → commit → push, or two clicks in VS Code.
  • .gitignore must exclude the virtual environment, caches and .env.
  • Keep repositories private by default.

Comprehension check

1. What is the difference between Git and GitHub? Can you use just one?

Reference answer: Git is the local version-control program that records commits, branches and history; GitHub is an online service that hosts Git repositories for backup, sharing and collaboration. Git alone is fully usable — commits stay on your machine and you can branch, merge and roll back locally — but there is no shared remote copy for another machine or collaborator. GitHub alone is not usable, because pushing and pulling are performed by local Git.

2. What do git add and git commit each do, and why are there two steps?

Reference answer: git add places selected changes in the staging area, deciding which files and which edits belong to the next commit. git commit freezes the staged content into a snapshot along with the message, author and time. The split allows precise commits: if you changed three files but only two belong together, stage those two and commit, and the history stays readable. git add . is the shortcut for "stage everything".

3. Why must .venv/ and .env be listed in .gitignore?

Reference answer: .venv/ contains a copy of the interpreter and dependencies, often hundreds of megabytes, and it cannot be reused across machines or Python versions; dependencies should be rebuilt from requirements.txt or pyproject.toml. .env holds API keys, database passwords and other secrets; once pushed to GitHub, especially to a public repository, anyone who can see the repository can take them, risking data loss or unexpected bills. Ignoring .env keeps the keys local.

4. What does the -u in git push -u origin main do?

Reference answer: -u (--set-upstream) links the local main branch to origin/main and records that link. Afterwards, on main, plain git push and git pull know which remote branch to use, so you do not repeat origin main. It only needs to be set on the first push.

5. You made several local commits but forgot to run git remote add origin. What happens when you run git push, and how do you fix it?

Reference answer: Git reports that no push destination is configured (something like fatal: No configured push destination). The commits are safe locally. Add the remote and push:

git remote add origin https://github.com/<user>/<repo>.git
git push -u origin main

If the remote already has content (for example a README created with the repository), pull it in first with git pull --rebase origin main, then push.

6. You committed a working version on Monday and broke the code on Wednesday. How do you get back to Monday, and does Wednesday's commit disappear?

Reference answer: find Monday's hash with git log, then inspect it with git checkout <hash>, or undo the change with git revert. To restore the working tree to that state without rewriting history, use git checkout <hash> -- . or git restore. Wednesday's commit still exists in the history: ordinary commands do not delete commits, which is precisely why you no longer need final_v2.py. Only operations like git reset --hard move the branch pointer so the commit leaves the current history, and even then the objects remain locally for a while.

How it connects

The previous chapter organized code with classes; this one adds version history and a remote backup. The next chapter covers the other two everyday essentials: .env to move secrets out of the code, Ruff to standardize style, and uv to replace pip for dependency management. Together the three chapters form a project skeleton you can hand to a client.

来源