Skip to content

搞英语 → 看世界

翻译英文优质信息和名人推特

Menu
  • 首页
  • 作者列表
  • 独立博客
  • 专业媒体
  • 名人推特
  • 邮件列表
  • 关于本站
Menu

git 分支:直觉与现实

Posted on 2023-11-23

你好!我一直在思考 git 分支,并且不断听到人们说他们发现 git 分支的工作方式是违反直觉的。这让我思考:分支的“直观”概念可能是什么,它与 git 的实际工作方式有何不同?

所以在这篇文章中我想简单谈谈

  • 我想很多人都有一个直观的心理模型
  • git 实际上如何在内部表示分支(“技术上正确”的定义)
  • “直观模型”和它的实际工作方式实际上是密切相关的
  • 直观模型的一些限制以及为什么它可能会导致问题

这篇文章中没有什么是开创性的,所以我会尽量保持简短。

直观的分支模型

当然,人们对分支有很多不同的直觉。我认为这是最接近物理上的“苹果树的树枝”隐喻的一个。

我的猜测是,很多人对 git 分支的看法是这样的:图中粉红色的 2 个提交位于一个“分支”上。

git-branch.png

我认为这张图有两点很重要:

  1. 该分支有 2 个提交
  2. 该分支有一个“父级”( main ),它是其分支

这看起来很合理,但这不是 git 定义分支的方式——最重要的是,git 没有任何分支“父”的概念。那么git是如何定义分支的呢?

在git中,一个分支就是完整的历史记录

在 git 中,分支是每个先前提交的完整历史记录,而不仅仅是“分支”提交。因此,在上面的图片中,两个分支( main和branch )都有 4 个提交。

我在https://github.com/jvns/branch-example制作了一个示例存储库,其分支设置方式与上图相同。让我们看看这两个分支:

main有 4 个提交:

 $ git log --oneline main 70f727a d f654888 c 3997a46 b a74606f a

mybranch也有 4 个提交。底部的两个提交在两个分支之间共享。

 $ git log --oneline mybranch 13cb960 y 9554dab x 3997a46 b a74606f a

因此mybranch有 4 个提交,而不仅仅是“分支”提交的 2 个提交13cb960和9554dab 。

你可以让 git 绘制两个分支上的所有提交,如下所示:

 $ git log --all --oneline --graph * 70f727a (HEAD -> main, origin/main) d * f654888 c | * 13cb960 (origin/mybranch, mybranch) y | * 9554dab x |/ * 3997a46 b * a74606f a

分支存储为提交 ID

在 git 内部,分支存储为微小的文本文件,其中包含提交 ID。该提交是分支上的最新提交。这就是我一开始所说的“技术上正确”的定义。

让我们看看示例存储库中main和mybranch的文本文件:

 $ cat .git/refs/heads/main 70f727acbe9ea3e3ed3092605721d2eda8ebb3f4 $ cat .git/refs/heads/mybranch 13cb960ad86c78bfa2a85de21cd54818105692bc

这是有道理的: 70f727是main上的最新提交, 13cb96是mybranch上的最新提交。

正如我之前提到的,这里缺少的一件事是这两个分支之间的任何关系。没有迹象表明mybranch是main的分支。

既然我们已经讨论了分支的直观概念是如何“错误”的,我想谈谈它在一些非常重要的方面如何也是正确的。

人们的直觉通常并没有那么错误

我认为告诉人们他们对 git 的直觉是“错误的”是很流行的。我觉得这很愚蠢——一般来说,即使人们对某个主题的直觉在某些方面在技术上是不正确的,人们通常也会出于非常合理的原因而拥有直觉! “错误”的模型可能非常有用。

因此,让我们讨论一下分支的直观“分支”概念与我们在实践中实际使用 git 的方式非常紧密匹配的 3 种方式。

变基使用分支的“直观”概念

现在让我们回到原来的图片。

git-branch.png

当你在main上 rebase mybranch时,它会获取“直观”分支上的提交(只有 2 个粉红色的提交)并将它们重播到main上。

结果是仅复制 2( x和y )。看起来是这样的:

 $ git switch mybranch $ git rebase main $ git log --oneline mybranch 952fa64 (HEAD -> mybranch) y 7d50681 x 70f727a (origin/main, main) d f654888 c 3997a46 b a74606f a

这里git rebase创建了两个新的提交( 952fa64和7d50681 ),其信息来自之前的两个x和y提交。

所以直观模型并没有那么错误!它准确地告诉您 rebase 中会发生什么。

但是因为 git 不知道mybranch是main的分支,所以您需要明确告诉它在哪里重新设置分支的基础。

合并也使用分支的“直观”概念

合并不会复制提交,但它们确实需要“基础”提交:合并的工作方式是它查看两组更改(从共享基础开始),然后合并它们。

让我们撤消刚才所做的变基,然后看看合并基是什么。

 $ git switch mybranch $ git reset --hard 13cb960 # undo the rebase $ git merge-base main mybranch 3997a466c50d2618f10d435d36ef12d5c6f62f57

这为我们提供了分支分支的“基础”提交3997a4 。这正是您认为可能基于我们的直观图景的提交。

github pull requests 也使用直观的想法

如果我们在 GitHub 上创建拉取请求以将mybranch合并到main中,它还会向我们显示 2 个提交:提交x和y 。这是有道理的,也符合我们对分支的直观概念。

gh-pr.png

我假设如果您在 GitLab 上发出合并请求,它会向您显示类似的内容。

直觉很好,但有一些限制

这使得我们对分支的直观定义实际上看起来相当不错!关于分支的“直观”想法与合并、变基以及 GitHub 拉取请求的工作方式完全一致。

在合并或变基或发出拉取请求时(例如git rebase main ),您确实需要显式指定另一个分支,因为 git 不知道您认为您的分支基于哪个分支。

但是分支的直观概念有一个相当严重的问题:你直观地思考main和分支分支的方式非常不同,而 git 不知道这一点。

那么让我们来谈谈不同类型的 git 分支。

主干和枝干

对于人类来说, main和mybranch是非常不同的,并且您对于如何使用它们可能有非常不同的意图。

我认为将某些分支视为“主干”分支,而将某些分支视为“分支”是很正常的。你也可以有一个分支的分支。

当然,git 本身并没有做出任何这样的区分(“分支”这个术语是我刚刚编造的!),但是它是一个什么样的分支肯定会影响你如何对待它。

例如:

  • 您可能会将mybranch重新设置为main ,但您可能不会将main重新设置为mybranch – 这会很奇怪!
  • 一般来说,人们在重写“主干”分支上的历史时比短命的分支分支要小心得多

git 让你“向后”进行变基

我认为人们对 git 感到厌烦的一件事是——因为 git 没有任何关于一个分支是否是另一个分支的“分支”的概念,它不会给你任何关于是否/何时适合对分支 X 进行变基的指导在Y分支上。你只需要知道。

例如,您可以执行以下任一操作:

 $ git checkout main $ git rebase mybranch

或者

$ git checkout mybranch $ git rebase main

Git 会很乐意让你做其中任何一个,尽管git rebase main非常正常,而git rebase mybranch则相当奇怪。

类似地,你可以“向后”合并,尽管这比向后变基要简单得多——出于不同的原因,将mybranch合并到main以及将main合并到mybranch都是有用的事情。

git 分支之间缺乏层次结构有点奇怪

我经常听到“ main分支并不特别”这样的说法,并且我一直对此感到困惑 – 在我工作的大多数存储库中, main非常特别!为什么人们说不是?

我认为重点是,即使分支之间确实存在关系( main通常很特殊!),git 对这些关系一无所知。

每次运行git rebase或git merge这样的 git 命令时,你都必须明确地告诉 git 分支之间的关系,如果你犯了一个错误,事情就会变得非常奇怪。

我不知道 git 在这里的设计是“对”还是“错”(它肯定有一些优点和缺点,我已经厌倦了阅读关于它的无休止的争论),但我确实认为这对很多人来说是令人惊讶的人们有充分的理由。

就这样!

回想起来,这一切似乎都非常明显,但我花了很长时间才弄清楚分支的更“直观”想法可能是什么,因为我太习惯了技术上的“分支是对提交的引用”定义。

我也没有真正想过 git 如何让你在每次运行git rebase或git merge命令时告诉它分支之间的层次结构 – 对我来说,这样做是第二天性,这不是什么大问题,但现在我在想,很容易看出有人会混淆。

原文: https://jvns.ca/blog/2023/11/23/branches-intuition-reality/

本站文章系自动翻译,站长会周期检查,如果有不当内容,请点此留言,非常感谢。
  • Abhinav
  • Abigail Pain
  • Adam Fortuna
  • Alberto Gallego
  • Alex Wlchan
  • Answer.AI
  • Arne Bahlo
  • Ben Carlson
  • Ben Kuhn
  • Bert Hubert
  • Bits about Money
  • Brian Krebs
  • ByteByteGo
  • Chip Huyen
  • Chips and Cheese
  • Christopher Butler
  • Colin Percival
  • Cool Infographics
  • Dan Sinker
  • David Walsh
  • Dmitry Dolzhenko
  • Dustin Curtis
  • Elad Gil
  • Ellie Huxtable
  • Ethan Marcotte
  • Exponential View
  • FAIL Blog
  • Founder Weekly
  • Geoffrey Huntley
  • Geoffrey Litt
  • Greg Mankiw
  • Henrique Dias
  • Hypercritical
  • IEEE Spectrum
  • Investment Talk
  • Jaz
  • Jeff Geerling
  • Jonas Hietala
  • Josh Comeau
  • Lenny Rachitsky
  • Liz Danzico
  • Lou Plummer
  • Luke Wroblewski
  • Matt Baer
  • Matt Stoller
  • Matthias Endler
  • Mert Bulan
  • Mostly metrics
  • News Letter
  • NextDraft
  • Non_Interactive
  • Not Boring
  • One Useful Thing
  • Phil Eaton
  • Product Market Fit
  • Readwise
  • ReedyBear
  • Robert Heaton
  • Ruben Schade
  • Sage Economics
  • Sam Altman
  • Sam Rose
  • selfh.st
  • Shtetl-Optimized
  • Simon schreibt
  • Slashdot
  • Small Good Things
  • Taylor Troesh
  • Telegram Blog
  • The Macro Compass
  • The Pomp Letter
  • thesephist
  • Thinking Deep & Wide
  • Tim Kellogg
  • Understanding AI
  • 英文媒体
  • 英文推特
  • 英文独立博客
©2025 搞英语 → 看世界 | Design: Newspaperly WordPress Theme