gitti 0.3.0 → 0.4.0
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 +4 -4
- data/Manifest.txt +2 -0
- data/README.md +32 -2
- data/Rakefile +2 -2
- data/lib/gitti.rb +4 -41
- data/lib/gitti/base.rb +57 -220
- data/lib/gitti/git.rb +290 -0
- data/lib/gitti/mirror.rb +33 -0
- data/lib/gitti/project.rb +9 -2
- data/lib/gitti/reposet.rb +12 -6
- data/lib/gitti/version.rb +9 -3
- data/test/test_base.rb +0 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef8765bec0642f4ee88c23169fffe92f8f0bba1a
|
4
|
+
data.tar.gz: a877ebe7e9bcff04915ed4fcc782dcf2c8000dc3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 683017b302f2becfaa0fb76c6f2dbfecd3e961ef534d8c8b784070a2df90fefc4df38c476d9601ef0d2e0167b2c613adbe781e918520ba15dc2e8e0b33e0ece7
|
7
|
+
data.tar.gz: 41320be67f3b4f4a3dd34bdac9a7ac4a94b21d47012f84be53cb8dee0170c9acc811927c910e985983f724a7d7826fbd36b04f457c31b25c47320733af7ce832
|
data/Manifest.txt
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# gitti
|
2
2
|
|
3
|
-
gitti gem - (yet) another (lite) git command line
|
3
|
+
gitti gem - (yet) another (lite) git command line helper / wrapper
|
4
4
|
|
5
5
|
* home :: [github.com/rubycoco/gitti](https://github.com/rubycoco/gitti)
|
6
6
|
* bugs :: [github.com/rubycoco/gitti/issues](https://github.com/rubycoco/gitti/issues)
|
@@ -11,7 +11,7 @@ gitti gem - (yet) another (lite) git command line wrapper / library
|
|
11
11
|
|
12
12
|
## Usage
|
13
13
|
|
14
|
-
`Git` • `GitProject`
|
14
|
+
`Git` • `GitProject` • `GitMirror`
|
15
15
|
|
16
16
|
|
17
17
|
### `Git` Class
|
@@ -58,6 +58,17 @@ Git.add_all ## same as git --all
|
|
58
58
|
Git.commit( "message" )
|
59
59
|
|
60
60
|
Git.files ## same as git ls-tree --full-tree --name-only -r HEAD
|
61
|
+
|
62
|
+
Git.check ## same as git fsck
|
63
|
+
Git.fsck ## alias for check
|
64
|
+
Git.checksum ## another alias for check
|
65
|
+
|
66
|
+
Git.origin ## same as git remote show origin
|
67
|
+
Git.upstream ## same as git remote show upstream
|
68
|
+
Git.origin?
|
69
|
+
Git.upstream?
|
70
|
+
|
71
|
+
|
61
72
|
Git.config( "user.name" ) ## use --get option
|
62
73
|
Git.config( "user.name", show_origin: true ) ## add --show-origin flag
|
63
74
|
Git.config( "user.name", show_scope: true ) ## add --show-scope flag
|
@@ -95,9 +106,28 @@ GitProject.open( "rubycoco/gitti" ) do |proj|
|
|
95
106
|
proj.commit( "message" )
|
96
107
|
|
97
108
|
proj.files
|
109
|
+
|
110
|
+
proj.origin
|
111
|
+
proj.upstream
|
112
|
+
proj.origin?
|
113
|
+
proj.upstream?
|
114
|
+
end
|
115
|
+
```
|
116
|
+
|
117
|
+
|
118
|
+
### `GitMirror` Class
|
119
|
+
|
120
|
+
Use the `GitMirror` class for existing mirrored (bare) git repo(sitories)
|
121
|
+
without workspace. Example:
|
122
|
+
|
123
|
+
``` ruby
|
124
|
+
GitMirror.open( "rubycoco/gitti.git" ) do |mirror|
|
125
|
+
mirror.update # sames as git remote update
|
98
126
|
end
|
99
127
|
```
|
100
128
|
|
129
|
+
|
130
|
+
|
101
131
|
That's it for now.
|
102
132
|
|
103
133
|
|
data/Rakefile
CHANGED
@@ -3,9 +3,9 @@ require './lib/gitti/version.rb'
|
|
3
3
|
|
4
4
|
Hoe.spec 'gitti' do
|
5
5
|
|
6
|
-
self.version =
|
6
|
+
self.version = GittiCore::VERSION
|
7
7
|
|
8
|
-
self.summary = 'gitti - (yet) another (lite) git command line
|
8
|
+
self.summary = 'gitti - (yet) another (lite) git command line helper / wrapper'
|
9
9
|
self.description = summary
|
10
10
|
|
11
11
|
self.urls = { home: 'https://github.com/rubycoco/gitti' }
|
data/lib/gitti.rb
CHANGED
@@ -1,44 +1,7 @@
|
|
1
|
-
|
2
|
-
require 'time'
|
3
|
-
require 'date' ## e.g. Date.today etc.
|
4
|
-
require 'yaml'
|
5
|
-
require 'json'
|
6
|
-
require 'uri'
|
7
|
-
require 'net/http'
|
8
|
-
require "net/https"
|
9
|
-
require 'open3'
|
10
|
-
require 'fileutils' ## e.g. FileUtils.mkdir_p etc.
|
1
|
+
require_relative 'gitti/base'
|
11
2
|
|
3
|
+
## note: auto include Gitti; for "modular" version use ("Sinatra-style")
|
4
|
+
## require "gitti/base"
|
12
5
|
|
6
|
+
include Gitti
|
13
7
|
|
14
|
-
# our own code
|
15
|
-
require 'gitti/version' # note: let version always go first
|
16
|
-
require 'gitti/base'
|
17
|
-
require 'gitti/project'
|
18
|
-
require 'gitti/reposet'
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
module Gitti
|
23
|
-
## todo: change to GitHubRepoRef or GitHubProject
|
24
|
-
## or Git::GitHub or Git::Source::GitHub or such - why? why not?
|
25
|
-
class GitHubRepo
|
26
|
-
attr_reader :owner, :name
|
27
|
-
|
28
|
-
def initialize( owner, name )
|
29
|
-
@owner = owner ## use/rename to login or something - why? why not??
|
30
|
-
@name = name # e.g. "rubylibs/webservice"
|
31
|
-
end
|
32
|
-
|
33
|
-
def ssh_clone_url
|
34
|
-
## check: use https: as default? for github - http:// still supported? or redirected?
|
35
|
-
## "http://github.com/#{@owner}/#{@name}"
|
36
|
-
"git@github.com:#{@owner}/#{@name}.git"
|
37
|
-
end
|
38
|
-
end ## class GitHubRepo
|
39
|
-
end ## module Gitti
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
# say hello
|
44
|
-
puts Gitti.banner ## if defined?( $RUBYCOCO_DEBUG )
|
data/lib/gitti/base.rb
CHANGED
@@ -1,220 +1,57 @@
|
|
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
|
-
class << self
|
59
|
-
alias_method :dirty?, :changes? ## add alias
|
60
|
-
end
|
61
|
-
|
62
|
-
|
63
|
-
#######
|
64
|
-
## more (major) git commands
|
65
|
-
|
66
|
-
def self.fetch
|
67
|
-
cmd = 'git fetch'
|
68
|
-
Shell.run( cmd )
|
69
|
-
end
|
70
|
-
|
71
|
-
def self.pull
|
72
|
-
cmd = 'git pull'
|
73
|
-
Shell.run( cmd )
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.fast_forward
|
77
|
-
cmd = 'git pull --ff-only'
|
78
|
-
Shell.run( cmd )
|
79
|
-
end
|
80
|
-
class << self
|
81
|
-
alias_method :ff, :fast_forward ## add alias
|
82
|
-
end
|
83
|
-
|
84
|
-
|
85
|
-
def self.push
|
86
|
-
cmd = 'git push'
|
87
|
-
Shell.run( cmd )
|
88
|
-
end
|
89
|
-
|
90
|
-
def self.add( pathspec=nil ) ## e.g. git add . or git add *.rb or such
|
91
|
-
cmd = 'git add'
|
92
|
-
cmd << " #{pathspec}" unless pathspec.nil? || pathspec.empty?
|
93
|
-
Shell.run( cmd )
|
94
|
-
end
|
95
|
-
|
96
|
-
def self.add_all
|
97
|
-
cmd = 'git add --all'
|
98
|
-
Shell.run( cmd )
|
99
|
-
end
|
100
|
-
|
101
|
-
def self.commit( message )
|
102
|
-
### todo/check: make message.nil? an ArgumentError - why? why not?
|
103
|
-
### if message.nil? || message.empty?
|
104
|
-
|
105
|
-
cmd = 'git commit'
|
106
|
-
cmd << %Q{ -m "#{message}"}
|
107
|
-
|
108
|
-
Shell.run( cmd )
|
109
|
-
end
|
110
|
-
|
111
|
-
|
112
|
-
#############
|
113
|
-
# change git ls-files to git ls-tree ... - why? why not?
|
114
|
-
## - note: git ls-files will include stages files too
|
115
|
-
# not only committed ones!!!
|
116
|
-
#
|
117
|
-
# git ls-tree --full-tree --name-only -r HEAD
|
118
|
-
# 1) --full-tree makes the command run as if you were in the repo's root directory.
|
119
|
-
# 2) -r recurses into subdirectories. Combined with --full-tree, this gives you all committed, tracked files.
|
120
|
-
# 3) --name-only removes SHA / permission info for when you just want the file paths.
|
121
|
-
# 4) HEAD specifies which branch you want the list of tracked, committed files for.
|
122
|
-
# You could change this to master or any other branch name, but HEAD is the commit you have checked out right now.
|
123
|
-
#
|
124
|
-
# see https://stackoverflow.com/questions/15606955/how-can-i-make-git-show-a-list-of-the-files-that-are-being-tracked
|
125
|
-
#
|
126
|
-
# was:
|
127
|
-
|
128
|
-
def self.files ## was: e.g. git ls-files . or git ls-files *.rb or such
|
129
|
-
### todo/check: include --full-tree - why? why not?
|
130
|
-
## will ALWAYS list all files NOT depending on (current) working directory
|
131
|
-
|
132
|
-
cmd = 'git ls-tree --full-tree --name-only -r HEAD' # was: 'git ls-files'
|
133
|
-
Shell.run( cmd )
|
134
|
-
end
|
135
|
-
## add list_files or ls_files alias - why? why not?
|
136
|
-
|
137
|
-
|
138
|
-
########
|
139
|
-
## query git configuration helpers
|
140
|
-
def self.config( prop,
|
141
|
-
show_origin: false,
|
142
|
-
show_scope: false ) ## find a better name e.g. config_get? why? why not?
|
143
|
-
cmd = "git config"
|
144
|
-
cmd << " --show-origin" if show_origin
|
145
|
-
cmd << " --show-scope" if show_scope
|
146
|
-
|
147
|
-
if prop.is_a?( Regexp )
|
148
|
-
## note: use Regexp#source
|
149
|
-
## Returns the original string of the pattern.
|
150
|
-
## e.g. /ab+c/ix.source #=> "ab+c"
|
151
|
-
## Note that escape sequences are retained as is.
|
152
|
-
## /\x20\+/.source #=> "\\x20\\+"
|
153
|
-
cmd << " --get-regexp #{prop.source}"
|
154
|
-
else ## assume string
|
155
|
-
cmd << " --get #{prop}"
|
156
|
-
end
|
157
|
-
|
158
|
-
Shell.run( cmd )
|
159
|
-
end
|
160
|
-
|
161
|
-
|
162
|
-
### add more - why? why not?
|
163
|
-
##
|
164
|
-
## def remote_update( opts={} ) ## e.g. git remote update
|
165
|
-
## command "remote update"
|
166
|
-
## end
|
167
|
-
|
168
|
-
## todo/check: rename remote to shorthand/shortcut or something or to branch - why, why not??
|
169
|
-
## def remote_show( name='origin', opts={}) ## e.g. git remote show origin
|
170
|
-
## command "remote show #{name}"
|
171
|
-
## end
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
###
|
178
|
-
# use nested class for "base" for running commands - why? why not?
|
179
|
-
class Shell
|
180
|
-
def self.run( cmd )
|
181
|
-
print "cmd exec >#{cmd}<..."
|
182
|
-
stdout, stderr, status = Open3.capture3( cmd )
|
183
|
-
|
184
|
-
if status.success?
|
185
|
-
print " OK"
|
186
|
-
print "\n"
|
187
|
-
else
|
188
|
-
print " FAIL (#{status.exitstatus})"
|
189
|
-
print "\n"
|
190
|
-
end
|
191
|
-
|
192
|
-
unless stdout.empty?
|
193
|
-
puts stdout
|
194
|
-
end
|
195
|
-
|
196
|
-
unless stderr.empty?
|
197
|
-
## todo/check: or use >2: or &2: or such
|
198
|
-
## stderr output not always an error (that is, exit status might be 0)
|
199
|
-
puts "STDERR:"
|
200
|
-
puts stderr
|
201
|
-
end
|
202
|
-
|
203
|
-
if status.success?
|
204
|
-
stdout # return stdout string
|
205
|
-
else
|
206
|
-
puts "!! ERROR: cmd exec >#{cmd}< failed with exit status #{status.exitstatus}:"
|
207
|
-
puts stderr
|
208
|
-
|
209
|
-
### todo/fix: do NOT use GitError here!!! make it more "general"
|
210
|
-
### use a Git::Shell.run() wrapper or such - why? why not?
|
211
|
-
## or use a Shell.git() or Shell.git_run() ???
|
212
|
-
## or pass in error class - why? why not?
|
213
|
-
raise GitError, "cmd exec >#{cmd}< failed with exit status #{status.exitstatus}<: #{stderr}"
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end # class Git::Shell
|
217
|
-
|
218
|
-
end # class Git
|
219
|
-
|
220
|
-
end # module Gitti
|
1
|
+
require 'pp'
|
2
|
+
require 'time'
|
3
|
+
require 'date' ## e.g. Date.today etc.
|
4
|
+
require 'yaml'
|
5
|
+
require 'json'
|
6
|
+
require 'uri'
|
7
|
+
require 'net/http'
|
8
|
+
require "net/https"
|
9
|
+
require 'open3'
|
10
|
+
require 'fileutils' ## e.g. FileUtils.mkdir_p etc.
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
# our own code
|
15
|
+
require 'gitti/version' # note: let version always go first
|
16
|
+
require 'gitti/git'
|
17
|
+
require 'gitti/project'
|
18
|
+
require 'gitti/mirror'
|
19
|
+
require 'gitti/reposet'
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
module Gitti
|
24
|
+
## todo: change to GitHubRepoRef or GitHubProject
|
25
|
+
## or Git::GitHub or Git::Source::GitHub or such - why? why not?
|
26
|
+
class GitHubRepo
|
27
|
+
attr_reader :owner, :name
|
28
|
+
|
29
|
+
def initialize( owner, name )
|
30
|
+
@owner = owner ## use/rename to login or something - why? why not??
|
31
|
+
@name = name # e.g. "rubylibs/webservice"
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def ssh_clone_url
|
36
|
+
## check: use https: as default? for github - http:// still supported? or redirected?
|
37
|
+
## "http://github.com/#{@owner}/#{@name}"
|
38
|
+
"git@github.com:#{@owner}/#{@name}.git"
|
39
|
+
end
|
40
|
+
|
41
|
+
def http_clone_url ## use clone_url( http: true ) -- why? why not?
|
42
|
+
## note: https is default for github - http:// gets redirected to https://
|
43
|
+
"http://github.com/#{@owner}/#{@name}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def https_clone_url
|
47
|
+
"https://github.com/#{@owner}/#{@name}"
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
end ## class GitHubRepo
|
52
|
+
end ## module Gitti
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
# say hello
|
57
|
+
puts GittiCore.banner ## if defined?( $RUBYCOCO_DEBUG )
|
data/lib/gitti/git.rb
ADDED
@@ -0,0 +1,290 @@
|
|
1
|
+
module Gitti
|
2
|
+
|
3
|
+
## raised by Git::Shell.run -- check if top-level ShellError alread exists?
|
4
|
+
## use ShellError or RunError - why? why not?
|
5
|
+
## and make Git::Shell top-level e.g. Shell - why? why not?
|
6
|
+
class GitError < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
class Git ## make Git a module - why? why not?
|
11
|
+
|
12
|
+
###
|
13
|
+
## todo/fix: change opts=nil to *args or such - why? why not?
|
14
|
+
|
15
|
+
|
16
|
+
###############
|
17
|
+
## "setup" starter git commands
|
18
|
+
|
19
|
+
def self.clone( repo, name=nil )
|
20
|
+
cmd = "git clone #{repo}"
|
21
|
+
cmd << " #{name}" unless name.nil? || name.empty?
|
22
|
+
Shell.run( cmd )
|
23
|
+
end
|
24
|
+
|
25
|
+
###
|
26
|
+
## What's the difference between git clone --mirror and git clone --bare
|
27
|
+
## see https://stackoverflow.com/questions/3959924/whats-the-difference-between-git-clone-mirror-and-git-clone-bare
|
28
|
+
##
|
29
|
+
## The git clone help page has this to say about --mirror:
|
30
|
+
## > Set up a mirror of the remote repository. This implies --bare
|
31
|
+
##
|
32
|
+
## The difference is that when using --mirror, all refs are copied as-is.
|
33
|
+
## This means everything: remote-tracking branches, notes, refs/originals/*
|
34
|
+
## (backups from filter-branch). The cloned repo has it all.
|
35
|
+
## It's also set up so that a remote update will re-fetch everything from the origin
|
36
|
+
## (overwriting the copied refs). The idea is really to mirror the repository,
|
37
|
+
## to have a total copy, so that you could for example host your central repo
|
38
|
+
## in multiple places, or back it up. Think of just straight-up copying the repo,
|
39
|
+
## except in a much more elegant git way.
|
40
|
+
##
|
41
|
+
## The new documentation pretty much says all this:
|
42
|
+
## see https://git-scm.com/docs/git-clone
|
43
|
+
##
|
44
|
+
## --mirror
|
45
|
+
## Set up a mirror of the source repository. This implies --bare.
|
46
|
+
## Compared to --bare, --mirror not only maps local branches of the source
|
47
|
+
## to local branches of the target, it maps all refs
|
48
|
+
## (including remote-tracking branches, notes etc.) and sets up a refspec configuration
|
49
|
+
## such that all these refs are overwritten by a git remote update
|
50
|
+
## in the target repository.
|
51
|
+
##
|
52
|
+
## More Articles / Resources:
|
53
|
+
## https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/duplicating-a-repository
|
54
|
+
|
55
|
+
|
56
|
+
## add -n (--no-checkout) -- needed - why? why not?
|
57
|
+
## add --no-hardlinks -- needed/recommended - why? why not?
|
58
|
+
|
59
|
+
def self.mirror( repo )
|
60
|
+
cmd = "git clone --mirror #{repo}"
|
61
|
+
Shell.run( cmd )
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
#################
|
66
|
+
## standard git commands
|
67
|
+
|
68
|
+
def self.version
|
69
|
+
cmd = 'git --version'
|
70
|
+
Shell.run( cmd )
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.status( short: false )
|
74
|
+
cmd = 'git status'
|
75
|
+
cmd << " --short" if short
|
76
|
+
Shell.run( cmd )
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.changes ## same as git status --short - keep shortcut / alias - why? why not?
|
80
|
+
## returns changed files - one per line or empty if no changes
|
81
|
+
cmd = 'git status --short'
|
82
|
+
Shell.run( cmd )
|
83
|
+
end
|
84
|
+
|
85
|
+
#####################
|
86
|
+
## status helpers
|
87
|
+
|
88
|
+
## git status --short returns empty stdout/list
|
89
|
+
def self.clean?() changes.empty?; end
|
90
|
+
|
91
|
+
def self.changes?() clean? == false; end ## reverse of clean?
|
92
|
+
class << self
|
93
|
+
alias_method :dirty?, :changes? ## add alias
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
#######
|
98
|
+
## more (major) git commands
|
99
|
+
|
100
|
+
def self.fetch
|
101
|
+
cmd = 'git fetch'
|
102
|
+
Shell.run( cmd )
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.pull
|
106
|
+
cmd = 'git pull'
|
107
|
+
Shell.run( cmd )
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.fast_forward
|
111
|
+
cmd = 'git pull --ff-only'
|
112
|
+
Shell.run( cmd )
|
113
|
+
end
|
114
|
+
class << self
|
115
|
+
alias_method :ff, :fast_forward ## add alias
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
def self.push
|
120
|
+
cmd = 'git push'
|
121
|
+
Shell.run( cmd )
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.add( *pathspecs ) ## e.g. git add . or git add *.rb or such
|
125
|
+
cmd = 'git add'
|
126
|
+
pathspecs = ['.'] if pathspecs.size == 0
|
127
|
+
cmd << " #{pathspecs.join('')}"
|
128
|
+
Shell.run( cmd )
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.add_all
|
132
|
+
cmd = 'git add --all'
|
133
|
+
Shell.run( cmd )
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.commit( message )
|
137
|
+
### todo/check: make message.nil? an ArgumentError - why? why not?
|
138
|
+
### if message.nil? || message.empty?
|
139
|
+
|
140
|
+
cmd = 'git commit'
|
141
|
+
cmd << %Q{ -m "#{message}"}
|
142
|
+
|
143
|
+
Shell.run( cmd )
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
#############
|
148
|
+
# change git ls-files to git ls-tree ... - why? why not?
|
149
|
+
## - note: git ls-files will include stages files too
|
150
|
+
# not only committed ones!!!
|
151
|
+
#
|
152
|
+
# git ls-tree --full-tree --name-only -r HEAD
|
153
|
+
# 1) --full-tree makes the command run as if you were in the repo's root directory.
|
154
|
+
# 2) -r recurses into subdirectories. Combined with --full-tree, this gives you all committed, tracked files.
|
155
|
+
# 3) --name-only removes SHA / permission info for when you just want the file paths.
|
156
|
+
# 4) HEAD specifies which branch you want the list of tracked, committed files for.
|
157
|
+
# You could change this to master or any other branch name, but HEAD is the commit you have checked out right now.
|
158
|
+
#
|
159
|
+
# see https://stackoverflow.com/questions/15606955/how-can-i-make-git-show-a-list-of-the-files-that-are-being-tracked
|
160
|
+
#
|
161
|
+
# was:
|
162
|
+
|
163
|
+
def self.files ## was: e.g. git ls-files . or git ls-files *.rb or such
|
164
|
+
### todo/check: include --full-tree - why? why not?
|
165
|
+
## will ALWAYS list all files NOT depending on (current) working directory
|
166
|
+
|
167
|
+
cmd = 'git ls-tree --full-tree --name-only -r HEAD' # was: 'git ls-files'
|
168
|
+
Shell.run( cmd )
|
169
|
+
end
|
170
|
+
## add list_files or ls_files alias - why? why not?
|
171
|
+
|
172
|
+
|
173
|
+
########
|
174
|
+
## query git configuration helpers
|
175
|
+
def self.config( prop,
|
176
|
+
show_origin: false,
|
177
|
+
show_scope: false ) ## find a better name e.g. config_get? why? why not?
|
178
|
+
cmd = "git config"
|
179
|
+
cmd << " --show-origin" if show_origin
|
180
|
+
cmd << " --show-scope" if show_scope
|
181
|
+
|
182
|
+
if prop.is_a?( Regexp )
|
183
|
+
## note: use Regexp#source
|
184
|
+
## Returns the original string of the pattern.
|
185
|
+
## e.g. /ab+c/ix.source #=> "ab+c"
|
186
|
+
## Note that escape sequences are retained as is.
|
187
|
+
## /\x20\+/.source #=> "\\x20\\+"
|
188
|
+
cmd << " --get-regexp #{prop.source}"
|
189
|
+
else ## assume string
|
190
|
+
cmd << " --get #{prop}"
|
191
|
+
end
|
192
|
+
|
193
|
+
Shell.run( cmd )
|
194
|
+
end
|
195
|
+
|
196
|
+
|
197
|
+
## git remote update will update all of your branches
|
198
|
+
## set to track remote ones, but not merge any changes in.
|
199
|
+
##
|
200
|
+
## git fetch --all didn't exist at one time, so git remote update what more useful.
|
201
|
+
## Now that --all has been added to git fetch, git remote update is not really necessary.
|
202
|
+
##
|
203
|
+
## Differences between git remote update and fetch?
|
204
|
+
## Is git remote update the equivalent of git fetch?
|
205
|
+
## see https://stackoverflow.com/questions/1856499/differences-between-git-remote-update-and-fetch/17512004#17512004
|
206
|
+
##
|
207
|
+
## git fetch learned --all and --multiple options,
|
208
|
+
## to run fetch from many repositories,
|
209
|
+
## and --prune option to remove remote tracking branches that went stale.
|
210
|
+
## These make git remote update and git remote prune less necessary
|
211
|
+
## (there is no plan to remove remote update nor remote prune, though).
|
212
|
+
def self.update
|
213
|
+
cmd = 'git remote update'
|
214
|
+
Shell.run( cmd )
|
215
|
+
end
|
216
|
+
|
217
|
+
def self.origin ## e.g. git remote show origin
|
218
|
+
cmd = "git remote show origin"
|
219
|
+
Shell.run( cmd )
|
220
|
+
end
|
221
|
+
|
222
|
+
def self.upstream ## e.g. git remote show origin
|
223
|
+
cmd = "git remote show upstream"
|
224
|
+
Shell.run( cmd )
|
225
|
+
end
|
226
|
+
|
227
|
+
def self.origin?
|
228
|
+
puts "todo/fix: check if remote origin is available/exists - how?"
|
229
|
+
end
|
230
|
+
|
231
|
+
def self.upstream?
|
232
|
+
puts "todo/fix: check if remote upstream is available/exists - how?"
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
def self.check ## e.g. git fsck - check/validate hash of objects
|
237
|
+
cmd = "git fsck"
|
238
|
+
Shell.run( cmd )
|
239
|
+
end
|
240
|
+
class << self
|
241
|
+
alias_method :fsck, :check ## add alias
|
242
|
+
alias_method :checksum, :check
|
243
|
+
end
|
244
|
+
|
245
|
+
|
246
|
+
|
247
|
+
###
|
248
|
+
# use nested class for "base" for running commands - why? why not?
|
249
|
+
class Shell
|
250
|
+
def self.run( cmd )
|
251
|
+
print "cmd exec >#{cmd}<..."
|
252
|
+
stdout, stderr, status = Open3.capture3( cmd )
|
253
|
+
|
254
|
+
if status.success?
|
255
|
+
print " OK"
|
256
|
+
print "\n"
|
257
|
+
else
|
258
|
+
print " FAIL (#{status.exitstatus})"
|
259
|
+
print "\n"
|
260
|
+
end
|
261
|
+
|
262
|
+
unless stdout.empty?
|
263
|
+
puts stdout
|
264
|
+
end
|
265
|
+
|
266
|
+
unless stderr.empty?
|
267
|
+
## todo/check: or use >2: or &2: or such
|
268
|
+
## stderr output not always an error (that is, exit status might be 0)
|
269
|
+
puts "STDERR:"
|
270
|
+
puts stderr
|
271
|
+
end
|
272
|
+
|
273
|
+
if status.success?
|
274
|
+
stdout # return stdout string
|
275
|
+
else
|
276
|
+
puts "!! ERROR: cmd exec >#{cmd}< failed with exit status #{status.exitstatus}:"
|
277
|
+
puts stderr
|
278
|
+
|
279
|
+
### todo/fix: do NOT use GitError here!!! make it more "general"
|
280
|
+
### use a Git::Shell.run() wrapper or such - why? why not?
|
281
|
+
## or use a Shell.git() or Shell.git_run() ???
|
282
|
+
## or pass in error class - why? why not?
|
283
|
+
raise GitError, "cmd exec >#{cmd}< failed with exit status #{status.exitstatus}<: #{stderr}"
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end # class Git::Shell
|
287
|
+
|
288
|
+
end # class Git
|
289
|
+
|
290
|
+
end # module Gitti
|
data/lib/gitti/mirror.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Gitti
|
2
|
+
|
3
|
+
class GitMirror
|
4
|
+
def self.open( path, &blk )
|
5
|
+
new( path ).open( &blk )
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.update( path ) ### all-in-one convenience shortcut
|
9
|
+
new( path).open { |mirror| mirror.update }
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
def initialize( path )
|
15
|
+
raise ArgumentError, "dir >#{path}< not found; dir MUST already exist for GitMirror class - sorry" unless Dir.exist?( path )
|
16
|
+
## todo/check: check for more dirs and files e.g.
|
17
|
+
## /info,/objects,/refs, /hooks, HEAD, config, description -- why? why not?
|
18
|
+
raise ArgumentError, "dir >#{path}/objects< not found; dir MUST already be initialized with git for GitMirror class - sorry" unless Dir.exist?( "#{path}/objects" )
|
19
|
+
@path = path
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def open( &blk )
|
24
|
+
Dir.chdir( @path ) do
|
25
|
+
blk.call( self )
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def update() Git.update; end
|
30
|
+
|
31
|
+
end # class GitMirror
|
32
|
+
end # module Gitti
|
33
|
+
|
data/lib/gitti/project.rb
CHANGED
@@ -35,14 +35,21 @@ class GitProject
|
|
35
35
|
|
36
36
|
def push() Git.push; end
|
37
37
|
|
38
|
-
def add(
|
38
|
+
def add( *pathspecs ) Git.add( *pathspecs ); end
|
39
39
|
def add_all() Git.add_all; end
|
40
40
|
def commit( message ) Git.commit( message ); end
|
41
41
|
|
42
42
|
def files() Git.files; end
|
43
43
|
|
44
|
-
def run( cmd ) Git::Shell.run( cmd ); end
|
45
44
|
|
45
|
+
### remote show origin|upstream|etc.
|
46
|
+
def origin() Git.origin; end
|
47
|
+
def upstream() Git.upstream; end
|
48
|
+
def origin?() Git.origin?; end
|
49
|
+
def upstream?() Git.upstream?; end
|
50
|
+
|
51
|
+
|
52
|
+
def run( cmd ) Git::Shell.run( cmd ); end
|
46
53
|
end # class GitProject
|
47
54
|
end # module Gitti
|
48
55
|
|
data/lib/gitti/reposet.rb
CHANGED
@@ -4,8 +4,9 @@ module Gitti
|
|
4
4
|
|
5
5
|
class GitRepoSet ## todo: rename to Hash/Dict/List/Map or use GitHubRepoSet ??
|
6
6
|
|
7
|
-
def self.
|
8
|
-
|
7
|
+
def self.read( path )
|
8
|
+
txt = File.open( path, 'r:utf-8') { |f| f.read }
|
9
|
+
hash = YAML.load( txt )
|
9
10
|
new( hash )
|
10
11
|
end
|
11
12
|
|
@@ -14,19 +15,24 @@ def initialize( hash )
|
|
14
15
|
@hash = hash
|
15
16
|
end
|
16
17
|
|
18
|
+
def size
|
19
|
+
## sum up total number of repos
|
20
|
+
@size ||= @hash.reduce(0) {|sum,(_,names)| sum+= names.size; sum }
|
21
|
+
end
|
22
|
+
|
17
23
|
def each
|
18
|
-
@hash.each do |
|
24
|
+
@hash.each do |org_with_counter,names|
|
19
25
|
|
20
26
|
## remove optional number from key e.g.
|
21
27
|
## mrhydescripts (3) => mrhydescripts
|
22
28
|
## footballjs (4) => footballjs
|
23
29
|
## etc.
|
24
30
|
|
25
|
-
|
31
|
+
org = org_with_counter.sub( /\([0-9]+\)/, '' ).strip
|
26
32
|
|
27
|
-
puts " -- #{key_with_counter} [#{key}] --"
|
33
|
+
## puts " -- #{key_with_counter} [#{key}] --"
|
28
34
|
|
29
|
-
yield(
|
35
|
+
yield( org, names )
|
30
36
|
end
|
31
37
|
end
|
32
38
|
|
data/lib/gitti/version.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
|
2
|
-
module
|
2
|
+
### note: use a different module for version (meta) info
|
3
|
+
### that is, GittiCore and NOT Gitti
|
4
|
+
### why? do NOT "pollute" Gitti with MAJOR, MINOR, PATH, and
|
5
|
+
### self.banner, self.root, etc.
|
6
|
+
|
7
|
+
|
8
|
+
module GittiCore ## todo/check: rename GittiBase or GittiMeta or such - why? why not?
|
3
9
|
MAJOR = 0 ## todo: namespace inside version or something - why? why not??
|
4
|
-
MINOR =
|
10
|
+
MINOR = 4
|
5
11
|
PATCH = 0
|
6
12
|
VERSION = [MAJOR,MINOR,PATCH].join('.')
|
7
13
|
|
@@ -16,5 +22,5 @@ module Gitti
|
|
16
22
|
def self.root
|
17
23
|
"#{File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )}"
|
18
24
|
end
|
19
|
-
end # module
|
25
|
+
end # module GittiCore
|
20
26
|
|
data/test/test_base.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gitti
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gerald Bauer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-09-
|
11
|
+
date: 2020-09-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rdoc
|
@@ -38,7 +38,7 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.16'
|
41
|
-
description: gitti - (yet) another (lite) git command line
|
41
|
+
description: gitti - (yet) another (lite) git command line helper / wrapper
|
42
42
|
email: ruby-talk@ruby-lang.org
|
43
43
|
executables: []
|
44
44
|
extensions: []
|
@@ -53,6 +53,8 @@ files:
|
|
53
53
|
- Rakefile
|
54
54
|
- lib/gitti.rb
|
55
55
|
- lib/gitti/base.rb
|
56
|
+
- lib/gitti/git.rb
|
57
|
+
- lib/gitti/mirror.rb
|
56
58
|
- lib/gitti/project.rb
|
57
59
|
- lib/gitti/reposet.rb
|
58
60
|
- lib/gitti/version.rb
|
@@ -83,5 +85,5 @@ rubyforge_project:
|
|
83
85
|
rubygems_version: 2.5.2
|
84
86
|
signing_key:
|
85
87
|
specification_version: 4
|
86
|
-
summary: gitti - (yet) another (lite) git command line
|
88
|
+
summary: gitti - (yet) another (lite) git command line helper / wrapper
|
87
89
|
test_files: []
|