git-multi 5.0.0 → 8.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.pryrc +3 -1
- data/.rubocop.yml +11 -0
- data/.ruby-version +1 -1
- data/Gemfile.lock +62 -32
- data/README.md +2 -0
- data/bin/console +3 -0
- data/exe/git-multi +5 -5
- data/git-multi.gemspec +13 -1
- data/lib/ext/string.rb +0 -2
- data/lib/git/hub.rb +22 -22
- data/lib/git/multi/commands.rb +1 -1
- data/lib/git/multi/config.rb +3 -4
- data/lib/git/multi/gemspec.rb +7 -0
- data/lib/git/multi/report.rb +13 -10
- data/lib/git/multi/version.rb +1 -1
- data/lib/git/multi.rb +29 -14
- data/man/git-multi.1 +59 -35
- data/man/git-multi.erb +13 -3
- data/man/git-multi.html +48 -37
- metadata +45 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c73ccad592eda6fef60d7911915d0bb1ca5f737ca2345fefda0df535b58a3a5b
|
4
|
+
data.tar.gz: 576070b973791f819e005dbac1d1df64f45bdcde6e998a2677f7212e046933c8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e8d0b3afb014f47cc25b31e5194b64d25393fa5554417f47ca73c52a1326e020365dbeb0be72becbdfb4b7b4eaad12c7119d703e6b6fa39761de89b29c7c589
|
7
|
+
data.tar.gz: fe03a9afbad48fc226683800286a0da9d9331b96b55c4896ee56c3da75b6c3ef6e52726917b3c60953046cec2619cc7a84ad90e43eadab9a0c79f9c7e925a930
|
data/.gitignore
CHANGED
data/.pryrc
CHANGED
@@ -4,11 +4,13 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'git/multi'
|
5
5
|
|
6
6
|
# this loads all 'git multi' contribs
|
7
|
+
# rubocop:disable Lint/NonDeterministicRequireOrder
|
7
8
|
Dir.glob File.join(__dir__, 'contrib', '**', '*.rb'), &method(:require)
|
9
|
+
# rubocop:enable Lint/NonDeterministicRequireOrder
|
8
10
|
|
9
11
|
# configure a logger
|
10
12
|
require 'logger'
|
11
|
-
logger = Logger.new(
|
13
|
+
logger = Logger.new($stdout)
|
12
14
|
logger.level = Logger::INFO
|
13
15
|
|
14
16
|
# configure Octokit middleware with logger
|
data/.rubocop.yml
CHANGED
@@ -6,6 +6,10 @@ AllCops:
|
|
6
6
|
- 'tmp/*'
|
7
7
|
- 'pkg/*'
|
8
8
|
|
9
|
+
require:
|
10
|
+
- rubocop-minitest
|
11
|
+
- rubocop-rake
|
12
|
+
|
9
13
|
Layout/LineLength:
|
10
14
|
Enabled: false
|
11
15
|
|
@@ -19,6 +23,9 @@ Metrics/MethodLength:
|
|
19
23
|
Metrics/ModuleLength:
|
20
24
|
Enabled: false
|
21
25
|
|
26
|
+
Rake/Desc:
|
27
|
+
Enabled: false
|
28
|
+
|
22
29
|
Style/BlockDelimiters:
|
23
30
|
Enabled: false
|
24
31
|
Style/Documentation:
|
@@ -38,3 +45,7 @@ Style/TrailingCommaInArrayLiteral:
|
|
38
45
|
Enabled: false
|
39
46
|
Style/TrailingCommaInHashLiteral:
|
40
47
|
Enabled: false
|
48
|
+
|
49
|
+
# https://github.com/rubocop/rubocop/issues/10394
|
50
|
+
Style/SwapValues:
|
51
|
+
Enabled: false
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.6.
|
1
|
+
2.6.10
|
data/Gemfile.lock
CHANGED
@@ -1,56 +1,84 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
git-multi (
|
4
|
+
git-multi (8.0.0)
|
5
5
|
faraday (~> 1)
|
6
6
|
octokit (~> 4)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
addressable (2.
|
11
|
+
addressable (2.8.0)
|
12
12
|
public_suffix (>= 2.0.2, < 5.0)
|
13
|
-
ast (2.4.
|
13
|
+
ast (2.4.2)
|
14
14
|
coderay (1.1.3)
|
15
|
-
faraday (1.0
|
16
|
-
|
15
|
+
faraday (1.10.0)
|
16
|
+
faraday-em_http (~> 1.0)
|
17
|
+
faraday-em_synchrony (~> 1.0)
|
18
|
+
faraday-excon (~> 1.1)
|
19
|
+
faraday-httpclient (~> 1.0)
|
20
|
+
faraday-multipart (~> 1.0)
|
21
|
+
faraday-net_http (~> 1.0)
|
22
|
+
faraday-net_http_persistent (~> 1.0)
|
23
|
+
faraday-patron (~> 1.0)
|
24
|
+
faraday-rack (~> 1.0)
|
25
|
+
faraday-retry (~> 1.0)
|
26
|
+
ruby2_keywords (>= 0.0.4)
|
27
|
+
faraday-em_http (1.0.0)
|
28
|
+
faraday-em_synchrony (1.0.0)
|
29
|
+
faraday-excon (1.1.0)
|
30
|
+
faraday-httpclient (1.0.1)
|
31
|
+
faraday-multipart (1.0.4)
|
32
|
+
multipart-post (~> 2)
|
33
|
+
faraday-net_http (1.0.1)
|
34
|
+
faraday-net_http_persistent (1.2.0)
|
35
|
+
faraday-patron (1.0.0)
|
36
|
+
faraday-rack (1.0.0)
|
37
|
+
faraday-retry (1.0.3)
|
17
38
|
interception (0.5)
|
39
|
+
json (2.6.2)
|
18
40
|
method_source (1.0.0)
|
19
|
-
minitest (5.
|
20
|
-
multipart-post (2.
|
21
|
-
octokit (4.
|
22
|
-
faraday (>=
|
23
|
-
sawyer (~> 0.
|
24
|
-
parallel (1.
|
25
|
-
parser (
|
41
|
+
minitest (5.16.2)
|
42
|
+
multipart-post (2.2.3)
|
43
|
+
octokit (4.25.1)
|
44
|
+
faraday (>= 1, < 3)
|
45
|
+
sawyer (~> 0.9)
|
46
|
+
parallel (1.22.1)
|
47
|
+
parser (3.1.2.0)
|
26
48
|
ast (~> 2.4.1)
|
27
|
-
pry (0.
|
49
|
+
pry (0.14.1)
|
28
50
|
coderay (~> 1.1)
|
29
51
|
method_source (~> 1.0)
|
30
|
-
pry-rescue (1.5.
|
52
|
+
pry-rescue (1.5.2)
|
31
53
|
interception (>= 0.5)
|
32
54
|
pry (>= 0.12.0)
|
33
|
-
public_suffix (4.0.
|
34
|
-
rainbow (3.
|
35
|
-
rake (13.0.
|
36
|
-
regexp_parser (
|
37
|
-
rexml (3.2.
|
38
|
-
rubocop (
|
55
|
+
public_suffix (4.0.7)
|
56
|
+
rainbow (3.1.1)
|
57
|
+
rake (13.0.6)
|
58
|
+
regexp_parser (2.5.0)
|
59
|
+
rexml (3.2.5)
|
60
|
+
rubocop (1.32.0)
|
61
|
+
json (~> 2.3)
|
39
62
|
parallel (~> 1.10)
|
40
|
-
parser (>=
|
63
|
+
parser (>= 3.1.0.0)
|
41
64
|
rainbow (>= 2.2.2, < 4.0)
|
42
|
-
regexp_parser (>= 1.
|
43
|
-
rexml
|
44
|
-
rubocop-ast (>=
|
65
|
+
regexp_parser (>= 1.8, < 3.0)
|
66
|
+
rexml (>= 3.2.5, < 4.0)
|
67
|
+
rubocop-ast (>= 1.19.1, < 2.0)
|
45
68
|
ruby-progressbar (~> 1.7)
|
46
|
-
unicode-display_width (>= 1.4.0, <
|
47
|
-
rubocop-ast (
|
48
|
-
parser (>=
|
49
|
-
|
50
|
-
|
69
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
70
|
+
rubocop-ast (1.19.1)
|
71
|
+
parser (>= 3.1.1.0)
|
72
|
+
rubocop-minitest (0.20.1)
|
73
|
+
rubocop (>= 0.90, < 2.0)
|
74
|
+
rubocop-rake (0.6.0)
|
75
|
+
rubocop (~> 1.0)
|
76
|
+
ruby-progressbar (1.11.0)
|
77
|
+
ruby2_keywords (0.0.5)
|
78
|
+
sawyer (0.9.2)
|
51
79
|
addressable (>= 2.3.5)
|
52
|
-
faraday (
|
53
|
-
unicode-display_width (
|
80
|
+
faraday (>= 0.17.3, < 3)
|
81
|
+
unicode-display_width (2.2.0)
|
54
82
|
|
55
83
|
PLATFORMS
|
56
84
|
ruby
|
@@ -63,6 +91,8 @@ DEPENDENCIES
|
|
63
91
|
pry-rescue
|
64
92
|
rake
|
65
93
|
rubocop
|
94
|
+
rubocop-minitest
|
95
|
+
rubocop-rake
|
66
96
|
|
67
97
|
BUNDLED WITH
|
68
|
-
2.
|
98
|
+
2.3.19
|
data/README.md
CHANGED
@@ -35,6 +35,8 @@ There are plenty of other utilities out there that do something similar, but typ
|
|
35
35
|
|
36
36
|
## Usage
|
37
37
|
|
38
|
+
Installing the gem installs the `git-multi` executable on your system's `${PATH}`, which means it can be run as a so-called [git subcommand](https://git.github.io/htmldocs/howto/new-command.html#:~:text=Runtime%20environment), as follows: `git multi`; a good starting point is:
|
39
|
+
|
38
40
|
$ git multi --help
|
39
41
|
|
40
42
|
## Known Issues
|
data/bin/console
CHANGED
data/exe/git-multi
CHANGED
@@ -6,11 +6,11 @@ require 'git/multi'
|
|
6
6
|
|
7
7
|
multi_repo = command = nil
|
8
8
|
|
9
|
-
if
|
10
|
-
# read list of repo full names from
|
11
|
-
multi_repo =
|
12
|
-
# reopen
|
13
|
-
|
9
|
+
if !$stdin.tty?
|
10
|
+
# read list of repo full names from $stdin (~pseudo multi-repo)
|
11
|
+
multi_repo = $stdin.readlines.map(&:strip).map(&:freeze).freeze
|
12
|
+
# reopen $stdin (to ensure all `Kernel.system` based cmds work)
|
13
|
+
$stdin.reopen('/dev/tty')
|
14
14
|
elsif (command = ARGV.shift)&.start_with?('++')
|
15
15
|
multi_repo = command.delete('++')
|
16
16
|
command = nil
|
data/git-multi.gemspec
CHANGED
@@ -14,7 +14,17 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.homepage = 'https://github.com/pvdb/git-multi'
|
15
15
|
spec.license = 'MIT'
|
16
16
|
|
17
|
-
spec.
|
17
|
+
spec.required_ruby_version = ['>= 2.6.0', '< 3.0.0']
|
18
|
+
|
19
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
20
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
21
|
+
spec.metadata['changelog_uri'] = File.join(spec.homepage, 'blob', 'master', 'README.md')
|
22
|
+
|
23
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
24
|
+
|
25
|
+
# Specify which files should be added to the gem when it is released.
|
26
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
27
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
18
28
|
`git ls-files -z`
|
19
29
|
.split("\x0")
|
20
30
|
.reject { |f| f.match(%r{^(test|spec|features)/}) }
|
@@ -34,4 +44,6 @@ Gem::Specification.new do |spec|
|
|
34
44
|
spec.add_development_dependency 'pry-rescue'
|
35
45
|
spec.add_development_dependency 'rake'
|
36
46
|
spec.add_development_dependency 'rubocop'
|
47
|
+
spec.add_development_dependency 'rubocop-minitest'
|
48
|
+
spec.add_development_dependency 'rubocop-rake'
|
37
49
|
end
|
data/lib/ext/string.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
class String
|
2
|
-
# rubocop:disable Layout/EmptyLineBetweenDefs
|
3
2
|
# rubocop:disable Style/SingleLineMethods
|
4
3
|
def colorize(color_code) "\e[#{color_code}m#{self}\e[0m"; end
|
5
4
|
|
@@ -12,5 +11,4 @@ class String
|
|
12
11
|
|
13
12
|
def undent() gsub(/^.{#{slice(/^ +/).length}}/, ''); end
|
14
13
|
# rubocop:enable Style/SingleLineMethods
|
15
|
-
# rubocop:enable Layout/EmptyLineBetweenDefs
|
16
14
|
end
|
data/lib/git/hub.rb
CHANGED
@@ -4,7 +4,7 @@ begin
|
|
4
4
|
require 'net/http/persistent'
|
5
5
|
if Octokit.middleware.adapter == Faraday::Adapter::NetHttp
|
6
6
|
adapter = Faraday::RackBuilder::Handler.new(Faraday::Adapter::NetHttpPersistent)
|
7
|
-
Octokit.middleware.instance_variable_set(
|
7
|
+
Octokit.middleware.instance_variable_set(:@adapter, adapter)
|
8
8
|
end
|
9
9
|
rescue LoadError
|
10
10
|
# NOOP - `Net::HTTP::Persistent` is optional, so
|
@@ -29,31 +29,31 @@ module Git
|
|
29
29
|
|
30
30
|
def connected?
|
31
31
|
@connected ||= begin
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
32
|
+
client.validate_credentials
|
33
|
+
true
|
34
|
+
rescue Faraday::ConnectionFailed
|
35
|
+
false
|
36
|
+
end
|
37
37
|
end
|
38
38
|
|
39
39
|
# FIXME: update login as part of `--refresh`
|
40
40
|
|
41
41
|
def login
|
42
42
|
@login ||= begin
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
43
|
+
client.user.login
|
44
|
+
rescue Octokit::Unauthorized, Faraday::ConnectionFailed
|
45
|
+
nil
|
46
|
+
end
|
47
47
|
end
|
48
48
|
|
49
49
|
# FIXME: update orgs as part of `--refresh`
|
50
50
|
|
51
51
|
def orgs
|
52
52
|
@orgs ||= begin
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
client.organizations.map(&:login)
|
54
|
+
rescue Octokit::Unauthorized, Faraday::ConnectionFailed
|
55
|
+
[]
|
56
|
+
end
|
57
57
|
end
|
58
58
|
|
59
59
|
# pick a (semi-)random repo from GitHub
|
@@ -76,10 +76,10 @@ module Git
|
|
76
76
|
|
77
77
|
@user_repositories = Hash.new { |repos, (user, type)|
|
78
78
|
repos[[user, type]] = begin
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
79
|
+
client
|
80
|
+
.repositories(user, type: type)
|
81
|
+
.sort_by { |repo| repo[:name].downcase }
|
82
|
+
end
|
83
83
|
}
|
84
84
|
|
85
85
|
def user_repositories(user, type = :owner)
|
@@ -93,10 +93,10 @@ module Git
|
|
93
93
|
|
94
94
|
@org_repositories = Hash.new { |repos, (org, type)|
|
95
95
|
repos[[org, type]] = begin
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
96
|
+
client
|
97
|
+
.org_repositories(org, type: type)
|
98
|
+
.sort_by { |repo| repo[:name].downcase }
|
99
|
+
end
|
100
100
|
}
|
101
101
|
|
102
102
|
def org_repositories(org, type = :owner)
|
data/lib/git/multi/commands.rb
CHANGED
data/lib/git/multi/config.rb
CHANGED
@@ -7,8 +7,8 @@ module Git
|
|
7
7
|
value.empty? && default ? default : value
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
list = `git config --get-all
|
10
|
+
def global_options(name)
|
11
|
+
list = `git config --global --get-all #{name}`
|
12
12
|
list.split($RS).map(&:strip).map(&:freeze)
|
13
13
|
end
|
14
14
|
|
@@ -22,8 +22,7 @@ module Git
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def env_var(name, default = nil)
|
25
|
-
|
26
|
-
(value.nil? || value.empty?) && default ? default : value
|
25
|
+
ENV.fetch(name, default)
|
27
26
|
end
|
28
27
|
end
|
29
28
|
end
|
data/lib/git/multi/gemspec.rb
CHANGED
@@ -16,6 +16,13 @@ module Git
|
|
16
16
|
|
17
17
|
\tgit config --global --add \033[1mgit.multi.workarea\033[0m <your_root_workarea>
|
18
18
|
|
19
|
+
You can specify a list of user or organization repositories to ignore:
|
20
|
+
|
21
|
+
\tgit config --global --add \033[1mgit.multi.exclude\033[0m <org_name>/<repo_name>
|
22
|
+
\tgit config --global --add \033[1mgit.multi.exclude\033[0m <user_name>/<repo_name>
|
23
|
+
|
24
|
+
(can be used multiple times to exclude multiple user or organization repositories)
|
25
|
+
|
19
26
|
Thanks for using \033[1mgit multi\033[0m ... the ultimate multi-repo utility for git!
|
20
27
|
|
21
28
|
PIM
|
data/lib/git/multi/report.rb
CHANGED
@@ -33,7 +33,10 @@ module Git
|
|
33
33
|
setting_status(["\tGitHub ", "#{github_count} repositories"])
|
34
34
|
setting_status(["\tcloned ", cloned_count, "(#{missing_count} missing)"])
|
35
35
|
Git::Multi.missing_repositories_for(owner).each do |missing|
|
36
|
-
setting_status(["\tmissing", missing.full_name], false, false)
|
36
|
+
setting_status(["\tmissing", missing.full_name], valid: false, optional: false)
|
37
|
+
end
|
38
|
+
Git::Multi.excluded_repositories_for(owner).each do |excluded|
|
39
|
+
setting_status(["\texcluded", excluded.full_name], valid: false, optional: false)
|
37
40
|
end
|
38
41
|
setting_status(["\tsubdirs", subdir_count, "(#{surplus_count} surplus)"])
|
39
42
|
end
|
@@ -42,14 +45,14 @@ module Git
|
|
42
45
|
github_count = Git::Multi.repositories_for(superproject).count
|
43
46
|
|
44
47
|
if github_count.zero?
|
45
|
-
setting_status([message, 'listed but not configured'], false, false)
|
48
|
+
setting_status([message, 'listed but not configured'], valid: false, optional: false)
|
46
49
|
else
|
47
|
-
setting_status([message], true)
|
50
|
+
setting_status([message], valid: true)
|
48
51
|
Git::Multi.repositories_for(superproject).each do |repo|
|
49
52
|
if File.directory? repo.local_path
|
50
|
-
setting_status(["\tcloned ", repo.full_name], true)
|
53
|
+
setting_status(["\tcloned ", repo.full_name], valid: true)
|
51
54
|
else
|
52
|
-
setting_status(["\tmissing", repo.full_name], false, false)
|
55
|
+
setting_status(["\tmissing", repo.full_name], valid: false, optional: false)
|
53
56
|
end
|
54
57
|
end
|
55
58
|
end
|
@@ -102,7 +105,7 @@ module Git
|
|
102
105
|
end
|
103
106
|
end
|
104
107
|
|
105
|
-
private_class_method def setting_status(messages, valid
|
108
|
+
private_class_method def setting_status(messages, valid: false, optional: true)
|
106
109
|
fields = messages.compact.join(' - ')
|
107
110
|
icon = valid ? TICK : optional ? ARROW : CROSS
|
108
111
|
puts "#{icon} #{fields}"
|
@@ -115,16 +118,16 @@ module Git
|
|
115
118
|
abbreviate(file),
|
116
119
|
File.file?(file) ? "#{File.size(file).commify} bytes" : nil,
|
117
120
|
],
|
118
|
-
file && !file.empty? && File.file?(file),
|
119
|
-
false
|
121
|
+
valid: file && !file.empty? && File.file?(file),
|
122
|
+
optional: false,
|
120
123
|
)
|
121
124
|
end
|
122
125
|
|
123
126
|
private_class_method def directory_status(messages, directory)
|
124
127
|
setting_status(
|
125
128
|
messages,
|
126
|
-
directory && !directory.empty? && File.directory?(directory),
|
127
|
-
false
|
129
|
+
valid: directory && !directory.empty? && File.directory?(directory),
|
130
|
+
optional: false,
|
128
131
|
)
|
129
132
|
end
|
130
133
|
end
|
data/lib/git/multi/version.rb
CHANGED
data/lib/git/multi.rb
CHANGED
@@ -36,9 +36,6 @@ module Git
|
|
36
36
|
TOKEN = global_option('github.token', DEFAULT_TOKEN)
|
37
37
|
|
38
38
|
GIT_MULTI_DIR = File.join(HOME, '.git', 'multi')
|
39
|
-
|
40
|
-
FileUtils.mkdir_p(GIT_MULTI_DIR) # ensure `~/.git/multi` directory exists
|
41
|
-
|
42
39
|
GITHUB_CACHE = File.join(GIT_MULTI_DIR, 'repositories.byte')
|
43
40
|
|
44
41
|
USERS = global_list('git.multi.users')
|
@@ -46,6 +43,7 @@ module Git
|
|
46
43
|
SUPERPROJECTS = global_list('git.multi.superprojects')
|
47
44
|
|
48
45
|
MULTI_REPOS = (USERS + ORGANIZATIONS + SUPERPROJECTS)
|
46
|
+
EXCLUDED_REPOS = global_options('git.multi.exclude')
|
49
47
|
|
50
48
|
MAN_PAGE = File.expand_path('../../man/git-multi.1', __dir__)
|
51
49
|
HTML_PAGE = File.expand_path('../../man/git-multi.html', __dir__)
|
@@ -129,6 +127,9 @@ module Git
|
|
129
127
|
#
|
130
128
|
|
131
129
|
def refresh_repositories
|
130
|
+
# ensure `~/.git/multi` directory exists
|
131
|
+
FileUtils.mkdir_p(GIT_MULTI_DIR)
|
132
|
+
|
132
133
|
File.open(GITHUB_CACHE, 'wb') do |file|
|
133
134
|
Marshal.dump(github_repositories, file)
|
134
135
|
end
|
@@ -148,15 +149,15 @@ module Git
|
|
148
149
|
else Dir.pwd
|
149
150
|
end
|
150
151
|
Dir.chdir(working_dir) do
|
151
|
-
if
|
152
|
-
|
152
|
+
if $stdout.tty? && $stderr.tty?
|
153
|
+
$stdout.puts "#{full_name.invert} (#{fractional_index})"
|
153
154
|
interactive.call(self)
|
154
|
-
elsif
|
155
|
-
errors = File.join(
|
155
|
+
elsif $stderr.tty? && captured
|
156
|
+
errors = File.join(Dir.tmpdir, "git-multi.#{$PID}")
|
156
157
|
captured.call(self, errors)
|
157
158
|
if File.exist?(errors) && !File.zero?(errors)
|
158
159
|
# rubocop:disable Style/StderrPuts
|
159
|
-
|
160
|
+
$stderr.puts "#{full_name.invert} (#{fractional_index})"
|
160
161
|
Kernel.system "cat #{errors} > /dev/tty ;"
|
161
162
|
# rubocop:enable Style/StderrPuts
|
162
163
|
end
|
@@ -194,8 +195,10 @@ module Git
|
|
194
195
|
repo.parent_dir = Pathname.new(File.join(WORKAREA, repo.owner.login))
|
195
196
|
repo.local_path = Pathname.new(File.join(WORKAREA, repo.full_name))
|
196
197
|
repo.fractional_index = "#{index + 1}/#{repos.count}"
|
198
|
+
# git multi will "hard ignore" all excluded repos
|
199
|
+
repo.excluded = EXCLUDED_REPOS.include?(repo.full_name)
|
197
200
|
# fix 'repo' => https://github.com/octokit/octokit.rb/issues/727
|
198
|
-
repo.compliant_ssh_url =
|
201
|
+
repo.compliant_ssh_url = "ssh://#{repo.ssh_url.split(':', 2).join('/')}"
|
199
202
|
# remove optional '.git' suffix from 'git@github.com:pvdb/git-multi.git'
|
200
203
|
repo.abbreviated_ssh_url = repo.ssh_url.chomp('.git')
|
201
204
|
# extend 'repo' with 'just do it' capabilities
|
@@ -213,7 +216,11 @@ module Git
|
|
213
216
|
# lists of repos for a given multi-repo
|
214
217
|
#
|
215
218
|
|
216
|
-
def
|
219
|
+
def full_names_for(superproject)
|
220
|
+
global_options("superproject.#{superproject}.repo")
|
221
|
+
end
|
222
|
+
|
223
|
+
def all_repositories_for(multi_repo = nil)
|
217
224
|
case (owner = superproject = full_names = multi_repo)
|
218
225
|
when nil
|
219
226
|
repositories # all of them
|
@@ -226,26 +233,34 @@ module Git
|
|
226
233
|
repository.owner.login == owner
|
227
234
|
}
|
228
235
|
when *SUPERPROJECTS
|
229
|
-
|
236
|
+
all_repositories_for(full_names_for(superproject))
|
230
237
|
else
|
231
238
|
raise ArgumentError, multi_repo
|
232
239
|
end
|
233
240
|
end
|
234
241
|
|
242
|
+
def repositories_for(multi_repo = nil)
|
243
|
+
all_repositories_for(multi_repo).delete_if(&:excluded)
|
244
|
+
end
|
245
|
+
|
235
246
|
#
|
236
247
|
# lists of repositories with a given state
|
237
248
|
#
|
238
249
|
|
239
250
|
def archived_repositories_for(multi_repo = nil)
|
240
|
-
|
251
|
+
all_repositories_for(multi_repo).find_all(&:archived)
|
241
252
|
end
|
242
253
|
|
243
254
|
def forked_repositories_for(multi_repo = nil)
|
244
|
-
|
255
|
+
all_repositories_for(multi_repo).find_all(&:fork)
|
245
256
|
end
|
246
257
|
|
247
258
|
def private_repositories_for(multi_repo = nil)
|
248
|
-
|
259
|
+
all_repositories_for(multi_repo).find_all(&:private)
|
260
|
+
end
|
261
|
+
|
262
|
+
def excluded_repositories_for(multi_repo = nil)
|
263
|
+
all_repositories_for(multi_repo).find_all(&:excluded)
|
249
264
|
end
|
250
265
|
|
251
266
|
#
|
data/man/git-multi.1
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
.\" Title: git-multi
|
3
3
|
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
|
4
4
|
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
|
5
|
-
.\" Date:
|
5
|
+
.\" Date: 07/30/2022
|
6
6
|
.\" Manual: Git Manual
|
7
|
-
.\" Source: Git 2.
|
7
|
+
.\" Source: Git 2.35.1.455.g1a4874565f.dirty
|
8
8
|
.\" Language: English
|
9
9
|
.\"
|
10
|
-
.TH "GIT\-MULTI" "1" "
|
10
|
+
.TH "GIT\-MULTI" "1" "07/30/2022" "Git 2\&.35\&.1\&.455\&.g1a4874" "Git Manual"
|
11
11
|
.\" -----------------------------------------------------------------
|
12
12
|
.\" * Define some portability stuff
|
13
13
|
.\" -----------------------------------------------------------------
|
@@ -31,7 +31,7 @@
|
|
31
31
|
git-multi \- execute the same git command in multiple repositories
|
32
32
|
.SH "VERSION"
|
33
33
|
.sp
|
34
|
-
This is \
|
34
|
+
This is \fBv8\&.0\&.0\fR of \fIgit multi\fR \&... hooray!
|
35
35
|
.SH "SYNOPSIS"
|
36
36
|
.sp
|
37
37
|
There are some options for \fBgit multi\fR itself, in which case it is invoked as follows:
|
@@ -490,32 +490,34 @@ The following is a list of valid arguments for the \fBgit multi \-\-query\fR opt
|
|
490
490
|
.RS 4
|
491
491
|
.\}
|
492
492
|
.nf
|
493
|
-
archive_url archived
|
494
|
-
blobs_url branches_url
|
495
|
-
collaborators_url comments_url
|
496
|
-
compare_url contents_url
|
497
|
-
created_at default_branch
|
498
|
-
description disabled
|
499
|
-
events_url fork
|
500
|
-
forks_count forks_url
|
501
|
-
git_commits_url git_refs_url
|
502
|
-
git_url has_downloads
|
503
|
-
has_pages has_projects
|
504
|
-
homepage hooks_url
|
505
|
-
id
|
506
|
-
issues_url
|
507
|
-
language
|
508
|
-
merges_url
|
509
|
-
name
|
510
|
-
notifications_url
|
511
|
-
organization
|
512
|
-
private
|
513
|
-
releases_url
|
514
|
-
stargazers_count
|
515
|
-
subscribers_count
|
516
|
-
svn_url
|
517
|
-
temp_clone_token
|
518
|
-
|
493
|
+
allow_forking archive_url archived
|
494
|
+
assignees_url blobs_url branches_url
|
495
|
+
clone_url collaborators_url comments_url
|
496
|
+
commits_url compare_url contents_url
|
497
|
+
contributors_url created_at default_branch
|
498
|
+
deployments_url description disabled
|
499
|
+
downloads_url events_url fork
|
500
|
+
forks forks_count forks_url
|
501
|
+
full_name git_commits_url git_refs_url
|
502
|
+
git_tags_url git_url has_downloads
|
503
|
+
has_issues has_pages has_projects
|
504
|
+
has_wiki homepage hooks_url
|
505
|
+
html_url id is_template
|
506
|
+
issue_comment_url issue_events_url issues_url
|
507
|
+
keys_url labels_url language
|
508
|
+
languages_url license merges_url
|
509
|
+
milestones_url mirror_url name
|
510
|
+
network_count node_id notifications_url
|
511
|
+
open_issues open_issues_count organization
|
512
|
+
owner permissions private
|
513
|
+
pulls_url pushed_at releases_url
|
514
|
+
size ssh_url stargazers_count
|
515
|
+
stargazers_url statuses_url subscribers_count
|
516
|
+
subscribers_url subscription_url svn_url
|
517
|
+
tags_url teams_url temp_clone_token
|
518
|
+
topics trees_url updated_at
|
519
|
+
url visibility watchers
|
520
|
+
watchers_count web_commit_signoff_required
|
519
521
|
.fi
|
520
522
|
.if n \{\
|
521
523
|
.RE
|
@@ -545,6 +547,33 @@ git multi \-\-json | jq \-r \*(Aq\&.[] | select(\&.fork == true) | \&.full_name\
|
|
545
547
|
.if n \{\
|
546
548
|
.RE
|
547
549
|
.\}
|
550
|
+
.SH "CHAINED INVOCATION"
|
551
|
+
.sp
|
552
|
+
When \fBgit multi\fR gets its input from a Unix pipeline \fI(as opposed to from a TTY)\fR, it constructs an "implicit" multi repo comprised of the "full" repo names it reads from \fBSTDIN\fR \fI(one full repo name per line)\fR\&.
|
553
|
+
.sp
|
554
|
+
This allows multiple \fBgit multi\fR invocations to be chained, for example by using the \fB\-\-json\fR or \fB\-\-find\fR options as follows:
|
555
|
+
.sp
|
556
|
+
.if n \{\
|
557
|
+
.RS 4
|
558
|
+
.\}
|
559
|
+
.nf
|
560
|
+
# run a git query or subcommand on repos that aren\*(Aqt archived (on GitHub)
|
561
|
+
git multi ++<multi_repo> \-\-json | jq \-r \*(Aq\&.[] | select(\&."archived" == false) | \&."full_name"\*(Aq | git multi <git_command>
|
562
|
+
.fi
|
563
|
+
.if n \{\
|
564
|
+
.RE
|
565
|
+
.\}
|
566
|
+
.sp
|
567
|
+
.if n \{\
|
568
|
+
.RS 4
|
569
|
+
.\}
|
570
|
+
.nf
|
571
|
+
# run a shell command inside repos that have Ruby as their main language
|
572
|
+
git multi ++<multi_repo> \-\-find \*(Aqlanguage == "Ruby"\*(Aq | git multi \-\-raw \*(Aqcat \&.ruby\-version\*(Aq
|
573
|
+
.fi
|
574
|
+
.if n \{\
|
575
|
+
.RE
|
576
|
+
.\}
|
548
577
|
.SH "FILES"
|
549
578
|
.PP
|
550
579
|
\fB${HOME}/Workarea\fR
|
@@ -556,11 +585,6 @@ root directory where repos will been cloned
|
|
556
585
|
.RS 4
|
557
586
|
local, binary cache of GitHub repository metadata
|
558
587
|
.RE
|
559
|
-
.PP
|
560
|
-
\fB${HOME}/\&.git/multi/superprojects\&.config\fR
|
561
|
-
.RS 4
|
562
|
-
definitions for so\-called "superproject" multi\-repos
|
563
|
-
.RE
|
564
588
|
.SH "REFERENCES"
|
565
589
|
.sp
|
566
590
|
.RS 4
|
data/man/git-multi.erb
CHANGED
@@ -246,6 +246,19 @@ are some examples:
|
|
246
246
|
# print out the name of all "forked" repositories
|
247
247
|
git multi --json | jq -r '.[] | select(.fork == true) | .full_name'
|
248
248
|
|
249
|
+
CHAINED INVOCATION
|
250
|
+
------------------
|
251
|
+
|
252
|
+
When `git multi` gets its input from a Unix pipeline _(as opposed to from a TTY)_, it constructs an "implicit" multi repo comprised of the "full" repo names it reads from `STDIN` _(one full repo name per line)_.
|
253
|
+
|
254
|
+
This allows multiple `git multi` invocations to be chained, for example by using the `--json` or `--find` options as follows:
|
255
|
+
|
256
|
+
# run a git query or subcommand on repos that aren't archived (on GitHub)
|
257
|
+
git multi ++<multi_repo> --json | jq -r '.[] | select(."archived" == false) | ."full_name"' | git multi <git_command>
|
258
|
+
|
259
|
+
# run a shell command inside repos that have Ruby as their main language
|
260
|
+
git multi ++<multi_repo> --find 'language == "Ruby"' | git multi --raw 'cat .ruby-version'
|
261
|
+
|
249
262
|
FILES
|
250
263
|
-----
|
251
264
|
|
@@ -255,9 +268,6 @@ FILES
|
|
255
268
|
`${HOME}/.git/multi/repositories.byte`::
|
256
269
|
local, binary cache of GitHub repository metadata
|
257
270
|
|
258
|
-
`${HOME}/.git/multi/superprojects.config`::
|
259
|
-
definitions for so-called "superproject" multi-repos
|
260
|
-
|
261
271
|
REFERENCES
|
262
272
|
----------
|
263
273
|
|
data/man/git-multi.html
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
5
5
|
<head>
|
6
6
|
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
|
7
|
-
<meta name="generator" content="AsciiDoc
|
7
|
+
<meta name="generator" content="AsciiDoc 10.2.0" />
|
8
8
|
<title>git-multi(1)</title>
|
9
9
|
<style type="text/css">
|
10
10
|
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
|
@@ -748,7 +748,7 @@ git-multi(1) Manual Page
|
|
748
748
|
<div class="sect1">
|
749
749
|
<h2 id="_version">VERSION</h2>
|
750
750
|
<div class="sectionbody">
|
751
|
-
<div class="paragraph"><p>This is <code>
|
751
|
+
<div class="paragraph"><p>This is <code>v8.0.0</code> of <em>git multi</em> … hooray!</p></div>
|
752
752
|
</div>
|
753
753
|
</div>
|
754
754
|
<div class="sect1">
|
@@ -1113,32 +1113,34 @@ and cached locally <em>(in binary format)</em> for performance and offline usage
|
|
1113
1113
|
<div class="paragraph"><p>The following is a list of valid arguments for the <code>git multi --query</code> option:</p></div>
|
1114
1114
|
<div class="literalblock">
|
1115
1115
|
<div class="content">
|
1116
|
-
<pre><code>archive_url archived
|
1117
|
-
blobs_url branches_url
|
1118
|
-
collaborators_url comments_url
|
1119
|
-
compare_url contents_url
|
1120
|
-
created_at default_branch
|
1121
|
-
description disabled
|
1122
|
-
events_url fork
|
1123
|
-
forks_count forks_url
|
1124
|
-
git_commits_url git_refs_url
|
1125
|
-
git_url has_downloads
|
1126
|
-
has_pages has_projects
|
1127
|
-
homepage hooks_url
|
1128
|
-
id
|
1129
|
-
issues_url
|
1130
|
-
language
|
1131
|
-
merges_url
|
1132
|
-
name
|
1133
|
-
notifications_url
|
1134
|
-
organization
|
1135
|
-
private
|
1136
|
-
releases_url
|
1137
|
-
stargazers_count
|
1138
|
-
subscribers_count
|
1139
|
-
svn_url
|
1140
|
-
temp_clone_token
|
1141
|
-
|
1116
|
+
<pre><code>allow_forking archive_url archived
|
1117
|
+
assignees_url blobs_url branches_url
|
1118
|
+
clone_url collaborators_url comments_url
|
1119
|
+
commits_url compare_url contents_url
|
1120
|
+
contributors_url created_at default_branch
|
1121
|
+
deployments_url description disabled
|
1122
|
+
downloads_url events_url fork
|
1123
|
+
forks forks_count forks_url
|
1124
|
+
full_name git_commits_url git_refs_url
|
1125
|
+
git_tags_url git_url has_downloads
|
1126
|
+
has_issues has_pages has_projects
|
1127
|
+
has_wiki homepage hooks_url
|
1128
|
+
html_url id is_template
|
1129
|
+
issue_comment_url issue_events_url issues_url
|
1130
|
+
keys_url labels_url language
|
1131
|
+
languages_url license merges_url
|
1132
|
+
milestones_url mirror_url name
|
1133
|
+
network_count node_id notifications_url
|
1134
|
+
open_issues open_issues_count organization
|
1135
|
+
owner permissions private
|
1136
|
+
pulls_url pushed_at releases_url
|
1137
|
+
size ssh_url stargazers_count
|
1138
|
+
stargazers_url statuses_url subscribers_count
|
1139
|
+
subscribers_url subscription_url svn_url
|
1140
|
+
tags_url teams_url temp_clone_token
|
1141
|
+
topics trees_url updated_at
|
1142
|
+
url visibility watchers
|
1143
|
+
watchers_count web_commit_signoff_required</code></pre>
|
1142
1144
|
</div></div>
|
1143
1145
|
</div>
|
1144
1146
|
</div>
|
@@ -1162,6 +1164,23 @@ git multi --json | jq -r '.[] | select(.fork == true) | .full_name'</code></pre>
|
|
1162
1164
|
</div>
|
1163
1165
|
</div>
|
1164
1166
|
<div class="sect1">
|
1167
|
+
<h2 id="_chained_invocation">CHAINED INVOCATION</h2>
|
1168
|
+
<div class="sectionbody">
|
1169
|
+
<div class="paragraph"><p>When <code>git multi</code> gets its input from a Unix pipeline <em>(as opposed to from a TTY)</em>, it constructs an "implicit" multi repo comprised of the "full" repo names it reads from <code>STDIN</code> <em>(one full repo name per line)</em>.</p></div>
|
1170
|
+
<div class="paragraph"><p>This allows multiple <code>git multi</code> invocations to be chained, for example by using the <code>--json</code> or <code>--find</code> options as follows:</p></div>
|
1171
|
+
<div class="literalblock">
|
1172
|
+
<div class="content">
|
1173
|
+
<pre><code># run a git query or subcommand on repos that aren't archived (on GitHub)
|
1174
|
+
git multi ++<multi_repo> --json | jq -r '.[] | select(."archived" == false) | ."full_name"' | git multi <git_command></code></pre>
|
1175
|
+
</div></div>
|
1176
|
+
<div class="literalblock">
|
1177
|
+
<div class="content">
|
1178
|
+
<pre><code># run a shell command inside repos that have Ruby as their main language
|
1179
|
+
git multi ++<multi_repo> --find 'language == "Ruby"' | git multi --raw 'cat .ruby-version'</code></pre>
|
1180
|
+
</div></div>
|
1181
|
+
</div>
|
1182
|
+
</div>
|
1183
|
+
<div class="sect1">
|
1165
1184
|
<h2 id="_files">FILES</h2>
|
1166
1185
|
<div class="sectionbody">
|
1167
1186
|
<div class="dlist"><dl>
|
@@ -1181,14 +1200,6 @@ git multi --json | jq -r '.[] | select(.fork == true) | .full_name'</code></pre>
|
|
1181
1200
|
local, binary cache of GitHub repository metadata
|
1182
1201
|
</p>
|
1183
1202
|
</dd>
|
1184
|
-
<dt class="hdlist1">
|
1185
|
-
<code>${HOME}/.git/multi/superprojects.config</code>
|
1186
|
-
</dt>
|
1187
|
-
<dd>
|
1188
|
-
<p>
|
1189
|
-
definitions for so-called "superproject" multi-repos
|
1190
|
-
</p>
|
1191
|
-
</dd>
|
1192
1203
|
</dl></div>
|
1193
1204
|
</div>
|
1194
1205
|
</div>
|
@@ -1222,7 +1233,7 @@ the <code>jq</code> command-line utility:
|
|
1222
1233
|
<div id="footer">
|
1223
1234
|
<div id="footer-text">
|
1224
1235
|
Last updated
|
1225
|
-
|
1236
|
+
2022-07-30 10:20:13 BST
|
1226
1237
|
</div>
|
1227
1238
|
</div>
|
1228
1239
|
</body>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git-multi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 8.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Vandenberk
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-07-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -122,6 +122,34 @@ dependencies:
|
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop-minitest
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rubocop-rake
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
125
153
|
description: Run the same git command in a set of related repos
|
126
154
|
email:
|
127
155
|
- pvandenberk@mac.com
|
@@ -165,14 +193,22 @@ files:
|
|
165
193
|
homepage: https://github.com/pvdb/git-multi
|
166
194
|
licenses:
|
167
195
|
- MIT
|
168
|
-
metadata:
|
196
|
+
metadata:
|
197
|
+
homepage_uri: https://github.com/pvdb/git-multi
|
198
|
+
source_code_uri: https://github.com/pvdb/git-multi
|
199
|
+
changelog_uri: https://github.com/pvdb/git-multi/blob/master/README.md
|
200
|
+
rubygems_mfa_required: 'true'
|
169
201
|
post_install_message: "\nThe only required setting for \e[1mgit multi\e[0m is:\n\n\tgit
|
170
202
|
config --global --add \e[1mgithub.token\e[0m <your_github_oauth_token>\n\nThe following
|
171
203
|
settings for \e[1mgit multi\e[0m are\noptional, and take 0, 1 or more values:\n\n\tgit
|
172
204
|
config --global --add \e[1mgit.multi.users\e[0m <list_of_github_users>\n\tgit config
|
173
205
|
--global --add \e[1mgit.multi.organizations\e[0m <list_of_github_orgs>\n\nUnless
|
174
206
|
your top-level workarea is `${HOME}/Workarea` you should also set:\n\n\tgit config
|
175
|
-
--global --add \e[1mgit.multi.workarea\e[0m <your_root_workarea>\n\
|
207
|
+
--global --add \e[1mgit.multi.workarea\e[0m <your_root_workarea>\n\nYou can specify
|
208
|
+
a list of user or organization repositories to ignore:\n\n\tgit config --global
|
209
|
+
--add \e[1mgit.multi.exclude\e[0m <org_name>/<repo_name>\n\tgit config --global
|
210
|
+
--add \e[1mgit.multi.exclude\e[0m <user_name>/<repo_name>\n\n(can be used multiple
|
211
|
+
times to exclude multiple user or organization repositories)\n\nThanks for using
|
176
212
|
\e[1mgit multi\e[0m ... the ultimate multi-repo utility for git!\n\n"
|
177
213
|
rdoc_options: []
|
178
214
|
require_paths:
|
@@ -181,14 +217,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
181
217
|
requirements:
|
182
218
|
- - ">="
|
183
219
|
- !ruby/object:Gem::Version
|
184
|
-
version:
|
220
|
+
version: 2.6.0
|
221
|
+
- - "<"
|
222
|
+
- !ruby/object:Gem::Version
|
223
|
+
version: 3.0.0
|
185
224
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
225
|
requirements:
|
187
226
|
- - ">="
|
188
227
|
- !ruby/object:Gem::Version
|
189
228
|
version: '0'
|
190
229
|
requirements: []
|
191
|
-
rubygems_version: 3.0.3
|
230
|
+
rubygems_version: 3.0.3.1
|
192
231
|
signing_key:
|
193
232
|
specification_version: 4
|
194
233
|
summary: The ultimate multi-repo utility for git!
|