开发者

Sharing code between two or more rails apps... alternatives to git submodules?

We have two separate rails_app, foo/ and bar/ (separate for good reason). They both depend on some models, etc. in a common/ folder, currently parallel to foo and bar.

Our current svn setup uses svn:externals to share common/. This weekend we wanted to try out git. After much research, it appears that the "kosher" way to solve this is using git submodule. We got that working after separating foo,bar,common into separate repositories, but then realized all the strings attached:

  1. Always commit the submodule before committing the parent.
  2. Always push the submodule before pushing the parent.
  3. Make sure that the submodule's HEAD points to a branch before committing to it. (If you're a bash user, I recommend using git-completion to put the current branch name in your prompt.)
  4. Always run 'git submodule update' after switching branches or pulling changes.

All these gotchas complicate things further than add,commit,push. We're looking for simpler ways to share common in git. This guy seems to have success using the git subtree extension, but that deviates from standard gitand still doesn't look that simple.

Is this the best we can do given our project structure? I don't know enough about rails plugins/engines, but that seems like a possible RoR-ish way to share libraries.

T开发者_运维技巧hanks in advance.


I think that the git submodule system have a great advantage over svn:externals or symbolic links (and it is also that makes them more difficult to use): the actual submodule version is stored for each superproject version. So is is quite safe to make changes in the submodule that breaks backward-compatibility: it will be possible to checkout any version of the superproject(s) with the proper submodule version, because the superproject will contain a reference to the proper submodule code. You may also maintain two branches of the submodule (v1.0.x and v2.0.x, for example) and use different branches in different projects without a problem.

So I think it is really worth to use submodules even if they are a bit complicated. Git 1.7 has some major improvements on this area, for example git status now indicates the uncommitted modifications in submodules, so you probably don't forget to commit submodules first. A good GUI may also be a help (I have a small pet project about this, see here).

If you really don't want to care about submodule versions (you never make backward-incompatibile changes in the common code) then I also suggest using symbolic links. Although committing and fetching won't be much easier than for a submodule...


I tend to prefer symbolic links to submodules.

1) Have foo, bar, and the common code (common) in 3 separate repos.

2) In directory for foo, add a symbolic link to common, where necessary.

$ cd foo
$ ln -s /path/to/common lib/common

3) Check in the link.

$ git add lib/common
$ git commit

4) Repeat for bar

This takes advantage of the fact that git respects symbolic links and stores the location of the target (as opposed to following the link.)

Ofcourse, the expectation is for you to consistently use the same target path for common. I work around this by not checking in the symlink, and adding a README.setup file in each of my projects reminding me to add the requisite symlinks upon initialization. Having a devsetup.sh that does this sort of initialization is useful here too.

IMO, this is much nicer to deal with than submodules.


A Plugin is totally the way to go, and if you end up using it on more than two projects or would be useful to the general public, probably worth the effort to make it into making it a gem.

Here is a good resource on the subject

http://nubyonrails.com/articles/the-complete-guide-to-rails-plugins-part-i

and more importantly ...

http://nubyonrails.com/articles/the-complete-guide-to-rails-plugins-part-ii

In the end you will have three git repositories one for foo, one for bar and one for the plugin.

Then in each project to keep it upto data you will be able to do

./script/plugin install --force git://github.com/path/to/plugin/repository

to keep it upto date.

Good luck!

-- jonathan


Git subtree is a part of GIT since 1.7.11 and I wrote an article about sharing code between Rails applications: http://igor-alexandrov.github.com/blog/2013/03/28/using-git-subtree-to-share-code-between-rails-applications

In short: yes git-subtree works and works great!


If you're looking at making a plugin, you should also consider making a gem. They are very similar in terms of using them, but gems tend to be easier to work with, support dependency management, and are easier to share/distribute with the community.

Ryan Bates of Railscast has a great tutorial video about making a gem that you can find here: http://railscasts.com/episodes/135-making-a-gem


You could create a repository with the common code and clone it twice. Both clones would become foo and bar. You could still develop the common code in separate branches in both projects and push that branch to the common code repository. To update the common code in the projects you would just merge the common branch into the master branches of foo and bar.

UPDATE: You can imagine this as a single repository with three branches: common, foo and bar. You would have the common code in the common branch and add the project specific code only to the foo or bar branches. Now you could clone this repository twice as foo and bar and delete one branch from both of them (branch foo from bar repository and branch bar from foo repository). Then you would delete both foo and bar from the first repository. This would become the common repository. The final result would be the same as above.


The best thing you can do is to create a plugin for your common libraries, or even a gem, that way you have a nice way to update/distribute it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜