Git与GitHub——代码的"时光机"与"协作平台"
写在前面:想象你写一篇3万字的毕业论文,每改一版都要另存为"论文_v1""论文_v2_最终版""论文_v2_最终版_真的最终版"...。Git就是帮你彻底告别这种噩梦的工具——它记录每一次改动,随时可以"时光倒流"。GitHub则把Git搬到了云端,让全世界的人一起协作。本章我们从零开始,把Git和GitHub玩明白!
1 版本控制的概念——为什么需要"后悔药"
生活类比
版本控制就像手机相册的"编辑历史":你对照片做了裁剪、调色、加滤镜,每一步都可以回退到之前的状态,而不用重新拍一张。
没有版本控制的痛苦
| 场景 | 结果 |
|---|---|
| 删了一段代码,后来发现还需要 | 找不回来了 |
| 两人同时改同一个文件 | 互相覆盖,不知道谁改了什么 |
| 想看看上周的代码长什么样 | 没法对比,只能凭记忆 |
| 上线后发现bug | 不知道是哪次提交引入的 |
SVN vs Git 对比
| 特性 | SVN(集中式) | Git(分布式) |
|---|---|---|
| 架构 | 中央服务器存储所有版本 | 每个人本地都有完整仓库 |
| 离线工作 | 无法提交 | 可以离线提交,之后再推送 |
| 分支管理 | 分支=目录拷贝,笨重 | 分支=指针移动,极轻量 |
| 速度 | 每次操作都要连服务器 | 大多数操作在本地完成,极快 |
| 适用场景 | 小团队、老项目 | 几乎所有现代项目 |
互动提问:为什么Git是"分布式"的?好处是什么?
点击查看答案
每个开发者的电脑上都有完整的仓库副本(包含所有历史),即使服务器宕机,任何一个人的本地仓库都可以恢复整个项目。这就是分布式的安全感。
2 Git安装——各发行版安装方式
CentOS / RHEL
# 使用yum安装
sudo yum install -y git
# 验证安装
git --version
Ubuntu / Debian
# 先更新软件源
sudo apt update
sudo apt install -y git
# 验证
git --version
从源码编译(获取最新版本)
# 1. 安装编译依赖
sudo yum install -y curl-devel expat-devel gettext-devel \
openssl-devel zlib-devel gcc perl-ExtUtils-MakeMaker
# 2. 下载源码
cd /usr/src
sudo wget https://github.com/git/git/archive/v2.43.0.tar.gz -O git.tar.gz
sudo tar xzf git.tar.gz
cd git-*
# 3. 编译安装
sudo make prefix=/usr/local all
sudo make prefix=/usr/local install
# 4. 验证
git --version
3 Git配置——告诉Git"你是谁"
# 全局配置(对所有仓库生效)
git config --global user.name "张三"
git config --global user.email "zhangsan@example.com"
# 查看配置
git config --list
git config user.name
# 配置默认编辑器
git config --global core.editor vim
# 配置颜色输出
git config --global color.ui auto
# 配置别名(偷懒必备)
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.lg "log --oneline --graph --all"
# 配置完后可以这样用:
git st # 等价于 git status
git co dev # 等价于 git checkout dev
git lg # 漂亮的图形化日志
为什么要配置user.name和email?
Git的每次commit都会记录作者信息。如果不配置,Git会拒绝提交——就像一个匿名信没有署名,无法追溯。
##4 工作区三阶段——Git的核心思想
生活类比
想象你在做一份PPT作业:
- 工作区(Working Directory)= 你桌面上正在编辑的PPT文件
- 暂存区(Staging Area / Index)= 你把改好的几页拖到"待提交"文件夹
- 本地仓库(Repository)= 你点了"保存版本",这版被永久记录
工作区 暂存区 本地仓库
(Working) → (Staging) → (Repository)
编辑文件 add 准备提交 commit 永久记录
← reset ← checkout
撤销修改 还原文件
三个区域之间的流转:
| 操作 | 方向 | 说明 |
|---|---|---|
git add | 工作区 → 暂存区 | 把修改标记为"准备提交" |
git commit | 暂存区 → 仓库 | 把暂存的内容永久保存 |
git reset | 仓库 → 暂存区 | 撤销暂存(不影响工作区) |
git checkout | 仓库 → 工作区 | 用仓库版本覆盖工作区 |
5 基本操作——Git入门六板斧
5.1 git init——创建仓库
# 创建新项目
mkdir my-project && cd my-project
git init
# 输出:Initialized empty Git repository in /path/to/my-project/.git/
# 此时会生成一个隐藏的 .git 目录,存放所有版本数据
ls -la .git/
5.2 git add——添加到暂存区
# 添加单个文件
git add index.html
# 添加多个文件
git add style.css script.js
# 添加所有改动(最常用)
git add .
# 添加所有改动但排除已删除的文件
git add -u
5.3 git commit——提交到仓库
# 标准提交
git commit -m "feat: 添加用户登录功能"
# 提交并自动add已跟踪的文件
git commit -am "fix: 修复导航栏样式问题"
# 修改上一次提交的消息
git commit --amend -m "feat: 添加用户登录功能(含表单验证)"
提交消息规范(推荐Conventional Commits):
feat: 新功能
fix: 修复bug
docs: 文档更新
style: 代码格式(不影响逻辑)
refactor: 重构
test: 添加测试
chore: 构建/工具变动
5.4 git status——查看状态
git status
# 输出示例:
# On branch main
# Changes to be committed:
# (use "git restore --staged <file>..." to unstage)
# modified: index.html
#
# Changes not staged for commit:
# modified: style.css
#
# Untracked files:
# new_feature.js
# 简洁模式
git status -s
# 输出:
# M index.html ← 已暂存(绿色M)
# M style.css ← 未暂存(红色M)
# ?? new_feature.js ← 未跟踪
5.5 git log——查看历史
# 标准日志
git log
# 单行简洁模式(最推荐)
git log --oneline
# 输出:
# a3f2b1c feat: 添加登录功能
# 9e8d7c6 fix: 修复首页bug
# 1a2b3c4 init: 项目初始化
# 图形化分支日志
git log --oneline --graph --all
# 查看最近3次提交
git log -3
# 查看某个文件的历史
git log --follow -p index.html
# 查看某个作者的提交
git log --author="张三"
# 查看某天的提交
git log --since="2024-01-01" --until="2024-01-31"
# 查看某次提交改了什么
git show a3f2b1c
5.6 git diff——查看差异
# 工作区 vs 暂存区(还没add的修改)
git diff
# 暂存区 vs 仓库(已add但没commit的修改)
git diff --staged
# 或
git diff --cached
# 两个提交之间的差异
git diff abc123 def456
# 两个分支之间的差异
git diff main feature/login
5.7 git reset——撤销与回退
# 撤销暂存(文件内容不变)
git reset HEAD style.css
# 等价于
git restore --staged style.css
# 回退到某次提交(保留修改在工作区)—— 最常用
git reset --mixed abc123
# 回退到某次提交(保留修改在暂存区)
git reset --soft abc123
# 彻底回退到某次提交(丢弃所有修改)—— 慎用!
git reset --hard abc123
# 回退上一个提交
git reset --hard HEAD~1
# 只撤销某个文件的某次修改
git checkout abc123 -- filename
互动提问:
git reset --hard和git reset --soft的区别是什么?点击查看答案
`--hard`:彻底回退,工作区和暂存区都恢复到目标提交的状态,未提交的修改全部丢失。`--soft`:只移动HEAD指针,修改保留在暂存区,可以重新commit。日常使用中 `--mixed`(默认)最安全。
6 分支——平行宇宙的魔法
生活类比
分支就像游戏的"存档点":你可以在主线剧情之外开一个"支线任务"(新分支),做完了可以合并回主线,也可以直接放弃支线。
6.1 分支基础操作
# 查看所有分支(当前分支带*号)
git branch
# 输出:
# develop
# * main
# feature/login
# 创建新分支
git branch feature/login
# 切换到新分支
git checkout feature/login
# 或更简洁的一步到位:
git checkout -b feature/login
# 新版Git推荐用switch
git switch -c feature/login
# 删除分支(必须先切到其他分支)
git branch -d feature/login # 安全删除(已合并的才能删)
git branch -D feature/login # 强制删除(未合并也能删)
# 重命名当前分支
git branch -m new-name
6.2 分支合并(merge)
# 场景:feature/login 开发完了,合并到 main
# 1. 切回主线
git checkout main
# 2. 合并
git merge feature/login
# 输出:
# Updating a3f2b1c..b4c3d2e
# Fast-forward
# login.html | 50 ++++++++++
# 1 file changed, 50 insertions(+)
# 3. 删除已合并的分支
git branch -d feature/login
# 合并时保留分支历史(生成合并提交)
git merge --no-ff feature/login -m "merge: 合并登录功能分支"
6.3 变基(rebase)
# rebase把当前分支的提交"搬"到目标分支的最新提交之后
# 让提交历史更线性、更干净
git checkout feature/login
git rebase main
# 如果rebase过程中遇到冲突
# 1. 手动解决冲突
# 2. git add 解决后的文件
# 3. git rebase --continue
# 放弃rebase
git rebase --abort
merge vs rebase 如何选择?
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| merge | 保留完整历史 | 历史可能很乱 | 公共分支合并 |
| rebase | 历史清晰线性 | 改写提交历史 | 个人分支整理 |
黄金法则:不要对已经推送到远程的公共分支执行rebase!
6.4 冲突解决
# 当两人修改了同一文件的同一位置时,Git会报冲突
# 冲突文件内容会变成:
# <<<<<<< HEAD
# 这是你修改的内容
# =======
# 这是别人修改的内容
# >>>>>>> feature/other-branch
# 解决步骤:
# 1. 手动编辑文件,删除冲突标记,保留正确内容
vim conflict_file.txt
# 2. 标记为已解决
git add conflict_file.txt
# 3. 提交合并结果
git commit -m "merge: 解决登录模块冲突"
实战冲突解决示例:
# 模拟冲突场景
git checkout -b branch-a
echo "张三的代码" > code.txt
git add code.txt && git commit -m "张三修改"
git checkout main
git checkout -b branch-b
echo "李四的代码" > code.txt
git add code.txt && git commit -m "李四修改"
git checkout main
git merge branch-a # 成功
git merge branch-b # 冲突!
# 编辑code.txt,选择保留哪份或合并两份
vim code.txt
git add code.txt
git commit -m "merge: 合并张三和李四的代码"
7 远程仓库——连接世界
生活类比
本地仓库是你的笔记本,远程仓库就是云盘——你把笔记同步到云盘,别人也能看到和协作。
7.1 基本远程操作
# 查看远程仓库
git remote -v
# 输出:
# origin https://github.com/user/repo.git (fetch)
# origin https://github.com/user/repo.git (push)
# 添加远程仓库
git remote add origin https://github.com/user/repo.git
# 克隆远程仓库(最常用)
git clone https://github.com/user/repo.git
cd repo
# 克隆到指定目录
git clone https://github.com/user/repo.git my-project
# 只克隆最近1次提交(加快速度)
git clone --depth 1 https://github.com/user/repo.git
7.2 push / pull / fetch
# push:推送本地提交到远程
git push origin main
git push origin feature/login
# 第一次推送时设置上游分支
git push -u origin main
# pull:拉取远程变更并合并(= fetch + merge)
git pull origin main
# fetch:只拉取远程变更,不自动合并(更安全)
git fetch origin
git log main..origin/main # 查看远程比本地多了什么
git merge origin/main # 确认后再合并
# 拉取所有分支
git fetch --all
日常工作流:
# 每天开工第一件事:拉取最新代码
git pull origin main
# 干活...编辑文件...
git add .
git commit -m "feat: 完成XX功能"
git push origin main
# 下班前确认没有遗漏
git status
git log --oneline -5
8 GitHub使用——全球最大的代码托管平台
8.1 注册与配置
- 访问 https://github.com 注册账号
- 配置SSH密钥(免密码推送)
# 生成SSH密钥对
ssh-keygen -t ed25519 -C "your_email@example.com"
# 查看公钥
cat ~/.ssh/id_ed25519.pub
# 复制公钥内容,添加到 GitHub → Settings → SSH and GPG keys
8.2 Fork与Pull Request
Fork工作流(参与开源项目的标准流程):
1. 在GitHub上点击项目的 "Fork" 按钮 → 复制一份到你自己的账号下
2. git clone 你fork后的仓库到本地
3. 创建分支,修改代码
4. git push 到你的fork仓库
5. 在GitHub上发起 Pull Request (PR) → 请求原项目合并你的改动
6. 项目维护者审核代码 → 合并
# 具体操作
git clone git@github.com:你的用户名/project.git
cd project
# 添加上游仓库(方便同步原项目的更新)
git remote add upstream https://github.com/原作者/project.git
# 同步上游更新
git fetch upstream
git merge upstream/main
# 创建功能分支
git checkout -b fix/typo-in-readme
# ... 修改文件 ...
git add . && git commit -m "docs: 修复README中的拼写错误"
git push origin fix/typo-in-readme
# 然后到GitHub网页上创建Pull Request
8.3 Issues(问题追踪)
GitHub Issues 是项目的问题追踪系统,可以用来:
- 报告bug
- 提出功能建议
- 讨论技术方案
# 一个好的Issue模板
## Bug描述
简要说明问题现象
## 复现步骤
1. 第一步...
2. 第二步...
3. 出现错误
## 期望行为
应该怎样工作
## 环境信息
- OS: Ubuntu 22.04
- 版本: v1.2.3
9 GitHub Pages——免费建站
GitHub Pages可以把仓库里的HTML/CSS/JS文件直接发布为网站。
# 1. 创建仓库:用户名.github.io
# 2. 上传index.html
# 3. 访问 https://用户名.github.io
# 或者用任意仓库的gh-pages分支
git checkout -b gh-pages
# 添加HTML文件
git add . && git commit -m "init: GitHub Pages"
git push origin gh-pages
# 在仓库Settings → Pages中选择gh-pages分支发布
适合搭建的内容:
- 个人博客(配合Jekyll/Hugo)
- 项目文档
- 个人简历页
- 课程作业展示
10 .gitignore——告诉Git"别跟踪这些文件"
# .gitignore 文件示例
# 忽略编译产物
*.o
*.class
*.pyc
__pycache__/
dist/
build/
# 忽略IDE配置
.vscode/
.idea/
*.swp
# 忽略系统文件
.DS_Store
Thumbs.db
# 忽略敏感信息(非常重要!)
.env
*.pem
*.key
secrets/
# 忽略日志
*.log
logs/
# 忽略依赖目录
node_modules/
vendor/
常见规则:
*.log # 忽略所有.log文件
build/ # 忽略build目录
doc/*.txt # 忽略doc下的.txt(不含子目录)
doc/**/*.txt # 忽略doc及其子目录下的所有.txt
!important.log # 不忽略important.log(即使前面有*.log)
如果文件已经被跟踪了,如何从Git中移除但保留本地文件?
git rm --cached filename
git rm -r --cached directory/
git commit -m "chore: 移除不应跟踪的文件"
11 tag——给版本打标签
# 创建轻量标签
git tag v1.0.0
# 创建附注标签(推荐,包含作者和说明)
git tag -a v1.0.0 -m "Release v1.0.0: 首个正式版"
# 给历史提交打标签
git tag -a v0.9.0 abc123 -m "Beta版本"
# 查看所有标签
git tag
git tag -l "v1.*" # 通配查找
# 查看标签详情
git show v1.0.0
# 推送标签到远程
git push origin v1.0.0
git push origin --tags # 推送所有标签
# 删除标签
git tag -d v1.0.0 # 删除本地
git push origin --delete v1.0.0 # 删除远程
12 cherry-pick——精挑细选某个提交
# 场景:main分支有个bugfix,你也想在你的分支上用
# 不用全部merge,只需cherry-pick那一个提交
git checkout feature/login
git cherry-pick abc123 # 把abc123这个提交"摘"过来
# 一次摘多个
git cherry-pick abc123 def456 ghi789
# 遇到冲突时
# 解决冲突后:
git cherry-pick --continue
# 或放弃:
git cherry-pick --abort
13 stash——临时保存工作现场
生活类比
stash就像"存档":你正在打Boss(写代码),突然要去做另一件事,赶紧存个档,做完回来读档继续。
# 保存当前未提交的修改
git stash
git stash save "正在做的登录功能,临时切换修bug"
# 查看已保存的stash列表
git stash list
# 输出:
# stash@{0}: On feature/login: 正在做的登录功能
# stash@{1}: On main: 临时修改
# 恢复最近一次stash
git stash pop # 恢复并删除该stash
git stash apply # 恢复但保留stash
# 恢复指定的stash
git stash pop stash@{1}
# 删除某个stash
git stash drop stash@{1}
# 清空所有stash
git stash clear
典型使用场景:
# 你正在feature分支开发,突然要切到main修紧急bug
git stash # 先存档
git checkout main # 切分支
# ...修bug、提交、推送...
git checkout feature/login # 切回来
git stash pop # 读档继续
14 git reflog——救命命令
生活类比
reflog是Git的"黑匣子":即使你
git reset --hard删掉了提交,reflog依然记录了所有操作。它是你最后的救命稻草。
# 查看所有操作历史(包括已"删除"的提交)
git reflog
# 输出:
# a3f2b1c HEAD@{0}: commit: feat: 添加新功能
# 9e8d7c6 HEAD@{1}: reset: moving to HEAD~3
# b4c3d2e HEAD@{2}: commit: fix: 重要修复
# c5d4e3f HEAD@{3}: commit: docs: 更新文档
# 场景:不小心 git reset --hard 丢掉了3个提交
# 从reflog中找到丢失的提交hash,然后恢复:
git reset --hard b4c3d2e # 恢复到"重要修复"那个状态
# 也可以用cherry-pick恢复单个提交
git cherry-pick b4c3d2e
互动提问:reflog和log有什么区别?
点击查看答案
`git log` 只显示当前分支的提交历史(已删除的看不到);`git reflog` 记录HEAD指针的所有移动(包括reset、rebase、checkout等操作),是本地操作日志。reflog默认保留90天。
15 Jenkins简介——自动化部署的"机器人"
什么是Jenkins?
Jenkins是一个开源的**持续集成/持续部署(CI/CD)**工具。简单来说,它就是一个"机器人":
- 你推送代码 → Jenkins自动运行测试
- 测试通过 → Jenkins自动打包部署到服务器
- 测试失败 → Jenkins发邮件通知你
安装Jenkins
# CentOS安装
sudo wget -O /etc/yum.repos.d/jenkins.repo \
https://pkg.jenkins.io/redhat/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat/jenkins.io-2023.key
sudo yum install -y jenkins java-17-openjdk
# 启动服务
sudo systemctl start jenkins
sudo systemctl enable jenkins
# 查看初始密码
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
# 访问 http://服务器IP:8080 完成初始化
Pipeline基础(Jenkinsfile)
// Jenkinsfile —— 定义CI/CD流水线
pipeline {
agent any
environment {
APP_NAME = 'my-web-app'
DEPLOY_DIR = '/var/www/html'
}
stages {
stage('拉取代码') {
steps {
git branch: 'main',
url: 'https://github.com/user/repo.git'
}
}
stage('安装依赖') {
steps {
sh 'npm install'
}
}
stage('运行测试') {
steps {
sh 'npm test'
}
}
stage('构建') {
steps {
sh 'npm run build'
}
}
stage('部署') {
steps {
sh "cp -r dist/* ${DEPLOY_DIR}/"
sh 'systemctl restart nginx'
}
}
}
post {
success {
echo "部署成功!"
// 可以发送通知
}
failure {
echo "构建失败,请检查代码!"
}
}
}
Jenkins工作流程图:
开发者git push → GitHub Webhook触发 → Jenkins拉取代码
→ 安装依赖 → 运行测试 → 构建 → 部署到服务器
→ 成功:通知团队
→ 失败:通知开发者修复
16 Git实战工作流总结
个人项目工作流
# 1. 初始化
mkdir project && cd project
git init
echo "# My Project" > README.md
git add . && git commit -m "init: 项目初始化"
# 2. 开发新功能
git checkout -b feature/xxx
# ...编码...
git add . && git commit -m "feat: 完成xxx"
git checkout main
git merge feature/xxx
git tag v1.0.0
# 3. 推送到远程
git remote add origin git@github.com:user/repo.git
git push -u origin main
git push --tags
团队协作工作流
# 每天开工
git pull origin main
git checkout -b feature/my-task
# 开发中(定期暂存)
git add .
git commit -m "feat: 进度更新"
# 提交前同步主线
git fetch origin
git rebase origin/main
# 解决冲突(如果有)
# 推送并创建PR
git push -u origin feature/my-task
# 在GitHub上创建Pull Request
# PR合并后清理
git checkout main
git pull origin main
git branch -d feature/my-task
运维常用命令精选
日常高频命令
git status -s # 快速查看状态
git add . && git commit -m "msg" # 快速提交
git log --oneline -10 # 查看最近10次提交
git diff --stat # 查看修改了哪些文件
git pull --rebase origin main # 拉取并变基(保持历史整洁)
分支管理
git branch -vv # 查看分支跟踪关系
git branch --merged # 查看已合并的分支(可安全删除)
git branch -d $(git branch --merged | grep -v main) # 批量删除已合并分支
排查与恢复
git reflog # 查看所有操作记录(救命用)
git blame filename # 查看每行是谁改的
git bisect start # 二分法查找引入bug的提交
git stash list # 查看暂存的修改
远程同步
git remote -v # 查看远程仓库地址
git fetch --all --prune # 拉取所有远程并清理已删除的分支
git push origin --tags # 推送所有标签
趣味命令专区
# 1. 查看你的Git统计信息
git log --author="你的名字" --oneline | wc -l # 你提交了多少次
git log --author="你的名字" --shortstat # 增删了多少行
# 2. 用ASCII图形看分支历史
git log --oneline --graph --all --decorate
# 3. 查看今天改了什么
git diff --stat HEAD@{0}@{2024-01-01}
# 4. 找出仓库中最大的文件
git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
sort -k3 -n | tail -10
# 5. 生成变更日志
git log --pretty=format:"%h %ad | %s [%an]" --date=short > CHANGELOG.txt
# 6. 一键初始化项目(含.gitignore)
mkdir my-project && cd my-project && \
git init && \
echo "node_modules/\n.env\n*.log\ndist/" > .gitignore && \
echo "# My Project" > README.md && \
git add . && git commit -m "init: 项目初始化"
# 7. 统计团队贡献
git shortlog -sn --all
# 输出:
# 150 张三
# 89 李四
# 45 王五
# 8. 查看某天的代码改动
git log --since="2024-03-01" --until="2024-03-02" -p --stat
# 9. 有趣的Git Easter Egg
git help everyday # Git的"日常指南"
本章小结:Git是程序员的"后悔药"和"协作桥梁"。记住三个核心概念:三阶段流转(工作区→暂存区→仓库)、分支管理(创建→开发→合并)、远程同步(push/pull/fetch)。遇到问题别慌,
git reflog永远是你的救命稻草。GitHub则让协作跨越了地理限制——Fork、PR、Issues三板斧,让你参与全球开源项目不再是梦。