<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
 
 <title type="text">Jason Meridth :: Personal Blog</title>
 
 <link href="http://blog.jasonmeridth.com/" />
 <updated>2011-12-25T20:46:10-08:00</updated>
 <id>http://blog.jasonmeridth.com/</id>
 <author>
   <name>Jason Meridth</name>
   <email>jmeridth@gmail.com</email>
 </author>

 
 <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/jmeridth" /><feedburner:info uri="jmeridth" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>29.523294</geo:lat><geo:long>-98.745046</geo:long><entry>
   <title>Readline Error With RVM and Rails 3 on Ubuntu</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/uhKPladILx8/readline-error-with-rvm-and-rails-3.html" />
   <updated>2010-11-25T00:00:00-08:00</updated>
   <id>http://blog.jasonmeridth.com/2010/11/25/readline-error-with-rvm-and-rails-3</id>
   <content type="html">&lt;h1&gt;Readline Error With RVM and Rails 3 on Ubuntu&lt;/h1&gt;

&lt;p class="meta"&gt;25 November 2010 - San Antonio&lt;/p&gt;


&lt;p&gt;So I'm using Rails 3 with RVM these days.  The last few times I created a new slice or restaged a laptop/desktop with Ubuntu I always seem to have an issue when I try to run the Rails console:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;my_app/&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;rails console
/home/jmeridth/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/irb/completion.rb:9:in &lt;span class="sb"&gt;`&lt;/span&gt;require&lt;span class="s1"&gt;&amp;#39;: no such file to load -- readline (LoadError)&lt;/span&gt;
&lt;span class="s1"&gt;  from /home/jmeridth/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/irb/completion.rb:9:in `&amp;lt;top (required)&amp;gt;&amp;#39;&lt;/span&gt;
  from /code/my_app/shared/bundle/ruby/1.9.1/gems/railties-3.0.1/lib/rails/commands/console.rb:3:in &lt;span class="sb"&gt;`&lt;/span&gt;require&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;  from /code/my_app/shared/bundle/ruby/1.9.1/gems/railties-3.0.1/lib/rails/commands/console.rb:3:in `&amp;lt;top (required)&amp;gt;&amp;#39;&lt;/span&gt;
  from /code/my_app/shared/bundle/ruby/1.9.1/gems/railties-3.0.1/lib/rails/commands.rb:20:in &lt;span class="sb"&gt;`&lt;/span&gt;require&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;  from /code/my_app/shared/bundle/ruby/1.9.1/gems/railties-3.0.1/lib/rails/commands.rb:20:in `&amp;lt;top (required)&amp;gt;&amp;#39;&lt;/span&gt;
  from script/rails:6:in &lt;span class="sb"&gt;`&lt;/span&gt;require&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;  from script/rails:6:in `&amp;lt;main&amp;gt;&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;I looked at the RVM site and saw how to install the readline package:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;rvm package install readline
&lt;span class="nv"&gt;$ &lt;/span&gt;rvm remove 1.9.2
&lt;span class="nv"&gt;$ &lt;/span&gt;rvm install 1.9.2 --with-readline-dir&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$rvm_path&lt;/span&gt;/usr
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;I did this and it still didn't work.  The advice I received from googling was to compile the readline extension by hand and see if any dependencies were missing:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;sudo apt-get install libncurses5-dev libreadline5-dev
&lt;span class="nv"&gt;$ &lt;/span&gt;ruby ~/.rvm/src/ruby-1.9.2-p0/readline/ext/extconf.rb
checking &lt;span class="k"&gt;for &lt;/span&gt;tgetnum&lt;span class="o"&gt;()&lt;/span&gt; in -lncurses... no
checking &lt;span class="k"&gt;for &lt;/span&gt;readline/readline.h... no
checking &lt;span class="k"&gt;for &lt;/span&gt;readline/history.h... no
checking &lt;span class="k"&gt;for &lt;/span&gt;readline&lt;span class="o"&gt;()&lt;/span&gt; in -lreadline... no
...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This meant that I was missing the lncurses and libreadline libraries from apt-get.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;sudo apt-get install libncurses5-dev libreadline5-dev
...they install...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now when I run extconf.rb, everything is there:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ruby ~/.rvm/src/ruby-1.9.2-p0/readline/ext/extconf.rb
checking &lt;span class="k"&gt;for &lt;/span&gt;tgetnum&lt;span class="o"&gt;()&lt;/span&gt; in -lncurses... yes
checking &lt;span class="k"&gt;for &lt;/span&gt;readline/readline.h.... yes
checking &lt;span class="k"&gt;for &lt;/span&gt;readline/history.h... yes
checking &lt;span class="k"&gt;for &lt;/span&gt;readline&lt;span class="o"&gt;()&lt;/span&gt; in -lreadline... yes
...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;A make file was generated, I run it, and then install:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/.rvm/src/ruby-1.9.2-p0/readline/ext/
&lt;span class="nv"&gt;$ &lt;/span&gt;make
...
&lt;span class="nv"&gt;$ &lt;/span&gt;sudo make install
...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now the rails console works:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;my_app&lt;span class="nv"&gt;$ &lt;/span&gt;rails console
Loading development environment &lt;span class="o"&gt;(&lt;/span&gt;Rails 3.0.3&lt;span class="o"&gt;)&lt;/span&gt;
ruby-1.9.2-p0 &amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;



</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2010/11/25/readline-error-with-rvm-and-rails-3.html</feedburner:origLink></entry>
 
 <entry>
   <title>Gotcha with Gitosis and python-setuptools</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/uMJFUNcHPDg/gotcha-with-gitosis-and-python-setuptools.html" />
   <updated>2010-05-26T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2010/05/26/gotcha-with-gitosis-and-python-setuptools</id>
   <content type="html">&lt;h1&gt;Gotcha with Gitosis and python-setuptools&lt;/h1&gt;
&lt;p&gt;26 May 2010 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;Today I decided to upgrade my slicehost slice from Intrepid Ibex to Lucid Lynx (Intrepid &amp;#8594; Jaunty &amp;#8594; Karmic &amp;#8594; Lucid).  Yeah, yeah, I&amp;#8217;m a little behind.  Anyways, It upgraded just fine.  However when I was trying to push code to my gitosis instance (which I installed over a year ago), I got the following stack trace:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/code/gitosis-admin&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; git pull origin master
/usr/bin/gitosis-serve:5: UserWarning: Unbuilt egg &lt;span class="k"&gt;for &lt;/span&gt;setuptools &lt;span class="o"&gt;[&lt;/span&gt;unknown version&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;/usr/lib/python2.6/dist-packages&lt;span class="o"&gt;)&lt;/span&gt;
  from pkg_resources import load_entry_point
Traceback &lt;span class="o"&gt;(&lt;/span&gt;most recent call last&lt;span class="o"&gt;)&lt;/span&gt;:
  File &lt;span class="s2"&gt;&amp;quot;/usr/bin/gitosis-serve&amp;quot;&lt;/span&gt;, line 5, in &amp;lt;module&amp;gt;
    from pkg_resources import load_entry_point
  File &lt;span class="s2"&gt;&amp;quot;/usr/lib/python2.6/dist-packages/pkg_resources.py&amp;quot;&lt;/span&gt;, line 2655, in &amp;lt;module&amp;gt;
    working_set.require&lt;span class="o"&gt;(&lt;/span&gt;__requires__&lt;span class="o"&gt;)&lt;/span&gt;
  File &lt;span class="s2"&gt;&amp;quot;/usr/lib/python2.6/dist-packages/pkg_resources.py&amp;quot;&lt;/span&gt;, line 648, in require
    &lt;span class="nv"&gt;needed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; self.resolve&lt;span class="o"&gt;(&lt;/span&gt;parse_requirements&lt;span class="o"&gt;(&lt;/span&gt;requirements&lt;span class="o"&gt;))&lt;/span&gt;
  File &lt;span class="s2"&gt;&amp;quot;/usr/lib/python2.6/dist-packages/pkg_resources.py&amp;quot;&lt;/span&gt;, line 546, in resolve
    raise DistributionNotFound&lt;span class="o"&gt;(&lt;/span&gt;req&lt;span class="o"&gt;)&lt;/span&gt;
pkg_resources.DistributionNotFound: &lt;span class="nv"&gt;gitosis&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;0.2
fatal: The remote end hung up unexpectedly
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This told me that I had been using python-setuptools for python 2.5.  A little googling and praying that I wouldn&amp;#8217;t have to roll back to the snapshot I took before I started the upgrade (Thank God!), I found the solution.  I went onto the gitosis slice, cloned the gitosis repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git clone git://eagain.net/gitosis
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;and then ran the setup again:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~ &amp;gt; &lt;span class="nb"&gt;cd &lt;/span&gt;gitosis
~ gitosis/ &amp;gt; sudo python setup.py install
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;and it fixed the issue.  Did I mention how much I love google.  Hope this helps someone else.&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2010/05/26/gotcha-with-gitosis-and-python-setuptools.html</feedburner:origLink></entry>
 
 <entry>
   <title>Gitosis and Gitweb Part 3</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/iYgtOj-gtfA/gitosis-and-gitweb-part-3.html" />
   <updated>2010-05-26T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2010/05/26/gitosis-and-gitweb-part-3</id>
   <content type="html">&lt;h1&gt;Gitosis and Gitweb Part 3&lt;/h1&gt;
&lt;p&gt;26 May 2010 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blog.jasonmeridth.com/2010/05/22/gitosis-and-gitweb-part-1.html"&gt;Gitosis and Gitweb &amp;#8211; Part 1&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://blog.jasonmeridth.com/2010/05/22/gitosis-and-gitweb-part-2.html"&gt;Gitosis and Gitweb &amp;#8211; Part 2&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://blog.jasonmeridth.com/2010/05/26/gitosis-and-gitweb-part-3.html"&gt;Gitosis and Gitweb &amp;#8211; Part 3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So we are setup, have a project, and have contributors via the first 2 parts.&lt;/p&gt;
&lt;p&gt;I know that we are all enamored by the UI of &lt;a href="http://github.com"&gt;GitHub.com&lt;/a&gt;.  I am.  Unfortunately you can&amp;#8217;t get private repositories for free (In all fairness it&amp;#8217;s only $7/mo. &amp;#8211; a &lt;em&gt;very&lt;/em&gt; wise investment).  I am aware of &lt;a href="http://gitorious.com"&gt;Gitorious&lt;/a&gt; like I mentioned in the first part, but I have no experience with that.  I will after this series and update this series if I find it better.  Again, I like to use the simplest thing that works. (Of course, &amp;#8220;simplest&amp;#8221; is in the eye of the beholder)&lt;/p&gt;
&lt;p&gt;In this section I&amp;#8217;m going to show you how to install Gitweb, a UI tool that let&amp;#8217;s you view your repositories.  I&amp;#8217;m also going to mention how to get it to auto-detect any new repositories and ensure they show up on the web UI.  I learned how to do most of this from my co-worker &lt;a href="http://twitter.com/ajmesserli"&gt;Antony Messerli&lt;/a&gt;.  He is a true Linux and problem-solving Jedi.&lt;/p&gt;
&lt;h2&gt;Install Apache&lt;/h2&gt;
&lt;p&gt;First, you need to ensure apache2 is installed.  Check to see if you have an /etc/apache2 folder.  If you do, you should be okay.  If you don&amp;#8217;t, you need to install it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;sudo apt-get install apache2
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;For more in-depth advice, I always reference the &lt;a href="http://articles.slicehost.com/2010/5/19/installing-apache-on-ubuntu"&gt;Slicehost Articles&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once you have that installed the daemon restarted, go to your slices ip address in the browser of your choice (i.e,. http://123.123.123.123) and you should something like &amp;#8220;It Works&amp;#8221;&lt;/p&gt;
&lt;p&gt;Voila! You have apache running.&lt;/p&gt;
&lt;h2&gt;Install the Package&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;sudo apt-get install gitweb
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This will install gitweb into /usr/share/gitweb, create a conf file at /etc/gitweb.conf, and add four files to /usr/share/gitweb/static (git-favicon.png, git-logo.png, gitweb.css, gitweb.js).&lt;/p&gt;
&lt;p&gt;You only need to edit the $projectroot variable in the /etc/gitweb.conf to point to your gitosis repositories folder:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="c"&gt;# path to git projects (&amp;lt;project&amp;gt;.git)&lt;/span&gt;
&lt;span class="nv"&gt;$projectroot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/home/git/repositories&amp;quot;&lt;/span&gt;;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Since this isn&amp;#8217;t a post about Apache, I just add the gitweb directory setup to the base Apache config.  Since Ubuntu includes the entire /etc/apache2/conf.d directory, I just added the following information into /etc/apach2/conf.d/gitweb:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;RewriteEngine on
RewriteRule ^/gitweb/&lt;span class="o"&gt;([&lt;/span&gt;a-zA-Z0-9_&lt;span class="se"&gt;\-&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;+&lt;span class="se"&gt;\.&lt;/span&gt;git&lt;span class="o"&gt;)&lt;/span&gt;/?&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="se"&gt;\?&lt;/span&gt;.*&lt;span class="o"&gt;)&lt;/span&gt;?&lt;span class="nv"&gt;$ &lt;/span&gt;/cgi-bin/gitweb.cgi/&lt;span class="nv"&gt;$1&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;L,PT&lt;span class="o"&gt;]&lt;/span&gt;

Alias /gitweb /home/git/repositories
&amp;lt;Directory /home/git/repositories&amp;gt;
Options Indexes FollowSymlinks ExecCGI
DirectoryIndex /cgi-bin/gitweb.cgi
AllowOverride None
&amp;lt;/Directory&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Restart Apache to make sure everything works&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;sudo /etc/init.d/apache2 restart
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The first time you go to your website again, you&amp;#8217;ll see Gitweb, but it&amp;#8217;ll say no projects are available.  Fix mentioned below.&lt;/p&gt;
&lt;h3&gt;Permission Hack (open to suggestions)&lt;/h3&gt;
&lt;p&gt;1. I had to make the repositories that I wanted visible in gitweb have permissions of 755 (aka owner has read, write, execute.  group and others have read, execute.)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;sudo chmod -R 755 /git/repositories/lostechies.git
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Once that was done I can see the repository and it&amp;#8217;s information on Gitweb.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://c1261852.cdn.cloudfiles.rackspacecloud.com/gitweb.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;If you want to edit the project description from &amp;#8220;Unnamed repository; edit this file &amp;#8216;description&amp;#8217; to name the repository.&amp;#8221; go to the repositories description file (/home/git/repositories/lostechies.git/description for this repo) and edit the file and save.&lt;/p&gt;
&lt;h3&gt;Cron job&lt;/h3&gt;
&lt;p&gt;I, again with the leadership of Ant, utilized a cron job he wrote to automatically make the repositories have permissions of 755.  I do have some repositories, like gitosis-admin, that I do not ever want visible on Gitweb.  The cron job excludes them.  Here is the cron job code, showing that I don&amp;#8217;t want to show my personal.git and gitosis-admin.git repositories.  This could be easily written in Ruby or any other &amp;#8220;scripting language&amp;#8221; of your choice:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="nv"&gt;GITOSIS_REPO_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/home/git/repositories&amp;quot;&lt;/span&gt;
&lt;span class="nv"&gt;GITOSIS_ADMIN_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$GITOSIS_REPO_PATH/gitosis-admin.git&amp;quot;&lt;/span&gt;
&lt;span class="nv"&gt;PERSONAL_REPO_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;$GITOSIS_REPO_PATH/personal.git&amp;quot;&lt;/span&gt;

debug &lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;[D]: $1&amp;quot;&lt;/span&gt; &amp;gt; /dev/null
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;dir in &lt;span class="sb"&gt;`&lt;/span&gt;find &lt;span class="nv"&gt;$GITOSIS_REPO_PATH&lt;/span&gt; -maxdepth 1 -mindepth 1 -type d&lt;span class="sb"&gt;`&lt;/span&gt;; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="k"&gt;    if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$dir&amp;quot;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$GITOSIS_ADMIN_PATH&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;        if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$dir&amp;quot;&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$PERSONAL_REPO_PATH&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
                &lt;span class="sb"&gt;`&lt;/span&gt;chmod -R 0755 &lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
        &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="k"&gt;    fi&lt;/span&gt;
&lt;span class="k"&gt;    &lt;/span&gt;debug &lt;span class="s2"&gt;&amp;quot;All repositories have permissions set to 0755&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I chose bash, so that I could take that time to learn it.&lt;br /&gt;
Translation:  Find all the directories in my gitosis repository path (/home/git/repositories) and if they are not gitosis-admin or personal, change their permissions, recursively, to 0755.&lt;/p&gt;
&lt;p&gt;I put this in a file called set_gitosis_permissions_to_view_on_gitweb.sh and put it in root&amp;#8217;s home folder, /root.  I then called the file from root&amp;#8217;s crontab:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~ /&amp;gt; sudo su -
&lt;span class="c"&gt;# /root &amp;gt; crontab -e&lt;/span&gt;
&lt;span class="c"&gt;# m h  dom mon dow   command&lt;/span&gt;
*/5 * * * * /root/set_gitosis_permissions_to_view_on_gitweb.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This means that every 5 minutes, my bash file will set any new repositories to 0755.  This is how to get Gitweb stood up.  The next post will show how to hide it behind &lt;span class="caps"&gt;HTTP&lt;/span&gt; basic auth and a self-signed certificate.&lt;/p&gt;
&lt;p&gt;Next Part:  Hiding the Gitweb site&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2010/05/26/gitosis-and-gitweb-part-3.html</feedburner:origLink></entry>
 
 <entry>
   <title>Gitosis and Gitweb Part 2</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/e4aUSIcNEXA/gitosis-and-gitweb-part-2.html" />
   <updated>2010-05-22T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2010/05/22/gitosis-and-gitweb-part-2</id>
   <content type="html">&lt;h1&gt;Gitosis and Gitweb Part 2&lt;/h1&gt;
&lt;p&gt;22 May 2010 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blog.jasonmeridth.com/2010/05/22/gitosis-and-gitweb-part-1.html"&gt;Gitosis and Gitweb &amp;#8211; Part 1&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://blog.jasonmeridth.com/2010/05/22/gitosis-and-gitweb-part-2.html"&gt;Gitosis and Gitweb &amp;#8211; Part 2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So we are setup now thanks to Part 1.&lt;/p&gt;
&lt;h2&gt;Gitosis repository contents&lt;/h2&gt;
&lt;p&gt;If we issue the &amp;#8220;find .&amp;#8221; command locally inside the gitosis-admin directory we will see the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/gitosis-admin&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; find .
&amp;lt;a bunch of files from the .git folder&amp;gt;....
./gitosis.conf
./keydir
./keydir/user@local.pub
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We have the .git folder, a gitosis.conf file, and a keydir with a pub key file.&lt;/p&gt;
&lt;h2&gt;Add our first project&lt;/h2&gt;
&lt;p&gt;Our project name for this example is lostechies. If you view the gitosis-admin.conf file you will see the initial content like so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/gitosis-admin&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; cat gitosis.conf 
&lt;span class="o"&gt;[&lt;/span&gt;gitosis&lt;span class="o"&gt;]&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;group gitosis-admin&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;writable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; gitosis-admin
&lt;span class="nv"&gt;members&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; user@local
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This is the result of the following command from the last part:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;sudo -H -u git gitosis-init &amp;lt; /tmp/id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;That command puts the public ssh key into the keydirs directory and adds the associated username from the file to be the first member of the gisotis-admin project.  Hence seeing user@local as the member.  It matches the filename of the pub file in the keydir directory (user@local.pub). That&amp;#8217;s how gitosis relates members listed in the conf file to the keys in the keydir directory, filename minus the pub extension.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s edit this conf file to include our lostechies project:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/gitosis-admin&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; cat gitosis.conf 
&lt;span class="o"&gt;[&lt;/span&gt;gitosis&lt;span class="o"&gt;]&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;group gitosis-admin&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;writable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; gitosis-admin
&lt;span class="nv"&gt;members&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; user@local

&lt;span class="o"&gt;[&lt;/span&gt;group lostechies&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;writable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; lostechies
&lt;span class="nv"&gt;members&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; user@local
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;It looks exactly like the gitosis-admin one.  Now we commit it just like we would normally when using Git.  We can add, then commit or commit with the -am argument.  This is possible since the gitosis-admin.conf file is already tracked by the repository.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/gitosis-admin&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; git commit -am &lt;span class="s2"&gt;&amp;quot;add lostechies project&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;master 6b7a5da&lt;span class="o"&gt;]&lt;/span&gt; add lostechies project
 1 files changed, 3 insertions&lt;span class="o"&gt;(&lt;/span&gt;+&lt;span class="o"&gt;)&lt;/span&gt;, 0 deletions&lt;span class="o"&gt;(&lt;/span&gt;-&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;and push it to the remote gitosis-admin repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/gitosis-admin&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; git push
Counting objects: 5, &lt;span class="k"&gt;done&lt;/span&gt;.
Delta compression using up to 2 threads.
Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;3/3&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
Writing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;3/3&lt;span class="o"&gt;)&lt;/span&gt;, 385 bytes, &lt;span class="k"&gt;done&lt;/span&gt;.
Total 3 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;, reused 0 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;
To git@YOUR_SERVER_HOSTNAME:gitosis-admin.git
   23842e9..6b7a5da  master -&amp;gt; master
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We need to create the lostechies repository locally, add an initial item (&lt;span class="caps"&gt;README&lt;/span&gt; in this case), and push it remotely.  Gitosis won&amp;#8217;t create the repository until something it pushed to it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~ &amp;gt; mkdir lostechies
~ &amp;gt; &lt;span class="nb"&gt;cd &lt;/span&gt;lostechies
~/lostechies &amp;gt; git init
~/lostechies&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; touch README
~/lostechies&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; git add README &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit -m &lt;span class="s2"&gt;&amp;quot;initial commit&amp;quot;&lt;/span&gt;
~/lostechies&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; git push origin master
Initialized empty Git repository in /home/git/repositories/lostechies.git/
Counting objects: 3, &lt;span class="k"&gt;done&lt;/span&gt;.
Writing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;3/3&lt;span class="o"&gt;)&lt;/span&gt;, 205 bytes, &lt;span class="k"&gt;done&lt;/span&gt;.
Total 3 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;, reused 0 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;
To git@YOUR_SERVER_HOSTNAME:lostechies.git
 * &lt;span class="o"&gt;[&lt;/span&gt;new branch&lt;span class="o"&gt;]&lt;/span&gt;      master -&amp;gt; master
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The lostechies repository now exists remotely.  Currently my account is the only that has access.  Let&amp;#8217;s add another contributor.&lt;/p&gt;
&lt;h2&gt;Add our first contributors&lt;/h2&gt;
&lt;p&gt;Say I want to allow my friend Joe to have commit (writable) access to my lostechies repository and I want my friend Ryan to only have readonly access.  I tell them to send me their public ssh keys.  I make sure the files are named joe.pub and ryan.pub.  I then put them into my local gitosis-admin repository&amp;#8217;s keydir directory and then I edit the gitosis.conf file to be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/gitosis-admin&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; cp ~/joe.pub keydir/ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cp ~/ryan.pub keydir/
~/gitosis-admin&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; vim gitosis.conf 
&lt;span class="o"&gt;[&lt;/span&gt;gitosis&lt;span class="o"&gt;]&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;group gitosis-admin&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;writable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; gitosis-admin
&lt;span class="nv"&gt;members&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; user@local

&lt;span class="o"&gt;[&lt;/span&gt;group lostechies&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;writable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; lostechies
&lt;span class="nv"&gt;members&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; user@local joe

&lt;span class="o"&gt;[&lt;/span&gt;group lostechies_ro&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nb"&gt;readonly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; lostechies
&lt;span class="nv"&gt;members&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; ryan
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Notice that I had to create a whole new group (lostechies_ro) to setup Ryan&amp;#8217;s readonly access.  You can&amp;#8217;t combine readonly and writable permissions in gitosis (wish we could &amp;#8211; open source contribution there?).&lt;/p&gt;
&lt;p&gt;Now I need to &amp;#8220;git add&amp;#8221; the new keys, and commit the changes to the conf file.  Finally I push the changes.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/gitosis-admin&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; git add keydir/joe.pub keydir/ryan.pub
~/gitosis-admin&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; git commit -am &lt;span class="s2"&gt;&amp;quot;add joe and ryan and give them access to lostechies repository&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;master efb193c&lt;span class="o"&gt;]&lt;/span&gt; add joe and ryan and give them access to lostechies repository
 3 files changed, 6 insertions&lt;span class="o"&gt;(&lt;/span&gt;+&lt;span class="o"&gt;)&lt;/span&gt;, 1 deletions&lt;span class="o"&gt;(&lt;/span&gt;-&lt;span class="o"&gt;)&lt;/span&gt;
 create mode 100644 keydir/joe.pub
 create mode 100644 keydir/ryan.pub
~/gitosis-admin&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; git push
Counting objects: 7, &lt;span class="k"&gt;done&lt;/span&gt;.
Delta compression using up to 2 threads.
Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;4/4&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
Writing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;4/4&lt;span class="o"&gt;)&lt;/span&gt;, 470 bytes, &lt;span class="k"&gt;done&lt;/span&gt;.
Total 4 &lt;span class="o"&gt;(&lt;/span&gt;delta 1&lt;span class="o"&gt;)&lt;/span&gt;, reused 0 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;
To git@YOUR_SERVER_HOSTNAME:gitosis-admin.git
   20148cf..efb193c  master -&amp;gt; master
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now Joe or Ryan can clone this repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git clone git@YOUR_SERVER_HOSTNAME:lostechies.git
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;:&lt;/strong&gt;&lt;/em&gt; Again, if they receive the following error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~ &amp;gt; git clone git@YOUR_SERVER_HOSTNAME:gitosis-admin.git
Initialized empty Git repository in /Users/user/gitosis-admin/.git/
ssh: connect to host YOUR_SERVER_HOSTNAME port 22: Connection refused
fatal: The remote end hung up unexpectedly
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The solution, involving the .ssh/config file is in the first post in this series.&lt;/p&gt;
&lt;p&gt;That is how you create a repository and add users.&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;DEBUG&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;If you are unable to connect you have the option of editing the gitosis.conf file with more message verbosity by adding &amp;#8220;loglevel=&lt;span class="caps"&gt;DEBUG&lt;/span&gt;&amp;#8221; at the top of the conf file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/gitosis-admin&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; vim gitosis.conf 
&lt;span class="o"&gt;[&lt;/span&gt;gitosis&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;loglevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;DEBUG
...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This will give you more information on the ouput when trying to push to the remote repository.&lt;/p&gt;
&lt;h2&gt;Can&amp;#8217;t push changes&lt;/h2&gt;
&lt;p&gt;As Scott Chacon states in his gitosis section of &lt;a href="http://progit.org/book/ch4-7.html"&gt;Pro Git&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;If you’ve lost push access by pushing a messed-up configuration, you can manually fix the file on the server under /home/git/.gitosis.conf — the file from which Gitosis reads its info. A push to the project takes the gitosis.conf file you just pushed up and sticks it there. If you edit that file manually, it remains like that until the next successful push to the gitosis-admin project.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The .gitosis.conf file in the git user&amp;#8217;s home directory is a symlink to the actual conf file in the gitosis-admin repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;lrwxrwxrwx 1 git  git    53 May 22 20:32 .gitosis.conf -&amp;gt; /home/git/repositories/gitosis-admin.git/gitosis.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Next Part: &lt;a href="http://blog.jasonmeridth.com/2010/05/26/gitosis-and-gitweb-part-3.html"&gt;Gitweb&lt;/a&gt;&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2010/05/22/gitosis-and-gitweb-part-2.html</feedburner:origLink></entry>
 
 <entry>
   <title>Gitosis and Gitweb Part 1</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/Y5H9GdK9K18/gitosis-and-gitweb-part-1.html" />
   <updated>2010-05-22T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2010/05/22/gitosis-and-gitweb-part-1</id>
   <content type="html">&lt;h1&gt;Gitosis and Gitweb Part 1&lt;/h1&gt;
&lt;p&gt;22 May 2010 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blog.jasonmeridth.com/2010/05/22/gitosis-and-gitweb-part-1.html"&gt;Gitosis and Gitweb &amp;#8211; Part 1&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://blog.jasonmeridth.com/2010/05/22/gitosis-and-gitweb-part-2.html"&gt;Gitosis and Gitweb &amp;#8211; Part 2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve had a number of people ask me where they should host their Git repositories.  Of course, my default question back is, &amp;#8220;Can the code be public or does it need to be private?&amp;#8221;.  Usually they say, &amp;#8220;public&amp;#8221;.  Therefore, my repsonse is &lt;a href="http://github.com"&gt;Github.com&lt;/a&gt;.  If they say, “private” I still say Github.  If they don&amp;#8217;t &lt;a href="http://github.com/security"&gt;&amp;#8216;trust&amp;#8217; Github&lt;/a&gt;, which they should &amp;#8211; click the link, then my response is &lt;a href="http://eagain.net/gitweb/?p=gitosis.git;a=summary"&gt;Gitosis&lt;/a&gt; and &lt;a href="http://git.wiki.kernel.org/index.php/Gitweb"&gt;Gitweb&lt;/a&gt;.  This is by no means the only solution.  I&amp;#8217;m aware of other ones like Gitorious.  I&amp;#8217;ve never used Gitorious.&lt;/p&gt;
&lt;p&gt;Back to Gitosis.  My personal Gitosis server is a slice at &lt;a href="http://slicehost.com"&gt;Slicehost.com&lt;/a&gt;.  You can use an Ubuntu server at home as long as you have remote access.  I&amp;#8217;ve personally only used Gitosis with an Ubuntu slice, so I don&amp;#8217;t know if there are any quirks with other Linux distributions. After setting up a slice (after following the instructions &lt;a href="http://articles.slicehost.com/2008/11/28/ubuntu-intrepid-setup-page-1"&gt;here&lt;/a&gt; and &lt;a href="http://articles.slicehost.com/2008/11/28/ubuntu-intrepid-setup-page-2"&gt;here&lt;/a&gt;) I am ready to go.&lt;/p&gt;
&lt;p&gt;Notice: This post is a combination of &lt;a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way"&gt;scie.nti.st&amp;#8217;s gitosis post&lt;/a&gt;  and &lt;a href="http://progit.org/book/ch4-7.html"&gt;Scott Chacon&amp;#8217;s Pro Git gitosis section&lt;/a&gt;.  They are my de facto references.  Maybe my own will be now. :)&lt;/p&gt;
&lt;p&gt;&amp;#8220;Enough talk.  Let&amp;#8217;s fight&amp;#8221;  ~Po, Kung Fu Panda&lt;/p&gt;
&lt;h2&gt;Intall Git&lt;/h2&gt;
&lt;p&gt;After logging into your box, let&amp;#8217;s install Git (if not already installed):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;sudo apt-get install git-core
...
After this operation, 16.3MB of additional disk space will be used.
Do you want to &lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;Y/n&lt;span class="o"&gt;]&lt;/span&gt;? 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Press enter or type &amp;#8216;Y&amp;#8217; and press enter and git will be installed.  Type the following to confirm:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~ &amp;gt; git --version
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;and you&amp;#8217;ll see something like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~ &amp;gt; git --version
git version 1.6.3.3
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2&gt;Intall python-setuptools&lt;/h2&gt;
&lt;p&gt;Also install the python-setuptools because we&amp;#8217;ll need them (gitosis is written in python):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;apt-get install python-setuptools
...
After this operation, 1126kB of additional disk space will be used.
Do you want to &lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;Y/n&lt;span class="o"&gt;]&lt;/span&gt;? 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Press enter or type &amp;#8216;Y&amp;#8217; and press enter and python-setuptools  will be installed.&lt;/p&gt;
&lt;h2&gt;Download Gitosis&lt;/h2&gt;
&lt;p&gt;We need to clone the gitosis source locally to install it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;mkdir src &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;src
~/src &lt;span class="nv"&gt;$ &lt;/span&gt;git clone git://eagain.net/gitosis.git
Initialized empty Git repository in /root/src/gitosis/.git/
remote: Counting objects: 614, &lt;span class="k"&gt;done&lt;/span&gt;.
remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;183/183&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
remote: Total 614 &lt;span class="o"&gt;(&lt;/span&gt;delta 434&lt;span class="o"&gt;)&lt;/span&gt;, reused 594 &lt;span class="o"&gt;(&lt;/span&gt;delta 422&lt;span class="o"&gt;)&lt;/span&gt;
Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;614/614&lt;span class="o"&gt;)&lt;/span&gt;, 93.82 KiB, &lt;span class="k"&gt;done&lt;/span&gt;.
Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;434/434&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2&gt;Install Gitosis&lt;/h2&gt;
&lt;p&gt;Now let&amp;#8217;s install it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/src &lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;gitostis
~/src/gitostis &lt;span class="nv"&gt;$ &lt;/span&gt;python setup.py install
&lt;span class="s2"&gt;&amp;quot;result&amp;quot;&lt;/span&gt;:http://gist.github.com/352769
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Gitosis is now installed.  Next steps are to create git user and handle a file permission on a git hook.&lt;/p&gt;
&lt;h2&gt;Create Git User&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;sudo adduser &lt;span class="se"&gt;\&lt;/span&gt;
    --system &lt;span class="se"&gt;\&lt;/span&gt;
    --shell /bin/bash &lt;span class="se"&gt;\&lt;/span&gt;
    --gecos &lt;span class="s1"&gt;&amp;#39;git version control&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    --group &lt;span class="se"&gt;\&lt;/span&gt;
    --disabled-password &lt;span class="se"&gt;\&lt;/span&gt;
    --home /home/git &lt;span class="se"&gt;\&lt;/span&gt;
    git
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You&amp;#8217;ll see something like the following if it is successful&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;Adding system user &lt;span class="sb"&gt;`&lt;/span&gt;git&lt;span class="s1"&gt;&amp;#39; (UID 103) ...&lt;/span&gt;
&lt;span class="s1"&gt;Adding new group `git&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;GID 105&lt;span class="o"&gt;)&lt;/span&gt; ...
Adding new user &lt;span class="sb"&gt;`&lt;/span&gt;git&lt;span class="s1"&gt;&amp;#39; (UID 103) with group `git&amp;#39;&lt;/span&gt; ...
Creating home directory &lt;span class="sb"&gt;`&lt;/span&gt;/home/git&lt;span class="err"&gt;&amp;#39;&lt;/span&gt; ...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2&gt;Use local, public ssh key&lt;/h2&gt;
&lt;p&gt;You need to initially use your public ssh key (id_rsa.pub).  If you have one, it will be at $&lt;span class="caps"&gt;HOME&lt;/span&gt;/.ssh/id_rsa.pub and if you have never generated one, you can do so by running the following command (accept the default location and you don&amp;#8217;t need to enter a passphrase when prompted):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;ssh-keygen -t rsa
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now you need to upload it to the server/slice.  I usually use the scp (secure copy command):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;scp &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.ssh/id_rsa.pub user@123.123.123.123:/tmp/
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This will upload the local id_rsa.pub file to the /tmp/ folder on the server.  Why there?  So that the git user can use it.  How is that possible?  The folder has permissions of 777 (drwxrwxrwt) meaning everyone has read and write access to it.&lt;/p&gt;
&lt;h3&gt;Sidenote:  &lt;span class="caps"&gt;SSH&lt;/span&gt; Port&lt;/h3&gt;
&lt;p&gt;If you have your sshd daemon running on a different port other than 22 (which is the default, but I highly suggest changing), then you need to use scp like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;scp -P 12345 &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.ssh/id_rsa.pub user@123.123.123.123:/tmp/
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I believe the &amp;#8220;-P&amp;#8221; option must be capitalized.&lt;/p&gt;
&lt;h2&gt;Initialize gitosis-admin repository&lt;/h2&gt;
&lt;p&gt;On the server, issue the following command to set your public ssh key as the first authorized key of a new gitosis-admin repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;sudo -H -u git gitosis-init &amp;lt; /tmp/id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You will see something like the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~&lt;span class="nv"&gt;$ &lt;/span&gt;sudo -H -u git gitosis-init &amp;lt; /tmp/id_rsa.pub
Initialized empty Git repository in /home/git/repositories/gitosis-admin.git/
Reinitialized existing Git repository in /home/git/repositories/gitosis-admin.git/
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This means it was successful.&lt;/p&gt;
&lt;p&gt;Take note:  If you put your id_rsa.pub file in a different location you need to use that instead of /tmp/id_rsa.pub&lt;/p&gt;
&lt;h2&gt;Change Permissions on post-update hook&lt;/h2&gt;
&lt;p&gt;You have to set the permissions on the post-update git hook of the gitosis-admin repository so that gitosis-admin can add new repository structures when they are added/removed to/from the gitosis.conf file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;sudo chmod 755 /home/git/repositories/gitosis-admin.git/hooks/post-update
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Note: &lt;em&gt;First round of this post, I didn&amp;#8217;t make this change.  When I added a new project, it failed because this hook didn&amp;#8217;t have the right permissions.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Clone gitosis-admin repository&lt;/h2&gt;
&lt;p&gt;Now we&amp;#8217;re going to use Git to administrate this gitosis instance.  I think that is pretty ingenius.  Let&amp;#8217;s clone the gitosis-admin repository locally:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~ &amp;gt; git clone git@YOUR_SERVER_HOSTNAME:gitosis-admin.git
Initialized empty Git repository in /Users/user/gitosis-admin/.git/
remote: Counting objects: 5, &lt;span class="k"&gt;done&lt;/span&gt;.
remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;4/4&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;5/5&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;1/1&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
remote: Total 5 &lt;span class="o"&gt;(&lt;/span&gt;delta 1&lt;span class="o"&gt;)&lt;/span&gt;, reused 5 &lt;span class="o"&gt;(&lt;/span&gt;delta 1&lt;span class="o"&gt;)&lt;/span&gt;
~ &amp;gt; &lt;span class="nb"&gt;cd &lt;/span&gt;gitosis-admin
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We are now in the gitosis-admin repository folder locally&lt;/p&gt;
&lt;h3&gt;Two most common errors&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;FIRST&lt;/span&gt; &lt;span class="caps"&gt;ONE&lt;/span&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~ &amp;gt; git clone git@YOUR_SERVER_HOSTNAME:gitosis-admin.git
Initialized empty Git repository in /Users/user/gitosis-admin/.git/
ssh: connect to host YOUR_SERVER_HOSTNAME port 22: Connection refused
fatal: The remote end hung up unexpectedly
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;it is because you have used a port for &lt;span class="caps"&gt;SSH&lt;/span&gt; other than port 22 (the default).  To fix this, you need to edit your .ssh/config file and add the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;Host YOUR_SERVER_HOSTNAME
Port YOUR_PORT
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Of course, you need to put in your server hostname and port number (i.e., mydomain.com and 12345)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;SECOND&lt;/span&gt; &lt;span class="caps"&gt;ONE&lt;/span&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~ &amp;gt; git clone git@YOUR_SERVER_HOSTNAME:gitosis-admin.git
Initialized empty Git repository in /Users/user/gitosis-admin/.git/
Permission denied &lt;span class="o"&gt;(&lt;/span&gt;publickey&lt;span class="o"&gt;)&lt;/span&gt;.
fatal: The remote end hung up unexpectedly
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This has usually hit me because I locked down my /etc/ssh/sshd_config file to only allow in certain users or groups.  I have to change the AllowUsers line in my file from:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;AllowUsers jmeridth
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;AllowUsers jmeridth git
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Once I restart the ssh daemon:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~ &amp;gt; sudo /etc/init.d/ssh restart
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now the git user has access to reach my server/slice via ssh.&lt;/p&gt;
&lt;h3&gt;The local gitosis-admin repository&lt;/h3&gt;
&lt;p&gt;You now have a local clone of the gitosis-admin repository.  The contents are only a conf file and key directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/gitosis-admin&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; ls
total 8
-rw-r--r--  1 user  staff   114B May 22 21:31 gitosis.conf
drwxr-xr-x  3 user  staff   102B May 22 21:31 keydir
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Note: before anyone asks, the (master) notation in my prompt is usage of the &lt;a href="http://blog.jasonmeridth.com/2010/05/22/git-ps1.html"&gt;__git_ps1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next Part: &lt;a href="http://blog.jasonmeridth.com/2010/05/22/gitosis-and-gitweb-part-2.html"&gt;Add Projects and Contributors&lt;/a&gt;&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2010/05/22/gitosis-and-gitweb-part-1.html</feedburner:origLink></entry>
 
 <entry>
   <title>git ps1</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/6q95d5inE8A/git-ps1.html" />
   <updated>2010-05-22T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2010/05/22/git-ps1</id>
   <content type="html">&lt;h1&gt;git ps1&lt;/h1&gt;
&lt;p class="meta"&gt;22 May 2010 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;I like knowing which Git branch I&amp;#8217;m currently in.  I use the git-ps1 function feature that comes with git-core.  If you clone or download the git source:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git://git.kernel.org/pub/scm/git/git.git
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;There is a file in the contrib/completion folder called git-completion.bash:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/code/git/contrib/completion&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; ls
total 96
-rwxr-xr-x  1 user  staff    44K Apr 14 15:26 git-completion.bash
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I copy this file to my $&lt;span class="caps"&gt;HOME&lt;/span&gt; folder as .git-completion.bash and then reference it and the ps1 prompt feature in my .bashrc file&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.git-completion.bash
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PS1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;\w$(__git_ps1 &amp;quot;(%s)&amp;quot;) &amp;gt; &amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And now whenever I cd into a folder that is a Git repository I see something like the following prompt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/gitosis-admin&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Notice the (master) notation.  That is telling me I&amp;#8217;m on the master branch.  It&amp;#8217;s just easier than issuing a &amp;#8220;git branch&amp;#8221; command everytime I want to know.&lt;/p&gt;
&lt;p&gt;I know there are many other configurations out there, but I like to use the simplest thing that works.&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2010/05/22/git-ps1.html</feedburner:origLink></entry>
 
 <entry>
   <title>OAuth</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/2OHeg5Ywb40/oauth.html" />
   <updated>2010-04-02T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2010/04/02/oauth</id>
   <content type="html">&lt;h1&gt;OAuth&lt;/h1&gt;
&lt;p class="meta"&gt;18 Jan 2010 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;I have gotten tired of twitterfeed not handling our &lt;span class="caps"&gt;RSS&lt;/span&gt; feed and tweeting our new posts.  So have the other LosTechies members.  I decided to finally learn OAuth so that I can write a script/app to handle tweeting our new blog posts.&lt;/p&gt;
&lt;p&gt;This is the way I learned so bare with me.&lt;/p&gt;
&lt;p&gt;First things first, is you have to go to &lt;a href="http://twitter.com"&gt;twitter&lt;/a&gt; and login to your account.  Once done, register your &lt;a href="http://twitter.com/oauth_clients"&gt;OAuth application&lt;/a&gt; and click the &lt;a href="http://twitter.com/apps/new"&gt;Register a new application&lt;/a&gt; link. This will set you up with an OAuth consumer key and secret; which we need to obtain the OAuth request token/secret and our ultimate goal of an OAuth access token/secret.&lt;/p&gt;
&lt;p&gt;Required fields that I had to fill out were:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Application Name&lt;/li&gt;
	&lt;li&gt;Descriptions&lt;/li&gt;
	&lt;li&gt;Application Website&lt;/li&gt;
	&lt;li&gt;Application Type (I chose Client)&lt;/li&gt;
	&lt;li&gt;Default Access Type (I chose Read &amp;amp; Write)&lt;/li&gt;
	&lt;li&gt;ReCaptcha at the bottom.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="http://c1261852.cdn.cloudfiles.rackspacecloud.com/twitter_new_oauth_app.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Once accepted you&amp;#8217;ll be directed to a page displaying your consumer key and secret, like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://c1261852.cdn.cloudfiles.rackspacecloud.com/oauth_consumer_key_and_secret.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve looked at a few ways to do this and the easiest that I found was by using the &lt;a href="http://github.com/moomerman/twitter_oauth"&gt;twitter_oauth gem&lt;/a&gt;. Following the &lt;span class="caps"&gt;README&lt;/span&gt; for this gem I was able to get an access token/secret pretty easily.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m doing all of this through &lt;span class="caps"&gt;IRB&lt;/span&gt; because there is one part where you need to open a web page and allow your twitter client to post to Twitter.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~ &amp;gt; irb
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:001:0&amp;gt; require &lt;span class="s1"&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="nb"&gt;true&lt;/span&gt;
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:002:0&amp;gt; require &lt;span class="s1"&gt;&amp;#39;twitter_oauth&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="nb"&gt;true&lt;/span&gt;
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:003:0&amp;gt; &lt;span class="nv"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; TwitterOAuth::Client.new&lt;span class="o"&gt;(&lt;/span&gt;
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:004:1* :consumer_key &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="s1"&gt;&amp;#39;YOUR_APP_CONSUMER_KEY&amp;#39;&lt;/span&gt;,
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:005:1* :consumer_secret &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="s1"&gt;&amp;#39;YOURA_APP_CONSUMER_SECRET&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; ...object output...
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:005:0&amp;gt; &lt;span class="nv"&gt;request_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; client.request_token
&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; ...object output...
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:006:0&amp;gt; puts request_token.key, request_token.secret
&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="o"&gt;[&lt;/span&gt;REQUEST_TOKEN&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="o"&gt;[&lt;/span&gt;REQUEST_SECRET&lt;span class="o"&gt;]&lt;/span&gt;

irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:007:0&amp;gt; request_token.authorize_url
&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; http://twitter.com/oauth/authorize?oauth_token&lt;span class="o"&gt;=&lt;/span&gt;TOKEN
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Copy that url and put it into your browser of choice.  When the &amp;#8220;Deny&amp;#8221; and &amp;#8220;Allow&amp;#8221; buttons become visible, click the &amp;#8220;Allow&amp;#8221; button.  You will be presented with a numeric &lt;span class="caps"&gt;PIN&lt;/span&gt;. Copy that number into your clipboard because we&amp;#8217;re going to use it on this final step to obtain the OAuth Access Token and Secret.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:007:0&amp;gt; &lt;span class="nv"&gt;access_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; client.authorize&lt;span class="o"&gt;(&lt;/span&gt;
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:008:1*   request_token.token,
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:009:1*   request_token.secret,
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:0010:1*  :oauth_verifier &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="s1"&gt;&amp;#39;THE_NUMERIC_PIN_YOU_GOT_FROM_TWITTER&amp;#39;&lt;/span&gt;
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:0011:1* &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; ...object output...
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:0011:0&amp;gt; puts access_token.key, access_token.secret
&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="o"&gt;[&lt;/span&gt;ACCESS_TOKEN&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="o"&gt;[&lt;/span&gt;ACCESS_SECRET&lt;span class="o"&gt;]&lt;/span&gt;
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:0012:0&amp;gt; client.authorized?
&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You now have everything you need to use the TwitterOAuth gem without having to authenticate everytime.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:0013:0&amp;gt; &lt;span class="nv"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; TwitterOAuth::Client.new&lt;span class="o"&gt;(&lt;/span&gt;
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:0014:1*    :consumer_key &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="s1"&gt;&amp;#39;YOUR_CONSUMER_KEY&amp;#39;&lt;/span&gt;,
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:0015:1*    :consumer_secret &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="s1"&gt;&amp;#39;YOUR-CONSUMER-SECRET&amp;#39;&lt;/span&gt;,
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:0016:1*    :token &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; access_token.token, 
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:0017:1*    :secret &lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; access_token.secret
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; ...object output...
irb&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;:0017:0&amp;gt; client.authorized?
&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;That is how I figured out OAuth without a callback &lt;span class="caps"&gt;URL&lt;/span&gt;.  Hacky, but it works.&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2010/04/02/oauth.html</feedburner:origLink></entry>
 
 <entry>
   <title>Pro Git Cliff Notes</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/q3ShZCZ30uQ/pro-git-cliff-notes.html" />
   <updated>2010-03-30T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2010/03/30/pro-git-cliff-notes</id>
   <content type="html">&lt;h1&gt;Pro Git Cliff Notes&lt;/h1&gt;
&lt;p class="meta"&gt;30 Mar 2010 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;These are my notes from reading Scott Chacon&amp;#8217;s &lt;a href="http://progit.org/book"&gt;Pro Git&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;&lt;strong&gt;highly&lt;/strong&gt;&lt;/em&gt; suggest &lt;a href="http://tinyurl.com/amazonprogit"&gt;buying this book&lt;/a&gt; if you are serious about using the Git version control tool.&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch3-1.html"&gt;pg 48&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A branch in Git is simply a lightweight movable pointer&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch3-1.html"&gt;pg 50&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;a special pointer called &lt;span class="caps"&gt;HEAD&lt;/span&gt;&amp;#8230;is a pointer to the local branch you&amp;#8217;re currently on&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch3-1.html"&gt;pg 52&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Creating a new branch is as quick and simple as writing 41 bytes to a file (40 characters and a newline).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch3-2.html"&gt;pg 53&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To create a branch and switch to it at the same time&amp;#8230;git checkout command with the -b switch&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch3-3.html"&gt;pg 61&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To see the last commit on each branch, you can run git branch -v&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch3-5.html"&gt;pg 69&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git checkout -b &lt;span class="o"&gt;[&lt;/span&gt;branch&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;remotename&lt;span class="o"&gt;]&lt;/span&gt;/&lt;span class="o"&gt;[&lt;/span&gt;branch&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;is the same as&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git checkout --track &lt;span class="o"&gt;[&lt;/span&gt;remotename&lt;span class="o"&gt;]&lt;/span&gt;/&lt;span class="o"&gt;[&lt;/span&gt;branch&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch4-1.html"&gt;pg 81&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Git protocol&amp;#8230;listens on a dedicated port (9418)&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch4-1.html"&gt;pg 82&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Git protocol is the fastst transfer protocol available.&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch5-2.html"&gt;pg 111&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Git project provides a document that lays out a number of good tips for creating commits from which to submit patches&amp;#8212;you can read it in the Git source code in the Documentation/SubmittingPatches file.&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch5-2.html"&gt;pg 116&lt;/a&gt; &lt;strong&gt;*&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git log --no-merges origin/master ^issue54
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch5-2.html"&gt;pg 121&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Compare origin changes with local changes before merging:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git log origin/featureA ^feature
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch5-2.html"&gt;pg 126&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git merge --no-commit --squash featureB
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch5-3.html"&gt;pg 130&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git apply
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;It&amp;#8217;s almost identical to running a patch -p1 command to apply the patch, although it&amp;#8217;s more paranoid and accepts fewer fuzzy matches then patch.&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch5-3.html"&gt;pg 131&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git apply --check
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;check to see if a patch applies cleanly before you try actually applying it&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch3-1.html"&gt;pg 134&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git log contrib --not master
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;To find common ancestor of both branches&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git merge-base contrib master
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git diff &lt;span class="o"&gt;[&lt;/span&gt;sha1 from previous &lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch5-3.html"&gt;pg 135&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git diff master...topic
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;shows you only the work your topic branch has introduced since its common ancestor with master.&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch5-3.html"&gt;pg 140&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;tagging releases with signed keys&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch5-3.html"&gt;pg 141&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;generating a build number with your tags&lt;/p&gt;
&lt;p&gt;preparing a release as a tarball&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch5-3.html"&gt;pg 142&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Show work by author since a specific time&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git shortlog --no-merges master --not v1.0.1
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch6-1.html"&gt;pg 144&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Git can figure out a short, unique abbreviation for your &lt;span class="caps"&gt;SHA&lt;/span&gt;-1 values&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git log --abbrev-commit --pretty&lt;span class="o"&gt;=&lt;/span&gt;oneline
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;wolves paragraph&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch6-1.html"&gt;pg 145&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Find out the SHA1 of a branch&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git rev-parse &lt;span class="o"&gt;[&lt;/span&gt;branch&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch6-1.html"&gt;pg 146&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To see reflog information inline with your normal log information&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git log -g master
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Because reflog is a log, it will show you where the &lt;span class="caps"&gt;HEAD&lt;/span&gt; pointer was 2 months ago &amp;#8211; if the repo is older than that&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git show HEAD@&lt;span class="o"&gt;{&lt;/span&gt;2.months.ago&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch6-1.html"&gt;pg 147&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;^ is the first parent of the current commit&lt;br /&gt;
^2 is the second parent of the current commit (only works if the current commit is a merge commit, where first parent is the branch you on when you merged, second was the other)&lt;br /&gt;
~ is the first parent&lt;br /&gt;
~2 (or any number) is the grandparent(s) of the current commit only on the current branch or branch you were on when you merged&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch6-1.html"&gt;pg 148&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Shows you any commits in your current branch that aren&amp;#8217;t in the master branch on your origin remote&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git log origin/master..HEAD
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Git substitutes &lt;span class="caps"&gt;HEAD&lt;/span&gt; if one side is missing (git log origin/master..)&lt;/p&gt;
&lt;p&gt;Just like above command and example shown on pg134&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git log refB --not refA
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch6-3.html"&gt;pg 155&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Tells the stash command to try to reapply the staged changes&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git stash apply --index
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch6-3.html"&gt;pg 156&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Create a branch from a stash, testchanges&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git stash branch testchanges
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch6-4.html"&gt;pg 157&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;#8230;don&amp;#8217;t amend your last commit if you&amp;#8217;ve already pushed it (git commit &amp;#8212;amend command)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git rebase -i HEAD~3
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Don&amp;#8217;t include any commit you&amp;#8217;ve already pushed to a central server&amp;#8212;doing so will confuse other developers by providing an alternate version of the same change&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch6-4.html"&gt;pg 158&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s important to note that these commits (interactive rebase) are listed in the opposite order (oldest first, newest last) than you normally see then using the log command (newest first).&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch6-4.html"&gt;pg 160&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;#8230;make sure no commit shows up in that list (git log -4 &amp;#8212;pretty=format:&amp;#8220;%h %s&amp;#8221;) that you&amp;#8217;ve already pushed to a shared repository&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch6-5.html"&gt;pg 164&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;was wondering how to automate the good/bad declaration&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch6-6.html"&gt;pg 168&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;git submodule update&lt;br /&gt;
You have to do this every time you pull down a submodule change in the main projects.  It&amp;#8217;s strange, but it works.&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch6-7.html" title="subtree merging"&gt;pg 172&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You want to pull the Rack project into your master project as a subdirectory&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git &lt;span class="nb"&gt;read&lt;/span&gt;-tree --prefix&lt;span class="o"&gt;=&lt;/span&gt;rack/ -u rack_branch
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch7-1.html"&gt;pg 175&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;global git config /etc/gitconfig&lt;br /&gt;
user global git config ~/.gitconfig&lt;br /&gt;
local repository git config .git/config&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch7-1.html"&gt;pg 182&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git config --global core.autocrlf input
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This setup should leave you with &lt;span class="caps"&gt;CRLF&lt;/span&gt; endings in Windows checkouts but LF endings on Mac and Linux systems and in the repository&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch7-2.html"&gt;pg 184&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To tell Git to treat a specific file as binary data, add the following line to your .gitattributes file:&lt;br /&gt;
*.extension -crlf -diff&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch7-2.html"&gt;pg 185&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;#8230;one of the most annoying problems known to humanity: version-controlling Word documents (&lt;span class="caps"&gt;LOL&lt;/span&gt;)&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch7-3.html"&gt;pg 192&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;post-receive hook&amp;#8230;This scripts can&amp;#8217;t stop the push process, but the client doesn&amp;#8217;t disconnect until it has completed; so, be careful when you try to do anything that may take a long time&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch7-4.html"&gt;pg 194&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Is practically the git log command&amp;#8230;it prints out only the &lt;span class="caps"&gt;SHA&lt;/span&gt;-1 values and no other information&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git rev-list &lt;span class="o"&gt;[&lt;/span&gt;SHA-1&lt;span class="o"&gt;]&lt;/span&gt;..&lt;span class="o"&gt;[&lt;/span&gt;SHA-1&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Get the commit message from each of these commits to test&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git cat-file commit &lt;span class="o"&gt;[&lt;/span&gt;SHA-1&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Incantation:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git cat-file commit &lt;span class="o"&gt;[&lt;/span&gt;SHA-1&lt;span class="o"&gt;]&lt;/span&gt; | sed &lt;span class="s1"&gt;&amp;#39;1,/^$/d&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch7-4.html"&gt;pg 196&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;See what files have been modified in a single commit&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git log -1 --name-only --pretty&lt;span class="o"&gt;=&lt;/span&gt;oneline:&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;SHA-1&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch7-4.html"&gt;pg 198&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;anything your script prints to stdout will be transferred to the client&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch7-4.html"&gt;pg 200&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Get your file listing from the staging area&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git diff-index --cached --name-only HEAD 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch9-2.html"&gt;pg 224&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Git is a content-addressable filesystem&lt;/p&gt;
&lt;p&gt;hash-object (plumbing command)&lt;/p&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch9-2.html"&gt;pg 221&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pull the content back out of Git&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git cat-file -p &lt;span class="o"&gt;[&lt;/span&gt;SHA-1&lt;span class="o"&gt;]&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch9-2.html"&gt;pg 226&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Git will tell you what type of object it is [blob, tree, tag, commit]&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git cat-file -t &lt;span class="o"&gt;[&lt;/span&gt;SHA-1&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p class="meta"&gt;&lt;a href="http://progit.org/book/ch9-2.html"&gt;pg 231&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Git compresses the new content with zlib&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2010/03/30/pro-git-cliff-notes.html</feedburner:origLink></entry>
 
 <entry>
   <title>Git tracking branches</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/6guUZMgtOYY/git-tracking-branches.html" />
   <updated>2010-03-23T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2010/03/23/git-tracking-branches</id>
   <content type="html">&lt;h1&gt;Git tracking branches&lt;/h1&gt;
&lt;p class="meta"&gt;23 Mar 2010 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;I have encountered this message multiple times when dealing with Git:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/code/blog/armmer.github.com&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; git pull
You asked me to pull without telling me which branch you
want to merge with, and &lt;span class="s1"&gt;&amp;#39;branch.master.merge&amp;#39;&lt;/span&gt; in
your configuration file does not tell me, either. Please
specify which branch you want to use on the &lt;span class="nb"&gt;command &lt;/span&gt;line and
try again &lt;span class="o"&gt;(&lt;/span&gt;e.g. &lt;span class="s1"&gt;&amp;#39;git pull &amp;lt;repository&amp;gt; &amp;lt;refspec&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;.
See git-pull&lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;details.

If you often merge with the same branch, you may want to
use something like the following in your configuration file:

    &lt;span class="o"&gt;[&lt;/span&gt;branch &lt;span class="s2"&gt;&amp;quot;master&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="nv"&gt;remote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &amp;lt;nickname&amp;gt;
    &lt;span class="nv"&gt;merge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &amp;lt;remote-ref&amp;gt;

    &lt;span class="o"&gt;[&lt;/span&gt;remote &lt;span class="s2"&gt;&amp;quot;&amp;lt;nickname&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &amp;lt;url&amp;gt;
    &lt;span class="nv"&gt;fetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &amp;lt;refspec&amp;gt;

See git-config&lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;details.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;and I&amp;#8217;ve been waiting for it again so that I can blog about it.  What this means is that the local master branch of my github pages repository is not tracking a remote branch.  The quickest way to get around this would be for me to explicitly state the remote name and branch:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/code/blog/armmer.github.com&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; git pull origin master
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;and it would pull successfully.  Well, I don&amp;#8217;t want to have to specify the remote and branch.  The easiest way to do this is to edit the configuration file as suggested and add the following (at least in my case):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;    &lt;span class="o"&gt;[&lt;/span&gt;branch &lt;span class="s2"&gt;&amp;quot;master&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="nv"&gt;remote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; origin
    &lt;span class="nv"&gt;merge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; refs/heads/master

    &lt;span class="o"&gt;[&lt;/span&gt;remote &lt;span class="s2"&gt;&amp;quot;origin&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; git@github.com:armmer/armmer.github.com.git
    &lt;span class="nv"&gt;fetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; +refs/heads/*:refs/remotes/origin/*
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The +refs/heads/&lt;strong&gt;:refs/remotes/origin/&lt;/strong&gt; notation is what I call the &lt;a href="http://progit.org/book/ch9-5.html"&gt;refspec format&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now if I do a &lt;em&gt;git pull&lt;/em&gt; I get:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;~/code/blog/armmer.github.com&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; &amp;gt; git pull
Already up-to-date.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;It worked.  Now back to coding&amp;#8230;&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2010/03/23/git-tracking-branches.html</feedburner:origLink></entry>
 
 <entry>
   <title>Git reset, checkout &amp; "bare double dash", and revert</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/Jljsds2u2LA/git-reset-checkout-bare-double-dash-revert.html" />
   <updated>2010-03-22T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2010/03/22/git-reset-checkout-bare-double-dash-revert</id>
   <content type="html">&lt;h1&gt;Git reset, checkout &amp;amp; &amp;#8220;bare double dash&amp;#8221;, and revert&lt;/h1&gt;
&lt;p class="meta"&gt;22 Mar 2010 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;Some of the common questions I get are about how to reset or revert changes in Git.  There are two typical scenarios you have to deal with.  One is if you haven&amp;#8217;t committed the code yet.  The other is if you &lt;em&gt;have&lt;/em&gt; committed the code.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Before&lt;/strong&gt; you have committed the code&lt;/h1&gt;
&lt;p&gt;Well, if you want to unstage a file you simply do the following:&lt;/p&gt;
&lt;h2&gt;git reset&lt;/h2&gt;
&lt;p&gt;Say you staged a change (&amp;#8220;git add&amp;#8221;) and you realize you either don&amp;#8217;t want the file tracked or the change staged.  &lt;em&gt;git reset&lt;/em&gt; is the command that will do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git reset HEAD &amp;lt;filename&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;One of the suggestions I&amp;#8217;ve &lt;a href="http://learn.github.com/p/undoing.html"&gt;read about&lt;/a&gt; and have given is to create an alias called unstage:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git config --global alias.unstage &lt;span class="s1"&gt;&amp;#39;reset HEAD&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;So now instead of:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git reset HEAD README
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;you can do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git unstage README 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I personally just stick to &lt;em&gt;git reset &lt;span class="caps"&gt;HEAD&lt;/span&gt; filename&lt;/em&gt;. &amp;#8220;Why?&amp;#8221; you ask.  It&amp;#8217;s so that if I have to use git on another system that doesn&amp;#8217;t have my aliases, I know the commands.&lt;/p&gt;
&lt;h2&gt;git checkout&lt;/h2&gt;
&lt;p&gt;Another common question is &amp;#8220;How do I undo an unstaged/uncommitted change?  I just want to roll my file back&amp;#8230;&amp;#8221;.  &lt;em&gt;git checkout &amp;#8212; filename&lt;/em&gt; handles this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git checkout -- README 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This will roll the &lt;span class="caps"&gt;README&lt;/span&gt; file back to the last committed version in the working directory.  Another question after I answer this is, &amp;#8220;Why do you have to put the two dashes there?&amp;#8221;  The two dashes are canonically called the &amp;#8220;bare double dashes&amp;#8221;.  The reason they are there is because it ensures that the checkout command know that we are trying to roll back a file and not change branches.  Remember that the typical usage of the checkout command is to change branches.  If you had a branch called &lt;span class="caps"&gt;README&lt;/span&gt;, this command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git checkout README 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;would checkout the &lt;span class="caps"&gt;README&lt;/span&gt; branch and not rollback the current &lt;span class="caps"&gt;README&lt;/span&gt; file in the working directory.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;After&lt;/strong&gt; you have committed the code&lt;/h2&gt;
&lt;p&gt;If you committed code that you realized you shouldn&amp;#8217;t have, you have two options:&lt;/p&gt;
&lt;h2&gt;git revert&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;git revert&lt;/em&gt; will create a new commit which undoes a specifc commit that you pass to it.  The usual use is to undo the last commit:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git revert HEAD
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;If you need to undo a commit that happened before the last commit you can pass it a &lt;a href="http://book.git-scm.com/4_git_treeishes.html"&gt;treeish&lt;/a&gt; argument or a specific SHA1 of the commit you want to undo:&lt;/p&gt;
&lt;p&gt;Revert the next-to-last commit:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git revert HEAD^
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Revert a specific commit by &lt;span class="caps"&gt;SHA&lt;/span&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git revert f8c7dd34
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Just be aware that if you pass a reference to a commit other than the last one, if there are any merge conflicts created by undoing the change, you will have to deal with those at the time of your new commit (the revert one).&lt;/p&gt;
&lt;h2&gt;git commit &amp;#8212;amend&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;git commit &amp;#8212;amend&lt;/em&gt; is another command that allows you to change your last commit.  Say I forgot to stage a file for the commit and I need to edit the commit message:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git commit -m &lt;span class="s1"&gt;&amp;#39;initial commit&amp;#39;&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git add awesome_file
&lt;span class="nv"&gt;$ &lt;/span&gt;git commit --amend
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;My visual editor of choice will open with the prior commit message allowing me to edit it, I change the message, save it and exit.  The previous commit is overridden by adding the content of my awesome_file and now has my new commit message.  Personally, I&amp;#8217;ve only had to use this a couple times because I&amp;#8217;m usually editing tracked files and by doing &lt;em&gt;git commit -am &amp;#8220;message&amp;#8221;&lt;/em&gt; I rarely forget to stage my files.  The times I&amp;#8217;ve had to use &lt;em&gt;git commit &amp;#8212;amend&lt;/em&gt; is when I forget to add/stage a new/untracked file.&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2010/03/22/git-reset-checkout-bare-double-dash-revert.html</feedburner:origLink></entry>
 
 <entry>
   <title>Refspec matches more than one</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/uvrFi-ee6Zo/refspec-matches-more-than-one.html" />
   <updated>2010-01-18T00:00:00-08:00</updated>
   <id>http://blog.jasonmeridth.com/2010/01/18/refspec-matches-more-than-one</id>
   <content type="html">&lt;h1&gt;Refspec matches more than one&lt;/h1&gt;
&lt;p class="meta"&gt;18 Jan 2010 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;I was trying to push to a canonical repository this morning and got the following error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&amp;gt; git push origin master
error: src refspec master matches more than one.
error: failed to push some refs to &lt;span class="s1"&gt;&amp;#39;ssh://user@host/srv/git/repo&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This happened because I had accidentally created a master tag locally.  Once I deleted the tag locally:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;tag -d master
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I was able to push again.&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2010/01/18/refspec-matches-more-than-one.html</feedburner:origLink></entry>
 
 <entry>
   <title>Git post-merge hook to auto-fire rails migrations</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/YFISdqEyAIs/git-post-merge-hook-to-auto-fire-rails-migrations.html" />
   <updated>2009-12-22T00:00:00-08:00</updated>
   <id>http://blog.jasonmeridth.com/2009/12/22/git-post-merge-hook-to-auto-fire-rails-migrations</id>
   <content type="html">&lt;h1&gt;Git post-merge hook to auto-fire rails migrations&lt;/h1&gt;
&lt;p class="meta"&gt;22 Dec 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;I saw &lt;a href="http://ampgt.com"&gt;Scott Bellware&lt;/a&gt; recently write on twitter: &lt;a href="http://twitter.com/bellware/status/6952706099"&gt;for christmas, i really want a git hook to detect if an update has changes in the db/migrations folder&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://twitter.com/cory_foy"&gt;Cory Foy&lt;/a&gt;, &lt;a href="http://twitter.com/aaronjensen"&gt;Aaron Jensen&lt;/a&gt;, and &lt;a href="http://twitter.com/armmer"&gt;myself&lt;/a&gt; all responded in turn.&lt;/p&gt;
&lt;p&gt;I think Cory and I were quickly searching for which git hook could be used for this idea.  Cory found it &lt;a href="http://twitter.com/cory_foy/status/6954512284"&gt;first&lt;/a&gt; and it was the post-merge/post-rebase hooks.  I researched the &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/githooks.html"&gt;post-merge hook&lt;/a&gt; (scroll down to post-merge) and noticed it has no params that we could work with to find out if the last commit had migrations (aka changes/additions to db/migrations folder in a rails project)&lt;/p&gt;
&lt;p&gt;I came up with the &lt;a href="http://gist.github.com/262319"&gt;following&lt;/a&gt; :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class="sb"&gt;`rake db:migrate &amp;amp;&amp;amp; rake db:test:prepare`&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sb"&gt;`git diff HEAD^`&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;db/migrations&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This will grab the previous diff and look for &amp;#8220;db/migrations&amp;#8221; in the text.  If it&amp;#8217;s present, it would auto-run &amp;#8220;rake db:migrate &amp;amp;&amp;amp; rake db:test:migrate&amp;#8221;.  In other words, it will migrate the development database schema, then the test database schema.&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/12/22/git-post-merge-hook-to-auto-fire-rails-migrations.html</feedburner:origLink></entry>
 
 <entry>
   <title>Suspicious Patch Lines</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/9ttU0PVW-JU/suspicious-patch-lines.html" />
   <updated>2009-12-20T00:00:00-08:00</updated>
   <id>http://blog.jasonmeridth.com/2009/12/20/suspicious-patch-lines</id>
   <content type="html">&lt;h1&gt;Suspicious Patch Lines&lt;/h1&gt;
&lt;p class="meta"&gt;20 Dec 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;DISCLAIMER&lt;/span&gt;:  This is &lt;i&gt;only&lt;/i&gt; relevant if you or someone contributing to your project are doing cross-platform development.  If you are typically just developing on Windows, you should be able to keep the config options set to false.&lt;/p&gt;
&lt;h2&gt;The Problem&lt;/h2&gt;
&lt;p&gt;While trying to commit changes to a file I have under source control with Git on a Windows box using cygwin, I received the following error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;jmeridth@web1 /cygdrive/d/site
&lt;span class="nv"&gt;$ &lt;/span&gt;git commit -am &lt;span class="s2"&gt;&amp;quot;changed the README to show authors&amp;quot;&lt;/span&gt;
*
* You have some suspicious patch lines:
*
* In README
* trailing whitespace &lt;span class="o"&gt;(&lt;/span&gt;line 26&lt;span class="o"&gt;)&lt;/span&gt;
README:26:
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This type of error has been discussed quite a bit amongst .&lt;span class="caps"&gt;NET&lt;/span&gt; developers who are transitioning to Git.  It has to due with the difference in handling of newlines between Windows and the Mac/*nix world.  There are five solutions to this:&lt;/p&gt;
&lt;p&gt;1) Run the following from inside the repository: (the one I usually use, due to my cross-platform development)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git config core.autocrlf &lt;span class="nb"&gt;true&lt;/span&gt;
git confit core.safecrlf &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;a href="http://help.github.com/dealing-with-lineendings/"&gt;Github Help Pages&lt;/a&gt; provide an excellent explanation about this.  Also read the &lt;a href="http://www.kernel.org/pub/software/scm/git-core/docs/git-config.html"&gt;direct documentation from git-core&lt;/a&gt;. This makes Git convert &lt;span class="caps"&gt;CRLF&lt;/span&gt; at the end of lines in the text files to LF when reading from the filesystem, and convert in reverse when writing to the filesystem. Just be aware also that if you do set this and one of your stored binary files is accidentally marked as text, there is a chance for it to become corrupted.&lt;/p&gt;
&lt;p&gt;2) Edit the .git/hooks/pre-commit file and comment out the following lines:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;/&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="nv"&gt;$/&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  bad_line&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;trailing whitespace&amp;quot;&lt;/span&gt;, &lt;span class="nv"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The reason why this is a problem is because there is a space (\s in posix regex) just before the end of the line (aka a trailing whitespace).  Normally this file wouldn&amp;#8217;t fire off unless you made it executable, but on Windows all of the git hooks run because there is no concept of whether they are executable or not, they all are by default.  On Mac/*nix Git repositories, you need to &amp;#8220;chmod +x&amp;#8221; (change to executable) the git hook files before Git will run them.&lt;/p&gt;
&lt;p&gt;3) When commiting do the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git commit --no-verify
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;and the pre-commit hook will be ignored.&lt;/p&gt;
&lt;p&gt;4) Rename/Move/Delete the .git/hooks/pre-commit file&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;mv .git/hooks/pre-commit .git/hooks/pre-commit.stop_working
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;5) Change the permissions on the .git/hooks/pre-commit file.  In this case, I&amp;#8217;m clearing the executable bit for all users (owner, group and rest of the world)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;chmod a-x .git/hooks/pre-commit
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/12/20/suspicious-patch-lines.html</feedburner:origLink></entry>
 
 <entry>
   <title>Agile coaching</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/7aw--4Cov0o/agile_coaching.html" />
   <updated>2009-12-13T00:00:00-08:00</updated>
   <id>http://blog.jasonmeridth.com/2009/12/13/agile_coaching</id>
   <content type="html">&lt;h1&gt;Agile coaching&lt;/h1&gt;
&lt;p class="meta"&gt;13 Dec 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;My manager let me borrow his copy of &lt;a href="http://pragprog.com/titles/sdcoach/agile-coaching"&gt;Pragmatic Programmer&amp;#8217;s Agile Coaching&lt;/a&gt;.  I&amp;#8217;ve read a good number of Agile process and management books.  I&amp;#8217;m partial to the Pragmatic Programmer publishers due to their consistently well-written books.  I also started using stickies instead of pens/pencils when I read my books.  Mainly because they stand out better and allow me to find my notes quicker.  The other reason is because I can remove them when I give the book away (which I&amp;#8217;ve done a good deal lately.  Of course, not with this book since it was my boss&amp;#8217;).  The stickies I use are &lt;a href="http://www.3m.com/us/office/postit/products/prod_ft_pgm.html"&gt;these&lt;/a&gt; and can be found at most office stores.&lt;/p&gt;
&lt;p&gt;Anyways, back to the book.  The authors, Rachel Davies and Liz Sedley, do a good job explaining the different ways to start/continue agile coaching.  The format of the book, multiple sections relevant to the chapter, Hurdles, and Checklist, worked very well for me.  They share their experience, pain points, and give you a list that you can contain in your short-term memory.&lt;/p&gt;
&lt;p&gt;I enjoyed reading this book because it made me, once again, focus more on the people aspect of software development and less on the coding.  I haven&amp;#8217;t focused much on that part because I&amp;#8217;ve assumed the people I work with are all professionals.  Unfortunately, I&amp;#8217;ve forgotten that they are human, too and need to be approached as humans and not machines.  I&amp;#8217;m still convinced that all software developers are control freaks.  Our computer does what we tell it to.  If it doesn&amp;#8217;t, it is usually our fault.&lt;/p&gt;
&lt;p&gt;I highly recommend this book.&lt;/p&gt;
&lt;h1&gt;&lt;span class="caps"&gt;NOTES&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;h2&gt;Chapter 1 &amp;#8211; Starting the Journey&lt;/h2&gt;
&lt;p&gt;Developing a Coaching attitude&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Lead by example &amp;#8211; follow the agile principles yourself&lt;/li&gt;
	&lt;li&gt;Keep your balance &amp;#8211; never take criticism personally&lt;/li&gt;
	&lt;li&gt;Set a realistic pace &amp;#8211; patience, change takes time&lt;/li&gt;
	&lt;li&gt;Mind your language &amp;#8211; stay professional, of course, but use terms like &amp;#8220;our/we/us&amp;#8221; instead of &amp;#8220;I/you/they&amp;#8221;.&lt;/li&gt;
	&lt;li&gt;Learn as you go &amp;#8211; most powerful lessons are learned from mistakes, expect to make them&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PrOpER cycle&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Problem: Pick a problem to work on.  Watch how the team works.  What needs to be improved&lt;/li&gt;
	&lt;li&gt;Options: Consider your options.  What could you try that might influence the situation for the better?  List at least three options&lt;/li&gt;
	&lt;li&gt;Experiment: Pick one option to try&lt;/li&gt;
	&lt;li&gt;Review: Review the outcome.  Did you improve things?  Even if things haven&amp;#8217;t improved, have you learned something?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Credit the Team&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Don&amp;#8217;t expect to get recognition&lt;/li&gt;
	&lt;li&gt;Supporting Role&lt;/li&gt;
	&lt;li&gt;Success &amp;#8211; credit goes to team&lt;/li&gt;
	&lt;li&gt;Failure &amp;#8211; commiserate with the team&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No Experience&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Uknown situation &amp;#8211; be open about it to the team rather than bluffing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;h2&gt;Chapter 2 &amp;#8211; Working with People&lt;/h2&gt;
&lt;p&gt;Yes, I&amp;#8217;m Listening&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Create space&lt;/li&gt;
	&lt;li&gt;Be open&lt;/li&gt;
	&lt;li&gt;Show interest&lt;/li&gt;
	&lt;li&gt;Affirm&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Gradient Scale for building agreement&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Endorse&lt;/li&gt;
	&lt;li&gt;Agree with reservations&lt;/li&gt;
	&lt;li&gt;Mixed feelings&lt;/li&gt;
	&lt;li&gt;Disagree but go with majority&lt;/li&gt;
	&lt;li&gt;Block&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;h2&gt;Chapter 3 &amp;#8211; Leading Change&lt;/h2&gt;
&lt;p&gt;Five Whys&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;will usually help you get to the real problem&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When Not to Ask Questions&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Take care not to ask questions when you actually want to give guidance.&lt;/li&gt;
	&lt;li&gt;If you ask a question, you have to accept the answer, even if you disagree, and this makes it harder to give the advice you wanted to give.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;h2&gt;Chapter 4 &amp;#8211; Building an Agile Team&lt;/h2&gt;
&lt;p&gt;If people feel really unsafe&amp;#8212;for example, if the are scared that they will lose their jobs&amp;#8212;you won&amp;#8217;t be able to do any Agile coaching.&lt;/p&gt;
&lt;p&gt;Not Too Easy, Not Too Hard&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Foster a culture where is&amp;#8217;s OK to experiment to learn more about a problem that the team is trying to solve.&lt;/li&gt;
	&lt;li&gt;Although, developing more than one solution may feel like a waste of time, it can be a quick qay to learn and a cheap way to mitigate the rise of making the wrong decision.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Find a Compelling Goal&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Once they understand that they don&amp;#8217;t need to wait for permission, it can free them to make a start.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Time For Innovation&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;If they don&amp;#8217;t get time to explore new technology or experiment with innovative product ideas, teams become demotivated.  Make time in iteration plans for them to explore new ideas.  This can do wonders for motivation&amp;#8212;and for the product.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Teams Aren&amp;#8217;t Cross-Functional&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Some companies organize teams by discipline, such as analysts, designers, testsers, software engineers, and so on, with separate reporting lines.  This is a serious blocker to becoming Agile because a fundamental Agile principle is cross-functional teams with different disciplines working together to build the best software.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;h2&gt;Chapter 5 &amp;#8211; Daily Standup&lt;/h2&gt;
&lt;p&gt;For the Team by the Team&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Standup is for them to synchronize their work.&lt;/li&gt;
	&lt;li&gt;It is &lt;em&gt;not&lt;/em&gt; held for a project manager or team lead to gather progress from the team or give feedback on their work.&lt;/li&gt;
	&lt;li&gt;Encourage the team to direct their answers toward other team members.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Establising a Team Focus&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Asking questions in the daily standup could cause members to focus responses to you, avoid this.&lt;/li&gt;
	&lt;li&gt;If response are continually directed at you, deflect them like this: &amp;#8220;Please, can you direct your replies to the whole team?  The daily standup is for you all to work out what you need to do today, not me&amp;#8221;. Worst case: do not attend the daily standup at all&lt;/li&gt;
	&lt;li&gt;Avoid giving praise during the stand-up, again to avoid focus of work and responses on you&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Handling Issues&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Parking lot of issues on the whiteboard&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Forget the Formula&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Don&amp;#8217;t let the rules, which are there to help you get started, become a straightjacket once you are more established.&lt;/li&gt;
	&lt;li&gt;Don&amp;#8217;t let the stand-ups/scrum lose it&amp;#8217;s meaning&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hurdle: Dail Standup Isn&amp;#8217;t Wanted&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&amp;#8230;if the whole team objects to the daily standups, you have a more serious problem on your hands.  It is possible that they&amp;#8217;re struggling to work as a team or that the meetings are being badly run.  We suggest you discuss their concerns in the retrospective.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;h2&gt;Chapter 6 &amp;#8211; Understanding What to Build&lt;/h2&gt;
&lt;p&gt;Life Cycle of a User Story&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;A story is a placeholder for a conversation and eventual task breakdown.&lt;/li&gt;
	&lt;li&gt;Ron Jefferies summarizes the critical aspects of users stories as the 3Cs&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
	&lt;li&gt;Card&lt;/li&gt;
	&lt;li&gt;Conversation&lt;/li&gt;
	&lt;li&gt;Confirmation&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Story Templates&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Purpose is to help team improve their understanding rather than a form to be filled in.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Confirming the Details&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Another common term for story tests is acceptance criteria&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hurdle: No User-Facing Functionality&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Still use your story templates and not short ambiguous task names&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;h2&gt;Chapter 7 &amp;#8211; Planning Ahead&lt;/h2&gt;
&lt;p&gt;Decomposing into Tasks&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&amp;#8230;if the team already has a clear idea of the work, decomposing into tasks may be overkill.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Arriving at an Estimate&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Use a story card matrix (grouping story cards with similar estimates into columns) to help the team keep their estimates consistent.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Keeping Track&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Noticed that putting tasks in a tracking tool can lead to micromanagement.&lt;/li&gt;
	&lt;li&gt;Remind the team that stakeholders will be interested in whole user stories being finished rather than tasks because tasks aren&amp;#8217;t deliverables.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hurdle: The Team Is Asked to Overcommit&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Try to convince the stakeholder or others in charge of the hard date, that all deliverables may not be delivered.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hurdle: Plan Changes During the Iteration&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Expect the team to create some additional tasks for a story as their understanding of the problem grows, but watch out if the tasks change a lot&amp;#8212;that is a sign that the team didn&amp;#8217;t come to grips with what needed to be done in planning.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hurdle: Planning Doesn&amp;#8217;t Make Sense&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Rather than waste time on planning iterations during times of low resources due to vacation, training, etc, or many bugs, create a prioritized queue of work on the team board.&lt;/li&gt;
	&lt;li&gt;If this happens a lot, then consider moving to a kanban style of development, which doesn&amp;#8217;t depend on iteration timeboxes to limit work in progress.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;h2&gt;Chapter 8 &amp;#8211; Keeping It Visible&lt;/h2&gt;
&lt;p&gt;Agile Planning Software Won&amp;#8217;t Help&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Adding &amp;#8220;agile&amp;#8221; software to an already broken process will only hinder communication further&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Electronic Boards&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Electronic tools don&amp;#8217;t need to break down to tasks, as their lifespan is only as long as the story is being worked upon.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;h2&gt;Chapter 9 &amp;#8211; Getting to &amp;#8220;Done&amp;#8221;&lt;/h2&gt;
&lt;p&gt;Defining What &amp;#8220;Done&amp;#8221; Means&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&amp;#8220;Done&amp;#8221; means the customer is happy with what has been developed, and &lt;em&gt;all&lt;/em&gt; the story tests pass.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Managing Bugs&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;If story test is failing, it needs to get fixed before the story can be considered as &amp;#8220;done&amp;#8221;&lt;/li&gt;
	&lt;li&gt;Team disgression on other bugs that come up during the iteration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;h2&gt;Chapter 10 &amp;#8211; Driving Development with Tests&lt;/h2&gt;
&lt;p&gt;Test-Driven Development&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&amp;#8230;encourages a developer to think about solving one small problem at a time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unit Test Rules by Michael Feathers, Object Mentor&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;A test is not a unit test if:&lt;/li&gt;
	&lt;li&gt;it talks to the database&lt;/li&gt;
	&lt;li&gt;it communicates across the network&lt;/li&gt;
	&lt;li&gt;it touches the file system&lt;/li&gt;
	&lt;li&gt;it can&amp;#8217;t run correctly at the same time as any of your other unit tests, or&lt;/li&gt;
	&lt;li&gt;you have to do special things to your environment (such as editing config files) to run it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Don&amp;#8217;t Force Toys on the Team&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Team rituals spring up naturally&lt;/li&gt;
	&lt;li&gt;Don&amp;#8217;t inflict the team with a forced, cute build token&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;h2&gt;Chapter 11 &amp;#8211; Clean Code&lt;/h2&gt;
&lt;p&gt;Agreeing On a Way Forward&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;possibly use an outside expert, therefore, focusing on the issues and not the personalities&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pair Programming&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;when driving, don&amp;#8217;t just type code in silence.  Explain what you&amp;#8217;re doing and why.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;h2&gt;Chapter 12 &amp;#8211; Demonstrating Results&lt;/h2&gt;
&lt;p&gt;Everyone Plays a Part&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;During the demonstration&amp;#8230;take notes unobtrusively on index cards rather than writing them up on a whiteboard because this can distract from the demo&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;h2&gt;Chapter 13 &amp;#8211; Driving Change with Retrospective&lt;/h2&gt;
&lt;p&gt;Looking Back&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Possibly use a timeline, having each member fill in items with sticky notes, will provide a &amp;#8220;clear&amp;#8221; picture of past events.&lt;/li&gt;
	&lt;li&gt;Art gallery &amp;#8211; have each member draw a picture (metaphor) of what the project/iteration felt like to them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mining for Gold&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Dot voting &amp;#8211; choose three most critical topics.  Each member gets three votes.  Prioritize critical topics based off dot summation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Designing a Retrospective&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;example of how to break down the time:&lt;/li&gt;
	&lt;li&gt;Review the goal of meeting, and remind the team of the ground rules (5 minutes)&lt;/li&gt;
	&lt;li&gt;Create a timeline (15 minutes)&lt;/li&gt;
	&lt;li&gt;Mine the timeline for insights (15 minutes)&lt;/li&gt;
	&lt;li&gt;Select the topics to focus on (10 minutes)&lt;/li&gt;
	&lt;li&gt;Review the progress on previous actions (5 minutes)&lt;/li&gt;
	&lt;li&gt;Generate ideas for improvements (15 minutes)&lt;/li&gt;
	&lt;li&gt;Action planning (15 minutes)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Prime Directive&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Ground Rules:&lt;/li&gt;
	&lt;li&gt;no laptops&lt;/li&gt;
	&lt;li&gt;cell phones on silent&lt;/li&gt;
	&lt;li&gt;taking turns to speak&lt;/li&gt;
	&lt;li&gt;Prime Directive: &amp;#8220;Regardless of what we discover, we understand and truly believe that everyone did the best job they could, give what they knew at the time, their skills and abilities, the resources available, and the situation at hand.&amp;#8221;&lt;/li&gt;
	&lt;li&gt;prime directive also helps counter &lt;em&gt;fundamental attribution error&lt;/em&gt;, which is the human tendency to explain the actions of other people as deliberate choice and downplay the situational fears.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Retrospective Prework&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;email querying attendees to gauge direction&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;#8212;&lt;/p&gt;
&lt;h2&gt;Chapter 14 &amp;#8211; Growing You&lt;/h2&gt;
&lt;p&gt;Ways to Grow What You Know&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Commit to read one technical book per month&lt;/li&gt;
	&lt;li&gt;Start your own blog&lt;/li&gt;
	&lt;li&gt;Contribute to an open source project&lt;/li&gt;
	&lt;li&gt;Post one a day to a community mailing list&lt;/li&gt;
	&lt;li&gt;Listen to a podcast on your way to work&lt;/li&gt;
	&lt;li&gt;Spare one evening a monh to attend an interest group&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Making a Plan&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Invest in your knowledge&lt;/li&gt;
	&lt;li&gt;Do not &lt;em&gt;expect&lt;/em&gt; your employer to pay for you&lt;/li&gt;
	&lt;li&gt;your plans need to achievable, bear in mind your other commitments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Personal Reflections&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;write down your thoughts to help articulate your feelings&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Take a Break&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;If you don&amp;#8217;t take time to unwind, you will be unable to put events into perspective and context.  If you are stressed, everything seems bigger, worse, and more important that it really is&lt;/li&gt;
	&lt;li&gt;Try to get a sense of perspective.  What are you stressed about?  When you look a year from now, will it still seem important?  If not, then is it important enough to worry about now?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Getting Comfortable&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Agile Coach == thick skin&lt;/li&gt;
	&lt;li&gt;Not everyone likes being challenged and stretched, and they may take it out on you&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Be Kind&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Don&amp;#8217;t judge others harshly&lt;/li&gt;
	&lt;li&gt;assume everyone is doing their best and that they do everything for a reason&lt;/li&gt;
	&lt;li&gt;Don&amp;#8217;t guess and then judge and gossip &amp;#8212; go talk to them, find out about them&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/12/13/agile_coaching.html</feedburner:origLink></entry>
 
 <entry>
   <title>Pair programming with screen</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/EI7CMzvHhlU/pair-programming-with-screen.html" />
   <updated>2009-12-06T00:00:00-08:00</updated>
   <id>http://blog.jasonmeridth.com/2009/12/06/pair-programming-with-screen</id>
   <content type="html">&lt;h1&gt;Pair programming with screen&lt;/h1&gt;
&lt;p class="meta"&gt;06 Dec 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve decided, once again, to make the jump back to &lt;span class="caps"&gt;VIM&lt;/span&gt; full-time.  It will help my bash-fu become stronger and also ensure that I can pair program with any other dev.  TextMate is awesome for personal development, but using &lt;a href="http://http://www.vim.org/scripts/script.php?script_id=1658"&gt;NERDTree&lt;/a&gt; (&lt;a href="http://www.flickr.com/photos/30496122@N07/2862367534/sizes/o/"&gt;example&lt;/a&gt;) and &lt;a href="http://rails.vim.tpope.net/"&gt;vim.rails&lt;/a&gt; (&lt;a href="http://cheat.errtheblog.com/s/rails_vim/"&gt;cheat sheet&lt;/a&gt;) by &lt;a href="http://twitter.com/tpope"&gt;@tpope&lt;/a&gt; has made my &lt;span class="caps"&gt;VIM&lt;/span&gt; experience much more pleasant..&lt;/p&gt;
&lt;p&gt;Checkout my vim files on &lt;a href="http://github.com/armmer/vim_files"&gt;github&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This post is for me to remember how to use &lt;a href="http://www.gnu.org/software/screen/"&gt;Gnu screen&lt;/a&gt; to pair program. side note: &lt;a href="http://cheat.errtheblog.com/s/screen/"&gt;here&lt;/a&gt; is the best cheat sheet on Gnu Screen.&lt;/p&gt;
&lt;p&gt;startup screen:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;screen -S sessionname
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;turn on multi-user&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;ctrl+a
:multiuser on
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;add permissions for the other user:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;ctrl+a
:acladd user
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;instruct second user to connect with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;screen -x yourusername/sessionname
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/12/06/pair-programming-with-screen.html</feedburner:origLink></entry>
 
 <entry>
   <title>Ruby Design Patterns by Russ Olsen</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/aRFZ7dCt-ME/ruby-design-patterns-by-russ-olsen.html" />
   <updated>2009-10-08T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2009/10/08/ruby-design-patterns-by-russ-olsen</id>
   <content type="html">&lt;h1&gt;Ruby Design Patterns by Russ Olsen&lt;/h1&gt;
&lt;p class="meta"&gt;08 Oct 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;After nudging by &lt;a href="http://agilejoe.lostechies.com/"&gt;Joe Ocampo&lt;/a&gt; and &lt;a href="http://www.ampgt"&gt;Scott Bellware&lt;/a&gt;, I finally sat down at finished &amp;#8220;Design Patterns in Ruby&amp;#8221; by Russ Olsen.&lt;/p&gt;
&lt;p&gt;The format of most of the chapters made the book an interesting read:&lt;br /&gt;
1. A introduction to why you might need the pattern&lt;br /&gt;
2. A static language developer&amp;#8217;s approach with the Ruby language&lt;br /&gt;
3. A seasoned Ruby developer&amp;#8217;s approach to the design pattern&lt;br /&gt;
4. Using and Abusing &lt;the design="" pattern=""&gt;&lt;br /&gt;
5. &lt;the design="" pattern=""&gt; in the wild&lt;br /&gt;
6. Wrapping up&lt;/p&gt;
&lt;p&gt;Some of the items that I learned [LosTechies is not a cult contrary to some of the examples you read below; some of the examples below are using LosTechies nomenclature but closely resemble what the author had in the book]&lt;/p&gt;
&lt;p&gt;If any of the stuff below intrigues you:  GO &lt;span class="caps"&gt;BUY&lt;/span&gt; &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;BOOK&lt;/span&gt;.  You won&amp;#8217;t regret it.  Even if you are trying to understand patterns in another language.  Russ Olsen does an excellent job explaining the &lt;span class="caps"&gt;INTENT&lt;/span&gt; of the patterns.&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;FUN&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;When teaching the reader about &amp;#8220;Truth, Lies, and nil&amp;#8221;, the author even pokes fun at himself:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;  &lt;span class="s1"&gt;&amp;#39;russ&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;smart&amp;#39;&lt;/span&gt;    &lt;span class="c1"&gt;# sadly, false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2&gt;&lt;span class="caps"&gt;BOOLEAN&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;In Ruby, zero, being neither &lt;i&gt;false&lt;/i&gt; nor &lt;i&gt;nil&lt;/i&gt;, evaluates to true in Boolean expression.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
 &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Zero is true!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;will print out: &lt;strong&gt;Zero is true!&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;ARRAYS&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Points for matrix reference in array examples&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;neo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;trinity&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;tank&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2&gt;&lt;span class="caps"&gt;REGULAR&lt;/span&gt; &lt;span class="caps"&gt;EXPRESSIONS&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;The flow of the language when creating regular expressions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="sr"&gt;/old/&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;this old house&amp;#39;&lt;/span&gt;     &lt;span class="c1"&gt;# 5 - the index of &amp;#39;old&amp;#39;&lt;/span&gt;&lt;span class="sr"&gt;&lt;/span&gt;
&lt;span class="sr"&gt;/Russ|Russell/&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Fred&amp;#39;&lt;/span&gt;      &lt;span class="c1"&gt;# nil - Fred is not Russ nor Russell&lt;/span&gt;&lt;span class="sr"&gt;&lt;/span&gt;
&lt;span class="sr"&gt;/.*/&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;any old string&amp;#39;&lt;/span&gt;      &lt;span class="c1"&gt;# 0 - the RE will match anything&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2&gt;&lt;span class="caps"&gt;ARBITRARY&lt;/span&gt; &lt;span class="caps"&gt;PARAMETERS&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Any author that uses DC comic character to explain arbitrary numbers of arguments, is a winner in my mind:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;describe_hero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;super_powers&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Name: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;power&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;super_powers&lt;/span&gt;
     &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Super power: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;power&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;describe_hero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Batman&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;describe_hero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Flash&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;speed&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;describe_hero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Superman&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;can fly&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;x-ray vision&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;invulnerable&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# w00t!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2&gt;&lt;span class="caps"&gt;DUCK&lt;/span&gt; &lt;span class="caps"&gt;TYPING&lt;/span&gt; &lt;span class="caps"&gt;AND&lt;/span&gt; &lt;span class="caps"&gt;UNIT&lt;/span&gt; &lt;span class="caps"&gt;TESTS&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;He mentions duck typing and the fact that &amp;#8220;Unit Tests Are Not Optional&amp;#8221; is a section heading when teaching the Template Method Pattern.&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;PROCS&lt;/span&gt; &lt;span class="caps"&gt;AND&lt;/span&gt; &lt;span class="caps"&gt;BLOCKS&lt;/span&gt;&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;# using the do/end notation&lt;/span&gt;
&lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
 &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hello&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;I am a follower of Pablo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;#you may use curly braces instead of do/end&lt;/span&gt;
&lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hello, I am a follower of Pablo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;#the preferred way to use curly braces&lt;/span&gt;
&lt;span class="n"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hello, I am a follower of Pablo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2&gt;&lt;span class="caps"&gt;STRATEGY&lt;/span&gt; &lt;span class="caps"&gt;PATTERN&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;using proc-based formatters to create a ruby-based strategy pattern&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Report&lt;/span&gt;
 &lt;span class="kp"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:text&lt;/span&gt;
 &lt;span class="kp"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:formatter&lt;/span&gt;

 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;amp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;formatter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="vi"&gt;@title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Monthly Report&amp;#39;&lt;/span&gt;
   &lt;span class="vi"&gt;@text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Things are going&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;really, really well.&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
   &lt;span class="vi"&gt;@formatter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;formatter&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;

 &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;output_report&lt;/span&gt;
   &lt;span class="vi"&gt;@formatter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;HTML_FORMATTER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="no"&gt;HTML&lt;/span&gt;

&lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Report&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;amp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="no"&gt;HTML_FORMATTER&lt;/span&gt;
&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_report&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You could create any type of formatter you want in a proc instead creating new classes.&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;OBSERVER&lt;/span&gt; &lt;span class="caps"&gt;PATTERN&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Modules exist that encapsulate things that some of us static developers might already be used to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;observer&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Employee&lt;/span&gt;
&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Observable&lt;/span&gt;

&lt;span class="kp"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:address&lt;/span&gt;
&lt;span class="kp"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:salary&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="vi"&gt;@name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;
 &lt;span class="vi"&gt;@title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
 &lt;span class="vi"&gt;@salary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;salary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_salary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="vi"&gt;@salary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_salary&lt;/span&gt;
 &lt;span class="n"&gt;changed&lt;/span&gt;
 &lt;span class="n"&gt;notify_observers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2&gt;&lt;span class="caps"&gt;ITERATOR&lt;/span&gt; &lt;span class="caps"&gt;PATTERN&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Internal Iterators versus External Iterators: (had never heard it put this way)&lt;br /&gt;
External iterator &amp;#8211; client drives the iteration&amp;#8230;you won&amp;#8217;t call next until you are good and ready for the next element&lt;br /&gt;
Internal iterator &amp;#8211; the aggregate relentlessly pushes the code block to accept item after item.&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;COMMAND&lt;/span&gt; &lt;span class="caps"&gt;PATTERN&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;The Command pattern translates very smoothly into code blocks.  Here is a PabloForPresidentButton class reworked to use code blocks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PabloForPresidentButton&lt;/span&gt;
  &lt;span class="kp"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:command&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;amp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  
  &lt;span class="c1"&gt;#&lt;/span&gt;
  &lt;span class="c1"&gt;# Lots of button drawing and management&lt;/span&gt;
  &lt;span class="c1"&gt;# code omitted ...&lt;/span&gt;
  &lt;span class="c1"&gt;#&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_button_push&lt;/span&gt;
    &lt;span class="vi"&gt;@command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@command&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;new_button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;PabloForPresidentButton&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;#&lt;/span&gt;
  &lt;span class="c1"&gt;# Make a developer stop looking so nerdy&lt;/span&gt;
  &lt;span class="c1"&gt;# by placing one over his pocket protector&lt;/span&gt;
  &lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The author does not diminish the needs for classes.  For straightforward actions, use a Proc object.  For complex object or objects that will carry around a lot of state, create a command class.&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;ADAPTER&lt;/span&gt; &lt;span class="caps"&gt;PATTERN&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Instead of adhering to some interface and trying to create your adapter, why not just extend the original class.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;# load original class&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;lostechies_text_object&amp;#39;&lt;/span&gt;

&lt;span class="c1"&gt;# now add some methods to original class&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LosTechiesTextObject&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sponsor&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;friend_of_pablo&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;blogger&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;follower_of_pablo&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Before any of you Open-Closed people attack, please re-read the definition of &lt;span class="caps"&gt;OCP&lt;/span&gt; &amp;#8211; Open for extension, closed for modification.  Doesn&amp;#8217;t this adhere to that?  :)&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;PROXY&lt;/span&gt; &lt;span class="caps"&gt;PATTERN&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;There are three tyes of Proxies:  The Protection Proxy, Remote Proxy, Virtual Proxy&lt;br /&gt;
These are mentioned in the Gang of Four book.  He introduces a Ruby-esqe way to approach proxies:  the method_missing Method&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AccountProxy&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;real_account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="vi"&gt;@subject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;real_account&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;method_missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Delegating &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; message to subject.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="vi"&gt;@subject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;ap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;AccountProxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="no"&gt;BankAccount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deposit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withdraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;account balance is now: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;ap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Will output:&lt;br /&gt;
delegating deposit method to subject.&lt;br /&gt;
delegating withdraw method to subject.&lt;br /&gt;
delegating balance method to subject.&lt;br /&gt;
account balance is now: 75&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;DECORATOR&lt;/span&gt; &lt;span class="caps"&gt;PATTERN&lt;/span&gt;&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Decorator1&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;common_item_to_decorate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="c1"&gt;#code&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Decorator2&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;common_item_to_decorate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="c1"&gt;#code&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SimpleItem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Decorator1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Decorator2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;howdy&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2&gt;&lt;span class="caps"&gt;SINGLETON&lt;/span&gt; &lt;span class="caps"&gt;PATTERN&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;The author admits the career of the singleton has been checkered, but still shows that you can use it in the Ruby world.  An example he gives us to allow testing of singleton implementation code is to put the implementation code in a base class and have the child be the singleton:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;singleton&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleLogger&lt;/span&gt;
&lt;span class="c1"&gt;#  All of the logging functionality in this class...&lt;/span&gt;
&lt;span class="c1"&gt;#  Test this code&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SingletonLogger&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;SimpleLogger&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2&gt;&lt;span class="caps"&gt;FACTORY&lt;/span&gt;/&lt;span class="caps"&gt;ABSTRACT&lt;/span&gt; &lt;span class="caps"&gt;FACTORY&lt;/span&gt; &lt;span class="caps"&gt;PATTERN&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;I never had it straight, exactly, what the difference between these patterns were (yes, besides name).  I never bothered to look.  According to the author, Factory returns back a single object while Abstract Factory is &amp;#8220;an object dedicated to creating a compatible set of objects&amp;#8221;.  According to GoF book (which I have open in front of me), Abstract Factory &amp;#8220;provides an interface for creating families of related or dependent objects without specifying their concreate classes&amp;#8221;.  Which one do you think would have turned the light bulb off in your head?  :)&lt;/p&gt;
&lt;p&gt;The other item was using &amp;#8220;Convention Over Configuration&amp;#8221; to generate abstract factories:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IOFactory&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="vi"&gt;@reader_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;const_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;Reader&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="vi"&gt;@writer_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;const_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;Writer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new_reader&lt;/span&gt;
   &lt;span class="vi"&gt;@reader_class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new_writer&lt;/span&gt;
   &lt;span class="vi"&gt;@writer_class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;html_factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;IOFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;HTML&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;html_reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;html_factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new_reader&lt;/span&gt;

&lt;span class="n"&gt;pdf_factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;IOFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PDF&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pdf_writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pdf_factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new_writer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Notice the correct classes (reader/writer) are generated dynamically with the help of the const_get Ruby method.&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;BUILDER&lt;/span&gt; &lt;span class="caps"&gt;PATTERN&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Magic methods: &amp;#8220;very easy to implement using the method_missing technique&amp;#8230;you simply catch all unexpected method calls with method_missing and parse the method name to see if it matches the pattern of your magic method name&amp;#8221;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;#example method passed into computer builder class&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_dvd_and_harddisk&lt;/span&gt;

&lt;span class="c1"&gt;#or&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_turbo_and_dvd_dvd_and_harddisk&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;method_missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shift&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;add&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
 &lt;span class="c1"&gt;#next is same as continue in for loop in C#&lt;/span&gt;
 &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;and&amp;#39;&lt;/span&gt;
 &lt;span class="c1"&gt;#each of the following method calls are a part of the builder class&lt;/span&gt;
 &lt;span class="n"&gt;add_cd&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;cd&amp;#39;&lt;/span&gt;
 &lt;span class="n"&gt;add_dvd&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;dvd&amp;#39;&lt;/span&gt;
 &lt;span class="n"&gt;add_hard_disk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;harddisk&amp;#39;&lt;/span&gt;
 &lt;span class="n"&gt;turbo&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;turbo&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Last 3 Chapters are the meat of the book:&lt;br /&gt;
&lt;span class="caps"&gt;INTERPRETER&lt;/span&gt; &lt;span class="caps"&gt;PATTERN&lt;/span&gt; (place where &lt;a href="http://www.ampgt.com"&gt;Bellware&lt;/a&gt; told me to start)&lt;br /&gt;
&lt;span class="caps"&gt;DOMAIN&lt;/span&gt; &lt;span class="caps"&gt;SPECIFIC&lt;/span&gt; &lt;span class="caps"&gt;LANGUAGE&lt;/span&gt; (&lt;span class="caps"&gt;DSL&lt;/span&gt;)&lt;br /&gt;
&lt;span class="caps"&gt;CONVENTION&lt;/span&gt; &lt;span class="caps"&gt;OVER&lt;/span&gt; &lt;span class="caps"&gt;CONFIGURATION&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Those stay obscure so you can go read it.  I think the book is worth a visit on Safari books if you have an account or worth the purchase for the bathroom reading.&lt;/p&gt;
&lt;p&gt;I enjoyed it.  Thanks &lt;a href="http://www.ampgt.com/"&gt;Scott&lt;/a&gt; and &lt;a href="http://agilejoe.lostechies.com/"&gt;Joe&lt;/a&gt;&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/10/08/ruby-design-patterns-by-russ-olsen.html</feedburner:origLink></entry>
 
 <entry>
   <title>Move my personal blog to Jekyll</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/IbhxB8pNE40/moved-blog-to-jekyll.html" />
   <updated>2009-10-08T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2009/10/08/moved-blog-to-jekyll</id>
   <content type="html">&lt;h1&gt;Move my personal blog to Jekyll&lt;/h1&gt;
&lt;p class="meta"&gt;08 Oct 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;Tonight I decided to finally move my blog to the &lt;a href="http://github.com/mojombo/jekyll"&gt;Jekyll&lt;/a&gt; blogging engine.  It&amp;#8217;s about static content and no longer using a database to store your posts.  I&amp;#8217;ve been reading about it for a while and decided to make the jumpt tonight.&lt;/p&gt;
&lt;p&gt;Hell, maybe I&amp;#8217;ll try to contribute back to the project for needs that I have and that don&amp;#8217;t exist.  I like that idea a lot.&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/10/08/moved-blog-to-jekyll.html</feedburner:origLink></entry>
 
 <entry>
   <title>git local pre-commit hook</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/63UP0H972Dk/git-local-pre-commit-hook.html" />
   <updated>2009-10-08T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2009/10/08/git-local-pre-commit-hook</id>
   <content type="html">&lt;h1&gt;git local pre-commit hook&lt;/h1&gt;
&lt;p class="meta"&gt;08 Oct 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve personally added a pre-commit hook to my local git repos.  It&amp;#8217;s like a personal CI before I push back to origin/master.  I run my tests locally anyway before committing and pushing, so I thought I would automate it.&amp;lt;&lt;/p&gt;
&lt;p&gt;I open the .git/hooks/pre-commit file in my local repo (i.e, full path is something like /Users/jasonmeridth/code/rails/myapp/.git/hooks/pre-commit) and put the following:&amp;lt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
rake db:migrate
rake db:test:prepare
rake
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;For non-rails developers, this will run any database migrations on my &lt;app_name&gt;&lt;em&gt;development database, then ensure the &lt;app_name&gt;&lt;/em&gt;test database has the same schema, and then runs the tests.&lt;/p&gt;
&lt;p&gt;The reason the last step above is &amp;#8220;rake&amp;#8221; is because I leave it to you to have your default rake task be &amp;#8220;rake test:units&amp;#8221; or &amp;#8220;rake spec&amp;#8221; depending on whether you are using a TestUnit framework or RSpec.&lt;/p&gt;
&lt;p&gt;Git hooks are not made executable by default, except on Windows because it doesn&amp;#8217;t understand the unix permissions.  On my Mac, I have to issue the following command (from the app root):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;chmod +x .git/hooks/pre-commit
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This makes the pre-commit hook executable and Git will run it before every commit to this repo. If this process returns a non-zero value (failure), then the commit does &lt;em&gt;not&lt;/em&gt; happen.  I&amp;#8217;ll be shown the failing tests and I can fix them and try to re-commit.&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/10/08/git-local-pre-commit-hook.html</feedburner:origLink></entry>
 
 <entry>
   <title>git instaweb</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/WK2qAsIk1lA/git-instaweb.html" />
   <updated>2009-10-08T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2009/10/08/git-instaweb</id>
   <content type="html">&lt;h1&gt;git instaweb&lt;/h1&gt;
&lt;p class="meta"&gt;08 Oct 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;I was reading &lt;a href="http://progit.org/book/ch4-6.html"&gt;Pro Git by Scott Chacon&lt;/a&gt; and was on the section about &amp;#8220;git instaweb&amp;#8221;.  This is where you can run gitweb, a cgi script that comes with git, locally or on a server.  I have successfully gotten gitweb up for my personal git repos on my remote server.  I use it all the time.  I was curious if I could get it working locally, for friends who prefer a visual tool to see their git logs, commits, etc.&lt;/p&gt;
&lt;p&gt;I cd into a local repo (you have to cd into the .git folder of the app to get the desired view):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /code/app/.git
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;and run the instaweb command (note: I&amp;#8217;m on a macbook pro that already has ruby installed, hence my choice of using webrick instead of the default lighttpd):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git instaweb -d webrick --start
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I tried the command without the &amp;#8220;&amp;#8212;start&amp;#8221; command and it kept trying to seek a browser.  I tried &amp;#8220;-b firefox&amp;#8221;, &amp;#8220;-b Firefox&amp;#8221;, &amp;#8220;-b /Application/Firefox.app/MacOS/firefox-bin&amp;#8221;, etc and they all failed.  I found the &amp;#8220;&amp;#8212;start&amp;#8221; suggestion on &lt;a href="http://stackoverflow.com/questions/1258353/running-git-instaweb-on-boot"&gt;StackOverflow.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once I ran this command, I could see the git log, commits, diffs, etc in gitweb for my local changes.  What this will do is run the daemon on port 1234 of localhost.  If you open your browser of choice and go to &lt;a href="http://localhost:1234"&gt;http://localhost:1234&lt;/a&gt; then you will see gitweb for the git repository you ran the command in.&lt;/p&gt;
&lt;p&gt;To stop the process, just change &amp;#8220;&amp;#8212;start&amp;#8221; with &amp;#8220;&amp;#8212;stop&amp;#8221;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;git instaweb -d webrick --stop
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Note:  I personally use &amp;#8220;git log &amp;#8212;graph&amp;#8221;, gitk, gitx, or other tools for this, usually.  Just thought it was a good addition to my git toolset.&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/10/08/git-instaweb.html</feedburner:origLink></entry>
 
 <entry>
   <title>Hudson service files</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/Ke27xlLcq2Y/hudson-service-files.html" />
   <updated>2009-06-09T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2009/06/09/hudson-service-files</id>
   <content type="html">&lt;h1&gt;Hudson service files&lt;/h1&gt;
&lt;p class="meta"&gt;06 Jun 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;This post is strictly for my reference.  These scripts are dependent on an existing user named hudson with a home directory of /home/hudson and the hudson.war file being located at /usr/share/hudson/hudson.war.&lt;/p&gt;
&lt;p&gt;/etc/init.d/hudson&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="c"&gt;#! /bin/bash&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# hudson    Start/Stop the Hudson Continuous Integration server.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# chkconfig: 345 91 10&lt;/span&gt;
&lt;span class="c"&gt;# description: Hudson is a Continuous Integration server. \&lt;/span&gt;
&lt;span class="c"&gt;#              It monitors a source code repository and triggers builds \&lt;/span&gt;
&lt;span class="c"&gt;#              when it detects any changes. See https://hudson.dev.java.net/ \&lt;/span&gt;
&lt;span class="c"&gt;#              for more details.&lt;/span&gt;
&lt;span class="c"&gt;# processname: hudson&lt;/span&gt;
&lt;span class="c"&gt;# pidfile: /var/run/hudson.pid&lt;/span&gt;


&lt;span class="c"&gt;# Source function library.&lt;/span&gt;
&lt;span class="c"&gt;#. /etc/rc.d/init.d/functions&lt;/span&gt;

&lt;span class="c"&gt;# Get config.&lt;/span&gt;
&lt;span class="c"&gt;#. /etc/sysconfig/network&lt;/span&gt;

&lt;span class="c"&gt;# Check that networking is up.&lt;/span&gt;
&lt;span class="c"&gt;#[ &amp;quot;${NETWORKING}&amp;quot; = &amp;quot;no&amp;quot; ] &amp;amp;&amp;amp; exit 0&lt;/span&gt;

&lt;span class="nv"&gt;startup&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/bin/start-hudson.sh
&lt;span class="nv"&gt;shutdown&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/bin/stop-hudson.sh
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;JAVA_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/java/jdk1.6.0
&lt;span class="nv"&gt;HUDSON_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;hudson

start&lt;span class="o"&gt;(){&lt;/span&gt;
 &lt;span class="nb"&gt;echo&lt;/span&gt; -n &lt;span class="s2"&gt;$&amp;quot;Starting Hudson service: &amp;quot;&lt;/span&gt;
 su - &lt;span class="nv"&gt;$HUDSON_USER&lt;/span&gt; -c &lt;span class="nv"&gt;$startup&lt;/span&gt;
 &lt;span class="nv"&gt;RETVAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
 &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

stop&lt;span class="o"&gt;(){&lt;/span&gt;
 &lt;span class="nb"&gt;echo&lt;/span&gt; -n  &lt;span class="s2"&gt;$&amp;quot;Stopping Hudson service: &amp;quot;&lt;/span&gt; 
 su - &lt;span class="nv"&gt;$HUDSON_USER&lt;/span&gt; -c &lt;span class="nv"&gt;$shutdown&lt;/span&gt;
 &lt;span class="nv"&gt;RETVAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
 &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

status&lt;span class="o"&gt;(){&lt;/span&gt;
 &lt;span class="nv"&gt;numproc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;ps -ef | grep hudson.war | grep -v &lt;span class="s2"&gt;&amp;quot;grep hudson.war&amp;quot;&lt;/span&gt; | wc -l&lt;span class="sb"&gt;`&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$numproc&lt;/span&gt; -gt 0 &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Hudson is running...&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="k"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Hudson is stopped...&amp;quot;&lt;/span&gt;
 &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

restart&lt;span class="o"&gt;(){&lt;/span&gt;
  stop
  start
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="c"&gt;# See how we were called.&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$1&amp;quot;&lt;/span&gt; in
start&lt;span class="o"&gt;)&lt;/span&gt;
 start
 ;;
stop&lt;span class="o"&gt;)&lt;/span&gt;
 stop
 ;;
status&lt;span class="o"&gt;)&lt;/span&gt;
 status
 ;;
restart&lt;span class="o"&gt;)&lt;/span&gt;
 restart
 ;;
*&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;$&amp;quot;Usage: $0 {start|stop|status|restart}&amp;quot;&lt;/span&gt;
 &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;esac&lt;/span&gt;

&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;/usr/local/bin/start-hudson.sh&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;HUDSON_WAR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/share/hudson/hudson.war
&lt;span class="nv"&gt;HUDSON_LOG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/hudson/hudson.log
java -jar &lt;span class="nv"&gt;$HUDSON_WAR&lt;/span&gt; &amp;gt; &lt;span class="nv"&gt;$HUDSON_LOG&lt;/span&gt; Z&amp;gt;&amp;amp;1 &amp;amp;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;/usr/local/bin/stop-hudson.sh&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;kill&lt;/span&gt; -9 &lt;span class="sb"&gt;`&lt;/span&gt;ps -ef | grep hudson.war | grep -v grep | awk &lt;span class="s1"&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/06/09/hudson-service-files.html</feedburner:origLink></entry>
 
 <entry>
   <title>Git post-receive hook with Integrity post call</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/mjLCEiS4IDI/git-post-receive-hook-with-integrity-post-call.html" />
   <updated>2009-05-28T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2009/05/28/git-post-receive-hook-with-integrity-post-call</id>
   <content type="html">&lt;h1&gt;Git post-receive hook with Integrity post call&lt;/h1&gt;
&lt;p class="meta"&gt;28 May 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;Using the following code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;#!/usr/bin/env ruby&lt;/span&gt;
 
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;net/http&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;net/https&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;json&amp;#39;&lt;/span&gt;
 
&lt;span class="c1"&gt;# EDIT POST_RECEIVE_URL&lt;/span&gt;
&lt;span class="no"&gt;POST_RECEIVE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://my.domain.com/application_name/push&amp;#39;&lt;/span&gt;
 
&lt;span class="n"&gt;old_head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;STDIN&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;
 
&lt;span class="c1"&gt;#puts &amp;quot;old_head: #{old_head}&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;#puts &amp;quot;new_head: #{new_head}&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;#puts &amp;quot;ref: #{ref}&amp;quot;&lt;/span&gt;
 
&lt;span class="n"&gt;revision_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`git-rev-list --pretty=format:&amp;#39;Author: %an &amp;lt;%ae&amp;gt;%nDate: %cd%n%s%n&amp;#39; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;new_head&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt; ^&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;old_head&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="n"&gt;revisions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;revision_text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\n\n/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\n/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/commit (\w+)/&lt;/span&gt;
  &lt;span class="n"&gt;sha1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vg"&gt;$1&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/Author: (.*) &amp;lt;(.+?)&amp;gt;/&lt;/span&gt;
  &lt;span class="n"&gt;author_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;author_email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vg"&gt;$1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vg"&gt;$2&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/Date: +(.+?) -0/&lt;/span&gt;
  &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vg"&gt;$1&lt;/span&gt;
  &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;
  &lt;span class="n"&gt;revisions&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sha1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;author&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s1"&gt;&amp;#39;email&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;author_email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;author_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;message&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;timestamp&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
 
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;revisions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty?&lt;/span&gt;
  &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
 
&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s1"&gt;&amp;#39;payload&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;ref&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;commits&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;revisions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_json&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
 
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;fork&lt;/span&gt;
  &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;detach&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;POST_RECEIVE_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;post_req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;post_req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basic_auth&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;53cr3t&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;p@55w0rd&amp;#39;&lt;/span&gt;
  &lt;span class="n"&gt;post_req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_form_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 
  &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;use_ssl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify_mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;OpenSSL&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SSL&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;VERIFY_NONE&lt;/span&gt;
  &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_req&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
 
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Running Integrity CI build for application_name application&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This git post-receive hook script queries the latest commit, gets the revision changes, and then passes that payload (via json) to a net/https &lt;span class="caps"&gt;POST&lt;/span&gt; call.  I setup our &lt;a href="http://www.integrityapp.com"&gt;Integrity CI server&lt;/a&gt; with a self-signed certificate and &lt;span class="caps"&gt;HTTP&lt;/span&gt; basic authentication.&lt;/p&gt;
&lt;p&gt;The Net::&lt;span class="caps"&gt;HTTP&lt;/span&gt;::Post.new instantiation group handles populating the basic authentication information and putting the payload into the form data of the request.  The Net::&lt;span class="caps"&gt;HTTP&lt;/span&gt;.new group handles telling the request that it will be via &lt;span class="caps"&gt;SSL&lt;/span&gt; (443) and to not verify the &lt;span class="caps"&gt;SSL&lt;/span&gt; certificate (since I&amp;#8217;m using a self-signed certificate; otherwise, I&amp;#8217;d get a warning and kill my automation process)&lt;/p&gt;
&lt;p&gt;The other important part is the &amp;#8220;if pid = fork&amp;#8221;.  The ruby &lt;a href="http://www.ruby-doc.org/core/classes/Process.html#M003179"&gt;fork&lt;/a&gt; command allows code to happen in the background, in the case the &lt;span class="caps"&gt;POST&lt;/span&gt; call, and therefore make the call synchronous. Otherwise, when the developers commit their code to the repository, they will have to wait for the build to finish before their prompt will be returned to them.  fork will return zero (0) if it fails to create the background process.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m still checking whether the zombie process warning in the rdoc (for the fork command) is a problem.  I&amp;#8217;ll update this if it is.&lt;/p&gt;
&lt;p&gt;The last line is notification for the user so they know what&amp;#8217;s going on. Always good to keep the user in the loop. :)&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/05/28/git-post-receive-hook-with-integrity-post-call.html</feedburner:origLink></entry>
 
 <entry>
   <title>Nerds</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/QYvdyGA0JN4/nerds.html" />
   <updated>2009-04-06T00:00:00-07:00</updated>
   <id>http://blog.jasonmeridth.com/2009/04/06/nerds</id>
   <content type="html">&lt;h1&gt;Nerds&lt;/h1&gt;
&lt;p class="meta"&gt;06 Apr 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;&lt;a href="http://agilejoe.lostechies.com"&gt;Joe Ocampo&lt;/a&gt; and I have been good friends for a while.&lt;/p&gt;
&lt;p&gt;This is from one of our pairing sessions.  I drink Monster.&lt;br /&gt;
&lt;img src="http://blog.jasonmeridth.com/images/monster_nerd_jason_joe.jpg" title="Monster and Nerd" alt="Monster and Nerd" /&gt;&lt;/p&gt;
&lt;p&gt;And this is from this past weekend at the Alt.&lt;span class="caps"&gt;NET&lt;/span&gt; conference:&lt;br /&gt;
&lt;img src="http://blog.jasonmeridth.com/images/jason_joe.jpg" title="Jason Meridth and Joe Ocampo" alt="Jason Meridth and Joe Ocampo" /&gt;&lt;/p&gt;
&lt;p&gt;Should make someone laugh.&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/04/06/nerds.html</feedburner:origLink></entry>
 
 <entry>
   <title>Git and sharedrepository</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/Epj9JN3j2Xc/git_and_sharedrepository.html" />
   <updated>2009-02-26T00:00:00-08:00</updated>
   <id>http://blog.jasonmeridth.com/2009/02/26/git_and_sharedrepository</id>
   <content type="html">&lt;h1&gt;Git and sharedrepository&lt;/h1&gt;
&lt;p class="meta"&gt;26 Feb 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;Today I pushed some code changes to our canonical repository.  Well, at least I tried.  I couldn&amp;#8217;t because the user and group that were associated to that change had been changed by the prior user&amp;#8217;s push.  It was the user change that was the problem, it was the group change.&lt;/p&gt;
&lt;p&gt;I found out that we needed to add &amp;#8220;sharedrepository=true&amp;#8221; to the /srv/git/our_repository/.git/config file so that the group assigned to the repo&amp;#8217;s objects (/srv/git/our_repository/.git/objects) doesn&amp;#8217;t get changed to the local user&amp;#8217;s.&lt;/p&gt;
&lt;p&gt;All the developers are a part of the same group on the git server; the same group initially assinged to the objects.  With the &amp;#8220;sharedrepository=true&amp;#8221; setting, that won&amp;#8217;t change when anyone from that group pushes to the canonically repository.&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/02/26/git_and_sharedrepository.html</feedburner:origLink></entry>
 
 <entry>
   <title>Hudson and Nginx</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/VIfijs_-9Ow/hudson-and-nginx.html" />
   <updated>2009-02-09T00:00:00-08:00</updated>
   <id>http://blog.jasonmeridth.com/2009/02/09/hudson-and-nginx</id>
   <content type="html">&lt;h1&gt;Hudson and Nginx&lt;/h1&gt;
&lt;p class="meta"&gt;09 Feb 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="caps"&gt;UPDATE&lt;/span&gt;:  I left &lt;span class="caps"&gt;HTTP&lt;/span&gt; Auth in place via Nginx and removed security from my Hudson instance.  This works for me because I don&amp;#8217;t care about Hudson security.  I&amp;#8217;m just trying to prevent external access to the dashboard.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve been having fun trying to figure out how to block a user&amp;#8217;s ability of going to http://mydomain:8080 and bypassing my 80 to 443 redirect and htpasswd &lt;span class="caps"&gt;HTTP&lt;/span&gt; basic authentication.  I even went as far as removing Nginx and installing Apache.&lt;br /&gt;
According to the Hudson site, we can use &lt;a href="http://hudson.gotdns.com/wiki/display/HUDSON/Apache+frontend+for+security"&gt;Apache to do this&lt;/a&gt;.  Either I&amp;#8217;m not smart enough or web pages like this reminded me why I hate the Java Enterprise stack as much as I do.  Talk about installation obfuscation.&lt;/p&gt;
&lt;p&gt;My problem exists because the Tomcat instance running the hudson war file uses &lt;a href="http://tomcat.apache.org/tomcat-5.5-doc/config/ajp.html#Standard%20Implementation"&gt;Apache JServe Protocol&lt;/a&gt; (&lt;span class="caps"&gt;AJP&lt;/span&gt;) and will allow direct access on whatever port you used (default 8080).  This is even if you proxy_pass to 8080 from 443 (&lt;span class="caps"&gt;SSL&lt;/span&gt;) or 80 (Web).&lt;/p&gt;
&lt;p&gt;Through testing and research it seems that &lt;a href="http://www.ruby-forum.com/topic/157269#693042"&gt;Nginx does not have a solution for this&lt;/a&gt;.  I can&amp;#8217;t allow access to my Hudson instance from external users.  I have a self-signed certificate and a .htpasswd file to protect the instance, but is all useless is someone could just type in http://mydomain.com:8080.  I want that redirected to https://mydomain.com which will then proxy internally to http://127.0.0.1:8080.&lt;/p&gt;
&lt;p&gt;I didn&amp;#8217;t want to fight this, so I just used iptables (linux firewall) to block external requests on port 8080 but allow internal requests to 8080.  Here is the entry in my iptables file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;&lt;span class="c"&gt;# Deny HTTP requests to port 8080 externally but allow internally&lt;/span&gt;
-A INPUT -i eth0 -p tcp -m tcp --dport 8080 -j REJECT
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I only allow access to my server via 80 (web), 443 (ssl) and my ssh port (I&amp;#8217;m not telling).&lt;/p&gt;
&lt;p&gt;This works for now, but I&amp;#8217;m experiencing another weird issue.  I follow the Nginx way of using &lt;span class="caps"&gt;HTTP&lt;/span&gt; basic authentication:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="bash"&gt;location  /  &lt;span class="o"&gt;{&lt;/span&gt;      
 auth_basic            &lt;span class="s2"&gt;&amp;quot;Restricted&amp;quot;&lt;/span&gt;;
 auth_basic_user_file  conf/htpasswd;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;If the user listed in the &lt;a href="http://httpd.apache.org/docs/2.0/programs/htpasswd.html"&gt;htpasswd&lt;/a&gt; file is also a registered user on the Hudson instance (through the Hudson UI) then the &lt;span class="caps"&gt;HTTP&lt;/span&gt; basic authentication will work.  If they are in the htpasswd file but not registered with Hudson, it fails with a &lt;span class="caps"&gt;HTTP&lt;/span&gt; 401 (Unauthorized).  Why would the &lt;span class="caps"&gt;HTTP&lt;/span&gt; basic authentication be &amp;#8220;tunneled&amp;#8221; through to Hudson?&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll update this post once I figure it out.&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/02/09/hudson-and-nginx.html</feedburner:origLink></entry>
 
 <entry>
   <title>Slicehost articles</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/B6xDaCrBD5Q/slicehost-articles.html" />
   <updated>2009-01-31T00:00:00-08:00</updated>
   <id>http://blog.jasonmeridth.com/2009/01/31/slicehost-articles</id>
   <content type="html">&lt;h1&gt;Slicehost articles&lt;/h1&gt;
&lt;p class="meta"&gt;31 Jan 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;If you are Linux newbie or are still unsure about how to setup your &lt;strong&gt;Linux&lt;/strong&gt; box/slice/server (sorry Windows guys), take a serious look at the &lt;a href="http://articles.slicehost.com/"&gt;Slicehost Articles&lt;/a&gt;.  Other articles include setup of Apache, Nginx, Postfix, MySQL, Ruby on Rails, Capistrano, &lt;span class="caps"&gt;SSH&lt;/span&gt;, Self-signed certificates, Django, etc.&lt;/p&gt;
&lt;p&gt;For all the Only Windows guys who read this, these articles are a great way to get your feet wet with Linux.  Can&amp;#8217;t hurt your pocket book.  It&amp;#8217;s free. Ubuntu is my favorite.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve tweeted about this a number of times.&lt;/p&gt;
&lt;p&gt;These articles are phenomenal&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/01/31/slicehost-articles.html</feedburner:origLink></entry>
 
 <entry>
   <title>Pair Programming</title>
   <link href="http://feedproxy.google.com/~r/jmeridth/~3/yqn0eTxkMgk/pair-programming.html" />
   <updated>2009-01-29T00:00:00-08:00</updated>
   <id>http://blog.jasonmeridth.com/2009/01/29/pair-programming</id>
   <content type="html">&lt;h1&gt;Pair Programming&lt;/h1&gt;
&lt;p class="meta"&gt;29 Jan 2009 &amp;#8211; San Antonio&lt;/p&gt;
&lt;p&gt;I recently found this post, &lt;a href="http://blog.jayfields.com/2008/02/pair-programming-all-time.html"&gt;Pair Programming all the time&lt;/a&gt;, by &lt;a href="http://blog.jayfields.com/"&gt;Jay Fields&lt;/a&gt; and loved it.  I&amp;#8217;ve felt the same way about pair programming.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;I define all the time (in terms of pairing) as when I&amp;#8217;m writing code that I&amp;#8217;m going to commit.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is perfect.  Common sense but stated explicitly.  I worked in an Agile shop for 2 1/2 years and the environment was setup to highlight pair programming.  Pictures and little explanation &lt;a href="http://www.lostechies.com/blogs/joe_ocampo/archive/2007/12/09/where-the-magic-happens-our-dev-lap.aspx"&gt;here&lt;/a&gt; (Thanks Joe).  We even marked tasks in the stories as low (L) or high (H) to dictate whether a pair was necessary (this was decided during our modeling week by the two developers who tasked the story, but always up for discussion during the iteration).  It worked out pretty well.&lt;/p&gt;
&lt;p&gt;I understand and have heard all the reasons to not pair program.  Sometimes it works and sometimes it doesn&amp;#8217;t.  I&amp;#8217;ve personally experienced the benefits.  You learn to work with different personalities and that can only benefit you in your professional career.  And, the obvious reason, is immediate code review.  But, as my friend Scott C. Reynolds &lt;a href="http://www.lostechies.com/blogs/scottcreynolds/archive/2009/01/23/on-teaching-learning-and-being-honest-with-ourselves.aspx"&gt;says&lt;/a&gt; (more or less):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;Not everyone is cut from the same cloth&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is true and that is life.  I hope this helps someone understand that not all pair programming enthusiasts are zealots.   I know it&amp;#8217;s a fine line though.&lt;/p&gt;</content>
 <feedburner:origLink>http://blog.jasonmeridth.com/2009/01/29/pair-programming.html</feedburner:origLink></entry>
 
 
</feed>

