git merge vs git rebase
git merge 和 git rebase 是两种合并分支的主要策略,它们各有优劣。
git merge:- 优点: 忠实记录了分支的合并历史,不会破坏原分支的提交记录。
- 缺点: 每次合并都会产生一个额外的合并提交(merge commit),可能导致提交历史变得复杂、分支线交错。
git rebase(变基):- 优点: 会将当前分支的提交“变基”到目标分支的最新提交之后,形成一条线性的提交历史,使历史记录更简洁、直观。
- 缺点: 会改写提交历史。绝对不要在共享的公共分支(如
master,develop)上执行rebase,这会给协作者带来巨大的麻烦。
使用场景
git merge: 用于将功能分支合并到公共分支(如develop或master)时。保留合并记录有助于代码审查和追溯。git rebase: 用于在个人开发分支上同步主分支的最新代码时。可以保持个人分支的提交历史干净。
rebase 后的 push 问题
当你对一个已经推送到远程的分支执行 rebase 后,本地分支的历史记录被改写,与远程分支产生分歧。此时直接 git push 会失败。
如果确认该分支只有你一个人在开发,可以使用强制推送来更新远程分支:
shell
git push --force-with-lease origin <branch-name>
# 或者更危险的
<NolebasePageProperties />
git push --force origin <branch-name>注意:
--force会强制覆盖远程分支,可能导致他人提交丢失。--force-with-lease相对安全,它只在远程分支没有新的提交时才强制推送。
git switch 和 git restore
git checkout 命令功能过于庞杂(切换分支、恢复文件等),因此社区引入了 switch 和 restore 使职责更清晰。
git switch: 专注于分支切换。shell# 切换到已有分支 git switch main # 创建并切换到新分支 git switch -c new_branch # 切换到某个 commit(分离头指针状态) git switch -d f8c5408git restore: 专注于文件恢复。shell# 恢复工作区的文件,撤销未暂存的修改 git restore test.txt # 从暂存区恢复文件到工作区(unstage) git restore --staged test.txt
git revert 和 git reset
git revert <commit-id>: 创建一个新的提交,用于撤销某次指定提交的更改。原有的提交历史得以保留,是一种安全的回退方式。git reset <commit-id>: 将HEAD指针回退到指定的提交,其后的提交将从历史记录中移除(取决于模式)。这是一种破坏性的操作。
| 特性 | git reset | git revert |
|---|---|---|
| 效果 | 指针后移,丢弃或重置后续提交 | 新增提交,抵消某个历史提交 |
| 历史记录 | 修改历史记录(破坏性) | 不修改历史记录(非破坏性) |
| 协作 | 只能在私有分支使用 | 可以在公共分支使用 |
| 安全性 | 较低,可能丢失工作 | 较高,所有操作都有记录 |
reset 的三种模式
git reset --soft <commit-id>: 仅移动HEAD指针。回退后的变更会保留在暂存区(Staged)。git reset --mixed <commit-id>(默认): 移动HEAD指针,并重置暂存区。回退后的变更会保留在工作区(Unstaged)。git reset --hard <commit-id>: 移动HEAD指针,并重置暂存区和工作区。回退后的变更会彻底丢失,请谨慎使用!
git tag
git tag 用于为项目历史中的某个特定节点(通常是版本发布点)创建一个语义化的别名。
shell
# 创建一个带附注的标签
git tag -a v1.0.0 -m "发布 1.0.0 版本"
# 为某个特定的 commit 打标签
git tag -a v0.9.0 <commit-id> -m "v0.9.0 版本"
# 推送所有本地标签到远程
git push --tags版本规范
推荐遵循 语义化版本 2.0.0 (SemVer) 规范。版本号格式为 主版本号.次版本号.修订号 (Major.Minor.Patch)。
git worktree
git worktree 允许你同时在同一个仓库中检出多个工作树(工作目录),对应不同的分支。这对于需要在不同分支间频繁切换、或同时进行多任务开发非常有用。
shell
# 在 ../my-hotfix 目录下创建一个链接到主仓库的 hotfix 分支工作区
git worktree add ../my-hotfix hotfix
# 查看所有工作区
git worktree list
# 清理无效的工作区引用
git worktree prune
# 移除工作区
git worktree remove ../my-hotfixGit Flow
Git Flow 是一种成熟的、基于分支的开发模型,它为不同类型的开发活动定义了专门的分支。

- 主分支:
master: 存放正式发布版本,代码永远是可部署的。develop: 日常开发的主分支,整合所有已完成的功能。
- 辅助分支:
feature/*: 开发新功能的分支,基于develop创建,完成后合并回develop。release/*: 准备发布新版本的分支,用于修复 Bug 和准备元数据。基于develop创建,完成后合并到master和develop。hotfix/*: 修复线上紧急 Bug 的分支,基于master创建,完成后合并到master和develop。
常见问题
.gitignore 不生效
.gitignore 文件只能忽略那些从未被 Git 跟踪(track)过的文件。如果文件已经被纳入版本管理,修改 .gitignore 是无效的。
解决方法:从 Git 的暂存区中移除该文件,然后重新提交。
shell
# 递归地移除所有文件的缓存
git rm -r --cached .
# 重新添加所有文件(此时 .gitignore 会生效)
git add .
# 提交更改
git commit -m "Fix .gitignore tracking"修改已提交的 commit message
shell
# 查看最近的提交历史,找到要修改的 commit 的父 commit ID
git log --oneline
# 进入交互式 rebase 界面
git rebase -i <parent-commit-id>
# 在编辑器中,将要修改的 commit 前的 `pick` 改为 `reword` (或 `r`)
# 保存并退出,Git 会弹出新的编辑器让你修改 commit messagegit status 显示中文乱码
shell
git config --global core.quotepath false参考
- 【Git】 什么!?都快 2023 年了还搞不清楚 git rebase 与 git merge
- 如何利用 Git 中的 tag 管理项目版本号
- A successful Git branching model
- Git、GitHub、GitLab Flow,傻傻分不清?一图看懂各种分支管理模型
- Git不要只会pull和push,试试这5条提高效率的命令
- 一文彻底搞清git reset和revert区别