云计算百科
云计算领域专业知识百科平台

第4章:Git分支与标签

第4章:Git分支与标签

本章目标

  • 理解分支的本质与 HEAD 的关系
  • 掌握分支的创建、切换、重命名、删除
  • 掌握合并(merge)与冲突解决完整流程
  • 理解并会使用变基(rebase)
  • 学会用标签(tag)标记版本
  • 了解常见的分支管理模型
  • 1. 什么是分支

    分支(Branch) 可以理解为一条独立的开发时间线。你可以在分支 A 上开发新功能,同时保持主分支 B 的稳定,最后再把两条线合并起来。

    Git 的分支与其他工具不同,它本质上只是一个指向提交的指针(存一个 40 位的哈希值,只占几十个字节),所以创建和切换分支是"瞬间"完成的。

    main

    A ─── B ─── C
    \\
    D ─── E ← dev 分支

    dev

    • main 指针指向提交 C
    • dev 指针指向提交 E
    • HEAD 指向"你当前所在的分支"(上图如果 HEAD → main,说明你在 main 分支上工作)

    1.1 主分支叫什么?

    • 早期 Git 默认主分支叫 master
    • 2020 年起,GitHub 新建仓库默认叫 main;Gitee 的默认分支通常是 master(可在仓库设置中修改)
    • Git 2.28+ 可用 git config –global init.defaultBranch main 设置本地默认分支名(见 [[第1章:Git入门与环境搭建]])

    2. 分支基本操作

    2.1 查看分支

    git branch # 本地分支(当前分支前有 * 号)
    git branch -v # 显示每个分支最后一次提交
    git branch -a # 本地 + 远程分支(remote 开头的是远程分支)
    git branch -vv # 显示分支与远程的追踪关系
    git branch –merged # 已合并到当前分支的分支(可安全删除)
    git branch –no-merged # 未合并的分支

    2.2 创建分支

    git branch dev # 基于当前提交创建 dev 分支(不切换)
    git branch dev <commit> # 基于指定提交创建
    git switch -c dev # 创建并立即切换(推荐)
    git checkout -b dev # 同上(旧写法)
    git branch dev origin/dev # 基于远程分支创建本地分支

    [!tip] switch vs checkout
    git switch 是 Git 2.23 引入的专用切换分支命令,语义更清晰;git checkout 一个命令身兼数职(切分支、恢复文件),容易混淆。建议新操作习惯用 switch / restore。

    2.3 切换分支

    git switch dev # 切换到 dev 分支
    git switch – # 切回上一个分支
    git switch -c dev # 创建并切换
    git checkout dev # 旧写法

    [!warning] 切换分支前
    工作区有未提交的改动时:

    • 如果改动与目标分支不冲突,Git 会把改动带过去(容易懵)
    • 如果冲突,Git 拒绝切换并要求你先 commit 或 stash
      建议:切换分支前保证工作区干净(git status 无输出),或先 git stash。

    2.4 重命名与删除分支

    git branch -m newname # 重命名当前分支
    git branch -m old new # 重命名指定分支
    git branch -d dev # 删除已合并的分支(安全)
    git branch -D dev # 强制删除未合并分支(危险)
    git push origin –delete dev # 删除远程分支

    [!warning] 删分支后悔了?
    只要分支上的提交曾经存在过,可以先 git reflog 找到对应提交,然后 git branch 名字 <commit> 复活。

    3. 合并分支:git merge

    合并 = 把另一个分支的改动并入当前分支。注意方向:先切到"接收方"分支,再合并"提供方"。

    # 把 dev 合并到 main:先切到 main,再合并 dev
    git switch main
    git merge dev

    3.1 快进合并(Fast-forward)

    如果从共同祖先到目标分支是"一条直线"(main 没有新提交),Git 只需把指针向前移动,这叫快进合并。

    合并前:
    A ─── B (main)
    \\
    C ─── D (dev)

    git switch main
    git merge dev

    合并后:
    A ─── B ─── C ─── D (main, dev) ← main 指针直接前移,无新提交

    想禁止快进、强制产生一个合并提交(保留分支痕迹):

    git merge –no-ff dev

    合并后(–no-ff):
    A ─── B ────────── M (main)
    \\ /
    C ─── D (dev)

    3.2 三方合并(3-way merge)

    如果两边都有新提交,Git 会找到共同祖先,把两边的改动合并,并自动生成一个合并提交:

    合并前:
    C ─── D (dev)
    /
    A ─── B
    \\
    E ─── F (main)

    合并后:
    C ─── D (dev)
    / \\
    A ─── B M (main) ← 合并提交
    \\ /
    E ─── F

    git merge dev # 自动合并,弹出提交信息编辑器
    git merge dev -m "合并dev分支" # 指定合并提交信息
    git merge –abort # 合并出问题?放弃本次合并,回到合并前状态

    3.3 冲突及其解决(重点)

    当两个分支修改了同一文件的同一位置,Git 无法自动决定用谁,就会产生冲突:

    Auto-merging hello.c
    CONFLICT (content): Merge conflict in hello.c
    Automatic merge failed; fix conflicts and then commit the result.

    此时文件内容变成:

    <<<<<<< HEAD
    printf("hello from main");
    =======
    printf("hello from dev");
    >>>>>>> dev

    含义:

    • <<<<<<< HEAD 到 ======= 之间:当前分支的内容
    • ======= 到 >>>>>>> dev 之间:要合入的 dev 分支的内容

    解决步骤:

    # 1. 查看哪些文件冲突
    git status
    # 输出:both modified: hello.c

    # 2. 打开文件,手动编辑成最终想要的内容(删掉 <<<<<<< ======= >>>>>>> 这些标记行)
    # 例如改成:printf("hello from main and dev");

    # 3. 标记为已解决(把文件加入暂存区)
    git add hello.c

    # 4. 完成合并提交
    git commit # 直接提交即可(信息已预填)

    # 如果中途想放弃合并:
    git merge –abort

    [!tip] 减少冲突的技巧

    • 勤 pull:经常同步远程改动,冲突窗口更小
    • 小步提交:一次提交只做一件事
    • 分工清晰:避免多人长期同时改同一个文件
    • 冲突工具:命令行手改难受时,用 git mergetool 或 TortoiseGit 的三方合并工具(见 [[第7章:TortoiseGit功能详解]])

    4. 变基:git rebase

    rebase = 把当前分支的提交"搬"到另一个分支的最新提交之后,形成一条干净的直线历史。

    git switch dev
    git rebase main

    变基前:
    C ─── D (dev)
    /
    A ─── B ─── E ─── F (main)

    变基后(dev 的 C、D 被复制为 C'、D' 接到 F 后面):
    A ─── B ─── E ─── F (main)
    \\
    C' ─── D' (dev)

    4.1 merge 与 rebase 对比

    对比项mergerebase
    历史形状 分叉的(保留真实轨迹) 直线的(被整理过)
    是否改写提交 是(生成新哈希)
    冲突解决次数 一次 可能每个提交都要解决
    使用场景 公共分支合并 私人分支同步主分支

    [!warning] rebase 的黄金法则
    不要对已经推送到远程的公共分支执行 rebase! 因为它改写了提交历史,会让其他人的仓库与你的对不上。rebase 自己的私有分支则没问题。

    4.2 交互式变基(整理提交)

    git rebase -i HEAD~3 # 编辑最近 3 个提交

    编辑器会列出:

    pick f7f3f6d 修复了第一个问题
    pick 310154e 修复了第二个问题
    pick a5f4a0d 改正了错别字

    把 pick 改成其他指令(想调整提交顺序时,直接上下移动行即可):

    指令作用
    pick 保留该提交
    reword 修改提交信息
    edit 停下来修改该提交内容
    squash 合并到上一个提交,合并提交信息
    fixup 合并到上一个提交,丢弃本条信息
    drop 删除该提交
    exec 在该位置执行一条自定义命令(进阶)

    [!example] 常用场景
    把最近 3 个"改bug、再改bug、还改bug"的碎提交压成一个干净的提交:git rebase -i HEAD~3,后两条前面改成 squash 或 fixup。

    4.3 rebase 遇到冲突

    # 解决掉冲突文件后:
    git add <文件>
    git rebase –continue

    # 想放弃变基,回到变基前:
    git rebase –abort

    # 跳过当前这个提交:
    git rebase –skip

    4.4 等效的 pull –rebase

    拉取远程更新时,如果本地有提交,默认会产生合并提交。想用变基方式保持直线:

    git pull –rebase
    git config –global pull.rebase true # 永久设为默认行为

    5. 标签:git tag

    标签用于给某个提交起一个"永久性的名字",典型用途是标记版本号(v1.0、v2.1.3)。分支会移动,标签不会。

    5.1 创建标签

    git tag v1.0 # 轻量标签(只是个指针)
    git tag -a v1.0 -m "1.0 正式版发布" # 附注标签(含作者、日期、说明,推荐)
    git tag -a v1.0 9fceb02 # 给历史提交补打标签

    5.2 查看与检出

    git tag # 列出全部标签
    git tag -l "v1.*" # 按模式过滤
    git show v1.0 # 查看标签详情
    git switch -c hotfix v1.0 # 基于标签创建分支

    5.3 推送与删除标签

    标签不会随 git push 自动上传,要单独推:

    git push origin v1.0 # 推送单个标签
    git push origin –tags # 推送所有本地标签
    git tag -d v1.0 # 删除本地标签
    git push origin –delete v1.0 # 删除远程标签

    6. 常见分支模型

    6.1 Git Flow(经典模型)

    main ───●──────────────●────────●─── 只放正式发布
    \\ / /
    release ●──●──●───● / 发布准备
    \\ /
    develop ───●────●────●────●────●────●─── 日常开发主干
    \\ / \\ /
    feature ●───● ●────● 功能分支

    分支用途
    main 只包含已发布版本,每个提交打标签
    develop 开发主干,功能都先合到这里
    feature/* 每个新功能一个分支,完成后合回 develop
    release/* 发布准备(修 bug、改版本号)
    hotfix/* 线上紧急修复,从 main 拉出,修完合回 main + develop

    适合版本发布节奏明确的中大型项目,流程偏重。

    6.2 GitHub Flow(轻量模型)

    main ───●────●─────────●────●───
    \\ \\ / /
    feature ●────●─────● / 从 main 拉功能分支
    \\ /
    ●──────● 合并回 main 后可立即部署

    • 只有 main 一条长期分支
    • 任何改动都从 main 拉分支 → 提交 → 发起 Pull Request → 评审 → 合并
    • 合并即可部署,适合持续交付的 Web 项目

    6.3 适合个人 / 小团队的做法

    • 单人项目:直接一个 main 分支 + 定期打标签即可
    • 2-5 人:main + feature 分支 + PR 评审
    • 养成习惯:任何新功能、修复都开新分支,开发完合并回 main

    7. 本章小结

    • 分支本质是指向提交的可移动指针,创建/切换极快
    • 合并方向:先切到接收方,再 git merge 提供方
    • 冲突=同一位置被两边修改;解决=手动编辑 → git add → git commit
    • rebase 让历史变直线,但别动公共分支
    • 标签用于标记版本;git push –tags 才会同步到远程
    • 小团队推荐 GitHub Flow:main + 功能分支 + 合并
    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 第4章:Git分支与标签
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!