Two repositories exist: rep1, rep2. Both are results of one-way syncs from the same SVN instance. (The changes in SVN are synched to git, but the changes in git are not synched back to SVN) the two repositories are not forks of each other.
rep1/master branch contains a file file1.txt
rep2/master branch contained the file file1.txt, but the file was deleted in rep2/
rep2 is added as a remote in rep1 in order to merge. (remot2)
branch rep2/master is created
git checkout -b rep2_master_branch --track rep2/master
a "merge" branch is created from the tip of rep1/master
git checkout -b merge-master-branches master
Execute a merge with option "theirs" and squash. allow-unrelated-histories is required as the merge comes from another server.
git merge -Xtheirs --squash rep2_master_branch --allow-unrelated-histories
What is observed is that rep1/file1.txt is NOT deleted.
Further observations, conflicts during the merge are correctly resolved, as are modififed and added files. It seems that the only omission are files that have been deleted in rep2.
How can I work around this? or better yet, how can this be resolved?
As far as Git is concerned, that is the correct merge result.
Git's
git mergeworks by comparing two branch tips to a common merge base. That is, if you draw the commit graph, and it looks like this:then the result of merging
branch1(commitL) withbranch2(commitR) will be computed by comparing the contents of commit*, the common point from which both branches derive, to the contents of commitLand to the contents of commitR.Whatever changed from
*toLhappened in the left side. Whatever changed from*toRhappened in the right side. Git combines these two "things that happened", applies those combined changes to the contents of*, and if all goes well, makes a new commit from the result.But you are using
--allow-unrelated-histories. This is required only when there is no common commit: we draw the history ofLandRand find that they never diverged from a common point. For instance, we might get:where
AandBare both root commits. So what should Git use as the common starting point, to figure out what changed since then?One can argue for various starting-points of one's choice, but Git's answer is: Use an empty commit. That is, with
--allow-unrelated-histories, Git pretends there's a common commit that has no files at all:Comparing commit
*, which is empty, to commitL, Git finds that every file onbranch1is newly created in the form that it has inL. Comparing*toR, Git finds that every file onbranch2is newly created in the form that it has inR. Wherever those files match, everything is fine: we just take that file. WhereverLhas a file thatRdoesn't or vice versa, everything is fine: we just take that file. Wherever bothLandRhave a file, but their contents differ, we have a merge conflict.Since you used
-X theirs, Git resolves each conflict by taking "their" changes ("theirs" being the commit you named, rather than the one you were on asHEAD) since the empty merge-base commit.If you want Git to pretend that some other commit is the merge base, you can use
git replace --graftto insert some fake parent linkage. For instance, suppose you want to fake-tie the two together at arbitrarily-chosen commit C:so that Git will compare
CtoL, andCtoR. As far asgit mergeitself goes, it doesn't matter which commit you choose in theA--...--Lchain; any commit will do (includingAandLthemselves), but note that Git will only "see" changes since the commit you pick (due to diffingC-vs-L, andC-vs-R). So, pick some appropriate commit in the chain and run:and Git will now use the replacement (graft) commit instead of the chosen commit. A
git mergewill now use the contents ofCas the common source. (You can delete the graft as soon asgit mergeexits, even if it exits with a merge conflict. Hence you can write a tiny script that inserts the graft, runsgit merge, and deletes the graft, to merge with arbitrarily-chosen ancestor. Just insert it as the replacement forLas long as it's on theB--...--Rline, or insert it as the replacement forRas long as it's on theA--...--Lline.)