---
title: "git 命令速查表"
canonical_url: "https://wwlight.vercel.app/guides/notes/git-cheatsheet"
---
# git 命令速查表

<div className="grid,gap-4,sm:grid-cols-2,[&>*]:my-0!">
<tip to="https://git-scm.com/book/zh/v2">

Git 官方

</tip>

<tip to="https://www.conventionalcommits.org/zh-hans/">

约定式提交

</tip>

<tip to="https://semver.org/lang/zh-CN/">

版本号格式

</tip>

<tip to="https://learngitbranching.js.org/?locale=zh_CN">

Learn Git Branching

</tip>
</div>

## 配置

```sh
$ git config --global init.defaultBranch main           # 设置本地默认分支为 main
$ git config --global core.ignorecase false             # 设置文件名大小写敏感 # [注意] macOS 默认不敏感，跨平台协作慎用
$ git config --global safe.directory "*"                # 忽略目录安全限制 # [注意] 降低所有权校验，共享机器慎用
$ git config --list                                     # 查看所有配置
$ git config --global -l                                # 查看全局配置
$ git config --local -l                                 # 查看当前仓库配置
$ git config --list --show-origin                       # 查看配置及其所在文件
$ git config --global user.name "name"                  # 设置全局用户名
$ git config --global user.email "example@example.com"  # 设置全局邮箱
$ git config --local user.name "name"                   # 设置当前仓库用户名
$ git config --local user.email "example@example.com"   # 设置当前仓库邮箱
$ git config user.name                                  # 查看用户名配置
$ git config user.email                                 # 查看邮箱配置
$ git config --unset --global user.name                 # 删除全局用户名配置
$ git config --unset --global user.email                # 删除全局邮箱配置
$ git config --global credential.helper store           # 永久记住账号密码 # [注意] 明文存储，公共设备勿用
$ git config --global credential.helper cache           # 临时记住账号密码（默认 15 分钟）
```

## 初始化与克隆

```sh
$ git init                                              # 在当前目录初始化仓库
$ git init --bare                                       # 创建裸仓库（仅含 .git 内容）
$ git init <path>                                       # 新建目录并初始化仓库
$ git clone <url>                                       # 克隆远程仓库
$ git clone <url> <dir>                                 # 克隆并重命名本地目录
$ git clone -b <branch> <url>                           # 克隆指定分支
```

## 状态与差异

```sh
$ git status                                            # 查看工作区与暂存区状态
$ git status -s                                         # 以短格式输出状态
$ git status --ignore-submodules                        # 忽略子模块状态
$ git status --ignored                                  # 显示被忽略的文件
$ git diff                                              # 查看工作区与暂存区差异
$ git diff --staged                                     # 查看暂存区与最新 commit 差异（同 --cached）
$ git diff <branch1> <branch2>                          # 比较两个分支差异
$ git diff <commit> -- <file>                           # 查看指定 commit 中某文件的差异
```

## 暂存与提交

```sh
$ git add -A                                            # 暂存所有改动（含删除）
$ git add .                                             # 暂存当前目录所有改动
$ git add ./README.md                                   # 暂存指定文件
$ git add 1.txt 2.txt                                   # 暂存多个文件
$ git commit -m "changes log"                           # 提交并附带描述信息
$ git commit README.md -m "message"                     # 只提交指定文件
$ git commit -v                                         # 提交并显示 diff
$ git commit --allow-empty-message                      # 允许空提交信息
$ git commit --amend -m "new message"                   # 修改上一次提交信息 # [注意] 已推送需配合 force push，协作分支慎用
$ git commit --no-verify -m "message"                   # 跳过 pre-commit 钩子验证 # [注意] 会绕过 CI/检查，仅在明确需要时使用
```

## 推送与拉取

```sh
$ git push                                              # 推送当前分支到上游
$ git push origin <local-branch>:<remote-branch>        # 推送本地分支到远端指定分支
$ git push -u origin main                               # 推送并设置上游分支（缩写 --set-upstream）
$ git push -f origin main                               # 强制推送（缩写 --force） # [注意] 覆盖远程历史，共享分支慎用
$ git fetch                                             # 拉取远程所有分支更新
$ git fetch origin <remote-branch>:<local-branch>       # 拉取远程分支到本地分支 # [注意] 可能覆盖本地同名分支
$ git pull                                              # 拉取并合并远程更新
$ git pull --rebase                                     # 拉取并以 rebase 方式整合
$ git pull origin <branch>                              # 拉取指定远程分支
```

## 日志与历史

```sh
$ git log                                               # 查看完整提交历史
$ git log -2                                            # 查看最近 N 次提交
$ git log -p -2                                         # 查看最近 N 次提交及 diff
$ git log -i --grep="fix: issue-28"                     # 按 commit message 搜索（-i 忽略大小写）
$ git log -S "alert(1)"                                 # 搜索引入/删除指定代码的提交
$ git log --author=<name>                               # 查看指定作者的提交
$ git log README.md                                     # 查看指定文件的提交历史
$ git log --merges                                      # 只显示合并提交
$ git log --graph --oneline --all                       # 图形化查看所有分支历史
$ git log --reverse                                     # 按时间正序查看历史
$ git shortlog                                          # 按贡献者分组输出日志
$ git shortlog -sn                                      # 统计各作者提交数量
$ git shortlog -n                                       # 按提交数量排序并输出 message
$ git shortlog -e                                       # 以邮箱格式化输出贡献度
$ git reflog                                            # 查看引用日志（含 reset/rebase 等操作记录）
```

## 分支

```sh
$ git branch                                            # 查看本地分支
$ git branch -a                                         # 查看所有分支（含远程）
$ git branch -r                                         # 查看远程分支
$ git branch -v                                         # 查看本地分支及最近提交
$ git branch -vv                                        # 查看本地与远程分支映射关系
$ git branch <branch>                                   # 创建分支（不切换）
$ git branch -f <branch>                                # 强制创建/重置分支指针 # [注意] 未合并提交可能丢失
$ git branch -d <branch>                                # 删除已合并的本地分支
$ git branch -D <branch>                                # 强制删除本地分支 # [注意] 未合并改动将丢失
$ git branch -m <new-branch>                            # 重命名当前分支
$ git branch -M <new-branch>                            # 强制重命名当前分支
$ git branch -m <old-branch> <new-branch>               # 重命名指定分支
$ git branch --set-upstream-to=origin/<branch> <branch> # 设置本地分支跟踪远程分支
$ git push origin --delete <branch>                     # 删除远程分支 # [注意] 影响所有协作者
$ git push origin :<branch>                             # 删除远程分支（旧写法） # [注意] 影响所有协作者
$ git push -u origin <new-branch>                       # 推送重命名后的分支
```

```sh
$ git checkout <branch>                                 # 切换到指定分支
$ git checkout -                                        # 切换到上一个分支
$ git checkout -f main                                  # 强制切换 # [注意] 未提交改动将丢失
$ git checkout -b <branch>                              # 创建并切换分支
$ git checkout -B <branch>                              # 强制创建分支（不切换） # [注意] 已存在分支会被重置
$ git checkout -t upstream/main                         # 跟踪远程分支并切换
$ git checkout -b <branch> origin/<branch>              # 拉取远程分支并建立跟踪
```

```sh
$ git switch <branch>                                   # 切换到指定分支（Git 2.23+）
$ git switch -                                          # 切换到上一个分支
$ git switch -f main                                    # 强制切换 # [注意] 未提交改动将丢失
$ git switch -c <branch>                                # 创建并切换分支
$ git switch -C <branch>                                # 强制创建分支（不切换） # [注意] 已存在分支会被重置
$ git switch -t upstream/main                           # 跟踪远程分支并切换
```

## 暂存工作区

```sh
$ git stash                                             # 保存当前工作区与暂存区改动
$ git stash save "修改了 issue-28 Bug"                   # 保存并添加注释（推荐）
$ git stash -u                                          # 保存时包含未追踪文件
$ git stash list                                        # 查看 stash 列表
$ git stash pop                                         # 恢复最近一次 stash 并从列表移除
$ git stash pop stash@{1}                               # 恢复指定 stash
$ git stash pop --index                                 # 恢复时连同暂存区状态一并还原
$ git stash apply                                       # 恢复 stash 但保留列表条目
$ git stash drop                                        # 删除最近一次 stash # [注意] 无法恢复
$ git stash drop stash@{0}                              # 删除指定 stash # [注意] 无法恢复
$ git stash clear                                       # 清空所有 stash # [注意] 无法恢复
```

## 恢复文件 restore

```sh
$ git restore <file>                                    # 丢弃工作区改动（恢复为暂存区或 HEAD）
$ git restore .                                         # 丢弃当前目录所有工作区改动
$ git restore --staged <file>                           # 取消暂存，保留工作区改动
$ git restore --staged .                                # 取消暂存当前目录所有文件
$ git restore --staged --worktree <file>                # 同时重置暂存区与工作区为 HEAD
$ git restore --source=<branch> <file>                  # 从指定分支恢复文件到工作区 # [注意] 会覆盖工作区中对应文件
$ git restore --source=<commit> <file>                  # 从指定 commit 恢复文件到工作区 # [注意] 会覆盖工作区中对应文件
$ git restore --source=<commit> --staged <file>         # 从指定 commit 恢复并暂存
```

## 合并

```sh
$ git merge <branch>                                    # 合并指定分支到当前分支
$ git merge --no-ff <branch>                            # 非快进合并，保留合并节点
$ git merge --squash <branch>                           # 将分支改动压成一个提交 # [注意] 不会自动提交，需手动 commit
$ git merge --abort                                     # 中止合并并恢复原状态
```

## 变基 rebase

```sh
$ git rebase main                                       # 将当前分支变基到 main 之上 # [注意] 已推送分支变基后需 force push
$ git rebase origin/main                                # 将当前分支变基到远程 main 之上 # [注意] 已推送分支变基后需 force push
$ git rebase -i HEAD~3                                  # 交互式变基最近 3 个提交（缩写 --interactive） # [注意] 会改写历史，共享分支慎用
$ git rebase --continue                                 # 解决冲突后继续变基
$ git rebase --abort                                    # 中止变基并恢复原状态
$ git rebase --skip                                     # 跳过当前提交继续变基 # [注意] 被跳过的提交不会进入当前分支
$ git pull --rebase                                     # 拉取远端并以 rebase 整合（避免多余 merge commit）
```

## 拣选 cherry-pick

```sh
$ git cherry-pick <commit>                              # 将指定提交应用到当前分支 # [注意] 同一 commit 重复拣选可能产生重复改动
$ git cherry-pick <commit1> <commit2>                   # 依次拣选多个提交
$ git cherry-pick -n <commit>                           # 拣选但不自动提交（缩写 --no-commit）
$ git cherry-pick -x <commit>                           # 拣选并在 message 中追加原 commit 引用
$ git cherry-pick --continue                            # 解决冲突后继续拣选
$ git cherry-pick --abort                               # 中止拣选并恢复原状态
```

## 回滚与撤销

<tip>

回滚说明

- `git reset`：回滚后历史记录被改写，适合未推送或本地整理；基本不会产生 merge 冲突。
- `git revert`：通过新增提交来撤销，保留完整历史；多人协作时更安全，但可能产生冲突。

</tip>

```sh
$ git reset --soft HEAD^                                # 撤销最近一次 commit，保留暂存区
$ git reset --mixed HEAD^                               # 撤销 commit 与 add，保留工作区（默认）
$ git reset --hard HEAD^                                # 撤销 commit、add 与工作区改动 # [注意] 未提交改动无法恢复
$ git reset --hard HEAD^^                               # 回退上两个版本 # [注意] 未提交改动无法恢复
$ git reset --hard <commit>                             # 回退到指定 commit # [注意] 未提交改动无法恢复
$ git reset --hard origin/main                          # 与远程 main 完全对齐，丢弃本地改动 # [注意] 本地未推送提交将全部丢失
$ git revert HEAD^                                      # 新建提交来撤销指定 commit（保留历史）
$ git revert <commit>                                   # 撤销指定 commit
$ git revert HEAD^ --no-edit                            # 撤销并跳过编辑提交信息
$ git revert --abort                                    # 中止 revert 操作
$ git push -f                                           # 强制推送（reset 后同步远程时使用） # [注意] 覆盖远程历史，共享分支慎用
```

## 远程仓库

```sh
$ git remote                                            # 查看远程仓库名称（默认 origin）
$ git remote -v                                         # 查看远程仓库地址
$ git remote -vv                                        # 查看远程仓库详细映射
$ git remote add <remote> <url>                         # 添加远程仓库
$ git remote show <remote>                              # 查看指定远程仓库信息
$ git remote rename <old-remote> <new-remote>           # 重命名远程仓库
$ git remote remove <remote>                            # 移除远程仓库 # [注意] 仅删除本地引用，不影响远端
$ git remote set-url origin <url>                       # 修改远程仓库地址
$ git remote prune origin                               # 清理已删除的远程分支引用
$ git push <remote>                                     # 推送到指定远程仓库
```

## 标签

```sh
$ git tag                                               # 列出本地标签
$ git tag -l                                            # 列出标签（同 --list）
$ git ls-remote --tags origin                           # 查看远程标签
$ git tag <tag>                                         # 在当前 HEAD 创建轻量标签
$ git tag -a <tag> -m "tag message"                     # 创建附注标签
$ git push origin <tag>                                 # 推送单个标签
$ git push origin --tags                                # 推送所有本地标签
$ git tag -d <tag>                                      # 删除本地标签 # [注意] 已推送 tag 需同步删除远程
$ git push origin :refs/tags/<tag>                      # 删除远程标签 # [注意] 影响依赖该 tag 的发布流程
$ git show <tag>                                        # 查看标签详情
```

## 工作树 worktree

```sh
$ git worktree list                                     # 列出所有工作树
$ git worktree add <path> <branch>                      # 在指定路径检出分支
$ git worktree add -b <branch> <path>                   # 新建分支并在指定路径检出
$ git worktree add --detach <path> <commit>             # 以 detached HEAD 检出指定 commit
$ git worktree remove <path>                            # 删除工作树
$ git worktree remove -f <path>                         # 强制删除工作树 # [注意] 未提交改动将丢失
$ git worktree prune                                    # 清理已不存在目录的工作树记录
$ git worktree move <worktree> <new-path>               # 移动工作树目录
```

## 子模块 submodule

<tip>

子模块使用场景

- 当前项目要包含另一个独立仓库，两边仍各自提交、各自推送。常见是第三方库，或自己维护、被多个父项目共用的库。
- 每个父项目把子仓库固定在自己验证过的某一次提交上。需要上游改动时，再单独更新这个指针。

</tip>

### clone 含子模块

<tip>

普通 `git clone` 会留下空的子模块目录。`init` 按 `.gitmodules` 把地址写入 `.git/config`，`update` 再检出父仓库记录的提交。

</tip>

```sh
$ git clone --recurse-submodules <url>                  # 克隆并递归初始化、检出子模块（含嵌套）
$ git submodule init                                    # 把 .gitmodules 登记进 .git/config，此时目录仍是空的
$ git submodule update                                  # 抓取并检出父仓库记录的提交
$ git submodule update --init                           # 合并 init 与 update
$ git submodule update --init --recursive               # 含嵌套子模块；克隆时漏了 --recurse-submodules 时用
```

### 添加

```sh
$ git submodule add <url> <path>                        # 添加子模块，写入 .gitmodules 并暂存提交指针
$ git submodule add -b <branch> <url> <path>            # 添加子模块并写入跟踪分支
$ git rm -r <path>                                      # 该目录已在索引中时，先移除再 submodule add # [注意] 工作区中该目录会被删除
```

```ini [.gitmodules]
[submodule "<name>"]
    path = <path>
    url = <url>
    branch = <branch>
```

- `<name>` 是这条记录的名字，默认和 `path` 相同。
- `path` 是子模块在父仓库里的目录。
- `url` 是克隆子模块用的远程地址。
- `branch` 可以不写。`git submodule update` 检出父仓库记下的那一次提交。写了 `branch` 后，`git submodule update --remote` 才改到这条远程分支的最新提交；不写则用远程仓库的默认分支。

### 查看

```sh
$ git submodule                                         # 查看子模块状态，等同 status
$ git submodule status                                  # 查看路径与检出提交（- 未初始化，+ 与索引不一致，U 冲突）
$ git submodule status --recursive                      # 递归查看嵌套子模块
$ git submodule status --cached                         # 查看父仓库索引里记录的提交
$ git config -f .gitmodules --list                      # 查看 .gitmodules 中的子模块记录
$ git diff <path>                                       # 查看父仓库记录的子模块提交是否变化
$ git diff --submodule                                  # 以提交日志显示子模块差异
$ git log -p --submodule                                # 查看历史时附带子模块提交说明
$ git submodule foreach 'git status -sb'                # 在每个子模块中执行命令
$ git -C <path> status -sb                              # 查看子模块自己的分支与改动
```

### 更新

<tip>

说明

- `git submodule update` 把 `<path>` 里的文件换成父仓库已经记下的那次提交。`git pull` 之后父仓库已经指向新提交，目录里仍是旧文件，再执行这条才会换成新文件。
- `git submodule update --remote` 把子模块换成远程分支上的最新提交。父仓库记下的提交保持不变，要 `git add <path>` 并提交，才会换成这次新提交。

</tip>

```sh
$ git submodule update                                  # 检出父仓库记录的提交（游离 HEAD）
$ git submodule update --init --recursive               # 初始化新增子模块，并递归检出嵌套子模块
$ git submodule update --force                          # 强制检出父仓库记录的提交 # [注意] 子模块未提交改动将丢失
$ git pull --recurse-submodules                         # 拉取父仓库，并检出子模块到记录的提交
$ git switch --recurse-submodules <branch>              # 切换分支时，把子模块同步到该分支记录的提交
$ git config submodule.recurse true                     # 让 pull、switch 等默认递归处理子模块（clone 除外）
$ git submodule update --remote <path>                  # 更新到跟踪分支最新提交；省略 <path> 则更新全部 # [注意] 父仓库指针需再提交
$ git submodule update --remote --merge                 # 将跟踪分支合并进子模块当前分支
$ git submodule update --remote --rebase                # 将子模块当前分支变基到跟踪分支 # [注意] 会改写子模块未推送提交
$ git submodule set-branch --branch <branch> <path>     # 修改 .gitmodules 里的跟踪分支
$ git submodule set-url <path> <url>                    # 修改远程地址，并同步到本地配置
$ git submodule sync --recursive                        # 把手改的 .gitmodules 地址写入 .git/config
$ git -C <path> switch <branch>                         # 在子模块中离开游离 HEAD，切到工作分支
$ git -C <path> restore .                               # 丢弃子模块工作区改动，提交指针不变
$ git add <path>                                        # 将子模块的新提交记入父仓库暂存区
$ git push --recurse-submodules=check                   # 子模块有未推送提交时，拒绝推送父仓库
$ git push --recurse-submodules=on-demand               # 先推送子模块已提交的改动，再推送父仓库
```

### 删除

<tip>

说明

- `git submodule deinit <path>` 删掉本机 `<path>` 里的文件。父仓库仍然记录这个子模块，之后可以再 `init` 并 `update`。
- `git rm <path>` 从父仓库去掉这个子模块，并改掉 `.gitmodules`。这次改动要提交，其他人拉下来才不再包含它。
- `.git/modules/<name>` 是缓存在父仓库里的子模块历史。留着以后还能检出旧提交；确定不再需要时再删除。

</tip>

```sh
$ git submodule deinit <path>                           # 清空检出目录，并删除 .git/config 中的登记
$ git submodule deinit -f <path>                        # 工作区有改动时强制取消检出 # [注意] 未提交改动将丢失
$ git rm <path>                                         # 从索引和 .gitmodules 移除子模块；有本地改动时加 -f
$ rm -rf .git/modules/<name>                            # 删除父仓库缓存的子模块仓库 # [注意] 旧提交将无法再离线检出
```


## Sitemap

See the full [sitemap](https://wwlight.vercel.app/sitemap.md) for all pages.
