15

I find that working with git submodules, I often encounter problems merging between commits which do contain a given submodules and those which represent the same code as a normal directory. Small reproducing example:

# Create one project, to be used as a subproject later on
git init a
cd a
echo aaa > aa
git add -A
git commit -m a1
cd ..

# Create a second project, containing a as a normal directory initially
git init b
cd b
mkdir a b
echo aaa > a/aa
echo bbb > b/bb
git add -A
git commit -m b1

# Replace directory with submodule
git rm -r a
git submodule add ../a a
git commit -m b2

# Try to create branch from the pre-submodule state of affairs
git checkout -b branch HEAD^

This already gives an error:

error: The following untracked working tree files would be overwritten by checkout:
    a/aa
Please move or remove them before you can switch branches.
Aborting

In order to avoid the error, I deinitialize all submodules first:

# Create feature brach starting at version without submodule
git submodule deinit .
git checkout -b branch HEAD^
echo abc > b/bb
git commit -a -m b3

As you can see, the feature branch is completely unrelated to the submodule, modifying a different set of files. Which makes this whole problem particularly annoying.

# Try to merge the feature branch
git checkout master
git merge branch

This fails again, with an error message I don't fully understand:

CONFLICT (file/directory): There is a directory with name a in branch. Adding a as a~HEAD
Automatic merge failed; fix conflicts and then commit the result.

I get the same error if I do a git submodule update --init before the git merge branch. I don't see any a~HEAD anywhere, neither in my directory tree nor in the output from git status, which reads like this:

On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")

Changes to be committed:

    modified:   b/bb

Unmerged paths:
  (use "git add <file>..." to mark resolution)

    added by us:     a

If I do git add a as suggested, I get another error:

error: unable to index file a
fatal: updating files failed

If I do git submodules update --init just before the merge, then I can do git add a successfully. But if I forget to do so, and then try doing that after the merge, I receive this error message:

Submodule 'a' (…/a) registered for path 'a'
Skipping unmerged submodule a

How do I recover from this situation? Something other than git merge --abort, since I'd like to use it for things like git rebase as well, and since in some scenarios (don't know how to reproduce) I couldn't even abort the merge cleanly, and had to do a hard reset instead.

How can I avoid it in the first place? Is there some magic setting which makes git do the right thing with submodules vs. directories during merges, so that I don't have to manually post-process a merge which only modifies files unrelated to the submodules?

MvG
  • 57,380
  • 22
  • 148
  • 276
  • FYI the `--abort` flag works for rebase as well. – approxiblue Aug 08 '15 at 04:08
  • @user880772: Yes, but it aborts the whole rebase, which means considerable effort might get lost if there were some conflicts along the way. – MvG Aug 08 '15 at 08:31
  • 1
    Git [doesn't handle submodule merging](https://codingkilledthecat.wordpress.com/2012/04/28/why-your-company-shouldnt-use-git-submodules/). Not in its usual magical way. If you don't want to forget running submodule update before a merge, you can turn "merge" into an alias (I feel horrible suggesting that). I don't see a clean way around this. – approxiblue Aug 13 '15 at 02:59

2 Answers2

4

No you should not add a, the merge is not supposed to change it. What you should run is

git reset a

So you ignore the "chage" for a.

PS: apparently git merely checks existense of a directory, so if you

git submodule deinit a
rmdir a

before merging, it will succeed. Not sure if this is what you want.

max630
  • 8,762
  • 3
  • 30
  • 55
0

I got similar problem when I merge code that contains folder that need to convert to submodule.

I solved it by using BFG --delete-folders to remove the folder from the new source code, and git gc to clean up the repository, then I will have git rebase without any conflicts.

Ramius
  • 121
  • 8