这是一个老问题,但我的 repo 也遇到了同样的问题,我终于找到了一个完整的解决方案,它(希望)保留了所有子树元数据。
假设我们有这个提交树:
B (master) Add README.md
|
A Initial commit
我们分叉了一个feature
分支,其中的子树位于lib/
:
git remote add -f githublib https://github.com/lib/lib.git
git subtree add --prefix lib/ githublib master --squash
它创建了一个具有两个父级的合并提交 D:我们当前的(B),以及一个与外部 repo 的压缩历史master
无关的提交。F
该提交还在其提交消息中包含一些git subtree
元数据(即git-subtree-dir
和git-subtree-split
)。
D (feature) Merged commit 'F' as 'lib/'
/ \
/ F Squashed 'lib/' content from GGGGGG
B (master) Add README.md
|
A Initial commit
稍后,我们分别向两个分支添加一些提交。
E (feature) Remove .gitignore from lib/
C | (master) Add LICENSE.md
| D Merged commit 'F' as 'lib/'
| / \
|/ F Squashed 'lib/' content from GGGGGG
B Add README.md
|
A Initial commit
现在我们要重新定位feature
到master
. 就是这样:
feature
1.逐一挑选提交,feature
在master
.
git branch -f feature C
git checkout feature
git cherry-pick D E
E' (feature) Remove .gitignore from lib/
|
D' Merged commit 'F' as 'lib/'
|
| E Remove .gitignore from lib/
C | (master) Add LICENSE.md
| D Merged commit 'F' as 'lib/'
| / \
|/ F Squashed 'lib/' content from GGGGGG
B Add README.md
|
A Initial commit
现在我们有了一个 rebase 的等价物,但是我们丢失了所有关于外部 repo 的信息,对于git subtree
. 要恢复它:
git checkout feature
git replace --graft D' C F
git filter-branch --tag-name-filter cat -- master..
现在我们得到了一张与开头完全相同的图片。旧的提交 D 和 E 仍然存在,但它们可以在以后被垃圾收集。
E' (feature) Remove .gitignore from lib/
|
D' Merged commit 'F' as 'lib/'
|\
| \
C \ (master) Add LICENSE.md
| \
| \
| F Squashed 'lib/' content from GGGGGG
B Add README.md
|
A Initial commit
警告:这会改写 的历史feature
,所以如果有其他人在这个分支上与你合作,请小心发布它。但是,由于您一开始就想进行变基,因此您可能已经意识到了 :-)