Git不是魔法 - 第2部分:你在时间线的哪个位置?
Source: Dev.to
The Pointer Called HEAD
现在我们已经知道提交形成了一个指向过去的链表,但还有一个关键点缺失:我们现在到底在什么位置?
在 Git 中,这个“你在这里”的标记叫 HEAD。HEAD 只是一个指针。它指向你当前查看的提交——大多数情况下,是最新的提交(即项目时间线的当前时刻)。
commit 0 # moves HEAD to wherever you tell it to go.
大多数时候,HEAD 指向一个 branch(分支),而分支指向一个提交。当你创建新提交时,分支向前移动,HEAD 随之移动。记住这一点,下面我们会讨论分支。
Branches: Multiple Timelines
假设在做三层蛋糕时,你突然想到:“要不也做个巧克力版?”你不想把原来的香草蛋糕弄坏,但又想尝试新点子。
于是你拍一张当前状态的宝丽来,开始另一本相册来记录巧克力版。两块蛋糕从同一点出发,随后各自演变。这就是 branches(分支)的概念。
分支只是指向某个提交的标签。创建新分支就相当于从当前时间线分叉出一条新时间线。
← commit 4 (chocolate-version)
/
commit 0 <- commit 1 <- commit 2 <- commit 3 (main)
你可以在 chocolate-version 上工作,提交更改,随意实验——而 main 保持不变。原来的香草蛋糕依旧安全。
Merging: Bringing Timelines Together
实验完后,你发现巧克力版非常棒,想把这些改动合并回主蛋糕配方。这叫 merging(合并)。
合并时,你告诉 Git:“把这条备用时间线里发生的一切,和我当前的时间线合并。”
commit 0 <- commit 1 <- commit 2 <- commit 3 <- commit 5 (merge commit)
\ /
← commit 4 (chocolate-version)
Git 会创建一个特殊的合并提交,它有两个父提交——分别来自两条时间线。大多数情况下 Git 能自动合并更改,但有时两条时间线在同一文件的同一位置做了不同修改,就会出现 merge conflicts(合并冲突)。此时需要手动解决冲突,然后完成合并。
Rebasing: Rewriting History
如果你不想要杂乱的合并提交,而更倾向于一条干净的线性历史,可以使用 rebase(变基)。
变基相当于说:“把我所有的实验性提交,假装它们是从另一个时间点开始的。”
变基前:
← commit 4 (chocolate-version)
/
commit 0 <- commit 1 <- commit 2 <- commit 3 (main)
变基后:
commit 0 <- commit 1 <- commit 2 <- commit 3 <- commit 4' (chocolate-version)
(main)
提交 4 变成了一个新的提交 4′,内容相同但父提交不同。你已经重写了历史,使其线性且整洁。
黄金法则: 切勿对已经与他人共享的提交进行变基。重写共享历史会给协作者带来混乱。
可以这么理解:合并是诚实的(它展示了两条时间线都真实发生),变基是整洁的(它假装只有一条时间线)。
You’ve Got the Power Now
- HEAD 是指示你所在位置的指针。
- Branches 是让你的代码拥有平行宇宙的标签。
- Merging 诚实地把时间线合在一起。
- Rebasing 重写历史,让一切保持整洁。
到目前为止,这一切都发生在你的机器上——你的个人“相册”。
当你想把这些相册分享给团队时会怎样?如何保持所有人的时间线同步?这就是 Part 3 的重点。