So I used git-subtree to have various branches of repoB in sub-directories of repoA, like so
git clone repoA
cd repoA
// some commits to repoA here
git subtree a
Ok, so I figured this out. It was a two-pronged problem. First of all, my tree actually looked like this:
I had a commit in my tree that touched src/dirA
, but was not yet pushed when repoB/branchA
had already moved on.
I discovered that git subtree pull
would not find the right base, because it is looking for a common ancestor, hence it used the version when I had last merged the trees, i.e. when I called git subtree add
initially.
Now, to resolve the common ancestor problem, one has to git subtree split --rejoin
, which performs a perfunctory merge, so git finds the right base again, i.e. after the commits pushed from repoA
to repoB/branchA
.
However, as you can see in my case, a git subtree split --rejoin
followed by a git subtree pull
does not solve my problems:
Due to the fact that git subtree split
creates a synthetic history of all commit that touch src/dirA
irrespective of the fact whether or not they were pushed, the SHA-1 sums diverge. I split the synthetic history into its own branch split
for demonstration purposes.
git subtree pull
will of course succeed after git subtree split --rejoin
. However, the next git subtree push
will fail, because the histories of repoB
and the synthetic tree are completely different after that.
Therefore, I had to go back before the offending non-pushed commit and pull the changes into my branch from there. This is complicated by the fact that git subtree split --rejoin
is still necessary, because git subtree pull
via git merge
can still not figure out the correct base on its own.
So the way I currently resolved my issue was by checking out the commit directly before the offending non-pushed src/dirA
commit. Then I did a git subtree split --rejoin
followed by a git subtree pull
. This of course adds two merges into my main tree, which I could not figure out how to squash into one merge, and from what I read in source code, there doesn't seem to be an easy solution to that problem.
After the successful git subtree pull
, I rebased the remaining commits from my master
branch onto master_fix
. Now the SHA-1 sums match throughout the shared history of repoA/master_fix
and repoB/branchA
.
This of course has the usual drawbacks of a rebase: if somebody else was working on master
, their history will be ruined by git branch -m master_fix master
.