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
11
12
13
14

#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

rails newproj #create a new dummy rails project
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191

#!/usr/bin/env ruby 

# == Synopsis 
#   This script streamlines the creation of GIT repositories
#          and the adding of the repository to a remote GIT server.
#          With one command you can create a new repository, add
#          it to your GIT server and start working.
#
# == Examples
#   This command just creates a new GIT repositor, but doesn't
#          add it to a remote origin server
#     gnr .
#     gnr /path/to/project
#
#   Other examples:
#     gnr . ssh://[user]@[domain]:[port]/[root_repo_path]/[new_repo_name]
#     gnr . ssh://user@domain.com:29876/var/git/repo.git
#
# == Usage 
#   gnr [options] local_project_folder remote_repository_path
#
#   For help use: gnr -h
#
# == Options
#   -h, --help          Displays help message
#   -v, --version       Display the version, then exit
#   -q, --quiet         Output as little as possible, overrides verbose
#   -V, --verbose       Verbose output
#
#
# == Author
#   Brian Webb <brian@parkersmithsoftware.com>
#
# == Copyright
#   Copyright (c) 2008 Parker Smith. Licensed under the MIT License:
#   http://www.opensource.org/licenses/mit-license.php


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: 3 + 4 =