jit 0.0.0 → 1.0.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 +5 -5
- data/LICENSE.txt +674 -0
- data/bin/jit +21 -0
- data/lib/color.rb +32 -0
- data/lib/command.rb +62 -0
- data/lib/command/add.rb +65 -0
- data/lib/command/base.rb +92 -0
- data/lib/command/branch.rb +199 -0
- data/lib/command/checkout.rb +104 -0
- data/lib/command/cherry_pick.rb +51 -0
- data/lib/command/commit.rb +86 -0
- data/lib/command/config.rb +126 -0
- data/lib/command/diff.rb +114 -0
- data/lib/command/fetch.rb +116 -0
- data/lib/command/init.rb +41 -0
- data/lib/command/log.rb +188 -0
- data/lib/command/merge.rb +148 -0
- data/lib/command/push.rb +172 -0
- data/lib/command/receive_pack.rb +92 -0
- data/lib/command/remote.rb +55 -0
- data/lib/command/reset.rb +64 -0
- data/lib/command/rev_list.rb +33 -0
- data/lib/command/revert.rb +69 -0
- data/lib/command/rm.rb +105 -0
- data/lib/command/shared/fast_forward.rb +19 -0
- data/lib/command/shared/print_diff.rb +116 -0
- data/lib/command/shared/receive_objects.rb +37 -0
- data/lib/command/shared/remote_agent.rb +44 -0
- data/lib/command/shared/remote_client.rb +82 -0
- data/lib/command/shared/send_objects.rb +24 -0
- data/lib/command/shared/sequencing.rb +146 -0
- data/lib/command/shared/write_commit.rb +167 -0
- data/lib/command/status.rb +210 -0
- data/lib/command/upload_pack.rb +54 -0
- data/lib/config.rb +240 -0
- data/lib/config/stack.rb +42 -0
- data/lib/database.rb +112 -0
- data/lib/database/author.rb +27 -0
- data/lib/database/backends.rb +57 -0
- data/lib/database/blob.rb +24 -0
- data/lib/database/commit.rb +70 -0
- data/lib/database/entry.rb +7 -0
- data/lib/database/loose.rb +70 -0
- data/lib/database/packed.rb +75 -0
- data/lib/database/tree.rb +77 -0
- data/lib/database/tree_diff.rb +88 -0
- data/lib/diff.rb +46 -0
- data/lib/diff/combined.rb +72 -0
- data/lib/diff/hunk.rb +64 -0
- data/lib/diff/myers.rb +90 -0
- data/lib/editor.rb +59 -0
- data/lib/index.rb +212 -0
- data/lib/index/checksum.rb +44 -0
- data/lib/index/entry.rb +91 -0
- data/lib/lockfile.rb +55 -0
- data/lib/merge/bases.rb +38 -0
- data/lib/merge/common_ancestors.rb +77 -0
- data/lib/merge/diff3.rb +156 -0
- data/lib/merge/inputs.rb +42 -0
- data/lib/merge/resolve.rb +178 -0
- data/lib/pack.rb +45 -0
- data/lib/pack/compressor.rb +83 -0
- data/lib/pack/delta.rb +58 -0
- data/lib/pack/entry.rb +54 -0
- data/lib/pack/expander.rb +54 -0
- data/lib/pack/index.rb +100 -0
- data/lib/pack/indexer.rb +200 -0
- data/lib/pack/numbers.rb +79 -0
- data/lib/pack/reader.rb +98 -0
- data/lib/pack/stream.rb +80 -0
- data/lib/pack/unpacker.rb +62 -0
- data/lib/pack/window.rb +47 -0
- data/lib/pack/writer.rb +92 -0
- data/lib/pack/xdelta.rb +118 -0
- data/lib/pager.rb +24 -0
- data/lib/progress.rb +78 -0
- data/lib/refs.rb +260 -0
- data/lib/remotes.rb +82 -0
- data/lib/remotes/protocol.rb +82 -0
- data/lib/remotes/refspec.rb +70 -0
- data/lib/remotes/remote.rb +57 -0
- data/lib/repository.rb +64 -0
- data/lib/repository/divergence.rb +21 -0
- data/lib/repository/hard_reset.rb +35 -0
- data/lib/repository/inspector.rb +49 -0
- data/lib/repository/migration.rb +168 -0
- data/lib/repository/pending_commit.rb +60 -0
- data/lib/repository/sequencer.rb +118 -0
- data/lib/repository/status.rb +98 -0
- data/lib/rev_list.rb +244 -0
- data/lib/revision.rb +155 -0
- data/lib/sorted_hash.rb +17 -0
- data/lib/temp_file.rb +34 -0
- data/lib/workspace.rb +107 -0
- metadata +103 -9
data/lib/pack/xdelta.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
module Pack
|
2
|
+
class XDelta
|
3
|
+
|
4
|
+
BLOCK_SIZE = 16
|
5
|
+
|
6
|
+
def self.create_index(source)
|
7
|
+
blocks = source.bytesize / BLOCK_SIZE
|
8
|
+
index = {}
|
9
|
+
|
10
|
+
(0 ... blocks).each do |i|
|
11
|
+
offset = i * BLOCK_SIZE
|
12
|
+
slice = source.byteslice(offset, BLOCK_SIZE)
|
13
|
+
|
14
|
+
index[slice] ||= []
|
15
|
+
index[slice].push(offset)
|
16
|
+
end
|
17
|
+
|
18
|
+
new(source, index)
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(source, index)
|
22
|
+
@source = source
|
23
|
+
@index = index
|
24
|
+
end
|
25
|
+
|
26
|
+
def compress(target)
|
27
|
+
@target = target
|
28
|
+
@offset = 0
|
29
|
+
@insert = []
|
30
|
+
@ops = []
|
31
|
+
|
32
|
+
generate_ops while @offset < @target.bytesize
|
33
|
+
flush_insert
|
34
|
+
|
35
|
+
@ops
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def generate_ops
|
41
|
+
m_offset, m_size = longest_match
|
42
|
+
return push_insert if m_size == 0
|
43
|
+
|
44
|
+
m_offset, m_size = expand_match(m_offset, m_size)
|
45
|
+
|
46
|
+
flush_insert
|
47
|
+
@ops.push(Delta::Copy.new(m_offset, m_size))
|
48
|
+
end
|
49
|
+
|
50
|
+
def longest_match
|
51
|
+
slice = @target.byteslice(@offset, BLOCK_SIZE)
|
52
|
+
return [0, 0] unless @index.has_key?(slice)
|
53
|
+
|
54
|
+
m_offset = m_size = 0
|
55
|
+
|
56
|
+
@index[slice].each do |pos|
|
57
|
+
remaining = remaining_bytes(pos)
|
58
|
+
break if remaining <= m_size
|
59
|
+
|
60
|
+
s = match_from(pos, remaining)
|
61
|
+
next if m_size >= s - pos
|
62
|
+
|
63
|
+
m_offset = pos
|
64
|
+
m_size = s - pos
|
65
|
+
end
|
66
|
+
|
67
|
+
[m_offset, m_size]
|
68
|
+
end
|
69
|
+
|
70
|
+
def remaining_bytes(pos)
|
71
|
+
source_remaining = @source.bytesize - pos
|
72
|
+
target_remaining = @target.bytesize - @offset
|
73
|
+
|
74
|
+
[source_remaining, target_remaining, MAX_COPY_SIZE].min
|
75
|
+
end
|
76
|
+
|
77
|
+
def match_from(pos, remaining)
|
78
|
+
s, t = pos, @offset
|
79
|
+
|
80
|
+
while remaining > 0 and @source.getbyte(s) == @target.getbyte(t)
|
81
|
+
s, t = s + 1, t + 1
|
82
|
+
remaining -= 1
|
83
|
+
end
|
84
|
+
|
85
|
+
s
|
86
|
+
end
|
87
|
+
|
88
|
+
def expand_match(m_offset, m_size)
|
89
|
+
while m_offset > 0 and @source.getbyte(m_offset - 1) == @insert.last
|
90
|
+
break if m_size == MAX_COPY_SIZE
|
91
|
+
|
92
|
+
@offset -= 1
|
93
|
+
m_offset -= 1
|
94
|
+
m_size += 1
|
95
|
+
|
96
|
+
@insert.pop
|
97
|
+
end
|
98
|
+
|
99
|
+
@offset += m_size
|
100
|
+
[m_offset, m_size]
|
101
|
+
end
|
102
|
+
|
103
|
+
def push_insert
|
104
|
+
@insert.push(@target.getbyte(@offset))
|
105
|
+
@offset += 1
|
106
|
+
flush_insert(MAX_INSERT_SIZE)
|
107
|
+
end
|
108
|
+
|
109
|
+
def flush_insert(size = nil)
|
110
|
+
return if size and @insert.size < size
|
111
|
+
return if @insert.empty?
|
112
|
+
|
113
|
+
@ops.push(Delta::Insert.new(@insert.pack("C*")))
|
114
|
+
@insert = []
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
data/lib/pager.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
class Pager
|
2
|
+
PAGER_CMD = "less"
|
3
|
+
PAGER_ENV = { "LESS" => "FRX", "LV" => "-c" }
|
4
|
+
|
5
|
+
attr_reader :input
|
6
|
+
|
7
|
+
def initialize(env = {}, stdout = $stdout, stderr = $stderr)
|
8
|
+
env = PAGER_ENV.merge(env)
|
9
|
+
cmd = env["GIT_PAGER"] || env["PAGER"] || PAGER_CMD
|
10
|
+
|
11
|
+
reader, writer = IO.pipe
|
12
|
+
options = { :in => reader, :out => stdout, :err => stderr }
|
13
|
+
|
14
|
+
@pid = Process.spawn(env, cmd, options)
|
15
|
+
@input = writer
|
16
|
+
|
17
|
+
reader.close
|
18
|
+
end
|
19
|
+
|
20
|
+
def wait
|
21
|
+
Process.waitpid(@pid) if @pid
|
22
|
+
@pid = nil
|
23
|
+
end
|
24
|
+
end
|
data/lib/progress.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
class Progress
|
2
|
+
UNITS = ["B", "KiB", "MiB", "GiB"]
|
3
|
+
SCALE = 1024.0
|
4
|
+
|
5
|
+
def initialize(output)
|
6
|
+
@output = output
|
7
|
+
@message = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def start(message, total = nil)
|
11
|
+
return if ENV["NO_PROGRESS"] or not @output.isatty
|
12
|
+
|
13
|
+
@message = message
|
14
|
+
@total = total
|
15
|
+
@count = 0
|
16
|
+
@bytes = 0
|
17
|
+
@write_at = get_time
|
18
|
+
end
|
19
|
+
|
20
|
+
def tick(bytes = 0)
|
21
|
+
return unless @message
|
22
|
+
|
23
|
+
@count += 1
|
24
|
+
@bytes = bytes
|
25
|
+
|
26
|
+
current_time = get_time
|
27
|
+
return if current_time < @write_at + 0.05
|
28
|
+
@write_at = current_time
|
29
|
+
|
30
|
+
clear_line
|
31
|
+
@output.write(status_line)
|
32
|
+
end
|
33
|
+
|
34
|
+
def stop
|
35
|
+
return unless @message
|
36
|
+
|
37
|
+
@total = @count
|
38
|
+
|
39
|
+
clear_line
|
40
|
+
@output.puts(status_line)
|
41
|
+
@message = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def get_time
|
47
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
48
|
+
end
|
49
|
+
|
50
|
+
def clear_line
|
51
|
+
@output.write("\e[G\e[K")
|
52
|
+
end
|
53
|
+
|
54
|
+
def status_line
|
55
|
+
line = "#{ @message }: #{ format_count }"
|
56
|
+
|
57
|
+
line.concat(", #{ format_bytes }") if @bytes > 0
|
58
|
+
line.concat(", done.") if @count == @total
|
59
|
+
|
60
|
+
line
|
61
|
+
end
|
62
|
+
|
63
|
+
def format_count
|
64
|
+
if @total
|
65
|
+
percent = (@total == 0) ? 100 : 100 * @count / @total
|
66
|
+
"#{ percent }% (#{ @count }/#{ @total })"
|
67
|
+
else
|
68
|
+
"(#{ @count })"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def format_bytes
|
73
|
+
power = Math.log(@bytes, SCALE).floor
|
74
|
+
scaled = @bytes / (SCALE ** power)
|
75
|
+
|
76
|
+
format("%.2f #{ UNITS[power] }", scaled)
|
77
|
+
end
|
78
|
+
end
|
data/lib/refs.rb
ADDED
@@ -0,0 +1,260 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "pathname"
|
3
|
+
|
4
|
+
require_relative "./lockfile"
|
5
|
+
require_relative "./revision"
|
6
|
+
|
7
|
+
class Refs
|
8
|
+
InvalidBranch = Class.new(StandardError)
|
9
|
+
StaleValue = Class.new(StandardError)
|
10
|
+
|
11
|
+
SymRef = Struct.new(:refs, :path) do
|
12
|
+
def read_oid
|
13
|
+
refs.read_ref(path)
|
14
|
+
end
|
15
|
+
|
16
|
+
def head?
|
17
|
+
path == HEAD
|
18
|
+
end
|
19
|
+
|
20
|
+
def branch?
|
21
|
+
path.start_with?("refs/heads/")
|
22
|
+
end
|
23
|
+
|
24
|
+
def remote?
|
25
|
+
path.start_with?("refs/remotes/")
|
26
|
+
end
|
27
|
+
|
28
|
+
def short_name
|
29
|
+
refs.short_name(path)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Ref = Struct.new(:oid) do
|
34
|
+
def read_oid
|
35
|
+
oid
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
HEAD = "HEAD"
|
40
|
+
ORIG_HEAD = "ORIG_HEAD"
|
41
|
+
SYMREF = /^ref: (.+)$/
|
42
|
+
|
43
|
+
REFS_DIR = Pathname.new("refs")
|
44
|
+
HEADS_DIR = REFS_DIR.join("heads")
|
45
|
+
REMOTES_DIR = REFS_DIR.join("remotes")
|
46
|
+
|
47
|
+
def initialize(pathname)
|
48
|
+
@pathname = pathname
|
49
|
+
@refs_path = @pathname.join(REFS_DIR)
|
50
|
+
@heads_path = @pathname.join(HEADS_DIR)
|
51
|
+
@remotes_path = @pathname.join(REMOTES_DIR)
|
52
|
+
end
|
53
|
+
|
54
|
+
def read_head
|
55
|
+
read_symref(@pathname.join(HEAD))
|
56
|
+
end
|
57
|
+
|
58
|
+
def update_head(oid)
|
59
|
+
update_symref(@pathname.join(HEAD), oid)
|
60
|
+
end
|
61
|
+
|
62
|
+
def set_head(revision, oid)
|
63
|
+
head = @pathname.join(HEAD)
|
64
|
+
path = @heads_path.join(revision)
|
65
|
+
|
66
|
+
if File.file?(path)
|
67
|
+
relative = path.relative_path_from(@pathname)
|
68
|
+
update_ref_file(head, "ref: #{ relative }")
|
69
|
+
else
|
70
|
+
update_ref_file(head, oid)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def read_ref(name)
|
75
|
+
path = path_for_name(name)
|
76
|
+
path ? read_symref(path) : nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def update_ref(name, oid)
|
80
|
+
update_ref_file(@pathname.join(name), oid)
|
81
|
+
end
|
82
|
+
|
83
|
+
def compare_and_swap(name, old_oid, new_oid)
|
84
|
+
path = @pathname.join(name)
|
85
|
+
|
86
|
+
update_ref_file(path, new_oid) do
|
87
|
+
unless old_oid == read_symref(path)
|
88
|
+
raise StaleValue, "value of #{ name } changed since last read"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def create_branch(branch_name, start_oid)
|
94
|
+
path = @heads_path.join(branch_name)
|
95
|
+
|
96
|
+
unless Revision.valid_ref?(branch_name)
|
97
|
+
raise InvalidBranch, "'#{ branch_name }' is not a valid branch name."
|
98
|
+
end
|
99
|
+
|
100
|
+
if File.file?(path)
|
101
|
+
raise InvalidBranch, "A branch named '#{ branch_name }' already exists."
|
102
|
+
end
|
103
|
+
|
104
|
+
FileUtils.mkdir_p(path.dirname)
|
105
|
+
update_ref_file(path, start_oid)
|
106
|
+
end
|
107
|
+
|
108
|
+
def delete_branch(branch_name)
|
109
|
+
path = @heads_path.join(branch_name)
|
110
|
+
|
111
|
+
lockfile = Lockfile.new(path)
|
112
|
+
lockfile.hold_for_update
|
113
|
+
|
114
|
+
oid = read_symref(path)
|
115
|
+
raise InvalidBranch, "branch '#{ branch_name }' not found." unless oid
|
116
|
+
|
117
|
+
File.unlink(path)
|
118
|
+
oid
|
119
|
+
ensure
|
120
|
+
lockfile.rollback
|
121
|
+
end
|
122
|
+
|
123
|
+
def current_ref(source = HEAD)
|
124
|
+
ref = read_oid_or_symref(@pathname.join(source))
|
125
|
+
|
126
|
+
case ref
|
127
|
+
when SymRef then current_ref(ref.path)
|
128
|
+
when Ref, nil then SymRef.new(self, source)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def list_all_refs
|
133
|
+
[SymRef.new(self, HEAD)] + list_refs(@refs_path)
|
134
|
+
end
|
135
|
+
|
136
|
+
def list_branches
|
137
|
+
list_refs(@heads_path)
|
138
|
+
end
|
139
|
+
|
140
|
+
def list_remotes
|
141
|
+
list_refs(@remotes_path)
|
142
|
+
end
|
143
|
+
|
144
|
+
def reverse_refs
|
145
|
+
table = Hash.new { |hash, key| hash[key] = [] }
|
146
|
+
|
147
|
+
list_all_refs.each do |ref|
|
148
|
+
oid = ref.read_oid
|
149
|
+
table[oid].push(ref) if oid
|
150
|
+
end
|
151
|
+
|
152
|
+
table
|
153
|
+
end
|
154
|
+
|
155
|
+
def short_name(path)
|
156
|
+
path = @pathname.join(path)
|
157
|
+
|
158
|
+
prefix = [@remotes_path, @heads_path, @pathname].find do |dir|
|
159
|
+
path.dirname.ascend.any? { |parent| parent == dir }
|
160
|
+
end
|
161
|
+
|
162
|
+
path.relative_path_from(prefix).to_s
|
163
|
+
end
|
164
|
+
|
165
|
+
def long_name(ref)
|
166
|
+
path = path_for_name(ref)
|
167
|
+
return path.relative_path_from(@pathname).to_s if path
|
168
|
+
|
169
|
+
raise InvalidBranch,
|
170
|
+
"the requested upstream branch '#{ ref }' does not exist"
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
def list_refs(dirname)
|
176
|
+
names = Dir.entries(dirname) - [".", ".."]
|
177
|
+
|
178
|
+
names.map { |name| dirname.join(name) }.flat_map do |path|
|
179
|
+
if File.directory?(path)
|
180
|
+
list_refs(path)
|
181
|
+
else
|
182
|
+
path = path.relative_path_from(@pathname)
|
183
|
+
SymRef.new(self, path.to_s)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
rescue Errno::ENOENT
|
188
|
+
[]
|
189
|
+
end
|
190
|
+
|
191
|
+
def path_for_name(name)
|
192
|
+
prefixes = [@pathname, @refs_path, @heads_path, @remotes_path]
|
193
|
+
prefix = prefixes.find { |path| File.file? path.join(name) }
|
194
|
+
|
195
|
+
prefix ? prefix.join(name) : nil
|
196
|
+
end
|
197
|
+
|
198
|
+
def read_oid_or_symref(path)
|
199
|
+
data = File.read(path).strip
|
200
|
+
match = SYMREF.match(data)
|
201
|
+
|
202
|
+
match ? SymRef.new(self, match[1]) : Ref.new(data)
|
203
|
+
rescue Errno::ENOENT
|
204
|
+
nil
|
205
|
+
end
|
206
|
+
|
207
|
+
def read_symref(path)
|
208
|
+
ref = read_oid_or_symref(path)
|
209
|
+
|
210
|
+
case ref
|
211
|
+
when SymRef then read_symref(@pathname.join(ref.path))
|
212
|
+
when Ref then ref.oid
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def update_ref_file(path, oid)
|
217
|
+
lockfile = Lockfile.new(path)
|
218
|
+
|
219
|
+
lockfile.hold_for_update
|
220
|
+
yield if block_given?
|
221
|
+
|
222
|
+
if oid
|
223
|
+
write_lockfile(lockfile, oid)
|
224
|
+
else
|
225
|
+
File.unlink(path) rescue Errno::ENOENT
|
226
|
+
lockfile.rollback
|
227
|
+
end
|
228
|
+
|
229
|
+
rescue Lockfile::MissingParent
|
230
|
+
FileUtils.mkdir_p(path.dirname)
|
231
|
+
retry
|
232
|
+
rescue => error
|
233
|
+
lockfile.rollback
|
234
|
+
raise error
|
235
|
+
end
|
236
|
+
|
237
|
+
def update_symref(path, oid)
|
238
|
+
lockfile = Lockfile.new(path)
|
239
|
+
lockfile.hold_for_update
|
240
|
+
|
241
|
+
ref = read_oid_or_symref(path)
|
242
|
+
|
243
|
+
unless ref.is_a?(SymRef)
|
244
|
+
write_lockfile(lockfile, oid)
|
245
|
+
return ref&.oid
|
246
|
+
end
|
247
|
+
|
248
|
+
begin
|
249
|
+
update_symref(@pathname.join(ref.path), oid)
|
250
|
+
ensure
|
251
|
+
lockfile.rollback
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def write_lockfile(lockfile, oid)
|
256
|
+
lockfile.write(oid)
|
257
|
+
lockfile.write("\n")
|
258
|
+
lockfile.commit
|
259
|
+
end
|
260
|
+
end
|