Appearance
git
config
1. 临时修改用户名和邮箱
如果只需要修改当前仓库的提交者信息,可以使用以下命令:
bash
git config user.name "新用户名"
git config user.email "新邮箱"2. 全局修改用户名和邮箱
bash
git config --global user.name "新用户名"
git config --global user.email "新邮箱"remote
1. 查看当前远程地址
bash
git remote -v2. 修改远程地址
bash
git remote set-url origin NEW_REMOTE_URL3. 验证修改
bash
git remote -v4. 推送到新地址
bash
git push origin main5. 添加或替换其他远程地址
bash
git remote add NAME NEW_REMOTE_URL6. 删除远程地址
bash
git remote remove NAME| 操作 | 命令 |
|---|---|
| 修改远程地址 | git remote set-url origin NEW_URL |
| 添加远程地址 | git remote add NAME NEW_URL |
| 删除远程地址 | git remote remove NAME |
撤销修改
1. 丢弃已暂存的修改
bash
git reset HEAD FILEgit reset HEAD FILE会将指定文件从暂存区移回工作区,修改仍然保留在工作区中,但不会再被标记为已暂存。
2. 丢弃工作区的修改
bash
git checkout -- FILEgit checkout -- FILE会将文件恢复到上一次提交时的状态,丢弃工作区中的修改
| 场景 | 命令 |
|---|---|
| 仅取消暂存区的修改 | git reset HEAD FILE |
| 取消暂存区修改并恢复文件内容 | git reset HEAD FILE → git checkout -- FILE |
Git 三步曲
Git 的核心工作流围绕本地仓库与远程仓库之间的同步展开:
text
工作区 → 暂存区 → 本地仓库 → 远程仓库
edit add commit push
← pull ←| 步骤 | 作用 | 为什么不可或缺 |
|---|---|---|
| commit | 将暂存区的变更提交到本地仓库,形成一个新的提交节点 | 没有commit,你的修改只停留在本地,无法被版本管理追踪 |
| pull | 从远程仓库拉取最新代码并合并到本地 | 没有pull,你可能在过时的代码基础上push,导致冲突或覆盖他人工作 |
| push | 将本地提交推送到远程仓库,与团队共享 | 没有push,你的commit只存在于本地,团队成员看不到你的成果 |
顺序逻辑:
- 先 commit:先固化自己的工作成果,确保有据可查
- 再 pull:获取他人最新工作,尽早发现冲突,在本地解决比远程解决更安全
- 后 push:在确认本地与远程一致后,安全地推送
⚠️ 如果先 push 再 pull,可能直接覆盖远程的他人提交;如果先 pull 再 commit,可能在过时代码上开发,后续合并更痛苦。
commit
git commit [options]
| 参数 | 说明 | 示例 |
|---|---|---|
-m [msg] | 直接指定提交信息,不打开编辑器 | git commit -m "feat: 添加用户登录接口" |
-a | 自动暂存所有已跟踪文件的修改(跳过 git add) | git commit -a -m "fix: 修复空指针异常" |
--amend | 修改上一次提交(追加修改或改写提交信息) | git commit --amend -m "feat: 更新登录逻辑" |
--no-verify | 跳过 pre-commit 和 commit-msg 钩子(慎用) | git commit --no-verify -m "wip: 临时提交" |
--allow-empty | 允许提交空变更(常用于 CI 触发) | git commit --allow-empty -m "chore: 触发部署" |
-s / --signoff | 在提交信息末尾追加 Signed-off-by 签名 | git commit -s -m "feat: 新功能" |
--author=[author] | 指定作者(覆盖 git config user) | git commit --author="Alice [a@b.com]" -m "..." |
--date=[date] | 指定提交日期 | git commit --date="2026-01-01T00:00:00" -m "..." |
常用组合:
bash
bash
git commit -am "fix: 修复分页查询bug"
# 等价于 git add -u && git commit -m "fix: 修复分页查询bug"💡 提交信息规范(Conventional Commits):
feat:新功能 |fix:修复 |docs:文档 |refactor:重构style:格式 |test:测试 |chore:构建/工具
pull
git pull [options] [remote [branch]]
| 参数 | 说明 | 示例 |
|---|---|---|
| (无参数) | 默认 git fetch + git merge | git pull |
--rebase | 用 rebase 代替 merge 合并,保持线性历史 | git pull --rebase |
--no-rebase | 强制使用 merge 合并(显式指定) | git pull --no-rebase |
--ff-only | 仅允许快进合并,有分歧则拒绝(最安全) | git pull --ff-only |
--no-ff | 禁止快进,始终产生合并提交 | git pull --no-ff |
--commit | 合并后自动提交(默认行为) | git pull --commit |
--no-commit | 合并但不自动提交,可先审查 | git pull --no-commit |
--squash | 将远程提交压缩为一个,不自动提交 | git pull --squash |
--tags | 同时拉取远程标签 | git pull --tags |
--depth=<n> | 浅克隆,仅拉取最近 n 层提交历史 | git pull --depth=1 |
--allow-unrelated-histories | 允许合并不相关的历史 | git pull --allow-unrelated-histories |
常用组合:
bash
git pull --rebase origin main
# 拉取 origin/main 并以 rebase 方式合并,历史更整洁💡 merge vs rebase 选择:
merge:保留完整分支历史,安全但历史图复杂rebase:线性历史,更整洁,但改写了提交的基底(公共分支慎用)- 推荐:个人分支用
--rebase,公共分支用merge
push
git push [options] [remote [refspec...]]
| 参数 | 说明 | 示例 |
|---|---|---|
| (无参数) | 推送当前分支到对应上游分支 | git push |
-u / --set-upstream | 推送并设置上游跟踪分支(首次推送必用) | git push -u origin feature/login |
--force / -f | 强制推送,覆盖远程历史(⚠️ 危险) | git push --force |
--force-with-lease | 安全版强制推送,仅当远程未被他人更新时才覆盖 | git push --force-with-lease |
--all | 推送所有本地分支 | git push --all origin |
--tags | 推送所有本地标签 | git push --tags |
--delete | 删除远程分支 | git push --delete origin old-branch |
--dry-run | 模拟推送,不实际执行(预检查) | git push --dry-run |
--no-verify | 跳过 pre-push 钩子 | git push --no-verify |
--prune | 推送时删除远程已不存在的本地分支的跟踪引用 | git push --prune |
常用组合:
bash
git push -u origin feature/login # 首次推送新分支并建立跟踪
git push --force-with-lease # rebase 后安全强制推送
git push origin --delete feature/old # 删除远程分支💡 force-with-lease vs force:
--force:无条件覆盖,可能丢失他人提交--force-with-lease:如果远程分支已被他人更新,推送会被拒绝,更安全
branch
1. 查看分支
bash
git branch
git branch -a
git branch -r2. 创建分支
bash
git branch BRANCH_NAME
git checkout -b BRANCH_NAME3. 切换分支
bash
git checkout BRANCH_NAME
git checkout BRANCH_NAME COMMIT_HASH
# git 2.23之后推荐使用git switch
git switch BRANCH_NAME切换分支前应该注意不要带着脏工作区切换,有变动的内容要么 commit,要么 stash。例如:在dev分支新增了a.txt文件未提交,切换到main分支后,这个文件还在,会污染main分支的工作区
4. 删除分支
bash
#安全删除:只有在分支已经被成功合并到上游分支(或当前分支)时,才会允许删除。
#如果分支尚未合并,Git 会拒绝删除并给出警告
git branch -d BRANCH_NAME
#强制删除:等价于 git branch -d --force,无论分支是否已合并,都会直接删除。
#不会做任何合并检查,直接删除分支及其指向的提交。当你确定不再需要该分支上的任何提交时使用。
git branch -D BRANCH_NAME
git push origin --delete BRANCH_NAME5. 合并分支
bash
git merge BRANCH_NAME解决冲突后:
bash
git add FILE
git commit -m DESC6. 推送分支
基本语法:
bash
git push 远程仓库名 本地分支:远程分支常用参数:
| 参数 | 说明 |
|---|---|
git push | 将当前分支推送到对应的远程分支(需已设置上游分支) |
git push origin | 推送到 origin 远程仓库 |
git push origin main | 将本地 main 分支推送到 origin/main |
git push origin local:remote | 将本地 local 分支推送到远程 remote 分支(分支名不同时) |
常用选项:
| 选项 | 说明 |
|---|---|
-u / --set-upstream | 推送的同时设置上游分支,后续可直接 git push |
--all | 推送所有本地分支到远程 |
--tags | 推送所有标签(tag) |
--delete | 删除远程分支,如 git push --delete origin feature |
-f / --force | 强制推送,覆盖远程历史(⚠️ 危险) |
--force-with-lease | 安全强制推送,只有远程分支未被他人更新时才覆盖(✅ 推荐) |
-d | 等价于 --delete,删除远程分支 |
--dry-run | 模拟推送,只显示会推送什么,不实际执行 |
-v / --verbose | 显示详细推送信息 |
-q / --quiet | 静默模式,只输出错误信息 |
--no-tags | 推送时不推送标签 |
常见用法示例:
bash
# 首次推送并设置上游分支
git push -u origin main
# 推送标签
git push origin v1.0.0
# 删除远程分支
git push origin --delete feature
# 或简写
git push origin -d feature
# 强制推送(推荐用 --force-with-lease 替代 --force)
git push --force-with-lease origin main
# 推送本地 feature 分支到远程的 dev 分支
git push origin feature:dev
# 删除远程分支的另一种写法(推送空分支)
git push origin :feature--force vs --force-with-lease:
| 选项 | 行为 | 安全性 |
|---|---|---|
--force | 无条件覆盖远程分支 | ⚠️ 可能覆盖他人的提交 |
--force-with-lease | 仅当远程分支仍是你上次拉取的状态时才覆盖 | ✅ 更安全 |
日常 rebase 后推送,优先使用
--force-with-lease,避免误覆盖协作者的提交。
7. 重命名分支
bash
git branch -m NEW_BRANCH_NAME
git branch -m OLD_BRANCH_NAME NEW_BRANCH_NAME8. 分支比较
9. 分支管理常见流程
| 操作 | 命令 |
|---|---|
| 创建分支 | git branch BRANCH_NAME |
| 切换分支 | git switch BRANCH_NAME |
| 删除分支 | git branch -d BRANCH_NAME |
| 合并分支 | git merge BRANCH_NAME |
| 推送分支 | git push origin BRANCH_NAME |
| 跟踪分支 | git branch --set-upstream-to=origin/BRANCH_NAME |
stash
git stash用来暂存更改,一般用来解决切换分支前当前功能未完成又不想临时提交的问题。
git stash 保存
| 参数 | 说明 | 示例 |
|---|---|---|
| (无参数) | 暂存已跟踪文件的修改和暂存区内容 | git stash |
-u / --include-untracked | 同时包含未跟踪的文件 | git stash -u |
-a / --all | 包含未跟踪文件和 .gitignore 忽略的文件 | git stash -a |
-m | 添加备注信息 | git stash -m "开发登录功能" |
-k / --keep-index | 只暂存工作区修改,保留暂存区内容不动 | git stash -k |
-p / --patch | 交互式选择要暂存的修改块 | git stash -p |
push | 显式写法(可配合路径参数只暂存指定文件) | git stash push -m "备注" path/to/file |
git stash 查看 / 恢复 / 删除 / 其他
| 参数 | 说明 | 示例 |
|---|---|---|
list | 列出所有 stash 记录 | git stash list |
show | 查看最新 stash 的文件变更概要 | git stash show |
show -p | 查看最新 stash 的完整 diff | git stash show -p |
show stash@{n} | 查看指定 stash 的概要 | git stash show stash@{1} |
pop | 恢复最新 stash 并删除该记录 | git stash pop |
pop stash@{n} | 恢复指定 stash 并删除该记录 | git stash pop stash@{1} |
apply | 恢复最新 stash 但保留记录 | git stash apply |
apply stash@{n} | 恢复指定 stash 但保留记录 | git stash apply stash@{1} |
drop | 删除最新的 stash 记录 | git stash drop |
drop stash@{n} | 删除指定的 stash 记录 | git stash drop stash@{1} |
clear | 删除所有 stash 记录 | git stash clear |
branch <名称> | 基于最新 stash 创建新分支并应用 | git stash branch hotfix stash@{1} |
fetch
git fetch 用于从远程仓库获取最新的提交、分支、标签等引用信息,但不会修改本地工作区和当前分支。它是 git pull 的"安全版"。
1. 基本用法
bash
# 拉取所有远程分支的更新
git fetch
# 拉取指定远程仓库的更新
git fetch origin
# 拉取指定远程分支的更新
git fetch origin main2. fetch 与 pull 的区别
| 对比项 | git fetch | git pull |
|---|---|---|
| 拉取远程数据 | ✅ | ✅ |
| 修改本地工作区 | ❌ 不修改 | ✅ 自动合并/快进 |
| 产生合并冲突的可能性 | 无 | 可能有 |
| 安全性 | 安全,不影响当前工作 | 可能破坏当前工作状态 |
| 本质 | 仅下载 | git fetch + git merge |
git pull=git fetch+git merge(默认行为)。也可以配置为git fetch+git rebase(git pull --rebase)。
3. 各自使用场景
| 场景 | 推荐命令 | 说明 |
|---|---|---|
| 想查看远程更新但不影响本地 | git fetch | 先拉取远程信息,再决定是否合并 |
| rebase 工作流中同步主分支 | git fetch | 配合 git rebase origin/main 使用,避免 git pull 产生的多余合并提交 |
| 本地分支落后远程,直接同步 | git pull | 简单场景下快速同步,等同于 fetch + merge |
| 本地有未提交的改动 | git fetch | git pull 可能产生冲突或覆盖提示,fetch 更安全 |
git pull适用于同一个分支的同步。例如:你在 main 分支上,想把远程 main 的最新代码拉下来
| 你当前所在分支 | 你想同步主分支最新代码 | 该敲什么命令 | 为什么 |
|---|---|---|---|
在 feature 分支上 | 想同步 main | 必须用 git fetch origin main | 用 pull 会把 main 直接塞进 feature,破坏分支纯净度,导致后续无法 rebase。 |
在 main 分支上 | 想更新本地 main | 直接用 git pull origin main | 因为 main 本来就是用来同步的,pull 自动合并,省去一步手动 merge的操作。 |
4. fetch 后的常用操作
bash
# 拉取远程更新
git fetch origin
# 查看本地分支与远程分支的差异
git log HEAD..origin/main
# 查看远程分支列表
git branch -r
# 确认无误后,手动合并或变基
git merge origin/main
# 或
git rebase origin/main5. 实战示例:fetch + rebase 工作流
以下是一个典型的"在功能分支上同步主分支最新代码并继续开发"的流程,体现了 git fetch 与 git pull 的核心区别:
bash
# 1. 切换到功能分支
git checkout feature/login
# 2. 拉取最新的 main(仅下载,不修改本地分支)
git fetch origin main
# 3. 在功能分支上执行 rebase(把功能分支的提交放到最新 main 后面)
git rebase origin/main
# 4. 继续开发,提交新功能
git add . && git commit -m "feat: 增加验证码登录"
# 5. 强制推送覆盖远程的功能分支(因为只有你用,所以安全)
git push --force-with-lease origin feature/login为什么这里用 git fetch 而不是 git pull?
git pull origin main会自动将远程 main 合并到当前分支(feature/login),产生一个多余的合并提交,污染提交历史。git fetch origin main只下载远程 main 的最新数据到origin/main引用,不触碰当前分支,再由git rebase origin/main将功能分支干净地变基到最新 main 之上,保持线性历史。git push --force-with-lease比git push --force更安全,它会在远程分支没有被他人更新时才允许强制推送,避免覆盖他人的提交。
rebase
git rebase 是 Git 中用于将一个分支的提交"重新应用"到另一个分支上的操作,从而产生线性、整洁的提交历史。与 git merge 不同,rebase 会重写提交历史。
1. 基本概念
git rebase的作用:将当前分支的提交变基到目标分支的最新提交之上,使提交历史呈线性。- 核心原理:取出当前分支的每个提交,依次"重放"到目标分支的顶端。
2. 基本用法
bash
# 将当前分支变基到 TARGET_BRANCH 上
git rebase TARGET_BRANCH示例:在 feature 分支上执行 git rebase main,会将 feature 分支的提交移到 main 最新提交之后。
3. 交互式 rebase
交互式 rebase 允许在变基过程中对提交进行编辑、合并、重排序、删除等操作。
bash
git rebase -i TARGET_BRANCH在打开的编辑器中,每个提交前有一个操作关键字:
| 关键字 | 说明 |
|---|---|
pick | 保留该提交(默认) |
reword | 保留提交,但修改提交信息 |
edit | 保留提交,但暂停以便修改提交内容 |
squash | 将该提交合并到前一个提交,合并提交信息 |
fixup | 将该提交合并到前一个提交,丢弃该提交信息 |
drop | 删除该提交 |
4. 处理冲突
变基过程中如果出现冲突:
bash
# 解决冲突后,继续变基
git add .
git rebase --continue
# 跳过当前提交
git rebase --skip
# 放弃整个变基操作,回到变基前的状态
git rebase --abort5. 常用场景与建议
| 场景 | 是否推荐 | 说明 |
|---|---|---|
| 本地分支更新到最新主分支 | ✅ 推荐 | 在 feature 分支上 git rebase main,保持提交历史整洁 |
| 压缩本地提交 | ✅ 推荐 | 使用 git rebase -i 合并、整理本地提交 |
| 多人协作的共享分支 | ❌ 不推荐 | 会导致他人的提交历史被重写,造成混乱和冲突 |
6. rebase vs merge 对比
| 对比项 | rebase | merge |
|---|---|---|
| 提交历史 | 线性、整洁 | 保留分支交叉历史 |
| 是否产生合并提交 | 否 | 是(默认) |
| 是否重写提交历史 | 是 | 否 |
| 多人共享分支安全性 | 不安全 | 安全 |
⚠️ 黄金法则:不要对已经推送到远程仓库且他人正在使用的分支执行 rebase。 rebase 会重写提交历史,导致协作者的提交丢失或产生冲突。rebase 最适合用于本地私有分支的整理和更新。
代码合入 main
rebase 完成后,feature 的代码还在 feature 分支上,要合入 main 有两种方式:
方式一:Pull Request / Merge Request(推荐)
text
git push --force-with-lease origin feature
↓
在 GitHub/GitLab 上创建 PR:feature → main
↓
代码审查 → 通过 → 合并
↓
此时 origin/main 才有 feature 的代码这是团队协作的标准流程,rebase 后提 PR,在平台上完成合并。
方式二:本地合并后推送
bash
# 1. rebase 完成,feature 已是最新
git push --force-with-lease origin feature
# 2. 切到 main
git checkout main
# 3. 拉取最新 main
git pull origin main
# 4. 合并 feature 到 main(因为 rebase 过,这里是 fast-forward 合并)
git merge feature
# 5. 推送 main
git push origin main
# 此时 origin/main 才有 feature 的代码因为 rebase 后 feature 的提交都在 main 最新提交之后,所以 git merge feature 会是 fast-forward 合并,不会产生合并提交,历史完全线性:
text
合并前: 合并后(fast-forward):
C'--D' feature A---B---E---C'---D' main, feature
/
A---B---E main完整流程图
text
git rebase origin/main
│
│ feature 的提交被重放到 origin/main 之后
│ origin/main 不变
▼
git push --force-with-lease origin feature
│
│ 远程 feature 分支更新
│ origin/main 依然不变
▼
┌────┴────┐
│ │
▼ ▼
PR合并 本地合并
│ │
│ git checkout main
│ git pull origin main
│ git merge feature
│ git push origin main
│ │
└────┬────┘
│
▼
origin/main 包含 feature 的代码rebase 是"准备"工作,让 feature 的提交历史干净地接在 main 后面;合并才是"交付"工作,把代码真正合入 main。
merge
git merge 是 Git 中用于将多个分支的内容合并到一个分支的操作。它是团队协作开发中处理分支合并的核心命令之一。
1. 基本概念
git merge的作用:将另一个分支的更改整合到当前分支。- 合并的前提:必须在某个分支上运行
git merge命令,目标是将另一个分支的更改合并到当前分支。
2. 参数说明
| 参数 | 说明 | 是否产生合并提交 |
|---|---|---|
| (无参数) | 默认行为:能快进则快进,不能快进则三方合并 | 视情况 |
--ff | 允许快进合并(与默认行为一致) | 视情况 |
--no-ff | 禁用快进合并,始终创建合并提交 | ✅ |
--ff-only | 只允许快进合并,不能快进则报错拒绝 | ❌ |
--squash | 将所有提交压缩到工作区,不自动提交,需手动 git commit | ❌ |
--abort | 取消正在进行的合并,恢复合并前状态 | — |
--continue | 冲突解决后继续完成合并 | — |
--commit | 合并成功后自动提交(默认行为) | — |
--no-commit | 执行合并但不自动提交,便于检查合并结果 | — |
-m <msg> | 指定合并提交的信息 | — |
--stat | 合并完成后显示差异统计 | — |
--no-stat | 合并完成后不显示差异统计 | — |
3. 合并的基本步骤
a. 切换到目标分支(合并到哪个分支):
bash
git checkout TARGET_BRANCH
# 或者更常用的方式:
git switch TARGET_BRANCHb. 执行合并:
bash
# 将 SOURCE_BRANCH 的更改合并到 TARGET_BRANCH
git merge SOURCE_BRANCHc. 解决冲突(如有):
- 如果合并过程中有冲突,Git 会提示哪些文件有冲突。
- 手动编辑冲突的文件,解决冲突后执行:
bash
git add CONFLICTED_FILE
git commit4. 合并模式
git merge 主要有两种模式:快进合并(Fast-Forward)和 三方合并(3-Way Merge)。
快进合并 (Fast-Forward Merge)
当目标分支没有新的提交时,Git 直接将目标分支指针移动到源分支的最新提交。有时,为了保持主分支的线性历史,主分支合并其他分支前,会将其他分支进行变基(rebase)操作,为的就是主分支可以快进合并其他分支。
三方合并 (3-Way Merge)
当两个分支都有新的提交时,Git 会创建一个新的合并提交。有时,为了更好的分支可视化,合并时就算分支没有新的提交或冲突,也需要保留一个合并提交。--no-ff 参数可以实现这一点。
--no-ff:
| 优点 | 说明 |
|---|---|
| 保留分支拓扑 | 即使可以快进合并,也强制创建合并提交,能清晰看到分支的创建、合并点 |
| 便于整体回退 | 可通过 git revert -m 1 MERGE_COMMIT 一次性回退整个分支的合并 |
| 历史更可读 | 合并提交记录了"何时合并了一个分支",而非将分支提交"摊平"到主线上 |
对比示意:
text
# 默认快进合并(ff):提交历史呈一条直线,看不出分支存在过(merge feature分支时,main还在c版本,feature的d、e版本会快进合并到main分支)
# 当两个分支已经分叉(main 和 feature 各有新提交),无论有没有冲突,和 git merge --no-ff feature 产生的结果是一样的————都会创建一个有两个父节点的合并提交。
A---B---C---D---E (main)
# --no-ff 合并:保留分支合并节点,就算没有F提交,也会产生合并提交G。
# --no-ff 的作用仅是阻止快进合并。当快进不可能发生时(分叉、冲突),它和ff或无参的行为完全一致,产生的合并提交在历史上没有区别.
A---B---C---F---G (main)
\ /
D---E (feature)⚠️ 注意: 如果是同步上游更新(如
git merge origin/main到本地 main),快进合并是合理的,无需--no-ff。--no-ff主要用于合并 feature/fix 等功能分支。 合并方式无所谓优劣,根据实际情况选择合适的合并策略。
5. 工作流模式与合并策略
| 工作流模式 | 推荐策略 | 命令示例 | 原因 |
|---|---|---|---|
| 个人开发,追求线性历史 | rebase + --ff-only | git rebase main → git merge --ff-only dev | 历史干净无噪音,无合并节点,bisect 友好 |
| 团队协作,feature 分支合并 | --no-ff | git merge --no-ff feature | 保留分支边界,便于整体回退和审计 |
| 同步上游更新 | 默认(--ff) | git merge origin/main | 快进即可,无需合并提交 |
| 不关心提交粒度,压成一个提交 | --squash | git merge --squash dev → git commit | 历史简洁,但丢失分支提交细节 |
| 紧急修复,直接合入主线 | --no-ff | git merge --no-ff hotfix | 保留修复的合并记录,便于追溯 |
6. 示例
如果主分支追求线性历史,各功能开发必须有功能分支(如feature-x),合并到main分支后关闭功能分支。
bash
git checkout feature-x
# 所有更改都已提交, 先巩固成果,同步到上游分支
git push origin feature-x
# 变基到main分支,保持线性历史
git rebase main
git switch main
# 合并feature-x分支到main分支,由于feature-x分支已经变基到main分支,一般都是可以快进合并,--ff-only保险不会产生合并提交
git merge --ff-only feature-x
git push origin main
# 删除功能分支,一般合并完成后不需要保留功能分支
git branch -d feature-x
# 如果远程分支也不保留
git push origin --delete feature-x功能分支rebase并合并到主分支后一般是不保留的,如果需要开发其他功能,一般基于主分支最新版本创建新的功能分支。如果懒得新增分支操作,或者是自己维护的长期分支(多人维护的分支不建议变基,会改变历史,影响协作者),想继续在分支上开发,因为此时本地feature-x已变基,推送上游分支会失败的,推荐
git push --force-with-lease同步到远程分支。
如果主分支追求提交历史好追溯,那么合并分支时建议强制保留一个合并提交较好。假设在dev阶段性开发完毕后,需要合并到main分支。推荐步骤如下:
bash
# 1. 确保当前在 dev 分支,提交所有改动
git add .
git commit -m "你的提交信息"
# 2. 先 push dev 到远程(保存工作成果)
git push origin dev
# 3. 切换到 main 分支
git checkout main
# 4. 拉取远程 main 最新代码
git pull origin main
# 5. 合并 dev 到 main(推荐 --no-ff),保留分支交叉历史
git merge --no-ff dev
# 6. 推送 main 到远程
git push origin main如果你不希望 dev 上的零碎提交出现在 main 上,用 squash 合并(main分支会丢失 dev 分支的提交历史,丢失贡献痕迹)
bash
git push origin dev
git checkout main
git pull origin main
# --squash会将dev分支的提交压缩到工作区,不自动提交,需手动 `git commit`
git merge --squash dev
git commit -m "feat: 合并 dev 分支改动"
git push origin maincherry-pick
1. 用法
bash
git cherry-pick COMMIT_HASH2. 提交多个hash
bash
git cherry-pick START_COMMIT_HASH^..END_COMMIT_HASHSTART_COMMIT_HASH是起始提交的哈希值。END_COMMIT_HASH是结束提交的哈希值。
3. cherry-pick 选项
| 选项 | 说明 |
|---|---|
-e | 编辑提交信息 |
-n | 不自动提交 |
-x | 在提交信息中记录来源 |
bash
git cherry-pick -e COMMIT_HASH
git cherry-pick -n COMMIT_HASH
git cherry-pick -x COMMIT_HASHrevert
git revert 用于撤销某次提交的更改,方式是创建一个新的提交来抵消目标提交的修改。与 git reset 不同,git revert 不会修改提交历史,是撤销已推送提交的安全方式。
1. 基本用法
bash
# 撤销指定提交,生成一个新的撤销提交
git revert COMMIT_HASH
# 撤销最近一次提交
git revert HEAD
# 撤销多个提交(按顺序逐个撤销)
git revert COMMIT_HASH_1 COMMIT_HASH_2
# 撤销一个范围的提交(不包含 START,包含 END)
git revert START..END2. 常用选项
| 选项 | 说明 | 示例 |
|---|---|---|
--no-edit | 使用默认撤销提交信息,不打开编辑器 | git revert --no-edit HEAD |
-e / --edit | 打开编辑器修改撤销提交信息(默认行为) | git revert -e HEAD |
-n / --no-commit | 撤销更改但不自动提交,可合并多次撤销后一起提交 | git revert -n COMMIT_HASH |
--continue | 冲突解决后继续撤销操作 | git revert --continue |
--abort | 取消整个撤销操作 | git revert --abort |
--skip | 跳过当前提交 | git revert --skip |
3. 撤销合并提交
合并提交有两个父提交,撤销时需要指定保留哪个父提交的历史:
bash
# 撤销合并提交,保留主分支(第 1 个父提交)的历史
git revert -m 1 MERGE_COMMIT_HASH-m 1:保留合并到的分支(如 main)的历史,撤销被合并分支(如 feature)的更改-m 2:保留被合并分支的历史,撤销合并到的分支的更改
4. revert vs reset 对比
| 对比项 | git revert | git reset |
|---|---|---|
| 撤销方式 | 创建新提交来抵消更改 | 直接移动分支指针,丢弃提交 |
| 是否修改提交历史 | ❌ 不修改 | ✅ 修改(重写历史) |
| 是否安全用于已推送分支 | ✅ 安全 | ❌ 危险,会导致他人历史不一致 |
| 适用场景 | 撤销已推送到远程的提交 | 撤销本地未推送的提交 |
| 操作可逆性 | 可逆(可以 revert 这个 revert) | 不可逆(提交被丢弃后难以恢复) |
⚠️ 黄金法则:对于已经推送到远程仓库的提交,始终使用
git revert而非git reset。git reset会重写历史,在多人协作中会导致严重问题。
reset
git reset 用于将当前分支的 HEAD 指针移动到指定提交,同时可以选择如何处理暂存区和工作区。它是撤销本地提交的常用命令,但会重写提交历史,不应用于已推送的提交。
1. 三种模式
git reset 的核心区别在于对暂存区(index)和工作区(working directory)的处理方式:
| 模式 | HEAD | 暂存区 | 工作区 | 说明 |
|---|---|---|---|---|
--soft | 移动 | 不变 | 不变 | 仅移动 HEAD,提交的更改保留在暂存区,可重新提交 |
--mixed(默认) | 移动 | 重置 | 不变 | 移动 HEAD 并重置暂存区,更改退回工作区(未暂存状态) |
--hard | 移动 | 重置 | 重置 | 移动 HEAD 并重置暂存区和工作区,所有更改丢失 |
图示:
text
--soft: HEAD → 目标提交 | 暂存区保留更改 | 工作区不变
--mixed: HEAD → 目标提交 | 暂存区重置 | 工作区保留更改
--hard: HEAD → 目标提交 | 暂存区重置 | 工作区重置(更改丢失!)2. 基本用法
bash
# 默认 --mixed 模式:撤销提交,更改退回工作区
git reset COMMIT_HASH
# --soft:撤销提交,更改保留在暂存区
git reset --soft COMMIT_HASH
# --hard:撤销提交,所有更改丢弃
git reset --hard COMMIT_HASH3. 常用场景
撤销最近一次提交(保留更改)
bash
# 撤销最近一次提交,更改保留在暂存区,可修改后重新提交
git reset --soft HEAD~1
# 撤销最近一次提交,更改退回工作区(未暂存状态)
git reset HEAD~1撤销最近 N 次提交
bash
# 撤销最近 3 次提交,更改保留在暂存区
git reset --soft HEAD~3丢弃所有本地更改
bash
# 重置到远程分支的状态,丢弃所有本地修改
git fetch origin
git reset --hard origin/main清空暂存区(取消 git add)
bash
# 将所有已暂存的文件退回工作区
git reset
# 将指定文件退回工作区
git reset FILE4. HEAD~n 说明
| 写法 | 说明 |
|---|---|
HEAD | 当前提交 |
HEAD~1 / HEAD^ | 当前提交的上一个提交 |
HEAD~2 | 当前提交往前第 2 个提交 |
HEAD~n | 当前提交往前第 n 个提交 |
5. 找回丢失的提交
git reset --hard 后提交似乎丢失了,但 Git 内部仍保留了一段时间的引用,可以通过以下方式找回:
bash
# 查看所有操作记录,找到丢失提交的哈希
git reflog
# 恢复到指定提交
git reset --hard COMMIT_HASH⚠️ 注意:
git reflog的记录有有效期(默认 90 天),过期后引用可能被垃圾回收清除,无法恢复。
6. reset 使用建议
| 场景 | 推荐命令 | 说明 |
|---|---|---|
| 撤销本地提交,想修改提交信息 | git reset --soft HEAD~1 | 更改保留在暂存区,直接重新 git commit |
| 撤销本地提交,想重新整理更改 | git reset HEAD~1 | 更改退回工作区,重新选择暂存 |
| 丢弃所有本地更改,恢复到远程状态 | git reset --hard origin/main | ⚠️ 不可恢复,谨慎使用 |
| 已推送的提交需要撤销 | 使用 git revert | reset 会重写历史,影响协作者 |
rm
1. 何时使用 rm
git rm 用于从 Git 版本库中移除文件的跟踪。与直接在文件管理器中删除文件不同,git rm 会同时从暂存区和工作区中删除文件,并将该删除操作记录为一次待提交的更改。
| 场景 | 推荐操作 | 说明 |
|---|---|---|
| 确定不再需要某文件,从项目中彻底删除 | git rm FILE | 从版本库和工作区同时删除,删除会进入暂存区 |
| 停止跟踪某文件,但保留本地文件 | git rm --cached FILE | 从版本库中移除跟踪,工作区文件保留(常用于 .gitignore 补救) |
| 误将敏感文件(密码、密钥)提交到仓库 | git rm --cached FILE + 提交 + 加入 .gitignore | 从版本库移除跟踪,防止后续推送泄露 |
⚠️ 注意: 直接用系统命令(如
del或在资源管理器中删除)删除文件,Git 不会自动将删除操作加入暂存区,需要再手动执行git add FILE或git rm FILE才能将删除纳入提交。使用git rm一步到位。
2. 常用操作
bash
git rm FILE2. 选项详解
| 选项 | 说明 |
|---|---|
--cached | 仅从版本库中删除,保留工作区文件 |
bash
git rm --cached FILE3. 注意事项
恢复已删除的文件:
bash
git checkout COMMIT_HASH -- file.txttag
1. 查看现有标签
bash
git tag2. 创建附注标签
bash
git tag -a TAG_NAME -m "MESSAGE"3. 给特定的提交打标签
bash
git tag TAG_NAME COMMIT_HASH4. 推送标签到远程仓库
bash
git push origin TAG_NAME5. 删除标签
bash
git tag -d TAG_NAME
git push origin --delete TAG_NAME6. 检查标签详细信息
bash
git show TAG_NAME7. 拉取标签
8. 拉取标签和代码的区别
9. 检出到某个标签
bash
git checkout TAG_NAME
git checkout -b NEW_BRANCH_NAMElog
git log 用于查看提交历史记录,是 Git 中最常用的审查命令之一。
1. 基本用法
bash
git log2. 参数详解
git log [options]
| 参数 | 说明 | 示例 |
|---|---|---|
| (无参数) | 显示完整提交历史 | git log |
-n / -[n] | 限制显示最近 n 条提交 | git log -5 |
--oneline | 每条提交压缩为一行(哈希+信息) | git log --oneline |
--all | 显示所有分支的提交历史 | git log --all |
--graph | 以 ASCII 图形显示分支与合并历史 | git log --graph |
--decorate | 显示引用(分支、标签)指向的提交 | git log --decorate |
-p / -u | 显示每条提交的完整 diff | git log -p |
--stat | 显示每条提交的文件变更统计(增删行数) | git log --stat |
--shortstat | 仅显示每条提交的增删行数汇总 | git log --shortstat |
--name-only | 仅显示每条提交变更的文件名 | git log --name-only |
--name-status | 显示变更文件名及状态(A/M/D) | git log --name-status |
--author=<pattern> | 按作者筛选(支持正则) | git log --author="Alice" |
--committer=<pattern> | 按提交者筛选 | git log --committer="Bob" |
--grep=<pattern> | 按提交信息筛选(支持正则) | git log --grep="feat" |
-i / --regexp-ignore-case | 配合 --author/--grep 忽略大小写 | git log --grep="fix" -i |
--since=<date> | 显示指定日期之后的提交 | git log --since="2026-01-01" |
--after=<date> | 同 --since | git log --after="2026-01-01" |
--until=<date> | 显示指定日期之前的提交 | git log --until="2026-06-01" |
--before=<date> | 同 --until | git log --before="2026-06-01" |
-- <path> | 仅显示涉及指定路径/文件的提交 | git log -- src/main.py |
-L <start>,<end>:<file> | 显示文件指定行范围的演变历史 | git log -L 10,20:main.py |
--follow | 跟踪文件重命名历史(需配合路径) | git log --follow -- README.md |
--no-merges | 不显示合并提交 | git log --no-merges |
--merges | 仅显示合并提交 | git log --merges |
--first-parent | 仅沿第一父提交链显示(忽略分支侧) | git log --first-parent |
--reverse | 按时间正序显示(最早的在前) | git log --reverse |
--abbrev-commit | 缩短提交哈希值 | git log --abbrev-commit |
--relative-date | 以相对时间显示日期(如 "2 days ago") | git log --relative-date |
--show-signature | 显示 GPG 签名验证结果 | git log --show-signature |
--diff-filter=<type> | 按变更类型筛选(A=新增, M=修改, D=删除) | git log --diff-filter=M |
--format=<fmt> / --pretty=<fmt> | 自定义输出格式 | git log --format="%h %s" |
3. 自定义格式占位符
--format / --pretty 支持的常用占位符:
| 占位符 | 说明 |
|---|---|
%H | 完整提交哈希 |
%h | 缩短提交哈希 |
%T | 完整树哈希 |
%t | 缩短树哈希 |
%an | 作者名字 |
%ae | 作者邮箱 |
%cn | 提交者名字 |
%ce | 提交者邮箱 |
%ad | 作者日期 |
%cd | 提交者日期 |
%ar | 作者相对日期 |
%cr | 提交者相对日期 |
%s | 提交信息(首行) |
%b | 提交信息(正文) |
%d | 引用装饰(分支、标签) |
%n | 换行 |
4. 范围查询
| 用法 | 说明 | 示例 |
|---|---|---|
<since>..<until> | 显示从 since 到 until 之间的提交 | git log main..dev |
<branch1>...<branch2> | 显示两分支各自的独有提交 | git log main...dev |
^<commit> | 排除指定提交及其祖先 | git log ^main dev |
-L :<func>:<file> | 显示函数的演变历史 | git log -L :main:app.py |
5. 常用组合
bash
git log --oneline --graph --all --decorate
# 经典可视化:所有分支、图形化、一行式、带标签
git log --oneline -10
# 最近 10 条提交,一行式
git log --since="1 week ago" --oneline --author="Alice"
# Alice 最近一周的提交
git log --grep="feat" --oneline
# 提交信息包含 "feat" 的提交
git log --stat -5
# 最近 5 条提交的文件变更统计
git log --format="%h - %an, %ar : %s"
# 自定义格式:短哈希 - 作者, 相对时间 : 提交信息
git log main..feature/login --oneline
# feature/login 有而 main 没有的提交(即将合并的内容)
git log -p -- src/main.py
# 查看 main.py 的完整变更历史及 diff💡 实用技巧:
git log --oneline --graph --all --decorate是最常用的可视化组合,建议设为别名:git config --global alias.lg "log --oneline --graph --all --decorate"git log branch1..branch2可查看 branch2 相对 branch1 的新提交,常用于合并前审查- 配合
--since/--until可快速定位时间段内的变更-L参数(行范围追踪)是排查某段代码演变历史的利器
团队协作工作流
1. Centralized Workflow(集中式工作流)
最简单的工作流,所有人在同一分支(通常是 main)上直接提交。
text
main
A --- B --- C --- D --- E
↑ ↑ ↑ ↑
Alice Bob Alice Carol流程:
bash
# 每个人在 main 上直接工作
git pull origin main
# 编写代码...
git add . && git commit -m "feat: 新功能"
git pull origin main # 推送前先拉取最新
git push origin main特点:
| 优点 | 缺点 |
|---|---|
| 简单易上手,无需分支管理 | 冲突频繁,互相阻塞 |
| 适合小团队 | 无法并行开发多个功能 |
| 适合持续部署的小项目 | main 不稳定,随时可能被破坏 |
适用场景: 2-3 人的小团队、个人项目、内部工具
2. Feature Branch Workflow(功能分支工作流)
每个功能/修复在独立分支上开发,通过 Pull Request/Merge Request 合入主分支。
text
main
A --- B --- C --------- F --------- I
\ \ \
D --- E G --- H J --- K
feature/a feature/b feature/c流程:
bash
# 1. 从 main 创建功能分支
git checkout -b feature/login main
# 2. 在功能分支上开发
git add . && git commit -m "feat: 实现登录页面"
git add . && git commit -m "feat: 添加表单验证"
# 3. 同步 main 最新代码(推荐 rebase)
git fetch origin main
git rebase origin/main
# 4. 推送功能分支
git push -u origin feature/login
# 5. 在 GitHub/GitLab 上创建 Pull Request
# → 代码审查 → 通过 → 合并到 main
# 6. 合并后删除功能分支
git checkout main
git pull origin main
git branch -d feature/login
git push origin --delete feature/login特点:
| 优点 | 缺点 |
|---|---|
| main 始终稳定 | 分支管理成本略高 |
| 支持代码审查(PR) | 需要平台支持(GitHub/GitLab) |
| 功能隔离,冲突减少 | — |
| 支持并行开发 | — |
适用场景: 中小团队、需要代码审查的项目
💡 提示:这是目前最主流的工作流,GitHub、GitLab、Bitbucket 均原生支持。
3. GitFlow 工作流
Vincent Driessen 提出的经典分支模型,使用两类分支(长期分支 + 短期分支)管理项目的完整生命周期。
分支结构:
| 分支类型 | 分支名 | 生命周期 | 说明 |
|---|---|---|---|
| 长期分支 | main | 永久 | 生产环境代码,每个提交都是一个可发布版本 |
| 长期分支 | develop | 永久 | 开发集成分支,包含下一个版本的所有功能 |
| 短期分支 | feature/* | 功能完成后删除 | 从 develop 创建,合并回 develop |
| 短期分支 | release/* | 发布完成后删除 | 从 develop 创建,合并回 main 和 develop |
| 短期分支 | hotfix/* | 修复完成后删除 | 从 main 创建,合并回 main 和 develop |
text
main
A ---------------------------------------- M --- N
\ / \
develop D --- E --- F --- G --- H --- L --- O
/ / / /
feature/a feature/b release/1.1 hotfix/xxx
C --- D' F'--- G' I --- J K流程:
日常功能开发
bash
# 1. 从 develop 创建功能分支
git checkout -b feature/user-profile develop
# 2. 开发并提交
git add . && git commit -m "feat: 用户个人资料页面"
# 3. 完成后合并回 develop
git checkout develop
git merge --no-ff feature/user-profile
git branch -d feature/user-profile准备发布
bash
# 1. 从 develop 创建发布分支
git checkout -b release/1.2.0 develop
# 2. 在发布分支上修复 bug、更新版本号(不再接受新功能)
git add . && git commit -m "fix: 修复发布前发现的 bug"
# 3. 发布:合并到 main 和 develop
git checkout main
git merge --no-ff release/1.2.0
git tag -a v1.2.0 -m "Release 1.2.0"
git checkout develop
git merge --no-ff release/1.2.0
git branch -d release/1.2.0紧急修复
bash
# 1. 从 main 创建热修复分支
git checkout -b hotfix/critical-bug main
# 2. 修复并提交
git add . && git commit -m "fix: 修复生产环境严重 bug"
# 3. 合并到 main 和 develop
git checkout main
git merge --no-ff hotfix/critical-bug
git tag -a v1.2.1 -m "Hotfix 1.2.1"
git checkout develop
git merge --no-ff hotfix/critical-bug
git branch -d hotfix/critical-bug特点:
| 优点 | 缺点 |
|---|---|
| 分支职责清晰,各司其职 | 分支模型复杂,学习成本高 |
| main 始终对应生产环境 | 日常开发需在 develop 和 feature 间频繁切换 |
| 支持并行开发、发布和热修复 | release 分支与 develop 的双向合并容易遗漏 |
| 有明确的版本管理(tag) | 对持续部署项目过于笨重 |
适用场景: 有明确版本发布周期的项目、需要同时维护多个版本的项目
💡 提示:GitFlow 适合有计划发布(如每两周一个版本)的项目。如果项目采用持续部署,Trunk-Based 工作流更合适。
4. Trunk-Based Development(主干开发工作流)
所有人在 main(trunk)上频繁提交,功能通过 Feature Flag 控制可见性,不再依赖长期存在的功能分支。
text
main (trunk)
A --- B --- C --- D --- E --- F --- G
↑ ↑ ↑ ↑ ↑ ↑
Alice Bob Alice Carol Bob Alice短生命周期分支(可选):
text
main
A --- B --- C --------- F --- G
\ /
D --- E
feature/x (1-2天)流程:
bash
# 方式一:直接在 main 上提交(最简单)
git pull origin main
# 编写代码,用 Feature Flag 包裹新功能
git add . && git commit -m "feat: 新功能(flag: NEW_LOGIN)"
git push origin main
# 方式二:使用短生命周期分支(1-2天)
git checkout -b feature/quick-fix main
git add . && git commit -m "fix: 快速修复"
git push -u origin feature/quick-fix
# 创建 PR → 审查 → 合并(分支存活不超过 1-2 天)Feature Flag 示例:
python
# 新功能用 flag 包裹,合并到 main 但不影响生产
if feature_flag.is_enabled("NEW_LOGIN"):
return new_login_flow()
else:
return old_login_flow()特点:
| 优点 | 缺点 |
|---|---|
| 历史始终线性,简单清晰 | 需要 Feature Flag 基础设施支持 |
| 强制小批量、频繁集成 | 代码审查必须快速(否则阻塞所有人) |
| 与 CI/CD 完美契合 | 未完成功能进入 main,需 flag 控制风险 |
| 无分支管理开销 | 对团队纪律性要求高 |
适用场景: 持续部署/持续交付的项目、高成熟度团队、微服务架构
💡 提示:Google、Facebook 等大厂普遍采用此工作流。关键前提是完善的 CI 流水线和 Feature Flag 系统。
工作流对比
| 特性 | 集中式 | Feature Branch | GitFlow | Trunk-Based |
|---|---|---|---|---|
| 分支复杂度 | 最低 | 低 | 高 | 最低 |
| main 稳定性 | ❌ 低 | ✅ 高 | ✅ 高 | ⚠️ 中(依赖 flag) |
| 代码审查 | ❌ 无 | ✅ PR | ✅ PR | ✅ PR(快速) |
| 并行开发 | ❌ 不支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 |
| 发布管理 | ❌ 无 | 手动 | ✅ 规范 | ✅ 持续部署 |
| 热修复流程 | ❌ 混乱 | 手动 | ✅ 规范 | ✅ 直接提交 |
| CI/CD 契合度 | 低 | 中 | 低 | ✅ 最高 |
| 团队规模 | 2-3人 | 5-20人 | 10-50人 | 不限 |
| 学习成本 | 最低 | 低 | 高 | 中 |
工作流选择建议
text
团队规模 + 发布方式 → 推荐工作流
2-3人,随意发布 → 集中式工作流
5-20人,需代码审查 → Feature Branch 工作流
10+人,有版本发布周期 → GitFlow 工作流
成熟团队,持续部署 → Trunk-Based 工作流