How to work around 'git subtree split' failing on revert commits?

329 views Asked by At

I'm running into the problem described in this mailing list post. 'git subtree split' fails to reconstruct the history when a revert commit is followed by a merge commit. I have slightly adjusted the test script provided by Fabien in his mailing list post:

git init

# create a directory that is going to be split
mkdir doc
echo "TEST" > doc/README
git add doc
# commit A
git commit -a -m"first version"

# create a branch with a new commit (Z)
git checkout -b test
echo "TEST" > doc/README1
git add doc/README1
git commit -a -m"added README1"
git checkout master

# modify the README file (commit B)
echo "TEST_" > doc/README
git commit -a -m"second version"

# revert the change (commit C)
echo "TEST" > doc/README
git commit -a -m"revert second version"
# or use git revert HEAD^

# split
git subtree split --prefix="doc" --branch=TARGET

# add another commit (to a file *not* in the subtree dir)
echo "BLA" > BLA
git add BLA
git commit -a -m"third version"

# adding another commit to a file in the subtree dir will "fix" things
#echo "MEH" > doc/MEH
#git add doc
#git commit -a -m"fourth version"

# the log will show the 3 commits as expected (including B and C)
GIT_PAGER= git log --oneline TARGET

# merge the test branch
git merge -m"merged test" test

# attempt to re-split; this will fail
git subtree split --prefix="doc" --branch=TARGET

# see what history split generates
git subtree split --prefix="doc" --branch=TARGET2

I have discovered that if the revert commit is followed by another commit that makes changes in the subtree directory, the split will work as expected (see "fourth version" above). This looks like a bug in git-subtree.

However, in my case, the merge has already been performed of course, so I cannot fix things by adding a dummy commit. Is there any other way around this? Perhaps a quick-fix patch to the git-subtree source code?

1

There are 1 answers

0
Brecht Machiels On

I think I understand what's going on. If there are no net changes in one of the two branches, the id of the merge commit will be the same as that of the last commit on the other branch (pass the -d option to git subtree split command to see the new commit id's of the split out commits). In that case, git-subtree will drop the merge commit. This is done because for regular commits, this means that the commit does not make changes to files in the subtree directory.

I was thinking the solution would be to simply adjust the copy_or_skip function to always copy merge commits. However, this may result in the produced commit history to differ from before (unnecessary merge commits were previously left out), leading to other problems.