本页目录

Git 操作手册

历史与查找

delta 是 git diff 的现代替代: 侧边栏, 行号, 语法高亮。配置: git config --global pager.diff delta && git config --global pager.log delta

# 提交历史
git log --oneline -20
git log --oneline --graph --all          # 所有分支可视化
git log -p <file>                        # 某文件的每次变更 diff
git log --since="2025-01-01" --until="2025-01-15"
git log --author="name" --oneline
git log -S "function_name"               # 搜索引入/删除某段代码的 commit (pickaxe)
git log -G "regex"                       # 同上, regex 版本

# 谁改的
git blame <file> -L 40,60

# 二分查找引入 bug 的 commit
git bisect start
git bisect bad HEAD                      # 当前版本有问题
git bisect good v1.0                     # v1.0 没问题
# → Git checkout 中间版本 → 测试 → git bisect good/bad → ... → 定位到第一个 bad commit
git bisect reset                         # 结束 bisect

# 找回丢失的 commit
git reflog                               # 所有 HEAD 变动记录 (30 天)
git reflog show feature-branch           # 某分支的 reflog
# → 找到被 reset/drop 的 commit hash → git checkout -b recovery <hash>

分支与合并

git branch                               # 本地分支列表
git branch -r                            # 远程分支列表
git branch -a                            # 全部
git checkout -b feature                  # 创建并切换

# merge: 保留分支历史, 产生 merge commit
git merge feature
# 适用: feature 分支合并到 main, 保留"这个功能是分开发"的信息

# rebase: 把当前分支的 commit 搬到目标分支后面, 线性历史
git rebase main
# 适用: 在发 PR 前把 feature 分支对齐 main, 保持线性历史

# rebase 冲突时:
git rebase --continue                    # 解决完冲突继续
git rebase --skip                        # 跳过当前 commit
git rebase --abort                       # 取消整个 rebase

# cherry-pick: 从其他分支摘取单个 commit
git cherry-pick <commit-hash>
# 适用: 只想把某 bug fix 合入 release 分支, 不带其他改动

# 删除已合并的分支
git branch --merged main | grep -v 'main' | xargs git branch -d

暂存与撤销

# 暂存当前修改 (切分支前)
git stash
git stash save "描述"
git stash list
git stash pop                            # 恢复最近一次 stash 并删除
git stash apply stash@{1}                # 恢复指定 stash 不删除
git stash drop stash@{1}
git stash clear                          # 清空所有 stash

# 撤销
git reset --soft HEAD~1                  # 撤销最近 commit, 保留修改在 stage
git reset --mixed HEAD~1                 # 撤销最近 commit, 保留修改在 worktree (默认)
git reset --hard HEAD~1                  # 撤销最近 commit, 丢弃所有修改 (不可逆!)
git checkout -- <file>                   # 丢弃未暂存的修改 (不可逆)
git restore <file>                       # 同 checkout -- (新命令)
git restore --staged <file>              # 取消 add (从 stage 移到 worktree)

# 撤销已经 push 的 commit (远程):
git revert <commit-hash>                 # 创建反向 commit (安全, 不修改历史)
# vs reset: revert 适合公共分支 (不破坏别人的历史), reset 适合本地分支

远程

git remote -v
git remote add upstream https://github.com/original/repo.git
git fetch upstream                       # 拉取所有远程分支, 不合并
git fetch --prune                        # 同时删除已在远程不存在的本地引用
git pull --rebase                        # fetch + rebase (推荐, 避免无意义 merge commit)

# 安全 force push: 只有当远程没被人改过时才推
git push --force-with-lease
# 比 --force 安全: 如果同事在你上次 fetch 后 push 了, 这个会拒绝, 避免覆盖

Submodule

git submodule update --init --recursive  # 首次 clone 后拉取所有子模块
git submodule update --remote            # 更新子模块到各自的最新 commit
git submodule foreach git pull origin main

Worktree

# 在同一 repo 的不同目录检出不同分支 (无需 clone 两份)
git worktree add ../hotfix hotfix-branch
# → ../hotfix 目录是 hotfix-branch 的工作树, 不影响当前目录

git worktree list
git worktree remove ../hotfix
# 适用: 在跑长时间的测试时, 同时在另一个分支修 bug

Tag

git tag v1.0.0                           # 轻量 tag
git tag -a v1.0.0 -m "Release v1.0.0"    # 带注释 tag (推荐)
git tag -d v1.0.0                        # 删除本地 tag
git push origin v1.0.0                   # push 单个 tag
git push --tags                          # push 所有 tag