如何在基础分支被Rebase到master后,对一个分支进行Rebase

8
我有一个分支 A,在其中进行了一些更改 a,然后我从 A 创建了一个新的分支 B,继续进行一些更改 b,使得 B 中的总更改为 a、b。最后,其他人将他们的更改 c 合并到主分支中,因此工作树现在看起来像这样:
- c (master)
 \ 
  - a (A) - b (B)

然后,我将A rebase到主分支,修改了从aa'的更改,并强制推送到分支A,因此工作树看起来像这样:

- c (master) - a' (A)
 \
  - a - b (B)

问题

如何将B变基到A,以便只更改新的变化b,然后使工作树看起来像这样:

- c (master) - a' (A) - b' (B)

如果我在分支B上尝试执行git rebase origin/A,那么它会尝试将提交ac, a'合并,这不是我想要的,因为我担心它会创建新的提交a'',然后工作目录会变成这样:
- c (master) - a' (A) - a'' - b' (B)

有没有办法只对变更b进行变基?(我已经尝试过搜索,但是没有找到具体涵盖此情况的结果)
编辑:我尝试在B上压缩和,但结果更糟,因为现在所有来自的更改都被注册为冲突。例如,假设我:
1. 在中添加了一行<1l>。 2. 在中将该行更改为<1l>。 3. 另一个提交中未更改此行。 4. 现在它是个冲突,因为<1l>在中添加,但<1l>在压缩的提交中添加。
4个回答

5
git rebase --onto A a B

--onto A 选定 A 作为新的基础。取得像 git log a..B 这样的一组提交记录,其中在你的情况下仅包括 b。这组提交记录被应用到新的基础上。

您始终可以使用 交互式变基 来处理简单或复杂的情况。

git rebase -i A

在编辑页面中,将代码行中的领先 pick 更改为 drop,或者直接删除整行。保存并退出。

如果 git rebase 不起作用,您还可以尝试使用 git cherry-pick 只应用想要的提交,然后将 B 重置为新的头部。

git checkout -b tmp A
git cherry-pick b
git checkout B
git branch B_bak
git reset tmp --hard
git branch -D tmp

如果出现问题,你可以运行 git checkout B && git reset B_bak --hard 来恢复 B


git rebase --onto A a B 中,我应该将 a 设置为什么?我尝试使用提交哈希的开头,但效果不佳。不幸的是,我无法记起问题出在哪里(尝试了5+个方法,每个都以不同的方式失败)。 - kajacx
1
@kajacx 在你的图表“- a - b(B)”中,“a”的SHA1值是什么? - ElpieKay
谢谢,经过多次尝试和阅读资料,我发现 git rebase --onto A a 是我需要的(当在 B 上检出时似乎与 git rebase --onto A a B 相同)。我仍然不记得第一次为什么失败了(也许我粘贴了错误的提交哈希值)。 - kajacx

1
我怎样把代码库中的分支B变基到A上,只修改新增的提交b
您可以简单地执行以下操作:
git rebase A B

这句话的意思是“切换到分支B并将其在A之上重新定位”。Git不会重新应用提交a,因为它可以确定a'已经引入了相同的更改。

补丁等价性

当两个不同的提交(即具有不同SHA-1哈希值的提交)引入相同的更改集时,它们被称为补丁等价

您可以使用git log--cherry-pick选项来确定两个分支之间的补丁等价提交:

--cherry-pick
当使用对称差异限制提交集时,省略任何引入与“另一侧”上的另一个提交相同更改的提交。

在您的情况下,如果执行以下操作:

git log --oneline --cherry-pick --left-right A...B

您会发现提交记录a'a被排除在输出之外,因为它们是补丁等效的。1

当您将B变基到A之上时,Git会逐个挑选来自B的提交记录,并将其应用于A之上。当它到达一个引入与现有提交相同更改的提交时,它将简单地跳过它并移动到下一个。


1 ... 符号(也称为 三个点)选择从两个引用中任意一个可达的提交,但不包括两者都可达的提交。这对于选择两个不同分支中从它们共同的父节点开始的“新”提交非常有用。


git rebase B A 似乎无法工作,它不仅将当前分支切换到 A,而且我甚至看不到正确的更改。 - kajacx
抱歉,我不小心颠倒了参数 :$。我已经更新了我的答案。 - Enrico Campidoglio
谢谢,我尝试交换参数,但似乎没有任何作用,这可能是VSCode中的一个漏洞或其他问题。最终我决定咬紧牙关并重新基于master分支,再次解决ac之间的冲突。 - kajacx
1
好的,我现在明白它是如何工作的了。Git不会重新应用提交a,因为它可以确定a'已经引入了相同的更改。这不起作用,因为存在冲突,我不仅需要再次解决冲突,而且必须完全按照以前的方式解决冲突,否则提交将不同。 - kajacx

1
告诉rebase去查找新基础的尖端原来在哪里,然后从那里开始:
git rebase --fork-point A

如果您当前分支的上游已设置,则该分支和--fork-point选项都是默认值,因此您的命令是

git rebase

0

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