Git 基本操作
3 / 9
Git 服务器
自在学
首页课程创意工坊价格
首页课程创意工坊价格
编程GitGit 分支

Git 分支

在版本控制体系中,分支(Branch)是用于隔离开发任务的机制,能让多个开发线并行推进而互不干扰。每个分支基于同一代码基础,可独立进行新功能开发、缺陷修复或实验性尝试。 所有分支的演进过程可以有机整合,便于团队协作和代码管理,实现高效的并行开发和风险控制。

Git 分支的本质


分支的本质

在软件开发中,Git 的分支(Branching)就扮演着类似的角色。它几乎是所有现代版本控制系统都具备的功能,但 Git 却把它做到了极致,甚至被誉为“杀手锏”特性。为什么这么说呢? 因为在许多旧的工具里,创建一个分支通常意味着完整地复制一份项目代码,对于大型项目来说,这个过程既耗时又占空间,就像每次想尝试新想法都要把整个图书馆复印一遍一样笨重。

但 Git 的分支却格外轻盈。创建一个分支,几乎在瞬间就能完成,切换分支也同样迅捷。这得益于 Git 独特的内部设计。它并不存储文件的差异变化,而是为每一次提交(commit)制作一个“快照”(snapshot),记录下那一刻所有文件的样貌。 所以,一个分支,其本质不过是一个指向某个快照的可移动便签。当你创建一个新分支时,Git 只是新建了一张便签,贴在你当前所在的快照上。它并没有复制任何文件,因此速度飞快。

为了更好地理解这一点,我们需要认识一个特殊的朋友:HEAD。HEAD 并不是一个分支,它更像是一个永远跟着你的“当前位置”指示牌。你正在哪个分支上工作,HEAD 就指向哪个分支。通过这个指示牌,Git 才知道你的下一次提交应该发生在哪个“平行宇宙”里。 我们来看一个简单的例子。假设你正在主分支 master 上工作,这是 Git 默认创建的主分支。

此时,你的 master 分支和 HEAD 都指向最新的快照 C2。现在,你突然有了一个实验性的想法,比如想给网站换一个全新的配色方案。你不想在主线上直接动工,以免把事情搞砸。于是,你决定创建一个名为 feature-color 的新分支。

|
git branch feature-color

执行这个命令后,Git 只是创建了一张名为 feature-color 的新便签,并将它也贴在了 C2 这个快照上。你的工作目录里的文件没有任何变化,但你的“平行宇宙”已经悄然诞生。

注意,虽然新分支建好了,但你的 HEAD 指示牌仍然指向 master。这意味着你还在“主线剧情”里。要想真正进入新的平行宇宙开始探索,你需要“切换”过去。

|
git checkout feature-color

这条命令做了两件事:首先,它把 HEAD 指示牌从 master 移到了 feature-color 上。其次,它会检查并确保你的工作目录和新分支的最新快照保持一致(虽然眼下它们还是一样的)。现在,你已经成功穿越到了 feature-color 的时空。

接下来,你在这个分支上大展拳脚,修改了样式文件,并提交了一个新的快照 C3。

|
# 你修改了 style.css 文件 git add . git commit -m "尝试新的蓝色主题"

提交后,因为你的 HEAD 指向 feature-color,所以是 feature-color 这张便签向前移动到了新的 C3 快照上,而 master 便签仍然静静地待在 C2 的位置。

就在这时,你接到一个紧急电话:主线网站上有一个严重的 Bug 需要立刻修复!情况紧急,但你无需惊慌。 你那还在试验中的新配色方案位于完全隔离的 feature-color 分支中,因此你完全可以把它们先放在一边,回到主线去拯救世界。你只需要再次切换回 master 分支。

|
git checkout master

奇迹发生了。你的工作目录瞬间恢复到了 C2 快照的状态,所有关于新配色的修改都“消失”了。这并非真的消失,它们只是被安全地保管在 feature-color 分支里。Git 帮你打理好了一切,让你能心无旁骛地专注于眼前的紧急任务。

切换分支会改变你的工作目录文件,这是 Git 分支最直观也最强大的体现之一。它会自动添加、删除和修改文件,让你的工作区恢复到目标分支上一次提交时的样子。 如果切换时,你当前有未提交的修改,且这些修改和目标分支有冲突,Git 会非常贴心地阻止你切换,防止你的修改丢失。

回到 master 分支后,你迅速修复了 Bug,并提交了新的快照 C4。

现在,你的项目历史就出现了两条独立的故事线:一条是关于 feature-color 的探索,另一条是 master 上紧急修复的 Bug。它们互不干扰,各自发展。 这就是 Git 分支的魅力:它鼓励你为每一个新想法、新功能、甚至每一次 Bug 修复都创建一个短暂的分支。这让你的工作流程变得异常清晰和灵活。


合并

故事线分叉后,终有需要汇合的一天。当你完成了分支上的工作,并希望将这些成果融入主线时,就需要用到“合并”(Merge)操作。

Git 分支的合并

假设你在 master 分支上修复了紧急 Bug(C4),现在你想把这个修复也应用到你的 feature-color 分支中,确保新功能是基于修复后的代码。此时,你只需要切换到 feature-color 分支,然后执行合并命令:

|
git checkout feature-color git merge master

在这个例子中,feature-color 分支所基于的 C2 是 master 分支 C4 的直接祖先。Git 会发现,要完成这次合并,它只需要把 feature-color 分支的历史“快进”到 master 的最新状态。 这种合并被称为“快进式”(Fast-forward)。它非常简单,Git 只是移动了一下分支的便签,没有产生新的提交。

现在,我们来处理更常见的情况。你的新配色方案 (feature-color) 经过测试后大受好评,你决定将它正式发布到主网站。这意味着,你需要将 feature-color 分支合并回 master 分支。

|
git checkout master git merge feature-color

这次合并就没那么简单了。因为在你开发新功能的同时,master 分支也因为修复 Bug 向前推进了。两条分支的历史在 C2 之后出现了分叉。对于这种情况,Git 会执行一次“三方合并”(Three-way merge)。

它会找到三个关键的快照:

  1. 两条分支的共同祖先(C2)
  2. master 分支的最新快照(C4)
  3. feature-color 分支的最新快照(我们假设是 C5)

Git 会将这两条分叉的“故事线”的成果整合起来,创造出一个全新的快照(C6)。这个新的快照会自动包含一个特殊的提交信息,被称为“合并提交”(Merge commit),它的特殊之处在于它有两个父提交(C4 和 C5)。

合并完成后,feature-color 分支的使命就结束了。你可以像丢掉一张草稿纸一样把它删除,而它的所有成果都已经被永久地记录在了 master 主线中。

|
git branch -d feature-color

冲突

冲突

合并并非总是一帆风顺。想象一下,如果在修复紧急 Bug 时,你修改了 index.html 文件的某一行;而不幸的是,在开发新配色时,你也修改了 index.html 文件的同一行。 当 Git 尝试合并这两条分支时,它就遇到了一个难题。对于这一行代码,它不知道该听谁的。这就是“合并冲突”(Merge Conflict)。

发生冲突时,Git 会暂停合并过程,并在冲突的文件中插入一些特殊的标记,把决定权交还给你。文件内容会变成类似这样:

|
<<<<<<< HEAD <div id="footer">联系我们:support@example.com</div> ======= <div id="footer">请通过 support@example.com 联系我们</div> >>>>>>> feature-color

<<<<<<< HEAD 到 ======= 之间的部分,是 HEAD 指向的分支(也就是你当前所在的 master 分支)中的内容。而 ======= 到 >>>>>>> feature-color 之间的部分,则是来自 feature-color 分支的内容。

你需要做的,就是扮演“总编辑”的角色:手动编辑这个文件,决定最终采用哪个版本,或者将两者结合,创造一个全新的、更完美的版本。例如,你可以决定保留更详细的描述,然后将整个冲突标记区域替换为:

|
<div id="footer"> 请通过 email.support@github.com 联系我们 </div>

在你解决了所有文件中的所有冲突后,你需要告诉 Git 问题已经解决了。方法很简单,就是使用 git add 命令将修复后的文件标记为“已解决”,然后再执行 git commit 来完成这次艰难的合并。 Git 会为你准备好一个默认的合并提交信息,你也可以根据需要进行修改。


远程分支

到目前为止,我们所有的分支操作都发生在你自己的电脑上,它们是完全本地的。但软件开发通常是团队协作的成果。你需要一种方式来与他人分享你的分支,并获取他人的工作成果,这就是远程分支(Remote Branches)的用处了。

当你使用 git clone 从一个服务器(比如 GitHub)克隆一个项目时,你不仅下载了代码,还建立了一个与远程仓库的连接。 这个连接,Git 默认称之为 origin。远程仓库里的分支,在你本地会以一种特殊的形式存在,叫做“远程跟踪分支”(remote-tracking branch),例如 origin/master。

origin/master 就像是远程 master 分支在你本地的一个“书签”或“镜像”。它记录了你上一次与服务器通信时,master 分支所在的位置。你不能直接在这个分支上修改,但可以用它来参照和合并。

当你想要把你的本地分支分享给团队时,比如你刚刚完成的 feature-color 分支,你需要使用 git push 命令:

|
git push origin feature-color

这个命令的意思是:“嘿,origin 服务器,请接收我的 feature-color 分支,并在你那边也创建一个同名分支。” 这样,你的队友就可以通过 git fetch 或 git pull 命令看到并获取你的新分支了。

反过来,当你的队友更新了远程仓库的某个分支,你需要运行 git fetch origin 来更新你本地的“书签”,比如 origin/master。fetch 命令只会下载最新数据,更新你的远程跟踪分支,但不会改变你本地的工作分支。 下载后,你需要手动执行 git merge origin/master 才能将远程的变更合并到你自己的 master 分支中。

git pull 命令则是一个便捷的组合技,它相当于 git fetch 紧接着 git merge。对于新手来说,它很方便,但了解其背后的两个步骤能让你对发生了什么有更清晰的认识。


变基

除了合并(merge)外,Git 还提供了另一种整合不同分支修改的方式,叫做“变基”(Rebase)。 假设我们的master 分支在 C2 之后有了 C4,而还有一个 experiment 分支在 C2 之后有了 C3。

使用 merge 会产生一个有两条父路径的合并提交。而如果我们切换到 experiment 分支,执行 rebase:

|
git checkout experiment git rebase master

这个命令的内在逻辑是:“请找到 experiment 分支和 master 分支的共同祖先(C2),然后把 experiment 分支上自那以后的所有修改(也就是 C3 对应的修改)像补丁一样,逐个应用到 master 分支的最新提交(C4)之后。”

执行后,Git 会生成一个新的提交 C3',它的内容和 C3 完全一样,但它的父提交不再是 C2,而是 C4。这样,experiment 分支的历史就好像是发生在 master 分支修复 Bug 之后 一样。

现在,experiment 分支的历史变成了一条完美的直线。此时再切换回 master 分支去合并 experiment,就只需要一次简单的“快进”了。最终的历史记录看起来就像所有的工作都是按顺序依次完成的,非常清爽。

变基的黄金法则

变基(rebase)是个强大的工具,但能力越大,责任越大。它有一个必须用生命去遵守的黄金法则:绝对不要对已经推送到远程仓库、与团队共享的分支进行变基。

为什么?因为变基的本质是抛弃旧的提交,创造新的提交。当你对一个公共分支执行变基并强制推送(git push --force)后,你就改写了所有团队成员所依赖的历史。 当他们再次尝试同步代码时,他们的本地历史会和远程历史产生巨大的冲突和混乱。这就像你和朋友们正在合作一本共享的云文档,你却偷偷把某一章节恢复到昨天的版本,然后把自己今天写的内容重新在上面写了一遍。 你的朋友们今天基于原先版本所做的所有修改,瞬间就找不到了共同的基础,整个协作流程会陷入灾难。

所以,请记住:

  • 在你的个人电脑上,对自己尚未分享出去的、私有的本地分支,可以随意使用变基来整理你的提交记录,让它们变得更清晰有条理。
  • 一旦你把一个分支推送出去,与他人共享,就请彻底忘记变基这个选项,老老实实地使用合并(merge)。

合并还是变基?

这没有一个绝对的答案,它更像是一个哲学问题。 一个明智的折中方案是:用变基来整理你本地的、私有的工作,用合并来整合团队的、公共的工作。 这样,你既能享受到清晰的个人工作记录,又能保证团队协作的稳定与和谐。

  • 分支的本质
  • 合并
  • 冲突
  • 远程分支
  • 变基
    • 变基的黄金法则
  • 合并还是变基?

目录

  • 分支的本质
  • 合并
  • 冲突
  • 远程分支
  • 变基
    • 变基的黄金法则
  • 合并还是变基?
自在学

© 2025 自在学,保留所有权利。

公网安备湘公网安备43020302000292号 | 湘ICP备2025148919号-1

关于我们隐私政策使用条款

© 2025 自在学,保留所有权利。

公网安备湘公网安备43020302000292号湘ICP备2025148919号-1