分支概览 (Branches in a Nutshell)

Git 的分支功能经常被誉为它的“杀手级特性”。与其他版本控制系统(VCS)相比,Git 的分支模型之所以特别,是因为其极其轻量。分支操作(如创建和切换)几乎是瞬间完成的。

Git 数据存储方式

理解 Git 分支的关键在于理解 Git 存储数据的方式:Git 不存储一系列的变更集或差异(changesets),而是将数据存储为一系列快照
当你进行一次提交(commit)时,Git 会存储一个提交对象(commit object):
  • 它包含一个指向你已暂存内容快照的指针 HEAD。
  • 它包含作者姓名、邮件地址和提交消息。
  • 它包含指向其直接前一个或多个提交(其父提交)的指针。

什么是分支?

Git 中的分支本质上是一个指向某个提交对象的可变指针(a simple pointer or reference to the head of a line of work)。
  • 创建一个新分支(例如 testing)实际上只是创建了一个指向你当前所在提交的新指针。
  • master 分支并非特殊分支,它与其他任何分支完全相同,它之所以普遍存在,是因为 git init 命令默认创建它。
  • 分支的创建成本极低,只需要向一个文件写入 41 个字节(40 位的 SHA-1 校验和加上一个换行符),因此创建和销毁分支非常快速。

HEAD 指针

Git 使用一个名为 HEAD 的特殊指针来追踪你当前在哪个分支上工作。
  • HEAD 是一个指向你当前本地分支的指针。
  • 当你进行提交时,HEAD 指向的分支指针会自动向前移动到新的提交上。
  • 当你切换分支时(git checkout),HEAD 也会移动到新分支,并且 Git 会将你的工作目录重置到该分支所指向的快照状态。
notion image

基本分支与合并 (Basic Branching and Merging)

创建和切换分支

命令
描述
示例
git branch <name>
创建一个新指针(分支),指向当前提交,但不切换。
git branch testing
git checkout <name>
切换到现有分支,将 HEAD 移动到该分支,并更新工作目录以匹配其快照。
git checkout testing
git checkout -b <name>
创建新分支并立即切换到该分支(快捷方式)。
git checkout -b iss53
git switch <name>
(Git 2.23+ 推荐) 切换到现有分支。
git switch testing-branch
git switch -c <name>
(Git 2.23+ 推荐) 创建新分支并立即切换到该分支。
git switch -c new-branch
重要提示: 当你在 Git 中切换分支时,你工作目录中的文件会发生变化,以匹配切换到的分支的最后一次提交快照。如果你的工作目录或暂存区有未提交的更改与目标分支冲突,Git 将阻止你切换分支。

基本合并操作

当你完成在功能分支(例如 hotfix)上的工作并想将其集成到主分支(例如 master)时,需要使用 git merge 命令。
  1. 切换到目标分支: 首先需要切换到你希望合并入(接收更改)的分支。
  1. 执行合并:
      • git merge <source_branch>

两种合并类型

  • 快进(Fast-forward)合并: 如果当前分支的指针(master)是源分支(hotfix)的直接祖先,Git 会简单地将当前分支指针向前移动到源分支的末端提交。Git 不会创建新的提交对象。
  • 三向合并(Three-way Merge): 如果两个分支的历史已经发散(diverged),Git 会找到它们的共同祖先(Common Ancestor),并使用三个快照(两个分支的尖端和共同祖先)来创建一个新的快照。这个结果快照被记录为一个合并提交(Merge Commit),它具有多于一个父提交的特点。
notion image
notion image

合并冲突处理

如果 Git 无法干净地将两个分支的更改合并在一起(通常是因为修改了同一文件的同一部分),就会发生合并冲突。
  • Git 会在冲突文件中标记冲突区域。
  • 解决冲突后,需要运行 git add 来标记文件为已解决(暂存)。
  • 最后,运行 git commit 来完成合并提交。

分支管理 (Branch Management)

查看分支

命令
描述
git branch
列出所有本地分支。当前分支前缀有 *
git branch -v
查看本地分支及其最近一次提交。
git branch --merged
过滤显示已合并到当前分支的分支。这些分支通常可以安全删除。
git branch --no-merged
过滤显示未合并到当前分支的分支。试图用 -d 删除这些分支会失败。

删除和重命名分支

  • 删除已合并的分支: git branch -d <branchname>
  • 强制删除未合并的分支: git branch -D <branchname>(用于丢弃未集成的工作)。
  • 重命名本地分支: git branch --move <old-name> <new-name>
  • 删除远程分支: 需要使用 git push 并加上 -delete 标志。

分支工作流程 (Branching Workflows)

长期分支 (Long-Running Branches)

Git 的轻量级合并使得拥有多个常开的长期分支成为可能,这些分支用于表示不同的开发阶段。
  • master 通常只包含完全稳定的、已发布或即将发布的代码。
  • developnext 用于集成主题分支、进行测试,当稳定后可以合并到 master 中。
  • 这种方法使得项目历史看起来像指针在沿着提交的直线向上移动,稳定分支位于历史的较下游。

主题分支 (Topic Branches)

主题分支是针对单个特定功能或相关工作创建的短寿命分支
  • 主题分支在 Git 中非常常见,开发者可以一天创建、工作、合并和删除多次。
  • 它允许开发者快速且完整地进行上下文切换,因为所有的更改都围绕着一个主题(siloed),使得代码审查更容易。

远程分支 (Remote Branches)

远程跟踪分支命名

远程跟踪分支(Remote-tracking branches)是远程仓库状态的引用,它们是不可移动的本地指针。
  • 它们的命名遵循 <remote>/<branch> 的形式。
  • 例如,origin/master 指向你上次与 origin 服务器通信时其 master 分支的所在位置。

远程协作命令

  • 推送分支: 必须显式推送才能分享本地分支:
    • git push <remote> <branch>
    • Git 会自动展开分支名,例如 serverfix 会被展开为 refs/heads/serverfix:refs/heads/serverfix
  • 抓取数据: git fetch <remote> 命令获取远程服务器上你本地没有的所有数据,并更新你的远程跟踪分支(例如,将 origin/master 指针移动到新的位置)。
notion image
notion image

跟踪分支 (Tracking Branches)

跟踪分支是与远程分支有直接关系的本地分支。
  • 设置跟踪: git branch -u origin/serverfixgit branch --set-upstream-to origin/serverfix
  • 上游引用简写: 设置跟踪分支后,你可以使用 @ {upstream}@ {u} 简写来引用其上游分支。
  • 查看跟踪状态: git branch -vv 命令会列出本地分支,显示它们正在跟踪哪个远程分支,以及本地分支是领先 (ahead)落后 (behind) 还是同步

变基 (Rebasing)

变基(rebase)是 Git 中集成一个分支更改到另一个分支的第二种主要方法,目的是为了保持线性、整洁的历史记录

变基的基本概念

  • 变基操作是获取在一个分支上引入的更改的补丁(patch),并将其重新应用到另一个分支的顶端。
  • 语法: 切换到主题分支,然后对基准分支进行变基。
    • 变基本质上是将一系列提交“重放”(replay)到新的基点上。

    变基的工作原理

    变基会执行以下步骤:
    1. 找到两个分支的共同祖先。
    1. 获取你所在分支上每个提交引入的差异(diff),并保存到临时文件。
    1. 将当前分支重置到目标基准分支的同一提交。
    1. 依次应用保存的每个更改(提交)。
    结果是,在变基完成后,你通常可以对目标分支进行快进合并(fast-forward merge),最终的项目快照与标准合并的结果相同,但历史记录看起来是线性的,好像所有工作都是串行发生的。
    notion image
    notion image
    notion image

    变基的风险

    变基唯一的最大风险是:
    • 不要对已存在于你的仓库外部且可能有人基于其进行工作的提交进行变基
    • 变基会放弃现有提交,并创建新的、相似但不同的提交。
    • 如果你推送了变基后的提交,并有人基于旧的提交历史进行了工作,他们将不得不重新合并(re-merge)他们的工作,这会导致混乱。
    因此,通常的最佳实践是:在将工作分享给世界之前(即在推送到公共仓库之前),可以使用变基来清理和美化你的本地提交历史。
     
    学习笔记——Git 自定义学习笔记——Git 基础
    Loading...