☰
Git 分支入门:从零掌握 branch、switch 和 merge
2026/10/4 6:10:16 网站建设 项目流程

上一篇已经介绍了 Git 最基础的本地版本管理流程:

修改代码 ↓ git status ↓ git diff ↓ 编译 / 测试 ↓ git add ↓ git commit

对于只有一个开发方向的小项目来说,这套流程已经够用了。

但实际开发很快就会遇到新的问题。

例如现在有一个已经可以正常运行的程序:

project

接下来想尝试加入一个新功能。

最直接的做法当然是继续修改当前代码。

但新功能可能需要改很多文件,而且暂时还不知道能不能成功。

如果直接在当前代码上修改:

稳定版本 ↓ 修改 ↓ 继续修改 ↓ 功能还没做完 ↓ 程序暂时跑不起来

这时候如果突然发现:

原来的稳定版本还需要继续使用怎么办?

当然可以依靠 commit 回退。

但 Git 还有一种更适合这种场景的机制:

branch

也就是:

分支

分支可以让我们从当前版本“分出去”一条新的开发路线,在不影响稳定代码的情况下开发新功能。

例如:

feature / main ──────────●

之后可以变成:

main │ ├── 稳定版本继续保留 │ └── feature │ ├── 修改代码 ├── 测试新方案 └── 完成新功能

如果新功能开发成功,就把它合并回 main。

如果失败,也可以直接删除这个分支。

这篇文章就从零开始介绍 Git 中最常用的分支操作:

branch switch merge

不涉及 GitHub 和远程仓库,仍然只讨论本地 Git。


1. 为什么需要分支?

先看一个实际场景。

假设有一个 Linux C 项目:

input_project/ ├── main.c ├── input.c ├── input.h └── Makefile

当前程序已经可以正常读取输入设备。

版本历史:

82a7f61 Add input device support 4c91e20 Fix read error handling 16af883 Initial project

现在准备加入:

select()

来实现多路输入监听。

这次修改可能涉及:

main.c input.c input.h

而且开发过程中程序可能暂时无法编译。

如果直接在当前代码上修改:

main │ ├── 稳定版本 │ ├── 修改 main.c │ ├── 修改 input.c │ └── 功能开发中……

此时 main 分支就不再是稳定状态。

更合理的方式是:

main │ ●────────────── 稳定版本 \ \ select-dev │ ├── 修改代码 ├── 编译 ├── 调试 └── 完成功能

新功能全部在:

select-dev

分支中完成。

main 不受影响。

等 select 功能确认没有问题以后:

select-dev │ └──────────→ main

再合并回去。

这就是分支最核心的用途。


2. branch 到底是什么?

很多初学者第一次接触 Git 分支时,会把它想得比较复杂。

实际上可以先把 branch 理解成:

指向某个 commit 的一条开发路线。

假设现在有三个 commit:

A ↓ B ↓ C

main 当前指向:

A → B → C ↑ main

严格来说应该是:

A → B → C ↑ main

这里的:

main

本质上就是一个指向 commit C 的名字。

如果创建一个新的分支:

dev

那么刚创建的时候:

A → B → C ↑ main dev

main 和 dev 都指向同一个 commit。

此时两个分支中的代码完全一样。

接下来切换到 dev,并创建新的 commit:

A → B → C ↑ main \ D ↑ dev

这时候两个分支就真正分开了。

main 仍然停留在:

C

dev 已经继续向前开发到:

D

这就是所谓的:

分支开发

3. 查看当前分支

先进入一个已经初始化过 Git 的项目。

例如:

cd input_project

查看当前分支:

git branch

可能看到:

* main

前面的:

*

表示当前所在分支。

也就是说:

* main

表示:

当前正在 main 分支上工作。

也可以执行:

git status

通常会看到:

On branch main

所以查看当前分支,最常用的两个命令就是:

git branch

和:

git status

4. 创建一个新分支

假设准备开发 select 功能。

可以创建一个分支:

git branch select-dev

再查看:

git branch

可能看到:

* main select-dev

这里要注意:

git branch select-dev

只是:

创建了 select-dev 分支。

并没有切换过去。

当前仍然是:

* main

也就是说代码还是处于 main 分支。


5. git switch:切换分支

切换到新分支:

git switch select-dev

可能会看到:

Switched to branch 'select-dev'

再次查看:

git branch

现在变成:

main * select-dev

说明当前已经进入:

select-dev

以后产生的新 commit 都会记录在这个分支上。


6. 创建并切换分支

刚才用了两步:

git branch select-dev git switch select-dev

实际开发中可以直接写成:

git switch -c select-dev

这里:

-c

可以理解为:

create

也就是:

创建分支并立即切换过去。

因此以后最常用的方式通常是:

git switch -c 分支名

例如:

git switch -c feature/select

查看:

git branch

可以看到:

main * feature/select

7. 为什么很多分支叫 feature/xxx?

分支名字并没有强制格式。

完全可以写:

test

或者:

dev

但实际项目中一般希望名字能表达用途。

例如:

feature/select

表示:

开发 select 功能

还可以看到:

feature/v4l2-capture feature/rga-resize feature/video-encode

如果是修复 Bug:

fix/read-error fix/memory-leak

如果是实验:

experiment/new-filter experiment/three-frame

这样看到分支名字就知道这个分支是干什么的。

例如:

main ├── feature/v4l2-capture ├── feature/rga-resize ├── fix/read-error └── experiment/new-filter

比:

main ├── test1 ├── test2 ├── aaa └── new

明显更容易维护。


8. 在新分支中修改代码

假设当前:

git branch

得到:

main * feature/select

现在修改:

main.c

原来:

#include <stdio.h> int main(void) { printf("Input project\n"); return 0; }

修改为:

#include <stdio.h> int main(void) { printf("Input project with select\n"); return 0; }

查看:

git status

会看到:

modified: main.c

查看具体修改:

git diff

确认没有问题以后:

git add main.c

再检查:

git diff --staged

最后提交:

git commit -m "Add select based input monitoring"

此时分支历史大概变成:

D ↑ feature/select / A → B → C ↑ main

main 还是:

C

feature/select 已经到了:

D

9. 切回 main 会发生什么?

现在执行:

git switch main

Git 会把工作区切换回 main 对应的状态。

也就是说:

feature/select

中的修改不会出现在 main 中。

例如在 feature/select 里面:

printf("Input project with select\n");

切回:

git switch main

可能又看到原来的:

printf("Input project\n");

这并不是代码丢失了。

而是因为两个分支代表两个不同版本。

可以理解为:

main │ └── 原来的稳定代码 feature/select │ └── 加入 select 的新代码

你切换到哪个分支,工作区就显示哪个分支对应的代码。

这也是分支非常有用的地方。


10. 切换分支前为什么最好保持工作区干净?

假设当前正在:

feature/select

里面修改代码,但还没有 commit。

执行:

git status

看到:

Changes not staged for commit: modified: main.c

这时候最好不要急着切换分支。

因为当前还有:

未提交修改

Git 有时候允许带着这些修改切换分支。

但如果两个分支对同一个文件存在不同修改,也可能直接拒绝切换。

因此对于刚开始学习 Git 的时候,推荐形成一个简单习惯:

切换分支之前先执行 git status。

比较理想的状态是:

nothing to commit, working tree clean

也就是:

working tree clean

再执行:

git switch main

会更加清楚,也不容易把不同功能的修改混在一起。


11. 查看所有分支

执行:

git branch

例如:

* main feature/select feature/epoll

说明当前仓库一共有三个本地分支:

main feature/select feature/epoll

其中:

main

前面有:

*

所以当前在 main。


12. merge:把分支合并回来

现在假设:

feature/select

已经开发完成,并且:

编译通过 测试通过 功能正常

接下来希望把这个功能加入 main。

第一步:

git switch main

确认:

git branch

看到:

* main feature/select

然后执行:

git merge feature/select

意思就是:

把 feature/select 中的修改合并到当前分支 main。

注意这个方向。

我们现在是在:

main

执行:

git merge feature/select

所以相当于:

feature/select ↓ main

而不是 main 合并到 feature/select。


13. 一个完整的分支流程

把前面的操作连起来就是:

首先确认当前状态:

git status

创建功能分支:

git switch -c feature/select

然后开发功能。

开发完成以后:

git status git diff

编译:

make

测试没有问题以后:

git add . git diff --staged git commit -m "Add select based input monitoring"

此时功能已经保存在:

feature/select

里面。

然后切回:

git switch main

合并:

git merge feature/select

最后查看:

git log --oneline

整个过程可以画成:

main │ ● │ ├───────────────────────┐ │ │ │ feature/select │ │ │ 修改 │ ↓ │ 测试 │ ↓ │ commit │ │ │◀──────────────────────┘ │ merge │ ↓ main

14. 什么是 Fast-forward?

第一次执行 merge 时,很可能看到类似:

Fast-forward

例如:

Updating 82a7f61..9c31e42 Fast-forward main.c | 10 ++++++++-- 1 file changed

Fast-forward 中文通常叫:

快进合并

假设最开始:

A → B → C ↑ main ↑ feature/select

创建 feature/select 以后,main 一直没有产生新的 commit。

只有 feature/select 向前开发:

A → B → C → D ↑ ↑ main feature/select

这时候 main 想合并 feature/select。

实际上 Git 不需要创建复杂的合并结构。

直接把 main 从:

C

移动到:

D

即可:

A → B → C → D ↑ main ↑ feature/select

这就是:

Fast-forward

可以简单理解为:

main 没有产生其他修改,所以直接向前移动即可。

对于刚开始学习 Git 来说,知道这个概念即可,不需要专门处理。


15. 合并完成以后删除分支

feature/select 已经开发完成,而且已经合并回 main。

这个分支通常就可以删除。

首先确保当前已经不在 feature/select:

git switch main

然后:

git branch -d feature/select

其中:

-d

表示删除分支。

再查看:

git branch

只剩:

* main

这里需要注意:

删除分支不等于删除已经合并的代码。

因为 feature/select 中的 commit 已经进入了 main。

例如合并以后:

A → B → C → D ↑ main

feature/select 只是一个指向 D 的分支名字。

删除:

feature/select

以后:

A → B → C → D ↑ main

commit D 仍然存在。

代码当然也仍然存在。


16. 为什么有时候 git branch -d 删除失败?

假设创建:

git switch -c experiment/test

然后在里面产生一个 commit。

但还没有合并回 main。

切换:

git switch main

然后执行:

git branch -d experiment/test

Git 可能拒绝删除。

原因是:

这个分支还有没有合并的 commit。

Git 是在保护你,避免直接丢失这些开发结果。

如果非常确定这个实验分支不要了,可以强制删除:

git branch -D experiment/test

注意这里是大写:

-D

它表示强制删除。

因此:

git branch -d 分支名

比较安全。

而:

git branch -D 分支名

要更加谨慎。

刚开始学习时,优先使用:

git branch -d

即可。


17. 一个完整的 C 项目实战

下面真正走一次完整流程。

假设现在有:

input_demo/ ├── main.c └── Makefile

main.c:

#include <stdio.h> int main(void) { printf("Linux input demo\n"); return 0; }

Makefile:

CC = gcc CFLAGS = -Wall -Wextra TARGET = input_demo all: $(CC) $(CFLAGS) main.c -o $(TARGET) clean: rm -f $(TARGET)

首先初始化:

git init -b main

加入文件:

git add .

检查:

git diff --staged

提交:

git commit -m "Initial input demo"

此时:

git log --oneline

可能看到:

16af883 Initial input demo

18. 创建功能分支

准备增加 select 说明。

创建:

git switch -c feature/select

查看:

git branch

输出:

main * feature/select

修改 main.c:

#include <stdio.h> #include <sys/select.h> int main(void) { printf("Linux input demo with select\n"); return 0; }

查看:

git status

再看修改:

git diff

编译:

make

如果看到:

gcc -Wall -Wextra main.c -o input_demo

并且没有明显警告或错误,再运行:

./input_demo

输出:

Linux input demo with select

确认正常。

提交:

git add main.c git diff --staged git commit -m "Add select support preparation"

查看:

git log --oneline

可能得到:

a2137c4 Add select support preparation 16af883 Initial input demo

19. 回到 main 看一下

现在:

git switch main

查看:

git log --oneline

可能只有:

16af883 Initial input demo

因为:

a2137c4

目前属于:

feature/select

再查看 main.c。

会发现还是:

#include <stdio.h> int main(void) { printf("Linux input demo\n"); return 0; }

说明 feature/select 中的开发完全没有影响 main。

这就是使用分支开发最直接的意义。


20. 合并功能分支

确认 feature/select 没有问题以后,在 main 中:

git merge feature/select

可能看到:

Updating 16af883..a2137c4 Fast-forward

再看:

git log --oneline

变成:

a2137c4 Add select support preparation 16af883 Initial input demo

main.c 也已经变成:

#include <stdio.h> #include <sys/select.h> int main(void) { printf("Linux input demo with select\n"); return 0; }

说明:

feature/select

中的功能已经进入 main。

最后删除:

git branch -d feature/select

完成。


21. 如果两个分支同时开发会怎样?

分支真正有价值的场景并不是只有一条支线。

例如:

main ├── feature/select └── feature/epoll

可以从稳定版本分别创建两个分支。

例如:

git switch main git switch -c feature/select

开发 select。

完成以后切回:

git switch main

还可以创建:

git switch -c feature/epoll

专门开发 epoll。

于是两个方案互不影响。

概念上:

feature/select / A → B → C \ feature/epoll

这在实验性开发中非常有用。

例如图像算法项目可能同时测试:

main ├── experiment/filter-a ├── experiment/filter-b └── experiment/filter-c

A 方案不影响 B。

B 方案不影响 C。

最后哪个方案效果好,再决定哪个合并到 main。


22. 分支特别适合实验代码

例如一个深度学习项目已经有稳定模型:

main

准备测试新的网络结构。

完全没有必要直接修改 main。

可以:

git switch -c experiment/new-attention

测试注意力模块。

另外再:

git switch main git switch -c experiment/new-loss

测试新的 loss。

结构就是:

main ├── experiment/new-attention └── experiment/new-loss

即使:

new-attention

最后效果不好,也不会影响:

main

直接删除实验分支即可。

这也是 Git 在算法开发中非常实用的地方。


23. 分支也适合功能开发

嵌入式项目中同样如此。

例如一个 IPC 项目:

mini_ipc/ ├── src/ ├── include/ ├── CMakeLists.txt └── README.md

main 保存当前稳定版本。

不同功能可以使用:

main ├── feature/v4l2-capture ├── feature/rga-resize ├── feature/h264-encode └── feature/rtsp-stream

开发 V4L2:

git switch -c feature/v4l2-capture

开发完成并测试通过以后:

git switch main git merge feature/v4l2-capture

然后继续开发 RGA:

git switch -c feature/rga-resize

这样项目历史会非常清楚。


24. 一个功能应该一个分支吗?

对于个人项目,不需要把规则搞得特别复杂。

可以先形成一个简单原则:

一个相对独立的功能,可以开一个分支。

例如:

加入摄像头采集

可以:

feature/v4l2-capture

加入编码:

feature/video-encode

修复内存泄漏:

fix/memory-leak

尝试新算法:

experiment/new-denoise

但是如果只是:

README 改一个错别字

或者:

修改一个很小的注释

对于个人小项目,没有必要强制每一次都建立新分支。

分支是帮助管理开发的工具,不是为了增加开发流程。


25. main 分支最好保持什么状态?

个人项目中可以建立一个非常简单的习惯:

main = 相对稳定

例如:

main │ ├── 可以正常编译 ├── 主要功能可以运行 └── 不放大量做到一半的代码

新功能:

feature/xxx

Bug 修复:

fix/xxx

实验:

experiment/xxx

完成以后:

测试 ↓ commit ↓ merge main

这样 main 通常保持在一个比较稳定的状态。


26. 常见错误:创建分支以后忘记切换

执行:

git branch feature/select

然后直接开始修改代码。

但:

git branch

显示:

* main feature/select

这意味着:

虽然创建了 feature/select,但实际仍然在 main 上修改。

所以创建功能分支时更推荐:

git switch -c feature/select

这样创建和切换一次完成。

并且修改代码以前先:

git status

确认:

On branch feature/select

27. 常见错误:merge 方向弄反

假设目标是:

把 feature/select 合并到 main。

正确做法:

git switch main git merge feature/select

可以记成:

先站到“最终想保留代码”的分支,再 merge 另一个分支。

也就是:

我要把 B 合并到 A

那么:

git switch A git merge B

例如:

feature/select ↓ main

就是:

git switch main git merge feature/select

28. 常见错误:功能没测试就直接 merge

例如在:

feature/select

修改完成以后,立即:

git switch main git merge feature/select

不太推荐。

更合理的是先在 feature/select 中完成:

git status ↓ git diff ↓ 编译 ↓ 测试 ↓ git add ↓ git diff --staged ↓ git commit

确认功能没有问题以后,再:

git switch main git merge feature/select

这样 main 才更容易保持稳定。


29. 常见错误:工作区很乱的时候频繁切换分支

例如:

git status

看到:

modified: main.c modified: input.c modified: Makefile

而且这些修改都还没有整理。

这时候又:

git switch feature/xxx

很容易把自己搞乱。

推荐习惯:

切换分支之前:

git status

最好看到:

nothing to commit, working tree clean

如果当前工作已经形成一个完整修改,就先 commit。

如果修改还没有完成,又确实必须切换分支,后面还可以学习:

git stash

不过 stash 暂时不是这一篇的重点。


30. 常见错误:什么都建一个分支

分支虽然很好用,但也没有必要变成:

feature/change-one-line feature/change-comment feature/test-print feature/change-variable-name

对于个人项目来说,这样反而增加管理负担。

比较适合开分支的是:

一个新功能 一个 Bug 修复 一个实验方案 一个较大的重构

原则仍然是:

为开发服务,而不是为了使用 Git 而使用 Git。


31. git branch 常用命令整理

查看本地分支:

git branch

创建分支:

git branch feature/select

删除已经合并的分支:

git branch -d feature/select

强制删除:

git branch -D feature/select

查看当前分支也可以使用:

git status

32. git switch 常用命令整理

切换分支:

git switch main

创建并切换:

git switch -c feature/select

例如:

git switch -c fix/read-error

再切回 main:

git switch main

33. git merge 常用方式

假设:

feature/select

需要进入:

main

执行:

git switch main git merge feature/select

然后如果已经不需要这个分支:

git branch -d feature/select

可以把它记成:

创建分支 ↓ 开发 ↓ 测试 ↓ commit ↓ 切回 main ↓ merge ↓ 删除功能分支

34. 一套推荐的日常分支工作流

假设准备开发:

V4L2 capture

先看当前状态:

git status

确保:

working tree clean

创建分支:

git switch -c feature/v4l2-capture

开始开发。

开发完成以后:

git status git diff

编译:

make

或者:

cmake --build build

测试正常以后:

git add . git diff --staged git commit -m "Add V4L2 video capture"

再次确认:

git status

然后:

git switch main

合并:

git merge feature/v4l2-capture

最后:

git branch -d feature/v4l2-capture

这就是一个非常典型的功能开发流程。


35. 配合上一篇,Git 工作流已经完整很多了

上一篇只使用:

main

工作流是:

修改 ↓ status ↓ diff ↓ 测试 ↓ add ↓ diff --staged ↓ commit

学习分支以后,可以扩展成:

main ↓ 创建 feature 分支 ↓ 开发 ↓ status ↓ diff ↓ 测试 ↓ add ↓ diff --staged ↓ commit ↓ 切回 main ↓ merge ↓ 删除 feature 分支

这已经比较接近真实项目中的 Git 使用方式。


36. 现在最需要掌握哪些命令?

这一篇真正需要记住的命令其实只有几个。

查看分支:

git branch

创建并切换:

git switch -c feature/xxx

切换:

git switch main

合并:

git merge feature/xxx

删除:

git branch -d feature/xxx

加上上一篇的:

git status git diff git add . git diff --staged git commit git log --oneline

已经可以处理很多个人项目。


37. 一个需要提前知道的问题:合并冲突

目前文章中的例子都比较简单。

例如:

main 没有修改 feature/select 有修改

这时候 merge 通常非常顺利。

但实际开发中可能出现:

main

修改了:

main.c

与此同时:

feature/select

也修改了 main.c 的同一部分。

例如 main 改成:

printf("Main version\n");

而 feature/select 改成:

printf("Select version\n");

Git 就可能不知道:

到底应该保留哪一个?

这时候会出现:

merge conflict

也就是:

合并冲突

Git 不会擅自替你决定,而是要求开发者处理冲突。

这一部分内容比较重要,也值得单独写一篇详细介绍。

所以这一篇先掌握:

branch switch merge

下一步再解决:

merge conflict

会更加清楚。


38. Git 分支可以怎么理解?

如果只记一个核心概念,可以这样理解:

main

是主开发路线。

feature/xxx

是一条临时分出去的开发路线。

例如:

feature/select / A ───── B ───── C \ feature/epoll

不同方案分别开发。

某个方案确认成功以后:

feature/select │ ↓ main

合并进去。

失败的实验:

experiment/test

则可以不影响 main,直接删除。

因此分支真正解决的问题是:

同一个项目可以同时维护不同的开发方向,而不会互相干扰。


39. 推荐形成的使用习惯

开始开发一个较完整的新功能之前:

git status

确认当前项目干净。

然后:

git switch -c feature/功能名

在新分支中开发。

开发过程中正常使用:

git status git diff

功能完成:

编译 测试

没有问题以后:

git add . git diff --staged git commit -m "描述本次功能"

再:

git switch main git merge feature/功能名

最后:

git branch -d feature/功能名

整个流程可以浓缩成:

main ↓ switch -c ↓ feature ↓ 开发 ↓ 测试 ↓ commit ↓ switch main ↓ merge ↓ main

40. 后续还需要学习什么?

到现在为止,我们已经完成了 Git 本地使用中两个非常重要的部分。

第一部分:

工作区 ↓ 暂存区 ↓ 本地仓库

掌握:

status diff add commit log restore

第二部分:

分支开发

掌握:

branch switch merge

接下来就可以继续学习:

Git 本地基础 ↓ branch / merge ↓ GitHub ↓ remote ↓ push ↓ clone ↓ pull ↓ 多人协作 ↓ 冲突处理

其中下一步最自然的是:

把本地 Git 仓库上传到 GitHub。

到时候就会接触:

git remote git push git clone git pull

也会真正理解:

本地仓库 ↕ 远程仓库

之间是什么关系。


总结

Git 分支的核心并不复杂。

首先有一个稳定的:

main

需要开发新功能时:

git switch -c feature/xxx

于是:

main \ feature/xxx

在 feature 中完成:

修改 ↓ 测试 ↓ commit

功能确认正常后:

git switch main git merge feature/xxx

最后删除已经完成使命的分支:

git branch -d feature/xxx

所以这一篇最需要记住的工作流就是:

git status ↓ git switch -c feature/xxx ↓ 开发 / 修改代码 ↓ git status ↓ git diff ↓ 编译 / 测试 ↓ git add . ↓ git diff --staged ↓ git commit ↓ git switch main ↓ git merge feature/xxx ↓ git branch -d feature/xxx

如果上一篇解决的是:

如何保存代码的不同版本?

那么这一篇解决的就是:

如何同时维护不同的开发路线?

掌握分支以后,Git 就不再只是一个简单的“代码存档工具”,而开始真正成为项目开发中的版本管理工具。

下一篇继续学习 GitHub,把目前只存在本地电脑中的 Git 仓库真正放到远程服务器上。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询