1. 什么是分支,为什么需要分支?
在 Git 中使用 branches(分支) 是版本控制的关键方面之一,它允许在同一个仓库中并行开展多条开发线。分支让 Git 成为协作、实验以及管理项目不同版本的强大工具。
gitGraph
commit id: "Initial setup"
commit id: "Add base features"
branch feature/new-idea
checkout feature/new-idea
commit id: "Implement new logic"
commit id: "Refactor the logic"
checkout main
commit id: "Urgent bugfix on main"
merge feature/new-idea
commit id: "Prepare for release"
main 分出一个新分支
feature/new-idea,用于安全开发。完成后将其合并回
main。
想象一下,您想对项目做一次大改,或者进行一次有风险的实验。如果没有 Git,您会怎么做?很可能会把整个项目复制到一个新文件夹中并在其中工作。如果结果满意——就把它移回主文件夹;如果不满意——直接删除那份副本。
Git 中的分支工作原理相同,但优雅得多。让我们用写书来打个比方:
- 您有一份完成的手稿(这就是您的主分支
main)。 - 您想写一个备选结局(创建一个新分支,例如
feature/new-idea)。 - 您在不影响手稿正文的情况下撰写新结局(在新分支中工作)。
- 如果新结局更好,就用它替换旧的(执行分支合并——
merge)。 - 带有不需要结局的旧草稿可以删除(删除该分支)。
2. 创建新分支并在其中工作
步骤 1:打开分支管理菜单。
在 IDE 顶部面板有一个显示当前分支名称的控件(默认是 main)。点击它并选择 + New Branch。
步骤 2:新分支名称。
最佳实践是按照您要解决的任务来命名分支。例如,feature/add-usage-examples。
创建分支后,IDE 会自动切换到它。您会在同一个控件中看到新名称。
步骤 3:进行并提交更改。
现在您处于自己的“沙盒”。让我们在文件 README.md 中添加一个新的“使用示例”部分。进行更改并像上一课学到的那样执行 commit。
3. 在分支之间切换
您添加的“使用示例”更改现在已安全地保存在分支 feature/add-usage-examples 中。让我们回到主分支 main 看看。
步骤 1。 再次点击显示当前分支名称的控件。
步骤 2。 在 Local 或 Recent 列表中选择分支 main,在出现的子菜单中点击 Checkout。
步骤 3:检查结果。
一旦切换完成,打开文件 README.md。您会发现其中没有“使用示例”部分!它还在另一个分支中。因此,您可以在不影响 main 分支稳定版本的情况下开发新功能。
4. 合并分支(Merge)
命令 merge 会将分支 feature/add-examples 的所有提交(在此为提交 C3)与当前分支 main 合并,创建一个新的合并提交。
gitGraph
commit id: "C1"
commit id: "C2"
branch feature/add-examples
checkout feature/add-examples
commit id: "C3: Add new section"
checkout main
merge feature/add-examples
现在,您已经在分支 feature/add-usage-examples 完成了任务,想把这些更改添加到主项目中。
步骤 1:切换到目标分支。
请确保您位于要接收更改的分支。在我们的例子中是 main。
步骤 2:执行合并。
再次点击分支管理控件。在列表中选择提供更改的分支(feature/add-usage-examples),并在子菜单中选择 Merge 将 feature/add-usage-examples 合并到 main。
步骤 3:检查结果。
现在在分支 main 的文件 README.md 中已经出现了您新增的示例部分。您已成功将自己的工作与项目主版本合并!
5. 合并冲突:别怕,这很正常!
有时在合并分支时会出现冲突。当两个分支在同一文件的同一行都做了修改时,就会发生这种情况。Git 无法自行判断哪一版本是正确的,需要您的帮助。
gitGraph
commit id: "C1: Common baseline"
branch feature/new-title
checkout main
commit id: "C2: main 中的更改"
checkout feature/new-title
commit id: "C3: feature 中的更改"
main 和
feature/new-title 都基于共同祖先(C1)产生了新提交(C2 和 C3)。这必然会在合并时引发冲突。
我们来模拟一个冲突:
- 确保您位于分支
main,并且没有未保存的更改。 - 立即创建新分支
feature/new-title,但暂时不要切换到它。请确保取消勾选 Checkout branch。 - 现在,仍在分支
main上,把README.md的第一行改为“My Awesome Project”,并执行commit。 - 切换到分支
feature/new-title。您会看到这里的README.md第一行还是旧的:这是创建分支时的文件状态。把同一行改为“My Super Project”,并执行commit。 - 返回分支
main,并与feature/new-title进行合并。
现在 Git 会发现两个分支从共同祖先开始各自演进。在两条历史中,同一行都被修改了,因此 Git 无法选择哪一个版本正确,会弹出窗口请您解决冲突。
Merge Revision
您会看到:
- 左侧(Your changes):来自您当前分支(
main)的文件版本。 - 右侧(Changes from branch...):来自待合并分支的文件版本。
- 中间(Result):您需要最终整理出的文件版本。
您可以点击箭头 >> 或 <<,以整体接受某一侧的版本。
当中央面板中的结果令您满意时,点击 Apply。IDE 会自动创建合并提交,冲突将得到解决。
为什么没有产生冲突?
有时即使完成了所有步骤,也不会出现冲突。多数情况下,这是因为 Git 能执行 fast-forward merge(快进合并),即一个分支的历史只是顺着另一个分支的历史继续前进。要想必然出现冲突,两个分支的历史必须从共同祖先开始分叉,各走各的。
例子:
- 在
main中已有一个提交(例如 C1)。 - 您在
main做了一个新的提交,内容为“My Awesome Project”。分支main现在指向提交 C2(main -> C1 -> C2)。 - 您从当前的 main 位置创建分支
feature/new-title。这意味着新分支同样从提交 C2 开始。 - 您在
feature/new-title中做了一个提交,内容为“My Super Project”。该分支“向前推进”,现在指向提交 C3(feature/new-title -> C1 -> C2 -> C3)。 - 您回到仍停留在提交 C2 的
main,并发起合并feature/new-title的操作。
Git 会观察到:分支 main 是分支 feature/new-title 的直接祖先。在您于另一个分支上工作期间,main 的历史并没有新的提交。Git 心想:“哦,这里只需要把 main 快进到提交 C3,就没有任何冲突了。”于是它仅仅把 main 的指针移动到提交 C3。
gitGraph
commit id: "C1"
commit id: "C2"
branch feature/new-title
checkout feature/new-title
commit id: "C3"
checkout main
merge feature/new-title
6. 查看变更历史
为了更好地理解项目中的变化,查看它的历史非常有用。
在 IDE 底部打开 Git 选项卡,选择 Log。您会看到所有分支和提交的图形化表示。这有助于直观地跟踪各分支从哪里分出、在哪里被合并。
在这里,您可以点击任意提交以查看其中包含了哪些更改、由谁在何时完成。这简直就是代码的时光机!
GO TO FULL VERSION