20

I have three repos - names changed for clarity:

SharedStuff, ProjectA and ProjectB

Both of the projects are using git-subtree to maintain a local copy of SharedStuff. They both have made local changes that I'm trying to merge up centrally, test, then merge back out to each again.

I've run this on the ProjectA repo:

git subtree split --prefix=SharedStuff -b SharedStuff_from_ProjectA --rejoin

...then pushed that to the SharedStuff repo, resolved a few simple conflicts, merged it up.

Now I've run this on the ProjectB repo:

git subtree split --prefix=platform/SharedStuff -b SharedStuff_from_Project_B --rejoin

...and again pushed that to the SharedStuff repo in a new branch. The problem occurs when I'm trying to merge those changes in.

In the current case, I switch to the SharedStuff_from_Project_B branch, then git merge master - but I immediately get all changed files listed as add/add conflicts. When I run git mergetool, each one has an error like this:

Merging:
somefile.xyz

Normal merge conflict for 'somefile.xyz':
  {local}: created file
  {remote}: created file
fatal: invalid path './somefile.xyz_BASE_20704.cs'

(Of course, if I try the other way around - to merge SharedStuff_from_Project_B into master - I get the same kinds of conflicts, just reversed. Still add/add).

My guess is that something might be wrong in ProjectB's history, causing the appearance of add/adds. I'm not sure how to further diagnose this, though - what can I do?

Edit: there was a previous subtree "rejoin" commit in ProjectB, but the changes weren't merged into SharedStuff at that point it seems. But, re-running git subtree split with --ignore-joins produces the same problem - lots of add/add merge conflicts, despite the history of that split subtree branch going back to when the SharedStuff was first put into ProjectB. :(

Edit: Also git merge-base between the split subtree from ProjectB and master on SharedStuff doesn't give any results. I'm not sure how this came to be or how to resolve?

Kieren Johnstone
  • 41,277
  • 16
  • 94
  • 144

1 Answers1

1

I do not know what caused this. However, here's how I resolved it - kind of. I still want a better answers!

Both 'shared' branches the actual master on SharedStuff and the split-off copy from ProjectB had a the same commits in their distant history - well, the same changes with the same tree SHAs internally, but different commit SHAs. This is because, somehow, the ProjectB branch had a different very first initial commit than SharedStuff.

So long as there were no common commits (with the same SHAs) in the history, merging, rebasing etc won't be able to find a common ground and will assume files were added in both histories.

The solution: find two early commits in the history with the same tree SHA (i.e. exactly the same file content), and commit info - message, author etc - and manually 'overwrite' the parent of that commit in ProjectB's split branch to the parent in SharedStuff's master.

I did this using a graft: Setting git parent pointer to a different parent

  1. Write a new line to .git/info/grafts, basically wrong-parent right-parent
  2. Switch to the branch - discover PowerShell echo used a 16-bit character format, re-save with Sublime Text and switch again ;)
  3. Run git filter-branch right-parent..HEAD on the branch to seal the deal
  4. Verify everything's mergeable

The next fun challenge will be seeing how this version merges back into ProjectB; will update when that's done..

I would still really welcome a real answer to this - this is really hacky!

Community
  • 1
  • 1
Kieren Johnstone
  • 41,277
  • 16
  • 94
  • 144
  • Quick correction: the graft line should actually be `child-of-wrong-parent right-parent`. But I still don't want to resort to this.. – Kieren Johnstone May 31 '16 at 07:17