Git 入门简介
本节课程,我们将通过开发一个游戏,学习如何使用 Git 进行版本控制,包括命令行和 VS Code 两种使用方式。
这是一个交互式课程,需要在 GitHub 上实际操作来完成学习。本页面为静态预览,仅方便您一次性阅读所有步骤内容。
前往 GitHub 开始学习 →课程概览
English | 中文
本课程翻译自 Github Skills,全部课程请点击 这里查看
Git 入门简介
本节课程,我们将通过开发一个游戏,学习如何使用 Git 进行版本控制,包括命令行和 VS Code 两种使用方式。
欢迎
适合人群: 希望学习 Git 版本控制的新手开发者
学习内容: Git 基础概念,包括提交(commits)、分支(branches)、历史记录以及协作基础
您将完成: 你将创建一个 Git 仓库,添加示例代码,然后开发一些简单的功能。
先决条件:
- 不需要任何 Git 或版本控制经验。
- 建议了解命令行(CLI)。
- 建议了解 Visual Studio Code。
学习时长: 不到一个小时
通过本次练习,你将:
- 了解版本控制是什么以及为什么要使用它。
- 配置你的 Git 账号。
- 创建你的第一个仓库并提交代码。
- 查看项目历史并比较文件差异。
- 学习使用分支进行安全实验。
- 了解如何使用 Git 进行协作。
如何开始本次练习
复制此练习到你的账户,然后等待大约 20 秒,让小猫咪(Mona)为你准备好第一节课,之后刷新页面。
遇到问题? 🤷
复制练习时,我们建议使用以下设置:
选择个人账户或组织作为仓库所有者。
建议选择公开仓库,因为私有仓库有GitHub Actions 分钟数限制
如果 20 秒后练习仍未准备好,请查看 Actions tab 页。
检查是否有作业(job)正在运行,有时可能需要更长时间。
如果页面显示作业失败,请提交 issue。太好了,你发现了一个 Bug!🐛
© 2025 GitHub • Code of Conduct • MIT License
课程步骤

Step 1: Git 版本控制介绍
假设你和你的团队正在开发一个游戏项目,随着时间的推移,你很快发现整理备份变得困难。而且,由于大家更新项目的方式不同,协作起来非常混乱。
经过一番快速搜索,你了解到 Git。据说它能轻松跟踪变更并与他人协作。它消除了传统方式(如文件名命名规范、共享文件夹和通过邮件来回发送文件)带来的混乱。
[!IMPORTANT] 为了降低学习门槛,本次练习使用云开发环境,已经预装了 Git。如果你想在自己的计算机上安装,请访问Git 官网 获取安装指南。
📖 理论知识: 什么是版本控制?
版本控制系统解决了开发者在随时间管理代码变更时面临的常见问题。例如:
- 数据备份和恢复
- 沙盒实验
- 并行开发
- 文件锁定
- 文件复制
- 冲突变更
- 团队协作
如果你经历过下面的场景,那你肯定会爱上 Git 的!😎
my-project-final-v2-really3.zip- “什么时候这个功能不工作的?我什么都没改啊!”(但你心里清楚你改过)
- “这个文件被锁定了。我先复制一份改着,等他周一回来再处理。”
- “v2 版本在哪封邮件里?好像是上周三的。”
什么是 "Git" 版本控制?
Git 是一种分布式版本控制系统,与传统的集中式版本控制系统(如SVN)不同,每个开发者都拥有完整的项目历史副本。
这提供了以下优势:
- 无需联网即可操作 - 大多数操作都是在本地处理的。
- 更高的健壮性 - 分布式的副本相当于多个备份。
- 灵活的工作流程 - 开发者可以使用自己的流程和工具。
如何使用 Git?
Git 是开发者们为开发者自己打造的开源软件。因此,社区一直在不断完善各种功能来满足绝大多数需求。
例如,社区已将 Git 融入几乎所有的开发工作流程。以下是一些例子:
- 命令行界面(CLI) - 原始官方工具。
- 代码编辑器 - 集成在你最喜欢的编辑器/工具里。例如:
- Visual Studio Code
- JetBrains IDEs
- Xcode
- Emacs/VIM
- 托管服务 - 集中式 Git 托管服务,支持通过 Web 浏览器在线编辑。例如:
- GitHub
- GitLab
- Gitea
- Azure DevOps
- AWS CodeCommit
- BitBucket
- 桌面应用程序 - 友好的图形用户界面。例如:
- GitHub Desktop
- Sourcetree
- TortoiseGit
- GitKraken
- Git Butler
- 还有更多: https://git-scm.com/tools/guis
⌨️ 实操环节: 打开示例项目
为了降低学习门槛,下面我们将通过一个预先配置好的云开发环境,来学习如何使用 Git。
右键点击下面的按钮,在一个新标签页中打开 Create Codespace 页面。使用默认配置即可。
🪧 注意: 通常情况下,GitHub Codespace 会自动包含代码库和所有必需的设置。这是一个修改后的体验,以便您可以从头开始练习。
确认 Repository 这一栏是你自己的练习副本,而不是原始仓库,然后单击绿色的 Create Codespace 按钮。
- ✅ 你的副本:
/{{full_repo_name}} - ❌ 原始仓库:
/skills/introduction-to-git
- ✅ 你的副本:
等待 Visual Studio Code 在浏览器中加载。
在左侧文件浏览器中,右键单击
src/index.html文件,然后选择 Show Preview,查看我们的示例游戏。⚠️ 注意: 暂时不要做任何改动!我们还没有添加版本控制! 😱
[!TIP] Feel free to leave the game open and give it more trial-runs as we make changes! 🧑🚀
⌨️ 实操练习 2: 使用命令行运行 Git
让我们从使用命令行界面(CLI)开始。这是使用 Git 最原始,也是最灵活的方式。
如果尚未打开集成终端,请使用
Ctrl+Shift+P打开终端,然后搜索并选择View: Toggle Terminal为了验证 Git 是否已成功安装,输入下面的命令,它会显示当前安装的 Git 版本。
git --version下面的命令会显示 Git 的帮助文档。
git --help
⌨️ 实操练习 3: 设置 Git 身份
在对我们的游戏进行版本控制之前,得先告诉 Git 咱们是谁,这样以后就能区分每次提交的作者了。
[!WARNING] Git 会在提交历史中存储作者的姓名和电子邮件,该信息对有权访问该存储库的任何人都是可见的。GitHub 提供了一个可选的 noreply 电子邮件地址,您可以在帐户电子邮件设置中启用它。
设置你的显示名称。
⚠️ 别忘了把
First和Last换成你自己的名字!git config --global user.name "First Last"设置你的电子邮件地址。为了保护隐私,你可以考虑在帐户电子邮件设置中启用你的 noreply 地址。
⚠️ 别忘了把
[email protected]换成你自己的邮箱!git config --global user.email "[email protected]"确认一下刚才的设置有没有生效。
git config --global --list好了,现在 Git 知道你是谁了,Mona 会开始自动检查你的作业。稍等片刻,她会在评论中回复进度与下一步任务。
[!TIP] 如果你有多个账号,也可以为每个项目单独设置用户名和邮箱。在已有的项目仓库中,使用
--local替换--global即可。

Step 2: 创建你的第一个仓库
现在我们已经熟悉了这个示例项目,并且告诉了 Git “你是谁”,接下来就让我们开始把游戏纳入版本控制吧!
📖 理论: Git 工作流
Git 的工作流涉及三个主要区域:
- Working Directory(工作目录): 你正在修改项目文件的地方,也就是你在电脑里能看到的目录。
- Staging Area(暂存区): 一个临时存储区域,用于存放你准备提交的修改。
- Repository(仓库): 仓库区(或版本库),存放你提交的修改的永久记录。
graph LR
A[Working Directory] -->|git add| B[Staging Area]
B -->|git commit| C[Repository]
C -->|git checkout| A
重要的 Git 命令
Git 有很多操作,对于本地仓库,最常用的命令有下面这些。
git init- 初始化一个新的仓库,以启用版本控制。git add- 将相关的修改添加到暂存区,为"提交"到历史记录做准备。git commit- 保存或"提交"暂存区中的修改到项目的历史记录中。- commit message - 对修改的简短描述,以帮助保持历史记录的条理清晰。
git status- 查看工作目录和暂存区的当前状态。git checkout- 将工作目录切换到仓库历史中的某个版本。
[!TIP] 提交信息很重要!简洁、清晰、描述性的提交信息能让你的项目历史更容易理解(并帮助你找到未来的 bug)!
⌨️ 实操练习: 初始化项目仓库 (使用命令行)
下面我们来给这个游戏项目加上版本控制,并提交当前版本。
首先,在终端中,切换到项目所在目录。
cd /workspaces/stack-overflown初始化 Git 仓库。
git init检查一下仓库的状态。注意这里提示 "No commits yet"(暂无提交),并提醒你使用
git add命令。git status将游戏文件添加到暂存区。这会创建一个锁定副本,为将它们提交到仓库历史做准备。
git add src/index.html git add src/index.js git add src/patterns.js git add src/style.css或者
git add src/*再次检查仓库状态。注意每个文件都被标识为
new file。git status提交修改到仓库历史。我们的项目历史就这样开始啦! :octocat:
git commit -m "Initial commit"再次检查仓库状态。此时提示 "working tree clean"(工作目录干净),这意味着当前的工作副本与仓库历史完全一致。
git status
⌨️ 实操练习 2: 使用 IDE 添加文件
接下来,我们尝试用 IDE 来添加文件。
在文件浏览器中,单击 New File... 图标,开始创建
README.md文件。确保它位于./stack-overflown/文件夹内。README.md打开文件并插入以下内容。
# Stack Overflown Organize the falling blocks into the current debug pattern before the stack overflows! ⏳在左侧导航栏中,选择 Source Control 选项卡。注意
README.md文件显示在 Changes(变更)区域。将文件提升到暂存区,方法是鼠标悬停在文件上并选择加号
+按钮。输入提交信息,然后按 Commit 按钮。
Start game documentation对于第二个提交,还将以下内容添加到
README.md中。## How to Develop - `index.html` - the game container for playing - `index.js` - the primary game logic - `patterns.js` - the error patterns to match during gameplay - `style.css` - the game formatting and styling将变更添加到暂存区,并使用以下消息提交。
Start developer docs提交完成后,Mona 会开始检查你的作业。请稍等片刻,她会在评论中回复进度与下一步任务。
遇到问题?🤷
- 如果
git status显示错误的文件,可以使用git restore --staged <filename>将它们从暂存区中移除。

步骤 3:探索 Git 历史记录
现在我们的游戏已经由 Git 跟踪,让我们学习如何探索都做了哪些更改、何时做的以及由谁做的。
📖 理论: 理解 Git 历史记录
Git 会通过提交(commit)来维护项目的完整历史记录。每次提交都包含以下内容:
- 唯一哈希 ID: 一个唯一的标识符,方便在历史记录中引用。
- 父提交: 对前一个提交的引用,形成链条。
- 作者信息: 谁做的修改。
- 时间戳: 更改应用的时间。
- 提交消息: 包含在该提交中所做更改的描述。
此外,HEAD 指针是一个特殊的标签,指示你在项目历史中的当前位置。你的项目结构大概如下图所示。
---
config:
theme: 'forest'
---
gitGraph
commit id: "9c6ef8a Initial commit"
commit id: "16ac970 Start game documentation"
commit id: "762ac02 Start developer docs" tag: "HEAD"
重要的 Git 命令
每个人查看历史记录的方式不同,社区也创建了许多可选项。 这里列出了一些你将来经常会用到的常用命令和选项。
git log- 显示项目的详细历史记录。git log --oneline- 每行一条提交,信息更精简。git log --graph- 以可视化的图表形式显示提交历史,这对于分支较多的情况很有帮助。
git checkout- 切换到历史记录中的不同时间点(会修改工作目录中的文件)。
⌨️ 实操练习 1: 探索历史记录(使用命令行)
显示详细的提交历史记录。
git log以单行形式显示每个提交。
git log --oneline以可视化的图表形式显示完整的提交历史记录。
git log --graph --oneline🪧 Note: This will look more interesting in a future step when the history is longer.
复制
Initial commit条目的 Commit ID。长短格式均可用。使用它切换到早期的版本。
git checkout <commit id>🪧 注意:
README.md文件已被移除。切换回
main上的最新提交。注意README.md文件又回来了。 🧐git checkout main
⌨️ 实操练习 2: 探索历史记录(使用 VS Code)
在左侧导航栏中,打开 Source Control(源代码管理)选项卡。
右键单击 Changes(变更)标题并选择 Graph(图表)选项。
检查 Graph(图表)面板。注意最近提交的时间线列表。
点击提交名称,展开该提交修改过的文件列表。
探索完 Git 历史记录后,Mona 应该已经在检查你的作业了。给她一点时间,继续关注评论。你将看到她回复进度信息和后续步骤。
遇到问题了?🤷
- 使用
git log --help查看所有可用的历史记录查看选项。

步骤 4:比较变更
现在我们已经学会了如何“撤销”,接下来我们对游戏做一些真正的改动!更重要的是,学习如何在提交到仓库历史之前使用 Git 查看到底改了什么。
理解文件差异对于审查你的工作和发现错误至关重要!
📖 理论: 差异对比(diffs)
Git 使用不同的符号和颜色来标记文件更改:
- 绿色
+表示添加的行 - 红色
-表示删除的行
示例:
+ This is a line that was added
- This is a line that was removed
[!TIP] 你可以使用以下命令更改 Git 的默认比较颜色。
git config --global color.diff.old yellow git config --global color.diff.new blue
重要的 Git 命令
git diff 命令用于显示不同开发状态之间的差异。
git diff- 显示工作目录和暂存区之间的差异。git diff --staged- 显示暂存区和上一次提交之间的差异。git diff HEAD~1- 显示当前提交和上一次提交之间的差异。
⌨️ 实操练习 1: 差异对比(使用 CLI)
让我们对游戏做一些改动,然后使用命令行来显示差异。
打开
src/index.html。在
line 20处,用下面的例子替换info-section部分。<div class="info-section"> <h3>Current Score</h3> <div class="score" id="score">0</div> <h3>High Score</h3> <div class="high-score" id="high-score">0</div> </div>这演示了 3 处修改:
- 将
Score标签修改为Current Score - 添加
High Score信息。 - 移除
status信息。
- 将
查看当前工作目录和上一次提交之间的差异。
git diff src/index.html将更改添加到到暂存区。
git add src/index.html再次运行
git diff。注意,现在没有显示任何更改,因为工作目录已经和暂存区保持一致。git diff src/index.html查看暂存区和上一次提交之间的差异。
git diff --staged src/index.html现在提交暂存区的更改,提交消息如下。
git commit -m "Add element for showing high score"
⌨️ 实操练习 2: 差异对比(使用 VS Code)
让我们对游戏做一些改动,然后使用 VS Code 来显示差异。
打开
src/patterns.js。在
line 3处,用下面的例子替换Null Pointer的pattern。{ name: "Null Pointer", pattern: [ [0, 1, 1, 1, 0], [0, 1, 0, 1, 0], [0, 1, 1, 1, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], ], },在
文件资源管理器中,注意patterns.js文件名颜色改变了,并且旁边显示了M,表示它已被修改。打开
源代码管理选项卡。在变更列表中,双击patterns.js文件以打开差异(比较)视图。💡 Tip: 你可以在对比视图中直接修改内容,改动会实时反馈!
将文件添加到 暂存区。 ⚠️ 注意:不要现在提交!
可以看到,对比视图不再显示差异了,因为当前文件已经和暂存区一致。
在 暂存变更 列表中,双击
patterns.js文件以打开差异(比较)视图。此时无法再对暂存区的内容进行修改,已锁定,因为它已经准备好提交了。
使用以下提交消息提交更改。
Make null pointer pattern easier to complete提交后,Mona 将自动检查您的作业。请稍等片刻,并关注评论区,她会回复进度信息和下一步操作。
遇到问题? 🤷
- 如果变更列表超出一屏,可以按
q退出文件查看。

Step 5: 使用分支进行协作
现在游戏已经被 Git 跟踪了,我们知道可以轻松地回退到某个可用的版本。而且,既然我们能在提交历史中看到确切的变更内容,就能确保不会把不相关的改动带进去。
但是,这又引发了一些新的疑问! 😱
"如何保持提交历史的整洁?"
"如何避免在历史记录中留下未完成版本的痕迹?"
"如果我需要同时处理多个功能或修复怎么办?"
📖 理论:理解分支
在 Git 中,分支(Branches)本质上是指向特定提交的轻量级指针(类似于标签)。这使得我们可以在不影响原始版本的情况下,基于某个版本进行开发,非常适合并行开发新功能或修复 Bug。
核心概念:
main分支: 通常代表可信的、可用的工作版本,也是最开始创建的分支。(在旧版本中常被称为master)- Feature Branch (功能分支): 一个安全、独立的工作空间,用于开发新功能而不影响主版本。
- Merging (合并): 将不同分支的变更合并到一起。
有哪些常用的分支合并策略?
不同的合并策略适用于不同的协作场景。下面介绍几种最常见的合并方式,它们各有侧重,可以根据项目的实际需求来选择。
Fast-forward merge (快进合并): 直接将子分支上的新提交移动到父分支上。
合并前: 原始状态
gitGraph LR:
commit id: "A"
commit id: "B"
branch feature
commit id: "C"
commit id: "D"
合并后: 快进合并
gitGraph LR:
commit id: "A"
commit id: "B"
commit id: "C"
commit id: "D"
合并提交(Merge commit): 在父分支上创建一个新的合并提交,将子分支的变更合并进去。这会保留子分支的完整历史记录,便于追溯。
合并前: 原始状态
gitGraph LR:
commit id: "A"
commit id: "B"
branch feature
commit id: "C"
commit id: "D"
checkout main
合并后: 合并提交
gitGraph LR:
commit id: "A"
commit id: "B"
branch feature
commit id: "C"
commit id: "D"
checkout main
merge feature id: "E"
Squash merge(压缩合并): 将一个分支上的多个提交压缩成一个新的单一提交合并到另一个分支上。
合并前: 原始状态
gitGraph LR:
commit id: "A"
commit id: "B"
branch feature
commit id: "C"
commit id: "D"
合并后: 压缩合并
gitGraph LR:
commit id: "A"
commit id: "B"
commit id: "C+D"
常用的分支命令
git branch my-new-feature- 创建一个新分支。git checkout my-new-feature- 切换到另一个分支。git merge- 将一个分支合并到另一个分支。(默认:快进合并)
[!TIP] 你可以使用
git reset --soft HEAD~1来撤销上一个提交。在 VS Code 中,可以使用命令面板搜索Undo Last Commit。
[!TIP] Git 2.23 引入了
git switch命令来简化分支管理。你会在未来看到它被更频繁地使用。
⌨️ 实操练习 1: 在分支上提交 (使用命令行)
下面我们来创建一个分支,练习在上面提交改动。
首先,让我们看看提交历史。注意它是完全线性的(还没有分支)。
git log --all --graph --oneline创建一个新分支并切换到该分支。
git branch fix-incomplete-high-score git checkout fix-incomplete-high-score显示所有可用分支。
git branch --list打开
index.js,我们来把最高分功能修好。在
line 41,插入一个用于跟踪最高分的新变量,然后提交。let highScore = 0;git add src/index.js git commit -m "Add new variable for tracking high score"在
line 61,插入从 local storage 加载分数并提交的代码。// Load high score from localStorage highScore = parseInt(localStorage.getItem("stackOverflownHighScore")) || 0; document.getElementById("high-score").textContent = highScore;git add src/index.js git commit -m "Add loading of stored high score"在
line 313,替换updateScore函数,使其跟踪最高分,然后提交。function updateScore() { document.getElementById("score").textContent = score; // Update high score if current score exceeds it if (score > highScore) { highScore = score; document.getElementById("high-score").textContent = highScore; localStorage.setItem("stackOverflownHighScore", highScore); } }git add src/index.js git commit -m "Add logic to keep track of highest score"让我们再次查看提交历史。注意我们的 feature 分支比
main分支多了 3 个提交,并且我们的 feature 分支用HEAD标记,明确了当前版本。git log --all --graph --oneline切换回
main分支。git checkout main合并新功能。
🪧 注意: 为了学习效果,我们用了 "non-fast forward" 选项,这样分支在历史中保持可见,让可视化图表看起来更有意思。
git merge --no-ff fix-incomplete-high-score -m "Fix high score tracker"再次查看提交历史图。注意我们刚刚合并的分支。
git log --all --graph --oneline删除指向该feature 分支的指针/标签,因为它已被合并,不再需要。
git branch --delete fix-incomplete-high-score🪧 注意: 这不会删除分支内容,只是删除了用于引用它的名称。
⌨️ 实操练习 2: 在分支上提交 (使用 VS Code)
在左侧导航中,打开 Source Control 选项卡。确保 Graph 面板仍然可见(来自步骤 3)。让我们在应用更改时观察它的更新。
在左下角状态栏,点击分支名称
main。一个选项菜单将会出现。选择 Create new branch... 选项并使用下面的名称。
add-level-counter打开
index.html。在line 21,插入一个用于显示当前级别的新元素,然后提交更改。<h3>Level</h3> <div class="score" id="level">1</div>提交信息
Add element to display current level打开
index.js,添加级别计数器。在
line 42,添加 2 个用于跟踪级别的变量,然后提交更改。let level = 1; let patternsCleared = 0;提交信息
Add variables for level and clear counter在
line 273,替换checkPatternMatch方法,然后提交更改。function checkPatternMatch() { for (let startRow = 0; startRow <= ROWS - PATTERN_SIZE; startRow++) { for (let startCol = 0; startCol <= COLS - PATTERN_SIZE; startCol++) { if (matchesPattern(startRow, startCol)) { clearPattern(startRow, startCol); score += 100; patternsCleared++; if (patternsCleared % 5 === 0) { level++; dropInterval = Math.max(200, 1000 - (level - 1) * 100); document.getElementById("level").textContent = level; } updateScore(); setNewTargetPattern(); return; } } } }提交信息
Add logic to calculate level注意 Graph 面板显示了完整的历史记录:新的提交、先前的分支以及原始的提交。
为了准备合并,再次单击分支名称并选择
main分支。单击三个点 (
...) 菜单,然后选择Branch,再选择Merge...。注意它执行了一次正常的 Fast Forward 风格合并。单击三个点 (
...) 菜单,然后选择Branch,再选择Delete Branch...。两个分支都合并后,Mona 应该会开始检查你的作业。给她一点时间,并关注评论。您将看到她回复进度信息和后续步骤。
遇到麻烦了?🤷
- 如果你分支名拼错了,可以用
git branch --move 旧名称 新名称重命名。

步骤 6: 了解协作
干得漂亮!你已经掌握了本地 Git 操作,我们的游戏现在可以安全地进行新功能的开发了!🎉
但是...真正有趣的开发发生在团队中,而不是一个人。这是一个额外的练习,但让我们开始探索这个话题。
📖 理论: Git 协作概念
由于分支提供了强大的并行能力,可以在不同功能上独立工作,因此自然而然地可以支持多个人同时工作。
最初,我们提到 Git 是一个“分布式”版本控制系统,这意味着它可以与其他副本的同一仓库共享更改!
协作通常是怎样的?
以下是典型的协作流程:
- 将远程仓库复制到本地计算机(称为 clone (克隆))。
- 创建分支并开发新功能。
- 将你的更改发布到远程仓库,让其他人也能访问(称为 push (推送))。
- 其他开发者决定是否喜欢你的更改。如果喜欢,他们会将其合并到他们版本的项目中(称为 pull (拉取))。
- 此外,你还可以主动要求另一位开发者将你的更改集成到他们的副本中(称为 pull request (拉取请求))。
⌨️ 实操练习
请回答 Mona 一个简单的问题,她将分享最终的评估!🎉
你最喜欢 Git 的哪个功能?
- It's free and open source. 😍
- I don't need internet to use it. 🛜
- I can use it with any operating system. 🍎🪟🐧
- The detailed history (if I write good messages). ✨
- That I might never write
final_really.zipever again! 😎