如何为标记提交单独创建一个分支?

3

我被委派以一种方式组织存储库,除了其他分支外,还有一个专用分支,我们只会在其中存储已发布版本的提交。下面是我想要实现的简化方案:

| trunk    |           | releases |
|----------+-----------+----------|
| commit 1 |           |          |
| commit 2 | v0.1 ---> | tag 1    |
| commit 3 |           |          |
| commit 4 |           |          |
| commit 5 |           |          |
| commit 6 | v0.2 ---> | tag 2    |
| commit 7 |           |          |
| commit 8 |           |          |
| commit 9 |           |          |

这对我来说有点高级了,所以我希望能得到一些关于如何做到这一点的指导!我不确定如何在“releases”分支中拥有第二个标签,而无需导入所有中间提交。这是否可能?

另外,如果您有更好的方案来实现同样的目标(目标是仅为发布专门创建一个分支),请不要犹豫提出建议!


1
为什么需要一个单独的分支?为什么不能在主分支上只有发布标签? - beatgammit
  1. 我不确定。
  2. 这是我被分配的任务 :)
  3. 有人认为,如果其他人需要发布版本,只需知道一个“地址”就可以更容易地转向它... 好吧,让我们称之为公司逻辑问题,我还不是大师。
- user797257
1
@tjameson:这看起来像是git-flow的一部分(http://nvie.com/posts/a-successful-git-branching-model/)。我不知道有什么方法可以通过git强制执行分支中只有标记的提交,但作为一种约定,它运行得相当不错。 - fjarri
4个回答

6

那样做没有意义,因为标记的提交代表了一个分支的状态,由提交和其前身组成。

仅隔离标记的提交将写入非常不同的历史记录,因为这些提交将缺少它们的祖先:是这些祖先加上标记的提交的序列将代码库引导到特定的状态。

更简单的方法是确保您在一个专用分支(例如主分支)中标记您的发布提交。

然后,一个简单的 git show-ref --tags 可以列出这些标记所引用的提交。

或者您可以从任何这些标记创建一个分支(用于修复发布版中的错误)。

git checkout -b newbranch v1.0

你可以使用git describe --long命令从任何提交中推导出最后一次发布的标签


OP wvxvw添加了在评论中

但是,具有发布的分支仅存储特殊提交(标记的提交)的历史记录,并指向其他分支作为提交来源

这可以通过将标记提交合并到“发布分支”中来实现,使用保留“theirs”的合并(即合并源,表示标记提交的源)

--x--x--x--x--x--x--x
 (v1)     (v2)
   \        \ 
----y--------y--

git commit --allow-empty 这样的 hack 可以在发布分支上解决问题,但标签仍将出现在 git tag 的输出中。--allow-empty 选项的好处是让 git describe 在不同的分支上有不同的工作方式。 - beatgammit
我认为关于“不存储提交”有些混淆。我的意思是,我希望提交历史记录被存储在实际发生的地方 - 在相关分支中,但是发布分支仅存储特殊提交(已标记的提交)的历史记录,并指向其他分支作为提交来源。我无法想象有可能同时合并来自几个其他提交的更改的完全独立的提交...虽然这不会有害,但我认为这是不可能的 :) - user797257
谢谢!我试图阅读您链接的其他问题,但与此同时要求已经改变了...另外,我并不真正认为我理解了其他答案,但我很高兴我不再需要这样做 :) 谢谢您的时间! - user797257

3
这段话有点难以理解。在git中,分支名称只是指向特定提交的标签,在添加新提交时,该名称会自动“向前移动”:
C1 -- C2 -- C3         <-- label X
              \
                D1     <-- label Y

如果您在“X分支”上添加了提交(即标签X指向的位置),则会得到以下结果:

C1 -- C2 -- C3 -- C4   <-- label X
              \
                D1     <-- label Y

一个Git标签可以是“轻量级”或“附注型”。它们的区别在于,前者仅是一个名称,就像这里的X和Y一样,指向特定提交的标签,而后者则是指向存储在仓库中的一种特殊对象的标签,该对象指向提交(这使得附注型标签能够携带比轻量级标签更多的数据:额外的数据与标签指向的提交ID一起存储)。不过在我们这里,这个区别并不是很重要。
假设我用标签TC和TD来标记提交C4和D1。我得到:
C1 -- C2 -- C3 -- C4   <-- branch X, tag TC
              \
                D1     <-- branch Y, TD

如果我向“分支X”或“分支Y”添加更多提交,分支标签会移动,而标签标签会保持不变。例如,如果我添加提交C5(在“分支X”上),X将指向C5,但TC仍将指向C4。然而,如果我通过将“分支Y”合并到“分支X”中来执行此操作 - 这将是新的提交C5 - 我将获得:

                   .------------- tag TC
                   v
C1 -- C2 -- C3 -- C4 -- C5   <-- branch X
               \      /
                  D1         <-- branch Y, tag TD

我现在可以(没有任何来自Git的投诉)完全删除“分支Y”,因为它的提交被“包含在”(实际上是可从)分支X和标签TD中。如果我这样做,“标签TD”根本不在分支Y上,因为分支Y不存在。即使我保留分支Y,标签TD仍然包含在“分支X”中!从C5开始并转到第二个父级可以得到D1,这就是TD指向的地方。

类似于我的答案,但有更多的ASCII艺术,所以+1 ;) - VonC
我认为我真正需要的是你的例子的相反情况... 我更倾向于在主分支上使用 --no-ff 提交,这样它就不会存储来自原始提交的分支的历史记录。你的帖子很有趣,但不幸的是它并没有帮助我实现目标 :( 不过还是谢谢你! - user797257
@wvxvw:你可能确实希望在用于发布的任何分支中使用--no-ff合并。但是标签仍然没有以任何有用的方式“在分支上”。提交是“在”引用标签的事物,更准确地说是“可从”引用标签到达的事物。实际上,标签与分支名称处于同一级别,位于该空间之外。(这就是为什么它们可以在.git/refs/tags/文件中找到,就像分支名称在.git/refs/branches/中一样。实际上,标签有时可能是提交的唯一外部名称,使提交不会被垃圾回收。) - torek

1

首先,您需要了解一些关于Git的知识:

  • Git存储库可以被视为一堆提交。每个提交都有一个或两个(合并)父提交。
  • 标签只是指向这些提交中的一个指针。它是固定的。
  • 分支也是指向这些提交中的一个指针。但它将始终指向您在该分支上进行最后一次提交的提交。因此,它是一个“动态”指针。

也许这能解释为什么您想要的并没有真正意义:标签独立于分支。


小细节:”章鱼合并“具有两个以上的父节点。(Mercurial一次只允许合并两个父节点;为了获得章鱼合并的效果,您需要进行一系列成对合并。当然,最终结果是相同的。) - torek
在Git中,根提交和零父提交都是存在的,因此提交可以有零个或多个父提交。 - CB Bailey

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接