分支管理(一):创建、切换与合并,体验“平行宇宙” 1. 问题场景假设你正在开发一个新功能预计要花两周时间。在这个过程中代码每天都处于“半成品”状态——功能没写完运行不起来甚至可能把现有功能搞崩。如果你直接在主分支master上开发这些不完整的提交会污染整个项目历史还可能影响其他同事的工作。但你又需要每天保存进度不能等两周后才一次性提交。解决这个矛盾的答案就是分支。你可以在一个独立的分支上自由实验、随时提交完全不影响主分支的稳定性。等功能开发完成且测试通过再把分支上的工作合并回主分支。这就像在“平行宇宙”里工作互不干扰随时可以汇合。2. 核心概念2.1 什么是分支在 Git 里分支仅仅是一个指向某个提交对象的可移动指针。创建一个新分支其实就是创建了一个新的指针让你可以在当前工作基础上分叉出一条独立的开发线。不同分支上的修改相互隔离直到你明确将它们合并。2.2 HEAD 指针HEAD是一个特殊的指针它始终指向你当前正在工作的分支或者说当前分支的最新提交。当你切换分支时HEAD也会跟着移动。2.3 为什么 Git 分支如此轻量有些老旧的版本控制系统创建分支时需要完整拷贝一份代码非常缓慢。Git 的分支只包含一个指针和极少量的元数据创建和切换几乎瞬间完成。这也是 Git 强烈鼓励分支策略的原因——你可以毫无心理负担地为每一个小功能、每一次 Bug 修复新建分支。3. 核心命令以下是分支管理最基础的一组命令先整体列出后面会逐个演示。# 查看所有本地分支当前分支前会有 * 号gitbranch# 创建一个新分支但不会切换过去gitbranchbranch_name# 切换到指定分支gitcheckoutbranch_name# 创建并切换到新分支常用组合gitcheckout-bbranch_name# 将指定分支合并到当前所在分支gitmergebranch_name# 删除指定分支gitbranch-dbranch_name4. 实战演示继续使用之前的myproject仓库或者创建一个全新的仓库来练习。假设当前只有 master 分支上面已经有一些提交记录。4.1 查看分支$gitbranch * master输出显示只有一个master分支前面的*表示当前HEAD指向它也就是你正在这个分支上工作。4.2 创建并切换到新分支假设你要开发一个支付功能需要创建一个专门的分支$gitcheckout-bfeature-payment Switched to a new branchfeature-payment这个命令等价于git branch feature-payment再git checkout feature-payment一步到位。再查看一下分支列表$gitbranch * feature-payment master当前分支已经切换到feature-payment。4.3 在新分支上开发和提交现在开始“开发新功能”。往ReadMe文件里添加一行标记性内容并提交$echoImplement payment moduleReadMe $gitaddReadMe $gitcommit-mstart payment module development[feature-payment a2b3c4d]start payment module development1filechanged,1insertion()这个提交记录到了feature-payment分支上对 master 分支毫无影响。4.4 切换回 master 分支现在回到 master 分支看看$gitcheckout master Switched to branchmaster查看ReadMe文件的内容$catReadMe# 没有 Implement payment module 这一行新功能分支上的那行内容消失了因为 master 分支的指针还停留在原来的提交点没有包含支付分支上的修改。此时git log也看不到那条start payment module development的提交除非你显式查看feature-payment分支的日志。4.5 合并分支支付功能已经开发完成需要把它合并回主分支。确保你在 master 分支上然后执行合并$gitmerge feature-payment Updating 14c12c3..a2b3c4d Fast-forward ReadMe|11filechanged,1insertion()Git 提示采用了Fast-forward模式。这是因为 master 分支在分离之后没有产生新的提交Git 只需要将 master 的指针直接“快进”到feature-payment指向的提交即可无需额外的合并提交。合并后 master 分支就包含了支付功能的代码ReadMe文件里那行内容也回来了。4.6 删除分支功能已经合并feature-payment分支不再需要了可以删掉以保持分支列表的整洁$gitbranch-dfeature-payment Deleted branch feature-payment(was a2b3c4d).此时git branch只会显示master。注意被删除的分支只是在本地被移除如果已经推送到远程仓库还需要额外的步骤删除远程分支后面文章会讲。5. 分支策略建议在实际项目中直接在主分支master上开发是大忌。一个常用的策略是master 分支始终保持稳定只用来发布正式版本。任何人不直接在 master 上提交。dev 分支开发集成分支日常开发的工作都在这个分支或其衍生分支上进行。个人功能分支每个新功能、每个 Bug 修复都从 dev 分支上拉出一个独立的分支。开发完成后合并回 dev再删除该功能分支。这种层级结构让项目历史清晰可追溯也最大程度降低了多人协作时的冲突概率。6. 注意事项分支的创建和切换非常轻量不要怕多建分支。即使是一个极小的改动也可以单独建分支这样如果发现方向不对直接删掉分支即可主分支完全不受影响。在合并分支之前建议先用git status确认当前处在正确的目标分支通常是 master 或 dev。很多人会把方向搞反把主分支合并到了功能分支上。如果删除分支时 Git 提示 “the branch is not fully merged”说明该分支上还有没有被合并到其他分支的提交。Git 是在保护你防止不小心丢失工作成果。如果确认那些提交确实没用了可以用git branch -D branch_name强制删除。7. 要点总结分支是 Git 的核心功能让你在隔离环境中自由开发不影响主线。git checkout -b name创建并切换分支是最常用的操作之一。git merge将分支上的工作合并到当前分支默认采用快进模式。合并完成且确认不再需要后应及时用git branch -d删除分支保持仓库整洁。养成良好的分支习惯为每个独立功能或修复都新建一个分支。8. 练习题一定要练习,玩起来,你可以随便玩,不需要局限于我举得例子,你想怎么搞就怎么搞,不要害怕搞坏了,只要你不用自己的真实项目,其他的,大不了把git删了重新下,搞起来,只有这样才学的扎实在你的learning-git仓库中创建一个feature-login分支并切换过去。在该分支上新建一个login.py文件写入一些模拟代码然后add和commit。切换回 master 分支确认login.py不存在。然后用git merge feature-login将其合并进来。合并成功后删除feature-login分支。尝试创建一个新分支temp并做一次提交然后不合并就直接用git branch -d temp删除它观察 Git 的警告信息。再用git branch -D temp强制删除。思考题如果 master 分支在feature-login创建之后又有了新的提交合并时还会是快进模式吗试着模拟并观察结果。