I'm trying to learn the new git-subtree command which was added in Git 1.7.11. I seem to lose ability to rebase after I add a subtree. I have the primary repository with README file and a library repository which also has a README file. I add it to lib directory with subtree add
:
$ git subtree add -P lib/mylib myliborigin master
This works fine, but now the history looks like this:
* 22c1fe6 (HEAD, master) Merge commit 'b6e698d9f4985825efa06dfdd7bba8d2930cd40e' as 'lib/mylib' -
|\
| * b6e698d Squashed 'lib/mylib/' content from commit d7dbd3d
* b99d55b Add readme
* 020e372 Initial
Now when I want to rebase my repo against origin/master
and it fails because the squash commit is applied directly against its parent commit which does not apply, because it is applied to the root of the repo and not the prefix I gave it to it when adding the subtree.
The reason for this is pretty clear if I look at the squash commit. There is no information about the prefix. It is just the original mylib commits squashed together. Only the next merge commit knows anything about it, but rebase does not take it to account here.
Are there any workarounds (besides never rebasing over the subtree commits)?
This works in simple cases:
git rebase --preserve-merges master
Thanks to @Techlive Zheng in the comments.
You may see
fatal: refusing to merge unrelated histories
Error redoing merge a95986e...
Which means that git failed to automatically apply your subtree. This puts you in the situation @ericpeters described in his answer. Solution:
Re-add your subtree (use the same command you originally used):
git subtree add -P lib lib-origin master
Continue the rebase:
git rebase --continue
And you're all set!
If you're wondering if it worked successfully, you can compare with your original version after rebasing to make sure you didn't change anything:
git diff <ref-before-rebase> <ref-after-rebase> -- .
(the -- .
at the end instructs git to only diff
the files in your current directory).
If all else fails and you don't care about preserving the commits themselves, you can simply git cherry-pick
the original subtree commit.
The commit message will look something like Add 'lib/' from commit '9767e6...'
-- that's the one you want.