CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
DevOps 入门实战/课时/Git 与 GitHub
RawBlame
课时目录12 节

DevOps 入门实战

  1. 01DevOps 入门
  2. 02操作系统
  3. 03Git 与 GitHub
  4. 04脚本语言
  5. 05网络协议
  6. 06Docker
  7. 07AWS
  8. 08Terraform
  9. 09Ansible
  10. 10GitHub Actions
  11. 11Nginx
  12. 12综合练习

Git 与 GitHub

版本控制与协作。

30 分钟

Git 与 GitHub

这一课你将能做到

  1. 完成 Git 本地核心操作:init、add、commit、branch、merge、rebase、回滚
  2. 把本地仓库推到 GitHub,配置 SSH 免密,走通 feature 分支 + Pull Request 协作流
  3. 写出规范的 commit message,并能用 git log、git reflog 自救任何误操作

为什么要学

没有版本控制的开发是什么样?改坏了代码想退回昨天的版本——没有了;多人同时改一个文件——互相覆盖;线上出了 bug 想对比「上一版到底改了什么」——靠记忆。Git 就是代码的时间机器,每一次 commit 都是一个可以随时穿越回去的快照。

而 GitHub 在这个时间机器之上加了「协作层」:代码托管、Pull Request 评审、Issue 管理、Actions 自动化。对 DevOps 来说更重要的是:所有自动化的触发点都是 Git 事件——push 触发构建、merge 触发部署。Git 玩不转,后面的 CI/CD 就是空中楼阁。

先建立图像

Git 的四个区域,代码在它们之间流动:

工作区          暂存区           本地仓库          远程仓库
(你改代码)  →  (git add)   →  (git commit)  →  (git push)
                ↑                                     │
                └──────── git pull / git fetch ←──────┘

回退方向:
git restore 文件        工作区 ← 暂存区(丢弃本地修改)
git restore --staged    暂存区 ← 本地仓库(取消暂存)
git reset --soft HEAD~1 本地仓库回退一个 commit(改动回暂存区)

分支模型(推荐初学者的 trunk-based 简化版):

main ────●────────●────────●──────▶  永远可发布
          \      /          \
feature    ●────●            ●──●   短命分支,几天内合回
                ↑
           Pull Request 评审 + CI 通过才允许合并

跟着做

步骤 1:从零建立本地仓库

# 进入你的 Spring Boot 项目
cd myapp
git init
git config user.name "Your Name"
git config user.email "you@example.com"

# .gitignore 是 Java 项目的门面,必须先建
cat > .gitignore << 'EOF'
target/
*.class
*.jar
!.mvn/wrapper/maven-wrapper.jar
.idea/
*.iml
.vscode/
application-local.yml
*.log
EOF

git add .
git commit -m "chore: initial commit with gitignore"

步骤 2:日常修改循环

# 改了两个文件后
git status                 # 永远先看状态,知道哪些文件变了
git diff                   # 看具体改了什么(未暂存的)
git add src/main/java/com/example/UserController.java
git commit -m "feat(user): 添加用户查询接口"

# 提交错了想改最后一条 commit 的说明
git commit --amend -m "feat(user): 添加用户分页查询接口"

步骤 3:分支操作——功能开发的标准姿势

# 从 main 切出功能分支
git checkout -b feature/user-cache

# 在分支上随便折腾、提交
git commit -am "feat(user): 接入 Redis 缓存"
git commit -am "test(user): 补充缓存命中测试"

# 合回 main(推荐 rebase 保持历史线性)
git checkout main
git pull origin main            # 先同步远程最新
git checkout feature/user-cache
git rebase main                 # 把我的提交「搬」到 main 最新之后
git checkout main
git merge feature/user-cache    # 快进合并,无多余 merge commit
git branch -d feature/user-cache

步骤 4:连接 GitHub,走通 PR 流程

# 生成 SSH 密钥(一次就好)
ssh-keygen -t ed25519 -C "you@example.com"
cat ~/.ssh/id_ed25519.pub
# 把输出粘贴到 GitHub → Settings → SSH Keys

# 关联远程仓库并推送
git remote add origin git@github.com:yourname/myapp.git
git branch -M main
git push -u origin main

# 以后的功能分支流程
git push origin feature/user-cache
# 然后在 GitHub 网页上点 "Compare & pull request"
# → 描述改动 → 请求 review → CI 通过 → Squash and merge

步骤 5:自救命令——误操作后悔药

# 误删了分支/误 reset,找回任意历史 commit
git reflog                    # 列出 HEAD 走过的每一步
git checkout -b rescue abc1234  # 从 reflog 里的 commit 恢复

# 线上紧急回滚:生成一个反向 commit(安全,不改历史)
git revert HEAD

# 把暂存区某个文件拉回来
git restore --staged src/xxx.java

讲清楚要点

  1. commit 是快照不是差异:Git 每个 commit 存的是整个项目的快照(相同文件用指针去重),所以切换分支、找回历史极快。
  2. 分支只是指针:创建一个分支 = 创建一个指向某个 commit 的指针,成本几乎为零。放心大胆地开分支。
  3. merge vs rebase:merge 保留真实历史(有合并节点),rebase 把历史「捋直」。团队约定:合公共分支用 merge 或 squash,同步自己分支用 rebase。已 push 的提交不要 rebase。
  4. Git 事件是 DevOps 的扳机:push 到 main → 触发生产部署;开 PR → 触发测试;打 tag → 触发发版。理解这个,第 10 课 GitHub Actions 就懂了 80%。
  5. 永不提交密钥:数据库密码、云厂商 AccessKey 进 Git 后,即使删除文件,历史记录里依然存在,必须当作已泄露处理(换密钥)。用 .gitignore + 环境变量兜底。

你可能会懵的地方

  • commit 了但还没 push,别人能看到吗? 不能。Git 是分布式的,commit 只存在你本地,push 之后才同步到 GitHub。这也是为什么可以在本地随便 commit、不满意就 amend,push 前都有后悔药。

  • merge 冲突是不是很可怕? 不可怕。冲突只是「同一行被两边都改了」,Git 不知道怎么选。打开文件找到 <<<<<<<、=======、>>>>>>> 标记,手动选出正确内容,删掉标记,git add 后 git rebase --continue(或 merge 时直接 commit)即可。

  • reset --hard 会丢东西吗? 会。git reset --hard 把工作区和暂存区全部重置,未提交的修改永久消失。执行前先 git stash 或确认没有未提交的重要改动。已经 commit 的永远可以用 reflog 找回。

  • fork 和 clone 有什么区别? clone 是把仓库下载到本地;fork 是在 GitHub 上把别人的仓库复制一份到你账号下。给开源项目提 PR 的标准流程:fork → clone 自己的 fork → 开分支改 → push → 在原项目提 PR。

  • tag 和 branch 有什么不同? 都是指针,但 branch 会随着新 commit 移动,tag 永远钉在某个 commit 上不动。tag 用来标记版本:git tag -a v1.2.0 -m "release",发版、回滚都靠它。

错法对照

错法问题正解
直接在 main 上开发出问题污染主干,无法回滚功能分支 + PR 合并
commit message 写「改bug」「update」三个月后没人知道改了什么约定式提交:feat/fix/chore(scope): 描述
把 target/、.idea/ 提交进仓库仓库臃肿,冲突不断.gitignore 提前配好
对已 push 的提交 rebase队友 pull 后历史错乱只 rebase 本地未推送的提交
一个大 commit 包含 10 个不相关改动无法单独回滚某一项原子提交:一个 commit 只做一件事

卡点急救

  1. push 被拒 non-fast-forward:远程有你本地没有的提交(队友推过)。先 git pull --rebase origin main,解决冲突后再 push。不要 --force 强推公共分支。
  2. 误 commit 到了 main:还没 push 的话——git reset --soft HEAD~1(改动回到暂存区)→ git stash → 切正确分支 → git stash pop。
  3. 冲突解决到一半想放弃:rebase 中 git rebase --abort,merge 中 git merge --abort,回到冲突前的状态,重新来过。

面试常问

  • git merge 和 git rebase 的区别?分别什么时候用? merge 创建一个合并 commit 把两条历史汇合,保留分支结构,可追溯性好;rebase 把当前分支的提交逐个重放到目标分支顶端,历史线性干净。公共分支的合入用 merge(或 GitHub 的 squash merge 保持单 commit),自己的功能分支同步主干用 rebase。铁律:不 rebase 已推送的提交。

  • 生产环境上线后发现 bug,如何用 Git 处理? 两种思路:①修复优先——从 main 切 hotfix 分支修复,合并后立刻部署(git flow 的做法);②回滚优先——git revert <有问题的 commit> 生成反向提交部署上去,恢复服务后再从容修 bug。实际工作中先回滚止血再修复更稳。

  • git pull 背后做了什么? git pull = git fetch + git merge(默认)。fetch 只是把远程的最新状态下载到本地的 origin/main 等引用,不动你的工作分支;merge 才真正合并。git pull --rebase 则是 fetch + rebase。排查问题时建议拆开用:先 fetch 看 origin/main 和本地差多少,再决定怎么合。

自测三问

  1. 写出从「新建功能分支」到「PR 合并并删除分支」的完整命令序列。
  2. git reset --soft HEAD~1、--mixed、--hard 三者的区别?
  3. 为什么不推荐把数据库密码提交到 Git,即使事后删除文件也不行?

小结一句话

Git 让每一次代码变更可回溯、可协作、可触发自动化——它是 DevOps 流水线的总开关。

延伸

  • Pro Git 中文版(官方免费书)
  • 下一课:脚本语言——用 Bash 和 Python 把重复操作自动化。
加载本节练习…
← 上一课操作系统下一课 →脚本语言