Epe*_*eli 58 git git-rebase git-subtree
我正在尝试学习在Git 1.7.11中添加的新git-subtree命令.添加子树后,我似乎失去了变基的能力.我有一个带有README文件的主存储库和一个库存储库,它也有一个README文件.我将它添加到lib目录subtree add
:
$ git subtree add -P lib/mylib myliborigin master
Run Code Online (Sandbox Code Playgroud)
这很好,但现在历史看起来像这样:
* 22c1fe6 (HEAD, master) Merge commit 'b6e698d9f4985825efa06dfdd7bba8d2930cd40e' as 'lib/mylib' -
|\
| * b6e698d Squashed 'lib/mylib/' content from commit d7dbd3d
* b99d55b Add readme
* 020e372 Initial
Run Code Online (Sandbox Code Playgroud)
现在当我想要反对我的repo origin/master
并且它失败时因为squash commit直接应用于它不适用的父提交,因为它被应用于repo的根而不是我添加的时候给它的前缀子树.
如果我看一下壁球提交,原因很清楚.没有关于前缀的信息.这只是原始的mylib提交压扁在一起.只有下一个合并提交知道它的任何内容,但rebase不会在此处考虑它.
是否有任何变通方法(除了永远不会对子树提交进行重新定位)?
这不是一个解决方案,但它目前的工作我使用...
使用您的初始示例:
* 22c1fe6 (HEAD, master) Merge commit 'b6e698d9f4985825efa06dfdd7bba8d2930cd40e' as 'lib/mylib' -
|\
| * b6e698d Squashed 'lib/mylib/' content from commit d7dbd3d
* b99d55b Add readme
* 020e372 Initial
Run Code Online (Sandbox Code Playgroud)
在子树添加之前,以交互方式重新引导到第二次提交:
$ git rebase -i 020e372
Run Code Online (Sandbox Code Playgroud)
删除先前提交的两个子树条目和标记编辑:
e b99d55b Add readme
Run Code Online (Sandbox Code Playgroud)
保存文件/关闭,然后当它进入"添加自述文件"提交时,运行修改命令:
$ git commit --amend
Run Code Online (Sandbox Code Playgroud)
然后重新添加新的子树:
$ git subtree add -P lib/mylib myliborigin master
Run Code Online (Sandbox Code Playgroud)
继续变革:
$ git rebase --continue
Run Code Online (Sandbox Code Playgroud)
然后你的分支应该从主人那里重新开始,并且子树将是"正常的",并且Squash + Merge完好无损:
* 22c1fe6 (HEAD, master) Merge commit 'b6e698d9f4985825efa06dfdd7bba8d2930cd40e' as 'lib/mylib' -
|\
| * b6e698d Squashed 'lib/mylib/' content from commit d7dbd3d
Run Code Online (Sandbox Code Playgroud)
Git 2.24.0(2019-11-04 发布)添加了对git rebase --rebase-merges --strategy [strategy]
. git rebase --rebase-merges --strategy subtree [branch]
因此,现在如果您在当前分支包含子树合并时运行,它现在就可以工作了。
对于我的项目,我决定可能不使用git subtree add
,而是使用 丢弃合并提交的第二个父级git replace --edit
。我还使用了Git 书籍 v1 过时的“子树”教程,它做了同样的事情,但很乏味。
这是一个老问题,但我的回购问题与我有同样的问题,我终于找到了一个完整的解决方案,它(希望)保留了所有的子树元数据.
假设我们有这个提交树:
B (master) Add README.md
|
A Initial commit
Run Code Online (Sandbox Code Playgroud)
我们feature
用一个子树分叉了一个分支lib/
:
git remote add -f githublib https://github.com/lib/lib.git
git subtree add --prefix lib/ githublib master --squash
Run Code Online (Sandbox Code Playgroud)
它创建了一个包含两个父项的合并提交D:我们当前的master
(B),以及与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
Run Code Online (Sandbox Code Playgroud)
稍后,我们会独立地向两个分支添加一些提交.
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
Run Code Online (Sandbox Code Playgroud)
现在我们要重新feature
加入master
.这是如何做:
feature
一个接一个地提交提交,以创建一个新的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
Run Code Online (Sandbox Code Playgroud)
现在我们有相当于一个rebase,但我们已经丢失了所有关于外部回购的信息git subtree
.要恢复它:
feature
以使其永久化.git checkout feature
git replace --graft D' C F
git filter-branch --tag-name-filter cat -- master..
Run Code Online (Sandbox Code Playgroud)
现在我们得到的图片与开头的图片完全相同.旧的提交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
Run Code Online (Sandbox Code Playgroud)
警告:这会重写历史记录feature
,因此如果有人在此分支上与您合作,请小心发布.但是,既然你想首先做一个变基,你可能会意识到这一点:-)
这在简单的情况下有效:
git rebase --preserve-merges master
Run Code Online (Sandbox Code Playgroud)
感谢@Techlive Zheng的评论。
你可能会看到
fatal: refusing to merge unrelated histories
Error redoing merge a95986e...
Run Code Online (Sandbox Code Playgroud)
这意味着git无法自动应用您的子树。这使您处于他的答案中描述的@ericpeters的情况。解:
重新添加子树(使用最初使用的相同命令):
git subtree add -P lib lib-origin master
Run Code Online (Sandbox Code Playgroud)
继续变基:
git rebase --continue
Run Code Online (Sandbox Code Playgroud)
一切准备就绪!
如果您想知道它是否成功运行,可以在重新定基后与原始版本进行比较,以确保您没有进行任何更改:
git diff <ref-before-rebase> <ref-after-rebase> -- .
Run Code Online (Sandbox Code Playgroud)
(-- .
最后指示git仅diff
显示当前目录中的文件)。
如果所有其他方法都失败了,并且您不关心自己保存提交,则可以简单地git cherry-pick
进行原始的子树提交。
提交消息看起来像Add 'lib/' from commit '9767e6...'
-这就是您想要的。
你需要使用
git rebase --preserve-merges --preserve-committer --onto new_place start end
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
10830 次 |
最近记录: |