用乐高类比解释 Git 分支

使用这个有用的乐高类比来理解在 Git 中分支位置的重要性。
2 位读者喜欢这个。
Open Lego CAD
图片版权:CC BY-SA 4.0 Klaatu Einzelgänger

在代码仓库中创建新分支是在使用 Git 时非常常见的任务。它是将不相关的更改彼此分离的主要机制之一。它通常也是决定什么被合并到主分支的主要指示器。

如果没有分支,一切都必须进行 cherry-pick,否则你所有的工作都将有效地合并为 squash rebase。问题是,分支继承了它们所 fork 的分支的工作,这可能导致你意外地推送了你从未打算放入新分支的提交。

解决方案是始终从 main 分支 fork(除非你不想这样做)。这是一个很容易说的规则,但不幸的是它也同样容易忘记,所以了解规则背后的原因可能会有所帮助。

分支不是文件夹

很自然地会将 Git 分支视为文件夹。

但它不是。

当你创建一个分支时,你并没有创建一个干净的环境,即使它看起来像是那样。一个分支继承了其父分支包含的所有数据。如果父分支是 main 分支,那么你的新分支包含你项目的共同历史记录。但是如果父分支是另一个从 main 分支分出来的分支,那么你的新分支将包含 main 分支的历史记录以及另一个分支的历史记录。我经常用乐高积木来思考,所以这里有一个视觉示例,它不是那些复杂的 Git 节点图(但实际上是,暗地里是)。

假设你的 main 分支是一个乐高底板。

Main branch

(Seth Kenlon CC BY-SA 4.0)

当你从 main 分支创建一个分支时,你添加了一块积木。假设你添加了一个名为 blue 的分支。

Main and blue branches

(Seth Kenlon BY-SA 4.0)

blue 分支包含底板的历史记录以及你在 blue 分支上所做的任何工作。在代码中,这是目前发生的情况

$ git branch
* main
$ git checkout -b blue

分支的分支

如果你在 blue 分支中又创建了一个分支,那么你是在 mainblue 的基础上构建的。假设你创建了一个名为 red 的分支,因为你想开始构建一个新功能。

Main and blue and red branches

(Seth Kenlon CC BY-SA 4.0)

这本身并没有什么问题,只要你理解你的 red 分支是建立在 blue 分支之上的。你在 blue 分支中所做的所有工作也存在于 red 分支中。只要你不想让 red 成为一个全新的开始,包含 main 分支的历史记录,这是一种完全可以接受的构建 repo 的方法。但是请注意,项目所有者无法,例如,在不接受一堆 blue 更改的情况下接受 red 更改,至少不经过很多麻烦是不行的。

干净的分割

如果你实际上想做的是将 bluered 开发为单独的功能,以便项目所有者可以选择合并其中一个而不是另一个,那么你需要这两个分支都只基于 main。这很容易做到。你只需先检出 main 分支,然后从那里创建你的新分支。

$ git branch
* blue
main
$ git checkout main
$ git checkout -b red

这是乐高积木中的样子

Main, blue, and red branches

(Seth Kenlon CC BY-SA 4.0)

现在你可以只将 blue 交付给项目所有者,或者只交付 red,或者两者都交付,项目所有者可以决定将什么附加到官方仓库中的 main 分支。更好的是,bluered 都可以继续单独开发。即使你完成了 blue 并将其合并到 main 中,一旦 red 的开发人员合并了来自 main 的更改,那么之前的 blue 就可以用于新的 red 开发。

Image of a lego git branch

(Seth Kenlon CC BY-SA 4.0)

分支示例

这是一个这个原则的简单演示。首先,创建一个带有 main 分支的 Git 仓库

$ mkdir example
$ cd example
$ git init -b main

用一个示例文件填充你新生的项目

$ echo "Hello world" > example.txt
$ git add example.txt
$ git commit -m 'Initial commit'

然后检出一个名为 blue 的分支,并进行一个你不想保留的愚蠢提交

$ git checkout -b blue
$ fortune > example.txt
$ git add example.txt
$ git commit -m 'Unwisely wrote over the contents of example.txt'

查看日志

$ git log --oneline
ba9915d Unwisely wrote over the contents of example.txt
55d4811 Initial commit

首先,假设你很高兴继续在 blue 之上进行开发。创建一个名为 red 的分支

$ git checkout -b red

查看日志

$ git log --oneline
ba9915d Unwisely wrote over the contents of example.txt
55d4811 Initial commit

你的新 red 分支,以及你在 red 中开发的任何内容,都包含你在 blue 中进行的提交。如果那是你想要的,那么你可以继续开发。但是,如果你打算重新开始,那么你需要从 main 而不是 blue 创建 red 分支。

现在检出你的 main 分支

$ git checkout main

查看日志

$ git log --oneline
55d4811 Initial commit

到目前为止看起来不错。blue 分支与 main 分支隔离,因此它是一个干净的基础,可以从中向不同的方向分支。是时候重置演示了。因为你还没有在 red 分支上做任何事情,所以你可以安全地删除它。如果这发生在现实生活中,并且你已经开始在 red 分支上开发,那么你必须将你的更改从 red cherry-pick 到一个新分支。

不过,这只是一个演示,所以可以安全地删除 red 分支

$ git branch -D red

现在创建一个名为 red 的新分支。这个版本的 red 旨在作为一个全新的开始,与 blue 分支不同。

$ git checkout -b red
$ git log --oneline
55d4811 Initial commit

尝试进行新的提交

$ echo "hello world" >> example.txt
$ git add example.txt
$ git commit -m 'A new direction'

查看日志

$ git checkout -b red
$ git log --oneline
de834ff A new direction
55d4811 Initial commit

最后再看一下 blue 分支

$ git checkout blue
$ git log --oneline
ba9915d Unwisely wrote over the contents of example.txt
55d4811 Initial commit

red 分支有它自己的历史记录。

blue 分支有它自己的历史记录。

两个不同的分支,都基于 main 分支。

谨慎 fork

和许多 Git 用户一样,我发现使用 Git 感知提示符更容易跟踪我当前的分支。在阅读了 Moshe Zadka 关于它的文章后,我一直在使用 Starship.rs,我发现它非常有用,尤其是在对一个打包项目进行大量更新时,该项目要求所有合并请求都只包含一个分支上的一个提交。

随着数百个更新在 20 个或更多参与者之间进行,管理这种情况的唯一方法是经常检出 main 分支,pull,并创建一个新分支。Starship 立即提醒我当前的分支以及该分支的状态。

从 main 分支还是从另一个分支 fork 新分支取决于你想实现什么。重要的是你要明白,你在哪里创建分支很重要。请注意你当前的分支。

标签
Seth Kenlon
Seth Kenlon 是一位 UNIX 极客、自由文化倡导者、独立多媒体艺术家和 D&D 爱好者。他曾在电影和计算机行业工作,经常同时进行。

2 条评论

用乐高作为例子真是太棒了!
谢谢!

顺便说一句:到 starship 文章的链接是错误的,并给出了 404 错误。应该是这个

https://open-source.net.cn/article/22/2/customize-prompt-starship

问候!

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 许可。
© . All rights reserved.