
Git 命令图解手册写给实习生的 30 个高频命令你以为自己在用 Git其实你只是在用add / commit / push。当你遇到分支冲突、reset --hard、误删文件时手足无措说明你还没真正看见Git 内部的运作。这篇博客的核心目的用图把每个命令的作用讲清楚。建议你打开终端跟着博客的命令一起敲一遍。为什么需要图示很多 Git 教程是这么写的git reset --hard HEAD~1表示回退到上一个版本。你看完之后依然不知道会发生什么——是只动版本库工作区的文件还在不在我改了一半的代码会不会丢Git 的所有命令本质上都是操作对象commit、分支指针、工作区文件、暂存区文件。图示能让你直接看到这些对象怎么变比任何文字描述都清楚。本博客约定*表示一个 commit 节点括号里的(HEAD - main)表示 HEAD 指针和 main 分支指针都指向这里箭头→表示命令的方向⚠️ 标记代表危险操作入门理解 Git 的三个区域这是全篇的基石所有命令都围绕这三个区域运作区域含义类比工作区Working Directory你实际编辑的文件办公桌上的草稿暂存区Stage / Index准备提交的文件中间站待提交的文件夹版本库Repository已提交的历史记录归档柜┌─────────────┐ git add ┌─────────────┐ git commit ┌─────────────┐ │ │ ──────────────► │ │ ───────────────► │ │ │ 工作区 │ │ 暂存区 │ │ 版本库 │ │ (Working) │ ◄────────────── │ (Stage) │ │ (Repository)│ │ │ git checkout │ │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ ▲ │ │ │ └──────────────── git reset ──────────────────────────────────────┘记住这张图所有 Git 命令都是在这个图上画箭头。接下来每个命令都对应到这张图上。辅助命令git status看三个区域分别有什么文件git diff看工作区和暂存区的差异git diff --staged看暂存区和版本库的差异第一章基础工作流1.git init— 初始化仓库gitinit把当前目录变成 Git 仓库生成一个隐藏的.git文件夹。之前 之后 my-project/ my-project/ ├── src/ ├── .git/ ← 新增 ├── README.md ├── src/ └── main.py ├── README.md └── main.py2.git clone url— 克隆远程仓库gitclone https://github.com/xxx/yyy.git把远程仓库完整下载到本地包含所有历史、分支、tag。3.git add file— 添加到暂存区gitaddhello.txt# 添加指定文件gitadd.# 添加当前目录所有变更之前hello.txt 是红色 之后hello.txt 是绿色 工作区 hello.txt (未跟踪/修改) 工作区 hello.txt 暂存区 (空) 暂存区 hello.txt ← 新增 版本库 (旧版本) 版本库 (旧版本)4.git commit -m msg— 提交到版本库gitcommit-mfeat: add login page把暂存区的内容保存为一个 commit永久进入版本库。每次 commit 都会生成一个节点 * c3 (HEAD - main) feat: add login page * * c2 fix: button style * * c1 init project⚠️注意commit只提交暂存区的内容。如果改了文件但没add改的内容不会被提交。5.git log— 查看提交历史gitlog# 详细gitlog--oneline# 简洁模式gitlog--oneline--graph# 图形化显示分支$ git log --oneline --graph * 8f3a21d (HEAD - main) feat: add login page * 3b2c109 fix: button style * a1d4e88 init project6.git push/git pull— 与远程同步gitpush origin main# 推送到远程 maingitpull origin main# 拉取并合并远程 main本地 * c3 (HEAD - main) ← git push ───► 远程* c3 (origin/main) * ◄── git pull ── * * c2 * c27..gitignore— 忽略文件# .gitignoretarget/ *.log .idea/ .DS_Store被忽略的文件不会出现在git status中也不会被误提交。第二章分支管理重点1. 核心认知分支就是一个指针很多人误以为分支是一份代码拷贝。不对。在 Git 里分支只是一个指向某个 commit 的可移动指针非常轻量。┌── * c4 (feature) feature 分支指针 │ * c3 (HEAD - main) main 分支指针 HEAD * * c2 * * c12.git branch系列gitbranch# 查看所有本地分支gitbranch feature-x# 创建分支指针指向当前 commitgitbranch-dfeature-x# 删除已合并的分支gitbranch-Dfeature-x# ⚠️ 强制删除未合并也会删3.git checkout/git switch— 切换分支gitswitch feature-x# 推荐写法语义清晰gitcheckout feature-x# 老写法也能切换分支切换前 切换后 * c3 (HEAD - main) * c3 (HEAD - feature-x) ← HEAD 移动到 feature | * c2 | * c14.git merge— 合并分支合并有两种情况结果完全不同情况 a快进合并Fast-forward当 feature 分支没有分叉时main 没新提交合并只是把 main 指针前移。合并前 合并后 * c4 (feature) * c4 (HEAD - main, feature) 指针前移 * * c3 (main) * * c2 * * c1情况 b三方合并生成 merge commit当两个分支都有新提交时Git 会生成一个特殊的 merge commit。合并前 合并后 * c4 (feature) * c5 (HEAD - main) merge commit | |\ * c3 (main) * c4 (feature) | | * c2 * c3 | | * c1 * c2 | * c15.git rebase— 变基rebase把当前分支的所有提交摘下来在目标分支的最新 commit 后面重新播放一遍。结果是一条直线。merge 后的历史分叉 rebase 后的历史一条直线 * c5 (merge) * c4 (HEAD - feature) |\ * c3 * c4 (feature) * c2 | * c1 * c3 (main) | * c2 | * c1什么时候用哪个场景推荐团队协作的共享分支如 mainmerge保留分叉历史自己的本地 feature 分支rebase让历史更干净⚠️黄金法则永远不要对已经推送到远程的 commit 做 rebase否则团队成员会陷入混乱。6. 冲突解决当两个分支改了同一文件的同一行Git 会停下来让你手动解决 HEAD 这是 main 分支的写法 这是 feature 分支的写法 feature解决步骤手动编辑文件决定保留哪一段或者合并删除、、标记git add file标记冲突已解决git commit完成合并第三章版本回退与恢复最容易翻车1.git reset— 移动 HEAD 指针⚠️reset 会改写历史已经 push 到远程的 commit 不要轻易 reset。reset有三种模式对应不同的破坏力模式HEAD 移动暂存区重置工作区重置适用场景--soft✓✗✗撤销 commit但保留改动想重新提交--mixed默认✓✓✗撤销 commit 撤销 add文件改动保留在工作区--hard✓✓✓⚠️彻底回退所有未提交的改动全丢执行 git reset --hard HEAD~1 后 之前 之后 * c3 (HEAD - main) * c2 (HEAD - main) ← HEAD 回退 * * * c2 * c1 * * * c1 c3 在 reflog 里还能找到⚠️--hard是不可逆的吗不一定见后面的git reflog。2.git revert— 安全的撤销reset是删除历史revert是新增一个反向 commit。已 push 的提交撤销用 revert不要用 reset。reset删除 c3 revert新增 c3 反向修改 * c4 * c4 (HEAD - main) 新提交 * * * c3 (被删除) * c3 ← 还在 * * * c2 * c2 * * * c1 * c1用法gitrevertcommit-hash# 撤销 merge commit 时需要指定主分支gitrevert-m1merge-commit-hash3.git stash— 暂存未提交的修改场景你正在改代码突然需要切换分支处理紧急 bug但当前改动还没写完不想 commit。gitstash# 把当前工作区和暂存区的改动暂存起来gitstash pop# 恢复最近一次 stashgitstash list# 查看所有 stashgitstash drop stash{0}# 删除指定 stashgit stash 后 git stash pop 后 工作区 (干净的旧版本) 工作区 (你的改动回来了) 暂存区 (空的) 暂存区 (你的改动) 版本库 (最新 commit) 版本库 (最新 commit)4.git reflog— 救命稻草reflog记录了 HEAD 的所有移动。即使你reset --hard把 commit “弄丢了”只要 reflog 还有记录就能找回来。场景你误执行了 git reset --hard HEAD~55 个 commit 没了 $ git reflog a1b2c3d (HEAD - main) HEAD{0} reset: moving to HEAD~5 ← 当前 f6e7d8c HEAD{1} commit: feat: xxx ← 这就是丢失的 commit ...恢复方法gitreset--hardf6e7d8c# 把 HEAD 指回那个 commit结论reset --hard不是 100% 不可逆只要你还记得用 reflog。5. 误删文件恢复# 工作区误删了 hello.txt从版本库恢复gitrestore hello.txt# Git 2.23 推荐gitcheckout -- hello.txt# 老写法# 文件已被 add 到暂存区想从暂存区撤回到工作区未删gitrestore--stagedhello.txt第四章多人协作与企业实战1. 远程仓库相关gitremote-v# 查看远程仓库地址gitremoteaddoriginurl# 添加远程仓库gitfetch origin# 拉取远程所有信息不合并gitpull origin main# 拉取并合并 fetch mergegitpush origin feature-x# 推送本地分支到远程2.git fetchvsgit pull的区别很多人把这两个混着用结果分支莫名其妙多了些 commit。fetch只是把远程的提交下载到本地不影响你的工作 远程 main * c5 | 本地 main * c4 ↓ git fetch 后 本地 main * c4 (main 指针没动) ↓ 但出现了一个 origin/main 指针 origin/main * c5 pullfetch merge本地 main 直接前进 本地 main * c5 (HEAD - main, origin/main) ← 已经合并了3.git tag— 版本标签gittag v1.0.0# 给当前 commit 打标签gittag-av1.0.0-mrelease# 附注标签推荐gitpush origin v1.0.0# 推送标签到远程gittag-dv1.0.0# 删除本地标签常用于版本发布v1.0.0、v1.1.0-beta。4.git cherry-pick— 挑选特定 commit场景main分支有个紧急修复你想把那个 commit 单独拿到release分支上但又不想合并整个分支。从 feature 挑选 c3 到 main feature 分支 main 分支 * c5 * c3 (HEAD) ← 新增是 c3 的副本 | | * c4 * c2 | | * c3 ←── cherry-pick ──► * c1 | * c2 | * c1用法gitcherry-pickcommit-hashgitcherry-pickhash1hash2# 一次挑多个gitcherry-pick--abort# 放弃 cherry-pick5. 协作最佳实践mainmaster │ ├── develop开发主分支 │ ├── feature/login 功能开发 │ ├── feature/payment │ └── feature/refund │ └── hotfix/xxx 紧急修复main只用来发布稳定版本绝不直接提交develop日常开发集成feature/xxx每个新功能一个分支完成后 merge 回 develophotfix/xxx紧急 bug 修复从 main 拉修复后同时合回 main 和 develop合并必须经过PR/MR 评审第五章救命命令速查┌─────────────────────────────────────────────────────────────┐ │ 场景 命令 │ ├─────────────────────────────────────────────────────────────┤ │ 撤销 git add git restore --staged f │ │ 撤销工作区修改 git restore f │ │ 修改最近一次 commit 信息 git commit --amend │ │ 找回 reset --hard 丢的 commit git reflog │ │ 撤销已 push 的 commit git revert hash │ │ 撤销未 push 的 merge git reset --hard HEAD~1 │ │ 撤销已 push 的 merge git revert -m 1 hash │ │ 暂时保存改动 git stash │ │ 恢复保存的改动 git stash pop │ │ 强制推送到远程⚠️ 慎用 git push -f │ │ 放弃当前合并 git merge --abort │ │ 放弃当前 rebase git rebase --abort │ └─────────────────────────────────────────────────────────────┘⚠️核心警告绝对不要在 master/main 上 force push除非团队所有人都明确知道任何reset --hard之前先看一眼git status和git diff确认没未保存的改动已 push 的提交优先用revert不要用reset结尾Git 命令全景图最后给你一张图把所有命令都串起来┌──────────────────────────────────────┐ │ 远程仓库 (origin) │ │ │ │ * c5 (origin/main) │ └───────────────┬──────────────────────┘ │ git fetch / git pull │ git push ▼ ┌─────────────┐ git add ┌─────────────┐ git commit ┌──────────────────────────────┐ │ │ ──────────► │ │ ───────────► │ 版本库 │ │ 工作区 │ │ 暂存区 │ │ │ │ (Working) │ │ (Stage) │ │ * c4 (HEAD - main, │ │ │ ◄────────── │ │ │ │ feature) │ │ │ git restore │ │ │ * c3 │ └─────────────┘ └─────────────┘ │ * c2 │ ▲ │ * c1 │ │ git stash / git checkout │ │ │ │ 分支main、feature、hotfix │ └─────────────────────────────────────────────────└──────────────────────────────┘ 历史查看git log / git reflog 撤销安全git revert 撤销危险git reset--soft / --mixed / --hard 跨分支搬运git cherry-pick / git rebase记住这张图你就掌握了 Git 的心法。剩下要做的就是多敲、多踩坑、多用 reflog 救命。真正的 Git 高手不是记住了多少命令而是脑子里随时能画出一张分支图清楚每个指针指向哪里。