forked from libgit2/rugged
-
Notifications
You must be signed in to change notification settings - Fork 0
/
repository.rb
274 lines (241 loc) · 8.35 KB
/
repository.rb
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# Copyright (C) the Rugged contributors. All rights reserved.
#
# This file is part of Rugged, distributed under the MIT license.
# For full terms see the included LICENSE file.
module Rugged
# Repository is an interface into a Git repository on-disk. It's the primary
# interface between your app and the main Git objects Rugged makes available
# to you.
class Repository
# Pretty formatting of a Repository.
#
# Returns a very pretty String.
def inspect
"#<Rugged::Repository:#{object_id} {path: #{path.inspect}}>"
end
# Get the most recent commit from this repo.
#
# Returns a Rugged::Commit object.
def last_commit
self.head.target
end
# Checkout the specified branch, reference or commit.
#
# target - A revparse spec for the branch, reference or commit to check out.
# options - Options passed to #checkout_tree.
def checkout(target, options = {})
options[:strategy] ||= :safe
options.delete(:paths)
return checkout_head(**options) if target == "HEAD"
if target.kind_of?(Rugged::Branch)
branch = target
else
branch = branches[target]
end
if branch
self.checkout_tree(branch.target, **options)
if branch.remote?
references.create("HEAD", branch.target_id, force: true)
else
references.create("HEAD", branch.canonical_name, force: true)
end
else
commit = Commit.lookup(self, self.rev_parse_oid(target))
references.create("HEAD", commit.oid, force: true)
self.checkout_tree(commit, **options)
end
end
###
# call-seq:
# repo.status { |file, status_data| block }
# repo.status(path) -> status_data
#
# Returns the status for one or more files in the working directory
# of the repository. This is equivalent to the +git status+ command.
#
# The returned +status_data+ is always an array containing one or more
# status flags as Ruby symbols. Possible flags are:
#
# - +:index_new+: the file is new in the index
# - +:index_modified+: the file has been modified in the index
# - +:index_deleted+: the file has been deleted from the index
# - +:worktree_new+: the file is new in the working directory
# - +:worktree_modified+: the file has been modified in the working directory
# - +:worktree_deleted+: the file has been deleted from the working directory
#
# If a +block+ is given, status information will be gathered for every
# single file on the working dir. The +block+ will be called with the
# status data for each file.
#
# repo.status { |file, status_data| puts "#{file} has status: #{status_data.inspect}" }
#
# results in, for example:
#
# src/diff.c has status: [:index_new, :worktree_new]
# README has status: [:worktree_modified]
#
# If a +path+ is given instead, the function will return the +status_data+ for
# the file pointed to by path, or raise an exception if the path doesn't exist.
#
# +path+ must be relative to the repository's working directory.
#
# repo.status('src/diff.c') #=> [:index_new, :worktree_new]
def status(file = nil, &block)
if file
file_status file
else
each_status(&block)
end
end
def diff(left, right, opts = {})
left = rev_parse(left) if left.kind_of?(String)
right = rev_parse(right) if right.kind_of?(String)
if !left.is_a?(Rugged::Tree) && !left.is_a?(Rugged::Commit) && !left.nil?
raise TypeError, "Expected a Rugged::Tree or Rugged::Commit instance"
end
if !right.is_a?(Rugged::Tree) && !right.is_a?(Rugged::Commit) && !right.nil?
raise TypeError, "Expected a Rugged::Tree or Rugged::Commit instance"
end
if left
left.diff(right, opts)
elsif right
right.diff(left, opts.merge(:reverse => !opts[:reverse]))
end
end
def diff_workdir(left, opts = {})
left = rev_parse(left) if left.kind_of?(String)
if !left.is_a?(Rugged::Tree) && !left.is_a?(Rugged::Commit)
raise TypeError, "Expected a Rugged::Tree or Rugged::Commit instance"
end
left.diff_workdir(opts)
end
# Walks over a set of commits using Rugged::Walker.
#
# from - The String SHA1 to push onto Walker to begin our walk.
# sorting - The sorting order of the commits, as defined in the README.
# block - A block that we pass into walker#each.
#
# Returns nothing if called with a block, otherwise returns an instance of
# Enumerable::Enumerator containing Rugged::Commit objects.
def walk(from, sorting=Rugged::SORT_DATE, &block)
walker = Rugged::Walker.new(self)
walker.sorting(sorting)
walker.push(from)
walker.each(&block)
end
# Look up a SHA1.
#
# Returns one of the four classes that inherit from Rugged::Object.
def lookup(oid)
Rugged::Object.lookup(self, oid)
end
# Look up an object by a revision string.
#
# Returns one of the four classes that inherit from Rugged::Object.
def rev_parse(spec)
Rugged::Object.rev_parse(self, spec)
end
# Look up an object by a revision string.
#
# Returns the oid of the matched object as a String
def rev_parse_oid(spec)
Rugged::Object.rev_parse_oid(self, spec)
end
# Look up a single reference by name.
#
# Example:
#
# repo.ref 'refs/heads/master'
# # => #<Rugged::Reference:2199125780 {name: "refs/heads/master",
# target: "25b5d3b40c4eadda8098172b26c68cf151109799"}>
#
# Returns a Rugged::Reference.
def ref(ref_name)
references[ref_name]
end
def refs(glob = nil)
references.each(glob)
end
def references
@references ||= ReferenceCollection.new(self)
end
def ref_names(glob = nil)
references.each_name(glob)
end
# All the tags in the repository.
#
# Returns a TagCollection containing all the tags.
def tags
@tags ||= TagCollection.new(self)
end
# All the remotes in the repository.
#
# Returns a Rugged::RemoteCollection containing all the Rugged::Remote objects
# in the repository.
def remotes
@remotes ||= RemoteCollection.new(self)
end
# All the branches in the repository
#
# Returns a BranchCollection containing Rugged::Branch objects
def branches
@branches ||= BranchCollection.new(self)
end
# All the submodules in the repository
#
# Returns a SubmoduleCollection containing Rugged::Submodule objects
def submodules
@submodules ||= SubmoduleCollection.new(self)
end
# Create a new branch in the repository
#
# name - The name of the branch (without a full reference path)
# sha_or_ref - The target of the branch; either a String representing
# an OID or a reference name, or a Rugged::Object instance.
#
# Returns a Rugged::Branch object
def create_branch(name, sha_or_ref = "HEAD")
case sha_or_ref
when Rugged::Object
target = sha_or_ref.oid
else
target = rev_parse_oid(sha_or_ref)
end
branches.create(name, target)
end
# Get the blob at a path for a specific revision.
#
# revision - The String SHA1.
# path - The String file path.
#
# Returns a Rugged::Blob object
def blob_at(revision, path)
tree = Rugged::Commit.lookup(self, revision).tree
begin
blob_data = tree.path(path)
rescue Rugged::TreeError
return nil
end
blob = Rugged::Blob.lookup(self, blob_data[:oid])
(blob.type == :blob) ? blob : nil
end
def fetch(remote_or_url, *args, **kwargs)
unless remote_or_url.kind_of? Remote
remote_or_url = remotes[remote_or_url] || remotes.create_anonymous(remote_or_url)
end
remote_or_url.fetch(*args, **kwargs)
end
# Push a list of refspecs to the given remote.
#
# refspecs - A list of refspecs that should be pushed to the remote.
#
# Returns a hash containing the pushed refspecs as keys and
# any error messages or +nil+ as values.
def push(remote_or_url, *args, **kwargs)
unless remote_or_url.kind_of? Remote
remote_or_url = remotes[remote_or_url] || remotes.create_anonymous(remote_or_url)
end
remote_or_url.push(*args, **kwargs)
end
end
end