git 使用指南
Git 是一个分布式版本控制系统,用于跟踪文件的变化。它最初由 Linus Torvalds 为 Linux 内核开发而创建。
# 概念
# 三区模型
Git 有三个主要区域:
- 工作区 (Working Directory): 你实际编辑文件的地方
- 暂存区 (Staging Area/Index): 准备提交的文件临时存储区域
- 仓库 (Repository): 包含所有提交历史的数据库
# 查看当前状态
git status
# 添加文件到暂存区
git add <file>
# 提交到仓库
git commit -m "commit message"
2
3
4
5
6
7
8
文件状态流转:
未跟踪 (Untracked)
↓ git add
已暂存 (Staged)
↓ git commit
已提交 (Committed)
↓ 修改文件
已修改 (Modified)
↓ git add
已暂存 (Staged)
2
3
4
5
6
7
8
9
# 提交对象
提交是 Git 中最重要的概念,它代表项目在某个时间点的快照。
提交对象结构:
# 查看提交对象
git cat-file -p <commit-hash>
# 输出示例:
# tree abc123... # 指向项目快照的树对象
# parent def456... # 父提交(可能有多个)
# author Name <email> # 作者信息
# committer Name <email> # 提交者信息
#
# 提交信息
2
3
4
5
6
7
8
9
10
提交对象包含:
- 项目快照(tree 对象)
- 父提交引用(普通提交 1 个,合并提交 2+ 个)
- 作者信息
- 提交时间
- 提交信息
# HEAD 与引用
HEAD 指针是一个特殊的指针,指向当前所在的分支或提交。
# 查看 HEAD 指向
cat .git/HEAD
# HEAD 的不同引用方式
HEAD # 当前提交
HEAD~1 # 父提交
HEAD~2 # 祖父提交
HEAD^ # 父提交(用于合并提交的第一个父提交)
HEAD^2 # 合并提交的第二个父提交
2
3
4
5
6
7
8
9
Detached HEAD 状态:
当 HEAD 直接指向某个提交而不是分支时,就处于 detached HEAD 状态。
# 切换到特定提交(进入 detached HEAD)
git checkout <commit-hash>
# 从 detached HEAD 创建新分支
git checkout -b new-branch
# 返回到分支
git checkout main
2
3
4
5
6
7
8
引用系统:
引用是指向提交的指针,主要包括:
- 分支引用:
.git/refs/heads/- 可变指针 - 远程引用:
.git/refs/remotes/- 远程分支的本地副本 - 标签引用:
.git/refs/tags/- 不可变指针
# 查看所有引用
git show-ref
# 查看特定引用指向的提交
git rev-parse main
git rev-parse HEAD
# 查看分支指向的提交
cat .git/refs/heads/main
# 输出:abc123def456...(一个 40 字符的 SHA-1 哈希)
2
3
4
5
6
7
8
9
10
# 分支
分支只是一个指向提交对象的可变指针,创建分支非常轻量(只有 41 字节)。
# 创建分支
git branch <branch-name>
# 切换分支
git checkout <branch-name>
git switch <branch-name> # 新命令
# 创建并切换
git checkout -b <branch-name>
git switch -c <branch-name> # 新命令
# 查看分支
git branch # 本地分支
git branch -r # 远程分支
git branch -a # 所有分支
git branch -vv # 详细信息
# 删除分支
git branch -d <branch-name> # 安全删除
git branch -D <branch-name> # 强制删除
# 重命名分支
git branch -m <old-name> <new-name>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 合并提交
合并提交与普通提交的区别在于它有多个父提交。
# 普通提交
A---B---C
↑
只有一个父提交
# 合并提交
A---B---C---M
\ /
D---E
↑ ↑
第二父提交和第一父提交
2
3
4
5
6
7
8
9
10
11
# 查看合并提交的父提交
git log --pretty=%P -1 <merge-commit>
# 查看第一父提交
git log --first-parent
# 查看第二父提交
git show <merge-commit>^2
2
3
4
5
6
7
8
合并类型:
- 快进合并 (Fast-forward):目标分支是当前分支的直接后继,指针直接移动
- 三方合并 (3-way merge):两个分支都有新提交,创建新的合并提交
- 压缩合并 (Squash merge):将多个提交压缩为一个
# 第一父路径
第一父路径是指沿着每个合并提交的第一个父节点追溯的路径,代表主线分支的演进历史。
# 合并前的历史
A---B---C (main)
\
D---E (feature)
# 执行 git merge feature 后
A---B---C---M (main)
\ /
D---E (feature)
2
3
4
5
6
7
8
9
在合并提交 M 中:
- 第一父节点 (First Parent):
C- 当前所在的分支(main) - 第二父节点 (Second Parent):
E- 被合并进来的分支(feature)
# 查看第一父路径
git log --first-parent
# 查看完整历史
git log --oneline --graph --all
# * M (HEAD -> main) Merge branch 'feature'
# |\
# | * Feature commit 2
# | * Feature commit 1
# * | Main commit 1
# |/
# * Initial commit
# 查看第一父路径(只看主分支演进)
git log --oneline --first-parent
# M (HEAD -> main) Merge branch 'feature'
# Main commit 1
# Initial commit
# 注意:Feature 的提交被忽略了
# 使用场景
git log --first-parent main # 查看主分支演进
git rev-list --first-parent --count main # 统计主分支提交数
git log --first-parent --merges --oneline # 查找合并点
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 祖先路径
祖先路径是指从一个提交到另一个提交的直接祖先链,排除不在这条路径上的提交。
# 假设有这样的历史
A---B---C---D---E (main)
\ /
F---G---H (feature)
/
X---Y (other)
# git rev-list B..E
# 输出:E, D, C, H, G, F(所有可达的提交)
# git rev-list B..E --ancestry-path
# 输出:E, D, C, H, G(只包括从 B 到 E 的祖先路径)
# 排除了 X, Y(不在祖先路径上)
2
3
4
5
6
7
8
9
10
11
12
13
# 查找提交何时被合并
git rev-list <commit>..main --ancestry-path --merges
# 查看功能分支的合并历史
git log <commit>..main --ancestry-path --oneline
# 统计祖先路径上的提交数
git rev-list --count <commit>..main --ancestry-path
2
3
4
5
6
7
8
# 命令
# 基础操作
# 初始化和克隆
# 初始化新仓库
git init
# 克隆远程仓库
git clone <repository-url>
git clone -b <branch-name> <repository-url> # 克隆特定分支
git clone --depth 1 <repository-url> # 浅克隆
2
3
4
5
6
7
# 文件操作
# 添加文件到暂存区
git add <file> # 添加特定文件
git add . # 添加所有修改的文件
git add -A # 添加所有文件(包括删除的)
# 从暂存区移除文件
git reset HEAD <file>
git restore --staged <file> # 新命令
# 删除文件
git rm <file> # 删除文件并添加到暂存区
git rm --cached <file> # 从版本控制中移除,但保留本地文件
2
3
4
5
6
7
8
9
10
11
12
# 提交操作
# 创建提交
git commit -m "提交信息"
git commit -am "提交信息" # 跳过暂存区,直接提交已跟踪文件
# 修改最后一次提交
git commit --amend
git commit --amend --no-edit # 不修改提交信息
# 查看提交历史
git log
git log --oneline
git log --graph --oneline --all
git log --pretty=format:'%h - %an, %ar : %s'
git log --since="2024-01-01" --until="2024-12-31"
git log --author="username"
git log -- <file-path>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 查看状态和差异
# 查看当前状态
git status
git status -s # 简短格式
# 查看差异
git diff # 工作区 vs 暂存区
git diff --staged # 暂存区 vs 最后一次提交
git diff --cached # 同上
git diff branch1..branch2 # 比较两个分支
git diff commit1 commit2 # 比较两个提交
git diff --name-only # 只显示文件名
git diff --stat # 显示统计信息
# 查看提交内容
git show # 查看最新提交
git show <commit-hash> # 查看特定提交
git show <commit-hash>:<file-path> # 查看特定文件的历史
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 分支操作
# 切换分支
git checkout <branch-name>
git switch <branch-name>
# 切换到上一个分支
git checkout -
git switch -
# 查看分支关系
git log --graph --oneline --all --decorate
2
3
4
5
6
7
8
9
10
# 合并与变基
# 合并 (Merge)
# 合并分支到当前分支
git merge <branch-name>
# 合并策略
git merge --no-ff <branch-name> # 禁用快进合并
git merge --squash <branch-name> # 压缩合并
# 取消合并
git merge --abort
2
3
4
5
6
7
8
9
# 变基 (Rebase)
变基是重写提交历史的方法,将一个分支的提交"重新应用"到另一个分支上,创建更线性的历史。
# 变基操作
git rebase <base-branch>
# 交互式变基
git rebase -i <commit-hash>
# 继续/跳过/取消变基
git rebase --continue
git rebase --skip
git rebase --abort
2
3
4
5
6
7
8
9
10
变基 vs 合并:
| 特性 | 变基 (Rebase) | 合并 (Merge) |
|---|---|---|
| 历史记录 | 线性、清晰 | 保留分支结构 |
| 提交数量 | 较少 | 可能产生合并提交 |
| 安全性 | 重写历史,需谨慎 | 安全,不改变历史 |
| 适用场景 | 个人分支整理 | 公共分支合并 |
⚠️ 重要提醒:不要对公共分支进行变基,会影响其他协作者。
# 远程操作
# 查看远程仓库
git remote -v
# 添加/移除/重命名远程仓库
git remote add <name> <url>
git remote remove <name>
git remote rename <old-name> <new-name>
git remote set-url <name> <new-url>
# 推送到远程
git push <remote> <branch>
git push origin main
git push --force-with-lease # 更安全的强制推送
git push origin --delete <branch-name> # 删除远程分支
# 拉取更新
git pull <remote> <branch>
git pull origin main
# 获取远程更新(不合并)
git fetch <remote>
git fetch --all
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 其他常用命令
# 标签
# 创建标签
git tag <tag-name>
git tag -a <tag-name> -m "标签信息"
# 查看标签
git tag
git tag -l "v1.*"
# 删除标签
git tag -d <tag-name>
# 推送标签
git push origin <tag-name>
git push origin --tags
2
3
4
5
6
7
8
9
10
11
12
13
14
# cherry-pick
# 应用特定提交
git cherry-pick <commit-hash>
git cherry-pick <commit1> <commit2>
git cherry-pick <start-commit>..<end-commit>
# 只应用修改,不创建提交
git cherry-pick -n <commit-hash>
# 继续/取消 cherry-pick
git cherry-pick --continue
git cherry-pick --abort
2
3
4
5
6
7
8
9
10
11
# stash
# 暂存当前修改
git stash
git stash push -m "暂存信息"
git stash -u # 包括未跟踪的文件
git stash -a # 包括所有文件
# 查看暂存
git stash list
git stash show
git stash show -p stash@{0}
# 应用暂存
git stash apply # 应用但不删除
git stash pop # 应用并删除
git stash apply stash@{n}
# 删除暂存
git stash drop stash@{n}
git stash clear
# 从暂存创建分支
git stash branch <branch-name>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# reset 与 revert
# reset - 重置到特定提交
git reset --soft <commit-hash> # 保留工作区和暂存区
git reset --mixed <commit-hash> # 保留工作区,清空暂存区
git reset --hard <commit-hash> # 清空工作区和暂存区
# revert - 撤销提交(创建新提交)
git revert <commit-hash>
git revert <commit1> <commit2>
git revert -m 1 <merge-commit> # 撤销合并提交
2
3
4
5
6
7
8
9
撤销操作对比:
| 操作 | 工作区 | 暂存区 | 提交历史 | 使用场景 |
|---|---|---|---|---|
git restore <file> | 撤销 | 保留 | 保留 | 撤销工作区修改 |
git restore --staged <file> | 保留 | 撤销 | 保留 | 取消暂存 |
git reset --soft HEAD~1 | 保留 | 保留 | 撤销 | 修改提交信息 |
git reset --mixed HEAD~1 | 保留 | 撤销 | 撤销 | 重新组织提交 |
git reset --hard HEAD~1 | 撤销 | 撤销 | 撤销 | 完全放弃修改 |
git revert <commit> | 新提交 | 新提交 | 新提交 | 安全撤销公共提交 |
# 底层命令
# git rev-list
git rev-list 是底层命令,用于列出提交对象的 SHA-1 哈希值,是很多高级命令的基础。
# 基本用法
git rev-list <commit-range>
# 列出提交历史
git rev-list HEAD
git rev-list commit1..commit2
git rev-list main..feature # 在 feature 但不在 main
git rev-list feature..main # 在 main 但不在 feature
# 统计提交数量
git rev-list --count HEAD
git rev-list --count main..feature
git rev-list --count --first-parent main
git rev-list --count --merges HEAD
# 查找特定提交
git rev-list --merges HEAD # 列出合并提交
git rev-list --no-merges HEAD # 列出非合并提交
git rev-list -n 10 HEAD # 列出最近 10 个提交
git rev-list --since="2024-01-01" --until="2024-12-31" HEAD
# 祖先路径
git rev-list commit1..commit2 --ancestry-path
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
rev-list vs log 对比:
| 特性 | git rev-list | git log |
|---|---|---|
| 用途 | 底层命令,输出提交 SHA | 高级命令,格式化输出 |
| 输出 | 只有提交哈希 | 包含作者、日期、信息 |
| 性能 | 更快 | 较慢 |
| 脚本使用 | 适合 | 不太适合 |
| 人类可读 | 否 | 是 |
实用示例:
# 查找两个分支的共同祖先
git merge-base main feature
# 查找提交何时被合并
commit_hash="abc1234"
git rev-list $commit_hash..main --ancestry-path --merges --reverse | head -1
# 比较两个分支
echo "Feature 领先 main: $(git rev-list --count main..feature) 个提交"
echo "Main 领先 feature: $(git rev-list --count feature..main) 个提交"
# 查找包含特定文件的提交
git rev-list --all -- path/to/file
git rev-list --count --all -- path/to/file
git rev-list --all --diff-filter=D -- path/to/file # 查找删除文件的提交
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 其他底层命令
# git cat-file - 查看 Git 对象
git cat-file -t <object-hash> # 查看对象类型
git cat-file -p <object-hash> # 查看对象内容
git cat-file -s <object-hash> # 查看对象大小
# git ls-tree - 列出树对象
git ls-tree HEAD
git ls-tree -r HEAD # 递归列出
git ls-tree --name-only HEAD # 只显示文件名
# git hash-object - 计算对象哈希值
git hash-object <file>
git hash-object -w <file> # 写入对象数据库
2
3
4
5
6
7
8
9
10
11
12
13
# 配置
# 配置级别
Git 有三个配置级别,优先级从高到低:
- 本地配置 (
--local): 仅对当前仓库有效,存储在.git/config - 全局配置 (
--global): 对当前用户所有仓库有效,存储在~/.gitconfig - 系统配置 (
--system): 对所有用户有效,存储在/etc/gitconfig
# 查看配置
git config --list
git config --local --list
git config --global --list
git config --system --list
git config --list --show-origin # 查看配置来源
2
3
4
5
6
# 基本配置
# 设置用户信息
git config --global user.name "Your Name"
git config --global user.email "[email protected]"
# 设置默认编辑器
git config --global core.editor "vim"
git config --global core.editor "code --wait" # VS Code
# 设置默认分支名
git config --global init.defaultBranch main
# 配置换行符处理
git config --global core.autocrlf true # Windows
git config --global core.autocrlf input # macOS/Linux
# 配置颜色显示
git config --global color.ui auto
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 别名配置
# 基础别名
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
# 高级别名
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
git config --global alias.lg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
git config --global alias.undo 'reset --soft HEAD~1'
git config --global alias.amend 'commit --amend --no-edit'
2
3
4
5
6
7
8
9
10
11
12
# 推荐配置
cat > ~/.gitconfig << 'EOF'
[user]
name = Your Name
email = [email protected]
[core]
editor = vim
autocrlf = input
quotepath = false
ignorecase = false
[init]
defaultBranch = main
[color]
ui = auto
[alias]
st = status
co = checkout
br = branch
ci = commit
unstage = reset HEAD --
last = log -1 HEAD
lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
[pull]
rebase = false
[push]
default = simple
followTags = true
[merge]
conflictstyle = diff3
[diff]
tool = vimdiff
[credential]
helper = cache --timeout=3600
EOF
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 高级配置
# 子模块
git submodule add <repository-url> <path>
git submodule init
git submodule update
git clone --recurse-submodules <repository-url>
# 工作树
git worktree add <path> <branch>
git worktree list
git worktree remove <path>
# 二分查找
git bisect start
git bisect bad
git bisect good <commit-hash>
git bisect run <command>
git bisect reset
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 工作流
# 基本工作流程
# 1. 克隆仓库
git clone <repository-url>
cd <project-name>
# 2. 创建功能分支
git checkout -b feature/new-feature
# 3. 开发和提交
git add .
git commit -m "Add new feature"
# 4. 推送到远程
git push origin feature/new-feature
# 5. 创建 Pull Request/Merge Request
# 6. 合并到主分支
git checkout main
git pull origin main
git merge feature/new-feature
git push origin main
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Git Flow 工作流
# 主分支
main # 生产环境代码
develop # 开发环境代码
# 功能分支
feature/* # 新功能开发
release/* # 发布准备
hotfix/* # 紧急修复
2
3
4
5
6
7
8
# 提交信息规范
约定式提交 (Conventional Commits):
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
2
3
4
5
类型 (type):
feat: 新功能fix: 修复bugdocs: 文档更新style: 代码格式调整refactor: 代码重构test: 测试相关chore: 构建过程或辅助工具变动
示例:
git commit -m "feat(auth): add user authentication system"
git commit -m "fix(api): resolve login endpoint timeout issue"
git commit -m "docs(readme): update installation instructions"
2
3
# 故障排除
# 常见问题
1. 推送被拒绝 (non-fast-forward)
# 解决方案1:先拉取再推送
git pull --rebase origin main
git push origin main
# 解决方案2:强制推送(谨慎使用)
git push --force-with-lease origin main
2
3
4
5
6
2. 提交到错误的分支
git reset --soft HEAD~1
git checkout correct-branch
git commit -m "Correct commit message"
2
3
3. 忘记添加文件到上次提交
git add forgotten-file
git commit --amend --no-edit
2
4. 提交了敏感信息
# 从最后一次提交中移除
git rm --cached sensitive-file
git commit --amend -m "Remove sensitive file"
# 从历史中完全移除
bfg --delete-files sensitive-file
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git push --force --all
2
3
4
5
6
7
8
9
5. 合并后想要撤销
# 如果还没有推送
git reset --hard HEAD~1
# 如果已经推送
git revert -m 1 <merge-commit-hash>
2
3
4
5
6. 误删分支
git reflog
git checkout -b recovered-branch <commit-hash>
2
7. 解决 "detached HEAD" 状态
git checkout -b temp-branch # 保存当前工作
git checkout main # 或直接切换回分支
2
8. 大文件导致推送失败
git filter-branch --tree-filter 'rm -f large-file' HEAD
# 或使用 git-filter-repo(推荐)
git filter-repo --path large-file --invert-paths
2
3
# 解决冲突
# 查看冲突文件
git status
# 查看冲突详情
git diff
# 手动解决冲突后
git add <resolved-file>
git commit -m "Resolve merge conflicts"
# 使用合并工具
git mergetool
# 查看冲突的两个版本
git show :1:<file> # 共同祖先版本
git show :2:<file> # 当前分支版本
git show :3:<file> # 合并分支版本
# 选择特定版本
git checkout --ours <file> # 使用当前分支版本
git checkout --theirs <file> # 使用合并分支版本
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
冲突标记:
<<<<<<< HEAD
当前分支的内容
=======
合并分支的内容
>>>>>>> feature-branch
2
3
4
5
# 恢复和清理
# 恢复删除的文件
git log --diff-filter=D --summary
git checkout <commit-hash> -- <file-path>
git checkout HEAD~1 -- <file-path>
# 从 reflog 恢复
git reflog
git checkout <reflog-entry> -- <file-path>
# 清理未跟踪的文件
git clean -f # 删除文件
git clean -fd # 删除文件和目录
git clean -n # 预览将要删除的文件
git clean -i # 交互式清理
# 压缩仓库
git gc
git gc --aggressive
git reflog expire --expire=now --all
git gc --prune=now
# 查看仓库大小
git count-objects -vH
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 性能优化
# 浅克隆
git clone --depth 1 <repository-url>
# 部分克隆
git clone --filter=blob:none <repository-url>
# 单分支克隆
git clone -b <branch> <repository-url>
# 使用 Git LFS
git lfs track "*.psd"
git lfs track "*.zip"
2
3
4
5
6
7
8
9
10
11
12
# 技巧
# 别名和脚本
# 实用别名(添加到 ~/.gitconfig)
[alias]
st = status
co = checkout
br = branch
ci = commit
unstage = reset HEAD --
last = log -1 HEAD
lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
undo = reset --soft HEAD~1
amend = commit --amend --no-edit
wip = commit -am "WIP"
aliases = config --get-regexp alias
contributors = shortlog --summary --numbered
recent = branch --sort=-committerdate --format='%(committerdate:relative)%09%(refname:short)'
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
# git-sync.sh - 同步远程分支
git fetch --all
git pull --rebase
git push
# git-cleanup.sh - 清理已合并的分支
git branch --merged | grep -v "\*" | grep -v "main" | grep -v "master" | xargs -n 1 git branch -d
2
3
4
5
6
7
8
# 搜索和查找
# 在提交历史中搜索代码
git log -S "function_name" --source --all
# 在提交信息中搜索
git log --grep="bug fix" --oneline
# 查找谁修改了某行代码
git blame <file>
git blame -L 10,20 <file>
# 查找文件的修改历史
git log --follow -- <file>
# 查找包含特定文件的提交
git log --all -- <file>
# 查找删除/添加的文件
git log --diff-filter=D --summary
git log --diff-filter=A --summary
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 高级查询
查找分支创建点:
git reflog --date=local --all | grep <branch-name>
查看修改何时合并到主分支:
添加以下别名到 ~/.gitconfig:
[alias]
find-merge = "!sh -c 'commit=$0 && branch=${1:-HEAD} && (git rev-list $commit..$branch --ancestry-path | cat -n; git rev-list $commit..$branch --first-parent | cat -n) | sort -k2 -s | uniq -f1 -d | sort -n | tail -1 | cut -f2'"
show-merge = "!sh -c 'merge=$(git find-merge $0 $1) && [ -n \"$merge\" ] && git show $merge'"
2
3
find-merge 原理:
--ancestry-path: 找到从起始提交到目标分支的所有祖先路径提交--first-parent: 只沿着主分支的第一父路径- 两者的交集就是合并提交
A---B---C---D---E---F (main)
\ /
G---H---I (feature)
# 查找 G 何时合并到 main
git rev-list G..main --ancestry-path
# 输出:F, E, I, H
git rev-list G..main --first-parent
# 输出:F, E, D, C
# 交集:F, E
# 最后一个(最新的):F(这就是合并提交)
2
3
4
5
6
7
8
9
10
11
12
13
使用示例:
# 查找特定提交何时合并到 master
git find-merge <commit-hash> master
# 显示合并提交的详细信息
git show-merge <commit-hash> master
2
3
4
5
# 钩子 (Hooks)
#!/bin/sh
# .git/hooks/pre-commit
# 运行测试
npm test
# 代码格式化检查
npm run lint
# 阻止提交特定文件
if git diff --cached --name-only | grep -q "debug.log"; then
echo "Error: Cannot commit debug.log"
exit 1
fi
2
3
4
5
6
7
8
9
10
11
12
13
14
# 分支管理技巧
# 删除已合并的分支
git branch --merged | grep -v "\*" | xargs -n 1 git branch -d
# 删除远程已删除的分支
git remote prune origin
# 查看分支关系
git log --graph --oneline --all --decorate
# 重命名分支
git branch -m old-name new-name
git push origin :old-name
git push origin new-name
2
3
4
5
6
7
8
9
10
11
12
13
# 实战
# 场景1:团队协作开发新功能
# 1. 从主分支创建功能分支
git checkout main
git pull origin main
git checkout -b feature/user-authentication
# 2. 开发过程中定期提交
git add src/auth/
git commit -m "feat(auth): add login functionality"
# 3. 同步主分支的最新更改
git fetch origin main
git rebase origin/main
# 4. 推送到远程
git push origin feature/user-authentication
# 5. 创建 Pull Request 后,根据反馈修改
git add .
git commit --amend
# 6. 强制推送更新
git push --force-with-lease origin feature/user-authentication
# 7. 合并后清理
git checkout main
git pull origin main
git branch -d feature/user-authentication
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 场景2:紧急修复生产环境 Bug
# 1. 从生产分支创建 hotfix 分支
git checkout main
git pull origin main
git checkout -b hotfix/critical-bug
# 2. 快速修复并测试
git add .
git commit -m "fix: resolve critical bug in payment module"
# 3. 合并到主分支
git checkout main
git merge --no-ff hotfix/critical-bug
git push origin main
# 4. 同时合并到开发分支
git checkout develop
git merge --no-ff hotfix/critical-bug
git push origin develop
# 5. 清理 hotfix 分支
git branch -d hotfix/critical-bug
git push origin --delete hotfix/critical-bug
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 场景3:整理混乱的提交历史
# 交互式变基整理最近 5 个提交
git rebase -i HEAD~5
# 在编辑器中调整提交
# pick -> 保留提交
# squash -> 合并到前一个提交
# reword -> 修改提交信息
# drop -> 删除提交
# 示例操作
pick abc1234 feat: add user model
squash def5678 fix typo
squash ghi9012 fix formatting
reword jkl3456 feat: add user validation
pick mno7890 docs: update README
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 场景4:恢复误删的提交
# 1. 查看所有操作历史
git reflog
# 2. 找到误删前的提交
# abc1234 HEAD@{0}: reset: moving to HEAD~1
# def5678 HEAD@{1}: commit: important feature
# 3. 恢复提交
git cherry-pick def5678
# 或者重置到那个状态
git reset --hard def5678
2
3
4
5
6
7
8
9
10
11
# 场景5:同时开发多个功能
# 使用 worktree 同时处理多个分支
git worktree add ../project-feature1 feature/feature1
git worktree add ../project-feature2 feature/feature2
# 在不同目录中独立工作
cd ../project-feature1
# 开发 feature1
cd ../project-feature2
# 开发 feature2
# 完成后清理 worktree
git worktree remove ../project-feature1
git worktree remove ../project-feature2
2
3
4
5
6
7
8
9
10
11
12
13
14
# 场景6:代码审查和反馈
# 审查者检出 PR 分支
git fetch origin pull/123/head:pr-123
git checkout pr-123
# 查看修改
git log main..pr-123
git diff main...pr-123
# 开发者根据反馈修改
git add .
git commit -m "refactor: address code review comments"
git push origin feature-branch
2
3
4
5
6
7
8
9
10
11
12
# 最佳实践
# 提交规范
提交信息格式:
<type>(<scope>): <subject>
<body>
<footer>
2
3
4
5
类型:
feat: 新功能fix: Bug 修复docs: 文档更新style: 代码格式(不影响代码运行)refactor: 重构perf: 性能优化test: 测试相关chore: 构建过程或辅助工具的变动ci: CI 配置文件和脚本的变动build: 影响构建系统或外部依赖的更改
示例:
feat(auth): add JWT authentication
Implement JWT-based authentication system with:
- Token generation and validation
- Refresh token mechanism
- Middleware for protected routes
Closes #123
2
3
4
5
6
7
8
最佳实践:
- 原子性提交:每个提交只做一件事
- 频繁提交:小步快跑,便于回滚
- 描述性信息:清楚说明"做了什么"和"为什么"
- 使用现在时:使用 "add feature" 而不是 "added feature"
- 限制长度:标题不超过 50 字符,正文每行不超过 72 字符
# 分支管理
分支命名规范:
feature/user-authentication # 功能分支
fix/login-error # Bug 修复
hotfix/critical-security-issue # 热修复
release/v1.2.0 # 发布分支
experiment/new-ui-design # 实验性功能
2
3
4
5
分支管理策略:
- 保护主分支:禁止直接推送,要求 PR 审查,要求 CI 通过
- 及时清理分支:
git branch --merged | grep -v "\*\|main\|develop" | xargs -n 1 git branch -d - 使用分支策略:Git Flow(版本发布)/ GitHub Flow(持续部署)/ GitLab Flow(环境分支)
# 协作开发
代码审查清单:
- [ ] 代码符合项目规范
- [ ] 测试覆盖充分
- [ ] 文档已更新
- [ ] 没有调试代码
- [ ] 性能影响可接受
- [ ] 安全性考虑充分
冲突解决策略:
- 预防冲突:频繁同步主分支
git fetch origin main && git rebase origin/main - 解决冲突:使用
git mergetool或手动编辑后git add <resolved-files> && git rebase --continue - 团队沟通:修改同一文件前先沟通,大规模重构提前通知
# 安全考虑
# 1. 使用 .gitignore
cat >> .gitignore << EOF
.env
*.key
*.pem
secrets/
config/local.js
EOF
# 2. 使用环境变量
const apiKey = process.env.API_KEY; # ✅ 正确
API_KEY=your_key_here # ❌ 错误
# 3. 使用 git-secrets
git secrets --install
git secrets --register-aws
# 4. SSH 密钥配置
ssh-keygen -t ed25519 -C "[email protected]"
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh -T [email protected]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 资源
# 官方文档
- Git 官方文档 (opens new window)
- Git 教程 (opens new window)
- Git 参考手册 (opens new window)
- 祖先引用、双点、三点... (opens new window)
# 在线教程
- Learn Git Online (opens new window)
- GitHub Learning Lab (opens new window)
- Git 教程 - 廖雪峰 (opens new window)
# 工具
GUI 客户端:
- GitHub Desktop - 简单易用
- GitKraken - 功能强大
- SourceTree - Atlassian 免费客户端
- TortoiseGit - Windows 集成
命令行工具:
- tig - 文本模式的 Git 浏览器
- hub - GitHub 命令行工具
- gh - GitHub CLI
- git-flow - Git Flow 工作流工具
在线平台:
- GitHub - 最流行的代码托管平台
- GitLab - 功能丰富的 DevOps 平台
- Bitbucket - Atlassian 的代码托管服务
- Gitee - 国内的代码托管平台