因此,我试图寻找答案,但发现的只是版本控制的方案不同,而没有区别。
答案 0 :(得分:3)
像您来自svn的声音。...树干可能只是另一个分支 ......就像您可能会创建的其他任何分支一样。 svn中通常称为Trunk的git在git上称为 master ,但是实际上,这是一个约定,因为没有要求在回购协议上拥有master分支,只是大多数回购协议都拥有它。 ..如果愿意,您可能在git中有一个名为trunk的分支。
答案 1 :(得分:2)
Git没有“主干”(尽管您可以假装任何特定分支都是您的“主干”)。
从某种意义上讲,Git也没有分支。这实际上取决于您如何定义分支。参见What exactly do we mean by "branch"?当然,如果我们以更有用的方式定义单词 branch ,则Git 确实具有分支。它们与SVN分支完全不同。
有趣的是,从某种意义上讲,SVN本身也没有分支。这是Red Bean book的引文:
您应该记住本节中的两个重要课程。首先,Subversion没有分支的内部概念,它只知道如何制作副本。复制目录时,结果目录只是一个“分支”,因为您将其附加到该目录。您可能会以不同的方式考虑目录,或者以不同的方式对待目录,但是对于Subversion而言,它只是一个普通目录,恰好带有一些其他历史信息。
对于Git,要记住的重要一点是Git与 commits 有关。提交是Git的主要leitmotif。每个提交都包含源代码的完整快照以及一些元数据:有关提交的信息。每个提交都有一个唯一的哈希ID, 1 保留给那个提交,而仅那个提交。例如,b697d92f56511e804b8ba20ccbe7bdc85dc66810
是在Git存储库的任何克隆中针对Git本身的提交,即Git 2.22。任何地方的其他提交都不会具有那个哈希ID。 2
因为每个提交都有一个唯一的哈希ID,所以我们(至少是Git)可以讨论或找到仅给出哈希ID的提交。因此,通常,每个提交都在其元数据中存储其他一些早期提交的哈希ID。具体来说,我们(或Git)最关心的较早提交是提交的直接 parent 的哈希ID:在提交之前 的那个。 / p>
请注意,当我们进行 new 提交时,我们知道 确切地应该在我们现在进行的新提交之前先进行。这是因为我们通过使用git checkout
检出一些现有提交来进行 new 提交。然后,我们进行该提交并执行git add
命令并运行git commit
。新的提交应具有我们检出的提交的哈希ID作为其父项。
让我们快速看一下它是如何工作的。但是,提交哈希ID大而丑陋,仅人类无法使用(通过剪切和粘贴除外),因此,让我们使用单个大写字母来代表这些提交。让我们来看一个简单的微型存储库,其中包含三个提交,并按我们按此顺序创建它们的过程分别称为A
,B
和C
。每个提交都存储其父级的哈希ID,该哈希ID构成了一个向后指向的提交链:
A <-B <-C
也就是说,提交C
说我的父母是B
,而B
说我的父母是A
。 A
没有父母-不能,这是第一次提交。技术术语是A
是 root提交,当您在新存储库中进行第一次提交时,您会看到[root commit]
由Git打印。 sup> 3
如果我们检出提交C
,对其进行一些工作,然后运行git commit
,Git将:
C
的哈希ID作为此新提交的父项放入元数据;和由于新提交D
的父级是C
,因此会自动扩展链:
A <-B <-C <-D
当然,D
获得了一个提交哈希ID,该ID大而丑陋,并且对于D
而言是唯一的,我们不可能记住它。但是我们不需要记住它:这就是计算机的用途。通过将实际的哈希ID存储在某些名称中,让计算机记住它。
该名称通常是分支名称,例如master
。也就是说,在制作D
之前,图片确实看起来像这样:
A--B--C <-- master
名称master
记住提交C
的实际哈希ID。我们运行git checkout master
,Git使用 name 查找ID,并使用ID查找提交,这将内容带入工作树,以便我们可以对其进行处理。 4
我们完成工作并运行git add
和git commit
并进行新的提交D
。 git commit
的 last 步骤是Git将D
的实际哈希ID(无论是什么)写入名称master
:
A--B--C--D <-- master
master
不再记得C
,而是D
;但这没关系,因为 D
记得C
。 master
在更早的时候记住了A
;然后它想起了B
,它想起了A
;然后它记住了C
。现在它记得D
。
要在Git中创建一个 new 分支,只需告诉它起一个新名称,指向一些现有的提交,如下所示:
A--B--C--D <-- master, feature
现在的诀窍是让Git在运行git commit
时记住要更新的分支名称,这就是所有大写字母中的特殊名称HEAD
出现的地方in。当您运行git checkout master
时,Git会将名称HEAD
附加到名称master
上:
A--B--C--D <-- master (HEAD), feature
运行git checkout feature
时,Git会将HEAD
附加到feature
上:
A--B--C--D <-- master, feature (HEAD)
两个检出命令均提取提交D
,这是存储所有文件的位置。此时,两个分支都具有所有四个提交-但是,如果您在feature
上并立即进行新提交,则该新提交将获得一个新的大的丑陋哈希ID,我们将致电E
。新提交以D
作为父提交,并且作为git commit
的最后一步,Git将E
的哈希ID写入feature
,因为在那里HEAD
附件:
A--B--C--D <-- master
\
E <-- feature (HEAD)
如果我们现在运行git checkout master
,Git将提交D
放回到我们的工作树中,并将HEAD
附加到master
。如果现在再进行一次新提交,则新提交的父级再次为D
,这次master
得到更新:
F <-- master (HEAD)
/
A--B--C--D
\
E <-- feature
这些提交(这些向后看的链)形成一个图,从技术上讲是有向无环图。实际上,诸如master
和feature
之类的分支名称只是 labels 指向图中的特定节点。当您说“分支功能”时,请注意您是说名称 feature
,还是提交E
,或者提交E
+ D
+ C
+ B
+ A
或其他任何方式。
在Git中,分支名称只是指向一个特定提交的标签。 分支本身是通过从该提交开始并在图形中向后工作而找到的。该图由提交及其父级链接组成。
在SVN中,正如Red Bean所说,分支是目录的副本(加上一些元数据)。对于Git,情况并非如此-单词 branch 含糊不清,有时表示 name ,持有提交哈希ID的短标签,有时表示通过以名称中的哈希ID开头找到的总体提交图。当用“分支”表示“一组提交”时,是那些提交而不是某些目录。
1 这些哈希ID实际上是提交数据(快照和元数据)的加密校验和。因此,无法更改任何提交。如果您实际获取原始提交数据,则可以通过git cat-file -p
;尝试git cat-file -p HEAD
一段时间-对其进行一些更改,然后将其存储回Git,您将得到一个具有自己唯一的新哈希ID的 new和different commit 。您可以将Git视为包含提交的仅附加数据库。严格来说,这不是真的,但这是一个很好的第一近似值。
2 从技术上讲,这仅意味着Git的任何Git存储库都无法重复使用该哈希ID。如果您自己的项目不是Git的来源,并且从未连接到Git的Git存储库,则可以使用该哈希ID。很有可能永远不会这样做:您所做的每个提交只有2个 160 机会中的1个给我们 哈希ID。 2 160 是一个非常大的数字:1,461,501,637,330,902,918,203,684,832,716,283,019,655,932,542,976,或short scale中约十五亿分之十。
3 分支名称必须指向一些现有的提交。这就带来了一个问题:在一个新的完全空的存储库中,没有提交,因此就没有分支。进行第一次提交(即新存储库的根提交)的操作将创建初始分支名称,通常为master
。您可以稍后通过使用git checkout --orphan
或通过使用git fetch
对另一个具有无关历史记录的Git存储库进行新的root提交,但是典型的Git存储库往往只有一个 根提交。一个根提交位于每个分支上!
4 由于密码校验和哈希ID,每次提交都被冻结。但这对于每次提交保存的快照也是如此。提交内的文件(从技术上讲只是Git对象数据库中的更多对象)也一直被冻结,并保存在特殊的只读Git压缩文件中格式。因为它们是只读的,所以可以在不同的提交之间进行共享共享,从而节省了大量空间:您可能有一个包含4000个文件的项目,并且更改了2个并进行了一次新提交。 Git在新提交中重新保存每个文件,但是其中3998个实际上只是在重新使用先前的快照:只有2个新快照。
这对于存档非常有用,但是对实际工作没有用。这些文件全部都是这种冻干的仅Git格式,您的计算机需要使用其日常文件格式。因此,Git必须解压缩冻干的文件,然后重新补水。这些复水的副本进入您的工作树中,您可以在其中查看和处理它们。您永远不会直接处理Git内副本。
此文件冻干和补水的过程使用中间区域,Git有时将其称为 staging area ,有时将其称为 index 。这两个词是同一事物的术语。重要的是要意识到索引/暂存区具有当前提交中的每个文件的副本,并且Git从索引/暂存区而不是来自 进行新的提交。工作树,但我们在这里不做进一步介绍。