我的结构看起来像这样 - >
master
develop
project
<sprint_number>
<task_number>
我在task_number分支上工作。然后我将任务与sprint分支合并。然后我将sprint与项目分支合并。通过这种方式,项目中的所有提交都是sprint,sprint上的所有提交都是任务。合并到项目分支后,我提交合并请求,并在合并到开发之前执行代码审查。
我应该一直在链条上做一次变装吗?例如:
git checkout develop
git rebase master
git checkout project
git rebase develop
git checkout <sprint_number>
git rebase project
git checkout <task_number>
git rebase <sprint_number>
答案 0 :(得分:7)
Git分支名称实际上并不存在于任何意义上:它们只是指向特定提交的指针。
像往常一样,我们需要做的是绘制一些提交 D 竖立的 A 循环 G raph(DAG)片段并考虑变形有意义的情况。所以我们从你的例子开始:
master develop project <sprint_number> <task_number>
并添加一些节点(并为它们提供单个大写字母而不是它们的&#34;真实姓名&#34;类似a1cf93a...
的哈希值,因为它们太大而且不实用):
A <- B <- C <-- master
\
D <- E <-- develop
\
F <- G <-- project
\
H <-- <sprint_number>
\
I <-- <task_number>
(这里的反斜杠应该是左上箭头,但是那些太难以用纯文本绘制)。
也就是说,在这种情况下,我们在master
上进行了(至少)三次提交(在提交之前可能有任意数量的提交A
我们根本没有绘制)。 master
的提示是提交C
,它指向提交B
,返回A
。
我们在develop
上有两个提交但不在master
上:提交E
是develop
的提示,E
指向D
1}},而D
指向B
。提交B
及其所有祖先(A
以及更早的内容)位于 master
和 {{1 }}
同时提交develop
是G
的提示; project
指回G
,指向F
,依此类推。这意味着提交E
和A
实际上是在所有三个分支上。但是等等,还有更多! B
的提示是H
和<sprint_number>
的提示,指向H
,依此类推;并且G
是I
和<task_number>
点的提示,返回I
。
最后,这意味着提交H
和A
在(至少)五个分支(此处显示的五个分支)上,B
和`E至少在四个分支,等等。
在git中, rebasing 实际上意味着将提交复制到新的,略有不同/修改的提交。 (这可能不是正确的方法。但是,我们稍后会谈到这一点,因为在你了解更多信息之前它不会有意义。)
D
的提示现在提交master
而不是提交C
。据推测,早些时候,主人的提示是B
,那时我们提交了B
(也许D
)。但现在您正在考虑将E
重新定位到develop
的新提示上。
要实现此目的,您必须复制将master
和D
提交到新的不同提交。我们会将这些副本称为E
和D'
。即使没有其他任何改变 - 并且其他内容可能会发生变化,特别是E'
和B
之间的任何不同之处都会进入新的C
- 副本{{原始提交D'
的1}}必须指向提交D'
而不是提交D
。
绘制只是这个副本阶段(遗漏原始C
的所有内容)我们得到:
B
(这次我也简化了左箭头,现在我们知道提交指向左侧了。)但原来的E
和A - B - C <-- master
\ \
\ D' - E' <-- develop (after rebase)
\
D - E [abandoned]
不再指向分支名称D
,一旦我们填写了图纸的其余部分,它们仍然可以到达:
E
此时特别重要的是原始提交develop
和A - B - C <-- master
\ \
\ D' - E' <-- develop (after rebase)
\
D-E
\
F-G <-- project
\
H <-- <sprint_number>
\
I <-- <task_number>
*不再在D
上。
忽略E
(这可以是一个解决方案),develop
命令确实需要三个参数,其中一个通常只取自--fork-point
:
git rebase
); 后两者通常合并为一个HEAD
参数。与此同时,您首先要对分支HEAD
进行rebase,以设置第一个参数。例如,如果我们决定将<upstream>
重新定位到git checkout
:
develop
这里最常见的提交复制提交是master
提交,因为git checkout develop
git rebase master
是HEAD
提交最多的提交,以及它的起始位置新副本将成长为git checkout
的提示。 Git首先考虑处理develop
上的每个提交(可能是master
,develop
,A
和B
),但它告诉避免复制D
上的每个提交,这意味着E
,master
和{{1} }。
(等等,什么?我们不应该复制A
?但我们首先要复制B
!好吧,没问题那么,我们只是不会复制它!)这就是我们如何将这两个事物合并为一个C
参数。我们希望在C
之后添加新副本,同时避免复制C
以及从<upstream>
返回的路径中的所有内容。
因此,如果我们选择继续执行此操作C
,我们会将C
和C
复制到git rebase
和D
并结束我们绘制了新的图片片段。
这对于E
来说非常棒,但如果我们这样做会发生什么:
D'
这一次,我们要求git复制从E'
提示可以访问的所有内容 - 这些是develop
,git checkout project
git rebase develop
,project
,{{1 }},G
和F
(可能更多) - 已经重新定位E
的提示,即提交D
。
这是一个问题。它可能是一个自我解决的,如果我们很幸运,因为rebase将检测复制提交的一些情况,并避免重新复制它们。也就是说,当git将B
复制到(另一个)新副本A
时,可能会检测develop
已存在于E'
中}。如果它 检测到它,它将跳过副本。将D
复制到D''
时会发生同样的情况:可能会检测到这不是必需的,并跳过副本。
另一方面,git的检测器可能会被愚弄,它可能会复制D
和/或E'
。我们绝对不想要那样,所以最好避免让git复制它们。
有很多方法可以提出,包括交互式rebase(我们可以在其中编辑E
指令,因此我们可以删除提交E''
的两个D
行E
),或者对pick
的参数更加聪明:
pick
第二个命令使用reflog历史来告诉git要复制的提交是D
(当前分支)上的提交,这些提交未包含在{em>之前的提示中{ {1}}。也就是说,E
解析为原始(未复制)提交git rebase
的提交ID。因此,这只会将提交git checkout project
git rebase --onto develop 'project@{1}'
和project
复制到project
和'project@{1}'
。
(顺便提一下,如果您在带有彩色标记的白板上绘制DAG,您可以使用颜色来表示原始提交及其副本。我发现这比所有E
和{{1}更容易阅读我只是无法在StackOverflow上绘制它。)
我们可以使用sprint和task重复此过程,使用reflog来识别要遗漏的提交。
从git 1.9开始,F
现在有G
,这实际上使我们在这里使用reflog自动化了。 (git 2.1中有一个错误修复,因为F'
未能发现不需要复制的提交,因此将此选项限制为2.1或更高版本是明智的。因此,这是一种方法。
最后,在回答这是否是一个好主意的问题之前,我还要再说一遍。而不是在G'
和D'
D''
上重新git rebase
,等等,假设我们通过重新定位任务来启动。这会告诉git将提交--fork-point
复制到git rebase --fork-point
,将develop
复制到master
,将project
复制到develop
,依此类推将D
复制到D'
。然后,任务分支将指向新提交E
,其历史链回到E'
。现在我们需要做的就是通过查找正确的副本,在复制的提交中重新指向sprint分支,F
分支和F'
分支。更新后的I
应指向I'
;更新后的I'
应指向C
;并且更新后的sprint分支应指向project
。
如果有额外的sprint和/或任务分支,他们可能需要复制一些不会被上面复制的提交,所以必须仔细使用这个技巧。与往常一样,它将有助于首先绘制DAG。
如果你有一个这种复杂的分支结构,那么变基可能是错误的方法。即使没有,这可能仍然是错误的做法。
请记住,正如我们刚刚看到的那样,变基涉及复制提交,然后移动分支标签以指向新副本而不是原始副本。当您使用仅您使用的存储库执行此操作时,它通常不会太令人困惑,因为您移动了所有分支标签并且现在已经完成:您要么使用旧的,要么-copy状态或新的复制后状态,除了执行所有这些rebase的短暂时间外,您可以忽略所有中间(中间rebase)状态。
如果其他人正在共享此存储库,请考虑您将为他们做什么 。在你完成所有这些大规模的变基之前,他们有思想是正确的develop
,develop
,冲刺和任务分支指针。他们正在使用原始(尚未复制)的提交,并根据这些原始提交进行自己的新提交。
现在你过来告诉他们:&#34;哦,嘿,忘了所有那些旧的提交!请改用这些全新的闪亮的!&#34;现在他们必须找到依赖于旧提交的他们所做的一切,并将所有这些更新为依赖于新的提交。
换句话说,他们必须处理一个&#34;上游变种&#34; - 或者实际上,来自众多上游变种。它通常不是很有趣(尽管相同的E'
代码使您可以自动执行此操作,也可以使它们从上游rebase自动恢复)。
project
有一个时间限制,因为它使用了reflog条目,并且reflog条目到期。如果你没有重新配置东西,git默认会在30天后使关键的reflog条目到期,所以如果你这样做,其他人都有大约一个月的时间从中恢复。
答案 1 :(得分:0)
通过这种方式,项目的所有提交都是sprint,sprint上的所有提交都是任务
你不需要这样做。只需使用您创建的pull请求,因为所有代码将合并到最终开发中。
只要您打开拉取请求,您也可以删除当地的分支机构,只保留最新的分支机构,以备将来更改时使用。
答案 2 :(得分:0)
在git中没有嵌套分支这样的东西。如果你有一个名为foo的分支,另一个名为foo / bar的分支,它们只是两个不同的分支。这些分支之间没有任何关系 - 以对待任何两个独立分支的方式对待它们。