我需要在创建分支时确认/更正我的假设。如果我在主分支中,那么:
git checkout -b some_branch
这意味着我已经从大师那里开始了一个新的分支。
另一方面,如果我签出另一个分支,并在那里创建一个分支:
git checkout some_branch
git checkout -b other_branch
这意味着我使用some_branch提交的所有当前代码创建了other_branch,对吗?
而且,无论当前分支如何,如果这样做:
git branch branch_2 branch_1
然后将使用branch_1作为基础创建branch_2。 这些假设是否正确?
答案 0 :(得分:16)
Git中没有分支的基本分支。相反,只有一个当前提交,Git调用分支的提示。
为了直观地理解这一点,你应该从绘制(至少部分)Git的提交图开始。这是一个只有三个提交的小存储库的例子:
A <-B <-C <--master
&#34;真实姓名&#34;任何给定提交都是那些丑陋的哈希ID之一,c0ffeeface1deadbead...
等等。此哈希ID唯一地标识特定提交,实际上是通过散列(因此名称&#34;哈希ID&#34;)该提交的内容来 make 。它们看起来是随机的,不可能记住,所以在这里我只使用单个大写字母。
Git&#34;看到&#34;图表是通过读取分支名称开始的,例如master
。此分支名称包含C
之类的提交的哈希ID 。我们说master
指向提交C
。
同时,commit C
本身包含其先前(或父)提交B
的哈希ID。我们说C
指向B
,master
指向C
的方式相同。
同样,将B
提交回A
。 A
是有史以来的第一次提交,所以它无处可回指......所以它不是没有。我们将A
称为 root 提交,它让我们(和Git)停止向后工作。
这些内部箭头有点令人讨厌,请注意B
的哈希ID实际上是 C
本身的一部分,所以它永远不会改变(如果我们尝试更改C
的这一部分,我们得到一个新的不同的提交。所以我们可以停止打扰它们,然后写下来:
A--B--C <-- master
来自分支名称的箭头,不常量,并且提示的整个概念提交< / em>来自。
假设我们要向master
添加新提交。我们执行Git所需的所有常规设置(添加或修改某些文件并使用git add
),然后运行git commit
。 GIT中:
写出新的提交D
(获取新的唯一哈希ID)。这个新提交指向C
:
A--B--C <-- master
\
D
然后,更改 master
(或者更确切地说,它存储的哈希ID),以便它指向我们刚刚做出的新提交:
A--B--C
\
D <-- master
当然,没有理由在图纸中保留这种扭结:
A--B--C--D <-- master
这就是Git中分支增长的方式。
要创建一个 new 分支,Git只需创建指向某个现有提交的分支名称 :
A
\
B
\
C
\
D <-- master
我们可以选择其中任何一个提交并在那里创建一个新的分支名称。我们选择B
并将newbr
指向那里:
A
\
B <-- newbr
\
C
\
D <-- master
我们会使用git branch newbr <thing-that-finds-B>
执行此操作。
我们如何找到B
?好吧,一种方法是运行git log
并剪切并粘贴哈希ID。但另一种方法是使用分支名称。名称newbr
现在指向B
。如果我们想要另一个分支点也提交B
:
git branch thirdbr newbr
这使得Git查找newbr
,其指向B
,并创建新名称thirdbr
,其中......也指向B
:
A--B <-- newbr, thirdbr
\
C--D <-- master
这就是为什么在Git中创建一个分支的速度非常快:它几乎什么都没做!它只是制作一个指向某个现有提交的标签。
某些分支名称指向的提交称为该分支的提示提交。请注意,一次提交可以同时是几个分支的提示。这是关于Git的一个更重要的事情的一部分:一些提交在许多分支上,所有这些都在同一时间。例如,提交A
- 根提交 - 在每个分支上。 (它可能在存储库中有多个root提交,虽然它有点棘手,我们现在不需要担心。你无法做到这一点。到目前为止显示的命令。)
分支标签的特殊属性是移动。他们不仅会移动,还会自动移动。
我们在进行新提交D
时已经看到了这一点。 Git将新提交的ID写入master
。但是: Git如何知道使用master
?就此而言,Git如何让D
的父母成为C
?< / p>
嗯,当然我们当时只有一个分支,但现在让我们新提交 ,现在我们有三个标签master
,{{1 }和newbr
。首先,让我们做thirdbr
,然后绘制结果:
git checkout thirdbr
图纸中没有真正改变, 1 除了我在这里添加了A--B <-- newbr, thirdbr (HEAD)
\
C--D <-- master
这个词。 HEAD是Git知道哪个分支和提交是当前分支和提交。
现在我们执行常规修改文件HEAD
和git add
。 Git写出新的提交,其父设置为提交git commit
。 Git发现当前分支是B
而thirdbr
指向thirdbr
,因此当前提交是B
。让我们在新的提交B
中绘制:
E
唯一剩下的就是移动当前分支名称 E
/
A--B <-- newbr
\
C--D <-- master
,使其指向新提交thirdbr
:
E
我们已经完成了所有工作:我们已经为分支 E <-- thirdbr (HEAD)
/
A--B <-- newbr
\
C--D <-- master
添加了一个新提交(它仍然是HEAD,因此仍然是当前分支,但现在thirdbr
是当前提交)。
当您向当前分支添加提交时,它的HEAD会告知当前提交的内容以及新提交的位置。 HEAD通常包含分支的名称,并且这是E
的作用:它检查一个特定的提交 - 通常是现有分支的提示 - 然后设置文件git checkout
以记住名称的分支。它是记住提示提交的分支名称本身。
使用HEAD
表示:&#34;检查指定的提交,然后创建指向该提交的新分支名称 newname ,然后将HEAD设置为该新名称。&#34;如果省略 commit 部分,则默认使用HEAD。由于HEAD (总是)当前提交,Git会跳过&#34;结账&#34; part,只需创建新的分支名称并将其存储到git checkout -b newname commit
文件中。
1 虽然图中没有任何变化,但Git必须更新我们的工作树和索引,以便我们可以拥有他们在提交HEAD
时的文件。