我有以下情况:
a--b--c--d--e--f--g--h--i--j (dev branch)
\ \ \
x--y--z--q--r--s (feature branch)
当我将dev
合并到feature
时,我发现我在功能分支上丢失了很多(或全部?)更改。我猜测dev
上的文件与feature
上的文件重叠的文件太多了。无论是什么原因,这都是与我合作的其他人的存储库(我不知道为什么会发生这种情况的部落知识)。
所以我有兴趣将feature
重新定位到dev
以重播更改。我想我将捕获整个feature
分支(返回提交x
),但我担心由提交feature
和z
表示的r
合并。我担心由于rebase的结果 - dev
分支中的旧代码将覆盖dev
分支上的新代码。
这是一个有效的问题吗?
如果是,那么我最简单的方法是筛选出feature
分支上的唯一更改并在dev
分支上重播它们?我不确定挑选樱桃也是正确的答案。但如果挑选樱桃是正确的答案,那么有人可以解释我应该尝试的命令序列吗"做对了"?
感谢。
答案 0 :(得分:2)
虽然有很多错误的答案,但没有一个正确的答案。但请注意,git rebase
通过复制一些提交工作,基本上, 1 执行一系列git cherry-pick
操作来制作每个副本。通常很难挑选合并,所以git rebase
根本不会打扰:它只是跳过合并。 2 这可能正是你想要的。
例如,假设这是提交图的文字转录/准确图表,或者至少是它的有趣部分:
a--b--c--d--e--f--g--h--i--j <-- dev
\ \ \
x--y--z--q--r--s <-- feature
(当然除了每个提交节点都有一个很难看的哈希ID而不是一个简单的单字母名称)。如果我们将x
,y
,q
和s
的效果复制到添加的四个新提交中提交j
,将它们放在新分支上,并将旧feature
重命名为old-feature
,我们得到:
x'-y'-q'-s' <-- new-feature
/
a--b--c--d--e--f--g--h--i--j <-- dev
\ \ \
x--y--z--q--r--s <-- old-feature
这四个副本可以通过在结帐后git cherry-pick
,x
,y
和q
的四个ID上运行s
来制作使用新分支名称j
提交new-feature
。
请注意,git rebase
选择提交复制,实质上是git rev-list <limit-hash>..HEAD
,其中<limit-hash>
是您提供的任何内容git rebase
<upstream>
参数。选择提交j
就足够了,因为这会从所选提交中排除整个a-b-c-d-e-f-g-h-i-j
链。我们只需要HEAD
来识别提交s
,因为如果我们使用新名称检出提交s
,我们就会这样做。
一旦git rebase
完成复制,它就会移动当前分支的名称,使其指向最后复制的提交,即s'
。因此,我们甚至根本不需要新的名称:我们只需git checkout feature && git rebase dev
,Git就会复制所需的提交。
这确实假设我们在这里绘制的图表是准确的。另请注意,git cherry-pick
的工作方式是 diff 每次提交其父级。这就是为什么难以挑选合并的原因:合并提交有两个,有时甚至更多的父母;我们应该反对哪一个? (Git允许您提供答案:git cherry-pick
为您提供-m
选项,以便在提交是合并时选择要使用的父项。但我们希望,至少对于此实验, throw离开合并,git rebase
为我们做了。)
变基的缺点,特别是长而详细的功能分支,是我们必须复制很多提交,我们可能会遇到很多冲突;然后其他拥有原始提交的人需要停止使用它们并切换到我们的新副本。有一个曲折的迷宫,可能会出错。优点是我们最终获得了简化,更清晰的历史记录,至少if we get all the fiddly maze of steppy twists, er, maze of steppy fiddles of twisty ...... oh no, I've been eaten by a grue!
1 有些rebase字面上使用git cherry-pick
,而有些则做相当的事情。
2 你可以挑选合并,等等;和rebase可以选择&#34;保留&#34;合并;但挑选合并产生一个普通的非合并提交,并且在这种情况下,首先尝试它并没有用。相反,&#34;合并保留&#34; rebase 重新执行合并,这有其自身的缺陷。但这些都不适用于此。