Git 常用命令速查手册

本文档面向实际开发场景,系统整理日常高频使用的 Git 命令,配有详实注释与示例。适用于个人开发者日常查阅,也适合团队新人快速上手。


目录


前言:Git 核心概念

理解 Git 的三大区域是掌握命令的基础:

区域 说明
工作区(Working Directory / Working Tree) 你当前编辑文件的地方,就是磁盘上的项目文件夹
暂存区(Staging Area / Index) 介于工作区和 Git 仓库之间的”待提交区”,文件修改先进入这里
Git 仓库(Repository) .git/ 目录,存放所有提交历史、分支、标签等数据

文件在三个区域之间的流转关系:

工作区  --git add-->  暂存区  --git commit-->  Git仓库
工作区  <--git checkout/reset--  暂存区
工作区  <--git checkout/reset--  Git仓库

基础配置

用户信息配置

每次提交都需要记录作者信息,建议在安装 Git 后第一时间配置。

# 配置全局用户名和邮箱(所有仓库共用)
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"

# 只对当前仓库生效(项目级配置,会覆盖全局配置)
git config --local user.name "Your Name"
git config --local user.email "your.email@example.com"

解释--global 是全局配置,存放在 ~/.gitconfig 文件中;--local 是当前仓库配置,存放在 .git/config 文件中。一般全局配置姓名和邮箱,每个项目可以在 .git/config 中单独配置公司邮箱等。

查看配置

# 查看所有配置(包含全局和本地)
git config --list --show-origin

# 查看全局配置
git config --global --list

# 查看当前仓库配置
git config --local --list

# 查看某个具体配置项
git config --global user.name

常用配置别名

通过别名减少重复输入,提高效率。

# 给常用命令设置简短别名
git config --global alias.st "status"       # git st 代替 git status
git config --global alias.co "checkout"     # git co 代替 git checkout
git config --global alias.br "branch"       # git br 代替 git branch
git config --global alias.ci "commit"       # git ci 代替 git commit
git config --global alias.lg "log --oneline --graph --decorate"
git config --global alias.unstage "reset HEAD --"
git config --global alias.last "log -1 HEAD"

解释:别名只是给长命令起一个短名字,不会改变命令的行为。lg 别名组合了 log 的多个参数,可以用一个 git lg 看到漂亮的分支图。

核心配置项

# 设置默认分支名(新仓库初始化时的默认分支)
git config --global init.defaultBranch main

# 开启 colorexpand(彩色输出,更易读)
git config --global color.ui auto

# 设置默认编辑器
git config --global core.editor vim

# 设置 CRLF 自动转换(Windows 用户推荐开启,防止跨平台换行符问题)
git config --global core.autocrlf true
# Linux/Mac 用户推荐
git config --global core.autocrlf input

# 忽略文件权限变更(跨平台开发时避免误报权限变化)
git config --global core.fileMode false

仓库初始化与克隆

在本机初始化新仓库

# 在当前目录下初始化一个新的 Git 仓库
# 执行后会在当前目录生成 .git 子目录,这就是 Git 仓库的核心数据
git init

# 初始化时指定目录(两种写法等价)
git init myproject
git init /path/to/myproject

# 初始化一个裸仓库(通常用于创建远程共享仓库,不含工作区)
git init --bare myproject.git

解释git init 会创建一个 .git/ 目录,其中包含所有 Git 需要的数据。裸仓库没有工作区,不能直接编辑文件,通常用作团队共享的中央仓库。”bare”表示”裸露的”,即只有仓库数据,没有工作目录。

克隆远程仓库

# 克隆仓库(默认完整克隆,包含所有历史)
git clone https://github.com/username/repository.git

# 克隆到指定目录
git clone https://github.com/username/repository.git myfolder

# 克隆指定分支(只拉取该分支,节省时间和带宽)
git clone --branch develop https://github.com/username/repository.git

# 克隆指定分支并切换到该分支
git clone --branch develop --single-branch https://github.com/username/repository.git

# 浅克隆(只克隆最近 N 次提交历史,适合大型仓库)
git clone --depth 1 https://github.com/username/repository.git

# 通过 SSH 克隆(需要配置 SSH 密钥,推荐在服务器上使用)
git clone git@github.com:username/repository.git

# 查看克隆下来的仓库的所有远程仓库地址
git clone https://github.com/username/repository.git
cd repository
git remote -v

解释--depth 1 创建的是浅克隆,历史记录只保留到最近一次提交,可以大大减少克隆时间。但浅克隆后无法进行完整的 git merge 和查看完整历史,如果需要完整历史,可以用 git fetch --unshallow 获取剩余历史。


文件状态与暂存区

查看当前状态

# 查看工作区文件的状态
# 这是日常使用频率最高的命令之一,每次操作前都建议先运行
git status

# 简洁模式(一行显示文件状态)
git status -s

# 状态示例输出说明:
# ??  file.txt        -> ?? 表示未跟踪文件(New file, not in Git)
# A   file.txt        -> A  表示已添加到暂存区(Staged)
# M   file.txt        -> M  左边 M 表示暂存区有修改(Modified, staged)
#  M  file.txt        ->  M 右边 M 表示工作区有修改(Modified, not staged)
# MM  file.txt        -> MM 表示暂存区和工作区都有修改
# D   file.txt        -> D  表示文件已删除(Deleted from staging/index)
# R   file.txt        -> R  表示文件已重命名(Renamed)

解释git status 会显示哪些文件被修改、哪些文件在暂存区、哪些文件未被跟踪。暂存区(Staging Area)是本次准备提交的内容,工作区是还在编辑的修改。

添加文件到暂存区

# 添加指定文件到暂存区
git add filename.txt

# 添加所有修改(包括新增、修改、删除的文件)
git add -A
git add --all

# 添加当前目录下的所有修改(包括子目录)
git add .

# 添加所有已跟踪文件的修改(不包括未跟踪的新文件)
git add -u
git add --update

# 交互式添加(逐个文件/区块选择添加)
git add -i
git add -p

# 添加某个目录下所有文件
git add src/

# 支持通配符
git add *.js
git add "*.txt"

# 将已经跟踪文件的修改添加到暂存区(不包括新文件)
git add -u

解释git add 是将工作区的变化放进暂存区。-A. 的区别在于:. 只添加当前目录及子目录的修改,-A 添加整个仓库(包括删除操作)。建议优先用 -A 确保完整。

-p 参数详解(交互式暂存)

git add -p 是高级技巧,允许你只暂存文件中的部分修改:

git add -p filename.js

运行后会逐个显示文件中的修改块(hunk),你可以选择:

按键 作用
y 暂存这个区块(yes)
n 不暂存这个区块(no)
s 将当前区块进一步拆分(split)
e 手动编辑区块(edit)
q 退出
? 显示帮助

解释:当你修复了一个 bug 同时又写了新功能,但只想先提交 bug 修复时,这个命令非常有用。


提交与历史

创建提交

# 将暂存区的内容创建为一个提交
git commit

# -m 参数直接指定提交信息(推荐,写法简洁)
git commit -m "feat: add user login functionality"

# 提交信息规范(推荐团队使用):
# feat:     新功能
# fix:      修复 bug
# refactor: 重构(不改变功能)
# docs:     文档更新
# style:    格式调整(不影响功能)
# test:     添加测试
# chore:    构建或辅助工具的变动
# perf:     性能优化

# 提交时显示具体的变更行数统计
git commit -v

# 将已跟踪文件的修改直接提交(跳过 git add 步骤)
# 注意:只提交已跟踪文件的修改,不会提交新文件
git commit -am "fix: correct calculation bug"

# 修改最后一次提交(追加修改或修改提交信息)
git commit --amend

# 空提交(通常用于触发 CI/CD pipeline)
git commit --allow-empty -m "trigger build"

解释--amend 不是修改提交,而是用一个新的提交”替换”最后一次提交。常用于提交后发现漏了文件或提交信息写错了。已推送到远程的提交不要使用 --amend,否则会破坏远程历史。

查看提交历史

# 查看完整提交历史(每条提交占一行,简洁)
git log --oneline

# 显示分支合并图(可视化分支结构)
git log --oneline --graph --all

# 显示最近 N 次提交
git log -n 5

# 显示分支合并图(完整版本)
git log --oneline --graph --all --decorate

# 每次提交显示文件变化统计
git log --stat

# 显示每次提交的具体改动内容
git log -p

# 只显示某个文件的提交历史
git log --oneline -- filename.txt

# 显示某个作者的提交历史
git log --oneline --author="username"

# 显示某个时间范围内的提交
git log --since="2026-01-01" --until="2026-06-01"

# 搜索提交信息中包含关键词的提交
git log --oneline --grep="fix"

# 搜索涉及指定文件改动的提交
git log --oneline -S "function_name"

# 一行命令实现漂亮的分支图(配合前面配置的别名)
git lg

查看某次提交的详情

# 查看某次提交的完整信息(提交者、日期、文件变化、具体改动)
git show <commit-hash>

# 只看提交信息,不看改动内容
git show --stat <commit-hash>

# 查看最近一次提交
git show HEAD
git show HEAD~1   # 上一次提交
git show HEAD~2   # 上上次提交

分支管理

查看分支

# 列出本地所有分支(当前分支前面有 * 号)
git branch

# 列出本地和远程所有分支
git branch -a

# 列出远程分支(以 remotes/ 前缀显示)
git branch -r

# 列出分支并显示最后一次提交信息
git branch -v

# 列出已合并到当前分支的所有分支(可安全删除的分支)
git branch --merged

# 列出尚未合并到当前分支的所有分支
git branch --no-merged

解释:分支本质是指向某个提交的可移动指针。在 Git 中创建一个分支非常轻量,只是在当前提交上创建一个新指针。git branch 只是创建分支,git checkoutgit switch 才会切换到该分支。

创建分支

# 在当前 HEAD 位置创建一个新分支(不会自动切换)
git branch feature-login

# 创建分支并立即切换到该分支(两个命令的快捷方式)
git checkout -b feature-login
git switch -c feature-login     # 新版 Git 推荐写法

# 基于某个提交创建分支
git branch feature-login abc1234

# 基于远程分支创建本地追踪分支
git checkout --track origin/develop
git switch --track origin/develop  # 新版写法

# 创建新分支但不要检出(只在仓库中创建分支引用,不切换)
git branch feature-login

解释git branch 只是创建指针,git checkout/switch -b 才是创建并切换。用 git branch -b 时,-b 表示创建并切换。用 git switch -c 是新版 Git(2.23+)推荐的写法,比 checkout 更直观。

切换分支

# 切换到已有分支(工作区有未提交的修改时需要先暂存或提交)
git checkout develop
git switch develop              # 新版推荐写法

# 切换到上一个分支(切换回来时很有用)
git checkout -
git switch -                    # 新版写法

# 强制切换(丢弃工作区的修改,危险!)
git checkout -f main

# 创建并切换(推荐两个命令二选一)
git checkout -b new-feature
git switch -c new-feature

注意:切换分支前,确保工作区是干净的。如果有未提交的修改,Git 不允许直接切换分支(除非修改被 stash 或能安全合并)。可以用 git status 检查。

重命名分支

# 重命名当前分支
git branch -m new-name

# 重命名指定分支
git branch -m old-name new-name

# 强制重命名(目标分支名已存在)
git branch -M new-name

删除分支

# 删除已合并的分支(安全删除,如果未合并会报错)
git branch -d feature-login

# 强制删除分支(无论是否已合并,直接删除)
git branch -D feature-login

# 删除远程分支
git push origin --delete feature-login

# 删除所有已合并到 main 的本地分支(清理)
git branch --merged main | grep -v "main" | xargs git branch -d

警告git branch -D 是强制删除,会丢失未合并的提交。在执行前确认该分支的改动已不需要。

推送本地分支到远程

# 推送本地分支到远程(首次推送需要设置上游分支)
git push -u origin feature-login
git push --set-upstream origin feature-login  # 完整写法

# 推送所有本地分支到远程
git push --all

# 推送所有标签
git push --tags

远程仓库

查看远程仓库

# 查看所有远程仓库的简短名称(通常只有 origin)
git remote

# 查看远程仓库的完整 URL 和名称
git remote -v
git remote --verbose

# 查看某个远程仓库的详细信息(URL、抓取/推送地址)
git remote show origin

添加/移除远程仓库

# 添加一个新的远程仓库(通常命名为 origin)
git remote add origin https://github.com/username/repository.git

# 添加一个 SSH URL 的远程仓库
git remote add origin git@github.com:username/repository.git

# 重命名远程仓库(origin -> upstream)
git remote rename origin upstream

# 移除远程仓库
git remote remove origin

# 修改远程仓库的 URL
git remote set-url origin https://github.com/username/new-repository.git
git remote set-url origin git@github.com:username/repository.git

解释origin 只是远程仓库的默认命名,可以改成任意名字。团队协作中常将上游仓库命名为 upstream,自己的 fork 命名为 origingit remote -v 显示的 (fetch) 是抓取地址,(push) 是推送地址。

重命名与删除远程

git remote rename old-name new-name
git remote remove remote-name

拉取、推送与同步

拉取远程更新

# 从远程抓取最新代码(自动尝试合并到当前分支)
git pull

# 拉取指定远程分支到当前分支
git pull origin main

# 拉取并变基(将本地提交在远程最新提交之后重放,推荐团队使用 rebase 工作流时)
git pull --rebase
git pull --rebase origin main

# 只抓取不合并(不修改工作区)
git fetch

# 抓取所有远程仓库的更新
git fetch --all

# 抓取指定远程仓库的更新
git fetch origin

# 抓取后查看远程分支相对于本地分支的差异
git fetch origin
git log HEAD..origin/main   # 查看本地 main 和远程 origin/main 的差距

解释git pull = git fetch + git mergefetch 只是将远程数据下载到本地,不会自动合并或修改工作区;pull 则是下载并尝试合并。--rebase 会将本地提交”重放”到远程最新提交之后,产生线性历史。

推送到远程

# 推送当前分支到远程仓库
git push

# 推送指定分支到指定远程
git push origin feature-login

# 推送并设置上游分支(关联本地分支和远程分支)
git push -u origin feature-login

# 推送所有标签
git push --tags

# 强制推送(覆盖远程历史,危险!)
git push --force
git push -f

# 删除远程分支(本地分支还在)
git push origin --delete feature-login

# 推送时忽略 pre-receive 钩子(通常用于强制推送已保护的分支)
git push --force-with-lease

警告:绝对不要对已共享的(其他人正在使用的)分支执行强制推送。--force-with-lease--force 更安全,它会检查远程分支在你上次 fetch 后是否有其他人推送过新提交。

同步远程分支列表

# 删除本地已失效的远程追踪分支(远程已删除的分支,本地还在显示)
git fetch --prune
git fetch -p                    # 简短写法

# 全局开启自动 prune(每次 fetch/pull 自动清理)
git config --global fetch.prune true

合并与变基

合并分支

# 将指定分支合并到当前分支(创建新的合并提交)
git merge feature-login

# 将 main 分支合并到当前分支
git checkout develop
git merge main

# 合并时创建一个合并提交(即使快进合并也创建提交)
git merge --no-ff feature-login

# 取消合并(当合并出现冲突时想放弃)
git merge --abort

# 合并但暂停(遇到冲突时暂停,让你手动解决后继续)
git merge --no-commit feature-login

# 查看即将合并到当前分支的提交
git log HEAD..origin/main

解释--no-ff 的意思是 “no fast-forward”,即禁用快进合并。即使 main 分支在 feature-login 创建后没有任何新的提交,合并时也会创建一个新的提交节点。这样可以在分支图上清楚看到 feature 的完整生命周期。

变基(Rebase)

# 将当前分支的提交"重放"到目标分支的最新提交之后
# 效果上等价于:先在目标分支上重新应用当前分支的所有提交
git rebase main

# 交互式变基(重写提交历史,功能强大且危险)
git rebase -i HEAD~3           # 修改最近3次提交

# 变基时解决冲突后继续
git rebase --continue

# 变基时放弃,回到变基前的状态
git rebase --abort

# 变基时暂停在某次提交上(用于修改)
git rebase --edit-todo

交互式变基(git rebase -i)常用操作:

在弹出的编辑器中,每一行是一个提交,可以修改开头的命令:

命令 作用
pick 保留提交(不变)
reword 修改提交信息
edit 暂停在此提交,可以修改文件
squash 将此提交与上一个提交合并
fixup 同 squash,但丢弃此提交的提交信息
drop 删除此提交
reorder 调整提交顺序
# 交互式变基,将最近的3个提交合并为一个
git rebase -i HEAD~3

编辑器内容示例:

pick abc1234 feat: add login page
pick def5678 feat: add logout functionality
pick 98fed3a fix: correct redirect URL

# 改为:
pick abc1234 feat: add login and logout
fixup def5678 feat: add logout functionality
fixup 98fed3a fix: correct redirect URL

警告:绝对不要对已推送到远程的提交进行变基!变基会重写提交历史,如果已经推送,团队其他人的本地历史会与远程不一致。已推送的提交只允许 git revert(生成反向提交)。

衍合(rebase)vs 合并(merge)

对比项 merge rebase
历史形态 保留完整分叉历史 产生线性历史
提交结构 创建合并提交 重放提交
协作安全 多人安全使用 不能在共享分支上使用
适用场景 合并发布分支到主分支 同步个人功能分支

经验法则:团队共享分支(main、develop)用 merge;个人功能分支同步主分支时用 rebase。


撤销与回退

工作区修改的撤销

# 撤销工作区的修改(将文件恢复到上一次提交的状态)
# 危险操作:会丢失未提交的修改!
git checkout -- filename
git checkout filename              # 简写(省略 -- 也行)

# 新版写法
git restore filename               # 丢弃工作区修改
git restore .                      # 丢弃所有工作区修改

# 恢复某个文件到指定提交
git restore --source=HEAD~1 filename.txt
git restore --source=abc1234 filename.txt

解释:这里的”撤销”是将工作区的文件恢复到最后一次提交(HEAD)的状态。如果文件未进入暂存区,撤销后恢复到最后提交状态;如果已暂存(add 过),则恢复到暂存区状态。

暂存区的撤销(取消暂存)

# 取消暂存(将文件从暂存区移回工作区,不丢失修改)
git reset HEAD filename
git reset filename                 # 简写,不指定文件时作用于所有暂存文件

# 新版写法(Git 2.23+)
git restore --staged filename
git restore --staged .             # 取消暂存所有文件

解释git reset 在这里只是移动 HEAD 指针(实际上只是将暂存区的索引重置),不会修改工作区的文件内容,所以修改不会丢失。

提交的回退

# 修改最后一次提交(追加暂存区内容到上次提交,或修改提交信息)
git commit --amend

# 将暂存区恢复到最后一次提交(即撤销最后一次 git add)
git reset HEAD~1

# --soft:保留修改在暂存区(文件内容不变,只是 commit 被撤销)
git reset --soft HEAD~1

# --mixed(默认):保留修改在工作区(不保留在暂存区)
git reset --mixed HEAD~1
git reset HEAD~1                    # 默认就是 --mixed

# --hard:丢弃所有修改(危险!暂存区和工作区全部恢复)
git reset --hard HEAD~1

# 回退到指定提交
git reset --hard abc1234

解释git reset 有三种模式——--soft 只移动分支指针,--mixed 移动指针并重置暂存区,--hard 移动指针、重置暂存区、恢复工作区。其中 --hard 是最彻底的,但也是最危险的。

远程分支的回退(revert vs reset)

# 生成一个新的提交来"撤销"指定提交的改动(安全,不会修改历史)
git revert abc1234

# 生成新提交撤销最近一次提交
git revert HEAD

# 撤销最近两次提交
git revert HEAD~2..HEAD

解释:当已经推送到远程、无法强制推送时,用 git revert 是安全的做法。它会创建一个新的提交,内容恰好与要撤销的提交相反(想当于对那次提交做”反做”),然后将新提交推送即可。

恢复误删的提交(reflog 救援)

# 查看所有 HEAD 移动记录(几乎所有操作都能找到)
git reflog

# 恢复误删的提交(找到对应的 hash 后直接 reset)
git reflog
# 输出示例:
# abc1234 HEAD@{0}: reset: moving to HEAD~1
# def5678 HEAD@{1}: commit: fix: correct typo
# 98fed3a HEAD@{2}: commit: feat: add feature

# 假设误删了 "fix: correct typo" 这次提交
git checkout abc1234               # 先切换到当时的提交
git checkout -b recovery           # 从这次提交创建一个新分支
# 然后可以将这个分支合并回去

解释git reflog 是 Git 的”后悔药”,它记录了 HEAD 指针的每一次移动。即使 reset 了、rebase 了、revert 了,甚至 reset –hard 了,都可以通过 reflog 找到并恢复。只要 .git/logs/ 目录还在(没有运行 git gc --prune=now 或清理),90 天内的操作基本都能恢复。


储藏工作进度

什么是 stash

当你正在修改代码,但需要临时切换到其他分支处理紧急事务时,可以使用 git stash 将当前工作区的修改”藏起来”,等处理完后再恢复。

基本操作

# 将工作区的修改和暂存区的内容全部储藏
git stash

# 储藏时添加说明信息(方便以后识别)
git stash save "WIP: working on feature-login"

# 查看所有储藏的列表
git stash list

# 应用最新的储藏(默认不删除 stash 记录)
git stash apply

# 应用最新的储藏并从 stash 列表中删除
git stash pop

# 应用指定编号的储藏(stash@{0}、stash@{1} 等)
git stash apply stash@{2}

# 应用最新储藏的同时恢复暂存区(保留之前 git add 的状态)
git stash pop
git stash apply --index

# 查看储藏的内容(不做任何应用操作)
git stash show
git stash show -p                  # 查看详细 diff

清理储藏

# 删除指定的储藏
git stash drop stash@{0}

# 清空所有储藏记录(危险)
git stash clear

# 删除并应用最新的储藏
git stash pop

创建分支并恢复储藏

# 从储藏创建新分支(如果储藏时的基础分支和当前分支差异很大,可以用这个)
git stash branch new-feature stash@{0}

解释:如果 stash 时基于的提交和当前分支差异很大,直接 git stash pop 可能会产生冲突。git stash branch 会基于 stash 创建时的提交创建一个新分支,在新分支上应用 stash,避免冲突问题。


标签管理

创建标签

# 给当前 HEAD 创建一个轻量标签
git tag v1.0.0

# 给指定提交打标签
git tag v1.0.0 abc1234

# 创建附注标签(推荐,包含更多信息)
git tag -a v1.0.0 -m "Release version 1.0.0"

# 创建带签名的标签(需要配置 GPG 密钥)
git tag -s v1.0.0 -m "Signed release"

# 打补打标签(给已推送的标签追加信息,需要 force push)
git tag -a v1.0.0 abc1234 -f -m "Update tag message"

解释:轻量标签只是一个指向特定提交的指针;附注标签是 Git 中的一个完整对象,包含打标签者的名字、邮箱、日期和标签信息,推荐用于正式发布版本。

查看标签

# 列出所有标签
git tag

# 列出标签并过滤(支持通配符)
git tag -l "v1.*"

# 查看标签详情
git show v1.0.0

删除标签

# 删除本地标签
git tag -d v1.0.0

# 删除远程标签
git push origin --delete v1.0.0
git push origin :refs/tags/v1.0.0   # 另一种写法

推送标签

# 推送一个标签到远程
git push origin v1.0.0

# 推送所有标签到远程
git push --tags

# 推送标签并设置上游(首次推送)
git push -u origin v1.0.0

检出标签

# 检出到指定标签(创建新分支并切换到该提交)
git checkout -b release-branch v1.0.0
git switch -c release-branch v1.0.0

解释:标签是不可变的,Git 不允许在标签位置直接创建提交。如果要在某个版本上继续开发,必须基于标签创建新分支。


忽略文件配置

.gitignore 文件

在项目根目录创建 .gitignore 文件,Git 会忽略匹配的文件。

# .gitignore 示例内容及解释

# 忽略所有 .log 文件
*.log

# 忽略 node_modules 目录(npm 包依赖)
node_modules/

# 忽略 build 目录(编译输出)
build/

# 忽略 dist 目录(打包输出)
dist/

# 忽略特定文件
.env
config.local.js

# 忽略某类目录(如所有 build 目录)
**/build/

# 忽略所有 .tmp 文件(任何子目录下)
**/*.tmp

# 不忽略 lib/debug.js(取反,排除例外)
!.gitignore
!lib/debug.js

# 忽略所有 obj 目录,但不清除嵌套的 obj 目录本身
obj/

注意gitignore 只会忽略”未跟踪”的文件。如果文件已经被 Git 跟踪(已提交到仓库),则需要在仓库中先删除该文件再添加忽略规则。

忽略已被跟踪的文件

# 从 Git 仓库中移除文件,但保留本地文件
git rm --cached filename

# 递归移除
git rm --cached -r directory/

# 提交这个变更(仓库中删除,本地保留)
git commit -m "remove cached files"

.gitignore 模板

GitHub 为各种语言/框架提供了现成的 .gitignore 模板:

# 通过 curl 快速下载一个 .gitignore 模板
curl -o .gitignore https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore

全局忽略规则

# 设置全局忽略规则(对所有仓库生效)
git config --global core.excludesFile ~/.gitignore_global

# 然后在 ~/.gitignore_global 中写入全局忽略规则
# 例如 macOS 的 .DS_Store、Windows 的 Thumbs.db 等

.git/info/exclude

本地仓库独用的忽略规则,不会被推送到远程:

# 在 .git/info/exclude 中添加规则(仅本地生效)
# 这适合用于本地调试临时文件

查看与比较

比较差异(diff)

# 查看工作区 vs 暂存区的差异(未 add 的修改)
git diff

# 查看暂存区 vs Git仓库的差异(已 add 但未 commit 的修改)
git diff --staged
git diff --cached              # --staged 的别名

# 查看工作区 vs Git仓库的差异(和上一次提交的差异)
git diff HEAD

# 比较两个分支的差异
git diff main feature-login
git diff main..feature-login   # 同上

# 比较两次提交之间的差异
git diff abc1234..def5678

# 只看某个文件的差异
git diff HEAD -- filename
git diff --staged filename

# 统计改动了多少行(不看具体内容)
git diff --stat

# 单词级别 diff(中文友好)
git diff --color-words

解释git diff 不加参数默认比较工作区和暂存区。git diff HEAD 比较工作区和最后一次提交。git diff --staged 比较暂存区和上一次提交。这三个是日常调试最常用的 diff 用法。

查看提交之间的文件列表

# 只看两次提交之间改动了哪些文件(不显示具体改动)
git diff --name-status abc1234..def5678

# A = Added(新增文件)
# M = Modified(修改文件)
# D = Deleted(删除文件)
# R = Renamed(重命名文件)
# C = Copied(复制文件)

比较分支

# 查看两个分支之间的所有差异
git diff main develop

# 查看当前分支相对于 main 分支多了哪些提交
git log main..HEAD

# 查看当前分支相对于 main 分支删除了哪些提交
git log HEAD..main

查看谁改了某一行(blame)

# 查看文件的每一行是哪个提交、谁改的
git blame filename

# 从第10行开始,每行显示5行上下文
git blame -L 10,20 filename

# 排除某个版本的影响(看某个版本之后的变化)
git blame --since="2026-01-01" filename

解释git blame 是代码溯源的利器,可以看到某一行代码是谁在什么时候、因为什么原因改的。常用于追查 bug 引入的提交。


重写历史

压缩多个提交(squash)

# 交互式压缩最近3个提交
git rebase -i HEAD~3

# 在弹出的编辑器中,将后面2个 pick 改成 squash 或 s
# pick abc1234 feat: add feature A
# s def5678 feat: add feature B
# s 98fed3a fix: typo

修改历史提交信息

# 修改最近一次提交信息
git commit --amend

# 修改历史某次提交信息(交互式)
git rebase -i HEAD~3
# 将要修改的提交行改为 reword

删除历史提交

# 交互式变基,删除某个提交
git rebase -i HEAD~5
# 将要删除的提交行改为 drop(或直接删除该行)

将多个提交整理成补丁

# 生成补丁文件
git format-patch -1 HEAD               # 最近一次提交的补丁
git format-patch -3 HEAD               # 最近3次提交的补丁
git format-patch abc1234..def5678      # 两个提交之间的补丁
git format-patch -o patches/            # 指定补丁输出目录

# 应用补丁(将补丁应用到当前分支)
git am patches/*.patch

注意:重写历史只适用于本地未推送的提交。已推送的提交可以用 git revert 生成反向提交来”撤销”。


子模块与子树

子模块(submodule)

当一个 Git 仓库需要引用另一个独立的 Git 仓库时使用。

# 添加子模块(在当前仓库中引用另一个仓库)
git submodule add https://github.com/username/library.git libs/library

# 克隆包含子模块的仓库
git clone --recurse-submodules https://github.com/username/project.git

# 更新子模块到远程最新版本
git submodule update --remote

# 进入子模块目录,像普通仓库一样操作
cd libs/library
git checkout main

# 在父仓库查看子模块状态
git submodule status

# 初始化子模块(在克隆仓库后首次需要)
git submodule init
git submodule update

子树(subtree)

另一种管理多仓库的方式,比 submodule 更简单(不需要 .gitmodules 配置)。

# 添加子树(将外部仓库作为本地子目录)
git subtree add --prefix=libs/library https://github.com/username/library.git main

# 从远程拉取子树更新
git subtree pull --prefix=libs/library https://github.com/username/library.git main

# 将本地修改推送到子树仓库
git subtree push --prefix=libs/library https://github.com/username/library.git main

解释:submodule 保留仓库的独立性,subtree 将外部仓库完全合并到本地目录中作为一个子目录。submodule 更”轻量”,subtree 更”简单直接”,根据场景选择。


Git Bisec 定位问题

当发现某个版本有 bug,但不知道是哪个提交引入时,可以用 git bisec 二分查找。

# 开始二分查找,指定已知有问题的提交和已知没问题的提交
git bisec start
git bisec bad                 # 当前版本有问题
git bisec good abc1234        # abc1234 是没问题的版本

# Git 会自动 checkout 中间版本,测试后告诉 Git 结果
git bisec good                # 当前版本没问题
git bisec bad                 # 当前版本有问题

# 重复以上步骤,直到找到引入 bug 的提交
# Git 会输出类似:"abc1234 is the first bad commit"

# 查找完成后清理 bisec 状态
git bisec reset

解释git bisec 使用二分查找算法,将搜索范围每次缩小一半。对于一个有 1000 个提交的历史,最多只需要约 10 次测试就能定位问题 commit,非常高效。


常用工作流示例

日常工作流程(功能开发)

# 1. 确保主分支是最新的
git checkout main
git pull origin main

# 2. 从主分支创建功能分支
git checkout -b feature/user-profile

# 3. 在功能分支上开发...
# 编辑文件 -> git add -> git commit
git add .
git commit -m "feat: add user profile page"

# 4. 提交前同步主分支最新代码(变基)
git fetch origin main
git rebase origin/main

# 5. 如果有冲突,解决冲突后继续
# 编辑冲突文件 -> git add -> git rebase --continue

# 6. 推送功能分支到远程
git push -u origin feature/user-profile

# 7. 在 GitLab/GitHub 上创建 Pull Request / Merge Request

修复生产 Bug 工作流

# 1. 从主分支(或发布标签)创建热修复分支
git checkout -b hotfix/correct-bug main
git checkout -b hotfix/correct-bug v1.0.0

# 2. 修复 bug,测试通过
git add .
git commit -m "fix: correct calculation error"

# 3. 合并到主分支
git checkout main
git merge --no-ff hotfix/correct-bug

# 4. 打补丁标签
git tag -a v1.0.1 -m "Hotfix version 1.0.1"
git push origin main --tags

# 5. 将修复也合并回开发分支
git checkout develop
git merge --no-ff hotfix/correct-bug

# 6. 推送
git push origin main develop --tags

# 7. 删除热修复分支
git branch -d hotfix/correct-bug
git push origin --delete hotfix/correct-bug

同步上游仓库(Git Fork 工作流)

# 1. Fork 别人的仓库后,克隆自己的 fork
git clone https://github.com/yourname/repository.git

# 2. 添加上游仓库(别人原仓库)作为远程
git remote add upstream https://github.com/original-owner/repository.git

# 3. 定期从上游仓库同步最新代码
git fetch upstream
git checkout main
git merge upstream/main

# 4. 将同步后的代码推送到自己的远程仓库
git push origin main

代码审查后合并

# 1. 更新你的功能分支(确保基于最新代码)
git checkout feature/user-profile
git fetch origin
git rebase origin/main

# 2. 如果有人对 MR/PR 提了修改意见,改完后重新提交
git add .
git commit --amend               # 修改最后一次提交
git push --force                 # 强制推送到远程(功能分支可以 force push)

# 3. 合并后更新本地主分支
git checkout main
git pull origin main

# 4. 删除已合并的功能分支
git branch -d feature/user-profile
git push origin --delete feature/user-profile

撤销操作急救

# 场景1:提交后发现漏了文件
git add forgotten-file.txt
git commit --amend --no-edit    # 追加到上一次提交,不改提交信息

# 场景2:提交信息写错了
git commit --amend              # 进入编辑器修改提交信息

# 场景3:想把最后一次提交拆分成多个
git reset --soft HEAD~1          # 撤销提交,保留所有修改在暂存区
git reset HEAD filename          # 将某个文件取消暂存
git commit -m "first part"
git commit -m "second part"

# 场景4:想合并多个提交成一个
git rebase -i HEAD~3             # 交互式变基,将多个 pick 改成 squash

# 场景5:回退到某个版本(未 push)
git reset --hard abc1234

# 场景6:回退已 push 的提交
git revert abc1234               # 生成反向提交
git push origin main

# 场景7:撤销最近的 N 次提交
git revert HEAD~2..HEAD

# 场景8:误删分支后恢复
git reflog
git checkout -b recovery abc1234 # 从找到的 commit 创建分支

附录:命令速查

按场景速查

场景 命令
开始新任务 git checkout -b feature/xxx && git pull origin main
查看状态 git statusgit status -s
暂存修改 git add filenamegit add -A
提交 git commit -m "message"
查看历史 git log --onelinegit lg
创建分支 git checkout -b xxxgit switch -c xxx
切换分支 git checkout xxxgit switch xxx
拉取更新 git pullgit pull --rebase
推送代码 git push -u origin xxx
查看差异 git diffgit diff --stagedgit diff HEAD
撤销修改 git restore filegit restore .
取消暂存 git restore --staged file
储藏修改 git stashgit stash pop
合并分支 git merge xxx
变基同步 git fetch && git rebase origin/main
打标签 git tag -a v1.0.0 -m "message"
推送标签 git push --tags
查看远程 git remote -v
查看谁改了代码 git blame file
搜索历史 git log --grep="keyword"
恢复误删提交 git reflog + git checkout -b recovery <hash>

本文档持续更新。如有遗漏或错误,欢迎反馈。