Lab0: GitLab
实验任务
- 下载与安装 Git
- 学习基本的 Git & GitHub 操作
- 加入 GitHub Classroom
前言:浅谈版本控制(Version Control)
假设你正在用 C++ 实现一个简易的学生成绩管理系统:
StudentGradeManagementSystem/
├── main.cpp
├── include/
│ ├── student.h
│ └── grade.h
├── src/
│ ├── student.cpp
│ └── grade.cpp
├── tests
│ └── test.cpp
└── docs/
└── README.md某一天,你灵机一动:如果我用 unordered_map 代替 vector 组织学生列表,这样查找某个学生的时间复杂度就从 vector,但之前的文件已经被覆盖了,你不得不再重写一遍。
或许有同学养成了代码备份的好习惯——将重构前的文件保存为 student_old.h、student_old.cpp等等。但当类似的情景再次发生时,你的项目结构将变得相当混乱。
另一种情景是,假设你和 Zecyel 同学在协作这个项目,你们同时修改了 main.cpp,合并的时候只能将代码逐行对比,将他的部分代码复制进来。
TIP
你之前有过多人协同开发的经历吗?如果有,你们是使用什么方式分工协作的?
什么是版本控制?
版本控制(Version Control)是一种用来记录文件内容的变化,并且能在以后回溯到特定版本的系统。
就像“保存历史记录”一样,它能帮我们:
- 保存每次修改(而不是只保留最新版本)
- 查看每次修改了什么
- 回退到任意一次修改
- 多人协作时合并修改
NOTE
你可以查看我们课程网页仓库的 commit 历史,这里记录了我们的每一次修改。
我们在生活中使用软件的版本号(例如 v1.98.2)则是“发行版”。
例如我们使用的校园助手 App,在历经界面优化、接口修复等多次修改形成一个稳定、完整的版本后,才会打上标签(tag)发行。
Git
Git 是一种分布式版本控制软件。
下载与安装
TIP
本学期的大部分实验都在 Linux 系统上完成,使用 Windows 系统的同学请在 WSL 或虚拟机安装 Git,使用服务器的同学请在服务器上安装 Git。
检查安装是否成功。在虚拟机 / 服务器上输入 git --version,如果输出 git version <版本号>,则为安装成功。
配置
在 Git 中,git config 是用来配置 Git 行为和环境的命令。
IMPORTANT
Git 每次提交都会记录“作者是谁”,需要配置用户名和邮箱:
git config --global user.name "用户名"
git config --global user.email "你的邮箱@example.com"Details
Git 的配置分为三个层级:
系统级(--system):对整个系统所有用户生效,配置写在
/etc/gitconfig用户级(--global):对当前用户生效,配置写在
~/.gitconfig项目级(默认):仅对当前仓库生效,配置写在
.git/config
(优先级:项目级 > 用户级 > 系统级)
在本学期实验中,使用 --global 即可。
其他的 Git 配置(可选):
# 默认分支名
git config --global init.defaultBranch main
# 别名
# 用 st 代表 status,以下类似
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.cm "commit -m"Git 基本操作
想要最低限度地使用 Git,以下的命令是必须掌握的。
git init将本地项目初始化为一个 Git 仓库。如果你打开项目文件夹,会发现多出了一个
.git文件夹。git add将指定的改动添加到暂存区,例如:
bash# 假设你处于 `/StudentGradeManagementSystem` 目录下 # 将 src 目录下的 student.cpp 添加到暂存区 git add src/student.cpp # 将当前目录下(及其递归子目录)的所有改动添加到暂存区 git add -A # 将当前目录下的所有后缀为 .cpp 的文件改动添加到暂存区(git add 支持字符串通配符) git add *.cppWARNING
请一定注意你所在的目录!如果你在
/src目录下执行git add -A,那么/StudentGradeManagementSystem目录下其他的改动不会被添加到暂存区。bash# 只暂存 /src 目录下的改动 user@linux:~/StudentGradeManagementSystem/src$ git add -A # 暂存整个项目的改动 user@linux:~/StudentGradeManagementSystem$ git add -Agit commit将暂存区的内容提交到本地仓库。
git commit一般有两种方式。git commit -m "your commit message"直接在命令行写 commit message。git commit执行后 Git 会打开默认编辑器,在这里可以写多行 commit message,适合对一次复杂的提交作详细描述。
TIP
VS Code 原生集成了 Git,同时提供了一系列插件,例如 Git 提交树可视化插件 Git Graph。
示例
以下是在 VS Code 中使用 Git 的演示:
创建一个空文件夹
test-git。点击左侧边栏中的
源代码管理图标。
点击 'Initialize Repository'(这一步等同于
git init)。新建
main.cpp,会出现U标记,意为Untracked(未跟踪的)。
回到
源代码管理界面,这里有两个+按钮。 上方的+代表将项目中的所有更改添加到暂存区,相当于在项目目录下执行git add -A。 下方的+代表将指定文件添加到暂存区,相当于执行git add main.cpp。
点击上方的
+,main.cpp的标记变为A,意为Added(已暂存)。
在文本框输入 commit message(可以是多行),点击提交,相当于执行
git commit -m "Initial commit"
修改
main.cpp。这时main.cpp的标记会变为M,意为Modified(已修改)
重复上述暂存、提交操作。

点击下方的
Git Graph,可以查看 Git 提交树。
Git 进阶操作
此处会涉及一些和“分支管理”相关的 Git 操作。熟悉这些指令可以让你更好地管理你的代码分支。
git status经常性地在运行 Git 命令前运行
git status是个好习惯,它可以告诉你,你当前在哪个分支下,有哪些修改还未被暂存,有哪些暂存区的文件还没被提交。bashuser@linux:~/test-git$ git status On branch main Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: added-file Untracked files: (use "git add <file>..." to include in what will be committed) untracked-filegit branch可以使用
git branch <branch-name>来从当前分支创建一个新的分支。注意,这不会将当前的代码分支切换到新创建的分支。例如,在
main分支下运行git branch dev会创建一个dev分支(你可以使用git status查看!)。但是当前仍然会在main分支。TIP
如果你想查看当前有哪些分支,可以使用
git branch或者git branch -a。查阅资料并在报告中回答,这两条命令的区别是什么?bashuser@linux:~/test-git$ git branch dev user@linux:~/test-git$ git branch dev * main user@linux:~/test-git$ git branch -a dev * maingit switch可以使用
git switch <branch-name>来切换到已经存在的分支。注意,你需要先保存你在当前分支上的所有文件,假如在当前分支上还有未 commit 的文件,那么这次git switch会失败。bashuser@linux:~/test-git$ git switch dev Switched to branch 'dev'git checkoutgit checkout曾经是使用最频繁的 Git 分支管理指令。但是现在,它的大部分功能已经被拆分到git branch和git switch了。我们仍在高频使用的git checkout指令只有git checkout -b <branch-name>。此指令相当于git branch <branch-name> && git switch <branch-name>,它可以从当前分支创建一个新的分支,并切换到这个分支。git mergegit merge用来把另一个分支的提交历史合并到当前分支。假设当前在 main 分支,你想合并 feature 分支:
bashgit checkout main git merge feature合并有两种常见的结果:
Fast-forward 合并。如果 main 没有新的提交,只落后于 feature:
bashmain: A---B \ feature: C---D执行
git merge feature后main分支会直接“快进”到D。bashmain: A---B---C---D \ feature: C---D非 fast-forward 合并。如果两个分支各有提交:
bashmain: A---B---E \ feature: C---D执行
git merge feature后 Git 会创建一个新的合并提交(merge commit)F:bashmain: A---B---E---F \ / feature: C---D
TIP
当两个分支修改了同一文件的同一位置,就会出现冲突(conflict),Git 无法自动合并。
bashuser@linux:~/test-git$ git merge feature Auto-merging main.cpp CONFLICT (content): Merge conflict in main.cpp Automatic merge failed; fix conflicts and then commit the result.这时需要你手动修改文件处理冲突并提交。
GitHub
GitHub 是一个基于 Git 的代码托管平台,你可以将你的本地 Git 仓库上传为远程仓库,这样别人就可以拉取你的代码,与你进行协作。
配置
你需要注册一个 GitHub 账户。
NOTE
注册 GitHub 的邮箱和你本地
git config使用的邮箱最好一致,这样远程仓库的 commit 记录才能与你的 GitHub 账户对应上。当然,一个 GitHub 账户支持绑定多个邮箱,只要你git config中的邮箱包括在其中就没问题了。在 Github 上配置 SSH 公钥
复制
cat ~/.ssh/id_rsa.pub或cat ~/.ssh/id_ed25519.pub输出的结果(即公钥)。打开 Github 并登录自己的账号。
点击右上角头像,进入 Settings :

进入页面后,在左侧选择
SSH and GPG keys, 在右侧点击New SSH Key。
在框中粘贴入自己复制的公钥,点击
Add SSH key即可。NOTE
SSH key 的生成参考这个文档
如果你在服务器上实验,需要在服务器上生成密钥对;如果在自己电脑的虚拟机上实验,需要在 WSL 中生成;如果你以后希望在本机拉取/上传 GitHub 仓库,则需要在本机生成密钥对。
验证配置是否成功
user@linux:~$ ssh -T git@github.com
Hi <用户名>! You've successfully authenticated, but GitHub does not provide shell access.如果没有得到期望的输出,请检查密钥对配置,或参考这个文档,如果仍有问题,请联系助教。
Git Remote 基本操作
git clone克隆远程仓库到本地。
bashuser@linux:~$ git clone <remote URL>git pull拉取最新的代码。这个操作相当于
git fetch(将远程分支拉到本地) +git merge(将远程分支合并入本地分支)git push将本地仓库的修改推送到远程仓库。
示例
如果你想修正我们课程网页上的错误,可以在 GitHub fork 我们的仓库到你自己的仓库,然后点击 Code,再选择 SSH,复制这串 URL。

在终端运行 git clone git@github.com:ICS-25Fall-FDU/ICS-25Fall-FDU.github.io.git(你需要替换成你自己仓库的地址)
user@linux:~# git clone git@github.com:ICS-25Fall-FDU/ICS-25Fall-FDU.github.io.git
Cloning into 'ICS-25Fall-FDU.github.io'...
remote: Enumerating objects: 893, done.
remote: Counting objects: 100% (48/48), done.
remote: Compressing objects: 100% (46/46), done.
remote: Total 893 (delta 15), reused 13 (delta 2), pack-reused 845 (from 1)
Receiving objects: 100% (893/893), 15.23 MiB | 239.00 KiB/s, done.
Resolving deltas: 100% (143/143), done.下一个 lab 发布时,我们的网页仓库会有更新,需要运行 git pull
user@linux:~/ICS-25Fall-FDU.github.io# git pull
Updating 67568b7..10fcbcf
Fast-forward
.gitignore | 3 +-
docs/.vitepress/config/zh.ts | 3 +-
docs/appendix/misc-qa.md | 45 +++++++++++++++++++++++++++++
3 files changed, 49 insertions(+), 2 deletions(-)
create mode 100644 docs/appendix/misc-qa.md如果你在自己的本地仓库提交了 commit,你就可以执行 git push,然后在 GitHub 上向我们的仓库发起 Pull Request,此部分可能会给你的实验附加分。
加入 GitHub Classroom
你将跳转到以下界面:

选择你的名字。
WARNING
请勿选择其他同学的名字,如果发现自己的名字已被使用请及时联系 houzexu22@m.fudan.edu.cn。
点击
Accept this assignment
你将看到以下界面,这里的 URL (形如
https://github.com/ICS-25Fall-FDU/lab0-gitlab-<username>)就是你个人本次作业的远程仓库。
点进远程仓库 URL 获取 remote URL(
git@github.com开头),这将是你git clone的 URL。
实验任务
认真阅读文档,学习 Git 的基本用法,并在报告中回答文档中的问题。(15 分)
加入 GitHub Classroom。
克隆你的个人远程仓库,完成
main.c文件中的TODO部分并进行一次 commit。(50 分)INFO
只要填入任意字符串就算完成,当然你也可以随意发挥(程序的正确性不纳入计分,有修改即可)。
如果你想要编译运行
main.c,执行bashmake ./main make clean在下面的三个网页中任选其二进行阅读,简要概括其内容,并谈谈你对“为什么要学习 Git”这个问题的理解。(15 分)
学习 Git 分支管理,新建
feature分支,在该分支以及main分支上对main.c分别进行一次修改与提交(10 分)。随后将
feature分支 merge 到main分支(即切换回 main 分支执行git merge feature),并处理发生的合并冲突(10 分)。IMPORTANT
在两个分支上的提交必须要满足:在
main分支合并时会出现冲突。请你解决这个冲突,并在实验报告里截图表明你遇到并解决了冲突。请阅读
git merge部分,思考如何修改main.c会出现冲突。如果你两次提交之后合并没有出现冲突,不必担心,你可以不用撤回之前的提交,而是继续尝试提交修改并 merge,直到出现冲突并解决。
在
main分支提交一份实验报告(实验报告单独评分),格式要求为PDF或Markdown。内容包括:- 文档中要求回答的问题
- 你的实验步骤
- 必要的截图
- 你的建议(可选)
TIP
这里的“提交”是指在文件夹内添加一个 PDF 或 Markdown 文件,然后
git add -A && git commit。如果你是 Word 爱好者,请你将它导出为 PDF。
你可以在自己电脑上任一位置用 Word 写实验报告并导出,然后把 PDF 文件拖拽复制到 VS Code 编辑器左侧的目录下。

提交
提交方式:在本地仓库完成上述所有实验后,将资料和报告都上传到 main 分支,并提交到 GitHub。
截止时间:10 月 8 日 23:59。逾期将扣除部分分数。
写在最后的话
作为第一次作业,这个文档的字数过多,但实际的任务很少。如果你对 Git 感兴趣可以认真读完,甚至在网上寻找其他学习资源。
如果你觉得内容过于冗长,只需对照实验任务针对性地学习重点。完成后续其它 Lab 最简单的流程就是 git clone -> 写完所有代码 -> git add -A && git commit -m "xxx" && git push。
学习资源
- Pro Git / Pro Git 中文版,推荐阅读1-3章
- 学习 Git 的在线游戏,挺好玩的
- ohshitgit,简短的介绍了如何从 Git 错误中恢复
- Git for Computer Scientists,简短的介绍了 Git 的数据模型
- git-from-the-bottom-up,详细的介绍了 Git 的实现细节
- explain-git-in-simple-words,如其名
- 用动图展示 10 大 Git 命令,一篇精美文章
Copilot