p-mongo-git 1.8.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 +7 -0
- data/.github/stale.yml +25 -0
- data/.github/workflows/continuous_integration.yml +45 -0
- data/.gitignore +10 -0
- data/.yardopts +11 -0
- data/CHANGELOG.md +119 -0
- data/CONTRIBUTING.md +151 -0
- data/Gemfile +4 -0
- data/ISSUE_TEMPLATE.md +15 -0
- data/LICENSE +21 -0
- data/MAINTAINERS.md +14 -0
- data/PULL_REQUEST_TEMPLATE.md +9 -0
- data/README.md +344 -0
- data/RELEASING.md +62 -0
- data/Rakefile +56 -0
- data/git.gemspec +46 -0
- data/lib/git.rb +306 -0
- data/lib/git/author.rb +14 -0
- data/lib/git/base.rb +599 -0
- data/lib/git/base/factory.rb +101 -0
- data/lib/git/branch.rb +126 -0
- data/lib/git/branches.rb +71 -0
- data/lib/git/config.rb +22 -0
- data/lib/git/diff.rb +156 -0
- data/lib/git/index.rb +5 -0
- data/lib/git/lib.rb +1222 -0
- data/lib/git/log.rb +135 -0
- data/lib/git/object.rb +312 -0
- data/lib/git/path.rb +31 -0
- data/lib/git/remote.rb +36 -0
- data/lib/git/repository.rb +6 -0
- data/lib/git/stash.rb +27 -0
- data/lib/git/stashes.rb +55 -0
- data/lib/git/status.rb +199 -0
- data/lib/git/version.rb +5 -0
- data/lib/git/working_directory.rb +4 -0
- data/lib/git/worktree.rb +38 -0
- data/lib/git/worktrees.rb +47 -0
- metadata +186 -0
@@ -0,0 +1,101 @@
|
|
1
|
+
module Git
|
2
|
+
|
3
|
+
class Base
|
4
|
+
|
5
|
+
module Factory
|
6
|
+
|
7
|
+
# @return [Git::Branch] an object for branch_name
|
8
|
+
def branch(branch_name = 'master')
|
9
|
+
Git::Branch.new(self, branch_name)
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [Git::Branches] a collection of all the branches in the repository.
|
13
|
+
# Each branch is represented as a {Git::Branch}.
|
14
|
+
def branches
|
15
|
+
Git::Branches.new(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
# returns a Git::Worktree object for dir, commitish
|
19
|
+
def worktree(dir, commitish = nil)
|
20
|
+
Git::Worktree.new(self, dir, commitish)
|
21
|
+
end
|
22
|
+
|
23
|
+
# returns a Git::worktrees object of all the Git::Worktrees
|
24
|
+
# objects for this repo
|
25
|
+
def worktrees
|
26
|
+
Git::Worktrees.new(self)
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Git::Object::Commit] a commit object
|
30
|
+
def commit_tree(tree = nil, opts = {})
|
31
|
+
Git::Object::Commit.new(self, self.lib.commit_tree(tree, opts))
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Git::Diff] a Git::Diff object
|
35
|
+
def diff(objectish = 'HEAD', obj2 = nil, **opts)
|
36
|
+
Git::Diff.new(self, objectish, obj2, **opts)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Git::Object] a Git object
|
40
|
+
def gblob(objectish)
|
41
|
+
Git::Object.new(self, objectish, 'blob')
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Git::Object] a Git object
|
45
|
+
def gcommit(objectish)
|
46
|
+
Git::Object.new(self, objectish, 'commit')
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Git::Object] a Git object
|
50
|
+
def gtree(objectish)
|
51
|
+
Git::Object.new(self, objectish, 'tree')
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [Git::Log] a log with the specified number of commits
|
55
|
+
def log(count = 30)
|
56
|
+
Git::Log.new(self, count)
|
57
|
+
end
|
58
|
+
|
59
|
+
# returns a Git::Object of the appropriate type
|
60
|
+
# you can also call @git.gtree('tree'), but that's
|
61
|
+
# just for readability. If you call @git.gtree('HEAD') it will
|
62
|
+
# still return a Git::Object::Commit object.
|
63
|
+
#
|
64
|
+
# object calls a factory method that will run a rev-parse
|
65
|
+
# on the objectish and determine the type of the object and return
|
66
|
+
# an appropriate object for that type
|
67
|
+
#
|
68
|
+
# @return [Git::Object] an instance of the appropriate type of Git::Object
|
69
|
+
def object(objectish)
|
70
|
+
Git::Object.new(self, objectish)
|
71
|
+
end
|
72
|
+
|
73
|
+
# @return [Git::Remote] a remote of the specified name
|
74
|
+
def remote(remote_name = 'origin')
|
75
|
+
Git::Remote.new(self, remote_name)
|
76
|
+
end
|
77
|
+
|
78
|
+
# @return [Git::Status] a status object
|
79
|
+
def status
|
80
|
+
Git::Status.new(self)
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [Git::Object::Tag] a tag object
|
84
|
+
def tag(tag_name)
|
85
|
+
Git::Object.new(self, tag_name, 'tag', true)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Find as good common ancestors as possible for a merge
|
89
|
+
# example: g.merge_base('master', 'some_branch', 'some_sha', octopus: true)
|
90
|
+
#
|
91
|
+
# @return [Array<Git::Object::Commit>] a collection of common ancestors
|
92
|
+
def merge_base(*args)
|
93
|
+
shas = self.lib.merge_base(*args)
|
94
|
+
shas.map { |sha| gcommit(sha) }
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
data/lib/git/branch.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'git/path'
|
2
|
+
|
3
|
+
module Git
|
4
|
+
|
5
|
+
class Branch < Path
|
6
|
+
|
7
|
+
attr_accessor :full, :remote, :name
|
8
|
+
|
9
|
+
def initialize(base, name)
|
10
|
+
@full = name
|
11
|
+
@base = base
|
12
|
+
@gcommit = nil
|
13
|
+
@stashes = nil
|
14
|
+
@remote, @name = parse_name(name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def gcommit
|
18
|
+
@gcommit ||= @base.gcommit(@full)
|
19
|
+
@gcommit
|
20
|
+
end
|
21
|
+
|
22
|
+
def stashes
|
23
|
+
@stashes ||= Git::Stashes.new(@base)
|
24
|
+
end
|
25
|
+
|
26
|
+
def checkout
|
27
|
+
check_if_create
|
28
|
+
@base.checkout(@full)
|
29
|
+
end
|
30
|
+
|
31
|
+
def archive(file, opts = {})
|
32
|
+
@base.lib.archive(@full, file, opts)
|
33
|
+
end
|
34
|
+
|
35
|
+
# g.branch('new_branch').in_branch do
|
36
|
+
# # create new file
|
37
|
+
# # do other stuff
|
38
|
+
# return true # auto commits and switches back
|
39
|
+
# end
|
40
|
+
def in_branch(message = 'in branch work')
|
41
|
+
old_current = @base.lib.branch_current
|
42
|
+
checkout
|
43
|
+
if yield
|
44
|
+
@base.commit_all(message)
|
45
|
+
else
|
46
|
+
@base.reset_hard
|
47
|
+
end
|
48
|
+
@base.checkout(old_current)
|
49
|
+
end
|
50
|
+
|
51
|
+
def create
|
52
|
+
check_if_create
|
53
|
+
end
|
54
|
+
|
55
|
+
def delete
|
56
|
+
@base.lib.branch_delete(@name)
|
57
|
+
end
|
58
|
+
|
59
|
+
def current
|
60
|
+
determine_current
|
61
|
+
end
|
62
|
+
|
63
|
+
def contains?(commit)
|
64
|
+
!@base.lib.branch_contains(commit, self.name).empty?
|
65
|
+
end
|
66
|
+
|
67
|
+
def merge(branch = nil, message = nil)
|
68
|
+
if branch
|
69
|
+
in_branch do
|
70
|
+
@base.merge(branch, message)
|
71
|
+
false
|
72
|
+
end
|
73
|
+
# merge a branch into this one
|
74
|
+
else
|
75
|
+
# merge this branch into the current one
|
76
|
+
@base.merge(@name)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def update_ref(commit)
|
81
|
+
@base.lib.update_ref(@full, commit)
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_a
|
85
|
+
[@full]
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_s
|
89
|
+
@full
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def check_if_create
|
95
|
+
@base.lib.branch_new(@name) rescue nil
|
96
|
+
end
|
97
|
+
|
98
|
+
def determine_current
|
99
|
+
@base.lib.branch_current == @name
|
100
|
+
end
|
101
|
+
|
102
|
+
# Given a full branch name return an Array containing the remote and branch names.
|
103
|
+
#
|
104
|
+
# Removes 'remotes' from the beggining of the name (if present).
|
105
|
+
# Takes the second part (splittign by '/') as the remote name.
|
106
|
+
# Takes the rest as the repo name (can also hold one or more '/').
|
107
|
+
#
|
108
|
+
# Example:
|
109
|
+
# parse_name('master') #=> [nil, 'master']
|
110
|
+
# parse_name('origin/master') #=> ['origin', 'master']
|
111
|
+
# parse_name('remotes/origin/master') #=> ['origin', 'master']
|
112
|
+
# parse_name('origin/master/v2') #=> ['origin', 'master/v2']
|
113
|
+
#
|
114
|
+
# param [String] name branch full name.
|
115
|
+
# return [<Git::Remote,NilClass,String>] an Array containing the remote and branch names.
|
116
|
+
def parse_name(name)
|
117
|
+
if name.match(/^(?:remotes)?\/([^\/]+)\/(.+)/)
|
118
|
+
return [Git::Remote.new(@base, $1), $2]
|
119
|
+
end
|
120
|
+
|
121
|
+
return [nil, name]
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
data/lib/git/branches.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
module Git
|
2
|
+
|
3
|
+
# object that holds all the available branches
|
4
|
+
class Branches
|
5
|
+
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def initialize(base)
|
9
|
+
@branches = {}
|
10
|
+
|
11
|
+
@base = base
|
12
|
+
|
13
|
+
@base.lib.branches_all.each do |b|
|
14
|
+
@branches[b[0]] = Git::Branch.new(@base, b[0])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def local
|
19
|
+
self.select { |b| !b.remote }
|
20
|
+
end
|
21
|
+
|
22
|
+
def remote
|
23
|
+
self.select { |b| b.remote }
|
24
|
+
end
|
25
|
+
|
26
|
+
# array like methods
|
27
|
+
|
28
|
+
def size
|
29
|
+
@branches.size
|
30
|
+
end
|
31
|
+
|
32
|
+
def each(&block)
|
33
|
+
@branches.values.each(&block)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns the target branch
|
37
|
+
#
|
38
|
+
# Example:
|
39
|
+
# Given (git branch -a):
|
40
|
+
# master
|
41
|
+
# remotes/working/master
|
42
|
+
#
|
43
|
+
# g.branches['master'].full #=> 'master'
|
44
|
+
# g.branches['working/master'].full => 'remotes/working/master'
|
45
|
+
# g.branches['remotes/working/master'].full => 'remotes/working/master'
|
46
|
+
#
|
47
|
+
# @param [#to_s] branch_name the target branch name.
|
48
|
+
# @return [Git::Branch] the target branch.
|
49
|
+
def [](branch_name)
|
50
|
+
@branches.values.inject(@branches) do |branches, branch|
|
51
|
+
branches[branch.full] ||= branch
|
52
|
+
|
53
|
+
# This is how Git (version 1.7.9.5) works.
|
54
|
+
# Lets you ignore the 'remotes' if its at the beginning of the branch full name (even if is not a real remote branch).
|
55
|
+
branches[branch.full.sub('remotes/', '')] ||= branch if branch.full =~ /^remotes\/.+/
|
56
|
+
|
57
|
+
branches
|
58
|
+
end[branch_name.to_s]
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s
|
62
|
+
out = ''
|
63
|
+
@branches.each do |k, b|
|
64
|
+
out << (b.current ? '* ' : ' ') << b.to_s << "\n"
|
65
|
+
end
|
66
|
+
out
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
data/lib/git/config.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Git
|
2
|
+
|
3
|
+
class Config
|
4
|
+
|
5
|
+
attr_writer :binary_path, :git_ssh
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@binary_path = nil
|
9
|
+
@git_ssh = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def binary_path
|
13
|
+
@binary_path || ENV['GIT_PATH'] && File.join(ENV['GIT_PATH'], 'git') || 'git'
|
14
|
+
end
|
15
|
+
|
16
|
+
def git_ssh
|
17
|
+
@git_ssh || ENV['GIT_SSH']
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/lib/git/diff.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
module Git
|
2
|
+
|
3
|
+
# object that holds the last X commits on given branch
|
4
|
+
class Diff
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(base, from = nil, to = nil, **opts)
|
8
|
+
@base = base
|
9
|
+
@from = from && from.to_s
|
10
|
+
@to = to && to.to_s
|
11
|
+
@opts = opts
|
12
|
+
|
13
|
+
@path = nil
|
14
|
+
@full_diff = nil
|
15
|
+
@full_diff_files = nil
|
16
|
+
@stats = nil
|
17
|
+
end
|
18
|
+
attr_reader :from, :to
|
19
|
+
|
20
|
+
def name_status
|
21
|
+
cache_name_status
|
22
|
+
end
|
23
|
+
|
24
|
+
def path(path)
|
25
|
+
@path = path
|
26
|
+
return self
|
27
|
+
end
|
28
|
+
|
29
|
+
def size
|
30
|
+
cache_stats
|
31
|
+
@stats[:total][:files]
|
32
|
+
end
|
33
|
+
|
34
|
+
def lines
|
35
|
+
cache_stats
|
36
|
+
@stats[:total][:lines]
|
37
|
+
end
|
38
|
+
|
39
|
+
def deletions
|
40
|
+
cache_stats
|
41
|
+
@stats[:total][:deletions]
|
42
|
+
end
|
43
|
+
|
44
|
+
def insertions
|
45
|
+
cache_stats
|
46
|
+
@stats[:total][:insertions]
|
47
|
+
end
|
48
|
+
|
49
|
+
def stats
|
50
|
+
cache_stats
|
51
|
+
@stats
|
52
|
+
end
|
53
|
+
|
54
|
+
# if file is provided and is writable, it will write the patch into the file
|
55
|
+
def patch(file = nil)
|
56
|
+
cache_full
|
57
|
+
@full_diff
|
58
|
+
end
|
59
|
+
alias_method :to_s, :patch
|
60
|
+
|
61
|
+
# enumerable methods
|
62
|
+
|
63
|
+
def [](key)
|
64
|
+
process_full
|
65
|
+
@full_diff_files.assoc(key)[1]
|
66
|
+
end
|
67
|
+
|
68
|
+
def each(&block) # :yields: each Git::DiffFile in turn
|
69
|
+
process_full
|
70
|
+
@full_diff_files.map { |file| file[1] }.each(&block)
|
71
|
+
end
|
72
|
+
|
73
|
+
class DiffFile
|
74
|
+
attr_accessor :patch, :path, :mode, :src, :dst, :type
|
75
|
+
@base = nil
|
76
|
+
NIL_BLOB_REGEXP = /\A0{4,40}\z/.freeze
|
77
|
+
|
78
|
+
def initialize(base, hash)
|
79
|
+
@base = base
|
80
|
+
@patch = hash[:patch]
|
81
|
+
@path = hash[:path]
|
82
|
+
@mode = hash[:mode]
|
83
|
+
@src = hash[:src]
|
84
|
+
@dst = hash[:dst]
|
85
|
+
@type = hash[:type]
|
86
|
+
@binary = hash[:binary]
|
87
|
+
end
|
88
|
+
|
89
|
+
def binary?
|
90
|
+
!!@binary
|
91
|
+
end
|
92
|
+
|
93
|
+
def blob(type = :dst)
|
94
|
+
if type == :src && !NIL_BLOB_REGEXP.match(@src)
|
95
|
+
@base.object(@src)
|
96
|
+
elsif !NIL_BLOB_REGEXP.match(@dst)
|
97
|
+
@base.object(@dst)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def cache_full
|
105
|
+
@full_diff ||= @base.lib.diff_full(@from, @to, {:path_limiter => @path}.update(**@opts))
|
106
|
+
end
|
107
|
+
|
108
|
+
def process_full
|
109
|
+
return if @full_diff_files
|
110
|
+
cache_full
|
111
|
+
@full_diff_files = process_full_diff
|
112
|
+
end
|
113
|
+
|
114
|
+
def cache_stats
|
115
|
+
@stats ||= @base.lib.diff_stats(@from, @to, {:path_limiter => @path})
|
116
|
+
end
|
117
|
+
|
118
|
+
def cache_name_status
|
119
|
+
@name_status ||= @base.lib.diff_name_status(@from, @to, {:path => @path})
|
120
|
+
end
|
121
|
+
|
122
|
+
# break up @diff_full
|
123
|
+
def process_full_diff
|
124
|
+
defaults = {
|
125
|
+
:mode => '',
|
126
|
+
:src => '',
|
127
|
+
:dst => '',
|
128
|
+
:type => 'modified'
|
129
|
+
}
|
130
|
+
final = {}
|
131
|
+
current_file = nil
|
132
|
+
@full_diff.split("\n").each do |line|
|
133
|
+
if m = /^diff --git a\/(.*?) b\/(.*?)/.match(line)
|
134
|
+
current_file = m[1]
|
135
|
+
final[current_file] = defaults.merge({:patch => line, :path => current_file})
|
136
|
+
else
|
137
|
+
if m = /^index ([0-9a-f]{4,40})\.\.([0-9a-f]{4,40})( ......)*/.match(line)
|
138
|
+
final[current_file][:src] = m[1]
|
139
|
+
final[current_file][:dst] = m[2]
|
140
|
+
final[current_file][:mode] = m[3].strip if m[3]
|
141
|
+
end
|
142
|
+
if m = /^([[:alpha:]]*?) file mode (......)/.match(line)
|
143
|
+
final[current_file][:type] = m[1]
|
144
|
+
final[current_file][:mode] = m[2]
|
145
|
+
end
|
146
|
+
if m = /^Binary files /.match(line)
|
147
|
+
final[current_file][:binary] = true
|
148
|
+
end
|
149
|
+
final[current_file][:patch] << "\n" + line
|
150
|
+
end
|
151
|
+
end
|
152
|
+
final.map { |e| [e[0], DiffFile.new(@base, e[1])] }
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|