创建新分支时的基本分支是什么?

时间:2017-04-21 19:10:59

标签: git github branch

我需要在创建分支时确认/更正我的假设。如果我在主分支中,那么:

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。 这些假设是否正确?

1 个答案:

答案 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指向Bmaster指向C的方式相同。

同样,将B提交回AA是有史以来的第一次提交,所以它无处可回指......所以它不是没有。我们将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知道哪个分支和提交是当前分支和提交。

现在我们执行常规修改文件HEADgit add。 Git写出新的提交,其父设置为提交git commit。 Git发现当前分支是Bthirdbr指向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时的文件。