版本控制

13 分钟阅读 · 17 组命令示例

Git 命令行指南:日常流程、分支策略与急救

适用场景:日常提交、分支管理、代码回退、冲突解决、协作流程。

适用版本:Git 2.43+;switchrestoreworktreebisect 均使用当前官方语法。

最后核对:2026-07-30

30 秒快速路径

bash
git status --short
git diff
git log --oneline --graph -10

目录

  1. 核心概念
  2. 日常工作流
  3. 分支管理
  4. worktree — 同时处理多个分支
  5. 查看历史
  6. bisect — 二分定位问题提交
  7. 撤销与回退
  8. stash — 临时保存
  9. rebase — 变基
  10. 冲突解决
  11. 远程操作
  12. reflog — 终极急救
  13. .gitignore 速查
  14. Git 配置

核心概念

三个区域

text
工作区 (Working Directory)     暂存区 (Staging/Index)     仓库 (Repository)
     你编辑的文件     ──add──→    准备提交的     ──commit──→    永久记录
                     ←─restore──              ←──reset──

文件状态

状态 含义
Untracked 新文件,Git 不跟踪
Modified 已跟踪文件被修改
Staged 已 add 到暂存区,等待 commit
Committed 已提交到仓库

日常工作流

bash
# ═══ 最常用的 5 个命令 ═══

git status                    # 查看当前状态(必须养成的习惯)
git add .                     # 暂存所有修改
git diff --cached             # 提交前检查暂存内容,避免带入密钥或无关文件
git commit -m "feat: 描述"    # 提交
git pull                      # 拉取远程更新
git push                      # 推送到远程

# ═══ 精细化 add ═══

git add file.ts               # 暂存指定文件
git add src/                  # 暂存整个目录
git add -p                    # 交互式暂存(逐块选择,最精细)
git add -u                    # 只暂存已跟踪文件的修改(不含新文件)

# ═══ commit 技巧 ═══

git commit -m "fix: 修复登录跳转"       # 一行消息
git commit                              # 打开编辑器写详细消息
git commit -am "quick fix"              # add + commit 合并(只对已跟踪文件)
git commit --amend                      # 修改上一次提交的消息或内容
git commit --amend --no-edit            # 把新暂存的文件追加到上次提交
# amend 会重写提交 ID;已经推送或被他人基于其开发时不要直接使用

Commit 消息规范

text
<type>: <description>

type 常用值:
  feat     新功能
  fix      修复 bug
  docs     文档变更
  style    格式调整(不影响逻辑)
  refactor 重构
  perf     性能优化
  test     测试
  chore    杂务(构建、依赖等)

分支管理

bash
# ═══ 基础操作 ═══

git branch                     # 列出本地分支
git branch -a                  # 列出所有分支(含远程)
git branch feature/login       # 创建分支
git switch feature/login       # 切换分支
git switch -c feature/login    # 创建 + 切换

# 旧版 Git / 旧文档中常见,仍可用
git checkout feature/login
git checkout -b feature/login

# ═══ 合并 ═══

git switch main                # 先切到目标分支
git merge feature/login        # 把 feature/login 合并进来
git merge --no-ff feature/x    # 强制产生合并提交(保留分支历史)

# ═══ 删除 ═══

git branch -d feature/login    # 删除已合并的分支
git branch -D feature/login    # 强制删除(未合并也删)
git push origin --delete feature/login  # 删除远程分支

# ═══ 重命名 ═══

git branch -m old-name new-name

分支命名规范

text
feature/login-page       # 新功能
fix/header-overflow      # 修复
hotfix/prod-crash        # 紧急修复
refactor/api-layer       # 重构
chore/update-deps        # 杂务

worktree — 同时处理多个分支

git worktree 可以让同一仓库同时拥有多个工作目录,适合当前分支做到一半时紧急修复、并行跑测试,避免频繁 stash 和切换。

bash
git worktree list

# 从 origin/main 创建 hotfix 分支,并检出到相邻目录
git worktree add -b hotfix ../project-hotfix origin/main

# 已存在的分支可直接指定
git worktree add ../project-release release/1.2

# 完成后先确认目录内没有需要保留的修改
git -C ../project-hotfix status
git worktree remove ../project-hotfix

# 清理已经被手工删除的失效记录
git worktree prune --dry-run
git worktree prune

同一个本地分支通常不能同时检出到两个 worktree。不要直接删除 worktree 目录;优先使用 git worktree remove,以便同步清理 Git 元数据。


查看历史

bash
# ═══ log ═══

git log                        # 完整日志
git log --oneline              # 单行简洁模式
git log --oneline -10          # 最近 10 条
git log --oneline --graph      # 带分支图
git log --stat                 # 显示每次提交修改了哪些文件
git log -p                     # 显示具体 diff

# ═══ 过滤 ═══

git log --author="Example User" # 按作者
git log --since="2024-01-01"   # 按日期
git log --grep="fix"           # 按提交消息搜索
git log -- src/App.tsx         # 某个文件的历史
git log -S "functionName"      # 搜索引入/删除某字符串的提交

# ═══ diff ═══

git diff                       # 工作区 vs 暂存区
git diff --staged              # 暂存区 vs 上次提交
git diff main..feature         # 两个分支端点的快照差异
git diff main...feature        # feature 相对共同祖先引入的修改(评审分支常用)
git diff HEAD~3                # 当前 vs 3 次提交前
git diff --stat                # 只看文件名和行数变化

# ═══ blame ═══

git blame src/App.tsx          # 每行是谁写的
git blame -L 10,20 file.ts    # 只看 10-20 行

bisect — 二分定位问题提交

已知一个正常版本和一个异常版本时,git bisect 会用二分搜索缩小范围。开始前先提交或暂存无关修改,并确保每次测试结果稳定。

bash
# 当前 HEAD 有问题,v1.2.0 已知正常
git bisect start HEAD v1.2.0 --

# Git 检出中间提交;测试后标记
git bisect good                 # 当前提交正常
git bisect bad                  # 当前提交异常

# 找到首个异常提交后回到开始前的位置
git bisect reset

测试可以稳定返回退出码时可自动执行:

bash
git bisect start HEAD v1.2.0 --
git bisect run npm test         # 0=good,1–127=bad;125=无法测试,跳过
git bisect reset

撤销与回退

bash
# ═══ 撤销工作区修改(还没 add)═══

git checkout -- file.ts        # 恢复单个文件(旧语法)
git restore file.ts            # 恢复单个文件(新语法)
git diff                       # 丢弃前先检查未暂存修改
git restore .                  # 丢弃所有未暂存修改(不可恢复)

# ═══ 撤销暂存(已 add,还没 commit)═══

git reset HEAD file.ts         # 取消暂存(旧语法)
git restore --staged file.ts   # 取消暂存(新语法)
git restore --staged .         # 全部取消暂存

# ═══ 撤销提交 ═══

git reset --soft HEAD~1        # 撤销上次提交,修改保留在暂存区
git reset --mixed HEAD~1       # 撤销上次提交,修改回到工作区(默认)
git reset --hard HEAD~1        # 撤销上次提交,修改全部丢弃(危险!)

git revert HEAD                # 创建一个"反向提交"来撤销(安全,适合已推送的)
git revert abc1234             # 撤销指定提交

# ═══ 恢复已删除的文件 ═══

git checkout HEAD -- deleted-file.ts   # 从最近一次提交恢复

reset 三种模式对比

模式 提交历史 暂存区 工作区
--soft ↩️ 回退 保留 保留
--mixed ↩️ 回退 ↩️ 清空 保留
--hard ↩️ 回退 ↩️ 清空 ↩️ 清空

stash — 临时保存

场景:写到一半需要切分支,但不想 commit 半成品。

bash
git stash                      # 保存当前修改到栈
git stash push -m "WIP login"  # 带备注
git stash list                 # 查看所有 stash
git stash pop                  # 恢复最近的 stash;仅成功应用时才从栈中删除
git stash apply                # 恢复但不删除(可以多次 apply)
git stash drop stash@{0}       # 删除指定 stash
git stash clear                # 清空所有 stash(不可恢复,先用 stash list 确认)

# 只 stash 部分文件
git stash push -m "partial" -- src/App.tsx src/utils.ts

# stash 包含未跟踪文件
git stash -u                   # -u = --include-untracked

rebase — 变基

rebase = 把你的提交"搬到"另一个分支的最新位置上,让历史成一条直线。

bash
# ═══ 基础 rebase ═══

git switch feature
git rebase main               # 把 feature 的提交移到 main 最新之后
# 等价于:我的修改好像是在 main 最新状态上做的

# ═══ 交互式 rebase(整理提交历史)═══

git rebase -i HEAD~5           # 编辑最近 5 次提交
# 在编辑器中可以:
#   pick   保留
#   squash 合并到上一个
#   reword 修改消息
#   drop   删除
#   edit   暂停让你修改
#   fixup  合并且丢弃消息

# ═══ rebase vs merge ═══

# merge:保留分支历史,产生合并提交
git merge feature    # 历史有分叉+合并点

# rebase:线性历史,没有合并提交
git rebase main      # 历史是一条直线

rebase 黄金规则

不要擅自 rebase 已经共享给他人的提交。 默认只 rebase 自己尚未共享的提交;团队确实需要重写协作分支时,必须先协调并明确后续强制推送策略。


冲突解决

bash
# 1. 合并/rebase 产生冲突
git merge feature
# CONFLICT (content): Merge conflict in src/App.tsx

# 2. 查看冲突文件
git status                     # 显示 "both modified" 的文件
text
# 3. 打开文件,冲突标记长这样:
<<<<<<< HEAD
你的代码
=======
对方的代码
>>>>>>> feature

# 4. 手动编辑,保留正确的代码,删掉标记
bash
# 5. 标记为已解决
git add src/App.tsx

# 6. 继续
git merge --continue           # 如果是 merge
git rebase --continue          # 如果是 rebase

# ═══ 放弃 ═══
git merge --abort              # 放弃合并,回到合并前
git rebase --abort             # 放弃 rebase

远程操作

bash
# ═══ 基础 ═══

git remote -v                  # 查看远程仓库地址
git remote add origin URL      # 添加远程
git remote set-url origin URL  # 修改地址

git fetch                      # 拉取远程更新(不合并)
git pull                       # fetch + merge
git pull --rebase              # fetch + rebase(更干净)
git push                       # 推送
git push -u origin feature     # 推送新分支并设置上游

# ═══ 强制操作(危险!)═══

git fetch origin
git push --force-with-lease    # 比 --force 多一层远程状态检查,但仍会重写历史
# 推送前确认分支和远程更新;公共分支应由保护规则阻止强制推送

# ═══ 跟踪 ═══

git branch -vv                 # 查看本地分支跟踪的远程分支
git branch -u origin/main      # 设置当前分支跟踪远程 main

reflog — 终极急救

reflog 记录本地引用(例如 HEAD)的移动历史,可以帮助找回曾经提交、切换或 reset 到过的提交。它不能保证恢复从未 commit、stash 或以其他方式被 Git 记录的工作区内容,记录也会按配置过期。

bash
git reflog                     # 查看所有 HEAD 移动记录
# 输出示例:
# abc1234 HEAD@{0}: reset: moving to HEAD~3
# def5678 HEAD@{1}: commit: feat: add login
# ghi9012 HEAD@{2}: checkout: moving from main to feature

# 找到想恢复的提交 hash 后,先创建分支,不要立刻再次 hard reset
git switch -c recovery def5678

# ═══ 常见急救场景 ═══

# "我 reset --hard 了,之前的内容已经提交过!"
git reflog                     # 找到 reset 之前的提交 hash
git branch recovery def5678    # 用实际找到的 hash 替换 def5678

# "我删了一个分支!"
git reflog                     # 找到那个分支最后一次提交
git checkout -b recovered abc1234

# "rebase 搞炸了!"
git rebase --abort             # 如果还在 rebase 中
# 或者
git reflog                     # 找到 rebase 之前的 HEAD
git branch before-rebase def5678  # 用实际找到的 hash 替换 def5678

.gitignore 速查

gitignore
# 基础语法
node_modules/          # 忽略整个目录
*.log                  # 忽略所有 .log 文件
dist/                  # 忽略构建产物
.env                   # 忽略环境变量文件
.env.local             # 本地环境变量

# 例外(! 取反)
!.env.example          # 不忽略示例文件

# 通配符
*.min.js               # 所有压缩 JS
**/*.test.ts           # 所有目录下的测试文件
/build                 # 只忽略根目录的 build(不含子目录的)

# 前端项目常见 .gitignore
node_modules/
dist/
.next/
.astro/
.cache/
*.log
.env
.env.local
.DS_Store
Thumbs.db
bash
# 查看哪些文件被忽略了
git status --ignored

# 已经被跟踪的文件加入 .gitignore 后需要:
git rm --cached file.txt       # 从 Git 移除跟踪但保留文件
git rm -r --cached dist/       # 目录同理

Git 配置

bash
# ═══ 用户信息 ═══
git config --global user.name "Your Name"
git config --global user.email "you@email.com"

# ═══ 常用配置 ═══
git config --global init.defaultBranch main         # 默认分支名
git config --global pull.rebase true                # pull 默认用 rebase
git config --show-origin --get core.autocrlf        # 先查看当前换行配置
git config --global core.editor "code --wait"       # 用 VS Code 当编辑器

# ═══ 别名(提效)═══
git config --global alias.co checkout
git config --global alias.sw switch
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --all"
git config --global alias.unstage "restore --staged"

# ═══ 查看配置 ═══
git config --list --show-origin     # 显示所有配置及来源文件

跨平台项目不要机械套用全局 core.autocrlf。优先在仓库中提交 .gitattributes,由项目明确规定 LF/CRLF;修改全局设置前确认编辑器、CI 和现有仓库的约定。


官方参考