Git 版本控制教程

从入门到协作,掌握现代开发的核心技能

Git Cover

开始之前

注意:确保你的网络可以畅通地连接 Gitee:https://gitee.com

这是一个国内版本的GitHub,有着和Github类似的使用体验,但是更方便访问。

总有一天,我会聚集一群不输给这些人的伙伴,并找到世界第一的财宝,我要成为海贼王!

—— 蒙奇·D·路飞 《海贼王》
One Piece

为什么需要版本控制?

版本控制在日常学术和工作中至关重要。以学术写作为例,你可能会面临:

  • 论文的多次迭代:产生许多不同版本,需要从中挑选最终稿。
  • 多方参与协作:多位作者需要同时编辑不同部分,并有效整合。

版本控制工具能帮我们记录历史、随时回退(时间回溯)、同步进度并解决冲突。

Git 的原理

Git 是一个为应对大型项目而生的分布式版本控制系统。它的包含四个工作区:

Git workflow
  1. 工作区 (Workspace):你当前编写代码的地方。
  2. 暂存区 (Stage/Index):临时存放你准备提交的改动。
  3. 本地仓库 (Repository):存储在你电脑上的项目所有版本的历史记录。
  4. 远程仓库 (Remote):托管在服务器上,用于团队协作和代码备份。

Git 的核心是分布式,每个人的电脑上都有一个完整的本地仓库,可以独立工作,然后将更新推送到远程仓库进行同步。

安装 Git

1. 下载与安装

前往Git官网下载最新的Windows安装包:https://git-scm.com/download/win

Download Git

下载后双击安装包,选择合适的安装路径,然后一路点击 "Next" 即可完成安装。

安装 Git

2. 验证安装成功

在桌面或任意文件夹内点击鼠标右键,如果菜单中出现 "Git Bash Here" 和 "Git GUI Here" 选项,证明安装成功。

Verify installation

3. 初步配置

安装后,需要设置你的用户名和邮箱,这是你提交代码时的身份标识(一般是github或gitee的账号和邮箱)。

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

基本命令:创建本地仓库

我们可以将任意一个文件夹初始化为Git本地仓库。

  1. 进入目标文件夹。
  2. 右键点击 "Git Bash Here" 打开命令行。
  3. 输入初始化命令:
git init

这会在当前目录下创建一个隐藏的 .git 文件夹。然后,使用 git status 查看仓库状态。

git status

初次会显示 "No commits yet",表示这是一个空的仓库。

基本命令:添加与提交 (1/2)

我们创建一个 hello.txt 文件,并查看状态。

touch hello.txt
git status

Git会提示有一个 "Untracked file" (未追踪文件)。这意味着Git发现了这个新文件,但尚未开始管理它。

Untracked files

使用 git add 将文件添加到暂存区,使其变为被追踪状态。

git add hello.txt

基本命令:添加与提交 (2/2)

再次使用 git status 查看,文件已变为绿色,并位于 "Changes to be committed" 下方,表示已成功进入暂存区。

Staged files

现在,使用 git commit 将暂存区的改动提交到本地仓库,形成一个新版本。-m 参数用于添加本次提交的描述信息。

git commit -m "Initial commit with hello.txt"

查看动画演示

基本命令:忽略文件 (.gitignore)

并非所有文件都需要版本控制(如编译产物、日志文件)。

我们可以在项目根目录创建一个名为 .gitignore 的文件,列出需要忽略的文件或目录模式。

常用规则示例:

# 1. 忽略特定文件
config.txt
secret.key

# 2. 忽略特定后缀的所有文件
*.log          # 所有 .log 文件
*.class        # Java 编译文件

# 3. 忽略文件夹及其所有内容
build/         # build 目录
.vscode/       # VS Code 配置

# 4. 忽略所有子目录中的特定文件
**/logs/       # 任何位置的 logs 目录
**/*.backup    # 任何位置的 .backup 文件

# 5. 忽略文件名包含特定字符串的文件
*temp*         # 文件名包含 temp 的文件
*cache*        # 文件名包含 cache 的文件

# 6. 忽略特定目录下的特定文件
src/*.class    # 只忽略 src 目录下的 .class 文件
docs/*.pdf     # 只忽略 docs 目录下的 PDF 文件

# 7. 例外规则(不忽略)
!important.log # 即使匹配 *.log,也不忽略这个文件
!build/keep.txt # 即使 build/ 被忽略,也保留这个文件

# 8. 系统文件
.DS_Store      # macOS 系统文件

规则说明:

  • * 匹配任意字符(除了 /)
  • ** 匹配任意目录层级
  • / 结尾表示目录
  • ! 开头表示例外(不忽略)
  • # 开头表示注释

.gitignore 练习题 (学会描述,AI生成)

题目

  1. 忽略名为 build 的文件夹。
  2. 忽略所有的 .log 文件。
  3. 已忽略 build/,但需跟踪 build/deploy.txt。
  4. 忽略 src 目录下所有 .tmp 文件。
  5. 忽略 docs 目录下所有以 ~ 结尾的文件。
  6. 忽略 test 目录下所有 .pyc 和 test/results 目录。
  7. 规则 *.log 和 !app.log 叠加会怎样?
  8. 忽略 .min.js, .env, .db, node_modules/, *.swp 文件。

答案

  1. build/
  2. *.log
  3. build/
    !build/deploy.txt
  4. src/*.tmp
  5. docs/*~
  6. test/*.pyc
    test/results/
  7. 除 app.log 外所有 .log 文件被忽略。
  8. *.min.js
    .env
    *.db
    node_modules/
    *.swp

基本命令:回滚版本

如果提交了错误的代码或想回到之前的某个版本,可以使用 git reset。

# 回滚到指定的 commit ID
git reset --hard <commitID>

--hard 参数会使工作区、暂存区和版本库都回退到指定状态,之后的提交记录会丢失。

如何找回“丢失”的提交?

如果回滚后又后悔了,可以使用 git reflog 查看所有HEAD的移动记录,找到回滚前的commit ID,再次使用 git reset --hard 即可恢复。

git reflog

分支 (Branches)

分支是Git的“杀手锏”功能。它允许你从主开发线上分离出来,创建一条独立的开发路线,用于开发新功能或修复bug,而不会影响主线的稳定性。

分支就像是Git世界里的‘平行宇宙’。你可以随时打开一个‘副本世界’,在里面大胆尝试新想法、修修补补,哪怕翻个底朝天,也不会影响到主宇宙的安宁。等你觉得一切都完美了,再把成果‘合并’回主线,就像把平行宇宙的成功经验带回现实世界。

Branch

在Git内部,分支仅仅是一个指向特定提交的轻量级指针。

分支操作:创建与切换

查看所有分支 (* 表示当前所在分支):

git branch

基于当前分支创建一个名为 `test` 的新分支:

git branch test

切换到 `test` 分支进行工作:

git checkout test
# 或者使用新命令: git switch test

在 `test` 分支上的所有提交都与 `master` 分支隔离,互不影响。

切换回 `master` 分支后,文件内容会恢复到 `master` 分支的状态。

查看动画演示

Branch divergence

分支操作:合并与冲突

当 `test` 分支的功能开发完成后,我们希望将其合并回 `master` 主分支。

# 1. 首先切换回主分支
git checkout master

# 2. 执行合并命令
git merge test

示例:合并冲突的具体场景

假设我们有一个 `hello.txt` 文件,在不同分支中被修改:

# 在 master 分支中,hello.txt 的内容是:
234

# 在 test 分支中,hello.txt 被修改为:
123-test

# 当我们在 master 分支执行 git merge test 时:
git checkout master
git merge test

解决冲突

在上面的示例中,由于 `master` 和 `test` 分支都修改了 `hello.txt` 文件的同一部分,合并时就会产生冲突 (Conflict)。Git会暂停合并,并在冲突文件中用特殊标记标出冲突区域:

# Git 会在 hello.txt 中显示冲突标记:
<<<<<<< HEAD
234
=======
123-test
>>>>>>> test

其中 `<<<<<<< HEAD` 到 `=======` 之间是当前分支(master)的内容,`=======` 到 `>>>>>>> test` 之间是要合并分支(test)的内容。

Conflict markers

手动编辑文件,保留需要的内容并删除冲突标记,然后再次 `git add` 和 `git commit` 即可完成合并(点击查看演示)

分支操作:变基 (Rebase)

除了合并,还可以使用 `rebase` (变基) 来整合分支。变基会提取当前分支的修改,然后将它们在目标分支的最新提交之后“重放”一遍,形成一条线性的提交历史。

Rebase
git checkout test
git rebase master

Merge vs. Rebase: Merge保留了真实的分支历史,而Rebase创建了更整洁的线性历史。

选择哪种方式取决于团队的协作规范(查看演示)。

分支操作:优选 (Cherry-pick)

有时我们不需要合并整个分支,只想将另一个分支的某一个或几个特定的提交应用到当前分支。这时可以使用 cherry-pick。

# 将指定的 commit 应用到当前分支
git cherry-pick <commit_id>
Cherry-pick

这是一种非常灵活的分支内容整合方式(查看演示)。

* 使用IDEA进行版本控制 (1/6)

创建项目

虽然命令行很强大,但图形化界面(GUI)更直观。我们以IDEA为例。在创建新项目时,记得勾选“创建Git仓库”。

IDEA create Git repository

项目创建后,点击左下角的“版本控制”或“Git”标签,可以查看版本状态。

* 使用IDEA进行版本控制 (2/6)

添加文件到暂存区

新建一个 hello.txt 文件。此时文件名会显示为红色,表示它是一个未追踪的文件。

Untracked files (red)

右键点击文件 -> Git -> 添加 (Add)。

Add files

添加后,文件名变为绿色,表示已进入暂存区。

* 使用IDEA进行版本控制 (3/6)

提交更改

点击工具栏上的提交按钮(通常是一个绿色的勾),打开提交窗口。

Commit button

在窗口中输入提交信息,然后点击“提交”按钮。提交后,可以在Git日志中看到新的提交记录。

Commit log

* 使用IDEA进行版本控制 (4/6)

分支操作

点击IDEA右下角的分支名称(如 `master`),可以方便地进行分支操作。

Branch menu

选择“新建分支”,输入分支名(如 `dev`)即可创建并切换到新分支。在 `dev` 分支修改并提交后,Git日志图会清晰地展示出分支的演进。

Branch graph

* 使用IDEA进行版本控制 (5/6)

合并与冲突解决

假设我们在 `master` 和 `dev` 分支上都修改了 `hello.txt`,现在要将 `dev` 合并到 `master`。

  1. 切换到 `master` 分支。
  2. 在分支菜单中选择 `dev` 分支,然后点击“合并到当前分支”。

如果出现冲突,IDEA会弹出一个冲突解决窗口。

Conflict resolution window

* 使用IDEA进行版本控制 (6/6)

合并与冲突解决 (续)

在三栏视图中,左侧是你的更改,右侧是对方的更改,中间是最终合并结果。你可以点击箭头按钮选择接受哪个版本的更改,或者直接在中间一栏手动编辑。

Three-column view

解决所有冲突后,点击“应用”,然后完成合并提交。Git日志图会显示一个清晰的合并节点。

Log after merge

远程仓库

远程仓库是托管在服务器上的Git仓库,用于团队协作和代码备份。常见的平台有 GitHub, Gitee, GitLab 等。

远程账户认证 (SSH)

为了让远程仓库识别你的身份,通常使用SSH密钥进行认证。

  1. 生成SSH密钥对:
    ssh-keygen -t rsa -C "your_email@example.com"
  2. 查看并复制公钥:
    cat ~/.ssh/id_rsa.pub (Linux/macOS)
    type %USERPROFILE%\.ssh\id_rsa.pub (Windows CMD)
    Get-Content $env:USERPROFILE\.ssh\id_rsa.pub (Windows PowerShell)
  3. 将复制的公钥添加到Gitee或GitHub的 "SSH公钥" 设置中。

这样,当你通过SSH协议与远程仓库交互时,服务器就能验证你的身份。

远程操作:推送 (Push)

将本地仓库的提交推送到远程仓库。

  1. 在Gitee上创建一个新的空仓库。
  2. 将远程仓库地址关联到本地仓库,并命名为 `origin`:
    git remote add origin git@gitee.com:username/repo.git
  3. 将本地 `master` 分支的提交推送到 `origin`:
    git push -u origin master
    -u 选项会建立本地分支与远程分支的跟踪关系,之后可以直接使用 git push。
Push successful

远程操作:克隆 (Clone)

从远程仓库复制一个完整的项目到本地,包括所有历史记录。

git clone git@gitee.com:username/repo.git
Clone principle

克隆操作会自动将远程仓库设置为 `origin`,并建立本地 `master` 分支对远程 `master` 分支的跟踪。

远程操作:拉取 (Pull) & 抓取 (Fetch)

当团队其他成员向远程仓库推送了新的提交后,你需要更新你的本地仓库。

git fetch (抓取)

从远程仓库下载最新的历史记录,但**不**会自动合并到你当前的工作分支。这让你有机会在合并前查看更改。

git fetch origin
# 查看抓取下来的分支
git branch -r
# 手动合并
git merge origin/master

git pull (拉取)

这是一个复合命令,相当于 git fetch + git merge。它会抓取最新内容并立即尝试合并到当前分支。

git pull origin master

贡献开源社区

掌握了Git,你就可以参与到全球的开源项目中!通常的流程 (Fork & Pull Request) 如下:

  1. Fork: 在GitHub/Gitee上,将你感兴趣的项目“复刻”一份到你自己的账户下。
  2. Clone: 将你自己账户下的项目克隆到本地。
  3. Branch: 创建一个新的分支来开发你的新功能或修复bug。
  4. Commit & Push: 完成修改后,提交并推送到你自己远程仓库的新分支上。
  5. Pull Request (PR): 在GitHub/Gitee上,向原始项目发起一个“拉取请求”,请求项目维护者将你的修改合并到主项目中。

参考视频:如何向开源社区贡献代码

教程结束

恭喜你!你已经掌握了Git的核心概念和常用命令。

版本控制是一项实践技能,请务必在你的项目中多多使用,熟能生巧。

接下来做什么?

  • 请通关这个游戏!!
  • 尝试在自己的项目中使用Git进行版本管理。
  • 学习使用图形化Git工具,如 SourceTree 或 VS Code 的 Git 插件。
  • 参与一个简单的开源项目,提交你的第一个Pull Request!
1 / X