【问题标题】:Commits on Tag and How It Merges with the Latest Version of Git Repository提交标签以及它如何与最新版本的 Git 存储库合并
【发布时间】:2017-07-12 01:17:37
【问题描述】:

好吧,我对 Git 不太熟悉。我被要求从某人的存储库中克隆一个存储库,然后使用该标签。所以这就是我所做的:

git clone someones_repo my_new_repo
git checkout tags/bla_bla_tag -b tag_branch

所以现在我在标签版本中,而不是在 master 分支中,而是在 tag_branch 中。

我做了更改,想提交它们并将它们与我的主文件合并,然后将我的更改提交到我们的官方存储库(我认为他们称之为黄金存储库)。以下是我的担忧:

  1. 这个“master”分支是否包含我克隆的最新版本的 repo?还是包含标签的版本?
  2. 如果 master 是标签的版本,然后我将我的更改合并到它,那么如果我将这些合并的更改提交到我们的官方 repo 会发生什么?官方 repo 的最新版本会成为我合并更改的版本吗?如果有人试图克隆官方 repo,那么他会得到我的合并版本吗?。

【问题讨论】:

    标签: git version-control git-merge git-tag


    【解决方案1】:

    对于您的问题:

    1. 对于你克隆的repo,只能确定你克隆的时间是最新版本。如果您的同事在您克隆后对他的 repo 进行了一些更改,那么您的本地 repo 不是最新版本。克隆的 repo 包含您同事的 repo 中存在的标签。有一种方法可以通过以下方式检查您的本地仓库是否为最新版本:

    git fetch origin git log master..origin/master

    如果有输出,说明你的本地master不是最新版本,你应该使用git pull拉取更改。

    1. 如果您使用的标签在 master 分支上,并且您将更改合并到 master 中,则官方 repo 的最新版本将成为您合并的新版本。之后,如果不克隆官方repo,master分支最新版本也是你合并的版本。

    PS:如果你和你的同事都在为官方 repo 工作,你应该首先从官方 repo 中克隆。

    【讨论】:

      【解决方案2】:

      已经有一些很好的答案,但您真正可以在这里使用的是图形说明。

      理解分支和标签如何在 Git 中工作的关键是要认识到分支和标签 names 仅仅是辅助工具。他们几乎没有真正制作分支。 “分支”这个词本身在 Git 中实际上是模棱两可的。要查看有关此内容和几个图表的更多信息,请单击 What exactly do we mean by "branch"? 这描述了分支标签如何选择特定提交,尽管不是分支增长的过程。 (另请注意,Pro Git 书中的第一个图像很好,但和 Jubobs 一样,我不喜欢第二个 Pro Git 图像。)

      我在 StackOverflow 帖子中使用了一种更简单的图表方法。以这个只有三个提交的存储库示例图为例。这三个提交中的每一个都有一个实际的哈希 ID——其中一个是那些缩写为 badf00dcafedad 等等的丑陋的 40 个字符的东西——但我只给它们一个字母的名称,并将分支名称放在上面右边:

      A <- B <- C   <-- master
      

      这里C 是我们最新的提交,在分支master。分支 name master 包含提交 C 的实际哈希 ID,例如 ac0ffee4cafedad5badf00d... 或其他。提交C 本身——实际的提交,存储在Git 的数据库中——有提交B 的ID。我们说master 指向 C,而C 指向BB 的 ID 为 A,因此它指向 AA 是任何人第一次提交,所以它不能指向任何地方。用 Git 的话来说,它没有 parent;这是一个根提交

      请注意,在这个系统中,父提交不知道他们有哪些孩子,但孩子确实知道他们的父母。为了在master 上进行新的提交,Git 将一些内容写入数据库,以新的提交对象结束。新的提交——我们称之为D——包含当前提交的 ID 作为其父提交,因此D 指向C。然后 Git 更新分支 namemaster,使其指向D

      A <- B <- C <- D
      

      (正如最近有人指出的那样,这很像挖掘家谱记录:你会发现“鲍勃琼斯,父母是亚瑟和莎莉”。显然鲍勃的出生记录不能列出 25 年后他会有一个女儿,所以它没有。同样,当你提交时,Git 知道提交的 parent 是谁,但它不知道提交是否会有孩子。)

      考虑到这一点,请考虑这个图形片段。我已经停止绘制内部箭头以节省空间等,但请记住,它们总是指向 向后(在这些图中向左):

      ...--D--E--F   <-- master
            \
             G--H    <-- sidebr
      

      我们通过在master 上进行两次新提交,即EF,以及通过创建一个新分支名称sidebr,指向提交@ 到达这里987654352@。然后我们git checkout sidebr 进行两次新的提交。它们是GH。当我们制作G 时,提交D 是当前的,并且是sidebr 指向的内容。因此,Git 以D 作为其父级写入提交,并将sidebr 更改为指向G。现在 G 是最新的,我们以 G 作为其父提交新的提交 H,并更新 sidebr 以指向 H,这就是我们得到这个图表的方式。

      标签时间

      现在是为这些图片添加标签的时候了。标签几乎(但不完全)与分支相同。与分支名称一样,标签名称 指向 提交。主要区别1 是分支名称​​应该 移动:它们通过添加新提交自动增长。标签名称​​不应该移动。

      因此,我们不妨将它们绘制在提交图的“内部”,而不是在右侧。 (或者,如果我们有颜色,我们可以为分支和标签名称使用不同的颜色——但我不能在 StackOverflow 上的文本中使用颜色。)所以让我们添加一个指向提交 E 的标签名称:

           tag:v0.1
              |
              v
      ...--D--E--F   <-- master
            \
             G--H    <-- sidebr
      

      这个标签指向提交E。它应该永远永远指向提交E2 关于原始 Git 哈希 ID 有一个有趣的事实,在这里非常相关:哈希 ID 是完全确定的,并且完全基于提交的实际内容(或其他 Git 对象)。因此,标签名称只不过是为那些糟糕的哈希 ID 之一提供了一个人类可读的名称。如果我们都能记住17f9f635c101aef03874e1de1d8d0322187494b3,我们就不需要Git 存储库中的标签v2.6.0——但肯定不会记住这一点。3支持>

      在任何情况下,您都可以git checkout 任何通过其 ID 或任何解析为其 ID 的提交。标记名称适用于后者,当然更容易记住。因此,鉴于上图,我们可以通过以下方式检查提交 E

      git checkout v0.1
      

      tag: 不是标签名称的一部分,只是我写的东西来说明为什么我们在这里有一个箭头)。然而,这给了我们一个“分离的 HEAD”,这就是为什么我们 git checkout -b newbranch v0.1: 分配一个新的分支 name 来指向提交。现在我们需要重新绘制图表以提供更多空间:

           tag:v0.1
              |
              |  F   <-- master
              v /
      ...--D--E      <-- newbranch (HEAD)
            \
             G--H    <-- sidebr
      

      我还添加了这个HEAD 的东西:这提醒我们现在这个新分支。如果我们现在进行新的提交,这将按照通常的方式增长分支:

           tag:v0.1
              |
              |  F   <-- master
              v /
      ...--D--E--I   <-- newbranch (HEAD)
            \
             G--H    <-- sidebr
      

      不应该移动的标签不会移动。 分支,然而,确实移动。我们可以进行任何我们喜欢的提交,并且每个提交都使当前分支(newbranch)提前合并我们的每个新提交。


      1另一个重要的区别是标签名称存在于所有存储库的共享名称空间中,而分支则不存在。还有带注释的标签,让您有机会附加一些未解释的数据,Git 允许您使用 GPG 加密签署此类标签。但这是另一个讨论。

      2可以强制移动标签,或者删除它并重新创建它指向不同的提交。有时甚至有充分的理由这样做。您只需要确定原因特别好,因为标签实际上只是哈希 ID 的人类可读名称,并且任何已经具有旧标签的存储库都可能认为旧标签到哈希- ID 映射仍然正确,即使您已强制移动标签。

      3我使用git rev-parse v2.6.0 找到它。上面的哈希 ID 是带注释的标记对象的 ID(您可以通过克隆 Git 的 Git 存储库来找到它)。实际提交是be08dee9738eaaa0423885ed189c2b6ad8368cf0。有一种特殊的语法可以一步找到commit ID,例如使用git rev-parse,也可以使用git show v2.6.0读取标签对象,然后git show标签的目标对象查看提交。

      【讨论】:

        【解决方案3】:

        我不确定您所说的“将更改提交到主仓库”是什么意思。我希望它是一个拉取请求,而不是直接推送到黄金回购

        1. 您本地分支的 master 将与该某人的 repo 的 master 相同。如果这两个 repo 定期保持同步,它可能与黄金 repo 的 master 相同。

        2. 标签只是你添加到某个提交的标签,通常用于 master 中的提交。如果您的拉取请求被合并,黄金仓库中的主服务器将成为您的主服务器版本。如果有人克隆了黄金仓库,他们将获得您的请求版本。

        我建议为此使用拉取请求工作流程。否则丢失提交的机会非常高

        【讨论】:

          【解决方案4】:

          当您从“标签”创建分支时,您会创建一个指向提交的指针。标签指向一个提交,你的分支也像一个指向这个提交的指针。如果没有更多信息,这个提交是否在主分支上是不可能的。

          要获取最新的master,你可以git fetch,最新的master将在origin/master

          例如,如果您基于标记的提交创建了一个提交,您可以通过以下方式交付它:

          git checkout master
          git pull -r
          git cherry-pick <your commit>
          git push origin master
          

          在简单的英语中,这意味着。结帐本地大师。更新本地主机以匹配远程主机。将您的新提交放在本地 master 之上,并更新本地 master 以指向此提交。将本地 master 交付给远程 master。

          【讨论】:

          • 嗨。我正在谈论 3 个 repo:-我的本地 repo-我的同事 repo-官方 repo(所有项目成员都提交/推送他们的更改)如果我克隆我的同事 repo 然后执行“git push origin master”,会不会被推送到我的同事仓库,而不是官方仓库?
          • 它只会被推送到你克隆的仓库
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-09-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-11
          • 2010-09-30
          相关资源
          最近更新 更多