Parker Smith Software

 

A script to make adding new GIT repositories easier

By Brian Webb

7 Nov 2008

My friend Jesse and I were trying to figure out a way to make the process of working with new GIT repositories easier. We wanted to create a new GIT repository locally, creating a new remote repository and adding the remote to the local so that you can push your development changes out for others to collaborate with. This involves a number of commands locally, then logging into your server, creating folders and git repositories there, then adding the remote repository to your local copy. Here is our current workflow:

1
2
3
4
5
6
7
8
9
10
 
#locally 
git init git add . git commit -m "initial import"  

#remote server 
cd /var/git mkdir newproject.git && cd newproject.git git --bare init  

#locally 
git remote add origin ssh://user@domain.com:35432/var/git/newproject.git 
git push origin master

That isn't a ton of work but it is a repetitive task that could be simplified. We started with some ideas of shell scripts and I ended up creating a script in Ruby that handles everything. It is called GNR which represented GIT - New - Repository when we came up with the concept. The script does all the commands above for you. Lets look at an example.

1
2
3
4
5
 
#create a new dummy rails project
rails newproj 

gnr newproj ssh://user@domain.com:35432/var/git/newproj.git

That's it. Now we can CD into the newproj directory and start working. There are a couple assumptions that this script makes though:

1. You are using public/private RSA keys to login to your SSH server without passwords
2. Your user in the remote repo URL string (user@domain.com) has privileges to be able to write to the directory where your repositories are stored (/var/git in this example)

So here is the code:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156


require 'optparse' 
require 'rdoc/usage'
require 'ostruct'
require 'date'


class App
  VERSION = '0.0.1'
  
  attr_reader :options

  def initialize(arguments, stdin)
    @arguments = arguments
    @stdin = stdin
    
    # Set defaults
    @options = OpenStruct.new
    @options.verbose = false
    @options.quiet = false
    @local_exists = false
    @remote_exists = false

  end #end initialize


  # Parse options, check arguments, then process the command
  def run
        
    if parsed_options? && arguments_valid? 
      
      puts "Start at #{DateTime.now}\n\n" if @options.verbose
      
      output_options if @options.verbose # [Optional]
            
      process_arguments            
      process_command
      
      puts "\nFinished at #{DateTime.now}" if @options.verbose
      
    else
      output_usage
    end
      
  end
  
  protected
  
    def parsed_options?
      
      # Specify options
      opts = OptionParser.new 
      opts.on('-v', '--version')    { output_version ; exit 0 }
      opts.on('-h', '--help')       { output_help }
      opts.on('-V', '--verbose')    { @options.verbose = true }  
      opts.on('-q', '--quiet')      { @options.quiet = true }
            
      opts.parse!(@arguments) rescue return false
      
      process_options
      true      
    end

    # Performs post-parse processing on options
    def process_options
      @options.verbose = false if @options.quiet
    end
    
    def output_options
      puts "Options:\n"
      
      @options.marshal_dump.each do |name, val|        
        puts "  #{name} = #{val}"
      end
    end

    # True if required arguments were provided
    def arguments_valid?
      true if @arguments.length >= 1 
    end
    
    # Setup the arguments
    def process_arguments
      @project_folder = @arguments[0]
      @repo = @arguments[1] ? @arguments[1] : nil
    end
    
    def output_help
      output_version
      RDoc::usage() #exits app
    end
    
    def output_usage
      RDoc::usage('usage') # gets usage from comments above
    end
    
    def output_version
      puts "#{File.basename(__FILE__)} version #{VERSION}"
    end
    
    def process_command
      
      FileUtils.cd(@project_folder, :verbose => @options.verbose) do
        begin
          FileUtils.cd(".git", :verbose => @options.verbose) do 
            @local_exists = true
            puts "Local repository already exists" unless @options.quiet
            config = File.new("config").read
            @remote_exists = true if config =~ /remote "origin"/
          end
        rescue
          %x[git init]
          %x[git add .]
          %x[git commit -m "Created initial local repo"]
          
          #ssh to server and make new repo.git
          if @repo
            
            #get the repo string into usable vars
            user = @repo.gsub("ssh://","").split("@")[0]
            domain = @repo.gsub("ssh://","").split("@")[1].split(":")[0]
            port = @repo.gsub("ssh://", "").split(":")[1].split("/")[0]
            remote_repo = @repo.gsub("ssh://", "").split(":")[1][@repo.gsub("ssh://", "").split(":")[1].index("/"), @repo.gsub("ssh://", "").split(":")[1].length]
            root_folder = remote_repo[0,remote_repo.rindex("/")]
            repo_folder = remote_repo[remote_repo.rindex("/")+1, remote_repo.length]
            repo_string = %(ssh://#{user}@#{domain}:#{port}#{root_folder}/#{repo_folder})
            
            commands = ["cd #{root_folder}", "mkdir #{repo_folder}", "cd #{repo_folder}", "git --bare init"]
            
            #ssh into the server and create the remote repo
            ssh_string = %(ssh -fCT #{user}@#{domain} -p #{port} "#{commands.join(" && ")}")
            Kernel.system "#{ssh_string}"
            
            #add the remote repo to the local repo
            Kernel.system "git remote add origin #{repo_string}"
            
            #push the local to the remote
            %x[git push origin master]
          
          end #end if @repo
        
        end #end rescue
      
      end #end FileUtils.cd
      
    end #end process_command
    
end #end App Class


# Create and run the application
app = App.new(ARGV, STDIN)
app.run


 
 
 
No Spam: 7 + 3 =
 
November 07, 2008 - Brian Webb
4