git-subtree添加后如何rebase?

我试图学习Git 1.7.11中添加的新的git-subtree命令。 我添加一个子树后,似乎失去了rebase的能力。 我有与自述文件和库存储库,也有自述文件的主要存储库。 我将它添加到subtree add lib目录:

 $ git subtree add -P lib/mylib myliborigin master 

这工作正常,但现在的历史看起来像这样:

 * 22c1fe6 (HEAD, master) Merge commit 'b6e698d9f4985825efa06dfdd7bba8d2930cd40e' as 'lib/mylib' - |\ | * b6e698d Squashed 'lib/mylib/' content from commit d7dbd3d * b99d55b Add readme * 020e372 Initial 

现在,当我想重新对我的repo对origin/master ,它失败,因为南瓜提交是直接应用于其父提交不适用,因为它是应用于回购的根,而不是我给它的前缀添加子树时。

这样做的原因很明显,如果我看看南瓜的承诺。 没有关于前缀的信息。 这只是原来的mylib承诺压在一起。 只有下一个合并提交知道它的任何事情,但是rebase并没有把它记在这里。

是否有任何解决方法(除了从不分配subtree提交)?

这不是一个解决scheme,但它目前的工作,我使用…

用你最初的例子:

 * 22c1fe6 (HEAD, master) Merge commit 'b6e698d9f4985825efa06dfdd7bba8d2930cd40e' as 'lib/mylib' - |\ | * b6e698d Squashed 'lib/mylib/' content from commit d7dbd3d * b99d55b Add readme * 020e372 Initial 

交互地重新添加到子树添加之前的第二次提交:

 $ git rebase -i 020e372 

删除两个子树条目并为之前的提交标记编辑:

 e b99d55b Add readme 

保存文件/closures,然后当它进入“添加自述文件”提交,运行修改命令:

 $ git commit --amend 

然后重新添加你的新子树:

 $ git subtree add -P lib/mylib myliborigin master 

继续rebase:

 $ git rebase --continue 

然后,你的分支应该被重新设置为主,并且该子树将与“壁球+合并”完好无损:

 * 22c1fe6 (HEAD, master) Merge commit 'b6e698d9f4985825efa06dfdd7bba8d2930cd40e' as 'lib/mylib' - |\ | * b6e698d Squashed 'lib/mylib/' content from commit d7dbd3d 

这是一个古老的问题,但我只是有我的回购相同的问题,我终于find了一个完整的解决scheme,(希望)保留所有的子树元数据。

假设我们有这个提交树:

 B (master) Add README.md | A Initial commit 

我们用一个驻留在lib/的子树分支了一个feature分支:

 git remote add -f githublib https://github.com/lib/lib.git git subtree add --prefix lib/ githublib master --squash 

它创build一个合并提交D与两个父母:我们当前的master (B)和一个不相关的提交F与外部回购的压扁的历史。 这个提交在其提交消息中还包含一些git subtree元数据(即, git-subtree-dirgit-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 。 就是这样:

1.樱桃 – 从feature一个接一个提交创buildfeature分支的master副本的新副本。

 git branch -f feature C git checkout feature git cherry-pick DE 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,但是我们已经失去了有关git subtree所需的外部回购的所有信息。 要恢复它:

2. 添加缺less的父链接作为嫁接 ,并重写feature的历史,使其永久。

 git checkout feature git replace --graft D' CF 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的历史logging,所以如果其他人在此分支上与您协作,请谨慎发布。 但是,既然你想首先做一个rebase,你可能会意识到:-)

显然这是预期的行为(对于“预期行为”的一些不正当的定义。)参见http://git.661346.n2.nabble.com/subtree-merges-lose-prefix-after-rebase-td7332850.html

这并不是说这对任何人都很有帮助。 我也很想find解决方法。

我有一个类似的问题:我想在做一个子树添加后重新绑定,并使用–preserve-merges仍然留给我一个合并冲突(由于冲突的.gitignore文件和其他人)。

就我而言,我并不一定打算使用任何子树function:我只是简单地引入一个本来应该是超级项目一部分的回购。 如果它帮助其他人,根据我发现的其他相关 答案 ,这是我最终做的。

假设我有两个项目,main_project和sub_project,在同一个目录中。 我想将sub_project拖到main_project中的一个名为sub_project的目录中,假设没有repo曾经有一个名为sub_project的目录:

 cd main_project git fetch ../sub_project git checkout -b sub_project FETCH_HEAD git filter-branch --prune-empty --tree-filter ' if [[ ! -e sub_project ]]; then mkdir -p sub_project git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files sub_project fi' git checkout branch-to-merge-within git merge sub_project git branch -d sub_project 

如果我发现这种方法有任何问题,我会更新。

你需要使用

 git rebase --preserve-merges --preserve-committer --onto new_place start end