跳转至

Git

主要内容

这篇是根据飞书 Git 与版本控制Git 与 Git 进阶Github与Gitlab工程规范 等文档整理的 Git 个人学习笔记。

主要参考:

前置知识:无,但最好能熟悉基本终端操作,例如 cdlsmkdirtouchcat

预计完成用时:0.5d 到 1d。第一遍能完成基础命令和冲突练习即可,进阶命令可以在真实项目里逐步补齐。

学习目标

基本目标

  • 理解 Git、GitHub/GitLab 与版本控制的基本作用。
  • 建立使用 Git 管理代码和协作开发的基本意识。
  • 掌握常见 Git 基础操作:克隆、提交、推送、拉取、分支切换、查看状态、查看历史。
  • 知道代码托管平台在协作、开源参与中的基本用途。

进阶目标

  • 能使用 Git 完成日常开发中的基础版本管理和协作操作。
  • 能参与 Issue、PR/MR 等协作流程。
  • 能处理冲突、回滚错误、临时保存修改、整理本地历史。
  • 对开源社区、协作规范与开源伦理有基本认识。

为什么要学 Git

最开始我很容易把 Git 理解成“云端备份工具”。但文档强调了两个关键词:版本控制协作

真正在实际的工程项目中代码几乎没有一次写完的。一个项目会经历需求变化、bug 修复、多人并行开发、线上回滚、版本发布、实验性尝试等情况。如果没有版本控制,就会退回到压缩包、文件名后缀、聊天软件传附件这种混乱的方式:

project-final.zip
project-final-new.zip
project-final-new-fix.zip
project-final-new-fix-real.zip

Git 解决的是:

  • 我能知道项目在某个时间点是什么样子。
  • 我能比较两次提交之间到底改了什么。
  • 我能把一次修改命名、归档、回溯。
  • 我能开一条分支做实验,不影响主线。
  • 多个人可以同时开发,再把结果合并。
  • 出错后可以回退,或者用新提交抵消错误。

GitHub/GitLab 解决的是另一层问题:

  • 把 Git 仓库放到一个大家都能访问和协作的平台上,并提供 Issue、PR/MR、权限管理、代码评审、CI/CD、开源社区等能力。

所以,会 Git 命令只是第一步;会协作开发,还要会提交清晰的 commit、开分支、提 PR/MR、处理 review、遵守分支策略、保护主分支。

版本控制

VCS 是什么

VCS 是 Version Control System,即版本控制系统。它负责记录、管理、回溯文件的修改历史。

按历史形态看,可以分为:

类型 说明 例子 个人理解
VCS 人工 手动复制文件、改文件名、打压缩包 final_v2.zip 小作业还能忍,团队项目不可维护
LVCS 本地版本控制 版本历史主要保存在本机 RCS 解决个人历史,但协作能力弱
CVCS 集中式版本控制 中央服务器保存主要历史 SVN 大家围绕中央服务器工作
DVCS 分布式版本控制 每个人本地都有完整仓库历史 Git、Mercurial 离线可用,分支和协作更灵活

Git 是 DVCS。它不要求每次操作都联网,因为本地就有完整仓库。只有 pullpushfetchclone 等与远程交互的命令才需要网络。

分支模型和 Workflow

分支模型不是 Git 自带的强制规则,而是团队约定的协作方式。

常见分支可以分为两类:

分支类别 分支 作用
常驻分支 main / master / production 产品分支,可发布版本,应该稳定
常驻分支 develop / development 开发主线,从产品分支创建,聚合日常开发
活动分支 feature/* 从开发分支创建,开发某个特性
活动分支 hotfix/* 从产品分支创建,紧急修复线上 bug
活动分支 release/* 从开发分支创建,进入正式发布前的整理和修复

如果是个人小项目,main + feature/* 足够。

如果是多人项目,至少应该避免所有人直接往 main 上提交。

Git 介绍

什么是 Git

Git 原作者是 Linus Torvalds, Linux 内核的作者。

Git 是分布式版本控制系统,有几个关键点:

  • 分布式:不联网也能提交、查看历史、切分支。
  • 版本控制:记录、管理、回溯文件修改历史。
  • 基于内容寻址:Git 更像是在保存内容快照和对象,而不是简单保存“文件名”。
  • 本地仓库完整:每个 clone 下来的仓库都带有完整历史。

Git 的四个区域

工作区 Working Tree
  -> 暂存区 Staging Area / Index
  -> 本地仓库 Local Repository
  -> 远程仓库 Remote Repository
命令 作用 对应流向
git status 查看当前状态 工作区/暂存区
git add 把修改加入暂存区 工作区 -> 暂存区
git commit 生成本地提交 暂存区 -> 本地仓库
git push 上传提交 本地仓库 -> 远程仓库
git fetch 拉取远程对象但不自动合并 远程仓库 -> 本地仓库
git pull 拉取并合并/变基 远程仓库 -> 本地仓库/工作区
git diff 比较差异 工作区、暂存区、提交之间

不确定时先 git status,再决定下一步。

安装与准备

安装可参考 Atlassian 的 Install Git 文档。安装后先确认版本:

git --version

然后配置身份。这个身份会写进 commit 里:

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

查看配置:

git config --list
git config --global --list

如果只想对某一个仓库设置身份,就在该仓库目录下去掉 --global

git config user.name "Project Name"
git config user.email "project_email@example.com"

创建本地版本库

git init

git init 会让当前文件夹变成 Git 仓库,本质是创建 .git 隐藏目录。

git init

也可以创建新目录并初始化:

git init my-project

初始化之后,文件还不会自动进入版本控制。要经过 addcommit

git status
git add .
git commit -m "chore: initial commit"

.git 目录

.git 是仓库的核心目录,里面保存对象、引用、配置、索引等内容。不要手动乱改 .git,除非很清楚自己在做什么。

.gitignore

.gitignore 放在版本库根目录下,规定哪些文件不要进入 Git 版本库。

常见应该忽略的内容:

node_modules/
dist/
build/
.env
*.log
.DS_Store
.idea/
.vscode/

.gitignore 的意义在于保持工程卫生,使依赖目录、构建产物、日志、私密配置等不污染仓库。

基本语法

规则 含义 例子
# 开头 注释 # logs
* 通配多个字符 *.log
** 通配中间目录 a/**/b 可匹配 a/ba/x/ba/x/y/b
/ 开头 只匹配仓库根目录 /dist 只忽略根目录 dist
/ 开头 可匹配任意目录 dist 可忽略任意层级 dist
! 取消忽略 !README.md

检查某个文件为什么被忽略:

git check-ignore -v <file>

常用模板可以参考 GitHub 的 github/gitignore 仓库。

暂存区、修改与提交

git add

git add <file>
git add <folder>
git add .

git add: 把修改加入暂存区。

暂存区像一次 commit 的草稿篮子:可以只提交一部分文件,而不把工作区所有修改都提交。

git commit

git commit

不带 -m 会打开默认编辑器,要求手动写提交信息。

git commit -m "feat(auth): add login form"

-m 适合较短提交。复杂提交建议写多行:

git commit

然后在编辑器里写:

feat(auth): add login form

Add controlled inputs for email and password.
Validate required fields before submitting.

Closes #12

git diff

git diff

比较工作区和暂存区。

git diff --cached

比较暂存区和 HEAD。

git diff main feature/login

比较两个分支。

git diff <commit1> <commit2>

比较两次提交。

提交前一般可以按照这个顺序看一下:

git status
git diff
git add .
git diff --cached
git commit -m "..."

Commit Message

Angular/Conventional Commits 风格。

一个完整格式大概是:

<type>(<scope>): <summary>

<body>

<footer>

常见字段:

字段 说明 例子
type 更改类型 featfixdocs
scope 影响范围,可选 authstorageapi
summary 简短描述 add login form
body 详细描述,可选 说明为什么改、怎么改
footer issue、破坏性变更等 Fixes #12

常见 type:

类型 含义
feat 新功能
fix 修复 bug
docs 文档修改
style 格式修改,不影响逻辑
refactor 重构,不是新增功能也不是修 bug
perf 性能优化
test 测试相关
ci CI/CD 配置相关
chore 工具、依赖、构建等杂项

重大更改可以写:

BREAKING CHANGE: change auth token format

或:

DEPRECATED: old upload API is deprecated

英文 summary 常见要求:一般现在时、首字母小写、句末无句号。

文件状态

分为三类:

状态 含义
Untracked 未跟踪,新建的本地文件,还没进入版本库
Tracked 已追踪,已经在版本库里
Ignored 被忽略,本地存在,但 .gitignore 规定不纳入版本控制

git status 会说明当前文件处于哪种状态。很多 Git 初学问题,其实是没分清:工作区改了、暂存区改了、还是已经 commit 了。

查看历史

git log

常用变体:

git log --oneline
git log --graph
git log --oneline --graph
git log --oneline --graph --all
git log --stat
git log -p
命令 用途
git log --oneline 每个提交显示一行,适合快速看历史
git log --graph 显示分支结构
git log --stat 显示文件删改统计
git log -p 显示具体修改内容

我常用:

git log --oneline --graph --all --decorate

它能让我看到分支结构、HEAD、tag 和远程分支位置。

分支

分支是什么

分支不是完整复制一份项目,而是指向某次提交的指针。因为 Git 的对象模型,创建分支非常轻量。

创建分支

git branch <name>

基于当前 HEAD 创建。

git branch <name> <commit-id>

基于某次提交创建。

git checkout -b <name>

创建并切换分支。

新写法:

git switch -c <name>

查看分支

git branch
git branch -a
git branch -v
git show-branch
命令 说明
git branch 查看本地分支
git branch -a 查看本地和远程分支
git branch -v 显示分支及其最新提交
git show-branch 更详细地显示分支关系

切换分支

git checkout <name>
git checkout <commit-id>
git checkout -

新写法:

git switch <name>
git switch -

git checkout -git switch - 可以回到上一个分支。

删除分支

git branch -d <branchname>

如果分支未合并,-d 会拒绝删除。强制删除是:

git branch -D <branchname>

强制删除前要确认这个分支确实不要了。

checkout 的另一个用法

飞书原文提到:

git checkout -- <file>

它会把某个文件从暂存区/HEAD 还原到工作区,用来撤销本地修改。新版本 Git 更推荐用:

git restore <file>

如果是把暂存区撤回来:

git restore --staged <file>

合并

merge

merge 会把其他分支合入当前分支:

git merge <branch>

也可以把多个分支合进当前分支:

git merge <branch1> <branch2>

合并结果会进入工作区和暂存区。如果有冲突,需要人工解决。

多人协作时,一般不直接在命令行把别人分支合进主分支,而是通过 GitHub/GitLab 的 PR/MR 完成,这样可以留下讨论、评审和 CI 检查记录。

squash merge

squash merge 会把目标分支多出的多个提交压缩成一个新提交,再合入当前分支。

适合:功能分支上有很多“试一下”“修一下”的临时提交,但最终希望主线历史简洁。

代价:原来的细粒度提交历史不会原样保留在主线。

rebase

rebase 是变基,会把当前分支的提交接到目标分支后面:

git rebase main

本地功能分支上,rebase 可以让历史更线性。但它会改写提交历史,所以协作时不要随便 rebase 已经公开、别人也基于它开发的分支。

命令行直接 rebase 会导致提交历史改变,同步时可能冲突,合作时不推荐随意使用。

GitHub PR 里的 rebase merge 和命令行 rebase 的历史方向理解上容易混淆。实际使用时只要记住:会改写历史的操作,不要轻易用在公共分支。

冲突

Git 无法自动判断两个修改谁应该保留。

典型流程:

git merge feature/login
# 出现 conflict

查看状态:

git status

冲突文件里通常会出现:

<<<<<<< HEAD
当前分支内容
=======
被合并分支内容
>>>>>>> feature/login

解决方式:

  1. 打开冲突文件。
  2. 判断应该保留哪部分,或手动合并两边逻辑。
  3. 删除冲突标记。
  4. 运行测试或至少运行项目。
  5. git add 解决后的文件。
  6. 完成 merge commit。
git add <file>
git commit

我的经验:解决冲突不要只看文本,要看业务语义。有时两边代码都要保留,但需要重新组织顺序。

修改提交历史

飞书原文提醒得很重要:Git 的提交历史可以修改,但如果项目已经公开且有他人协作,就不应该随意修改公共历史。

revert

git revert <commit-id>

revert 不会删除旧提交,而是生成一个新提交,用来撤销目标提交的更改。

适合:公共分支、线上分支、已经 push 出去的提交。

commit --amend

修改最新提交的提交信息:

git commit --amend

或直接指定新 message:

git commit --amend -m "fix(auth): handle empty password"

它本质上会创建一个新提交替换旧提交,所以也是修改历史。不建议对已经协作共享的提交随便 amend。

有时也可以用 amend 把漏掉的文件补进上一个提交:

git add missed-file.js
git commit --amend

reset

git reset <commit-id>

reset 会移动 HEAD/分支指针。常见模式:

模式 HEAD 暂存区 工作区 用途
--soft 回退 不改 不改 撤销提交但保留暂存
--mixed 回退 回退 不改 撤销提交和暂存,保留文件修改,默认模式
--hard 回退 回退 回退 完全回到目标提交,危险

例子:

git reset --soft HEAD~1
git reset --mixed HEAD~1
git reset --hard HEAD~1

--hard 会丢弃工作区修改,使用前要非常确定。

reflog

如果 reset 错了,可以尝试:

git reflog

reflog 记录 HEAD 的移动历史,可以帮我找回刚刚所在的提交。但它不是永久保险,时间太久或清理后可能丢失。

git stash

stash 是隐藏区,可以理解为一个栈。它适合临时保存未完成修改,让工作区变干净。

典型场景:

  • 正在一个分支工作,突然需要切到另一个分支处理紧急问题。
  • 做了一些实验性修改,不想 commit,但也不想丢。
  • 切分支时 Git 提示本地修改会被覆盖。

常用命令:

git stash
git stash list
git stash apply stash@{0}
git stash drop stash@{0}
git stash pop
命令 说明
git stash 保存当前修改到 stash 栈
git stash list 查看所有 stash
git stash apply stash@{0} 恢复某个 stash,但不删除记录
git stash drop stash@{0} 删除某个 stash
git stash pop 恢复栈顶 stash,并删除它

补充:如果想顺手写说明,可以用:

git stash push -m "wip login page"

stash 不是长期保存方案。长期有价值的工作应该 commit 到分支。

tag 与语义化版本

tag 常用来标记版本发布点。

创建标签

轻量标签:

git tag v1.0.0

给某个提交打标签:

git tag v1.0.0 <commit-id>

附注标签:

git tag -a v1.0.0 -m "release v1.0.0"

查看标签:

git tag

推送标签:

git push origin v1.0.0
git push origin --tags

语义化版本

格式:

v主版本号.次版本号.修订号[-预发布版本号]

例子:

v1.0.0-beta < v1.0.0-rc.1 < v1.0.0 < v1.0.1

含义:

字段 含义
修订号 patch 兼容修改,修正不正确的行为
次版本号 minor 添加新功能,但保持兼容
主版本号 major 不兼容的 API 修改
0.y.z 表示仍在开发阶段,不保证稳定
预发布版本 alphabetarc.1

进阶命令

飞书原文把这部分列为可选,但它们在真实项目里很常见。

fetch / pull / push

git fetch origin

只拉取远程信息,不自动合并。

git pull origin main

拉取并合并,通常相当于 fetch + merge,也可能配置为 fetch + rebase

git push origin <branch>

把本地分支推到远程。

cherry-pick

git cherry-pick <commit-id>

把某个提交单独摘到当前分支。适合只想拿某个 bugfix,而不是合并整个分支。

show

git show <commit-id>

查看某次提交的详细内容。

也可以看 tag:

git show v1.0.0

interactive rebase

git rebase -i HEAD~3

可以整理最近几个本地提交,例如 squash、reword、drop。只建议用于尚未公开的本地分支。

force push

git push --force-with-lease

如果 rebase 或 amend 后需要推送改写后的历史,可能要 force push。比 --force 更稳的是 --force-with-lease,它会检查远程是否有别人新提交,降低覆盖别人工作的风险。

但原则是:公共分支尽量不要 force push。

Git Hooks

Git Hooks 是在 Git 特定事件前后自动执行脚本的机制。例如:

  • commit 前检查格式。
  • commit 前检查敏感信息。
  • push 前运行测试。
  • merge 后清理或生成文件。

常见 hook:

Hook 触发时机 常见用途
pre-commit commit 前 格式化、lint、密钥扫描
commit-msg commit message 写完后 检查 commit 格式
pre-push push 前 运行测试

飞书 Hooks 文档还把 Git Hooks 和 AI Agent Hooks 类比:本质都是在某个事件发生时触发自动化动作。区别是 Git Hooks 更偏固定脚本,Agent Hooks 可能让模型或工具参与判断。

远程版本库

Git 是分布式 VCS,但多人协作通常需要一个远程的“权威”版本库。远程仓库也是普通 Git 仓库,只是放在 GitHub/GitLab/Gitee 或团队服务器上。

clone

git clone <src>

指定目录:

git clone <src> <dest>

clone 会自动建立 remote 关联,通常叫 origin

查看远程:

git remote -v

添加远程:

git remote add origin <repo-url>

修改远程地址:

git remote set-url origin <repo-url>

pull 与 push

git pull <remote> <branch>
git push <remote> <branch>

常见:

git pull origin main
git push origin feat/login

第一次推送新分支时:

git push -u origin feat/login

-u 会建立 upstream,之后可以直接:

git push
git pull

SSH 与远程连接

远程仓库可以用 HTTPS,也可以用 SSH。SSH 的关键是公钥和私钥。

飞书原文建议使用 ed25519:相较 RSA,key 更短,安全性也更好。

生成 SSH key:

ssh-keygen -t ed25519 -C "your_email@example.com"

生成后通常会在用户目录下出现 .ssh 文件夹:

~/.ssh/id_ed25519
~/.ssh/id_ed25519.pub
文件 能不能公开 说明
私钥,无 .pub 后缀 不能 只能自己保存,不能上传网络,不能发给别人
公钥,.pub 结尾 可以 上传到 GitHub/GitLab Settings

测试 GitHub:

ssh -T git@github.com

测试 GitLab 时把域名换成对应 GitLab 域名。

一个冷知识:可以通过下面的地址看到某个 GitHub 用户公开添加的 SSH 公钥:

https://github.com/<用户名>.keys

GitLab 也有类似能力。

GitHub / GitLab / Gitee

为什么需要代码托管平台

如果团队还在用压缩包分享代码,每个人的一次更新都要手动同步,合并也只能靠人肉复制。代码托管平台相当于一个统一的协作中心:大家把更新推上去,再通过一套流程形成最新版本。

GitHub/GitLab/Gitee 不是 Git 本身,而是围绕 Git 提供协作能力的平台。

GitHub

GitHub 是最知名的代码托管和开源社区平台。它提供:

  • 仓库托管。
  • Issue 讨论和任务管理。
  • Pull Request。
  • GitHub Actions。
  • Release。
  • Star、Fork、Watch 等开源社区机制。

一般情况下访问 GitHub 可能受网络环境影响。飞书原文也提到,如果暂时无法解决访问问题,可以先用 Gitee 学习基本流程。

GitLab

GitLab 可以理解为企业或组织内部常用的 Git 托管平台。学校、实验室、公司都可以部署自己的 GitLab。

飞书原文提到:

  • gitlab.com
  • X-Lab GitLab:https://xlab.zju.edu.cn/git

GitLab 中 Pull Request 通常叫 Merge Request,即 MR。

Git Workflow

为什么需要 Workflow ?

设想多人都在 main 分支上提交:

  • 冲突频繁
  • main 可能长期不可用
  • 不知道哪个提交可以发布
  • 难以管理 release
  • review 和测试没有统一入口

Git Workflow 就是一套使用 Git 的流程规范。

Feature Branch Workflow

适合实验室和多数 Web 项目入门协作。

main
  -> feat/login
  -> feat/comment-api
  -> fix/upload-error

基本流程:

  1. 从稳定分支拉取最新代码。
  2. 创建功能分支。
  3. 在功能分支开发和提交。
  4. 推送功能分支到远程。
  5. 提 PR/MR。
  6. 经过 review 和 CI 后合并。
  7. 删除已合并的功能分支。

命令示例:

git switch main
git pull origin main
git switch -c feat/comment-api
# edit files
git status
git diff
git add .
git commit -m "feat(comment): add create comment api"
git push -u origin feat/comment-api

GitFlow Workflow

GitFlow 更适合发布节奏明确、版本管理更复杂的项目。

常见分支:

main / production
develop
feature/*
release/*
hotfix/*

我的理解:

  • main 保持可发布。
  • develop 聚合开发成果。
  • feature/* 做新功能。
  • release/* 做发布前收尾。
  • hotfix/* 从生产分支拉出,快速修线上问题。

GitFlow 比 Feature Branch 更重。小项目不要为了“看起来专业”而强行上复杂流程。

Forking Workflow

适合开源项目或没有直接写权限的仓库。

基本流程:

  1. Fork 原仓库到自己的账号。
  2. Clone 自己的 fork。
  3. 添加原仓库为 upstream。
  4. 在自己的分支开发。
  5. Push 到自己的 fork。
  6. 向原仓库提 PR。
git remote -v
git remote add upstream <original-repo-url>
git fetch upstream
git switch main
git merge upstream/main

飞书原文提到内部一般更常用 Feature Branch Workflow,但了解 Forking Workflow 有助于参与开源。

PR / MR

Pull Request 或 Merge Request 不是“我写完了,帮我合一下”的通知,而是一个可讨论、可审核、可追踪的变更单元。

一份好的 PR/MR 通常包含:

  • 改了什么。
  • 为什么改。
  • 如何验证。
  • 有无截图或日志。
  • 是否影响接口、数据库、配置、部署。
  • 关联的 Issue。

PR/MR 的价值:

  • 避免所有人直接改主分支。
  • 让代码评审有固定入口。
  • 让 CI 自动检查有触发点。
  • 让未来回溯知道当时为什么这样改。

工程规范相关

飞书 工程规范.md 把 Git 学习延伸到协作规范:目录结构、命名、commit、PR、整洁代码。

为什么需要工程规范

  • 提高代码和项目可读性
  • 提高可维护性
  • 提高协作效率
  • 帮助 AI 工具理解项目结构

项目目录规范

可以观察开源项目里的目录名:

目录 常见含义
common 通用逻辑、工具、类型
dao 数据访问层
service 业务逻辑层
controller 请求入口或接口控制层
components 前端组件
hooks React Hooks 或复用逻辑
tests 测试
scripts 自动化脚本

目录规范的目的不是套模板,而是让人能快速定位代码职责。

命名

命名要表达语义,并和语言/团队风格一致。

  • 小驼峰:userNamegetUserInfo
  • 大驼峰:UserProfileCreateOrderRequest
  • snake_case:user_nameget_user_info
  • kebab-case:user-profilecreate-order
  • 常量:MAX_RETRY_COUNT

代码整洁原则

飞书原文提到 Clean Code、Clean Architecture、SOLID、DRY、KISS。

我的简化理解:

原则 笔记
SRP 单一职责 一个模块最好只有一个变化理由
OCP 开闭原则 尽量通过新增代码扩展行为,而不是频繁修改旧代码
LSP 里氏替换 子类型应能替换父类型,不破坏约定
ISP 接口隔离 不要让调用方依赖用不到的接口
DIP 依赖反转 高层策略不应依赖底层细节,细节应依赖抽象
DRY 避免重复,把同一逻辑集中维护
KISS 能简单就简单,避免不必要复杂度

这些原则和 Git 的关系是:Git 记录变化,但工程规范决定变化是否容易被理解、review 和维护。

Git 与 AI/Vibe Coding

飞书 Vibe Coding 文档里有一句很重要的话:Git 是 Vibe Coding 的“后悔药”。

用 AI 写代码时,改动速度会非常快,如果没有 Git,很容易从“自动化加速”变成“自动化制造混乱”。

我的实践方式:

git switch -c experiment/vibe-demo
# 让 AI 完成一个小阶段
git status
git diff
git add .
git commit -m "feat: add first todo prototype"

原则:

  • AI 每完成一个明确阶段,就 commit。
  • 尝试新奇方案时开实验分支。
  • 方向错了直接回到稳定分支,不要在坏代码上继续堆修复。
  • 提交前一定看 diff,不要无脑接受所有改动。
日常 Git 流程
  • 新项目
mkdir my-project
cd my-project
git init
git config user.name "Your Name"
git config user.email "your_email@example.com"
printf "node_modules/\ndist/\n.env\n" > .gitignore
git add .
git commit -m "chore: initial commit"
  • 参与已有项目
git clone <repo-url>
cd <repo-name>
git switch main
git pull origin main
git switch -c feat/my-task
  • 提交前
git status
git diff
git add .
git diff --cached
git commit -m "feat(scope): summary"
  • 提 PR/MR 前
git switch main
git pull origin main
git switch feat/my-task
git merge main
# or: git rebase main, only if this is my private branch
git push -u origin feat/my-task
  • 出问题时
git status
git log --oneline --graph --all
git reflog

先看状态和历史,再决定 restorerevertreset 还是重新开分支。

Practice

本部分练习可以在 X-Lab GitLab 或 GitLab/GitHub/Gitee 上完成。

远程版本库管理:

本地版本管理练习

  1. 新建一个 Git 仓库。
  2. main 分支上进行一版更新。
  3. 新建一个有辨识度的 branch,例如 feat/conflict-demo
  4. 分别在 main 分支与 branch 分支上提交一版更新,保证这两个更新会产生冲突。
  5. Merge 自建 branch 到 main 分支,处理 conflict。
  6. main 分支中提交一版更新。
  7. 将 branch 同步到 main 分支的最新更新上。

GitHub/GitLab 练习

  1. 根据 GitHub 官方 hello-world 教程创建一个代码仓库。
  2. 在平台上创建一个 Issue。
  3. main 创建一个功能分支。
  4. 推送分支并提 PR/MR。
  5. 在 PR/MR 描述里写清楚改动和验证方式。
  6. 合并后删除远程功能分支。

可视化练习

  • Learn Git Branching
  • 搜索 Git 分支可视化教程,辅助理解 merge、rebase、reset、cherry-pick。

常见坑

  • 把私密配置提交了

.env、数据库密码、token、私钥都不应该提交。已经提交到公开仓库时,删除文件再 commit 不等于从历史中消失,需要进一步清理历史并轮换密钥。

  • 在主分支直接开发

个人项目偶尔可以,但团队项目最好用功能分支和 PR/MR。

  • 不看 diff 就 commit

尤其使用 AI 工具时,一定要看 diff。AI 可能顺手改了不该改的文件。

  • 乱用 reset --hard

reset --hard 会改工作区。没有备份或没有确认前不要用。

  • 对公共分支 rebase/force push

这可能覆盖或打乱别人的工作。除非团队流程明确要求,否则不要这样做。

  • commit 太大

一个 commit 改了十件事,review 和回滚都会痛苦。更好的方式是按语义拆分提交。

一些名词

  • HEAD

HEAD 表示当前工作位置,通常指向当前分支的最新提交。理解 HEAD 有助于理解 resetcheckoutrebase

  • Index

Index 就是暂存区。它决定下一次 commit 里会包含哪些内容。

  • Origin

origin 是默认远程仓库名,不是固定必须叫这个,只是 clone 后常见默认名。

  • Upstream

本地分支关联的远程分支叫 upstream。有 upstream 后,可以直接 git pullgit push

  • Fast-forward

如果当前分支没有额外提交,合并另一个分支时只需要移动指针,这叫 fast-forward。

  • 冲突

冲突: Git 无法自动判断两个修改谁应该保留。解决冲突的过程本质是人工合并语义。

  • PR

PR :把代码变更转化为可讨论、可审核、可追踪的协作单元。

思考题
  1. 大家可以看到,我们在文中将 Git 与 GitHub/GitLab 并列介绍。版本控制系统与代码托管平台分别解决什么问题?为什么会用 Git 不等于会协作开发?

    版本控制系统解决的是代码历史管理问题。Git 可以记录每次修改、比较差异、创建分支、合并分支、回滚错误。它主要回答“代码如何随时间变化”。

    代码托管平台解决的是多人围绕代码协作的问题。GitHub/GitLab 提供远程仓库、Issue、PR/MR、权限管理、CI/CD、代码评审、Release 和开源社区入口。它主要回答“多人如何围绕同一份代码工作”。

    会 Git 只是会操作版本历史;协作开发还需要知道如何拆任务、命名分支、写 commit、提交 PR/MR、说明改动、接受 review、处理冲突、保护主分支、遵守开源协议。这些都不是单靠 Git 命令能自动完成的。

  2. 这一块内容要多多实践,推荐大家去试试相关的操作,去提个 Issue,提个 PR,都会让我们对此部分内容理解得更加深入。

    我的实践路线是:先在自己的仓库完成 init -> add -> commit -> branch -> merge -> conflict,再到 GitHub/GitLab 上完成 Issue -> branch -> push -> PR/MR -> review -> merge。前者练的是 Git 的版本模型,后者练的是平台协作流程。

    如果只在本地练 Git,很容易忽略权限、远程分支、PR 描述、CI 检查和 review;如果只会在网页上点按钮,又会在冲突、回滚、同步分支时手忙脚乱。所以这两部分要一起练。

  3. 什么是小驼峰命名?什么是 snake_case 命名?

    小驼峰是第一个单词首字母小写,后续单词首字母大写,例如 userNamegetUserInfocreateOrder

    snake_case 是用下划线连接小写单词,例如 user_nameget_user_infocreate_order

    不同语言和团队有不同习惯。JavaScript/TypeScript 里变量和函数常用小驼峰,Python 里变量和函数常用 snake_case。关键不是某种命名绝对更好,而是项目内部保持一致。

  4. Commit 时,featfix 等分别表示什么含义?

    它们是 commit message 中的提交类型,帮助别人快速理解这次提交的性质。

    • feat:新增功能。
    • fix:修复 bug。
    • docs:文档修改。
    • style:格式修改,不影响代码逻辑。
    • refactor:重构,不是新增功能也不是修 bug。
    • perf:性能优化。
    • test:测试相关。
    • ci:CI/CD 配置相关。
    • chore:依赖、构建、工具配置等杂项。

    例如 feat(storage): add file upload api 表示在 storage 这个范围内新增了文件上传接口。