13

We used to have a local hack of delayed_job in a Rails app, in vendor/plugins/delayed_job. It was installed as a one-time event and checked into git in the main app repo.

Now we decided to fork delayed_job on github and replace the subdirectory by a git submodule, as described e.g. here:

http://doblock.com/articles/using-git-submodules-to-manage-plugins-in-rails

Before doing that, I simply removed vendor/plugins/delayed_job, without checking it in. Now, despite adding the submodule, git status in the main repo still shows new files in vendor/plugins/delayed_job.

How should we handle the situation where a subdirectory which was a part of the repo is deleted and made to hold a git submodule? Should we first delete it with git rm, or obliterate it even more thoroughly, before cloning a submodule into its place?

Alexy
  • 1,520
  • 2
  • 16
  • 30

2 Answers2

17

Assuming that you do not care about the current contents of vendor/plugins/delayed_job in your working tree (i.e. the content that will be checked out as a submodule is already a suitable replacement for the content in your working tree), the normal procedure for converting a directory into a submodule looks like this:

git rm -r vendor/plugins/delayed_job
git submodule add github.com:account/delayed_job.git vendor/plugins/delayed_job

Of course, the GitHub repository URL may vary; for example, you may want to use an HTTP URL instead of the above SSH URL.

But, it seems like you did something a bit different. As best I can tell, you did something like this:

rm -rf vendor/plugins/delayed_job
git clone github.com:account/delayed_job.git vendor/plugins/delayed_job

There are two flaws with this procedure:

  1. The plain rm leaves the old files in your Git index.
  2. Directly cloning gives you a “subrepository”, but not an official submodule.

Assuming that you do not have any intentionally staged changes in vendor/plugins/delayed_job (you probably do not, since you are replacing it with a submodule), you can clean up the situation with these commands:

git rm --cached -r vendor/plugins/delayed_job
git submodule add github.com:account/delayed_job.git vendor/plugins/delayed_job

Cleaning out all the vendor/plugins/delayed_job entries from the index should fix your “still shows new files” problem. Using git submodule add will create the .gitmodules file which turns the “subrepository” into a true submodule.

Chris Johnsen
  • 214,407
  • 26
  • 209
  • 186
  • 1
    Chris -- thanks for the rundown! The first rm -fr we did, but the second command was: git submodule add ... which is the last you show. I guess it differs from git clone only in that it creates .gitmodules, correct? So we probably should still be OK to do as you suggest... – Alexy Jun 30 '11 at 06:13
  • 1
    @Alexy: Yes, `git submodule add` will create the `.gitmodules` file. You should see it listed in the “Changes to be committed” section of `git status`. I am still confused about your “new files in vendor/plugins/delayed_job” though. It is invalid for the index to have a submodule at a particular directory and plain files under that same directory; your `git status` should not show any “new file”s under that directory once the submodule was in place there (though there will probably be “deleted” ones because the index had to be cleaned of files under that directory). – Chris Johnsen Jun 30 '11 at 07:03
  • we didn't do a git rm, and do see new files reported even after the submodule was just added... Basically showing new files in the submodule, even in the presence of .gitmodules. Perhaps we should roll back and do rm first as you suggest? – Alexy Jun 30 '11 at 14:19
  • 1
    @Alexy: My best guess is that you can do `git rm --cached -r vendor/plugins/delayed_job/` to clean the index of any plain file entries under the submodule’s directory. If you leave off the trailing slash, then you may need to do `git add vendor/plugins/delayed_job` (you **must not** use a trailing slash here!) to re-add the “gitlink” entry for the submodule. You should not need to use `git submodule add` again if you already have a cloned subrepository in place and a corresponding entry in `.gitmodules`. – Chris Johnsen Jun 30 '11 at 23:29
  • @Alexy: However, I still do not understand how you arrived at a state with a submodule (“gitlink” entry) at a path **and** files under that same path. It is technically possible, but it is an erroneous state; if it is reproducible with a recent version of Git, then it is a bug. – Chris Johnsen Jun 30 '11 at 23:30
4

I absolutely WOULD NOT RECOMMENDED DOING THIS. You're going to have a lot of fallout since git doesn't know what to do when a directory changes types into a submodule. It would be a significantly better idea to remove the old folder, then make a new one with a different name.

We have a repo used by many people (50+) and decided to make a submodule out of a folder. In order to not have to change some build scripts and the like we did the above change. But this makes git freak out, and so every old branch (pre submodule change) cannot be switched to without first deleting the folder and doing other nonsense, merges with old branches are extremely difficult, and worst of all our automated build system, which is distributed across several machines, totally broke and cannot be manually resolved like individual users can.

So. Just don't do it. Git absolutely does not handle it gracefully.

Eli
  • 4,874
  • 6
  • 41
  • 50