我们说我有:
A - B - C - D - E - F master
\
\- G - H new feature branch
现在我意识到实际提交B和C. 属于新功能,所以我想将它们移到"新功能分支"。换句话说,我想要"新功能分支"从A开始,包括提交B和C:
A - D - E - F master
\
\- B - C - G - H new feature branch
我该怎么做?从我所读过的内容来看,似乎rebase
是我正在寻找的功能,但在我搞砸我的存储库之前,我想确定一下。
(我已经搜索过并发现了很多非常相似的问题和例子,但没有一个像我所描述的情景那样完全,所以我是要求确定(毕竟,回购是毁灭的宝贵财富))。
答案 0 :(得分:6)
Edmundo's answer是正确的(并且已经投票),但值得指出一些额外的项目。
首先,你的问题是关于"移动分支的根源"但这是Git;分支机构不会拥有根,而不是你想的方式。让我们看一下你的图形绘图:
A - B - C - D - E - F master
\
\- G - H new feature branch
我认为你,就像我第一次使用Git时一样,想将提交A-B-C-D-E-F
视为master
分支,并提交G-H
作为特色分支。但这并不是Git的工作方式。让我们重新绘制它,而不更改任何提交链接:
E--F <-- master
/
A--B--C--D
\
G--H <-- feature
这应该更清楚一点,就Git而言,提交A-B-C-D
在两个分支上。只有一个根。该提交A
:它是一个根,因为它没有父提交,从提交到父级的链中没有向后链接。
其次,无论你怎么做,最终都要复制一些提交。原因是每个提交的父ID都是该提交的标识的一部分。 &#34;真名&#34;任何提交都是它的哈希ID,哈希ID是通过读取提交的完整内容构建的:源代码树,提交消息,作者姓名和日期等,但也总是包含父ID。 1 < / sup>您希望最终的图形类似于:
D--E--F <-- master
/
A
\
B--C--G--H <-- feature
但现有的D
链接(或点)返回到现有的C
,而不是A
,现有的G
指向现有的D
}}
这就是为什么樱桃选择有效:git cherry-pick
本质上复制提交。新副本&#34;做同样的事情&#34;作为原作,但某事不同,即使它像&#34一样简单;我的父母是......&#34;。 (通常它也有一个不同的附加树对象,只是它与更改所做的,与其新的父对象相比,是相同的将原稿与原始父母进行比较时原稿的更改。这意味着you can't actually get what you want, just what you need:
D'-E'-F' <-- master
/
A
\
B--C--G'-H' <-- feature
其中小刻度标记表示结果是原件的副本。
原件会怎么样?答案是:如果您需要它们,它们仍然存在于存储库中。全貌更像是这样:
D'-E'-F' <-- master
/
/ E--F [abandoned]
/ /
A--B--C--D
\ \
\ G--H [abandoned]
\
G'-H' <-- feature
虽然git cherry-pick
有效,git rebase
- 特别是git rebase -i
- 的作用是以花哨的自动方式完成这些副本,最后一步是移动分支名称,放弃原始版本提交。所以git rebase -i
有时候是更容易的方式。
如果你运行git rebase -i
,你会看到所有pick
个命令,而这些命令实际上就是git cherry-pick
:它确实在做一系列的挑选。如果您自己进行这些操作,可能会更清楚地发生了什么,并且您可以更好地控制分支标签的移动时间。
1 对于合并提交,这是父 s ,复数。所有的父母都参与哈希。
答案 1 :(得分:3)
修复主人:
git checkout A
git cherry-pick master~3..master # apply the changes we actually want to keep on master
git branch -f master # reposition master on new position
git checkout master
从功能分支中删除提交D:
git checkout feature-branch~3 # or git checkout C
git cherry-pick feature-branch~2..feature-branch # apply the last 2 revisions
git branch -f feature-branch
git checkout feature-branch
答案 2 :(得分:3)
您可以使用git rebase
执行此操作。
首先,让我们来自master
的一些提交:
$ git checkout master
$ git rebase --onto A C
这会将所有提交范围从C转移到master
(但不包括C本身)到提交A上。
现在重新定义feature
但抛出提交D:
$ git checkout feature
$ git rebase --onto C D
与上一个命令类似,这会将提交范围从D到feature
(不包括D本身)移到C上。