mgit 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/lib/mgit.rb +1 -0
- data/lib/mgit/commands/add.rb +1 -1
- data/lib/mgit/commands/fetch.rb +2 -2
- data/lib/mgit/commands/ffmerge.rb +48 -0
- data/lib/mgit/commands/foreach.rb +3 -3
- data/lib/mgit/commands/grep.rb +2 -2
- data/lib/mgit/commands/list.rb +4 -2
- data/lib/mgit/commands/log.rb +56 -0
- data/lib/mgit/commands/remove.rb +2 -2
- data/lib/mgit/commands/status.rb +20 -19
- data/lib/mgit/registry.rb +51 -0
- data/lib/mgit/repository.rb +50 -37
- data/lib/mgit/version.rb +1 -1
- metadata +7 -10
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YTg0NzVjMDFlNDEzNjNjZGE0ZjQ3ZGZhNGFlZjA0MDUxZGNlMDZmNw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NGYxNWRlMjA4NTJiYjk5MTUwOWRkOThmYzEwMWFmMjNlYmQ3MDJmNQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MjNlM2NiZjExMzQ5MzdjMWEzZTAxZDFmYmVmNDQ0YmQyZjk2ZjQ3ZmMyY2Yz
|
10
|
+
ODYyYWQzZTM4OTk3NjhlMjUwZDZiYmJkNDg0MDIyMTc2ZWQ0OTQwNGFkMjE4
|
11
|
+
ZjI3M2Y0YmJmNDU3OTg1NmJkYWYzY2VmYTQxZGNkMDkzODA4Yjg=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZTQyMGI2ZjNmZjY5ZDRlNzA3YTQxMzkwOWJmZmFjNjNmNGM2MDc5Y2RkNmZl
|
14
|
+
ZGNmN2JkNmUyZTcyYjQ1YmJmMzI2YzA0MGY2NDIzMWZlNmVkYThkMTE2M2Rl
|
15
|
+
ZWFlN2QyMzEzMmZiY2I0NmUzYWY3NjJhMDA2ODBjMGI3YjdmYTE=
|
data/lib/mgit.rb
CHANGED
data/lib/mgit/commands/add.rb
CHANGED
data/lib/mgit/commands/fetch.rb
CHANGED
@@ -3,9 +3,9 @@ module MGit
|
|
3
3
|
def execute(args)
|
4
4
|
raise TooManyArgumentsError.new(self) if args.size != 0
|
5
5
|
|
6
|
-
|
6
|
+
Registry.chdir_each do |repo|
|
7
7
|
`git remote`.split.each do |remote|
|
8
|
-
puts "Fetching #{remote} in repository #{name}...".yellow
|
8
|
+
puts "Fetching #{remote} in repository #{repo.name}...".yellow
|
9
9
|
`git fetch #{remote}`
|
10
10
|
end
|
11
11
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module MGit
|
2
|
+
class FFMergeCommand < Command
|
3
|
+
def execute(args)
|
4
|
+
raise TooManyArgumentsError.new(self) if args.size != 0
|
5
|
+
|
6
|
+
Registry.chdir_each do |repo|
|
7
|
+
if repo.dirty?
|
8
|
+
puts "Skipping repository #{repo.name} since it's dirty.".red
|
9
|
+
next
|
10
|
+
end
|
11
|
+
|
12
|
+
puts "Fast-forward merging branches in repository #{repo.name}...".yellow
|
13
|
+
|
14
|
+
tb = tracking_branches
|
15
|
+
cb = current_branch
|
16
|
+
tb.each do |b|
|
17
|
+
`git checkout -q #{b}`
|
18
|
+
`git merge --ff-only @{u}`
|
19
|
+
end
|
20
|
+
`git checkout -q #{cb}`
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def usage
|
25
|
+
'ffmerge'
|
26
|
+
end
|
27
|
+
|
28
|
+
def description
|
29
|
+
'merge all upstream tracking branches that can be fast-forwarded'
|
30
|
+
end
|
31
|
+
|
32
|
+
register_command :ffmerge
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def tracking_branches
|
37
|
+
`git for-each-ref --format='%(refname:short) %(upstream:short)' refs/heads`.
|
38
|
+
split("\n").
|
39
|
+
map { |b| b.split(' ') }.
|
40
|
+
reject { |b| b.size != 2 }.
|
41
|
+
map(&:first)
|
42
|
+
end
|
43
|
+
|
44
|
+
def current_branch
|
45
|
+
`git rev-parse --abbrev-ref HEAD`
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -5,9 +5,9 @@ module MGit
|
|
5
5
|
|
6
6
|
command = args.join(' ')
|
7
7
|
|
8
|
-
|
9
|
-
puts "Executing command in repository #{name}...".yellow
|
10
|
-
if !system(command) && !ask("Executing command '#{command}' in repository '#{name}' failed. Would you like to continue anyway?".red)
|
8
|
+
Registry.chdir_each do |repo|
|
9
|
+
puts "Executing command in repository #{repo.name}...".yellow
|
10
|
+
if !system(command) && !ask("Executing command '#{command}' in repository '#{repo.name}' failed. Would you like to continue anyway?".red)
|
11
11
|
break
|
12
12
|
end
|
13
13
|
end
|
data/lib/mgit/commands/grep.rb
CHANGED
@@ -6,8 +6,8 @@ module MGit
|
|
6
6
|
|
7
7
|
ptrn = args[0]
|
8
8
|
|
9
|
-
|
10
|
-
puts "Looking for pattern '#{ptrn}' in repository #{name}...".yellow
|
9
|
+
Registry.chdir_each do |repo|
|
10
|
+
puts "Looking for pattern '#{ptrn}' in repository #{repo.name}...".yellow
|
11
11
|
puts `git grep #{ptrn}`
|
12
12
|
puts
|
13
13
|
end
|
data/lib/mgit/commands/list.rb
CHANGED
@@ -3,8 +3,10 @@ module MGit
|
|
3
3
|
def execute(args)
|
4
4
|
raise TooManyArgumentsError.new(self) if args.size != 0
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
Registry.each do |repo|
|
7
|
+
nc = 24
|
8
|
+
display = (repo.name.size > nc) ? (repo.name[0..(nc - 3)] + '...') : repo.name.ljust(nc, ' ')
|
9
|
+
puts "#{display} => #{repo.path}"
|
8
10
|
end
|
9
11
|
end
|
10
12
|
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module MGit
|
2
|
+
class LogCommand < Command
|
3
|
+
def execute(args)
|
4
|
+
raise TooManyArgumentsError.new(self) if args.size > 1
|
5
|
+
|
6
|
+
days = 1
|
7
|
+
|
8
|
+
if args.size == 1
|
9
|
+
begin
|
10
|
+
days = Integer(args[0])
|
11
|
+
rescue ArgumentError => e
|
12
|
+
raise new CommandUsageError("First argument must be an integer", self)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Registry.chdir_each do |repo|
|
17
|
+
lc = latest_commits(days)#.sort_by { |c| c[:author] }
|
18
|
+
next if lc.empty?
|
19
|
+
|
20
|
+
puts "In repository #{repo.name} the following commits were made:".yellow
|
21
|
+
|
22
|
+
longest_name = lc.map { |c| c[:author].size }.max
|
23
|
+
|
24
|
+
lc.each do |c|
|
25
|
+
puts "#{c[:commit]} #{c[:author].ljust(longest_name, ' ')} #{c[:subject]}"
|
26
|
+
end
|
27
|
+
puts
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def usage
|
32
|
+
'log [number_of_days]'
|
33
|
+
end
|
34
|
+
|
35
|
+
def description
|
36
|
+
'what happened since *n* days ago'
|
37
|
+
end
|
38
|
+
|
39
|
+
register_command :log
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def latest_commits(days)
|
44
|
+
`git log --pretty=format:"%h#%an#%s" --reverse --all --since=#{days}.days.ago --relative-date`.
|
45
|
+
split("\n").
|
46
|
+
map { |line| line.split('#') }.
|
47
|
+
map do |words|
|
48
|
+
{
|
49
|
+
:commit => words[0],
|
50
|
+
:author => words[1],
|
51
|
+
:subject => words[2..-1].join('#')
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/mgit/commands/remove.rb
CHANGED
@@ -6,8 +6,8 @@ module MGit
|
|
6
6
|
|
7
7
|
ptrn = args[0]
|
8
8
|
|
9
|
-
repo =
|
10
|
-
name == ptrn || path == File.expand_path(ptrn)
|
9
|
+
repo = Registry.find do |repo|
|
10
|
+
repo.name == ptrn || repo.path == File.expand_path(ptrn)
|
11
11
|
end
|
12
12
|
|
13
13
|
raise CommandUsageError.new("Couldn't find repository matching '#{ptrn}'.", self) unless repo
|
data/lib/mgit/commands/status.rb
CHANGED
@@ -5,10 +5,10 @@ module MGit
|
|
5
5
|
def execute(args)
|
6
6
|
raise TooManyArgumentsError.new(self) if args.size != 0
|
7
7
|
|
8
|
-
|
8
|
+
Registry.chdir_each do |repo|
|
9
9
|
nc = 36
|
10
|
-
display = (name.size > nc) ? (name[0..(nc - 3)] + '...') : name.ljust(nc, ' ')
|
11
|
-
puts "#{display} => [#{flags.to_a.join(', ')}]"
|
10
|
+
display = (repo.name.size > nc) ? (repo.name[0..(nc - 3)] + '...') : repo.name.ljust(nc, ' ')
|
11
|
+
puts "#{display} => [#{flags(repo).to_a.join(', ')}]"
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -25,25 +25,26 @@ module MGit
|
|
25
25
|
|
26
26
|
private
|
27
27
|
|
28
|
-
def flags
|
29
|
-
flags =
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
if(m = /## ([\w,\/]+)\.\.\.([\w,\/]+) \[(\w+) (\d+)\]/.match(s))
|
41
|
-
flags << "#{m[3].capitalize} of #{m[2]} by #{m[4]}".blue
|
42
|
-
end
|
28
|
+
def flags(repo)
|
29
|
+
flags = []
|
30
|
+
|
31
|
+
fs = repo.flags
|
32
|
+
flags << 'Index'.red if fs.include?(:index)
|
33
|
+
flags << 'Dirty'.red if fs.include?(:dirty)
|
34
|
+
flags << 'Untracked'.yellow if fs.include?(:untracked)
|
35
|
+
|
36
|
+
if fs.include?(:diverged)
|
37
|
+
ds = repo.divergence
|
38
|
+
ds.each do |d|
|
39
|
+
flags << "#{d.first[0].to_s.capitalize} of #{d.first[1][:branch]} by #{d.first[1][:by]}".blue
|
43
40
|
end
|
44
41
|
end
|
45
42
|
|
46
|
-
flags.empty?
|
43
|
+
if flags.empty?
|
44
|
+
flags << 'Clean'.green
|
45
|
+
end
|
46
|
+
|
47
|
+
flags
|
47
48
|
end
|
48
49
|
end
|
49
50
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module MGit
|
4
|
+
module Registry
|
5
|
+
def self.all
|
6
|
+
self.load.map { |name, path| Repository.new(name, path) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.each(&block)
|
10
|
+
self.all.each(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.chdir_each
|
14
|
+
self.all.each do |repo|
|
15
|
+
Dir.chdir(repo.path) do
|
16
|
+
yield repo
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.find(&block)
|
22
|
+
self.all.find(&block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.add(name, path)
|
26
|
+
repos = self.load
|
27
|
+
repos[name] = path
|
28
|
+
self.save! repos
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.remove(name)
|
32
|
+
repos = self.load
|
33
|
+
repos.delete name
|
34
|
+
self.save! repos
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def self.repofile
|
40
|
+
File.join(Dir.home, '.config/mgit.yml')
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.load
|
44
|
+
File.exists?(self.repofile) ? YAML.load_file(self.repofile) : {}
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.save!(repos)
|
48
|
+
File.open(self.repofile, 'w') { |fd| fd.write repos.to_yaml }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/mgit/repository.rb
CHANGED
@@ -1,47 +1,60 @@
|
|
1
|
-
require '
|
1
|
+
require 'set'
|
2
2
|
|
3
3
|
module MGit
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
4
|
+
class Repository
|
5
|
+
attr_reader :name, :path
|
6
|
+
|
7
|
+
def initialize(name, path)
|
8
|
+
@name = name
|
9
|
+
@path = path
|
10
|
+
end
|
11
|
+
|
12
|
+
def dirty?
|
13
|
+
[:index, :dirty, :untracked].any? { |f| flags.include?(f) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def flags
|
17
|
+
flags = Set.new
|
18
|
+
status_lines do |s|
|
19
|
+
case s.split[0]
|
20
|
+
when 'A'
|
21
|
+
flags << :index
|
22
|
+
when 'M'
|
23
|
+
flags << :dirty
|
24
|
+
when '??'
|
25
|
+
flags << :untracked
|
26
|
+
when '##'
|
27
|
+
flags << :diverged
|
17
28
|
end
|
18
29
|
end
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
30
|
+
flags
|
31
|
+
end
|
32
|
+
|
33
|
+
def divergence
|
34
|
+
divergence = []
|
35
|
+
status_lines do |s|
|
36
|
+
if s.split[0] == '##'
|
37
|
+
if(m = /## ([\w,\/]+)\.\.\.([\w,\/]+) \[(\w+) (\d+)\]/.match(s))
|
38
|
+
if m[3] =~ /behind/
|
39
|
+
divergence << { :behind => { :branch => m[2], :by => m[4] } }
|
40
|
+
else
|
41
|
+
divergence << { :ahead => { :branch => m[2], :by => m[4] } }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
divergence
|
35
47
|
end
|
36
48
|
|
37
49
|
private
|
38
|
-
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
50
|
+
|
51
|
+
def status_lines
|
52
|
+
Dir.chdir(path) do
|
53
|
+
status = `git status --short --branch --ignore-submodules`.split("\n")
|
54
|
+
status.each do |s|
|
55
|
+
yield s
|
56
|
+
end
|
57
|
+
end
|
45
58
|
end
|
46
59
|
end
|
47
60
|
end
|
data/lib/mgit/version.rb
CHANGED
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mgit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- FlavourSys Technology GmbH
|
@@ -14,7 +13,6 @@ dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: colorize
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ! '>='
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ! '>='
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: highline
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ! '>='
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ! '>='
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -59,36 +54,38 @@ files:
|
|
59
54
|
- lib/mgit/commands/foreach.rb
|
60
55
|
- lib/mgit/commands/remove.rb
|
61
56
|
- lib/mgit/commands/fetch.rb
|
57
|
+
- lib/mgit/commands/log.rb
|
62
58
|
- lib/mgit/commands/grep.rb
|
59
|
+
- lib/mgit/commands/ffmerge.rb
|
63
60
|
- lib/mgit/commands/version.rb
|
64
61
|
- lib/mgit/commands/status.rb
|
65
62
|
- lib/mgit/repository.rb
|
63
|
+
- lib/mgit/registry.rb
|
66
64
|
- lib/mgit/version.rb
|
67
65
|
- lib/mgit.rb
|
68
66
|
- bin/mgit
|
69
67
|
homepage: http://github.com/flavoursys/mgit
|
70
68
|
licenses:
|
71
69
|
- MIT
|
70
|
+
metadata: {}
|
72
71
|
post_install_message:
|
73
72
|
rdoc_options: []
|
74
73
|
require_paths:
|
75
74
|
- lib
|
76
75
|
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
-
none: false
|
78
76
|
requirements:
|
79
77
|
- - ! '>='
|
80
78
|
- !ruby/object:Gem::Version
|
81
79
|
version: '0'
|
82
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
-
none: false
|
84
81
|
requirements:
|
85
82
|
- - ! '>='
|
86
83
|
- !ruby/object:Gem::Version
|
87
84
|
version: '0'
|
88
85
|
requirements: []
|
89
86
|
rubyforge_project:
|
90
|
-
rubygems_version: 1.
|
87
|
+
rubygems_version: 2.1.10
|
91
88
|
signing_key:
|
92
|
-
specification_version:
|
89
|
+
specification_version: 4
|
93
90
|
summary: MGit meta repository tool
|
94
91
|
test_files: []
|