Git 中的分支


假设你正在开发 weather-app,写到一半时想试着加一个五日天气预报功能。这个功能可能要提交好几次才能调好,在调好之前,你肯定不想让那些没写完的代码,跟已经在正常给用户使用的那部分代码混在一起。分支正是 Git 用来解决这个问题的办法:开一条独立的工作线来放这个实验性功能,而 main 分支会一直保持你开始改动之前的样子,正常工作。
分支到底是什么
来看看它实际是怎么用的:
$ git branch forecast
$ git switch forecast
Switched to branch 'forecast'两条命令:第一条创建一个叫 forecast 的新分支,第二条把你切换到这个分支上。从这里开始,你做的每一次提交都会落在 forecast 上,而 main 会一直待在原地不动。
分支 本质上就是一个指向某次提交的、可以移动的标签。现在,main 和 forecast 都指向同一个提交——也就是你运行 git branch forecast 时所在的那个提交。一旦你在 forecast 上再次提交,这个标签就会往前移动到新的提交上。而 main 会一直待在原来的位置,直到你切换到它上面并亲自在那里提交。
用 git branch 可以同时看到这两个标签:
$ git branch
forecast
* main星号标记的是你当前所在的分支。分支说到底就是一个指向某次提交的名字。这就是它的全部原理。这一章接下来讲的内容,本质上都是围绕着如何移动这些标签展开的。
git branch forecast 会创建一个指向你当前提交的新标签,而 git switch forecast 会把你切换到这个标签上。在你真正提交之前,你的文件不会有任何变化。我喜欢把分支想象成贴在某次提交上的便利贴:添加起来很便宜,移动起来很便宜,用完撕掉也很便宜。 创建和切换分支
单独运行 git branch forecast 只会创建这个标签,不会把你切换过去。大多数时候你想要一步到位,所以 git switch 提供了一个快捷方式:
$ git switch -c forecast
Switched to a new branch 'forecast'-c 代表“create”(创建)。git switch -c 会同时创建分支并把你切换过去。几乎每次开始新工作时,你都会用这一条命令。
切换分支会改变你的文件呈现出的是哪个快照。试试看:下面的 echo 命令是快速创建新文件 src/forecast.js 并写入一行内容的简便写法,其余的都是你已经熟悉的命令:
$ git switch forecast
$ echo "// 五日预报逻辑" > src/forecast.js
$ git add src/forecast.js
$ git commit -m "Start forecast module"
$ ls src
forecast.js index.js
$ git switch main
Switched to branch 'main'
$ ls src
index.js这个文件并没有消失。它一直存在于 forecast 分支上,只是 main 分支的快照从来就没包含过它。切回 forecast,它就会原样重新出现。
git switch -c forecast 一步创建分支并切换过去,这也是你几乎每次都会用到的方式。切换分支会换掉你看到的文件版本,所以在一个分支上新加的文件,在另一个分支上是看不到的,除非你切回来。什么都没丢,只是暂时停在另一个分支上而已。 HEAD 和分离头指针
Git 用一个叫 HEAD 的标记来记录你当前所在的位置。通常情况下,HEAD 指向你当前所在的分支,而那个分支又指向某次提交,所以每次你切换分支或提交时,HEAD 都会自动跟着移动。但如果你不是通过分支名,而是通过哈希值检出某个具体的提交,或者检出一个标签(tag,一种固定钉在某次提交上的标签,常用来标记发布版本),HEAD 就会直接挂到那一个提交上,而不再挂在某个分支标签上。这种状态被称为“分离头指针”(detached HEAD)。
在这种状态下,你可以随意浏览,甚至可以提交,但没有任何名字指向这些新提交。如果你不先创建一个分支就切换到别的分支上去,这些提交就会变得很难再找回来。
$ git switch a1b2c3d
HEAD is now at a1b2c3d Add password strength meter“HEAD is now at”这条提示信息,就是 Git 在告诉你:你已经离开了分支的地界,HEAD 现在直接挂在了某一个提交上。
接下来该学什么
到这里,你已经学会了创建分支、在分支之间切换,也见到了当你在别处做实验时,main 是怎么保持不动的。接下来的问题是,分支上的工作要怎么合并回 main,这正是合并与冲突要讲的内容。如果你想在往下学之前,先回顾一下如何查看提交历史,历史记录会带你过一遍 git log、git show 和 git diff。

