Module: FalkorLib::Git

Defined in:
lib/falkorlib/git/base.rb

Overview

Management of Git operations

Class Method Summary collapse

Class Method Details

.add(path, msg = "", options = {}) ⇒ Object

Add a file/whatever to Git and commit it Supported options:

  • :force [boolean]: force the add



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/falkorlib/git/base.rb', line 244

def add(path, msg = "", options = {})
 exit_status = 0
    dir  = File.realpath File.dirname(path)
    root = rootdir(path)
    relative_path_to_root = Pathname.new( File.realpath(path) ).relative_path_from Pathname.new(root)
    real_msg = (msg.empty? ? "add '#{relative_path_to_root}'" : msg)
    opts = '-f' if options[:force]
    Dir.chdir( dir ) do
  exit_status = run %{
          git add #{opts} #{path}
          git commit -s -m "#{real_msg}" #{path}
        }
    end
 exit_status.to_i
end

.branch?(path = Dir.pwd) ⇒ Boolean

Get the current git branch

Returns:

  • (Boolean)


193
194
195
# File 'lib/falkorlib/git/base.rb', line 193

def branch?(path = Dir.pwd)
    list_branch(path)[0]
end

.command?(cmd, path = Dir.pwd) ⇒ Boolean

Check the availability of a given git command

Returns:

  • (Boolean)


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
# File 'lib/falkorlib/git/base.rb', line 57

def command?(cmd, path = Dir.pwd)
    cg = MiniGit::Capturing.new(path)
    cmd_list = cg.help :a => true
    # typical run:
    # usage: git [--version] [--help] [-C <path>] [-c name=value]
    #            [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
    #            [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
    #            [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
    #            <command> [<args>]
    #
    # available git commands in '/usr/local/Cellar/git/1.8.5.2/libexec/git-core'
    #
    #   add   [...]        #   [...]          | The part we are interested in, delimited by '\n\n' sequence
    #   [...]         /
    #
    # 'git help -a' and 'git help -g' lists available subcommands and some
    # concept guides. See 'git help <command>' or 'git help <concept>'
    # to read about a specific subcommand or concept
    l = cmd_list.split("\n\n")
    l.shift # useless first part
    #ap l
    subl = l.each_index.select{|i| l[i] =~ /^\s\s+/ } # find sublines that starts with at least two whitespaces
    #ap subl
    return false if subl.empty?
    subl.any? { |i| l[i].split.include?(cmd) }
end

.config(key, dir = Dir.pwd, options = {}) ⇒ Object

config ###### Retrieve the Git configuration You can propose a pattern as key Supported options:

* :list [boolean] list all configutations
* :hash [boolean] return a Hash


151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/falkorlib/git/base.rb', line 151

def config(key, dir = Dir.pwd, options = {})
  #info "Retrieve the Git configuration"
  res = nil
  if (options[:list] or (key.is_a? Regexp) or (key =~ /\*/))
    cg  = MiniGit::Capturing.new(dir)
    res = (cg.config :list => true).split("\n")
    res.select! { |e| e.match(key) } unless key =='*'
    #res = res.map { |e| e.split('=') }.to_h if options[:hash]
    res = Hash[ res.map { |e| e.split('=') } ] if options[:hash]
  else
    g = MiniGit.new(dir)
    res = g[key]
    res = { key => g[key] } if options[:hash]
  end
  #ap res
  res
end

.config_warn(type = :subtrees) ⇒ Object

Raise a warning message if subtree/submodule section is not present



434
435
436
437
438
439
440
441
442
443
444
445
446
447
# File 'lib/falkorlib/git/base.rb', line 434

def config_warn(type = :subtrees)
    warn "You shall setup 'FalkorLib.config.git[#{type.to_sym}]' to configure #{type} as follows:"
    warn "     FalkorLib.config.git do |c|"
    warn "       c[#{type.to_sym}] = {"
    warn "          '<subdir>' => {"
    warn "             :url    => '<giturl>',"
    warn "             :branch => 'develop'   # if different from master"
    warn "          },"
    warn "        }"
    warn "     end"
    if type == :submodules
        warn "This will configure the Git submodule into FalkorLib.config.git.submodulesdir i.e. '#{ FalkorLib.config.git.submodulesdir}'"
    end
end

.create_branch(branch, path = Dir.pwd) ⇒ Object

Create a new branch



130
131
132
133
134
135
# File 'lib/falkorlib/git/base.rb', line 130

def create_branch(branch, path = Dir.pwd)
 #ap method(__method__).parameters.map { |arg| arg[1] }
 g = MiniGit.new(path)
 error "not yet any commit performed -- You shall do one" unless has_commits?(path) 
    g.branch "#{branch}"
end

.delete_branch(branch, path = Dir.pwd, opts = { :force => false }) ⇒ Object

Delete a branch.



138
139
140
141
142
# File 'lib/falkorlib/git/base.rb', line 138

def delete_branch(branch, path = Dir.pwd, opts = { :force => false })
    g = MiniGit.new(path)
 error "'#{branch}' is not a valid existing branch" unless list_branch(path).include?( branch )
 g.branch (opts[:force] ? :D : :d) => "#{branch}"
end

.dirty?(path = Dir.pwd) ⇒ Boolean

Check if a git directory is in dirty mode git diff –shortstat 2> /dev/null | tail -n1

Returns:

  • (Boolean)


262
263
264
265
266
267
# File 'lib/falkorlib/git/base.rb', line 262

def dirty?(path = Dir.pwd)
    g = MiniGit.new(path)
    a = g.capturing.diff :shortstat => true
    #ap a
    ! a.empty?
end

.fetch(path = Dir.pwd) ⇒ Object

Fetch the latest changes



171
172
173
174
175
# File 'lib/falkorlib/git/base.rb', line 171

def fetch(path = Dir.pwd)
    Dir.chdir( path ) do
        execute "git fetch --all -v"
    end
end

.gitdir(path = Dir.pwd) ⇒ Object

Return the git root directory for the path (current directory by default)



124
125
126
127
# File 'lib/falkorlib/git/base.rb', line 124

def gitdir(path = Dir.pwd)
    g = MiniGit.new
    g.find_git_dir(path)[0]
end

.grab(branch, path = Dir.pwd, remote = 'origin') ⇒ Object

Grab a remote branch



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/falkorlib/git/base.rb', line 198

def grab(branch, path = Dir.pwd, remote = 'origin')
    exit_status = 1
    error "no branch provided" if branch.nil?
    remotes  = FalkorLib::Git.remotes(path)
    branches = FalkorLib::Git.list_branch(path)
    Dir.chdir(FalkorLib::Git.rootdir( path ) ) do
        if branches.include? "remotes/#{remote}/#{branch}"
            info "Grab the branch '#{remote}/#{branch}'"
            exit_status = execute "git branch --set-upstream #{branch} #{remote}/#{branch}"
        else
            warning "the remote branch '#{remote}/#{branch}' cannot be found"
        end
    end
    exit_status
end

.has_commits?(path) ⇒ Boolean

Check if the repositories already holds some commits

Returns:

  • (Boolean)


47
48
49
50
51
52
53
54
# File 'lib/falkorlib/git/base.rb', line 47

def has_commits?(path)
 res = false
 Dir.chdir(path) do
  stdout, stderr, exit_status = Open3.capture3( "git rev-parse HEAD" ) 
  res = (exit_status == 0)
 end
 res
end

.init(path = Dir.pwd, options = {}) ⇒ Object

Initialize a git repository



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
# File 'lib/falkorlib/git/base.rb', line 88

def init(path = Dir.pwd, options = {})
    # FIXME for travis test: ensure the global git configurations
    # 'user.email' and 'user.name' are set
    [ 'user.name', 'user.email' ].each do |userconf|
        if MiniGit[userconf].nil?
            warn "The Git global configuration '#{userconf}' is not set so"
            warn "you should *seriously* consider setting them by running\n\t git config --global #{userconf} 'your_#{userconf.sub(/\./, '_')}'"
            default_val = ENV['USER']
            default_val += '@domain.org' if userconf =~ /email/
            warn "Now putting a default value '#{default_val}' you could change later on"
            run %{
                 git config --global #{userconf} "#{default_val}"
            }
            #MiniGit[userconf] = default_val
        end
    end
 exit_status = 1
    Dir.mkdir( path ) unless Dir.exist?( path )
 Dir.chdir( path ) do
  execute "git init" unless FalkorLib.config.debug
  exit_status = $?.to_i
 end
    # #puts "#init #{path}"
    # Dir.chdir( "#{path}" ) do
    #     %x[ pwd && git init ] unless FalkorLib.config.debug
    # end
 exit_status
end

.init?(path = Dir.pwd) ⇒ Boolean

Check if a git directory has been initialized

Returns:

  • (Boolean)


37
38
39
40
41
42
43
44
# File 'lib/falkorlib/git/base.rb', line 37

def init?(path = Dir.pwd)
    begin
        g = MiniGit.new(path)
    rescue Exception
        return false
    end
    return true
end

.last_tag_commit(path = Dir.pwd) ⇒ Object

Get the last tag commit, or nil if no tag can be found



270
271
272
273
274
275
276
# File 'lib/falkorlib/git/base.rb', line 270

def last_tag_commit(path = Dir.pwd)
 res = nil
 g = MiniGit.new(path)
 # git rev-list --tags --max-count=1)
    a = g.capturing.rev_list :tags => true, :max_count => 1
 a
end

.list_branch(path = Dir.pwd) ⇒ Object

Get an array of the local branches present (first element is always the current branch)



179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/falkorlib/git/base.rb', line 179

def list_branch(path = Dir.pwd)
    cg = MiniGit::Capturing.new(path)
    res = cg.branch :a => true
    res = res.split("\n")
    # Eventually reorder to make the first element of the array the current branch
    i = res.find_index { |e| e =~ /^\*\s/ }
    unless (i.nil? || i == 0)
        res[0], res[i] = res[i], res[0]
    end
    res.each { |e| e.sub!(/^\*?\s+/, '')  }
    res
end

.list_files(path = Dir.pwd) ⇒ Object

List the files currently under version



236
237
238
239
# File 'lib/falkorlib/git/base.rb', line 236

def list_files(path = Dir.pwd)
 g = MiniGit.new(path)
 g.capturing.ls_files.split
end

.publish(branch, path = Dir.pwd, remote = 'origin') ⇒ Object

Publish a branch on the remote



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/falkorlib/git/base.rb', line 215

def publish(branch, path = Dir.pwd, remote = 'origin')
    exit_status = 1
    error "no branch provided" if branch.nil?
    remotes  = FalkorLib::Git.remotes(path)
    branches = FalkorLib::Git.list_branch(path)
    Dir.chdir(FalkorLib::Git.rootdir( path ) ) do
        if branches.include? "remotes/#{remote}/#{branch}"
            warning "the  remote branch '#{remote}/#{branch}' already exists"
        else
            info "Publish the branch '#{branch}' on the remote '#{remote}'"
            exit_status = run %{
                  git push #{remote} #{branch}:refs/heads/#{branch}
                  git fetch #{remote}
                  git branch --set-upstream-to #{remote}/#{branch} #{branch}
        }
        end
    end
    exit_status
end

.remotes(path = Dir.pwd) ⇒ Object

List of Git remotes



279
280
281
282
# File 'lib/falkorlib/git/base.rb', line 279

def remotes(path = Dir.pwd)
    g = MiniGit.new(path)
    g.capturing.remote.split()
end

.remotes?(path = Dir.pwd) ⇒ Boolean

remotes?(path = Dir.pw)

Returns:

  • (Boolean)


285
286
287
# File 'lib/falkorlib/git/base.rb', line 285

def remotes?(path = Dir.pwd)
 return ! remotes(path).empty?
end

.rootdir(path = Dir.pwd) ⇒ Object

Return the Git working tree from the proposed path (current directory by default)



118
119
120
121
# File 'lib/falkorlib/git/base.rb', line 118

def rootdir(path = Dir.pwd)
    g = MiniGit.new
    g.find_git_dir(path)[1]
end

.submodule_init(path = Dir.pwd, submodules = , options = {}) ⇒ Object

Initialize git submodule from the configuration



292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/falkorlib/git/base.rb', line 292

def submodule_init(path = Dir.pwd, submodules = FalkorLib.config.git[:submodules], options = {})
    exit_status  = 1
    git_root_dir = rootdir(path)
    if File.exists?("#{git_root_dir}/.gitmodules")
        unless submodules.empty?
            # TODO: Check if it contains all submodules of the configuration
        end
    end
    #ap FalkorLib.config.git
    Dir.chdir(git_root_dir) do
        exit_status = FalkorLib::Git.submodule_update( git_root_dir )
        submodules.each do |subdir,conf|
            next if conf[:url].nil?
            url = conf[:url]
            dir = "#{FalkorLib.config.git[:submodulesdir]}/#{subdir}"
            branch = conf[:branch].nil? ? 'master' : conf[:branch]
            if File.directory?( dir )
              puts "  ... the git submodule '#{subdir}' is already setup."
            else
              info "adding Git submodule '#{dir}' from '#{url}'"
                exit_status = run %{
                   git submodule add -b #{branch} #{url} #{dir}
                   git commit -s -m "Add Git submodule '#{dir}' from '#{url}'" .gitmodules #{dir}
                }
            end
        end
    end
    exit_status
end

.submodule_update(path = Dir.pwd) ⇒ Object

Update the Git submodules to the local registered version



323
324
325
326
327
328
329
330
# File 'lib/falkorlib/git/base.rb', line 323

def submodule_update(path = Dir.pwd)
 execute_in_dir(rootdir(path), 
                %{
           git submodule init
           git submodule foreach git fetch
           git submodule update
    })
end

.submodule_upgrade(path = Dir.pwd) ⇒ Object

Upgrade the Git submodules to the latest HEAD version from the remote



333
334
335
336
337
338
# File 'lib/falkorlib/git/base.rb', line 333

def submodule_upgrade(path = Dir.pwd)
  execute_in_dir(rootdir(path), 
                %{
           git submodule foreach 'git fetch origin; git checkout $(git rev-parse --abbrev-ref HEAD); git reset --hard origin/$(git rev-parse --abbrev-ref HEAD); git submodule update --recursive; git clean -dfx'
     })         
end

.subtree_diff(path = Dir.pwd) ⇒ Object

Show difference between local subtree(s) and their remotes“

Raises:



383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
# File 'lib/falkorlib/git/base.rb', line 383

def subtree_diff(path = Dir.pwd)
    raise ArgumentError, "Git 'subtree' command is not available" unless FalkorLib::Git.command? "subtree"
    if FalkorLib.config.git[:subtrees].empty?
        FalkorLib::Git.config_warn(:subtrees)
        return 1
    end
    exit_status = 0
    git_root_dir = rootdir(path)
    Dir.chdir(git_root_dir) do
        FalkorLib.config.git[:subtrees].each do |dir,conf|
            next if conf[:url].nil?
            url    = conf[:url]
            remote = dir.gsub(/\//, '-')
            branch = conf[:branch].nil? ? 'master' : conf[:branch]
            remotes = FalkorLib::Git.remotes
            raise IOError, "The git remote '#{remote}' is not configured" unless remotes.include?( remote )
            raise IOError, "The git subtree directory '#{dir}' does not exists" unless File.directory? ( File.join(git_root_dir, dir) )
            info "Git diff on subtree '#{dir}' with remote '#{remote}/#{branch}'"
            exit_status = execute "git diff #{remote}/#{branch} #{FalkorLib::Git.branch?( git_root_dir )}:#{dir}"
        end
    end
    exit_status
end

.subtree_init(path = Dir.pwd) ⇒ Object

Initialize git subtrees from the configuration

Raises:



342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/falkorlib/git/base.rb', line 342

def subtree_init(path = Dir.pwd)
    raise ArgumentError, "Git 'subtree' command is not available" unless FalkorLib::Git.command? "subtree"
    if FalkorLib.config.git[:subtrees].empty?
        FalkorLib::Git.config_warn(:subtrees)
        return 1
    end
    exit_status = 0
    git_root_dir = rootdir(path)
    Dir.chdir(git_root_dir) do
        FalkorLib.config.git[:subtrees].each do |dir,conf|
            next if conf[:url].nil?
            url    = conf[:url]
            remote = dir.gsub(/\//, '-')
            branch = conf[:branch].nil? ? 'master' : conf[:branch]
            remotes = FalkorLib::Git.remotes
            unless remotes.include?( remote )
                info "Initialize Git remote '#{remote}' from URL '#{url}'"
                exit_status = execute "git remote add -f #{remote} #{url}"
            end
            unless File.directory?( File.join(git_root_dir, dir) )
                info "initialize Git subtree '#{dir}'"
                exit_status = execute "git subtree add --prefix #{dir} --squash #{remote}/#{branch}"
            end
        end

    end
    exit_status
end

.subtree_init?(path = Dir.pwd) ⇒ Boolean

Check if the subtrees have been initialized. Actually based on a naive check of sub-directory existence

Returns:

  • (Boolean)


373
374
375
376
377
378
379
# File 'lib/falkorlib/git/base.rb', line 373

def subtree_init?(path = Dir.pwd)
 res = true
 FalkorLib.config.git[:subtrees].keys.each do |dir| 
  res = res && File.directory?(File.join(path, dir)) 
 end
 res
end

.subtree_up(path = Dir.pwd) ⇒ Object Also known as: subtree_pull

Pull the latest changes, assuming the git repository is not dirty



408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
# File 'lib/falkorlib/git/base.rb', line 408

def subtree_up(path = Dir.pwd)
    error "Unable to pull subtree(s): Dirty Git repository" if FalkorLib::Git.dirty?( path )
    exit_status = 0
    git_root_dir = rootdir(path)
    Dir.chdir(git_root_dir) do
        FalkorLib.config.git[:subtrees].each do |dir,conf|
            next if conf[:url].nil?
            url    = conf[:url]
            remote = dir.gsub(/\//, '-')
            branch = conf[:branch].nil? ? 'master' : conf[:branch]
            remotes = FalkorLib::Git.remotes
            info "Pulling changes into subtree '#{dir}' using remote '#{remote}/#{branch}'"
            raise IOError, "The git remote '#{remote}' is not configured" unless remotes.include?( remote )
            info "\t\\__ fetching remote '#{remotes.join(',')}'"
            FalkorLib::Git.fetch( git_root_dir )
            raise IOError, "The git subtree directory '#{dir}' does not exists" unless File.directory? ( File.join(git_root_dir, dir) )
            info "\t\\__ pulling changes"
            exit_status = execute "git subtree pull --prefix #{dir} --squash #{remote} #{branch}"
            #exit_status = puts "git subtree pull --prefix #{dir} --squash #{remote} #{branch}"
        end
    end
    exit_status
end