How should I use git submodules to share code between Heroku apps? - ruby-on-rails

I have a few Rails 3 apps deployed to Heroku that need to share some business logic. Apparently, although Heroku's Bundler support is pretty solid, it can't yet pull from a private Github repo. So instead I'm building a couple of gems, vendoring them into each app, checking them into git, and pushing them up with the rest of my code.
This has worked alright, but every time I want to change something in these shared gems I have to go to each app, gem unpack to the right directory, git add/git remove all the files that have changed, and so on, and it's becoming a bit of a pain. I may also want to set up different branches of my business logic, and having different applications follow different branches, but I don't know how I'd accomplish that by vendoring.
It looks like git submodules were invented for this kind of situation, but the last time I tried submodules I just found them horribly confusing. I suppose that's what I'd need to do, but the code snippet that Heroku gives as an example at that link is also pretty confusing.
So, my questions:
Are submodules what I want to use here?
What's the simplest possible git workflow I'd need in order to do what I'm describing?
I'm not a beginner with git, but I'm not quite intermediate either, and I want to start with a simple set of steps I can use to learn from. I'd need to track a local git repository from within my vendor/gems directory, pull in updates from that repository regularly, and do so in such a way that Heroku/Bundler doesn't throw a fit when I try to push the entire app to production.
Thank you!

You might find apenwarr’s git subtree command helpful. It provides a nice wrapper around Git’s subtree merge functionality.
Add a new subtree:
git subtree add --prefix=vendor/gems/shiny remote-or-url-to-shiny-gem branch
Pull new commits into the subtree:
git subtree pull --prefix=vendor/gems/shiny remote-or-url-to-shiny-gem branch
You might also like the --squash option if you do not want to incorporate the history.
You can also use git subtree to extract local commits that change the subtree so that they can be pushed to the subtree’s source repository (the split and push sub-commands).

You can use the git-subtree technique
http://progit.org/book/ch6-7.html

As for me, git-subtree was a non sufficient. It required too much tweaking and digging and the result had some annoying flaws and made it look like a bandage. BTW The mentioned apenwarr’s git subtree was last updated two years ago (as to Apr12...) and if git subtree is chosen then i recommend using helmo's fork (or alikes).
I would deifintly recommend using git submodules. Sure, its has some flaws too, but most of them are better handled in later version of git, and you could add some hooks and scripts to make it usable by git newbies. Plus, its far more widely used.
Regarding Heroku, it is now supported. If you need private repositories, Create a user and use its credentials for this purpose and use this format for the repository location:
https://username:password#github.com/user/repo.git
More, For Ruby apps, you can alternately do this with Bundler's :git option.
HTH

Related

What's the best way to look up why/when changes were made in a git?

I am inspecting the gem Shoulda as an example. Shoulda no longer has the methods assert_good_value. So my question is, what is the best way to figure out when and why it was removed, and what it might have been replaced by?
So far, the only way I could think to do this is to clone the git related to Shoulda, and do :
git log -Sassert_good_value
Which brought back a few commits worth investigating. However, I'm not really sure how to investigate these commits other than git checkout into the SHA and see if I can see anything important. But doing so this way does not show me what was added/removed, and it also doesn't show me how or if any of these are connected to a git issue.
What am I possibly doing wrong, or what is the best way to accomplish this?
git log -p
That gives you a less interface containing each commit as a diff. Then enter /assert_good_value to search for a change to it.
To investigate the commits from doing the git log -Sassert_good_value, you could just git show into the SHA. That will return all the changes made by that certain commit.
Hope that helps!

git command in rails controller

I am trying to set up a system where, when I commit changes to my GitHub repository, my server also receives those commits.
To do that, I set my GitHub repo to send a post-receive hook to a URL on my rails app. I have a controller that will handle this.
The problem is this: how can I run git commands in a rails controller? I get how to do it in the command line.
Do I just type something like this:
# controller method where post-receive hook is sent
def commit
git pull origin development
end
Do this!
def commit
system "git pull origin development"
end
There is quite a big difference between what your stated goal is and what the command you're planning to use does. In order to get the commits, all you need to run is git fetch. You can use system or backticks in order to run shell commands from your ruby code, but you need to be careful about what you run. You should keep in mind that a pull is a merge, which means that at any time changes could conflict and it would leave your repository waiting for human intervention (not to mention files with conflict markers all over them) as it's part of the high-level user interface, and not meant at all to be scripted.
If you do want the version of the files in the tip, to do deployment or similar, you can check out http://gitolite.com/the-list-and-irc/deploy.html for some different ways to do that, depending on the situation.
You can use a combination of shelling out to git fetch and git checkout or rugged in your code to perform this update, and be aware that this is all IO-bound (part of it over the network) which means that it can take an arbitrary amount of time to run, which may not work too well with the rest of your app if it's blocking ruby's execution.
Try a Ruby abstraction on top of Git like Rugged or Ruby/Git. Both remain active while other similar libraries seem to have fallen by the wayside.

Ignoring .gitignore

My brother and I are collaborating on an app from two different computers -- one mac and one pc. I can't for the life of me get Postgres to work on his computer, and after a whole bunch of hours, I decided to just have his computer run sqlite3 for development (which is easy as pie), and basically have all the production stuff happen on my mac, while still allowing him to make functional changes from his pc. And merge them to github.
The trouble is, this involves having two different database.yml files, two different db/schema.rb files (I think), and different gemfiles, one with sqlite and the other with pg.
My thought was just to do all that on his computer and add those files to the gitignore file. But if THAT isn't ignored, then when I pull back to my mac, won't I be merging his incorrect configurations to my machine?
At any rate, that's why I was thinking of adding .gitignore to .gitignore. Will this work? Will it create universe-bending paradoxes? Is there a better way to do this that I don't know about?
Are those two schemas really different? They usually aren't.
If they aren't then just ignore config/database.yml and create contig/database_sqlite_example.yml and contig/database_ppostgresql_example.yml. That way, when someone clones repo, he can use SQLite or PostgreSQL by simply copying example file to database.yml (which will be ignored)
No, don't ignore .gitignore
I've always liked the idea of creating local branches for this. I actually go a little local branch crazy... but that's a different issue all together.
If you want to have a private little work bubble then keep your branch local only. You control what gets merged into master (or whatever your development branch is) and you can commit everything in your local branch to git for history sake.
If you want to share what you are working on then just share your branch out. But this way you can keep your environment setups isolated while sharing the local branch so that it is visible for collaboration.
There's plenty of good documentation on Git Branching and Sharing so I'll leave that to you instead of clouding the post with links that surely will get broken.
I'm not sure any of us "really want to" be working directly in the master anyway, especially in collaboration efforts such as yours.

How to version control a rails plugin and the testing app together

I'm in the process of creating my first rails plugin and am finding managing version control of the plugin and testing app rather annoying.
Here's my problem:
To actually test my plugin in action I need to run it within a test application (which is basically just a scaffold app where I install the plugin)
When I'm making changes to the plugin, it's convenient for me to change it within the test application so i can immediately see the changes come through. However, when I want to commit and push my changes back to github I end up copying all the files out of the test app back into my "naked plugin" folder and doing my commits.
Is there a better way to manage this without copying files back and forth? I'm interested to hear from other plugin developers if possible on how you manage this situation.
One potential solution I've conceived of is to have another git repository within the vendor/plugins/myplugin directory (which will have the remote repo of github). Im not sure if this is best though (and so far I haven't been very successful in making it work...)
I recommend to use git submodules, check a detailed description.
I create a soft link in the vendor/plugin directory to point to the plugin source code.
If you are on Windows you can use the junction tool to create a softlink.
E.g:
c:\test_app
vendor
plugin
foo_plugin -> points to c:\foo_plugin
c:\foo_plugin
lib
Submodules are going work best I think. What I don't like about developing plugins is that you're always starting/stopping the script/server. Without knowing what kind of plugin you're building, I'll just assume that you're building an abstracted class of some kind.
I personally think the best way to go is to develop the class in the lib directory of your rails app. Once you get it about 99% done, then move the class into the lib directory of your plugin. Then commit the changes to the plugin repo.
If you're willing to package your final plugin as a gem, then there is a much easier way. In your basic scaffold app, inside your Gemfile you can point to a local path:
gem 'foo', :path => "../foo"
This way your scaffold app and engine/plugin are in two separate directories; two completely unrelated git repos. You don't even have to start & stop your scaffold web server when you make changes to the plugin (at least in rails 3).
I just wrote up a tutorial for how I created my first rails engine and I extracted the foundation into a good starting point for other engine builders:
http://keithschacht.com/creating-a-rails-3-engine-plugin-gem
As an end user of a plugin, I think it's much easier if it's packaged as a gem. Not only is more functionality possible with a gem, developers can install it once and use it in many apps, dependencies can be easily handled, upgrades are as simple as changing a version number, and you don't have to store the entire plugin in your main app's repo.

Good Git deployment using branches strategy with Heroku?

What is a good deployment strategy to use with Git + Heroku (Ruby on Rails)?
Currently, the way I work with my origin Git repository: All features (or 'stories') are first checked out as branches, then get merged with master and pushed to origin.
Anything pushed to origin/master triggers a script that pulls the new rails code to the staging area (simple rails webserver).
When the time comes for me to push a new production version to Heroku, should I create a new branch (called something like production_version_121), and push that somehow to Heroku?
Ideally, I'd like to pick and choose which features from previous development versions I should include into the production branch... test it, and push to Heroku.
For example, I may not want all the latest code to get pushed to production. I might want to feature "a" that I had worked on and feature "c" both merged into production somehow, without including experimental feature "b" which needs more debugging.
N.B. I'm going to try avoiding Capistrano at first and get something working manually for now.
Any thoughts? Best practices?
In the Gemcutter project we simply have a production branch. Any changes that we want to see on the production site get merged into that branch, and then deployed with:
git push heroku production:master
The staging branch serves a similar purpose for the staging site (also on Heroku)
Ever since I read Vincent Driessen's A successful Git branching model, I have been hooked. My entire company (8 of us) have now standardized on this model and a few other places I've consulted with have also started using it as well.
Most everyone I've shown it to says they were doing something similar already and found it very easy to adapt.
In a nutshell, you have 2 branches that are permanent (master and develop). Most of the time you'll just be making branches off of develop and merging them back into develop. Things get a little more complex when you get into doing production releases and hotfixes, but after reading the post a couple of times, it becomes engrained.
There's even a command line tool called git-flow to help you out.
There are a variety of ways to go about this, and it really depends on your preference.
I'll give you one possible strategy off the top of my head: Given you already have an automated staging setup that uses master, I would suggest creating a 'production' branch. When you want to promote a fix/feature to production, you would just merge the topic branch into your 'production' branch.
git checkout production
git pull . my-topic-branch
(resolve any conflicts)
When you are ready to actually push that code to your production server, you should tag the branch using a unique name (probably with a timestamp). Then you simply push the production branch to Heroku.
git checkout production
git tag release-200910201249
I'd suggest creating a script or git alias to automate the tagging for timestamps, since using a consistent naming scheme is important. I use something like this:
git config alias.dtag '!git tag release-`date "+%Y%m%d%H%M"`'
That allows me to do just type git dtag when I want to tag a release with a timestamp.
You can view you tags using git tag and view them using git show release-1234. For more information on tags, run git help tag. You may also find this Github guide on tagging helpful. I'd also recommend reading up other people's workflows (here's a nice writeup) and pick and choose what works for you.

Resources