在其他任何事情之前,我只是git分支的新手。我不知道每个功能分支都应该从master
扩展出来,并且只使用与下一个功能分支有关的先决条件功能分支。
我有三个分支。 master
,feature-1
和feature-2
都推送了Bitbucket存储库(启用了问题跟踪)。事情是提交M4
和M5
是关键提交,所有分支都应该在提交合并之前对其进行重新定义(git rebase
的任务)
M1 -- M2 -- M3 -- M4 -- M5 [master]
\ /
A1 --- A2 [feature-1]
\
B1 -- B2 -- B3 [feature-2]
feature-2
的开发已完成,现在需要合并到master。以下是我feature-2
为M4
和M5
提交feature-2
提交的任务的优先顺序。
git push
- 开发feature-2
git checkout feature-2
git rebase master
git pull
执行git status
后,我已经注意到了这些步骤。我必须再次推送所有提交(feature-2
,M4
,M5
和冲突提交。我所要做的就是做git push
并启动拉取请求并完成,对吧?但这会在问题跟踪器中添加另一个git commit注释。
有没有办法将feature-2
重新定位到master
,而无需再次推送feature-2
,M4
和M5
以及{{ 1}}应该包含冲突提交。
更新
答案 0 :(得分:11)
由于您已经推送了两个功能分支,因此根本不应该进行变基。强烈建议重新定位已发布的分支,因为它会破坏其他开发人员的存储库。原因是rebase只是提交的完全重写。您正在重新设置的提交将被重新创建,内容已更改,最重要的是 - 具有不同的哈希值。这导致新提交与旧提交不兼容,因此拥有旧提交的人最终会与替换它们的新提交冲突。
对此的正确解决方案是简单地合并更改。虽然这可能不会看起来那么漂亮,但它是一种非破坏性的动作,其中没有改变现有的提交。所有这一切都是提交添加,这将导致推或拉时没有问题。
话虽这么说,你可以改组并仍然发布已更改的分支。但要做到这一点,你需要强制推动分支机构,而其他开发人员需要将这些更改重置为新版本。
将下面的一些评论包含在答案中:重要的是要理解在Git中,分支只是提交的指针。整个历史 - 没有分支 - 是一个很大的非循环图,其中提交只指向其父提交。所以从问题中拿出你的例子,这是历史,没有任何分支指针:
A -- B -- C -- D -- E
\ /
F --- G
\
H -- I -- J
每个字母代表一个提交,所有提交一个连接到,左边是其父级。例如,F
的父级为A
,C
是与父级B
和G
的合并提交。
现在,如果我们向该可视化添加分支,那么我们只需添加指向某些提交的指针。它真的没什么别的(分支实际上只是一个包含提交哈希的文件):
master
↓
A -- B -- C -- D -- E
\ /
F --- G ← feature-1
\
H -- I -- J
↑
feature-2
现在,假设我们提交feature-2
分支。我们将该提交添加到树中......
\
H -- I -- J -- K
↑
feature-2
...然后我们向前移动分支指针:
\
H -- I -- J -- K
↑
feature-2
现在,为了理解推送过程中发生的事情,我们需要记住远程分支也只是分支,因此只是另一组指针。所以它实际上看起来像这样:
\
H -- I -- J ----------- K
↑ ↑
origin/feature-2 feature-2
我认为您可以想象现在推送期间会发生什么:我们告诉远程存储库更新其分支指针,使其指向K
。但是服务器只有J
,所以我们需要给服务器一些东西来构造K
可访问的树(所以其中的任何其他提交,以及这些提交的所有实际内容)。但是我们当然不需要实际推送J
,H
,甚至A
(尽管feature-2
上的所有技术 }分支,因为你可以到达他们); Git非常聪明,可以找出实际丢失的对象(你可以看到Git在你开始推送时计算它)。
因此,一旦我们将丢失的对象转移到远程存储库,我们就告诉远程存储库更新其feature-1
指针,因此它也将指向K
。如果成功,我们也会更新我们的远程分支(origin/feature-2
)以指向它(只是为了同步)。
现在,合并情况确实如此。想象一下,我们将master
合并到feature-2
(在git merge master
时使用feature-2
):
master
↓
A -- B -- C -- D -- E -----
\ / \
F --- G ← feature-1 \
\ \
H -- I -- J -- K -- L
↑
feature-2
现在,如果我们想推送feature-2
,我们再次需要为远程存储库提供它没有的所有对象。由于我们现在正在进行合并提交,我们需要检查所有父项:因此,如果服务器没有K
,我们需要推送K
;但是,如果它没有E
,我们必须推E
。当然,我们需要再次关注这些父母,以确保遥控器上存在所有对象。一旦完成,我们再次告诉遥控器更新分支指针。
所以总结一下:分支包含所有提交,通过在非循环树中导航其提交的父级来以某种方式可访问。但即使这意味着分支通常非常“大”(历史长度),Git只会将这些对象传输到它没有的远程存储库。因此,虽然合并可以向分支添加更多提交,但如果远程已经从另一个分支知道它们,则不一定必须传输这些提交。
最后,关于变基的最后一句话:上面我们git merge master
将master
分支合并到feature-2
。如果我们改为git rebase master
,那么完整的树现在看起来像这样:
master feature-2
↓ ↓
A -- B -- C -- D -- E -- H' -- I' -- J' -- K'
\ /
F --- G ← feature-1
\
H -- I -- J -- K
↑
origin/feature-2
如您所见,有新的提交H'
,I'
,J'
和K'
。这些是重写的提交,因此它们从E
(在rebase时指向master
处)而不是G
开始。由于我们重新定位,因此没有合并提交L
。如上所述,原始提交仍然存在。只是没有指针指向它们;因此他们“迷失”并最终将被垃圾收集。
那么现在推的问题是什么?远程分支仍指向原始K
,但我们希望它现在指向K'
。因此,我们开始为远程存储库提供所需的所有对象,就像之前一样。但是当我们告诉它设置更新分支指针时,它会拒绝这样做。这样做的原因是,通过将指针设置为K'
,它必须“返回历史记录”并忽略提交H
到K
的存在。它不知道我们已经重新定义了那些,并且重写的和原始的之间也没有联系。因此,为了防止意外数据丢失,远程将拒绝更新分支指针。
现在,您可以强制推送分支。这将告诉远程存储库更新分支指针,即使这样做会抛出那些原始提交。所以你这样做,情况将是这样的:
origin/feature-2
master feature-2
↓ ↓
A -- B -- C -- D -- E -- H' -- I' -- J' -- K'
\ /
F --- G ← feature-1
到目前为止,一切都很顺利:你决定对分支进行rebase,你告诉远程存储库接受它而不用质疑它。但现在想象我想拉那个;我的分支仍然指向I
。因此,run pull与反向推送相同:遥控器为我提供了完成历史记录所需的所有对象,然后它告诉我在哪里设置分支指针。在那时,我的本地Git拒绝这样做,原因与远程存储库之前做的相同。
通过之前的推动,我们知道我们想要替换原始提交;但是我们没有那个,所以我们现在需要调查或询问我们是否应该只更换我们的本地分支,或者是否实际上有一些故障。如果我们在当地做了一些我们想要合并的工作,情况会变得更糟。
这些问题发生在每次获取原始提交的人身上。一般来说,你想完全避免这种混乱,所以规则是永远不要改变你已经发布的东西。只要没有其他人得到那些原始提交,你就可以进行改造,但是一旦不再这样,那么对于所有参与者来说都会是一团糟。所以合并绝对是首选。
答案 1 :(得分:2)
据我了解,您的代码库(团队)规则要求您针对master
重新设置功能分支。你可以这样说git rebase --onto master A2 feature-2
这意味着“接受以A2独占的特征-2的提交并将它们置于主人之上”。然后,您可以将更改直接推送到master
,同时删除或保持feature-2
分支不变,这取决于工作流程约定。
另一方面,如果不要求rebase - 您可以将feature-2
简单合并到master
,将更改推送到master
,如@poke建议。
答案 2 :(得分:1)
有没有办法将
feature-2
重新定位到master
,而无需再次推送feature-2
的提交
不是真的,考虑到一个rebase将重播master上的feature-2的提交,给你这个:
M1 -- M2 -- M3 -- M4 -- M5 [master]
\ / \
A1 --- A2 [feature-1] A1' --- A2'
\
B1' -- B2' -- B3' [feature-2]
如'
符号所示,所有提交都已更改(其SHA1不同)。
由于A1
和A2
已经合并到master
,因此更好的基础会是
git rebase --onto master A2 feature-2
那会得到:
M1 -- M2 -- M3 -- M4 -- M5 [master]
\ / \
A1 --- A2 [feature-1] B1' -- B2' -- B3' [feature-2]
您应该git push --force
新修订的feature-2
分支,以便更新您的提款请求。
强制推送应该更新Bitbucket中的拉取请求,因为它支持自2012年第四季度以来的推送(issue 4913)。
强制推动不会产生任何其他不利影响,考虑到你正在推动分支到你的分支,大概是你是唯一推动更新的分支。
由于拉取请求会自动使用feature-2
的新历史记录自行更新,因此不会影响所述拉取请求。