Git 常用命令速查手册
Git 常用命令速查手册
本文档面向实际开发场景,系统整理日常高频使用的 Git 命令,配有详实注释与示例。适用于个人开发者日常查阅,也适合团队新人快速上手。
目录
- 前言:Git 核心概念
- 基础配置
- 仓库初始化与克隆
- 文件状态与暂存区
- 提交与历史
- 分支管理
- 远程仓库
- 拉取、推送与同步
- 合并与变基
- 撤销与回退
- 储藏工作进度
- 标签管理
- 忽略文件配置
- 查看与比较
- 重写历史
- 子模块与子树
- Git Bisec 定位问题
- 常用工作流示例
前言: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 checkout或git 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 命名为origin。git 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 merge。fetch只是将远程数据下载到本地,不会自动合并或修改工作区;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 status、git status -s |
| 暂存修改 | git add filename、git add -A |
| 提交 | git commit -m "message" |
| 查看历史 | git log --oneline、git lg |
| 创建分支 | git checkout -b xxx、git switch -c xxx |
| 切换分支 | git checkout xxx、git switch xxx |
| 拉取更新 | git pull、git pull --rebase |
| 推送代码 | git push -u origin xxx |
| 查看差异 | git diff、git diff --staged、git diff HEAD |
| 撤销修改 | git restore file、git restore . |
| 取消暂存 | git restore --staged file |
| 储藏修改 | git stash、git 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> |
本文档持续更新。如有遗漏或错误,欢迎反馈。







