Git将项目历史记录为一系列快照或提交。通常,这些记录形成一条线性序列,每个提交都基于前一个提交。但是,软件开发很少会严格按照这种线性方式进行。你经常需要同时处理不同的事务。设想你正在开发一个重要的新功能,但突然发现一个紧急错误需要修正已发布给用户的代码。你需要一种方法来暂停功能开发,在稳定的代码库上修正错误,然后返回到功能开发,而不会让这两部分工作互相干扰。这时,Git分支就发挥作用了。把分支看作不是项目文件的完整副本,而是一个轻量级可移动指针,指向某个特定的提交。当你开始工作时,Git会自动创建一个默认分支,通常命名为main(在旧项目中可能叫master)。这个main分支代表主要的开发线,通常跟踪稳定或可用于生产的代码。每次你进行提交时,这个分支指针都会自动向前移动,指向你刚刚创建的最新提交。所以,一个简单的历史可能看起来像这样:main分支指针指向最新提交,而该提交本身又指向上一个父提交,以此类推,构成项目历史。digraph G { rankdir=LR; node [shape=circle, style=filled, color="#adb5bd", fontname="Arial"]; edge [fontname="Arial"]; C1 -> C2 -> C3; subgraph cluster_0 { style=dotted; label = "main"; labeljust="l"; C3; } C1 [label="C1"]; C2 [label="C2"]; C3 [label="C3"]; HEAD [shape=plaintext, label="HEAD"]; HEAD -> C3 [label="main", style=dashed]; // 显示HEAD指向分支,分支再指向提交 }一个简单的Git历史图。提交(C1, C2, C3)形成一个序列。main分支指向最新提交(C3),HEAD表明main是当前活跃的分支。创建一个新分支意味着创建一个新指针,该指针从当前分支所指向的同一提交开始。比如,当你在main分支上,且该分支指向提交C3时,你创建了一个名为new-feature的新分支。最初,main和new-feature都将指向C3。digraph G { rankdir=LR; node [shape=circle, style=filled, color="#adb5bd", fontname="Arial"]; edge [fontname="Arial"]; C1 -> C2 -> C3; subgraph cluster_0 { style=dotted; label = "main"; labeljust="l"; C3; } subgraph cluster_1 { style=dotted; label = "new-feature"; labeljust="l"; C3; // 两者最初都指向这里 } C1 [label="C1"]; C2 [label="C2"]; C3 [label="C3"]; HEAD [shape=plaintext, label="HEAD"]; HEAD -> C3 [label="main", style=dashed]; // HEAD仍在main分支上 // 将指针在C3附近可视化分组 }创建new-feature分支之后。main和new-feature这两个指针都引用相同的提交C3。HEAD仍指向main。现在,如果你切换到new-feature分支(我们很快会讲到如何操作)并进行一次新提交,比如C4,会发生一些有趣的事情。new-feature指针向前移动指向C4,但main分支指针仍停留在原地,继续指向C3。你的HEAD指针现在表明你正在new-feature分支上处理事务。digraph G { rankdir=LR; node [shape=circle, style=filled, fontname="Arial"]; edge [fontname="Arial"]; C1 -> C2 -> C3 -> C4 [color="#748ffc"]; // new-feature分支的提交 // 提交样式 C1 [color="#adb5bd"]; C2 [color="#adb5bd"]; C3 [color="#adb5bd"]; C4 [color="#748ffc"]; // 新提交的颜色 // 明确地放置分支标签 main_label [label="main", shape=none, fontcolor="#495057"]; main_label -> C3 [style=dashed]; feature_label [label="new-feature", shape=none, fontcolor="#4263eb"]; feature_label -> C4 [style=dashed]; C1 [label="C1"]; C2 [label="C2"]; C3 [label="C3"]; C4 [label="C4"]; HEAD [shape=plaintext, label="HEAD"]; HEAD -> C4 [label="new-feature", style=dashed, color="#4263eb"]; }切换到new-feature并进行提交C4后。new-feature分支指针推进到C4,而main停留在C3。HEAD现在指向new-feature。这产生了从提交C3分叉的两条独立的开发线。你可以在new-feature分支上继续处理你的功能,而不影响main分支。如果需要,你可以切换回main,创建另一个分支(例如bug-fix),在那里进行提交,它不会影响main或new-feature,直到你明确决定合并它们(这称为合并,稍后会讲到)。主要结论是,Git分支极其轻量。创建新分支不涉及复制文件或目录;它只是创建一个小文件,其中包含它所指向提交的40个字符的SHA-1哈希值。这种效率使得分支成为Git工作流程中一个常见且重要的部分,不像某些旧版本控制系统,在那些系统中,分支操作成本更高。使用分支提供了几个重要优点:隔离: 处理新功能或错误修正,而不干扰稳定代码库(main)。尝试: 在单独分支上尝试新想法或重构代码。如果不成功,你可以直接丢弃该分支,而不影响主项目。并行开发: 多个开发者(甚至一个开发者处理多个任务)可以同时处理不同的功能或修正。清晰历史: 保持main分支整洁,只包含稳定、经过测试的代码,而开发发生在其他分支上。理解这种指针想法是有效使用Git分支能力的重要基础,我们将在后续章节中进一步研究这一点。